Reimplemented the READ SUBCHANNEL command for both ATAPI and SCSI.

This commit is contained in:
OBattler
2017-01-04 22:33:49 +01:00
parent a8bc5133ec
commit d2be2fcc81
6 changed files with 137 additions and 27 deletions

View File

@@ -529,6 +529,21 @@ static void ioctl_read_capacity(uint8_t *b)
ioctl_close(); 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) static void ioctl_read_header(uint8_t *in_cdb, uint8_t *b)
{ {
const UCHAR cdb[12]; const UCHAR cdb[12];
@@ -1054,6 +1069,7 @@ static CDROM ioctl_cdrom=
ioctl_readtoc_raw, ioctl_readtoc_raw,
ioctl_getcurrentsubchannel, ioctl_getcurrentsubchannel,
ioctl_read_capacity, ioctl_read_capacity,
ioctl_read_subchannel,
ioctl_read_header, ioctl_read_header,
ioctl_read_disc_information, ioctl_read_disc_information,
ioctl_read_track_information, ioctl_read_track_information,

View File

@@ -18,6 +18,8 @@ void iso_close(void);
static FILE* iso_image; static FILE* iso_image;
static int iso_changed = 0; static int iso_changed = 0;
static uint32_t lba = 0;
static uint32_t iso_cd_pos = 0, iso_cd_end = 0; static uint32_t iso_cd_pos = 0, iso_cd_end = 0;
void iso_audio_callback(int16_t *output, int len) 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) static void iso_seek(uint32_t pos)
{ {
// pclog("iso_seek stub\n"); // pclog("iso_seek stub\n");
lba = pos;
return; return;
} }
@@ -113,8 +116,39 @@ static int iso_medium_changed(void)
static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf)
{ {
// pclog("iso_getcurrentsubchannel stub\n"); long size;
return 0; 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) static void iso_eject(void)
@@ -418,6 +452,7 @@ static CDROM iso_cdrom =
iso_getcurrentsubchannel, iso_getcurrentsubchannel,
NULL, NULL,
NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL,
iso_sector_data_type, iso_sector_data_type,

View File

@@ -134,6 +134,7 @@ static CDROM null_cdrom =
null_getcurrentsubchannel, null_getcurrentsubchannel,
NULL, NULL,
NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL,
null_sector_data_type, null_sector_data_type,

View File

@@ -11,6 +11,7 @@ typedef struct CDROM
int (*readtoc_raw)(uint8_t *b, int msf, int maxlen); int (*readtoc_raw)(uint8_t *b, int msf, int maxlen);
uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf);
void (*read_capacity)(uint8_t *b); 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_header)(uint8_t *in_cdb, uint8_t *b);
void (*read_disc_information)(uint8_t *b); void (*read_disc_information)(uint8_t *b);
int (*read_track_information)(uint8_t *in_cdb, uint8_t *b); int (*read_track_information)(uint8_t *in_cdb, uint8_t *b);

View File

@@ -2577,25 +2577,53 @@ static void atapicommand(int ide_board)
break; break;
case GPCMD_READ_SUBCHANNEL: case GPCMD_READ_SUBCHANNEL:
temp=idebufferb[2]&0x40; if (idebufferb[3] > 3)
if (idebufferb[3]!=1)
{ {
// pclog("Read subchannel check condition %02X\n",idebufferb[3]); // pclog("Read subchannel check condition %02X\n",idebufferb[3]);
atapi_invalid_field(ide); atapi_invalid_field(ide);
break; break;
} }
pos=0; switch(idebufferb[3])
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)
{ {
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->packetstatus = ATAPI_STATUS_DATA;
ide->cylinder=len; ide->cylinder=len;

View File

@@ -1120,25 +1120,54 @@ SCSIOut:
break; break;
case GPCMD_READ_SUBCHANNEL: case GPCMD_READ_SUBCHANNEL:
Temp = cdb[2] & 0x40; if (cdb[3] > 3)
if (cdb[3] != 1)
{ {
SCSIStatus = SCSI_STATUS_CHECK_CONDITION; SCSIStatus = SCSI_STATUS_CHECK_CONDITION;
SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
SCSICallback[id]=50*SCSI_TIME; SCSICallback[id]=50*SCSI_TIME;
break; break;
} }
pos = 0; switch(cdb[3])
cmdbuffer[pos++] = 0; {
cmdbuffer[pos++] = 0; /*Audio status*/ case 0:
cmdbuffer[pos++] = 0; cmdbuffer[pos++] = 0; /*Subchannel length*/ alloc_length = 4;
cmdbuffer[pos++] = 1; /*Format code*/ break;
cmdbuffer[1] = cdrom->getcurrentsubchannel(&cmdbuffer[5], msf); case 1:
len = 16; alloc_length = 16;
if (!Temp) break;
len = 4; 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; SCSIPhase = SCSI_PHASE_DATAIN;
SCSIStatus = SCSI_STATUS_OK; SCSIStatus = SCSI_STATUS_OK;
SCSICallback[id]=1000*SCSI_TIME; SCSICallback[id]=1000*SCSI_TIME;