CDROM part I

Eric Pouech eric.pouech at wanadoo.fr
Sat Jan 12 08:51:03 CST 2002


this patch is part of a 2 piece Wine modification. those patches are
intended to remove
the Wine cdrom.h interface and replace it with the NT way (meaning
letting devices, here cdrom, being
opened with "\\.\X:" names in CreateFile, and all manipulations being
done thru DeviceIoControl calls)

this first patch implements the interface on the kernel (in fact ntdll)
side
the second patch force the usage of the NT API throughout Wine code:
mcicda.drv and MSCDEX (int 2f)

from a function point of view, those patches enable also applications to
use the NT interface. The IOCTL for
reading sectors have also been added. They've been tested for cdda, and
ripping works great ;-)

the two patches must be applied together

the include/cdrom.h and misc/cdrom.c files become obsolete

A+
-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: cdrom_if
ChangeLog: change the wine internal/proprietary cdrom interface to the NT's model
	
	>>> Need to remove obsolete include/cdrom.h and misc/cdrom.c files <<<
	
GenDate: 2002/01/12 14:32:23 UTC
ModifiedFiles: dlls/ntdll/Makefile.in files/drive.c files/file.c include/file.h include/winioctl.h misc/Makefile.in win32/device.c
AddedFiles: dlls/ntdll/cdrom.c include/ntddcdrm.h include/ntddstor.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.21
diff -u -u -r1.21 Makefile.in
--- dlls/ntdll/Makefile.in	6 Jan 2002 18:38:46 -0000	1.21
+++ dlls/ntdll/Makefile.in	7 Jan 2002 20:02:48 -0000
@@ -6,6 +6,7 @@
 EXTRALIBS = $(LIBUNICODE)
 
 C_SRCS = \
+	cdrom.c \
 	critsection.c \
 	debugtools.c \
 	exception.c \
Index: files/drive.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/files/drive.c,v
retrieving revision 1.63
diff -u -u -r1.63 drive.c
--- files/drive.c	6 Nov 2001 20:57:18 -0000	1.63
+++ files/drive.c	12 Jan 2002 03:17:53 -0000
@@ -44,7 +44,6 @@
 #include "wine/winbase16.h"   /* for GetCurrentTask */
 #include "winerror.h"
 #include "drive.h"
-#include "cdrom.h"
 #include "file.h"
 #include "heap.h"
 #include "msdos.h"
@@ -52,6 +51,9 @@
 #include "task.h"
 #include "debugtools.h"
 #include "wine/server.h"
+#include "winioctl.h"
+#include "ntddstor.h"
+#include "ntddcdrm.h"
 
 DEFAULT_DEBUG_CHANNEL(dosfs);
 DECLARE_DEBUG_CHANNEL(file);
@@ -459,6 +461,40 @@
     return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
 }
 
+/******************************************************************
+ *		static WORD CDROM_Data_FindBestVoldesc
+ *
+ *
+ */
+static WORD CDROM_Data_FindBestVoldesc(int fd)
+{
+    BYTE cur_vd_type, max_vd_type = 0;
+    unsigned int offs, best_offs = 0, extra_offs = 0;
+    char sig[3];
+
+    for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
+    {
+        /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
+         * the volume label is displaced forward by 8
+         */
+        lseek(fd, offs + 11, SEEK_SET); /* check for non-ISO9660 signature */
+        read(fd, &sig, 3);
+        if ((sig[0] == 'R') && (sig[1] == 'O') && (sig[2]=='M'))
+        {
+            extra_offs = 8;
+        }
+        lseek(fd, offs + extra_offs, SEEK_SET);
+        read(fd, &cur_vd_type, 1);
+        if (cur_vd_type == 0xff) /* voldesc set terminator */
+            break;
+        if (cur_vd_type > max_vd_type)
+        {
+            max_vd_type = cur_vd_type;
+            best_offs = offs + extra_offs;
+        }
+    }
+    return best_offs;
+}
 
 /***********************************************************************
  *           DRIVE_ReadSuperblock
@@ -567,8 +603,103 @@
     return close (fd);
 }
 
+/******************************************************************
+ *		static HANDLE   CDROM_Open
+ *
+ *
+ */
+static HANDLE   CDROM_Open(int drive)
+{
+    char       root[6];
+
+    strcpy(root, "\\\\.\\A:");
+    root[4] += drive;
 
+    return CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+}
 
+/**************************************************************************
+ *                              CDROM_Data_GetLabel             [internal]
+ */
+DWORD CDROM_Data_GetLabel(int drive, char *label)
+{
+#define LABEL_LEN       32+1
+    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
+    WORD offs = CDROM_Data_FindBestVoldesc(dev);
+    WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
+    DWORD unicode_id = 0;
+ 
+    if (offs)
+    {
+        if ((lseek(dev, offs+0x58, SEEK_SET) == offs+0x58)
+        &&  (read(dev, &unicode_id, 3) == 3))
+        {
+            int ver = (unicode_id & 0xff0000) >> 16;
+ 
+            if ((lseek(dev, offs+0x28, SEEK_SET) != offs+0x28)
+            ||  (read(dev, &label_read, LABEL_LEN) != LABEL_LEN))
+                goto failure;
+ 
+            close(dev);
+            if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
+            &&  ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
+            { /* yippee, unicode */
+                int i;
+                WORD ch;
+                for (i=0; i<LABEL_LEN;i++)
+                { /* Motorola -> Intel Unicode conversion :-\ */
+                     ch = label_read[i];
+                     label_read[i] = (ch << 8) | (ch >> 8);
+                }
+                WideCharToMultiByte( CP_ACP, 0, label_read, -1, label, 12, NULL, NULL );
+                label[11] = 0;
+            }
+            else
+            {
+                strncpy(label, (LPSTR)label_read, 11);
+                label[11] = '\0';
+            }
+            return 1;
+        }
+    }
+failure:
+    close(dev);
+    ERR("error reading label !\n");
+    return 0;
+}
+
+/**************************************************************************
+ *				CDROM_GetLabel			[internal]
+ */
+static DWORD CDROM_GetLabel(int drive, char *label)
+{
+    HANDLE              h = CDROM_Open(drive);
+    CDROM_DISK_DATA     cdd;
+    DWORD               br;
+    DWORD               ret = 1;
+
+    if (!h || !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+        return 0;
+
+    switch (cdd.DiskData & 0x03)
+    {
+    case CDROM_DISK_DATA_TRACK:
+        if (!CDROM_Data_GetLabel(drive, label))
+            ret = 0;
+    case CDROM_DISK_AUDIO_TRACK:
+        strcpy(label, "Audio CD   ");
+        break;
+    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
+        FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
+        /* fall through */
+    case 0:
+        ret = 0;
+        break;
+    }
+    TRACE("CD: label is '%s'.\n", label);
+
+    return ret;
+}
 /***********************************************************************
  *           DRIVE_GetLabel
  */
@@ -605,6 +736,132 @@
 	DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
 }
 
+#define CDFRAMES_PERSEC                 75
+#define CDFRAMES_PERMIN                 (CDFRAMES_PERSEC * 60)
+#define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
+#define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
+
+/**************************************************************************
+ *                              CDROM_Audio_GetSerial           [internal]
+ */
+static DWORD CDROM_Audio_GetSerial(HANDLE h)
+{
+    unsigned long serial = 0;
+    int i;
+    WORD wMagic;
+    DWORD dwStart, dwEnd, br;
+    CDROM_TOC toc;
+
+    if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0))
+        return 0;
+
+    /*
+     * wMagic collects the wFrames from track 1
+     * dwStart, dwEnd collect the beginning and end of the disc respectively, in
+     * frames.
+     * There it is collected for correcting the serial when there are less than
+     * 3 tracks.
+     */
+    wMagic = toc.TrackData[0].Address[2];
+    dwStart = FRAME_OF_TOC(toc, toc.FirstTrack);
+
+    for (i = 0; i <= toc.LastTrack - toc.FirstTrack; i++) {
+        serial += (toc.TrackData[i].Address[0] << 16) | 
+            (toc.TrackData[i].Address[1] << 8) | toc.TrackData[i].Address[2];
+    }
+    dwEnd = FRAME_OF_TOC(toc, toc.LastTrack + 1);
+ 
+    if (toc.LastTrack - toc.FirstTrack + 1 < 3)
+        serial += wMagic + (dwEnd - dwStart);
+
+    return serial;
+}
+
+/**************************************************************************
+ *                              CDROM_Data_GetSerial            [internal]
+ */
+static DWORD CDROM_Data_GetSerial(int drive)
+{
+    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
+    WORD offs;
+    union {
+        unsigned long val;
+        unsigned char p[4];
+    } serial;
+    BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
+ 
+
+    if (dev == -1) return 0;
+    offs = CDROM_Data_FindBestVoldesc(dev);
+
+    serial.val = 0;
+    if (offs)
+    {
+        BYTE buf[2048];
+        OSVERSIONINFOA ovi;
+        int i;
+ 
+        lseek(dev, offs, SEEK_SET);
+        read(dev, buf, 2048);
+        /*
+         * OK, another braindead one... argh. Just believe it.
+         * Me$$ysoft chose to reverse the serial number in NT4/W2K.
+         * It's true and nobody will ever be able to change it.
+         */
+        ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+        GetVersionExA(&ovi);
+        if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&  (ovi.dwMajorVersion >= 4))
+        {
+            b0 = 3; b1 = 2; b2 = 1; b3 = 0;
+        }
+        for (i = 0; i < 2048; i += 4)
+        {
+            /* DON'T optimize this into DWORD !! (breaks overflow) */
+            serial.p[b0] += buf[i+b0];
+            serial.p[b1] += buf[i+b1];
+            serial.p[b2] += buf[i+b2];
+            serial.p[b3] += buf[i+b3];
+        }
+    }
+    close(dev);
+    return serial.val;
+}
+        
+/**************************************************************************
+ *				CDROM_GetSerial			[internal]
+ */
+static DWORD CDROM_GetSerial(int drive)
+{
+    DWORD               serial = 0;
+    HANDLE              h = CDROM_Open(drive);
+    CDROM_DISK_DATA     cdd;
+    DWORD               br;
+
+    if (!h || ! !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+        return 0;
+
+    switch (cdd.DiskData & 0x03)
+    {
+    case CDROM_DISK_DATA_TRACK:
+        /* hopefully a data CD */
+        serial = CDROM_Data_GetSerial(drive);
+        break;
+    case CDROM_DISK_AUDIO_TRACK:
+        /* fall thru */
+    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
+        serial = CDROM_Audio_GetSerial(h);
+        break;
+    case 0:
+        break;
+    }
+    
+    if (serial)
+        TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial), LOWORD(serial));
+
+    CloseHandle(h);
+
+    return serial;
+}
 
 /***********************************************************************
  *           DRIVE_GetSerialNumber
@@ -612,7 +869,7 @@
 DWORD DRIVE_GetSerialNumber( int drive )
 {
     DWORD serial = 0;
-char buff[DRIVE_SUPER];
+    char buff[DRIVE_SUPER];
 
     if (!DRIVE_IsValid( drive )) return 0;
     
@@ -938,7 +1195,7 @@
     assert(s);
     ret = strlen(s) + 3; /* length of WHOLE current directory */
     if (ret >= buflen) return ret + 1;
-    lstrcpynA( buf, "A:\\", min( 4, buflen ) );
+    lstrcpynA( buf, "A:\\", min( 4u, buflen ) );
     if (buflen) buf[0] += DRIVE_GetCurrentDrive();
     if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 );
     return ret;
Index: files/file.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/files/file.c,v
retrieving revision 1.129
diff -u -u -r1.129 file.c
--- files/file.c	9 Jan 2002 20:30:51 -0000	1.129
+++ files/file.c	9 Jan 2002 22:50:30 -0000
@@ -449,6 +449,11 @@
             ret = FILE_OpenPipe(filename,access);
             goto done;
         }
+        else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
+        {
+            ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
+            goto done;
+        }
         else if (!DOSFS_GetDevice( filename ))
         {
             ret = DEVICE_Open( filename+4, access, sa );
Index: include/file.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/include/file.h,v
retrieving revision 1.36
diff -u -u -r1.36 file.h
--- include/file.h	7 Jan 2002 18:07:00 -0000	1.36
+++ include/file.h	12 Jan 2002 14:30:20 -0000
@@ -115,4 +115,10 @@
 /* win32/device.c */
 extern HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa );
 
+/* ntdll/cdrom.c.c */
+extern BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode, 
+                                  LPVOID lpInBuffer, DWORD nInBufferSize, 
+                                  LPVOID lpOutBuffer, DWORD nOutBufferSize,
+                                  LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
+
 #endif  /* __WINE_FILE_H */
Index: include/winioctl.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/include/winioctl.h,v
retrieving revision 1.7
diff -u -u -r1.7 winioctl.h
--- include/winioctl.h	25 Apr 1999 12:36:54 -0000	1.7
+++ include/winioctl.h	17 Dec 2001 06:41:02 -0000
@@ -150,7 +150,9 @@
 #define IOCTL_STORAGE_RESERVE            CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_STORAGE_RELEASE            CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_STORAGE_FIND_NEW_DEVICES   CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
-
+#define IOCTL_STORAGE_EJECTION_CONTROL   CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_MCN_CONTROL        CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS)
+ 
 #define IOCTL_STORAGE_GET_MEDIA_TYPES    CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
@@ -213,6 +215,81 @@
 #define PARTITION_LDM                   0x42      /* Logical Disk Manager partition */
 #define PARTITION_UNIX                  0x63      /* Unix */
 
+typedef enum _MEDIA_TYPE {
+    Unknown, F5_1Pt2_512, F3_1Pt44_512, F3_2Pt88_512, F3_20Pt8_512, F3_720_512, F5_360_512,
+    F5_320_512, F5_320_1024, F5_180_512, F5_160_512, RemovableMedia, FixedMedia, F3_120M_512,
+    F3_640_512, F5_640_512, F5_720_512, F3_1Pt2_512, F3_1Pt23_1024, F5_1Pt23_1024, F3_128Mb_512,
+    F3_230Mb_512, F8_256_128 
+} MEDIA_TYPE, *PMEDIA_TYPE;
+
+typedef struct _FORMAT_PARAMETERS {
+   MEDIA_TYPE           MediaType;
+   DWORD                StartCylinderNumber;
+   DWORD                EndCylinderNumber;
+   DWORD                StartHeadNumber;
+   DWORD                EndHeadNumber;
+} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS;
+ 
+typedef WORD   BAD_TRACK_NUMBER;
+typedef WORD   *PBAD_TRACK_NUMBER;
+ 
+typedef struct _FORMAT_EX_PARAMETERS {
+   MEDIA_TYPE           MediaType;
+   DWORD                StartCylinderNumber;
+   DWORD                EndCylinderNumber;
+   DWORD                StartHeadNumber;
+   DWORD                EndHeadNumber;
+   WORD                 FormatGapLength;
+   WORD                 SectorsPerTrack;
+   WORD                 SectorNumber[1];
+} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS;
+ 
+typedef struct _DISK_GEOMETRY {
+    LARGE_INTEGER       Cylinders;
+    MEDIA_TYPE          MediaType;
+    DWORD               TracksPerCylinder;
+    DWORD               SectorsPerTrack;
+    DWORD               BytesPerSector;
+} DISK_GEOMETRY, *PDISK_GEOMETRY;
+ 
+typedef struct _PARTITION_INFORMATION {
+    LARGE_INTEGER       StartingOffset;
+    LARGE_INTEGER       PartitionLength;
+    DWORD               HiddenSectors;
+    DWORD               PartitionNumber;
+    BYTE                PartitionType;
+    BOOLEAN             BootIndicator;
+    BOOLEAN             RecognizedPartition;
+    BOOLEAN             RewritePartition;
+} PARTITION_INFORMATION, *PPARTITION_INFORMATION;
+ 
+typedef struct _SET_PARTITION_INFORMATION {
+    BYTE                PartitionType;
+} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION;
+ 
+typedef struct _DRIVE_LAYOUT_INFORMATION {
+    DWORD               PartitionCount;
+    DWORD               Signature;
+    PARTITION_INFORMATION PartitionEntry[1];
+} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION;
+ 
+typedef struct _VERIFY_INFORMATION {
+    LARGE_INTEGER       StartingOffset;
+    DWORD               Length;
+} VERIFY_INFORMATION, *PVERIFY_INFORMATION;
+ 
+typedef struct _REASSIGN_BLOCKS {
+    WORD                Reserved;
+    WORD                Count;
+    DWORD               BlockNumber[1];
+} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS;
+ 
+#if(_WIN32_WINNT >= 0x0400)
+typedef struct _DISK_CONTROLLER_NUMBER {
+    DWORD               ControllerNumber;
+    DWORD               DiskNumber;
+} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER;
+#endif /* _WIN32_WINNT >= 0x0400 */
 
 /* Device Io Stuff - Most VxD support.
  * NOTE: All VxD messages seem to start with a hiword or 0
Index: misc/Makefile.in
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/misc/Makefile.in,v
retrieving revision 1.34
diff -u -u -r1.34 Makefile.in
--- misc/Makefile.in	14 Jun 2001 19:27:03 -0000	1.34
+++ misc/Makefile.in	20 Dec 2001 20:30:56 -0000
@@ -7,7 +7,6 @@
 MODULE    = misc
 
 C_SRCS = \
-	cdrom.c \
 	cpu.c \
 	error.c \
 	main.c \
Index: win32/device.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/win32/device.c,v
retrieving revision 1.57
diff -u -u -r1.57 device.c
--- win32/device.c	30 Nov 2001 18:46:55 -0000	1.57
+++ win32/device.c	12 Jan 2002 14:29:46 -0000
@@ -319,8 +319,7 @@
 
 
 
-HANDLE DEVICE_Open( LPCSTR filename, DWORD access,
-                      LPSECURITY_ATTRIBUTES sa )
+HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa )
 {
     const struct VxDInfo *info;
 
@@ -333,21 +332,28 @@
     return 0;
 }
 
-static const struct VxDInfo *DEVICE_GetInfo( HANDLE handle )
+static DWORD DEVICE_GetClientID( HANDLE handle )
 {
-    const struct VxDInfo *info = NULL;
+    DWORD       ret = 0;
     SERVER_START_REQ( get_file_info )
     {
         req->handle = handle;
-        if (!wine_server_call( req ) &&
-            (reply->type == FILE_TYPE_UNKNOWN) &&
-            (reply->attr & 0x10000))
-        {
-            for (info = VxDList; info->name; info++)
-                if (info->id == LOWORD(reply->attr)) break;
-        }
+        if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
+            ret = reply->attr;
     }
     SERVER_END_REQ;
+    return ret;
+}
+
+static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
+{
+    const struct VxDInfo *info = NULL;
+    
+    if (clientID & 0x10000)
+    {
+        for (info = VxDList; info->name; info++)
+            if (info->id == LOWORD(clientID)) break;
+    }
     return info;
 }
 
@@ -366,13 +372,13 @@
 			      LPDWORD lpcbBytesReturned,
 			      LPOVERLAPPED lpOverlapped)
 {
-        const struct VxDInfo *info;
+        DWORD clientID;
 
         TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped	);
 
-	if (!(info = DEVICE_GetInfo( hDevice )))
+	if (!(clientID = DEVICE_GetClientID( hDevice )))
 	{
 		SetLastError( ERROR_INVALID_PARAMETER );
 		return FALSE;
@@ -381,7 +387,12 @@
 	/* Check if this is a user defined control code for a VxD */
 	if( HIWORD( dwIoControlCode ) == 0 )
 	{
-		if ( info->deviceio )
+                const struct VxDInfo *info;
+                if (!(info = DEVICE_GetInfo( clientID )))
+                {
+                        FIXME( "No device found for id %lx\n", clientID);
+                }
+                else if ( info->deviceio )
 		{
 			return info->deviceio( dwIoControlCode, 
                                         lpvInBuffer, cbInBuffer, 
@@ -400,7 +411,15 @@
 	}
 	else
 	{
-		switch( dwIoControlCode )
+                char str[3];
+
+                strcpy(str,  "A:");
+                str[0] += LOBYTE(clientID);
+                if (GetDriveTypeA(str) == DRIVE_CDROM)
+                    return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
+                                                 lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
+                                                 lpOverlapped);
+                else switch( dwIoControlCode )
 		{
 		case FSCTL_DELETE_REPARSE_POINT:
 		case FSCTL_DISMOUNT_VOLUME:
@@ -1135,7 +1154,7 @@
     case VWIN32_DIOC_DOS_INT13:
     case VWIN32_DIOC_DOS_INT25:
     case VWIN32_DIOC_DOS_INT26:
-	case VWIN32_DIOC_DOS_DRIVEINFO:
+    case VWIN32_DIOC_DOS_DRIVEINFO:
     {
         CONTEXT86 cxt;
         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
@@ -1160,7 +1179,7 @@
         case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
         case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
         case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
-		case VWIN32_DIOC_DOS_DRIVEINFO:	DOS3Call( &cxt ); break; /* Call int 21h 730x */
+        case VWIN32_DIOC_DOS_DRIVEINFO:	DOS3Call( &cxt ); break; /* Call int 21h 730x */
         }
 
         CONTEXT_2_DIOCRegs( &cxt, pOut );
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ dlls/ntdll/cdrom.c	Sat Jan 12 15:31:33 2002
@@ -0,0 +1,996 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/* Main file for CD-ROM support
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1999, 2001 Eric Pouech
+ * Copyright 2000 Andreas Mohr
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ntddk.h"
+#include "winioctl.h"
+#include "ntddstor.h"
+#include "ntddcdrm.h"
+#include "drive.h"
+#include "file.h"
+#include "debugtools.h"
+
+#ifdef HAVE_LINUX_CDROM_H
+# include <linux/cdrom.h>
+#endif
+#ifdef HAVE_LINUX_UCDROM_H
+# include <linux/ucdrom.h>
+#endif
+#ifdef HAVE_SYS_CDIO_H
+# include <sys/cdio.h>
+#endif
+
+DEFAULT_DEBUG_CHANNEL(cdrom);
+
+/* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom 
+ * this should be removed when a proper device interface is implemented
+ */
+struct cdrom_cache {
+    int fd;
+    int count;
+};
+static struct cdrom_cache cdrom_cache[26];
+
+/******************************************************************
+ *		CDROM_Open
+ *
+ *
+ */
+static int CDROM_Open(HANDLE hDevice, DWORD clientID)
+{
+    int dev = LOWORD(clientID);
+
+    if (dev >= 26) return -1;
+
+    if (!cdrom_cache[dev].count)
+    {
+        char root[4];
+
+        strcpy(root, "A:\\");
+        root[0] += dev;
+        if (GetDriveTypeA(root) != DRIVE_CDROM) return -1;
+        cdrom_cache[dev].fd = open(DRIVE_GetDevice(dev), O_RDONLY|O_NONBLOCK);
+        if (cdrom_cache[dev].fd == -1)
+        {
+            FIXME("Can't open %s: %s\n", root, strerror(errno));
+            return -1;
+        }
+    }
+    cdrom_cache[dev].count++;
+    return cdrom_cache[dev].fd;
+}
+
+/******************************************************************
+ *		CDROM_Close
+ *
+ *
+ */
+static void CDROM_Close(DWORD clientID, int fd)
+{
+    int dev = LOWORD(clientID);
+    
+    if (dev >= 26 || fd != cdrom_cache[dev].fd) FIXME("how come\n");
+    if (--cdrom_cache[dev].count == 0)
+        close(cdrom_cache[dev].fd);
+}
+
+/******************************************************************
+ *		CDROM_GetStatusCode
+ *
+ *
+ */
+static DWORD CDROM_GetStatusCode(int io)
+{
+    if (io == 0) return 0;
+    switch (errno)
+    {
+    case EIO:   return STATUS_NO_MEDIA_IN_DEVICE;
+    }
+    FIXME("Unmapped error code %d: %s\n", errno, strerror(errno));
+    return STATUS_IO_DEVICE_ERROR;
+}
+
+static DWORD CDROM_GetControl(int dev, CDROM_AUDIO_CONTROL* cac)
+{
+    cac->LbaFormat = 0; /* FIXME */
+    cac->LogicalBlocksPerSecond = 1; /* FIXME */
+    return  STATUS_NOT_SUPPORTED;
+}
+
+static DWORD CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
+{
+    return STATUS_NOT_SUPPORTED;
+}
+
+static DWORD CDROM_GetDriveGeometry(int dev, DISK_GEOMETRY* dg)
+{
+#if 0
+    dg->Cylinders.s.LowPart = 1; /* FIXME */
+    dg->Cylinders.s.HighPart = 0; /* FIXME */
+    dg->MediaType = 1; /* FIXME */
+    dg->TracksPerCylinder = 1; /* FIXME */
+    dg->SectorsPerTrack = 1; /* FIXME */
+    dg->BytesPerSector= 1; /* FIXME */
+#endif
+    return STATUS_NOT_SUPPORTED;
+}
+
+/**************************************************************************
+ *                              CDROM_Reset                     [internal]
+ */
+static DWORD CDROM_ResetAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMRESET));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCRESET, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}  
+
+/******************************************************************
+ *		CDROM_SetTray
+ *
+ *
+ */
+static DWORD CDROM_SetTray(int dev, BOOL doEject)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, doEject ? CDROMEJECT : CDROMCLOSETRAY));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode((ioctl(dev, CDIOCALLOW, NULL)) || 
+                               (ioctl(dev, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
+                               (ioctl(dev, CDIOCPREVENT, NULL)));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ControlEjection
+ *
+ *
+ */
+static DWORD CDROM_ControlEjection(int dev, const PREVENT_MEDIA_REMOVAL* rmv)
+{
+    int val = rmv->PreventMediaRemoval;
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROM_LOCKDOOR, val));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, (val) ? CDIOPREVENT : CDIOCALLOW, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ReadTOC
+ *
+ *
+ */
+static DWORD CDROM_ReadTOC(int dev, CDROM_TOC* toc)
+{
+    DWORD       ret = STATUS_NOT_SUPPORTED;
+
+#if defined(linux)
+    int                         i, io = -1;
+    struct cdrom_tochdr		hdr;
+    struct cdrom_tocentry	entry;
+
+    io = ioctl(dev, CDROMREADTOCHDR, &hdr);
+    if (io == -1) 
+    {
+        WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
+        goto end;
+    }
+    toc->FirstTrack = hdr.cdth_trk0;
+    toc->LastTrack  = hdr.cdth_trk1;
+
+    TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
+
+    for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
+    {
+	if (i == toc->LastTrack + 1)
+        {
+	    entry.cdte_track = CDROM_LEADOUT;
+        } else {
+            entry.cdte_track = i;
+        }
+	entry.cdte_format = CDROM_MSF;
+	io = ioctl(dev, CDROMREADTOCENTRY, &entry);
+	if (io == -1) {
+	    WARN("error read entry (%s)\n", strerror(errno));
+	    goto end;
+	}
+        toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
+        toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
+        /* marking last track with leadout value as index */
+        toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
+        toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
+        toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
+        toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
+        toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
+    }
+end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    int                         i, io = -1;
+    struct ioc_toc_header	hdr;
+    struct ioc_read_toc_entry	entry;
+    struct cd_toc_entry         toc_buffer;
+
+    io = ioctl(dev, CDIOREADTOCHEADER, &hdr);
+    if (io == -1) 
+    {
+        WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
+        goto end;
+    }
+    toc->FirstTrack = hdr.starting_track;
+    toc->LastTrack  = hdr.ending_track;
+
+    TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
+
+    for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
+    {
+	if (i == toc->LastTrack + 1)
+        {
+#define LEADOUT 0xaa
+	    entry.starting_track = LEADOUT;
+        } else {
+            entry.starting_track = i;
+        }
+	memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
+	entry.address_format = CD_MSF_FORMAT;
+	entry.data_len = sizeof(toc_buffer);
+	entry.data = &toc_buffer;
+	io = ioctl(dev, CDIOREADTOCENTRYS, &entry);
+	if (io == -1) {
+	    WARN("error read entry (%s)\n", strerror(errno));
+	    goto end;
+	}
+        toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
+        toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
+        /* marking last track with leadout value as index */
+        toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
+        toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
+        toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
+        toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
+        toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
+    }
+end:
+    ret = CDROM_GetStatusCode(io);
+#else
+    ret = STATUS_NOT_SUPPORTED;
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_GetDiskData
+ *
+ *
+ */
+static DWORD CDROM_GetDiskData(int dev, CDROM_DISK_DATA* data)
+{
+    CDROM_TOC   toc;
+    DWORD       ret;
+    int         i;
+
+    if ((ret = CDROM_ReadTOC(dev, &toc)) != 0) return ret;
+    data->DiskData = 0;
+    for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
+        if (toc.TrackData[i].Control & 0x04)
+            data->DiskData |= CDROM_DISK_DATA_TRACK;
+        else
+            data->DiskData |= CDROM_DISK_AUDIO_TRACK;
+    }
+    return 0;
+}
+
+/******************************************************************
+ *		CDROM_ReadQChannel
+ *
+ *
+ */
+static DWORD CDROM_ReadQChannel(int dev, const CDROM_SUB_Q_DATA_FORMAT* fmt, 
+                                SUB_Q_CHANNEL_DATA* data)
+{
+    DWORD               ret = STATUS_NOT_SUPPORTED;
+    unsigned            size;
+    SUB_Q_HEADER*       hdr = (SUB_Q_HEADER*)data;
+    int                 io;
+
+#ifdef linux
+    struct cdrom_subchnl	sc;
+    sc.cdsc_format = CDROM_MSF;
+
+    io = ioctl(dev, CDROMSUBCHNL, &sc);
+    if (io == -1)
+    {
+	TRACE("opened or no_media (%s)!\n", strerror(errno));
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	goto end;
+    }
+
+    hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+
+    switch (sc.cdsc_audiostatus) {
+    case CDROM_AUDIO_INVALID:
+	hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+	break;
+    case CDROM_AUDIO_NO_STATUS: 
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	break;
+    case CDROM_AUDIO_PLAY:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
+        break;
+    case CDROM_AUDIO_PAUSED:
+        hdr->AudioStatus = AUDIO_STATUS_PAUSED;
+        break;
+    case CDROM_AUDIO_COMPLETED:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
+        break;
+    case CDROM_AUDIO_ERROR:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
+        break;
+    default:
+	TRACE("status=%02X !\n", sc.cdsc_audiostatus);
+        break;
+    }
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->CurrentPosition.FormatCode = sc.cdsc_format;
+        data->CurrentPosition.Control = sc.cdsc_ctrl;
+        data->CurrentPosition.ADR = sc.cdsc_adr;
+        data->CurrentPosition.TrackNumber = sc.cdsc_trk;
+        data->CurrentPosition.IndexNumber = sc.cdsc_ind;
+
+        data->CurrentPosition.AbsoluteAddress[0] = 0;
+        data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
+        data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
+        data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
+
+        data->CurrentPosition.TrackRelativeAddress[0] = 0;
+        data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
+        data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
+        data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
+        data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+        {
+            struct cdrom_mcn mcn;
+            if ((io = ioctl(dev, CDROM_GET_MCN, &mcn)) == -1) goto end;
+
+            data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+            data->MediaCatalog.Mcval = 0; /* FIXME */
+            memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
+            data->MediaCatalog.MediaCatalog[14] = 0;
+        }
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        FIXME("TrackIsrc: NIY on linux");
+        data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
+        data->TrackIsrc.Tcval = 0;
+        io = 0;
+        break;
+    }
+
+ end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct ioc_read_subchannel	read_sc;
+    struct cd_sub_channel_info	sc;
+
+    read_sc.address_format = CD_MSF_FORMAT;
+    read_sc.track          = 0;
+    read_sc.data_len       = sizeof(sc);
+    read_sc.data           = &sc;
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        read_sc.data_format    = CD_CURRENT_POSITION;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        read_sc.data_format    = CD_MEDIA_CATALOG;
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        read_sc.data_format    = CD_TRACK_INFO;
+        sc.track_info.track_number = data->TrackIsrc.Track;
+        break;
+    }
+    io = ioctl(dev, CDIOCREADSUBCHANNEL, &read_sc);
+    if (io == -1)
+    {
+	TRACE("opened or no_media (%s)!\n", strerror(errno));
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	goto end;
+    }
+
+    hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+
+    switch (sc.header.audio_status) {
+    case CD_AS_AUDIO_INVALID:
+	hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+	break;
+    case CD_AS_NO_STATUS:
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+        break;
+    case CD_AS_PLAY_IN_PROGRESS:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
+        break;
+    case CD_AS_PLAY_PAUSED:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PAUSED;
+        break;
+    case CD_AS_PLAY_AUDIO_COMPLETED:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
+        break;
+    case CD_AS_PLAY_ERROR:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
+        break;
+    default:
+	TRACE("status=%02X !\n", sc.header.audio_status);
+    }
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->CurrentPosition.FormatCode = sc.position.data_format;
+        data->CurrentPosition.Control = sc.position.control;
+        data->CurrentPosition.ADR = sc.position.addr_type;
+        data->CurrentPosition.TrackNumber = sc.position.track_number;
+        data->CurrentPosition.IndexNumber = sc.position.index_number;
+
+        data->CurrentPosition.AbsoluteAddress[0] = 0;
+        data->CurrentPosition.AbsoluteAddress[1] = sc.position.absaddr.msf.minute;
+        data->CurrentPosition.AbsoluteAddress[2] = sc.position.absaddr.msf.second;
+        data->CurrentPosition.AbsoluteAddress[3] = sc.position.absaddr.msf.frame;
+        data->CurrentPosition.TrackRelativeAddress[0] = 0;
+        data->CurrentPosition.TrackRelativeAddress[1] = sc.position.reladdr.msf.minute;
+        data->CurrentPosition.TrackRelativeAddress[2] = sc.position.reladdr.msf.second;
+        data->CurrentPosition.TrackRelativeAddress[3] = sc.position.reladdr.msf.frame;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
+        data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+        data->MediaCatalog.FormatCode = sc.media_catalog.data_format;
+        data->MediaCatalog.Mcval = sc.media_catalog.mc_valid;
+        memcpy(data->MediaCatalog.MediaCatalog, sc.media_catalog.mc_number, 15);
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->TrackIsrc.Tcval = sc.track_info.ti_valid;
+        memcpy(data->TrackIsrc.TrackIsrc, sc.track_info.ti_number, 15);
+        break;
+    }
+
+ end:
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_Verify
+ *
+ *
+ */
+static DWORD CDROM_Verify(int dev)
+{
+    /* quick implementation */
+    CDROM_SUB_Q_DATA_FORMAT     fmt;
+    SUB_Q_CHANNEL_DATA          data;
+
+    fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
+    return CDROM_ReadQChannel(dev, &fmt, &data) ? 0 : 1;
+}
+
+/******************************************************************
+ *		CDROM_PlayAudioMSF
+ *
+ *
+ */
+static DWORD CDROM_PlayAudioMSF(int dev, const CDROM_PLAY_AUDIO_MSF* audio_msf)
+{
+    DWORD       ret = STATUS_NOT_SUPPORTED;
+#ifdef linux
+    struct 	cdrom_msf	msf;
+    int         io;
+
+    msf.cdmsf_min0   = audio_msf->StartingM;
+    msf.cdmsf_sec0   = audio_msf->StartingS;
+    msf.cdmsf_frame0 = audio_msf->StartingF;
+    msf.cdmsf_min1   = audio_msf->EndingM;
+    msf.cdmsf_sec1   = audio_msf->EndingS;
+    msf.cdmsf_frame1 = audio_msf->EndingF;
+
+    io = ioctl(dev, CDROMSTART);
+    if (io == -1)
+    {
+	WARN("motor doesn't start !\n");
+	goto end;
+    }
+    io = ioctl(dev, CDROMPLAYMSF, &msf);
+    if (io == -1)
+    {
+	WARN("device doesn't play !\n");
+	goto end;
+    }
+    TRACE("msf = %d:%d:%d %d:%d:%d\n",
+	  msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
+	  msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
+ end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct	ioc_play_msf	msf;
+    int         io;
+
+    msf.start_m      = audio_msf->StartingM;
+    msf.start_s      = audio_msf->StartingS;
+    msf.start_f      = audio_msf->StartingF;
+    msf.end_m        = audio_msf->EndingM;
+    msf.end_s        = audio_msf->EndingS;
+    msf.end_f        = audio_msf->EndingF;
+
+    io = ioctl(dev, CDIOCSTART, NULL);
+    if (io == -1)
+    {
+	WARN("motor doesn't start !\n");
+	goto end;
+    }
+    io = ioctl(dev, CDIOCPLAYMSF, &msf);
+    if (io == -1)
+    {
+	WARN("device doesn't play !\n");
+	goto end;
+    }
+    TRACE("msf = %d:%d:%d %d:%d:%d\n",
+	  msf.start_m, msf.start_s, msf.start_f,
+	  msf.end_m,   msf.end_s,   msf.end_f);
+end:
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_SeekAudioMSF
+ *
+ *
+ */
+static DWORD CDROM_SeekAudioMSF(int dev, const CDROM_SEEK_AUDIO_MSF* audio_msf)
+{
+#if defined(linux)
+    struct cdrom_msf0	msf;
+    msf.minute = audio_msf->M;
+    msf.second = audio_msf->S;
+    msf.frame  = audio_msf->F;
+
+    return CDROM_GetStatusCode(ioctl(dev, CDROMSEEK, &msf));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    FIXME("Could a BSD expert implement the seek function ?\n");
+    return STATUS_NOT_SUPPORTED;
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_PauseAudio
+ *
+ *
+ */
+static DWORD CDROM_PauseAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMPAUSE));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCPAUSE, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ResumeAudio
+ *
+ *
+ */
+static DWORD CDROM_ResumeAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMRESUME));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCRESUME, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_StopAudio
+ *
+ *
+ */
+static DWORD CDROM_StopAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMSTOP));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCSTOP, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_GetVolume
+ *
+ *
+ */
+static DWORD CDROM_GetVolume(int dev, VOLUME_CONTROL* vc)
+{
+#if defined(linux)
+    struct cdrom_volctrl volc;
+    int io;
+    
+    io = ioctl(dev, CDROMVOLREAD, &volc);
+    if (io != -1)
+    {
+        vc->PortVolume[0] = volc.channel0;
+        vc->PortVolume[1] = volc.channel1;
+        vc->PortVolume[2] = volc.channel2;
+        vc->PortVolume[3] = volc.channel3;
+    }
+    return CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct  ioc_vol     volc;
+    int io;
+    
+    io = ioctl(dev, CDIOCGETVOL, &volc);
+    if (io != -1)
+    {
+        vc->PortVolume[0] = volc.vol[0];
+        vc->PortVolume[1] = volc.vol[1];
+        vc->PortVolume[2] = volc.vol[2];
+        vc->PortVolume[3] = volc.vol[3];
+    } 
+    return CDROM_GetStatusCode(io);
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_SetVolume
+ *
+ *
+ */
+static DWORD CDROM_SetVolume(int dev, const VOLUME_CONTROL* vc)
+{
+#if defined(linux)
+    struct cdrom_volctrl volc;
+
+    volc.channel0 = vc->PortVolume[0];
+    volc.channel1 = vc->PortVolume[1];
+    volc.channel2 = vc->PortVolume[2];
+    volc.channel3 = vc->PortVolume[3];
+   
+    return CDROM_GetStatusCode(ioctl(dev, CDROMVOLCTRL, &volc));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct  ioc_vol     volc;
+
+    volc.vol[0] = vc->PortVolume[0];
+    volc.vol[1] = vc->PortVolume[1];
+    volc.vol[2] = vc->PortVolume[2];
+    volc.vol[3] = vc->PortVolume[3];
+
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCSETVOL, &volc));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_RawRead
+ *
+ *
+ */
+static DWORD CDROM_RawRead(int dev, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
+{
+    int	        ret = STATUS_NOT_SUPPORTED;
+    int         io = -1;
+    DWORD       sectSize;
+
+    switch (raw->TrackMode)
+    {
+    case YellowMode2:   sectSize = 2336;        break;
+    case XAForm2:       sectSize = 2328;        break;
+    case CDDA:          sectSize = 2352;        break;
+    default:    return STATUS_INVALID_PARAMETER;
+    }
+    if (len < raw->SectorCount * sectSize) return STATUS_BUFFER_TOO_SMALL;
+    /* strangely enough, it seems that sector offsets are always indicated with a size of 2048, 
+     * even if a larger size if read...
+     */
+#if defined(linux)
+    {
+        struct cdrom_read       cdr;
+        struct cdrom_read_audio cdra;
+
+        switch (raw->TrackMode)
+        {
+        case YellowMode2:
+            if (raw->DiskOffset.s.HighPart) FIXME("Unsupported value\n");
+            cdr.cdread_lba = raw->DiskOffset.s.LowPart; /* FIXME ? */
+            cdr.cdread_bufaddr = buffer;
+            cdr.cdread_buflen = raw->SectorCount * sectSize;
+            io = ioctl(dev, CDROMREADMODE2, &cdr);
+            break;
+        case XAForm2:
+            FIXME("XAForm2: NIY\n");
+            return ret;
+        case CDDA:
+            /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
+             * between by NT2K box and this... should check on the same drive... 
+             * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
+             * (linux/NT).
+             * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
+             * talking of 0.2 ms of sound
+             */
+            /* 2048 = 2 ** 11 */
+            if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
+            cdra.addr.lba = ((raw->DiskOffset.s.LowPart >> 11) |
+                (raw->DiskOffset.s.HighPart << (32 - 11))) - 1;
+            FIXME("reading at %u\n", cdra.addr.lba);
+            cdra.addr_format = CDROM_LBA;
+            cdra.nframes = raw->SectorCount;
+            cdra.buf = buffer;
+            io = ioctl(dev, CDROMREADAUDIO, &cdra);
+            break;
+        }
+    }
+    *sz = sectSize * raw->SectorCount;
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    {
+        struct ioc_read_audio   ira;
+
+        switch (raw->TrackMode)
+        {
+        case YellowMode2:
+            FIXME("YellowMode2: NIY\n");
+            return ret;
+        case XAForm2:
+            FIXME("XAForm2: NIY\n");
+            return ret;
+        case CDDA:
+            /* 2048 = 2 ** 11 */
+            if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
+            ira.address.lba = ((raw->DiskOffset.s.LowPart >> 11) |
+                raw->DiskOffset.s.HighPart << (32 - 11)) - 1;
+            ira.address_format = CD_LBA_FORMAT;
+            ira.nframes = raw->SectorCount;
+            ira.buffer = buffer;
+            io = ioctl(dev, CDIOCREADAUDIO, &ira);
+            break;
+        }
+    }
+    *sz = sectSize * raw->SectorCount;
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_DeviceIoControl
+ *
+ *
+ */
+BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode, 
+                           LPVOID lpInBuffer, DWORD nInBufferSize, 
+                           LPVOID lpOutBuffer, DWORD nOutBufferSize,
+                           LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
+{
+    DWORD       sz;
+    DWORD       error = 0;
+    int         dev;
+
+    TRACE("%lx[%c] %lx %lx %ld %lx %ld %lx %lx\n", 
+          (DWORD)hDevice, 'A' + LOWORD(clientID), dwIoControlCode, (DWORD)lpInBuffer, nInBufferSize, 
+          (DWORD)lpOutBuffer, nOutBufferSize, (DWORD)lpBytesReturned, (DWORD)lpOverlapped);
+
+    if (lpBytesReturned) *lpBytesReturned = 0;
+    if (lpOverlapped)
+    {
+        FIXME("Overlapped isn't implemented yet\n");
+        SetLastError(STATUS_NOT_SUPPORTED);
+        return FALSE;
+    }
+
+    SetLastError(0);
+    dev = CDROM_Open(hDevice, clientID);
+    if (dev == -1)
+    {
+        CDROM_GetStatusCode(-1);
+        return FALSE;
+    }
+
+    switch (dwIoControlCode)
+    {
+    case IOCTL_STORAGE_CHECK_VERIFY:
+    case IOCTL_CDROM_CHECK_VERIFY:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_Verify(dev);
+        break;
+
+/* EPP     case IOCTL_STORAGE_CHECK_VERIFY2: */
+
+/* EPP     case IOCTL_STORAGE_FIND_NEW_DEVICES: */
+/* EPP     case IOCTL_CDROM_FIND_NEW_DEVICES: */
+
+    case IOCTL_STORAGE_LOAD_MEDIA:
+    case IOCTL_CDROM_LOAD_MEDIA:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetTray(dev, FALSE);
+        break;
+     case IOCTL_STORAGE_EJECT_MEDIA:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetTray(dev, TRUE);
+        break;
+
+    case IOCTL_DISK_MEDIA_REMOVAL:
+    case IOCTL_STORAGE_MEDIA_REMOVAL:
+    case IOCTL_STORAGE_EJECTION_CONTROL:
+        /* FIXME the last ioctl:s is not the same as the two others... 
+         * lockcount/owner should be handled */
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ControlEjection(dev, (const PREVENT_MEDIA_REMOVAL*)lpInBuffer);
+        break;
+
+/* EPP     case IOCTL_STORAGE_GET_MEDIA_TYPES: */
+
+    case IOCTL_STORAGE_GET_DEVICE_NUMBER:
+        sz = sizeof(STORAGE_DEVICE_NUMBER);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDeviceNumber(dev, (STORAGE_DEVICE_NUMBER*)lpOutBuffer);
+        break;
+
+    case IOCTL_STORAGE_RESET_DEVICE:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_ResetAudio(dev);
+        break;
+
+    case IOCTL_CDROM_GET_CONTROL:
+        sz = sizeof(CDROM_AUDIO_CONTROL);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetControl(dev, (CDROM_AUDIO_CONTROL*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
+        sz = sizeof(DISK_GEOMETRY);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDriveGeometry(dev, (DISK_GEOMETRY*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_DISK_TYPE:
+        sz = sizeof(CDROM_DISK_DATA);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDiskData(dev, (CDROM_DISK_DATA*)lpOutBuffer);
+        break;
+
+/* EPP     case IOCTL_CDROM_GET_LAST_SESSION: */
+
+    case IOCTL_CDROM_READ_Q_CHANNEL:
+        sz = sizeof(SUB_Q_CHANNEL_DATA);
+        if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT)) 
+            error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ReadQChannel(dev, (const CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer,
+                                        (SUB_Q_CHANNEL_DATA*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_READ_TOC:
+        sz = sizeof(CDROM_TOC);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ReadTOC(dev, (CDROM_TOC*)lpOutBuffer);
+        break;
+
+/* EPP     case IOCTL_CDROM_READ_TOC_EX: */
+
+    case IOCTL_CDROM_PAUSE_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_PauseAudio(dev);
+        break;
+    case IOCTL_CDROM_PLAY_AUDIO_MSF:
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_PlayAudioMSF(dev, (const CDROM_PLAY_AUDIO_MSF*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_RESUME_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_ResumeAudio(dev);
+        break;
+    case IOCTL_CDROM_SEEK_AUDIO_MSF:
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_SeekAudioMSF(dev, (const CDROM_SEEK_AUDIO_MSF*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_STOP_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_StopAudio(dev);
+        break;
+    case IOCTL_CDROM_GET_VOLUME:
+        sz = sizeof(VOLUME_CONTROL);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetVolume(dev, (VOLUME_CONTROL*)lpOutBuffer);
+        break;
+    case IOCTL_CDROM_SET_VOLUME:
+        sz = 0;
+        if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetVolume(dev, (const VOLUME_CONTROL*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_RAW_READ:
+        sz = 0;
+        if (nInBufferSize < sizeof(RAW_READ_INFO)) error = STATUS_INVALID_PARAMETER;
+        else if (lpOutBuffer == NULL) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer, 
+                                   lpOutBuffer, nOutBufferSize, &sz);
+        break;
+    default:
+        FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
+        sz = 0;
+        error = STATUS_INVALID_PARAMETER;
+        break;
+    }
+
+    if (lpBytesReturned) *lpBytesReturned = sz;
+    if (error) 
+    {
+        SetLastError(error);
+        return FALSE;
+    }
+    CDROM_Close(clientID, dev);
+    return TRUE;
+}
+                
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ include/ntddcdrm.h	Thu Dec 13 20:58:42 2001
@@ -0,0 +1,167 @@
+/* DDK information for CD ROM */
+
+#ifndef __NTDDCDRM_H
+#define __NTDDCDRM_H
+
+#define IOCTL_CDROM_BASE                FILE_DEVICE_CD_ROM
+#define IOCTL_CDROM_UNLOAD_DRIVER       CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_READ_TOC            CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_CONTROL         CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_PLAY_AUDIO_MSF      CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_SEEK_AUDIO_MSF      CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_STOP_AUDIO          CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_PAUSE_AUDIO         CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RESUME_AUDIO        CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_VOLUME          CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_SET_VOLUME          CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_READ_Q_CHANNEL      CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_LAST_SESSION    CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RAW_READ            CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT,  FILE_READ_ACCESS)
+#define IOCTL_CDROM_DISK_TYPE           CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY  CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_CHECK_VERIFY        CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_MEDIA_REMOVAL       CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_EJECT_MEDIA         CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_LOAD_MEDIA          CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RESERVE             CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RELEASE             CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_FIND_NEW_DEVICES    CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#include "ntddstor.h"
+
+#define MAXIMUM_NUMBER_TRACKS 100
+#define MAXIMUM_CDROM_SIZE 804
+
+typedef struct _TRACK_DATA {
+    UCHAR               Reserved;
+    UCHAR               Control : 4;
+    UCHAR               Adr : 4;
+    UCHAR               TrackNumber;
+    UCHAR               Reserved1;
+    UCHAR               Address[4];
+} TRACK_DATA, *PTRACK_DATA;
+
+typedef struct _CDROM_TOC {
+    UCHAR               Length[2];
+    UCHAR               FirstTrack;
+    UCHAR               LastTrack;
+    TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
+} CDROM_TOC, *PCDROM_TOC;
+
+#define CDROM_TOC_SIZE sizeof(CDROM_TOC)
+
+typedef struct _CDROM_PLAY_AUDIO_MSF {
+    UCHAR               StartingM;
+    UCHAR               StartingS;
+    UCHAR               StartingF;
+    UCHAR               EndingM;
+    UCHAR               EndingS;
+    UCHAR               EndingF;
+} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;
+
+typedef struct _CDROM_SEEK_AUDIO_MSF {
+    UCHAR               M;
+    UCHAR               S;
+    UCHAR               F;
+} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;
+
+typedef struct _CDROM_DISK_DATA {
+    ULONG               DiskData;
+} CDROM_DISK_DATA, *PCDROM_DISK_DATA;
+
+#define CDROM_DISK_AUDIO_TRACK      (0x00000001)
+#define CDROM_DISK_DATA_TRACK       (0x00000002)
+
+#define IOCTL_CDROM_SUB_Q_CHANNEL    0x00
+#define IOCTL_CDROM_CURRENT_POSITION 0x01
+#define IOCTL_CDROM_MEDIA_CATALOG    0x02
+#define IOCTL_CDROM_TRACK_ISRC       0x03
+
+typedef struct _CDROM_SUB_Q_DATA_FORMAT {
+    UCHAR               Format;
+    UCHAR               Track;
+} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
+
+typedef struct _SUB_Q_HEADER {
+    UCHAR               Reserved;
+    UCHAR               AudioStatus;
+    UCHAR               DataLength[2];
+} SUB_Q_HEADER, *PSUB_Q_HEADER;
+
+typedef struct _SUB_Q_CURRENT_POSITION {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Control : 4;
+    UCHAR               ADR : 4;
+    UCHAR               TrackNumber;
+    UCHAR               IndexNumber;
+    UCHAR               AbsoluteAddress[4];
+    UCHAR               TrackRelativeAddress[4];
+} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;
+
+typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Reserved[3];
+    UCHAR               Reserved1 : 7;
+    UCHAR               Mcval : 1;
+    UCHAR               MediaCatalog[15];
+} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
+
+typedef struct _SUB_Q_TRACK_ISRC {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Reserved0;
+    UCHAR               Track;
+    UCHAR               Reserved1;
+    UCHAR               Reserved2 : 7;
+    UCHAR               Tcval : 1;
+    UCHAR               TrackIsrc[15];
+} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;
+
+typedef union _SUB_Q_CHANNEL_DATA {
+    SUB_Q_CURRENT_POSITION      CurrentPosition;
+    SUB_Q_MEDIA_CATALOG_NUMBER  MediaCatalog;
+    SUB_Q_TRACK_ISRC            TrackIsrc;
+} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;
+
+#define AUDIO_STATUS_NOT_SUPPORTED      0x00
+#define AUDIO_STATUS_IN_PROGRESS        0x11
+#define AUDIO_STATUS_PAUSED             0x12
+#define AUDIO_STATUS_PLAY_COMPLETE      0x13
+#define AUDIO_STATUS_PLAY_ERROR         0x14
+#define AUDIO_STATUS_NO_STATUS          0x15
+
+#define ADR_NO_MODE_INFORMATION         0x0
+#define ADR_ENCODES_CURRENT_POSITION    0x1
+#define ADR_ENCODES_MEDIA_CATALOG       0x2
+#define ADR_ENCODES_ISRC                0x3
+
+#define AUDIO_WITH_PREEMPHASIS          0x0
+#define DIGITAL_COPY_PERMITTED          0x2
+#define AUDIO_DATA_TRACK                0x4
+#define TWO_FOUR_CHANNEL_AUDIO          0x8
+
+typedef struct _CDROM_AUDIO_CONTROL {
+    UCHAR               LbaFormat;
+    USHORT              LogicalBlocksPerSecond;
+} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL;
+
+typedef struct _VOLUME_CONTROL {
+    UCHAR               PortVolume[4];
+} VOLUME_CONTROL, *PVOLUME_CONTROL;
+
+typedef enum _TRACK_MODE_TYPE {
+    YellowMode2,
+    XAForm2,
+    CDDA
+} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
+
+typedef struct __RAW_READ_INFO {
+    LARGE_INTEGER       DiskOffset;
+    ULONG               SectorCount;
+    TRACK_MODE_TYPE     TrackMode;
+} RAW_READ_INFO, *PRAW_READ_INFO;
+
+#endif /* __NTDDCDRM_H */
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ include/ntddstor.h	Thu Dec 13 20:58:52 2001
@@ -0,0 +1,229 @@
+/* DDK definitions for storage media access */
+
+#ifndef _NTDDSTOR_H_
+#define _NTDDSTOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
+
+#define IOCTL_STORAGE_CHECK_VERIFY      CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_MEDIA_REMOVAL     CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_EJECT_MEDIA       CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA        CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESERVE           CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RELEASE           CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_FIND_NEW_DEVICES  CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES   CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_RESET_BUS         CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE      CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_QUERY_PROPERTY    CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+typedef struct _STORAGE_DEVICE_NUMBER {
+    DEVICE_TYPE         DeviceType;
+    ULONG               DeviceNumber;
+    ULONG               PartitionNumber;
+} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
+
+typedef struct _STORAGE_BUS_RESET_REQUEST {
+    UCHAR               PathId;
+} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST;
+
+typedef struct _PREVENT_MEDIA_REMOVAL {
+    BOOLEAN             PreventMediaRemoval;
+} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL;
+
+typedef struct _TAPE_STATISTICS {
+    ULONG               Version;
+    ULONG               Flags;
+    LARGE_INTEGER       RecoveredWrites;
+    LARGE_INTEGER       UnrecoveredWrites;
+    LARGE_INTEGER       RecoveredReads;
+    LARGE_INTEGER       UnrecoveredReads;
+    UCHAR               CompressionRatioReads;
+    UCHAR               CompressionRatioWrites;
+} TAPE_STATISTICS, *PTAPE_STATISTICS;
+
+#define RECOVERED_WRITES_VALID          0x00000001
+#define UNRECOVERED_WRITES_VALID        0x00000002
+#define RECOVERED_READS_VALID           0x00000004
+#define UNRECOVERED_READS_VALID         0x00000008
+#define WRITE_COMPRESSION_INFO_VALID    0x00000010
+#define READ_COMPRESSION_INFO_VALID     0x00000020
+
+typedef struct _TAPE_GET_STATISTICS {
+    ULONG               Operation;
+} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS;
+
+#define TAPE_RETURN_STATISTICS          0L
+#define TAPE_RETURN_ENV_INFO            1L
+#define TAPE_RESET_STATISTICS           2L
+
+typedef enum _STORAGE_MEDIA_TYPE {
+    /* see also defines in ntdddisk.h */
+
+    DDS_4mm = 0x20,
+    MiniQic,
+    Travan,
+    QIC,
+    MP_8mm,
+    AME_8mm,
+    AIT1_8mm,
+    DLT,
+    NCTP,
+    IBM_3480,
+    IBM_3490E,
+    IBM_Magstar_3590,
+    IBM_Magstar_MP,
+    STK_DATA_D3,
+    SONY_DTF,
+    DV_6mm,
+    DMI,
+    SONY_D2,
+    CLEANER_CARTRIDGE,
+    CD_ROM,
+    CD_R,
+    CD_RW,
+    DVD_ROM,
+    DVD_R,
+    DVD_RW,
+    MO_3_RW,
+    MO_5_WO,
+    MO_5_RW,
+    MO_5_LIMDOW,
+    PC_5_WO,
+    PC_5_RW,
+    PD_5_RW,
+    ABL_5_WO,
+    PINNACLE_APEX_5_RW,
+    SONY_12_WO,
+    PHILIPS_12_WO,
+    HITACHI_12_WO,
+    CYGNET_12_WO,
+    KODAK_14_WO,
+    MO_NFR_525,
+    NIKON_12_RW,
+    IOMEGA_ZIP,
+    IOMEGA_JAZ,
+    SYQUEST_EZ135,
+    SYQUEST_EZFLYER,
+    SYQUEST_SYJET,
+    AVATAR_F2,
+    MP2_8mm 
+} STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE;
+
+#define MEDIA_ERASEABLE         0x00000001
+#define MEDIA_WRITE_ONCE        0x00000002
+#define MEDIA_READ_ONLY         0x00000004
+#define MEDIA_READ_WRITE        0x00000008
+#define MEDIA_WRITE_PROTECTED   0x00000100
+#define MEDIA_CURRENTLY_MOUNTED 0x80000000
+
+typedef struct _DEVICE_MEDIA_INFO {
+    union {
+        struct {
+            LARGE_INTEGER       Cylinders;
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               TracksPerCylinder;
+            ULONG               SectorsPerTrack;
+            ULONG               BytesPerSector;
+            ULONG               NumberMediaSides;
+            ULONG               MediaCharacteristics;
+        } DiskInfo;
+        struct {
+            LARGE_INTEGER       Cylinders;
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               TracksPerCylinder;
+            ULONG               SectorsPerTrack;
+            ULONG               BytesPerSector;
+            ULONG               NumberMediaSides;
+            ULONG               MediaCharacteristics;
+        } RemovableDiskInfo;
+        struct {
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               MediaCharacteristics;
+            ULONG               CurrentBlockSize;
+        } TapeInfo;
+    } DeviceSpecific;
+} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO;
+
+typedef struct _GET_MEDIA_TYPES {
+    ULONG               DeviceType;
+    ULONG               MediaInfoCount;
+    DEVICE_MEDIA_INFO   MediaInfo[1];
+} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES;
+
+typedef enum _STORAGE_QUERY_TYPE {
+    PropertyStandardQuery = 0,
+    PropertyExistsQuery,
+    PropertyMaskQuery,
+    PropertyQueryMaxDefined 
+} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
+
+typedef enum _STORAGE_PROPERTY_ID {
+    StorageDeviceProperty = 0,
+    StorageAdapterProperty
+} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
+
+typedef struct _STORAGE_PROPERTY_QUERY {
+    STORAGE_PROPERTY_ID         PropertyId;
+    STORAGE_QUERY_TYPE          QueryType;
+    UCHAR                       AdditionalParameters[1];
+} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
+
+typedef struct _STORAGE_DESCRIPTOR_HEADER {
+    ULONG                       Version;
+    ULONG                       Size;
+} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER;
+
+typedef enum _STORAGE_BUS_TYPE {
+    BusTypeUnknown = 0x00,
+    BusTypeScsi,
+    BusTypeAtapi,
+    BusTypeAta,
+    BusType1394,
+    BusTypeSsa,
+    BusTypeFibre,
+    BusTypeMaxReserved = 0x7F
+} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
+
+typedef struct _STORAGE_DEVICE_DESCRIPTOR {
+    ULONG                       Version;
+    ULONG                       Size;
+    UCHAR                       DeviceType;
+    UCHAR                       DeviceTypeModifier;
+    BOOLEAN                     RemovableMedia;
+    BOOLEAN                     CommandQueueing;
+    ULONG                       VendorIdOffset;
+    ULONG                       ProductIdOffset;
+    ULONG                       ProductRevisionOffset;
+    ULONG                       SerialNumberOffset;
+    STORAGE_BUS_TYPE            BusType;
+    ULONG                       RawPropertiesLength;
+    UCHAR                       RawDeviceProperties[1];
+} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
+
+typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
+    ULONG                       Version;
+    ULONG                       Size;
+    ULONG                       MaximumTransferLength;
+    ULONG                       MaximumPhysicalPages;
+    ULONG                       AlignmentMask;
+    BOOLEAN                     AdapterUsesPio;
+    BOOLEAN                     AdapterScansDown;
+    BOOLEAN                     CommandQueueing;
+    BOOLEAN                     AcceleratedTransfer;
+    BOOLEAN                     BusType;
+    USHORT                      BusMajorVersion;
+    USHORT                      BusMinorVersion;
+} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NTDDSTOR_H_ */


More information about the wine-patches mailing list