diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/vdd/samples/mscdex | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/mvdm/vdd/samples/mscdex')
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/dirs | 23 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/readme.txt | 22 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/tsr/makefile | 49 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/tsr/messages/usa/messages.inc | 2 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.asm | 246 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.inc | 30 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/makefile | 11 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/mscdex.h | 313 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/sources | 27 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/vcdex.c | 1474 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/vcdex.def | 8 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/vcdex.h | 91 | ||||
-rw-r--r-- | private/mvdm/vdd/samples/mscdex/vdd/vcdex.rc | 48 |
13 files changed, 2344 insertions, 0 deletions
diff --git a/private/mvdm/vdd/samples/mscdex/dirs b/private/mvdm/vdd/samples/mscdex/dirs new file mode 100644 index 000000000..faaa9370e --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/dirs @@ -0,0 +1,23 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + +History: + Created 27-Mar-91 by Jeff Parsons (jeffpar) + from template created 12-Apr-1990 by Steve Wood (stevewo) + + +NOTE: Commented description of this file is in \nt\public\oak\bin\dirs.tpl + +!ENDIF + +DIRS=vdd diff --git a/private/mvdm/vdd/samples/mscdex/readme.txt b/private/mvdm/vdd/samples/mscdex/readme.txt new file mode 100644 index 000000000..f2256daa8 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/readme.txt @@ -0,0 +1,22 @@ + +Hi Sudeep, + +Here are the MSCDEX files. There is a TSR and a VDD. I normally build the +TSR with 16-bit tools. + +The only installation changes required would be that the TSR (MSCDEXNT.EXE) +be added to the Autoexec.nt. This line in autoexec.nt needs to be before the +"dosx" line, per a bug in dosx. + +The VCDEX.DLL needs to be in the path. The MSCDEXNT.TSR does a +RegisterModule() to it. + + +I have a couple of CD player apps in the TEST directory. CDP is a win16 +app, and CDPLYR is a DOS app (from the soundblaster disks). Both of them +use MSCDEX exclusively. + + +I hope that does it. Let me know if you run into any problems. + +-Neil diff --git a/private/mvdm/vdd/samples/mscdex/tsr/makefile b/private/mvdm/vdd/samples/mscdex/tsr/makefile new file mode 100644 index 000000000..8879a627f --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/tsr/makefile @@ -0,0 +1,49 @@ +!IFNDEF BUILDMSG +BUILDMSG= +!ENDIF + +########## Path definition so we find 16 bit tools ########## +# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be +# in a directory that is greater than 128 chars down the path, even if +# rc 3.1 is running as an OS/2 app. + +PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH) + +.SUFFIXES: +.SUFFIXES: .c .obj .lst .exe .exc .exs .com .sal .cod .sil .inc .skl .cla .cl1 .ctl .asm .idx .msg + +MAKE =nmake +asm =masm +awarn =-W1 +aflags =-Mx -t $(awarn) $(extasw) +ainc =-I. -I$(_NTBINDIR)\public\sdk\inc + +!IFNDEF COUNTRY +COUNTRY=usa +!ENDIF + +.asm.obj: + $(asm) $(ainc) $(aflags) $*.asm; + +.asm.lst: + $(asm) -l $(ainc) $(aflags) $*.asm; + +all: mscdexnt.exe + -binplace mscdexnt.exe + +clean: cleanup all + +cleanup: + if exist *.obj del *.obj + if exist *.exe del *.exe + if exist *.map del *.map + if exist *.sym del *.sym + if exist messages.inc del messages.inc + +messages.inc : messages\$(COUNTRY)\messages.inc + copy messages\$(COUNTRY)\messages.inc . + +mscdexnt.obj: mscdexnt.asm mscdexnt.inc messages.inc + +mscdexnt.exe: mscdexnt.obj + link16 /CP:1 mscdexnt.obj, mscdexnt; diff --git a/private/mvdm/vdd/samples/mscdex/tsr/messages/usa/messages.inc b/private/mvdm/vdd/samples/mscdex/tsr/messages/usa/messages.inc new file mode 100644 index 000000000..94ea20e1a --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/tsr/messages/usa/messages.inc @@ -0,0 +1,2 @@ +Message1 db CR,LF,'MSCDEXNT Will Run Only Under Windows NT.',CR,LF,'$' +Message2 db CR,LF,'MSCDEXNT is already installed.',CR,LF,'$' diff --git a/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.asm b/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.asm new file mode 100644 index 000000000..ca0ff46a1 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.asm @@ -0,0 +1,246 @@ + name mscdexnt +; +; MSCDEXNT +; +; Author: Neil Sandlin (neilsa) +; +; Description: +; +; This TSR implements the v86 mode portion of MSCDEX support under +; NT. Basically, all this piece does is hook INT2F and watch for +; MSCDEX calls. When the first one occurs, it tries to load VCDEX.DLL. +; If that succeeds, it passes the call (and all subsequent calls) +; to VCDEX for processing. +; + include isvbop.inc + include mscdexnt.inc + +_TEXT segment word public 'CODE' + assume cs:_TEXT,ds:_TEXT,es:_TEXT + +;*----------------------- TSR Code --------------------------* + +DrvStrat proc far ; Strategy Routine + ret +DrvStrat endp + +DrvIntr proc far ; INterrupt routine + ret +DrvIntr endp + +;****************************************************************************** +; +; Int2FHook +; +; +;****************************************************************************** +Int2FHook proc near + + cmp ah, MSCDEX_ID ;MSCDEX? + jnz int2fchain ;no + cmp al, MAX_MSCDEX_CMD ;command too high? + ja int2fchain ;yes + + cmp word ptr cs:[hVDD], 0 ;zero is an invalid module handle + jnz callvdd ;registered ok + + cmp byte ptr cs:[fVDDChecked],1 + jz vddfailed + + call RegisterVDD + jc vddfailed ;didn't get it + +callvdd: + push ax ;put ax on stack + mov ax, word ptr cs:[hVDD] + DispatchCall + add sp, 2 ;vdd has set ax accordingly + iret ;svc handled, return to caller + +vddfailed: + or al,al + jnz try_0b + xor bx,bx + jmp short int2f_done +try_0b: + cmp al,0bh + jne int2f_done +;; williamh - June 1 1993 - if unable to load VDD, we should tell +;; the caller that the drive is NOT a cd rom. + xor ax, ax + mov bx,0adadh +int2f_done: + iret + +int2fchain: + jmp dword ptr cs:[oldint] + +Int2FHook endp + +;**************************************************************************** +; +; RegisterVDD +; +;**************************************************************************** +RegisterVDD proc near + + push ax + push bx + push cx + push dx + push si + push di + push ds + push es + + + mov ax, cs + mov ds, ax + mov es, ax + ; Load vcdex.dll + mov si, offset DllName ; ds:si = dll name + mov di, offset InitFunc ; es:di = init routine + mov bx, offset DispFunc ; ds:bx = dispatch routine + + push cs ; pass far pointer to headers + pop cx ; in cx:dx + mov dx, offset drive_header + + RegisterModule + jc errorexit ; jif error + mov cs:[hVDD],ax ; save handle + +errorexit: + mov byte ptr cs:[fVDDChecked],1 + pop es + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret + +RegisterVDD endp + +;*----------------------- TSR Data Area ---------------------* +oldint dd 0 +hVDD DW 0 + +fVDDChecked DB 0 ; 0 - VDD never called. 1 - VDD once called. + +DllName DB "VCDEX.DLL",0 +InitFunc DB "VDDRegisterInit",0 +DispFunc DB "VDDDispatch",0 + + + ALIGN 16 +drive_header: + DrvHd 'MSCDEX00' + + ALIGN 16 +Init_Fence: +;*-------------------------- Initialization Code ----------------------* + +mscdexnt proc far + + ; at this point es,ds -> PSP + ; SS:SP points to stack + + ; first check that we are running under NT + + mov ax, GET_NT_VERSION + int 21h + cmp bl, NT_MAJOR_VERSION + je cdx_chk_more + jmp cdx_badver +cdx_chk_more: + cmp bh, NT_MINOR_VERSION + je cdx_ver_ok + jmp cdx_badver + +cdx_ver_ok: + ; Now check that this TSR is'nt already installed + mov ah,MSCDEX_ID + mov al,0bh ; call function 0b + int MPX_INT ; int 2f + + cmp bx,0adadh + jne cdx_chks_done + jmp cdx_installed + +cdx_chks_done: + + ; free the env segment + + push es + push ds + mov es, es:[2ch] + mov ah, 49h + int 21h + + mov ah, DOS_GET_VECTOR + mov al, MPX_INT ; 2f + int 21h ; get old vector + mov WORD PTR cs:oldint,bx ; save old vector here + mov WORD PTR cs:oldint+2,es + + mov dx, offset Int2FHook + push cs ; get current code segment + pop ds + mov ah, DOS_SET_VECTOR + mov al, MPX_INT ; vector to hook + int 21h ; hook that vector + +; +; Compute size of TSR area +; + pop ds + pop es + mov dx, offset Init_Fence ; end of fixed TSR code + mov cl, 4 ; divide by 16 + shr dx, cl + add dx, 16 ; add in PSP +; +; Terminate and stay resident +; + mov ah, DOS_TSR ; TSR + mov al, 0 + int 21h ; TSR + +cdx_badver: + mov dx, offset Message1 + push cs + pop ds + mov ah,09h + int 21h + jmp short cdx_exit + +cdx_installed: + mov dx, offset Message2 + push cs + pop ds + mov ah,09h + int 21h + +cdx_exit: + mov ax,4c00h ; Exit + int 21h + +mscdexnt endp + + include messages.inc + +_TEXT ends + +InitStack segment para stack 'STACK' + + dw 256 dup (?) + +top_of_stack equ $ + +InitStack ends + + end mscdexnt + diff --git a/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.inc b/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.inc new file mode 100644 index 000000000..7cee3d55e --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.inc @@ -0,0 +1,30 @@ +;----------------------------- E Q U A T E S ---------------------------- +DOS_SET_VECTOR equ 25h +DOS_GET_VECTOR equ 35h +DOS_TSR equ 31h + +MPX_INT equ 2fh +MSCDEX_ID equ 15h +MAX_MSCDEX_CMD equ 10h + +GET_NT_VERSION equ 3306h +NT_MAJOR_VERSION equ 05 +NT_MINOR_VERSION equ 50 + +CR equ 0dh +LF equ 0Ah + +;----------------------------- M A C R O S ------------------------------ +DrvHd MACRO name + DD -1 + DW 0c840h + DW 0 + DW 0 + DB name + dw 0 + db 0 + db 1 + db 10 dup (0) + ENDM + + diff --git a/private/mvdm/vdd/samples/mscdex/vdd/makefile b/private/mvdm/vdd/samples/mscdex/vdd/makefile new file mode 100644 index 000000000..85f1ecf36 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/makefile @@ -0,0 +1,11 @@ +# Sample VDD makefile +# +# Copyright (c) 1991, Microsoft Corporation +# + + +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/mvdm/vdd/samples/mscdex/vdd/mscdex.h b/private/mvdm/vdd/samples/mscdex/vdd/mscdex.h new file mode 100644 index 000000000..8d86db882 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/mscdex.h @@ -0,0 +1,313 @@ +/* + The following definitions were derived from the "CD-ROM Programmer's + Guide for MS-DOS CD-ROM Extensions, Version 2.21" January 1992 + */ +#define MSCDEX_VERSION 0x0215 + +#define CDSTAT_ERROR 0X8000 +#define CDSTAT_BUSY 0X0200 +#define CDSTAT_DONE 0X0100 + +#define CDERR_WRITE_PROTECT 0 +#define CDERR_UNKNOWN_UNIT 1 +#define CDERR_NOT_READY 2 +#define CDERR_UNKNOWN_CMD 3 +#define CDERR_CRC 4 +#define CDERR_STRUCT_LENGTH 5 +#define CDERR_SEEK 6 +#define CDERR_UNKNOWN_MEDIA 7 +#define CDERR_SECT_NOTFOUND 8 +#define CDERR_WRITE_FAULT 10 +#define CDERR_READ_FAULT 11 +#define CDERR_GENERAL 12 +#define CDERR_PARAMETER 13 // Per mscdex spec +#define CDERR_DISK_CHANGE 15 + +#define DEVICE_INIT 0 +#define IOCTL_READ 3 +#define INPUT_FLUSH 7 +#define OUTPUT_FLUSH 11 +#define IOCTL_WRITE 12 +#define DEVICE_OPEN 13 +#define DEVICE_CLOSE 14 +#define READ_LONG 128 +#define READ_LONG_PREFETCH 130 +#define SEEK 131 +#define PLAY_AUDIO 132 +#define STOP_AUDIO 133 +#define WRITE_LONG 134 +#define WRITE_LONG_VERIFY 135 +#define RESUME_AUDIO 136 + + +#define IOCTLR_RADDR 0 +#define IOCTLR_LOCHEAD 1 +#define IOCTLR_ERRSTAT 3 +#define IOCTLR_AUDINFO 4 +#define IOCTLR_DRVBYTES 5 +#define IOCTLR_DEVSTAT 6 +#define IOCTLR_SECTSIZE 7 +#define IOCTLR_VOLSIZE 8 +#define IOCTLR_MEDCHNG 9 +#define IOCTLR_DISKINFO 10 +#define IOCTLR_TNOINFO 11 +#define IOCTLR_QINFO 12 +#define IOCTLR_SUBCHANINFO 13 +#define IOCTLR_UPCCODE 14 +#define IOCTLR_AUDSTAT 15 + +#define IOCTLW_EJECT 0 +#define IOCTLW_LOCKDOOR 1 +#define IOCTLW_RESETDRV 2 +#define IOCTLW_AUDINFO 3 +#define IOCTLW_DRVBYTES 4 +#define IOCTLW_CLOSETRAY 5 + +#define MODE_HSG 0 +#define MODE_REDBOOK 1 + +typedef union _SECTOR_ADDR { + BYTE b[4]; + ULONG dw; +} SECTOR_ADDR; + + +#pragma pack(1) + +typedef struct _REQUESTHEADER { + BYTE rhLength; + BYTE rhUnit; + BYTE rhFunction; + WORD rhStatus; + BYTE rhReserved[8]; + + BYTE irwrData; + LPBYTE irwrBuffer; + WORD irwrBytes; +} REQUESTHEADER, *LPREQUESTHEADER; + +typedef struct _DEVICE_HEADER { + DWORD link; + WORD attributes; + WORD strategy; + WORD interrupt; + BYTE name[8]; + WORD reserved; + BYTE drive; + BYTE numunits; + BYTE reserved2[10]; +} DEVICE_HEADER, *PDEVICE_HEADER; + +typedef struct _DRIVE_DEVICE_LIST { + BYTE Unit; + DWORD DeviceHeader; +} DRIVE_DEVICE_LIST, *PDRIVE_DEVICE_LIST; + + +typedef struct _IOCTLR_RADDR_BLOCK { + BYTE ctlcode; // 0 + DWORD devheader; +} IOCTLR_RADDR_BLOCK, *PIOCTLR_RADDR_BLOCK; + + +typedef struct _IOCTLR_LOCHEAD_BLOCK { + BYTE ctlcode; // 1 + BYTE addrmode; + SECTOR_ADDR headlocation; +} IOCTLR_LOCHEAD_BLOCK, *PIOCTLR_LOCHEAD_BLOCK; + + +typedef struct _IOCTLR_ERRSTAT_BLOCK { + BYTE ctlcode; // 3 + BYTE statistics; // array of undefined length +} IOCTLR_ERRSTAT_BLOCK, *PIOCTLR_ERRSTAT_BLOCK; + + +typedef struct _IOCTLR_AUDINFO_BLOCK { + BYTE ctlcode; // 4 + BYTE chan0; + BYTE vol0; + BYTE chan1; + BYTE vol1; + BYTE chan2; + BYTE vol2; + BYTE chan3; + BYTE vol3; +} IOCTLR_AUDINFO_BLOCK, *PIOCTLR_AUDINFO_BLOCK; + + +typedef struct _IOCTLR_DRVBYTES_BLOCK { + BYTE ctlcode; // 5 + BYTE numbytes; + BYTE buffer[128]; +} IOCTLR_DRVBYTES_BLOCK, *PIOCTLR_DRVBYTES_BLOCK; + + +typedef struct _IOCTLR_DEVSTAT_BLOCK { + BYTE ctlcode; // 6 + DWORD devparms; +} IOCTLR_DEVSTAT_BLOCK, *PIOCTLR_DEVSTAT_BLOCK; + +#define DEVSTAT_DOOR_OPEN 0X00000001 +#define DEVSTAT_DOOR_UNLOCKED 0X00000002 +#define DEVSTAT_SUPPORTS_COOKED 0X00000004 +#define DEVSTAT_READ_WRITE 0X00000008 +#define DEVSTAT_PLAYS_AV 0X00000010 +#define DEVSTAT_SUPPORTS_ILEAVE 0X00000020 +#define DEVSTAT_SUPPORTS_PRFTCH 0X00000080 +#define DEVSTAT_SUPPORTS_CHMAN 0X00000100 +#define DEVSTAT_SUPPORTS_RBOOK 0X00000200 +#define DEVSTAT_NO_DISC 0X00000800 +#define DEVSTAT_SUPPORTS_RWSCH 0X00001000 + + +typedef struct _IOCTLR_SECTSIZE_BLOCK { + BYTE ctlcode; // 7 + BYTE readmode; + WORD sectsize; +} IOCTLR_SECTSIZE_BLOCK, *PIOCTLR_SECTSIZE_BLOCK; + + +typedef struct _IOCTLR_VOLSIZE_BLOCK { + BYTE ctlcode; // 8 + DWORD size; +} IOCTLR_VOLSIZE_BLOCK, *PIOCTLR_VOLSIZE_BLOCK; + + +typedef struct _IOCTLR_MEDCHNG_BLOCK { + BYTE ctlcode; // 9 + BYTE medbyte; +} IOCTLR_MEDCHNG_BLOCK, *PIOCTLR_MEDCHNG_BLOCK; + +#define MEDCHNG_NOT_CHANGED 1 +#define MEDCHNG_DONT_KNOW 0 +#define MEDCHNG_CHANGED 0XFF + + +typedef struct _IOCTLR_DISKINFO_BLOCK { + BYTE ctlcode; // 10 + BYTE tracklow; + BYTE trackhigh; + SECTOR_ADDR startleadout; +} IOCTLR_DISKINFO_BLOCK, *PIOCTLR_DISKINFO_BLOCK; + + +typedef struct _IOCTLR_TNOINFO_BLOCK { + BYTE ctlcode; // 11 + BYTE trknum; + SECTOR_ADDR start; + BYTE trkctl; +} IOCTLR_TNOINFO_BLOCK, *PIOCTLR_TNOINFO_BLOCK; + + +typedef struct _IOCTLR_QINFO_BLOCK { + BYTE ctlcode; // 12 + BYTE ctladr; + BYTE trknum; + BYTE pointx; + BYTE min; + BYTE sec; + BYTE frame; + BYTE zero; + BYTE apmin; + BYTE apsec; + BYTE apframe; +} IOCTLR_QINFO_BLOCK, *PIOCTLR_QINFO_BLOCK; + + +typedef struct _IOCTLR_SUBCHANINFO_BLOCK { + BYTE ctlcode; // 13 + SECTOR_ADDR startsect; + DWORD transaddr; + DWORD numsect; +} IOCTLR_SUBCHANINFO_BLOCK, *PIOCTLR_SUBCHANINFO_BLOCK; + + +typedef struct _IOCTLR_UPCCODE_BLOCK { + BYTE ctlcode; // 14 + BYTE ctladr; + BYTE upcean[7]; + BYTE zero; + BYTE aframe; +} IOCTLR_UPCCODE_BLOCK, *PIOCTLR_UPCCODE_BLOCK; + + +typedef struct _IOCTLR_AUDSTAT_BLOCK { + BYTE ctlcode; // 15 + WORD audstatbits; + SECTOR_ADDR startloc; + SECTOR_ADDR endloc; +} IOCTLR_AUDSTAT_BLOCK, *PIOCTLR_AUDSTAT_BLOCK; + +#define AUDSTAT_PAUSED 1 + + +typedef struct _IOCTLW_LOCKDOOR_BLOCK { + BYTE ctlcode; // 1 + BYTE lockfunc; +} IOCTLW_LOCKDOOR_BLOCK, *PIOCTLW_LOCKDOOR_BLOCK; + + +typedef struct _IOCTLW_AUDINFO_BLOCK { + BYTE ctlcode; // 3 + BYTE chan0; + BYTE vol0; + BYTE chan1; + BYTE vol1; + BYTE chan2; + BYTE vol2; + BYTE chan3; + BYTE vol3; +} IOCTLW_AUDINFO_BLOCK, *PIOCTLW_AUDINFO_BLOCK; + + +typedef struct _IOCTLW_DRVBYTES_BLOCK { + BYTE ctlcode; // 4 + BYTE buffer; +} IOCTLW_DRVBYTES_BLOCK, *PIOCTLW_DRVBYTES_BLOCK; + + + +typedef struct _READ_LONG_BLOCK { + BYTE header[13]; + BYTE addrmode; + DWORD transaddr; + WORD numsect; + SECTOR_ADDR startsect; + BYTE readmode; + BYTE ileavesize; + BYTE ileaveskip; +} READ_LONG_BLOCK, *PREAD_LONG_BLOCK; + + +typedef struct _SEEK_BLOCK { + BYTE header[13]; + BYTE addrmode; + DWORD transaddr; + WORD numsect; + SECTOR_ADDR startsect; +} SEEK_BLOCK, *PSEEK_BLOCK; + + +typedef struct _PLAY_AUDIO_BLOCK { + BYTE header[13]; + BYTE addrmode; + SECTOR_ADDR startsect; + DWORD numsect; +} PLAY_AUDIO_BLOCK, *PPLAY_AUDIO_BLOCK; + + +typedef struct _WRITE_LONG_BLOCK { + BYTE header[13]; + BYTE addrmode; + DWORD transaddr; + WORD numsect; + SECTOR_ADDR startsect; + BYTE readmode; + BYTE ileavesize; + BYTE ileaveskip; +} WRITE_LONG_BLOCK, *PWRITE_LONG_BLOCK; + + +#pragma pack() + diff --git a/private/mvdm/vdd/samples/mscdex/vdd/sources b/private/mvdm/vdd/samples/mscdex/vdd/sources new file mode 100644 index 000000000..c9a9f09c5 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/sources @@ -0,0 +1,27 @@ +INDENTED_DIRECTIVES=1 + +MAJORCOMP=vdd +MINORCOMP=vcdex + +TARGETNAME=vcdex +TARGETPATH=obj +TARGETTYPE=DYNLINK +TARGETLIBS=$(_NTDRIVE)\nt\public\sdk\lib\*\kernel32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\user32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\ntvdm.lib + +DLLENTRY=VDDInitialize +DLLBASE=0x2000000 + +# we don't use any CRT +USE_NOLIBS=1 + +SOURCES=vcdex.c VCDEX.RC + +C_DEFINES=-DWIN_32 + +UMTYPE=windows +UMTEST= +UMLIBS= +UMRES=Obj\*\VCDEX.Res + diff --git a/private/mvdm/vdd/samples/mscdex/vdd/vcdex.c b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.c new file mode 100644 index 000000000..0d7895855 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.c @@ -0,0 +1,1474 @@ +/*++ + +Copyright (c) 1991, Microsoft Corporation + +Module Name: + + vcdex.c + +Abstract: + + Virtual Device Driver for MSCDEX + +Environment: + + NT-MVDM (User Mode VDD) + +Author: + + Neil Sandlin (neilsa), 3/20/93 + +Notes: + + Implementation Restrictions- + + Currently, the starting and ending locations returned by the mscdex + "audio status info" are not returned by NT drivers. This makes it + difficult to maintain these values when the calling applications + exit, or when multiple applications are controlling a single drive. + + Currently, this implementation does not validate the length argument of + the IOCTL calls. This needs to be added for robustness, but will not + affect well-behaved apps. + + +Revision History: + + + +--*/ + +// +// Include files. +// + +#include "windows.h" +#include "winerror.h" +#include <vddsvc.h> +#include <mscdex.h> +#include "devioctl.h" +#include "ntddcdrm.h" +#include "ntdddisk.h" +#include "vcdex.h" + +// +// Global variables. +// + +PFNSVC apfnSVC [] = { + ApiGetNumberOfCDROMDrives, + ApiGetCDROMDriveList, + ApiGetCopyrightFileName, + ApiGetAbstractFileName, + ApiGetBDFileName, + ApiReadVTOC, + ApiReserved, + ApiReserved, + ApiAbsoluteDiskRead, + ApiAbsoluteDiskWrite, + ApiReserved, + ApiCDROMDriveCheck, + ApiMSCDEXVersion, + ApiGetCDROMDriveLetters, + ApiGetSetVolDescPreference, + ApiGetDirectoryEntry, + ApiSendDeviceRequest +}; + +PDRIVE_INFO DrivePointers[MAXDRIVES]; +PDRIVE_INFO DrvInfo; +LPREQUESTHEADER VdmReq; // for "send device request" +USHORT NumDrives = 0, FirstDrive = 0xff; +DWORD DeviceHeader; // for "get CDROM drive list" +BYTE LastRealStatus = AUDIO_STATUS_NO_STATUS; + +#define IS_DRIVE_CDROM(drive) \ + (drive < MAXDRIVES && DrivePointers[drive] != NULL) + + +HANDLE hVdd; +HANDLE hProcessHeap; + + + +VOID UserBlockHook(VOID); +VOID UserTerminateHook(USHORT); + + + +BOOL +VDDInitialize( + HANDLE hDll, + DWORD dwReason, + LPVOID lpReserved + ) + +/*++ + +Routine Description: + + The entry point for the Vdd which handles intialization and termination. + +Arguments: + + hVdd - The handle to the VDD + + Reason - flag word thatindicates why Dll Entry Point was invoked + + lpReserved - Unused + +Return Value: + BOOL bRet - if (dwReason == DLL_PROCESS_ATTACH) + TRUE - Dll Intialization successful + FALSE - Dll Intialization failed + else + always returns TRUE +--*/ + +{ + int i; + + switch ( dwReason ) { + + case DLL_PROCESS_ATTACH: + hVdd = hDll; + hProcessHeap = GetProcessHeap(); + + DisableThreadLibraryCalls(hDll); + + DebugPrint (DEBUG_MOD, "VCDEX: Process Attach\n"); + break; + + case DLL_PROCESS_DETACH: + + for (i=0; i<MAXDRIVES; i++) + + if (DrivePointers[i] != NULL) { + + if (DrivePointers[i]->Handle != INVALID_HANDLE_VALUE) { + CloseHandle(DrivePointers[i]->Handle); + } + HeapFree(hProcessHeap, 0, DrivePointers[i]); + + } + + DebugPrint (DEBUG_MOD, "VCDEX: Process Detach\n"); + break; + + default: + + break; + + } + + return TRUE; + +} + + + +VOID +VDDRegisterInit( + VOID + ) +/*++ + +Routine Description: + + This routine is called when the MSCDEXNT TSR makes its RegisterModule + call. Most of the initialization is done here instead of in the + VDDInitialize routine to improve performance in the case where the + VDD is loaded, but not used. + + The main point of this routine is to search for CDROM drives and set + up an array of pointers to point to DRIVE_INFO structures. The array + is a fixed size array, one for each possible DOS drive. The structures + are allocated only if a CDROM drive exists at the corresponding drive + letter in the array. + + By doing a CreateFile() to the drive letter of the drive, a handle to + the SCSI CDROM class driver is returned. This handle is used for all + communication with the drive. + + + +Return Value: + + SUCCESS - Client carry is clear + Client CX = # of CDROM drives + + FAILURE - Client carry is set + +--*/ + + +{ + CHAR chRoot [] = "?:\\"; + USHORT i; + HANDLE hDriver; + PDRIVE_INFO drvp; + static BOOLEAN Initialized = FALSE; + + if (Initialized) { + setCF(0); + return; + } + + + // Make far pointer with offset zero (DX is para aligned) + DeviceHeader = (DWORD) ((getCX() << 16) + (getDX() << 12)); + + for (i=0; i<MAXDRIVES; i++) { + + chRoot[0] = i + 'A'; + + if (GetDriveType((LPSTR) chRoot) == DRIVE_CDROM) { + + hDriver = OpenPhysicalDrive(i); + + if (hDriver != INVALID_HANDLE_VALUE) { + + drvp = (PDRIVE_INFO)HeapAlloc(hProcessHeap, + 0, + sizeof(DRIVE_INFO) + ); + + if(drvp == NULL) { + DebugPrint (DEBUG_MOD, "VCDEX: Out of memory on initializetion\n"); + Initialized = FALSE; + setCF(1); + return; + } + + DrivePointers[i] = drvp; + drvp->Handle = hDriver; + drvp->DriveNum = i; + drvp->ValidVTOC = FALSE; + drvp->MediaStatus = MEDCHNG_CHANGED; + + drvp->PlayStart.dw = 0; + drvp->PlayCount = 0; + GetAudioStatus (drvp); + + NumDrives++; + if (FirstDrive == 0xff) + FirstDrive = i; + + + // + // Keep the handle close until app really wants to use it + // + drvp->Handle = INVALID_HANDLE_VALUE; + CloseHandle(hDriver); + + + } else { + DrivePointers[i] = NULL; + } + + } + + } + + if (NumDrives == 0) { + + setCF(1); + + } else { + PDEVICE_HEADER pDev = (PDEVICE_HEADER) GetVDMPointer( + ((ULONG)getCX()<<16)+getDX(), + 1, FALSE); + + // Put the first valid cdrom drive number in the device header + pDev->drive = FirstDrive+1; + + VDDInstallUserHook(hVdd, NULL, UserTerminateHook, UserBlockHook, NULL); + + DebugPrint (DEBUG_MOD, "VCDEX: Initialized\n"); + Initialized = TRUE; + + setCF(0); + + } + + return; +} + + +VOID UserTerminateHook(USHORT Pdb) +{ + UserBlockHook(); +} + + +VOID UserBlockHook(VOID) +{ + + int DrvNum; + + DrvNum = MAXDRIVES; + while (DrvNum--) { + if (DrivePointers[DrvNum] && + DrivePointers[DrvNum]->Handle != INVALID_HANDLE_VALUE ) + { + CloseHandle(DrivePointers[DrvNum]->Handle); + DrivePointers[DrvNum]->Handle = INVALID_HANDLE_VALUE; + } + } +} + + + + + + + + + +VOID +VDDDispatch( + VOID + ) +/*++ + +Routine Description: + + This is the main MSCDEX api function dispatcher. When this routine + is entered, an int2f has just been executed. Client registers are + set to what they were at the time of the call with the exception + of AX, which must contain a handle for the DispatchCall(). The + value of AX was pushed on the stack. So, this routine restores it, + and uses AL to index into the function call table apfnSVC[]. + + +Return Value: + + SUCCESS - Client carry is clear + FAILURE - Client carry is set + +--*/ + +{ + + LPWORD VdmWordPtr; + WORD VdmAX; + ULONG VdmAddress; + + // + // The TSR pushes AX on the stack. Pick up the value here + // + + VdmAddress = ( getSS() << 16 ) | getSP(); + + VdmWordPtr = (LPWORD) GetVDMPointer ( VdmAddress, 2, FALSE); + + VdmAX = *VdmWordPtr; + + // + // AL has the MSCDEX function code + // + setAX (VdmAX); //restore AX + + (apfnSVC [VdmAX & 0xFF])(); + + return; +} + + + +/**************************************************************************** + + MSCDEX API SUBROUTINES + + The following routines perform the individual functions specified by + the MSCDEX extensions. + + + ****************************************************************************/ +VOID +ApiReserved( + VOID + ) + +{ + + DebugFmt (DEBUG_API, "VCDEX: Reserved Function call, ax=%.4X\n", getAX()); + +} + + +VOID +ApiGetNumberOfCDROMDrives( + VOID + ) + +{ + + DebugPrint (DEBUG_API, "VCDEX: Get # of CDROM drives\n"); + + setBX (NumDrives); + + if (NumDrives) + setCX (FirstDrive); + +} + + +VOID +ApiGetCDROMDriveList( + VOID + ) + +{ + + PDRIVE_DEVICE_LIST devlist, devlist0; + ULONG VdmAddress; + USHORT Drive; + BYTE Unit; + + DebugPrint (DEBUG_API, "VCDEX: Get CDROM drive list\n"); + + VdmAddress = ( getES() << 16 ) | getBX(); + devlist = devlist0 = (PDRIVE_DEVICE_LIST) GetVDMPointer (VdmAddress, + MAXDRIVES*sizeof(DRIVE_DEVICE_LIST), + FALSE); + + for (Drive=0, Unit=0; Drive<MAXDRIVES; Drive++) + if (DrivePointers[Drive] != NULL) { + devlist->Unit = Unit; + devlist->DeviceHeader = DeviceHeader; + devlist++; + Unit++; + } + + FreeVDMPointer (VdmAddress, + MAXDRIVES*sizeof(DRIVE_DEVICE_LIST), + devlist0, + FALSE); + + +} + +VOID +ApiGetCopyrightFileName( + VOID + ) +{ + ULONG VdmAddress; + LPBYTE fnBuffer; + + DebugPrint (DEBUG_API, "VCDEX: Get Copyright File Name\n"); + + if (!IS_DRIVE_CDROM(getCX())) { // Is drive CDROM? + setAX (15); // no + setCF (1); + } + + VdmAddress = ( getES() << 16 ) | getBX(); + fnBuffer = (LPBYTE) GetVDMPointer (VdmAddress, 38, FALSE); + + *fnBuffer = 0; // currently not implemented + + FreeVDMPointer (VdmAddress, 38, fnBuffer, FALSE); + +} + +VOID +ApiGetAbstractFileName( + VOID + ) +{ + + ULONG VdmAddress; + LPBYTE fnBuffer; + + DebugPrint (DEBUG_API, "VCDEX: Get Abstract File Name\n"); + + if (!IS_DRIVE_CDROM(getCX())) { // Is drive CDROM? + setAX (15); // no + setCF (1); + } + + VdmAddress = ( getES() << 16 ) | getBX(); + fnBuffer = (LPBYTE) GetVDMPointer (VdmAddress, 38, FALSE); + + *fnBuffer = 0; // currently not implemented + + FreeVDMPointer (VdmAddress, 38, fnBuffer, FALSE); + +} + + +VOID +ApiGetBDFileName( + VOID + ) +{ + + ULONG VdmAddress; + LPBYTE fnBuffer; + + DebugPrint (DEBUG_API, "VCDEX: Get Bibliographic Doc File Name\n"); + + if (!IS_DRIVE_CDROM(getCX())) { // Is drive CDROM? + setAX (15); // no + setCF (1); + } + + VdmAddress = ( getES() << 16 ) | getBX(); + fnBuffer = (LPBYTE) GetVDMPointer (VdmAddress, 38, FALSE); + + *fnBuffer = 0; // currently not implemented + + FreeVDMPointer (VdmAddress, 38, fnBuffer, FALSE); + +} + +VOID +ApiReadVTOC( + VOID + ) +{ + + DebugPrint (DEBUG_API, "VCDEX: Read VTOC\n"); + setCF(1); // currently not implemented + +} + + + +VOID +ApiAbsoluteDiskRead( + VOID + ) +{ + + DebugPrint (DEBUG_API, "VCDEX: Absolute Disk Read\n"); + setCF(1); // currently not implemented + +} + +VOID +ApiAbsoluteDiskWrite( + VOID + ) +{ + DebugPrint (DEBUG_API, "VCDEX: Absolute Disk Write\n"); + setCF(1); // read only +} + + +VOID +ApiCDROMDriveCheck( + VOID + ) + +{ + + DebugPrint (DEBUG_API, "VCDEX: CDROM drive check\n"); + + setBX (0xADAD); // MSCDEX Signature + + if (IS_DRIVE_CDROM(getCX())) // is CD ROM drive + setAX (1); // yes + else + setAX (0); // no + +} + +VOID +ApiMSCDEXVersion( + VOID + ) + +{ + DebugPrint (DEBUG_API, "VCDEX: MSCDEX Version\n"); + setBX (MSCDEX_VERSION); // MSCDEX Version # + +} + +VOID +ApiGetCDROMDriveLetters( + VOID + ) + +{ + ULONG VdmAddress; + LPBYTE VdmPtr, VdmPtr0; + USHORT Drive; + + DebugPrint (DEBUG_API, "VCDEX: Get CDROM Drive Letters\n"); + + VdmAddress = (getES() << 16) | getBX(); + VdmPtr = VdmPtr0 = (LPBYTE) GetVDMPointer (VdmAddress, MAXDRIVES, FALSE); + + for (Drive=0; Drive<MAXDRIVES; Drive++) + if (DrivePointers[Drive] != NULL) + *VdmPtr++ = (BYTE) Drive; + + FreeVDMPointer (VdmAddress, MAXDRIVES, VdmPtr0, FALSE); + +} + + +VOID +ApiGetSetVolDescPreference( + VOID + ) +{ + + DebugPrint (DEBUG_API, "VCDEX: Set Volume Descriptor Preference\n"); + setCF(1); // currently not implemented + +} + +VOID +ApiGetDirectoryEntry( + VOID + ) +{ + + DebugPrint (DEBUG_API, "VCDEX: Get Directory Entry\n"); + setCF(1); // currently not implemented + +} + + + +VOID +ApiSendDeviceRequest( + VOID + ) +{ + + ULONG VdmAddress; + BOOL Success; + DWORD BytesReturned; + DWORD absStart, absEnd; + int DrvNum; + + VdmAddress = ( getES() << 16 ) | getBX(); + VdmReq = (LPREQUESTHEADER) GetVDMPointer (VdmAddress, + sizeof (REQUESTHEADER), + FALSE); + + + DebugFmt (DEBUG_IO, ">RQ %d ", (DWORD) VdmReq->rhFunction); + + DrvNum = getCX(); + + if (!IS_DRIVE_CDROM(DrvNum)) { + VdmReq->rhStatus = CDSTAT_ERROR | CDSTAT_DONE | CDERR_UNKNOWN_UNIT; + return; + + } + + DrvInfo = DrivePointers[DrvNum]; + + if (DrvInfo->Handle == INVALID_HANDLE_VALUE) { + DrvInfo->Handle = OpenPhysicalDrive(DrvInfo->DriveNum); + if (DrvInfo->Handle == INVALID_HANDLE_VALUE) { + VdmReq->rhStatus = CDSTAT_ERROR | CDSTAT_DONE | CDERR_UNKNOWN_UNIT; + HeapFree(hProcessHeap, 0, DrvInfo); + DrivePointers[DrvNum] = NULL; + NumDrives--; + if (FirstDrive == DrvNum) { + FirstDrive = 0xff; + while (++DrvNum < MAXDRIVES) { + if (DrivePointers[DrvNum]) { + FirstDrive = DrvNum; + break; + } + } + } + + return; + } + } + + + GetAudioStatus (DrvInfo); + + if (DrvInfo->Playing) + VdmReq->rhStatus |= CDSTAT_BUSY; + + switch (VdmReq->rhFunction) { + + case IOCTL_READ: + + IOCTLRead(); + + break; + + case IOCTL_WRITE: + + IOCTLWrite(); + + break; + + case INPUT_FLUSH: + case OUTPUT_FLUSH: + case DEVICE_OPEN: + case DEVICE_CLOSE: + case READ_LONG: + case READ_LONG_PREFETCH: + case SEEK: + DebugPrint (DEBUG_API, "Unsupported MSCDEX Device Request\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + break; + + case PLAY_AUDIO: { + + CDROM_PLAY_AUDIO_MSF PlayAudioMSF; + PPLAY_AUDIO_BLOCK playreq = (PPLAY_AUDIO_BLOCK) VdmReq; + + if (playreq->addrmode == MODE_HSG) { + + absStart = playreq->startsect.dw; + PlayAudioMSF.StartingM = (BYTE) (absStart / (75 * 60)); + PlayAudioMSF.StartingS = (BYTE) ((absStart / 75) % 60); + PlayAudioMSF.StartingF = (BYTE) (absStart % 75); + + } else if (playreq->addrmode == MODE_REDBOOK) { + + PlayAudioMSF.StartingM = playreq->startsect.b[2]; + PlayAudioMSF.StartingS = playreq->startsect.b[1]; + PlayAudioMSF.StartingF = playreq->startsect.b[0]; + + absStart = (PlayAudioMSF.StartingM * 75 * 60) + + (PlayAudioMSF.StartingS * 75) + + (PlayAudioMSF.StartingF); + } else { + + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_PARAMETER; + break; + + } + + absEnd = absStart + playreq->numsect - 1; + + PlayAudioMSF.EndingM = (BYTE) (absEnd / (75 * 60)); + PlayAudioMSF.EndingS = (BYTE) ((absEnd / 75) % 60); + PlayAudioMSF.EndingF = (BYTE) (absEnd % 75); + + DebugPrint (DEBUG_IO, "Play "); + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_PLAY_AUDIO_MSF, + (LPVOID) &PlayAudioMSF, + sizeof (CDROM_PLAY_AUDIO_MSF), + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + + ProcessError (DrvInfo, PLAY_AUDIO,0); + + else { + + DrvInfo->Playing = TRUE; + DrvInfo->Paused = FALSE; + DrvInfo->PlayStart.dw = playreq->startsect.dw; + DrvInfo->PlayCount = playreq->numsect; + + } + + break; + } + + case STOP_AUDIO: + + if (DrvInfo->Playing) { + + DebugPrint (DEBUG_IO, "Pause "); + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_PAUSE_AUDIO, + (LPVOID) NULL, 0, + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + + ProcessError (DrvInfo, STOP_AUDIO,0); + + else { + DrvInfo->Playing = FALSE; + DrvInfo->Paused = TRUE; + } + + } else { + + DebugPrint (DEBUG_IO, "Stop "); + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_STOP_AUDIO, + (LPVOID) NULL, 0, + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + // Fake out GetAudioStatus to simulate stop + DrvInfo->Playing = FALSE; + DrvInfo->Paused = FALSE; + LastRealStatus = AUDIO_STATUS_PLAY_COMPLETE; + + if (!Success) { + DWORD dwErr; + + dwErr = GetLastError(); + if (dwErr == ERROR_MR_MID_NOT_FOUND || + dwErr == ERROR_NO_MEDIA_IN_DRIVE ) + { + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + } + } + + } + + break; + + case WRITE_LONG: + case WRITE_LONG_VERIFY: + + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_WRITE_PROTECT; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + break; + + case RESUME_AUDIO: + + if (DrvInfo->Paused) { + + DebugPrint (DEBUG_IO, "Resume "); + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_RESUME_AUDIO, + (LPVOID) NULL, 0, + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + + ProcessError (DrvInfo, RESUME_AUDIO,0); + + } else { + + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_GENERAL; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + } + + break; + + default: + DebugPrint (DEBUG_API, "Invalid MSCDEX Device Request\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + } + + VdmReq->rhStatus |= CDSTAT_DONE; + + DebugFmt (DEBUG_IO, ": %.4X ", VdmReq->rhStatus); + +} + +VOID +IOCTLRead( + VOID + ) + +{ + + LPBYTE Buffer; + BOOL Success; + DWORD BytesReturned; + + Buffer = GetVDMPointer ((ULONG)VdmReq->irwrBuffer, 16, FALSE); + + DebugFmt (DEBUG_IO, "iord %d ", (DWORD) *Buffer); + + switch (*Buffer) { + + case IOCTLR_AUDINFO: { + + PIOCTLR_AUDINFO_BLOCK audinfo = (PIOCTLR_AUDINFO_BLOCK) Buffer; + VOLUME_CONTROL VolumeControl; + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_GET_VOLUME, + (LPVOID) NULL, 0, + (LPVOID) &VolumeControl, + sizeof (VOLUME_CONTROL), + &BytesReturned, (LPVOID) NULL); + + if (Success) { + + // no support for input=>output channel manipulation + audinfo->chan0 = 0; + audinfo->chan1 = 1; + audinfo->chan2 = 2; + audinfo->chan3 = 3; + + audinfo->vol0 = VolumeControl.PortVolume[0]; + audinfo->vol1 = VolumeControl.PortVolume[1]; + audinfo->vol2 = VolumeControl.PortVolume[2]; + audinfo->vol3 = VolumeControl.PortVolume[3]; + + } else { + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + } + + break; + } + + case IOCTLR_DEVSTAT: { + + PIOCTLR_DEVSTAT_BLOCK devstat = (PIOCTLR_DEVSTAT_BLOCK) Buffer; + + devstat->devparms = DEVSTAT_DOOR_UNLOCKED | + DEVSTAT_SUPPORTS_RBOOK; + + + if (!DrvInfo->StatusAvailable) { + + DrvInfo->MediaStatus = MEDCHNG_CHANGED; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + switch (DrvInfo->LastError) { + case ERROR_NO_MEDIA_IN_DRIVE: + devstat->devparms |= DEVSTAT_NO_DISC | + DEVSTAT_DOOR_OPEN; + + DebugFmt (DEBUG_STATUS, ":%.4X ", devstat->devparms); + + break; + //BUGBUG case for recently inserted (80000016) - see below + } + + break; + } + + if (!(DrvInfo->current.Control & AUDIO_DATA_TRACK)) + devstat->devparms |= DEVSTAT_PLAYS_AV; + + break; + } + + case IOCTLR_VOLSIZE: { + + PIOCTLR_VOLSIZE_BLOCK volsize = (PIOCTLR_VOLSIZE_BLOCK) Buffer; + PTRACK_DATA Track; + PCDROM_TOC cdromtoc; + + if ((cdromtoc = ReadTOC (DrvInfo))!=NULL) { + + Track = &cdromtoc->TrackData[cdromtoc->LastTrack]; + + volsize->size = (DWORD) ( (Track->Address[1]*60*75) + + (Track->Address[2]*75) + + Track->Address[3] ); + + } + break; + } + + case IOCTLR_MEDCHNG: { + + PIOCTLR_MEDCHNG_BLOCK medptr = (PIOCTLR_MEDCHNG_BLOCK) Buffer; + BYTE status = DrvInfo->MediaStatus; + + if (status == MEDCHNG_NOT_CHANGED) { + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_CHECK_VERIFY, + (LPVOID) NULL, 0, + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (Success) + + medptr->medbyte = MEDCHNG_NOT_CHANGED; + + else { + + medptr->medbyte = MEDCHNG_CHANGED; + DrvInfo->MediaStatus = MEDCHNG_CHANGED; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + } + + } else + medptr->medbyte = DrvInfo->MediaStatus; + + break; + } + + case IOCTLR_DISKINFO: { + + PIOCTLR_DISKINFO_BLOCK diskinfo = (PIOCTLR_DISKINFO_BLOCK) Buffer; + PTRACK_DATA Track; + PCDROM_TOC cdromtoc; + + if ((cdromtoc = ReadTOC (DrvInfo))!=NULL) { + diskinfo->tracklow = cdromtoc->FirstTrack; + diskinfo->trackhigh = cdromtoc->LastTrack; + + Track = &cdromtoc->TrackData[cdromtoc->LastTrack]; + + diskinfo->startleadout.b[0] = Track->Address[3]; + diskinfo->startleadout.b[1] = Track->Address[2]; + diskinfo->startleadout.b[2] = Track->Address[1]; + diskinfo->startleadout.b[3] = Track->Address[0]; + + } else { + + // zeroes apparently needed when not there physically + diskinfo->tracklow = 0; + diskinfo->trackhigh = 0; + diskinfo->startleadout.dw = 0; + + } + break; + } + + case IOCTLR_TNOINFO: { + + PIOCTLR_TNOINFO_BLOCK tnoinfo = (PIOCTLR_TNOINFO_BLOCK) Buffer; + PTRACK_DATA Track; + PCDROM_TOC cdromtoc; + + if ((cdromtoc = ReadTOC (DrvInfo))!=NULL) { + + if (tnoinfo->trknum > cdromtoc->LastTrack) { + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_SECT_NOTFOUND; + break; + } + + Track = &cdromtoc->TrackData[tnoinfo->trknum-1]; + tnoinfo->start.b[0] = Track->Address[3]; + tnoinfo->start.b[1] = Track->Address[2]; + tnoinfo->start.b[2] = Track->Address[1]; + tnoinfo->start.b[3] = Track->Address[0]; + + tnoinfo->trkctl = Track->Control; + } + + break; + } + + case IOCTLR_QINFO: { + + PIOCTLR_QINFO_BLOCK qinfo = (PIOCTLR_QINFO_BLOCK) Buffer; + + if (DrvInfo->StatusAvailable) { + + qinfo->ctladr = DrvInfo->current.Control | DrvInfo->current.ADR<<4; + qinfo->trknum = DrvInfo->current.TrackNumber; + qinfo->pointx = DrvInfo->current.IndexNumber; + qinfo->min = DrvInfo->current.TrackRelativeAddress[1]; + qinfo->sec = DrvInfo->current.TrackRelativeAddress[2]; + qinfo->frame = DrvInfo->current.TrackRelativeAddress[3]; + + qinfo->zero = DrvInfo->current.AbsoluteAddress[0]; + qinfo->apmin = DrvInfo->current.AbsoluteAddress[1]; + qinfo->apsec = DrvInfo->current.AbsoluteAddress[2]; + qinfo->apframe = DrvInfo->current.AbsoluteAddress[3]; + + } else { + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + } + + break; + } + + case IOCTLR_UPCCODE: { + + PIOCTLR_UPCCODE_BLOCK upccode = (PIOCTLR_UPCCODE_BLOCK) Buffer; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + static CDROM_SUB_Q_DATA_FORMAT subqfmt = {IOCTL_CDROM_MEDIA_CATALOG}; + int i; + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_READ_Q_CHANNEL, + (LPVOID) &subqfmt, + sizeof (CDROM_SUB_Q_DATA_FORMAT), + (LPVOID) &MediaCatalog, + sizeof (SUB_Q_MEDIA_CATALOG_NUMBER), + &BytesReturned, (LPVOID) NULL); + + if (!Success) + + ProcessError (DrvInfo, IOCTL_READ, IOCTLR_UPCCODE); + + else { + + if (MediaCatalog.Mcval) { + + // The author is uncertain that this is the correct method, + // but it appears to work empirically. + for (i=0; i<7; i++) + upccode->upcean[i] = MediaCatalog.MediaCatalog[i]; + + } else + + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_SECT_NOTFOUND; + + } + + break; + } + + case IOCTLR_AUDSTAT: { + PIOCTLR_AUDSTAT_BLOCK audstat = (PIOCTLR_AUDSTAT_BLOCK) Buffer; + + audstat->audstatbits = 0; + + if (DrvInfo->Paused) + audstat->audstatbits |= AUDSTAT_PAUSED; + + audstat->startloc.dw = DrvInfo->PlayStart.dw; + audstat->endloc.dw = DrvInfo->PlayCount; + + break; + } + + + case IOCTLR_RADDR: + case IOCTLR_LOCHEAD: + case IOCTLR_ERRSTAT: + case IOCTLR_DRVBYTES: + case IOCTLR_SECTSIZE: + case IOCTLR_SUBCHANINFO: + DebugPrint (DEBUG_API, "Unsupported MSCDEX IOCTL Read\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + break; + + default: + DebugPrint (DEBUG_API, "Invalid MSCDEX IOCTL Read\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + } +} + +VOID +IOCTLWrite( + VOID + ) + +{ + LPBYTE Buffer; + BOOL Success; + DWORD BytesReturned; + + Buffer = GetVDMPointer ((ULONG)VdmReq->irwrBuffer, 16, FALSE); + + DebugFmt (DEBUG_IO, "iowt %d ", (DWORD) *Buffer); + + switch (*Buffer) { + + case IOCTLW_EJECT: + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_EJECT_MEDIA, + (LPVOID) NULL, 0, + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + ProcessError (DrvInfo, IOCTL_WRITE, IOCTLW_EJECT); + break; + + case IOCTLW_LOCKDOOR: { + + PREVENT_MEDIA_REMOVAL MediaRemoval; + PIOCTLW_LOCKDOOR_BLOCK lockdoor = (PIOCTLW_LOCKDOOR_BLOCK) Buffer; + + MediaRemoval.PreventMediaRemoval = (BOOLEAN) lockdoor->lockfunc; + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_MEDIA_REMOVAL, + (LPVOID) &MediaRemoval, + sizeof(PREVENT_MEDIA_REMOVAL), + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + ProcessError (DrvInfo, IOCTL_WRITE, IOCTLW_LOCKDOOR); + break; + } + + case IOCTLW_AUDINFO: { + PIOCTLW_AUDINFO_BLOCK audinfo = (PIOCTLW_AUDINFO_BLOCK) Buffer; + VOLUME_CONTROL VolumeControl; + + // note: no support for input=>output channel manipulation + VolumeControl.PortVolume[0] = audinfo->vol0; + VolumeControl.PortVolume[1] = audinfo->vol1; + VolumeControl.PortVolume[2] = audinfo->vol2; + VolumeControl.PortVolume[3] = audinfo->vol3; + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_SET_VOLUME, + (LPVOID) &VolumeControl, + sizeof (VOLUME_CONTROL), + (LPVOID) NULL, 0, + &BytesReturned, (LPVOID) NULL); + + if (!Success) + ProcessError (DrvInfo, IOCTL_WRITE, IOCTLW_AUDINFO); + break; + } + + + + case IOCTLW_RESETDRV: + case IOCTLW_DRVBYTES: + case IOCTLW_CLOSETRAY: + DebugPrint (DEBUG_API, "Unsupported MSCDEX IOCTL Write\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + break; + + default: + DebugPrint (DEBUG_API, "Invalid MSCDEX IOCTL Write\n"); + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_UNKNOWN_CMD; + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + } + + +} + + +/************************************************************************** + + INTERNAL UTILITY ROUTINES + + **************************************************************************/ + +PCDROM_TOC +ReadTOC ( + PDRIVE_INFO DrvInfo + ) +/*++ + +Routine Description: + + Because several MSCDEX functions return information that is in the + Volume Table Of Contents (VTOC), this routine is called to cache + the TOC in the DRIVE_INFO structure. Subsequent operations that + request information from the VTOC will not have to get it from + the drive. + +Return Value: + + DWORD value from GetLastError() + +--*/ + +{ + BOOL Success = TRUE; + DWORD BytesReturned; + + if ((DrvInfo->ValidVTOC) && + (DrvInfo->MediaStatus == MEDCHNG_NOT_CHANGED)) + return(&DrvInfo->VTOC); + + Success = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_READ_TOC, + (LPVOID) NULL, 0, + (LPVOID) &DrvInfo->VTOC, sizeof (CDROM_TOC), + &BytesReturned, (LPVOID) NULL); + + if (!Success) { + DrvInfo->ValidVTOC = FALSE; + ProcessError (DrvInfo, 0, 0); + return (NULL); + } + + DrvInfo->ValidVTOC = TRUE; + DrvInfo->MediaStatus = MEDCHNG_NOT_CHANGED; + return (&DrvInfo->VTOC); + + +} + +BOOLEAN +GetAudioStatus( + PDRIVE_INFO DrvInfo + ) + +/*++ + + Because the AudioStatus byte does not statically reflect the difference + between paused and stopped, we have to try to watch for the transition + from one state to another to keep track of it. + +--*/ +{ + + static CDROM_SUB_Q_DATA_FORMAT subqfmt = {IOCTL_CDROM_CURRENT_POSITION}; + DWORD BytesReturned; + BYTE AudStat; + + DrvInfo->Paused = FALSE; + DrvInfo->Playing = FALSE; + + DrvInfo->StatusAvailable = DeviceIoControl (DrvInfo->Handle, + (DWORD) IOCTL_CDROM_READ_Q_CHANNEL, + (LPVOID) &subqfmt, + sizeof (CDROM_SUB_Q_DATA_FORMAT), + (LPVOID) &DrvInfo->current, + sizeof (SUB_Q_CURRENT_POSITION), + &BytesReturned, (LPVOID) NULL); + + if (DrvInfo->StatusAvailable) { + + AudStat = DrvInfo->current.Header.AudioStatus; + + DebugFmt (DEBUG_STATUS, "+%.2X ", AudStat); + + switch (AudStat) { + + case AUDIO_STATUS_IN_PROGRESS: + + DrvInfo->Paused = FALSE; + DrvInfo->Playing = TRUE; + LastRealStatus = AudStat; + break; + + case AUDIO_STATUS_PAUSED: + + if (LastRealStatus == AUDIO_STATUS_IN_PROGRESS) { + + DrvInfo->Playing = FALSE; + DrvInfo->Paused = TRUE; + + } + break; + + case AUDIO_STATUS_PLAY_ERROR: + case AUDIO_STATUS_PLAY_COMPLETE: + + DrvInfo->Paused = FALSE; + DrvInfo->Playing = FALSE; + LastRealStatus = AudStat; + break; + + } + + } else { + DrvInfo->LastError = GetLastError(); + } + + return (DrvInfo->StatusAvailable); + +} + + +DWORD +ProcessError( + PDRIVE_INFO DrvInfo, + USHORT Command, + USHORT Subcmd + ) +/*++ + +Routine Description: + + This routine is called when a DeviceIoControl() fails. The extended + error code is retrieved, and status bits are set according to the + operation that was in progress. + + The DriveInfo Handle is closed + + + BUGBUG: At the time of this writing, NT fails to remap status 80000016, + (when a disc is re-inserted into the drive). So the case for MID_NOT_FOUND + was added below. This should be changed to the appropriate code when + this error status is properly mapped. + + +Return Value: + + DWORD value from GetLastError() + +--*/ + + +{ + DWORD err; + + err = GetLastError(); + + DebugFmt (DEBUG_ERROR, "Err! %d, ", Command); + DebugFmt (DEBUG_ERROR, "%d: ", Subcmd); + DebugFmt (DEBUG_ERROR, "%.8X\n", err); + + switch (err) { + + case ERROR_MR_MID_NOT_FOUND: // To cover unmapped 80000016 + case ERROR_NO_MEDIA_IN_DRIVE: + + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_NOT_READY; + DrvInfo->MediaStatus = MEDCHNG_CHANGED; + break; + + default: + VdmReq->rhStatus = CDSTAT_ERROR | CDERR_GENERAL; + + } + + CloseHandle(DrvInfo->Handle); + DrvInfo->Handle = INVALID_HANDLE_VALUE; + + return (err); + +} + + + +HANDLE +OpenPhysicalDrive( + int DriveNum + ) +/*++ + +Routine Description: + + int DriveNum; Zero based (0 = A, 1 = B, 2 = C ...) + +Return Value: + + HANDLE Drive Handle as returned from CreateFile + +--*/ +{ + HANDLE hDrive; + CHAR chDrive [] = "\\\\.\\?:"; + + chDrive[4] = DriveNum + 'A'; + + hDrive = CreateFile (chDrive, + GENERIC_READ, + FILE_SHARE_READ, + (LPSECURITY_ATTRIBUTES) NULL, + OPEN_EXISTING, + 0, + (HANDLE) NULL); + + + return hDrive; +} diff --git a/private/mvdm/vdd/samples/mscdex/vdd/vcdex.def b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.def new file mode 100644 index 000000000..7ce282195 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.def @@ -0,0 +1,8 @@ +LIBRARY VCDEX + +DESCRIPTION 'MSCDEX Translation VDD for NT-MVDM' + +EXPORTS + VDDInitialize + VDDRegisterInit + VDDDispatch diff --git a/private/mvdm/vdd/samples/mscdex/vdd/vcdex.h b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.h new file mode 100644 index 000000000..db8633b5f --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.h @@ -0,0 +1,91 @@ + +#define MAXDRIVES 26 + +typedef VOID (*PFNSVC)(VOID); + +typedef struct _DRIVE_INFO { + HANDLE Handle; + USHORT DriveNum; + USHORT LogicalBlocksPerSecond; + BOOLEAN Playing; + BOOLEAN Paused; + BOOLEAN ValidVTOC; + BOOLEAN StatusAvailable; + DWORD LastError; + BYTE MediaStatus; + SECTOR_ADDR PlayStart; //BUGBUG zero on reset, new disc, play complete + DWORD PlayCount; + SUB_Q_CURRENT_POSITION current; + CDROM_TOC VTOC; +} DRIVE_INFO, *PDRIVE_INFO; + + +VOID ApiReserved (VOID); +VOID ApiGetNumberOfCDROMDrives (VOID); +VOID ApiGetCDROMDriveList (VOID); +VOID ApiGetCopyrightFileName (VOID); +VOID ApiGetAbstractFileName (VOID); +VOID ApiGetBDFileName (VOID); +VOID ApiReadVTOC (VOID); +VOID ApiAbsoluteDiskRead (VOID); +VOID ApiAbsoluteDiskWrite (VOID); +VOID ApiCDROMDriveCheck (VOID); +VOID ApiMSCDEXVersion (VOID); +VOID ApiGetCDROMDriveLetters (VOID); +VOID ApiGetSetVolDescPreference (VOID); +VOID ApiGetDirectoryEntry (VOID); +VOID ApiSendDeviceRequest (VOID); +VOID IOCTLRead (VOID); +VOID IOCTLWrite (VOID); + +PCDROM_TOC ReadTOC (PDRIVE_INFO DrvInfo); +BOOLEAN GetAudioStatus (PDRIVE_INFO DrvInfo); + +DWORD +ProcessError( + PDRIVE_INFO DrvInfo, + USHORT Command, + USHORT Subcmd + ); + +HANDLE +OpenPhysicalDrive( + int DriveNum + ); + + + + +#define DEBUG_MOD 0x01 +#define DEBUG_API 0x02 +#define DEBUG_IO 0x04 +#define DEBUG_STATUS 0x08 +#define DEBUG_ERROR 0x80 + +#ifdef DEBUG + +USHORT DebugLevel = 0; + +#define DebugPrint(LEVEL,STRING) \ + { \ + if (DebugLevel & LEVEL) \ + OutputDebugString (STRING); \ + } + +#define DebugFmt(LEVEL,STRING, PARM) \ + { \ + char szBuffer[80]; \ + if (DebugLevel & LEVEL) { \ + sprintf (szBuffer, STRING, PARM); \ + OutputDebugString (szBuffer); \ + } \ + } + +#else + +#define DebugPrint(LEVEL,STRING) {} +#define DebugFmt(LEVEL,STRING,PARM) {} + +#endif + + diff --git a/private/mvdm/vdd/samples/mscdex/vdd/vcdex.rc b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.rc new file mode 100644 index 000000000..f338bb2b1 --- /dev/null +++ b/private/mvdm/vdd/samples/mscdex/vdd/vcdex.rc @@ -0,0 +1,48 @@ +/* +** VCDEX.RC +** +** Ntverp.h defines several global values that don't need to be +** changed except for official releases such as betas, sdk updates, etc. +** +** Common.ver has the actual version resource structure that all these +** #defines eventually initialize. +*/ + +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DLL +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_UNKNOWN +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "32-bit MSCDEX Virtual Device Driver" +#define VER_INTERNALNAME_STR "VCDEX.DLL" +#define VER_ORIGINALFILENAME_STR "VCDEX.DLL" + +#include "common.ver" |