From d2be2fcc815c1d7188aefb79cff79069edeabadb Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Jan 2017 22:33:49 +0100 Subject: [PATCH] Reimplemented the READ SUBCHANNEL command for both ATAPI and SCSI. --- src/cdrom-ioctl.c | 16 ++++++++++++++ src/cdrom-iso.c | 39 +++++++++++++++++++++++++++++++-- src/cdrom-null.c | 1 + src/cdrom.h | 1 + src/ide.c | 52 +++++++++++++++++++++++++++++++++----------- src/scsi_cdrom.c | 55 ++++++++++++++++++++++++++++++++++++----------- 6 files changed, 137 insertions(+), 27 deletions(-) diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c index 51f95e799..37197b51f 100644 --- a/src/cdrom-ioctl.c +++ b/src/cdrom-ioctl.c @@ -529,6 +529,21 @@ static void ioctl_read_capacity(uint8_t *b) ioctl_close(); } +static void ioctl_read_subchannel(uint8_t *in_cdb, uint8_t *b) +{ + const UCHAR cdb[12]; + UCHAR buf[24]; + + ioctl_open(0); + + memcpy(cdb, in_cdb, 12); + SCSICommand(cdb, buf, 24); + + memcpy(b, buf, 24); + + ioctl_close(); +} + static void ioctl_read_header(uint8_t *in_cdb, uint8_t *b) { const UCHAR cdb[12]; @@ -1054,6 +1069,7 @@ static CDROM ioctl_cdrom= ioctl_readtoc_raw, ioctl_getcurrentsubchannel, ioctl_read_capacity, + ioctl_read_subchannel, ioctl_read_header, ioctl_read_disc_information, ioctl_read_track_information, diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c index ec073d9ba..1b44f6953 100644 --- a/src/cdrom-iso.c +++ b/src/cdrom-iso.c @@ -18,6 +18,8 @@ void iso_close(void); static FILE* iso_image; static int iso_changed = 0; +static uint32_t lba = 0; + static uint32_t iso_cd_pos = 0, iso_cd_end = 0; void iso_audio_callback(int16_t *output, int len) @@ -64,6 +66,7 @@ static void iso_stop(void) static void iso_seek(uint32_t pos) { // pclog("iso_seek stub\n"); + lba = pos; return; } @@ -113,8 +116,39 @@ static int iso_medium_changed(void) static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) { - // pclog("iso_getcurrentsubchannel stub\n"); - return 0; + long size; + int pos=0; + if (strlen(iso_path) == 0) + { + return 0; + } + + b[pos++]=0; + b[pos++]=0; + b[pos++]=0; + + int32_t temp = lba; + if (msf) + { + memset(&(b[pos]), 0, 8); + lba_to_msf(&(b[pos]), temp); + pos += 4; + lba_to_msf(&(b[pos]), temp); + pos += 4; + } + else + { + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + } + + return 0x13; } static void iso_eject(void) @@ -418,6 +452,7 @@ static CDROM iso_cdrom = iso_getcurrentsubchannel, NULL, NULL, + NULL, NULL, NULL, iso_sector_data_type, diff --git a/src/cdrom-null.c b/src/cdrom-null.c index f8c087835..76ec0ab3c 100644 --- a/src/cdrom-null.c +++ b/src/cdrom-null.c @@ -134,6 +134,7 @@ static CDROM null_cdrom = null_getcurrentsubchannel, NULL, NULL, + NULL, NULL, NULL, null_sector_data_type, diff --git a/src/cdrom.h b/src/cdrom.h index 7b54fe546..e8103e5ca 100644 --- a/src/cdrom.h +++ b/src/cdrom.h @@ -11,6 +11,7 @@ typedef struct CDROM int (*readtoc_raw)(uint8_t *b, int msf, int maxlen); uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); void (*read_capacity)(uint8_t *b); + void (*read_subchannel)(uint8_t *in_cdb, uint8_t *b); void (*read_header)(uint8_t *in_cdb, uint8_t *b); void (*read_disc_information)(uint8_t *b); int (*read_track_information)(uint8_t *in_cdb, uint8_t *b); diff --git a/src/ide.c b/src/ide.c index 1d533491b..97945e3c0 100644 --- a/src/ide.c +++ b/src/ide.c @@ -2577,25 +2577,53 @@ static void atapicommand(int ide_board) break; case GPCMD_READ_SUBCHANNEL: - temp=idebufferb[2]&0x40; - if (idebufferb[3]!=1) + if (idebufferb[3] > 3) { // pclog("Read subchannel check condition %02X\n",idebufferb[3]); atapi_invalid_field(ide); break; } - pos=0; - idebufferb[pos++]=0; - idebufferb[pos++]=0; /*Audio status*/ - idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ - idebufferb[pos++]=1; /*Format code*/ - idebufferb[1]=cdrom->getcurrentsubchannel(&idebufferb[5],msf); - // pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); - len=16; - if (!temp) + switch(idebufferb[3]) { - len=4; + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + if (cdrom->read_subchannel) + { + cdrom->read_subchannel(idebufferb, idebufferb); + len = alloc_length; + } + else + { + temp = idebufferb[3] & 3; + temp |= (idebufferb[2] & 0x40); + memset(idebufferb, 24, 0); + pos = 0; + idebufferb[pos++]=0; + idebufferb[pos++]=0; /*Audio status*/ + idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ + idebufferb[pos++]=temp & 3; /*Format code*/ + if ((temp & 3) == 1) + { + idebufferb[1]=cdrom->getcurrentsubchannel(&idebufferb[5],msf); + } + if (!(temp & 0x40) || ((temp & 3) == 0)) + { + len=4; + } + else + { + len = alloc_length; + } } ide->packetstatus = ATAPI_STATUS_DATA; ide->cylinder=len; diff --git a/src/scsi_cdrom.c b/src/scsi_cdrom.c index a26e02ee6..4f3d18023 100644 --- a/src/scsi_cdrom.c +++ b/src/scsi_cdrom.c @@ -1120,25 +1120,54 @@ SCSIOut: break; case GPCMD_READ_SUBCHANNEL: - Temp = cdb[2] & 0x40; - if (cdb[3] != 1) + if (cdb[3] > 3) { SCSIStatus = SCSI_STATUS_CHECK_CONDITION; SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); SCSICallback[id]=50*SCSI_TIME; break; } - - pos = 0; - cmdbuffer[pos++] = 0; - cmdbuffer[pos++] = 0; /*Audio status*/ - cmdbuffer[pos++] = 0; cmdbuffer[pos++] = 0; /*Subchannel length*/ - cmdbuffer[pos++] = 1; /*Format code*/ - cmdbuffer[1] = cdrom->getcurrentsubchannel(&cmdbuffer[5], msf); - len = 16; - if (!Temp) - len = 4; - + + switch(cdb[3]) + { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + if (cdrom->read_subchannel) + { + cdrom->read_subchannel(cdb, cmdbuffer); + len = alloc_length; + } + else + { + memset(cmdbuffer, 24, 0); + pos = 0; + cmdbuffer[pos++]=0; + cmdbuffer[pos++]=0; /*Audio status*/ + cmdbuffer[pos++]=0; cmdbuffer[pos++]=0; /*Subchannel length*/ + cmdbuffer[pos++]=cdb[3]; /*Format code*/ + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + { + len = 4; + } + else + { + len = alloc_length; + } + if (cdb[3] == 1) + { + cmdbuffer[1]=cdrom->getcurrentsubchannel(&cmdbuffer[5],msf); + } + } + SCSIPhase = SCSI_PHASE_DATAIN; SCSIStatus = SCSI_STATUS_OK; SCSICallback[id]=1000*SCSI_TIME;