1717 *
1818 */
1919
20- #include " cdrom_drive.h"
20+ #include " cdrom_drive.h"
2121
2222#if defined(GG_ENABLE_PHYSICAL_CDROM) && defined(_WIN32)
2323
2828#include < ntddscsi.h>
2929
3030#define CDROM_DRIVE_RAW_SECTOR_SIZE 2352
31+ #define CDROM_DRIVE_DATA_SECTOR_SIZE 2048
3132#define CDROM_DRIVE_SENSE_SIZE 32
3233#define CDROM_DRIVE_TIMEOUT_SECONDS 20
3334#define SCSI_READ_CD_EXPECTED_TYPE_CDDA 0x04
@@ -50,6 +51,42 @@ struct GeargrafxCdRomSetSpeed
5051 ULONG rotation_control;
5152};
5253
54+ static bool windows_error_is_media_unavailable (DWORD error);
55+ static bool scsi_sense_is_media_unavailable (const UCHAR* sense);
56+
57+ static void init_scsi_read_request (ScsiPassThroughDirectWithSense& request, u8 * buffer, ULONG length, UCHAR cdb_length)
58+ {
59+ memset (&request, 0 , sizeof (request));
60+ request.pass_through .Length = sizeof (SCSI_PASS_THROUGH_DIRECT);
61+ request.pass_through .CdbLength = cdb_length;
62+ request.pass_through .SenseInfoLength = CDROM_DRIVE_SENSE_SIZE;
63+ request.pass_through .DataIn = SCSI_IOCTL_DATA_IN;
64+ request.pass_through .DataTransferLength = length;
65+ request.pass_through .TimeOutValue = CDROM_DRIVE_TIMEOUT_SECONDS;
66+ request.pass_through .DataBuffer = buffer;
67+ request.pass_through .SenseInfoOffset = offsetof (ScsiPassThroughDirectWithSense, sense);
68+ }
69+
70+ static bool execute_scsi_read (HANDLE file, ScsiPassThroughDirectWithSense& request, ULONG expected_length, bool * media_unavailable)
71+ {
72+ DWORD bytes_returned = 0 ;
73+ if (!DeviceIoControl (file, IOCTL_SCSI_PASS_THROUGH_DIRECT, &request, sizeof (request), &request, sizeof (request), &bytes_returned, NULL ))
74+ {
75+ if (IsValidPointer (media_unavailable))
76+ *media_unavailable = windows_error_is_media_unavailable (GetLastError ());
77+ return false ;
78+ }
79+
80+ if (request.pass_through .ScsiStatus != 0 )
81+ {
82+ if (IsValidPointer (media_unavailable))
83+ *media_unavailable = scsi_sense_is_media_unavailable (request.sense );
84+ return false ;
85+ }
86+
87+ return request.pass_through .DataTransferLength == expected_length;
88+ }
89+
5390static void init_drive_info (CdRomDriveInfo& info)
5491{
5592 info.id [0 ] = 0 ;
@@ -197,16 +234,9 @@ static bool read_cd_spti(HANDLE file, u32 lba, u32 sector_count, u8* buffer, boo
197234 if (!IsValidPointer (buffer) || (sector_count == 0 ))
198235 return false ;
199236
200- ScsiPassThroughDirectWithSense request = {};
201- request.pass_through .Length = sizeof (SCSI_PASS_THROUGH_DIRECT);
202- request.pass_through .CdbLength = 12 ;
203- request.pass_through .SenseInfoLength = CDROM_DRIVE_SENSE_SIZE;
204- request.pass_through .DataIn = SCSI_IOCTL_DATA_IN;
205237 ULONG expected_length = sector_count * CDROM_DRIVE_RAW_SECTOR_SIZE;
206- request.pass_through .DataTransferLength = expected_length;
207- request.pass_through .TimeOutValue = CDROM_DRIVE_TIMEOUT_SECONDS;
208- request.pass_through .DataBuffer = buffer;
209- request.pass_through .SenseInfoOffset = offsetof (ScsiPassThroughDirectWithSense, sense);
238+ ScsiPassThroughDirectWithSense request;
239+ init_scsi_read_request (request, buffer, expected_length, 12 );
210240 request.pass_through .Cdb [0 ] = 0xBE ;
211241 request.pass_through .Cdb [1 ] = audio ? SCSI_READ_CD_EXPECTED_TYPE_CDDA : SCSI_READ_CD_EXPECTED_TYPE_MODE1;
212242 request.pass_through .Cdb [2 ] = (UCHAR)(lba >> 24 );
@@ -218,25 +248,27 @@ static bool read_cd_spti(HANDLE file, u32 lba, u32 sector_count, u8* buffer, boo
218248 request.pass_through .Cdb [8 ] = (UCHAR)sector_count;
219249 request.pass_through .Cdb [9 ] = audio ? SCSI_READ_CD_READ_CDDA : SCSI_READ_CD_READ_MODE1_RAW;
220250
221- DWORD bytes_returned = 0 ;
222- if (!DeviceIoControl (file, IOCTL_SCSI_PASS_THROUGH_DIRECT, &request, sizeof (request), &request, sizeof (request), &bytes_returned, NULL ))
223- {
224- if (IsValidPointer (media_unavailable))
225- *media_unavailable = windows_error_is_media_unavailable (GetLastError ());
226- return false ;
227- }
251+ return execute_scsi_read (file, request, expected_length, media_unavailable);
252+ }
228253
229- if (request.pass_through .ScsiStatus != 0 )
230- {
231- if (IsValidPointer (media_unavailable))
232- *media_unavailable = scsi_sense_is_media_unavailable (request.sense );
233- return false ;
234- }
254+ static bool read_data_spti (HANDLE file, u32 lba, u8 * buffer, bool * media_unavailable)
255+ {
256+ if (IsValidPointer (media_unavailable))
257+ *media_unavailable = false ;
235258
236- if (request. pass_through . DataTransferLength != expected_length )
259+ if (! IsValidPointer (buffer) )
237260 return false ;
238261
239- return true ;
262+ ScsiPassThroughDirectWithSense request;
263+ init_scsi_read_request (request, buffer, CDROM_DRIVE_DATA_SECTOR_SIZE, 10 );
264+ request.pass_through .Cdb [0 ] = 0x28 ;
265+ request.pass_through .Cdb [2 ] = (UCHAR)(lba >> 24 );
266+ request.pass_through .Cdb [3 ] = (UCHAR)(lba >> 16 );
267+ request.pass_through .Cdb [4 ] = (UCHAR)(lba >> 8 );
268+ request.pass_through .Cdb [5 ] = (UCHAR)lba;
269+ request.pass_through .Cdb [8 ] = 1 ;
270+
271+ return execute_scsi_read (file, request, CDROM_DRIVE_DATA_SECTOR_SIZE, media_unavailable);
240272}
241273
242274static HANDLE open_device_handle (const char * device_id, bool read_write)
@@ -496,6 +528,28 @@ bool CdRomDrive::ReadRawSectors2352(u32 lba, u32 sector_count, u8* buffer, bool
496528 return true ;
497529}
498530
531+ bool CdRomDrive::ReadDataSector2048 (u32 lba, u8 * buffer, bool report_errors)
532+ {
533+ if (!IsOpen () || !IsValidPointer (buffer))
534+ return false ;
535+
536+ bool media_unavailable = false ;
537+ if (read_data_spti (m_file, lba, buffer, &media_unavailable))
538+ return true ;
539+
540+ if (media_unavailable)
541+ {
542+ if (report_errors)
543+ Error (" Physical CD-ROM media unavailable for %s at LBA %u" , m_device_id, lba);
544+ return false ;
545+ }
546+
547+ if (report_errors)
548+ Error (" SCSI READ(10) failed for %s at LBA %u" , m_device_id, lba);
549+
550+ return false ;
551+ }
552+
499553bool CdRomDrive::SetSpeed (u16 speed)
500554{
501555 if (!IsOpen ())
0 commit comments