diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c index b3a85f7..2558849 100644 --- a/src/cdrom-ioctl.c +++ b/src/cdrom-ioctl.c @@ -4,8 +4,10 @@ #include #ifdef __MINGW64__ #include "ntddcdrm.h" +#include "ntddscsi.h" #else #include "ddk/ntddcdrm.h" +#include "ddk/ntddscsi.h" #endif #include "ibm.h" #include "ide.h" @@ -426,21 +428,73 @@ static void ioctl_load(void) cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); } -static void ioctl_readsector(uint8_t *b, int sector) +#define IOCTL_DATA_BUFFER 8192 + +typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR SenseBuf[32]; +} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; + +static int ioctl_readsector(uint8_t *b, int sector) { LARGE_INTEGER pos; + BOOL status; long size; - if (!cdrom_drive) return; + int c; + + if (!cdrom_drive) + return -1; if (ioctl_cd_state == CD_PLAYING) - return; + return -1; ioctl_cd_state = CD_STOPPED; pos.QuadPart=sector*2048; ioctl_open(0); SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN); - ReadFile(hIOCTL,b,2048,&size,NULL); + status = ReadFile(hIOCTL,b,2048,&size,NULL); ioctl_close(); + + /*If the read failed, try again using SPTI*/ + if (!status || size != 2048) + { + uint8_t cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; + DWORD returned; + uint8_t data_buffer[IOCTL_DATA_BUFFER]; + + ioctl_open(0); + + cmd[9] |= 1 << 4; // userdata + + cmd[3] = (uint8_t)(sector >> 16); + cmd[4] = (uint8_t)(sector >> 8); + cmd[5] = (uint8_t)(sector >> 0); + + memset(&swb, 0, sizeof (swb)); + memcpy(swb.spt.Cdb, cmd, 12); + + swb.spt.Length = sizeof (SCSI_PASS_THROUGH); + swb.spt.CdbLength = 12; + swb.spt.DataIn = SCSI_IOCTL_DATA_IN; + swb.spt.DataTransferLength = IOCTL_DATA_BUFFER; + swb.spt.DataBuffer = data_buffer; + memset(data_buffer, 0, IOCTL_DATA_BUFFER); + swb.spt.TimeOutValue = 80 * 60; + swb.spt.SenseInfoOffset = (uintptr_t)&swb.SenseBuf - (uintptr_t)&swb;//offsetof(swb, SenseBuf); + swb.spt.SenseInfoLength = 32; + + if (DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), + &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), + &returned, NULL)) + memcpy(b, data_buffer, 2048); + + ioctl_close(); + } + + return !status; } static void lba_to_msf(uint8_t *buf, int lba) @@ -695,28 +749,22 @@ void ioctl_reset() tocvalid = 1; } +void ioctl_set_drive(char d) +{ + sprintf(ioctl_path, "\\\\.\\%c:", d); + pclog("Path is %s\n", ioctl_path); + tocvalid = 0; + atapi = &ioctl_atapi; +} + int ioctl_open(char d) { -// char s[8]; - if (!ioctl_inited) - { - sprintf(ioctl_path,"\\\\.\\%c:",d); - pclog("Path is %s\n",ioctl_path); - tocvalid=0; - } -// pclog("Opening %s\n",ioctl_path); - hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + hIOCTL = CreateFile(ioctl_path,GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if (!hIOCTL) { //fatal("IOCTL"); } - atapi=&ioctl_atapi; - if (!ioctl_inited) - { - ioctl_inited=1; - CloseHandle(hIOCTL); - hIOCTL = NULL; - } return 0; } @@ -732,7 +780,6 @@ void ioctl_close(void) static void ioctl_exit(void) { ioctl_stop(); - ioctl_inited=0; tocvalid=0; } diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h index a040b83..aa1c0d5 100644 --- a/src/cdrom-ioctl.h +++ b/src/cdrom-ioctl.h @@ -7,5 +7,6 @@ extern int ioctl_open(char d); extern void ioctl_reset(); extern void ioctl_close(); +void ioctl_set_drive(char d); #endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c index 2742adf..98f3bb7 100644 --- a/src/cdrom-iso.c +++ b/src/cdrom-iso.c @@ -99,11 +99,13 @@ static void iso_load(void) pclog("iso_load stub\n"); } -static void iso_readsector(uint8_t *b, int sector) +static int iso_readsector(uint8_t *b, int sector) { - if (!cdrom_drive) return; + if (!cdrom_drive) + return -1; fseek(iso_image,sector*2048,SEEK_SET); fread(b,2048,1,iso_image); + return 0; } static void lba_to_msf(uint8_t *buf, int lba) diff --git a/src/ide.c b/src/ide.c index 3163226..dbfd0e7 100644 --- a/src/ide.c +++ b/src/ide.c @@ -108,6 +108,7 @@ /* ATAPI Additional Sense Codes */ #define ASC_AUDIO_PLAY_OPERATION 0x00 #define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 #define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 #define ASC_MEDIUM_NOT_PRESENT 0x3a @@ -2131,7 +2132,24 @@ static void atapicommand(int ide_board) break; } - atapi->readsector(idebufferb,ide->cdpos); + if (atapi->readsector(idebufferb,ide->cdpos)) + { +// pclog("Read sector failed\n"); + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_LBA_OUT_OF_RANGE; + atapi_sense.ascq = 0; + + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + { + ide->error |= MCR_ERR; + } + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; + } #ifndef RPCEMU_IDE readflash=1; #endif diff --git a/src/ide.h b/src/ide.h index 1ae14bc..1335a84 100644 --- a/src/ide.h +++ b/src/ide.h @@ -25,7 +25,7 @@ typedef struct ATAPI int (*readtoc_session)(uint8_t *b, int msf, int maxlen); int (*readtoc_raw)(uint8_t *b, int maxlen); uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); - void (*readsector)(uint8_t *b, int sector); + int (*readsector)(uint8_t *b, int sector); void (*readsector_raw)(uint8_t *b, int sector); void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); void (*seek)(uint32_t pos); diff --git a/src/pc.c b/src/pc.c index 9a097de..d361c30 100644 --- a/src/pc.c +++ b/src/pc.c @@ -290,13 +290,13 @@ void initpc(int argc, char *argv[]) cdrom_null_open(cdrom_drive); #else cdrom_drive = 0; - ioctl_open(cdrom_drive); + ioctl_set_drive(cdrom_drive); #endif } } else { - ioctl_open(cdrom_drive); + ioctl_set_drive(cdrom_drive); } } diff --git a/src/win.c b/src/win.c index b85a80a..1b0fcf9 100644 --- a/src/win.c +++ b/src/win.c @@ -1034,7 +1034,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM } atapi->exit(); atapi_close(); - ioctl_open(0); + ioctl_set_drive(0); CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); @@ -1065,7 +1065,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM } atapi->exit(); atapi_close(); - ioctl_open(0); + ioctl_set_drive(0); if (cdrom_enabled) { /* Signal disc change to the emulated machine. */ @@ -1147,7 +1147,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM old_cdrom_drive = cdrom_drive; atapi->exit(); atapi_close(); - ioctl_open(new_cdrom_drive); + ioctl_set_drive(new_cdrom_drive); if (cdrom_enabled) { /* Signal disc change to the emulated machine. */