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
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 = ≻ + 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_ */