moved request sense command into t10spc, supporting the old obsolete format and the new one. [smf]

This commit is contained in:
smf- 2013-10-05 19:38:34 +00:00
parent cddbf287ba
commit b3034cbfca
5 changed files with 136 additions and 96 deletions

View File

@ -17,7 +17,7 @@ void t10mmc::t10_start(device_t &device)
device.save_item(NAME(last_lba));
device.save_item(NAME(num_subblocks));
device.save_item(NAME(cur_subblock));
device.save_item(NAME(play_err_flag));
device.save_item(NAME(m_audio_sense));
}
void t10mmc::t10_reset()
@ -36,10 +36,20 @@ void t10mmc::t10_reset()
m_sector_bytes = 2048;
num_subblocks = 1;
cur_subblock = 0;
play_err_flag = 0;
m_audio_sense = 0;
}
// scsicd_exec_command
void t10mmc::abort_audio()
{
if (m_cdda->audio_active())
{
m_cdda->stop_audio();
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR;
}
}
//
// Execute a SCSI command.
@ -47,15 +57,26 @@ void t10mmc::ExecCommand()
{
int trk;
// keep updating the sense data while playing audio.
if (command[0] == SCSI_CMD_REQUEST_SENSE && m_audio_sense != SCSI_SENSE_ASC_ASCQ_NO_SENSE && m_sense_key == SCSI_SENSE_KEY_NO_SENSE && m_sense_asc == 0 && m_sense_ascq == 0)
{
if (m_audio_sense == SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS && !m_cdda->audio_active())
{
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED;
}
set_sense(SCSI_SENSE_KEY_NO_SENSE, (sense_asc_ascq_t) m_audio_sense);
if (m_audio_sense != SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS)
{
m_audio_sense = SCSI_SENSE_ASC_ASCQ_NO_SENSE;
}
}
switch ( command[0] )
{
case 0x03: // REQUEST SENSE
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
break;
case 0x12: // INQUIRY
logerror("T10MMC: REQUEST SENSE\n");
logerror("T10MMC: INQUIRY\n");
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
break;
@ -72,7 +93,7 @@ void t10mmc::ExecCommand()
break;
case 0x1b: // START STOP UNIT
m_cdda->stop_audio();
abort_audio();
m_phase = SCSI_PHASE_STATUS;
m_transfer_length = 0;
break;
@ -104,7 +125,7 @@ void t10mmc::ExecCommand()
cur_subblock = 0;
}
m_cdda->stop_audio();
abort_audio();
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = blocks * m_sector_bytes;
@ -142,7 +163,7 @@ void t10mmc::ExecCommand()
length = 4;
}
m_cdda->stop_audio();
abort_audio();
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = length;
@ -168,13 +189,13 @@ void t10mmc::ExecCommand()
if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
{
play_err_flag = 0;
m_cdda->start_audio(lba, blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
}
else
{
logerror("T10MMC: track is NOT audio!\n");
play_err_flag = 1;
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
}
m_phase = SCSI_PHASE_STATUS;
@ -184,6 +205,7 @@ void t10mmc::ExecCommand()
case 0x48: // PLAY AUDIO TRACK/INDEX
// be careful: tracks here are zero-based, but the SCSI command
// uses the real CD track number which is 1-based!
logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], blocks);
lba = cdrom_get_track_start(cdrom, command[4]-1);
blocks = cdrom_get_track_start(cdrom, command[7]-1) - lba;
if (command[4] > command[7])
@ -196,12 +218,19 @@ void t10mmc::ExecCommand()
blocks = cdrom_get_track_start(cdrom, command[4]) - lba;
}
if (blocks && cdrom)
trk = cdrom_get_track(cdrom, lba);
if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
{
m_cdda->start_audio(lba, blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
}
else
{
logerror("T10MMC: track is NOT audio!\n");
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
}
logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], blocks);
m_phase = SCSI_PHASE_STATUS;
m_transfer_length = 0;
break;
@ -218,10 +247,7 @@ void t10mmc::ExecCommand()
break;
case 0x4e: // STOP
if (cdrom)
{
m_cdda->stop_audio();
}
abort_audio();
logerror("T10MMC: STOP_PLAY_SCAN\n");
m_phase = SCSI_PHASE_STATUS;
@ -259,14 +285,15 @@ void t10mmc::ExecCommand()
if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO)
{
play_err_flag = 0;
m_cdda->start_audio(lba, blocks);
m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
}
else
{
logerror("T10MMC: track is NOT audio!\n");
play_err_flag = 1;
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
}
m_phase = SCSI_PHASE_STATUS;
m_transfer_length = 0;
break;
@ -287,7 +314,7 @@ void t10mmc::ExecCommand()
cur_subblock = 0;
}
m_cdda->stop_audio();
abort_audio();
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = blocks * m_sector_bytes;
@ -317,27 +344,6 @@ void t10mmc::ReadData( UINT8 *data, int dataLength )
switch ( command[0] )
{
case 0x03: // REQUEST SENSE
logerror("T10MMC: Reading REQUEST SENSE data\n");
memset( data, 0, dataLength );
data[0] = 0x71; // deferred error
if (m_cdda->audio_active())
{
data[12] = 0x00;
data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS
}
else if (play_err_flag)
{
play_err_flag = 0;
data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK
data[13] = 0x00;
}
// (else 00/00 means no error to report)
break;
case 0x12: // INQUIRY
memset( data, 0, dataLength );
data[0] = 0x05; // device is present, device is CD/DVD (MMC-3)
@ -404,8 +410,6 @@ void t10mmc::ReadData( UINT8 *data, int dataLength )
{
case 1: // return current position
{
int msf;
if (!cdrom)
{
return;
@ -413,8 +417,6 @@ void t10mmc::ReadData( UINT8 *data, int dataLength )
logerror("T10MMC: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]);
msf = command[1] & 0x2;
int audio_active = m_cdda->audio_active();
if (audio_active)
{
@ -452,6 +454,7 @@ void t10mmc::ReadData( UINT8 *data, int dataLength )
last_phys_frame = last_lba;
int msf = command[1] & 0x2;
if (msf)
{
int m,s,f;

View File

@ -24,6 +24,8 @@ protected:
virtual void t10_start(device_t &device);
virtual void t10_reset();
void abort_audio();
cdrom_image_device *m_image;
cdda_device *m_cdda;
cdrom_file *cdrom;
@ -33,7 +35,7 @@ protected:
UINT32 last_lba;
UINT32 num_subblocks;
UINT32 cur_subblock;
UINT32 play_err_flag;
int m_audio_sense;
};
#endif

View File

@ -34,11 +34,6 @@ void t10sbc::ExecCommand()
{
switch ( command[0] )
{
case 0x03: // REQUEST SENSE
m_phase = SCSI_PHASE_DATAIN;
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
break;
case 0x04: // FORMAT UNIT
m_phase = SCSI_PHASE_STATUS;
m_transfer_length = 0;
@ -123,8 +118,6 @@ void t10sbc::ExecCommand()
void t10sbc::ReadData( UINT8 *data, int dataLength )
{
int i;
// if we're a drive without a disk, return all zeroes
if (!disk)
{
@ -134,14 +127,6 @@ void t10sbc::ReadData( UINT8 *data, int dataLength )
switch ( command[0] )
{
case 0x03: // REQUEST SENSE
data[0] = 0x80; // valid sense
for (i = 1; i < 12; i++)
{
data[i] = 0;
}
break;
case 0x12: // INQUIRY
memset( data, 0, dataLength );
data[0] = 0x00; // device is direct-access (e.g. hard disk)

View File

@ -1,18 +1,32 @@
#include "t10spc.h"
#define SCSI_SENSE_SIZE 4
void t10spc::t10_start(device_t &device)
{
device.save_item(NAME(command));
device.save_item(NAME(commandLength));
device.save_item(NAME(m_phase));
device.save_item(NAME(m_transfer_length));
device.save_item(NAME(m_phase));
device.save_item(NAME(m_sense_key));
device.save_item(NAME(m_sense_asc));
device.save_item(NAME(m_sense_ascq));
device.save_item(NAME(m_sense_information));
}
void t10spc::t10_reset()
{
m_phase = SCSI_PHASE_BUS_FREE;
m_sense_key = 0;
m_sense_asc = 0;
m_sense_ascq = 0;
m_sense_information = 0;
}
void t10spc::set_sense(sense_key_t key, sense_asc_ascq_t asc_ascq)
{
m_sense_key = key;
m_sense_asc = (asc_ascq >> 8) & 0xff;
m_sense_ascq = asc_ascq & 0xff;
m_sense_information = 0;
}
void t10spc::ExecCommand()
@ -30,8 +44,19 @@ void t10spc::ExecCommand()
break;
case SCSI_CMD_REQUEST_SENSE:
m_phase = SCSI_PHASE_DATAOUT;
m_transfer_length = SCSI_SENSE_SIZE;
m_phase = SCSI_PHASE_DATAIN;
if (command[4] == 0)
{
m_transfer_length = 4;
}
else if (command[4] > 18)
{
m_transfer_length = 18;
}
else
{
m_transfer_length = command[ 4 ];
}
break;
case SCSI_CMD_SEND_DIAGNOSTIC:
@ -51,11 +76,38 @@ void t10spc::ReadData( UINT8 *data, int dataLength )
switch( command[ 0 ] )
{
case SCSI_CMD_REQUEST_SENSE:
data[ 0 ] = SCSI_SENSE_NO_SENSE;
data[ 1 ] = 0x00;
data[ 2 ] = 0x00;
data[ 3 ] = 0x00;
if (command[4] == 0)
{
data[0] = m_sense_asc & 0x7f;
data[1] = (m_sense_information >> 16) & 0x1f;
data[2] = (m_sense_information >> 8) & 0xff;
data[3] = (m_sense_information >> 0) & 0xff;
}
else
{
data[0] = 0x70;
data[1] = 0;
data[2] = m_sense_key & 0xf;
data[3] = (m_sense_information >> 24) & 0xff;
data[4] = (m_sense_information >> 16) & 0xff;
data[5] = (m_sense_information >> 8) & 0xff;
data[6] = (m_sense_information >> 0) & 0xff;
data[7] = 10;
data[8] = 0;
data[9] = 0;
data[10] = 0;
data[11] = 0;
data[12] = m_sense_asc;
data[13] = m_sense_ascq;
data[14] = 0;
data[15] = 0;
data[16] = 0;
data[17] = 0;
}
set_sense(SCSI_SENSE_KEY_NO_SENSE, SCSI_SENSE_ASC_ASCQ_NO_SENSE);
break;
default:
logerror( "SCSIDEV unknown read %02x\n", command[ 0 ] );
break;

View File

@ -29,10 +29,32 @@ protected:
int SCSILengthFromUINT8( UINT8 *length ) { if( *length == 0 ) { return 256; } return *length; }
int SCSILengthFromUINT16( UINT8 *length ) { return ( *(length) << 8 ) | *(length + 1 ); }
enum sense_key_t
{
SCSI_SENSE_KEY_NO_SENSE = 0,
SCSI_SENSE_KEY_ILLEGAL_REQUEST = 5
};
enum sense_asc_ascq_t
{
SCSI_SENSE_ASC_ASCQ_NO_SENSE = 0x0,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS = 0x0011,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_PAUSED = 0x0012,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED = 0x0013,
SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR = 0x0014,
SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK = 0x6400
};
void set_sense(sense_key_t key, sense_asc_ascq_t asc_ascq);
UINT8 command[ 32 ];
int commandLength;
int m_transfer_length;
int m_phase;
UINT8 m_sense_key;
UINT8 m_sense_asc;
UINT8 m_sense_ascq;
UINT32 m_sense_information;
int m_sector_bytes;
device_t *m_device;
};
@ -52,28 +74,4 @@ protected:
#define SCSI_CMD_MODE_SELECT ( 0x15 )
#define SCSI_CMD_SEND_DIAGNOSTIC ( 0x1d )
#define SCSI_SENSE_ADDR_VALID 0x80
#define SCSI_SENSE_NO_SENSE 0x00
#define SCSI_SENSE_NO_INDEX 0x01
#define SCSI_SENSE_SEEK_NOT_COMP 0x02
#define SCSI_SENSE_WRITE_FAULT 0x03
#define SCSI_SENSE_DRIVE_NOT_READY 0x04
#define SCSI_SENSE_NO_TRACK0 0x06
#define SCSI_SENSE_ID_CRC_ERROR 0x10
#define SCSI_SENSE_UNCORRECTABLE 0x11
#define SCSI_SENSE_ADDRESS_NF 0x12
#define SCSI_SENSE_RECORD_NOT_FOUND 0x14
#define SCSI_SENSE_SEEK_ERROR 0x15
#define SCSI_SENSE_DATA_CHECK_RETRY 0x18
#define SCSI_SENSE_ECC_VERIFY 0x19
#define SCSI_SENSE_INTERLEAVE_ERROR 0x1A
#define SCSI_SENSE_UNFORMATTED 0x1C
#define SCSI_SENSE_ILLEGAL_COMMAND 0x20
#define SCSI_SENSE_ILLEGAL_ADDRESS 0x21
#define SCSI_SENSE_VOLUME_OVERFLOW 0x23
#define SCSI_SENSE_BAD_ARGUMENT 0x24
#define SCSI_SENSE_INVALID_LUN 0x25
#define SCSI_SENSE_CART_CHANGED 0x28
#define SCSI_SENSE_ERROR_OVERFLOW 0x2C
#endif