summaryrefslogtreecommitdiffstats
path: root/private/mvdm/vdd/samples/mscdex
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/vdd/samples/mscdex
downloadNT4.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/dirs23
-rw-r--r--private/mvdm/vdd/samples/mscdex/readme.txt22
-rw-r--r--private/mvdm/vdd/samples/mscdex/tsr/makefile49
-rw-r--r--private/mvdm/vdd/samples/mscdex/tsr/messages/usa/messages.inc2
-rw-r--r--private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.asm246
-rw-r--r--private/mvdm/vdd/samples/mscdex/tsr/mscdexnt.inc30
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/makefile11
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/mscdex.h313
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/sources27
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/vcdex.c1474
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/vcdex.def8
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/vcdex.h91
-rw-r--r--private/mvdm/vdd/samples/mscdex/vdd/vcdex.rc48
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"