mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +03:00
machine/t10mmc.cpp: Implemented most features of T10 MMC read CD (0xbe) command. (#11499)
This commit is contained in:
parent
7206fadfee
commit
3b9a281077
@ -162,6 +162,7 @@ void atapi_cdrom_device::ExecCommand()
|
||||
case T10MMC_CMD_PLAY_AUDIO_TRACK_INDEX:
|
||||
case T10MMC_CMD_PAUSE_RESUME:
|
||||
case T10MMC_CMD_PLAY_AUDIO_12:
|
||||
case T10MMC_CMD_READ_CD:
|
||||
case T10SBC_CMD_READ_12:
|
||||
if(!m_image->exists())
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ void t10mmc::t10_start(device_t &device)
|
||||
device.save_item(NAME(m_cur_subblock));
|
||||
device.save_item(NAME(m_audio_sense));
|
||||
device.save_item(NAME(m_sotc));
|
||||
device.save_item(NAME(m_read_cd_flags));
|
||||
}
|
||||
|
||||
void t10mmc::t10_reset()
|
||||
@ -50,6 +51,7 @@ void t10mmc::t10_reset()
|
||||
m_cur_subblock = 0;
|
||||
m_audio_sense = 0;
|
||||
m_sotc = 0;
|
||||
m_read_cd_flags = 0;
|
||||
}
|
||||
|
||||
// scsicd_exec_command
|
||||
@ -539,58 +541,220 @@ void t10mmc::ExecCommand()
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Implement reladr bit, flag bits, test and handle other conditions besides reads to "any type" sector types
|
||||
m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
|
||||
m_blocks = command[6]<<16 | command[7]<<8 | command[8];
|
||||
m_read_cd_flags = command[9];
|
||||
m_transfer_length = 0;
|
||||
|
||||
// m_device->logerror("T10MMC: READ CD start_lba[%08x] block_len[%06x] %02x %02x %02x %02x\n", m_lba, m_blocks, command[1], command[9], command[10], command[11]);
|
||||
|
||||
auto expected_sector_type = BIT(command[1], 2, 3);
|
||||
auto trk = m_image->get_track(m_lba);
|
||||
auto track_type = m_image->get_track_type(trk);
|
||||
if (expected_sector_type != 0)
|
||||
{
|
||||
m_device->logerror("T10MMC: READ CD requested a sector type of %d which is unhandled\n", expected_sector_type);
|
||||
if (command[10] != 0)
|
||||
m_device->logerror("T10MMC: READ CD requested sub-channel data which is not implemented %02x\n", command[10]);
|
||||
|
||||
if ((expected_sector_type == 1 && track_type != cdrom_file::CD_TRACK_AUDIO)
|
||||
|| (expected_sector_type == 2 && track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
|| (expected_sector_type == 3 && track_type != cdrom_file::CD_TRACK_MODE2 && track_type != cdrom_file::CD_TRACK_MODE2_RAW)
|
||||
|| (expected_sector_type == 4 && track_type != cdrom_file::CD_TRACK_MODE2_FORM1)
|
||||
|| (expected_sector_type == 5 && track_type != cdrom_file::CD_TRACK_MODE2_FORM2))
|
||||
const int expected_sector_type = BIT(command[1], 2, 3);
|
||||
int last_track_type = -1;
|
||||
uint8_t last_read_cd_flags = 0;
|
||||
for (int lba = m_lba; lba < m_lba + m_blocks; lba++)
|
||||
{
|
||||
auto trk = m_image->get_track(lba);
|
||||
auto track_type = m_image->get_track_type(trk);
|
||||
|
||||
// If there's a transition between CD data and CD audio anywhere in the requested range then return an error
|
||||
if ((last_track_type == cdrom_file::CD_TRACK_AUDIO && track_type != cdrom_file::CD_TRACK_AUDIO)
|
||||
|| (last_track_type != cdrom_file::CD_TRACK_AUDIO && track_type == cdrom_file::CD_TRACK_AUDIO))
|
||||
{
|
||||
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
|
||||
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
|
||||
m_transfer_length = 0;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
// Must read the subheader to figure out what sector type it is exactly when dealing with these specific track types
|
||||
int mode2_form = 0;
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2_RAW || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
|
||||
{
|
||||
uint8_t tmp_buffer[2352];
|
||||
const int submode_offset = track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX ? 2 : 0x12;
|
||||
|
||||
if (!m_image->read_data(lba, tmp_buffer, cdrom_file::CD_TRACK_RAW_DONTCARE))
|
||||
{
|
||||
m_device->logerror("T10MMC: CD read error! (%08x)\n", lba);
|
||||
return;
|
||||
}
|
||||
|
||||
mode2_form = BIT(tmp_buffer[submode_offset], 5) + 1;
|
||||
}
|
||||
|
||||
// If the expected sector type field is set then all tracks within the specified range must be the same
|
||||
if ((expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_CDDA && track_type != cdrom_file::CD_TRACK_AUDIO)
|
||||
|| (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
|| (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2 && track_type != cdrom_file::CD_TRACK_MODE2)
|
||||
|| (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM1 && track_type != cdrom_file::CD_TRACK_MODE2_FORM1 && mode2_form != 1)
|
||||
|| (expected_sector_type == T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM2 && track_type != cdrom_file::CD_TRACK_MODE2_FORM2 && mode2_form != 2))
|
||||
{
|
||||
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
|
||||
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
|
||||
m_transfer_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// No fields selected is a valid request but none of the rest of the verification code is required in that case
|
||||
if (m_read_cd_flags == 0)
|
||||
{
|
||||
last_track_type = track_type;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for illegal combinations
|
||||
// t10 mmc spec gives a table which shows illegal combinations and combinations that get demoted
|
||||
auto read_cd_flags = m_read_cd_flags & 0xf8;
|
||||
|
||||
// CDDA tracks can only ever be user data or no data (0), requesting other fields is not illegal but will be demoted to just user data
|
||||
if (track_type == cdrom_file::CD_TRACK_AUDIO)
|
||||
read_cd_flags = read_cd_flags ? T10MMC_READ_CD_FIELD_USER_DATA : 0;
|
||||
|
||||
// All of these combinations will be illegal for all tracks besides CDDA tracks
|
||||
bool is_illegal_combo = (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_USER_DATA))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_USER_DATA))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_SUBHEADER | T10MMC_READ_CD_FIELD_ECC));
|
||||
|
||||
// Mode 2 form 1/2 sectors have additional restrictions that CDDA, mode 1, and mode 2 formless tracks don't
|
||||
if (!is_illegal_combo && (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form > 0))
|
||||
{
|
||||
is_illegal_combo = (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA))
|
||||
|| (read_cd_flags == (T10MMC_READ_CD_FIELD_SYNC | T10MMC_READ_CD_FIELD_HEADER | T10MMC_READ_CD_FIELD_USER_DATA | T10MMC_READ_CD_FIELD_ECC));
|
||||
}
|
||||
|
||||
// Mask out flags that can't be used for specific track types
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE1 || track_type == cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
{
|
||||
// Sub header only is valid but will return 0 bytes, otherwise subheader is always demoted
|
||||
if (read_cd_flags != T10MMC_READ_CD_FIELD_SUBHEADER)
|
||||
read_cd_flags &= ~T10MMC_READ_CD_FIELD_SUBHEADER;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2)
|
||||
{
|
||||
// Mode 2 formless
|
||||
// No EDC/ECC data
|
||||
read_cd_flags &= ~T10MMC_READ_CD_FIELD_ECC;
|
||||
|
||||
// Sub header only is valid but will return 0 bytes, otherwise subheader is always demoted
|
||||
if (read_cd_flags != T10MMC_READ_CD_FIELD_SUBHEADER)
|
||||
read_cd_flags &= ~T10MMC_READ_CD_FIELD_SUBHEADER;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form == 2)
|
||||
{
|
||||
// No EDC/ECC data
|
||||
read_cd_flags &= ~T10MMC_READ_CD_FIELD_ECC;
|
||||
}
|
||||
|
||||
// Requested fields must be valid for all tracks within the selected range
|
||||
if (is_illegal_combo || (last_track_type != -1 && read_cd_flags != last_read_cd_flags))
|
||||
{
|
||||
m_device->logerror("T10MMC: READ CD called with invalid data request for given track type %d %02x\n", track_type, command[9]);
|
||||
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_FIELD_IN_CDB);
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
|
||||
m_transfer_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// The actual transfer size must be calculated for every possible valid requested data
|
||||
const int c2_error_codes = BIT(m_read_cd_flags, 1, 2);
|
||||
const bool requested_c2 = c2_error_codes == T10MMC_READ_CD_C2_ONLY;
|
||||
const bool requested_c2_error_block = c2_error_codes == T10MMC_READ_CD_C2_BLOCK;
|
||||
|
||||
const bool requested_edc_ecc = (read_cd_flags & T10MMC_READ_CD_FIELD_ECC) != 0;
|
||||
const bool requested_user_data = (read_cd_flags & T10MMC_READ_CD_FIELD_USER_DATA) != 0;
|
||||
const bool requested_header = (read_cd_flags & T10MMC_READ_CD_FIELD_HEADER) != 0;
|
||||
const bool requested_subheader = (read_cd_flags & T10MMC_READ_CD_FIELD_SUBHEADER) != 0;
|
||||
const bool requested_sync = (read_cd_flags & T10MMC_READ_CD_FIELD_SYNC) != 0;
|
||||
|
||||
if (requested_c2 || requested_c2_error_block)
|
||||
m_transfer_length += 294;
|
||||
|
||||
if (requested_c2_error_block)
|
||||
m_transfer_length += 2;
|
||||
|
||||
if (track_type == cdrom_file::CD_TRACK_AUDIO)
|
||||
{
|
||||
if (requested_user_data)
|
||||
m_transfer_length += 2352;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE1 || track_type == cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
{
|
||||
if (requested_sync)
|
||||
m_transfer_length += 12;
|
||||
if (requested_header)
|
||||
m_transfer_length += 4;
|
||||
if (requested_user_data)
|
||||
m_transfer_length += 2048;
|
||||
if (requested_edc_ecc)
|
||||
m_transfer_length += 288;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2)
|
||||
{
|
||||
if (requested_sync)
|
||||
m_transfer_length += 12;
|
||||
if (requested_header)
|
||||
m_transfer_length += 4;
|
||||
if (requested_user_data)
|
||||
m_transfer_length += 2336;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || mode2_form == 1)
|
||||
{
|
||||
if (requested_sync)
|
||||
m_transfer_length += 12;
|
||||
if (requested_header)
|
||||
m_transfer_length += 4;
|
||||
if (requested_subheader)
|
||||
m_transfer_length += 8;
|
||||
if (requested_user_data)
|
||||
m_transfer_length += 2048;
|
||||
if (requested_edc_ecc)
|
||||
m_transfer_length += 280;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || mode2_form == 2)
|
||||
{
|
||||
if (requested_sync)
|
||||
m_transfer_length += 12;
|
||||
if (requested_header)
|
||||
m_transfer_length += 4;
|
||||
if (requested_subheader)
|
||||
m_transfer_length += 8;
|
||||
if (requested_user_data)
|
||||
m_transfer_length += 2328;
|
||||
}
|
||||
|
||||
last_track_type = track_type;
|
||||
last_read_cd_flags = read_cd_flags;
|
||||
}
|
||||
|
||||
if ((track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW) || command[9] != 0x10)
|
||||
{
|
||||
// TODO: Only mode 1 user data reads are supported for now
|
||||
m_device->logerror("T10MMC: READ CD called with unimplemented parameters\n");
|
||||
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
|
||||
m_transfer_length = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Only worry about SGI block extension stuff if it ever becomes an issue
|
||||
if (m_num_subblocks > 1)
|
||||
{
|
||||
m_cur_subblock = m_lba % m_num_subblocks;
|
||||
m_lba /= m_num_subblocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_subblock = 0;
|
||||
}
|
||||
m_device->logerror("T10MMC: READ CD does not handle sub blocks currently\n");
|
||||
|
||||
// All fields were matched between all tracks, so store the simplified version
|
||||
m_read_cd_flags = last_read_cd_flags | (m_read_cd_flags & ~0xf8);
|
||||
|
||||
m_cur_subblock = 0;
|
||||
m_phase = SCSI_PHASE_DATAIN;
|
||||
m_status_code = SCSI_STATUS_CODE_GOOD;
|
||||
m_transfer_length = m_blocks * m_sector_bytes;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -606,7 +770,7 @@ void t10mmc::ExecCommand()
|
||||
void t10mmc::ReadData( uint8_t *data, int dataLength )
|
||||
{
|
||||
uint32_t temp;
|
||||
uint8_t tmp_buffer[2048];
|
||||
uint8_t tmp_buffer[2352];
|
||||
|
||||
switch ( command[0] )
|
||||
{
|
||||
@ -640,7 +804,6 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
|
||||
|
||||
case T10SBC_CMD_READ_10:
|
||||
case T10SBC_CMD_READ_12:
|
||||
case T10MMC_CMD_READ_CD: // TODO: Will need its own logic once more support is implemented
|
||||
//m_device->logerror("T10MMC: read %x dataLength lba=%x\n", dataLength, m_lba);
|
||||
if ((m_image) && (m_blocks))
|
||||
{
|
||||
@ -672,6 +835,245 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
|
||||
}
|
||||
break;
|
||||
|
||||
case T10MMC_CMD_READ_CD:
|
||||
//m_device->logerror("T10MMC: read CD %x dataLength lba=%x\n", dataLength, m_lba);
|
||||
if ((m_image) && (m_blocks))
|
||||
{
|
||||
const int c2_error_codes = BIT(m_read_cd_flags, 1, 2);
|
||||
const bool requested_c2 = c2_error_codes == T10MMC_READ_CD_C2_ONLY;
|
||||
const bool requested_c2_error_block = c2_error_codes == T10MMC_READ_CD_C2_BLOCK;
|
||||
|
||||
const bool requested_edc_ecc = (m_read_cd_flags & T10MMC_READ_CD_FIELD_ECC) != 0;
|
||||
const bool requested_user_data = (m_read_cd_flags & T10MMC_READ_CD_FIELD_USER_DATA) != 0;
|
||||
const bool requested_header = (m_read_cd_flags & T10MMC_READ_CD_FIELD_HEADER) != 0;
|
||||
const bool requested_subheader = (m_read_cd_flags & T10MMC_READ_CD_FIELD_SUBHEADER) != 0;
|
||||
const bool requested_sync = (m_read_cd_flags & T10MMC_READ_CD_FIELD_SYNC) != 0;
|
||||
|
||||
// m_device->logerror("T10MMC: read CD flags c2[%d] c2block[%d] edc/ecc[%d] user[%d] header[%d] subheader[%d] sync[%d]\n", requested_c2, requested_c2_error_block, requested_edc_ecc, requested_user_data, requested_header, requested_subheader, requested_sync);
|
||||
|
||||
if (m_read_cd_flags == 0)
|
||||
{
|
||||
// No data is supposed to be returned
|
||||
if (dataLength > 0)
|
||||
memset(data, 0, dataLength);
|
||||
|
||||
data += dataLength;
|
||||
dataLength = 0;
|
||||
}
|
||||
|
||||
while (dataLength > 0)
|
||||
{
|
||||
int data_idx = 0;
|
||||
auto trk = m_image->get_track(m_lba);
|
||||
auto track_type = m_image->get_track_type(trk);
|
||||
|
||||
// Some CHDs don't have the required data so just log the error and return zeros as required
|
||||
// CD_TRACK_MODE1: Only has user data
|
||||
// CD_TRACK_MODE1_RAW: Has all fields required
|
||||
// CD_TRACK_MODE2: Only has user data
|
||||
// CD_TRACK_MODE2_FORM1: ?
|
||||
// CD_TRACK_MODE2_FORM2: ?
|
||||
// CD_TRACK_MODE2_FORM_MIX: Subheader data + user data + EDC/ECC data
|
||||
// CD_TRACK_MODE2_RAW: Has all fields required
|
||||
// CD_TRACK_AUDIO: Only returns user data
|
||||
|
||||
auto read_track_type = track_type;
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE1)
|
||||
read_track_type = cdrom_file::CD_TRACK_MODE1_RAW; // mode1 has code for partial promotion to mode1_raw so make use of it
|
||||
|
||||
if (!m_image->read_data(m_lba, tmp_buffer, read_track_type))
|
||||
{
|
||||
m_device->logerror("T10MMC: CD read error! (%08x)\n", m_lba);
|
||||
return;
|
||||
}
|
||||
|
||||
int mode2_form = 0;
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2_RAW)
|
||||
mode2_form = BIT(tmp_buffer[0x12], 5) + 1;
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
|
||||
mode2_form = BIT(tmp_buffer[2], 5) + 1;
|
||||
|
||||
if (requested_sync)
|
||||
{
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
|
||||
{
|
||||
m_device->logerror("T10MMC: sync data is not available for track type %d, inserting fake sync data\n", track_type);
|
||||
constexpr uint8_t sync_field[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
|
||||
memcpy(data + data_idx, sync_field, std::size(sync_field));
|
||||
}
|
||||
else
|
||||
memcpy(data + data_idx, tmp_buffer, 12);
|
||||
|
||||
data_idx += 12;
|
||||
}
|
||||
|
||||
if (requested_header)
|
||||
{
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2 || track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
|
||||
{
|
||||
m_device->logerror("T10MMC: header data is not available for track type %d, inserting fake header data\n", track_type);
|
||||
|
||||
uint32_t msf = to_msf(m_lba);
|
||||
data[data_idx] = BIT(msf, 16, 8);
|
||||
data[data_idx+1] = BIT(msf, 8, 8);
|
||||
data[data_idx+2] = BIT(msf, 0, 8);
|
||||
data[data_idx+3] = 2; // mode 2
|
||||
}
|
||||
else
|
||||
memcpy(data + data_idx, tmp_buffer + 12, 4);
|
||||
|
||||
data_idx += 4;
|
||||
}
|
||||
|
||||
if (requested_subheader)
|
||||
{
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2_RAW)
|
||||
{
|
||||
memcpy(data + data_idx, tmp_buffer + 16, 8);
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX)
|
||||
{
|
||||
// Only been able to verify 1 CHD for form mix, appears to have the 8 subheader bytes at the top of the sector
|
||||
memcpy(data + data_idx, tmp_buffer, 8);
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1 || track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
|
||||
{
|
||||
// It's not possible to generate a fake subheader for mode 2 tracks because the submode byte contains detailed info
|
||||
// about what actual data is inside the block
|
||||
m_device->logerror("T10MMC: subheader data is not available for track type %d\n", track_type);
|
||||
memset(data + data_idx, 0, 8);
|
||||
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
|
||||
data[data_idx+2] = data[data_idx+6] = 1 << 5; // The form 2 flag can at least be set accurately
|
||||
}
|
||||
|
||||
// Mode 1 and mode 2 formless return 0 bytes
|
||||
if (track_type != cdrom_file::CD_TRACK_MODE1 && track_type != cdrom_file::CD_TRACK_MODE1_RAW && track_type != cdrom_file::CD_TRACK_MODE2)
|
||||
data_idx += 8;
|
||||
}
|
||||
|
||||
if (requested_user_data)
|
||||
{
|
||||
int buffer_offset = 0;
|
||||
int data_len = 0;
|
||||
|
||||
if (track_type == cdrom_file::CD_TRACK_AUDIO)
|
||||
{
|
||||
buffer_offset = 0;
|
||||
data_len = 2352;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE1)
|
||||
{
|
||||
buffer_offset = 0;
|
||||
data_len = 2048;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
{
|
||||
buffer_offset = 16;
|
||||
data_len = 2048;
|
||||
}
|
||||
else if ((track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 1))
|
||||
{
|
||||
buffer_offset = 24;
|
||||
data_len = 2048;
|
||||
}
|
||||
else if ((track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 2))
|
||||
{
|
||||
buffer_offset = 24;
|
||||
data_len = 2328;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 1)
|
||||
{
|
||||
buffer_offset = 8;
|
||||
data_len = 2048;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 2)
|
||||
{
|
||||
buffer_offset = 8;
|
||||
data_len = 2328;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2)
|
||||
{
|
||||
// Untested
|
||||
buffer_offset = 0;
|
||||
data_len = 2336;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM1)
|
||||
{
|
||||
// Untested
|
||||
m_device->logerror("T10MMC: reading user data from untested mode 2 form 1 track\n");
|
||||
buffer_offset = 0;
|
||||
data_len = 2048;
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
|
||||
{
|
||||
// Untested
|
||||
m_device->logerror("T10MMC: reading user data from untested mode 2 form 2 track\n");
|
||||
buffer_offset = 0;
|
||||
data_len = 2324;
|
||||
}
|
||||
|
||||
memcpy(data + data_idx, tmp_buffer + buffer_offset, data_len);
|
||||
data_idx += data_len;
|
||||
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE2_FORM2)
|
||||
{
|
||||
// Untested, but the sector size of 2324 as noted in cdrom.h
|
||||
// implies the lack of the last 4 bytes for the (optional) CRC
|
||||
memset(data + data_idx, 0, 4);
|
||||
data_idx += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (requested_edc_ecc)
|
||||
{
|
||||
if (track_type == cdrom_file::CD_TRACK_MODE1_RAW)
|
||||
{
|
||||
// Includes the 8 bytes of padding
|
||||
memcpy(data + data_idx, tmp_buffer + 16 + 2048, 288);
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_RAW && mode2_form == 1)
|
||||
{
|
||||
memcpy(data + data_idx, tmp_buffer + 24 + 2048, 280);
|
||||
}
|
||||
else if (track_type == cdrom_file::CD_TRACK_MODE2_FORM_MIX && mode2_form == 1)
|
||||
{
|
||||
memcpy(data + data_idx, tmp_buffer + 8 + 2048, 280);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_device->logerror("T10MMC: EDC/ECC data is not available for track type %d\n", track_type);
|
||||
memset(data + data_idx, 0, 280);
|
||||
}
|
||||
|
||||
data_idx += 280;
|
||||
}
|
||||
|
||||
if (requested_c2 || requested_c2_error_block)
|
||||
{
|
||||
m_device->logerror("T10MMC: C2 field is not supported, returning zero data\n");
|
||||
memset(data + data_idx, 0, 294);
|
||||
data_idx += 294;
|
||||
}
|
||||
|
||||
if (requested_c2_error_block)
|
||||
{
|
||||
m_device->logerror("T10MMC: error block field is not supported, returning zero data\n");
|
||||
memset(data + data_idx, 0, 2);
|
||||
data_idx += 2;
|
||||
}
|
||||
|
||||
m_lba++;
|
||||
m_blocks--;
|
||||
|
||||
m_last_lba = m_lba;
|
||||
dataLength -= data_idx;
|
||||
data += data_idx;
|
||||
data_idx = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T10MMC_CMD_READ_SUB_CHANNEL:
|
||||
switch (command[3])
|
||||
{
|
||||
|
@ -48,6 +48,26 @@ protected:
|
||||
T10MMC_CMD_READ_CD = 0xbe
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
T10MMC_READ_CD_SECTOR_TYPE_ANY = 0,
|
||||
T10MMC_READ_CD_SECTOR_TYPE_CDDA = 1,
|
||||
T10MMC_READ_CD_SECTOR_TYPE_MODE1 = 2,
|
||||
T10MMC_READ_CD_SECTOR_TYPE_MODE2 = 3,
|
||||
T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM1 = 4,
|
||||
T10MMC_READ_CD_SECTOR_TYPE_MODE2_FORM2 = 5,
|
||||
|
||||
// These shouldn't be treated as masks, 3 is a reserved value
|
||||
T10MMC_READ_CD_C2_ONLY = 1, // C2 error bits (294 bytes)
|
||||
T10MMC_READ_CD_C2_BLOCK = 2, // C2 error bits (294 bytes) + block error byte (logical OR of all the C2 error bit bytes) + 1 padding byte
|
||||
|
||||
T10MMC_READ_CD_FIELD_ECC = 0x08, // EDC/ECC
|
||||
T10MMC_READ_CD_FIELD_USER_DATA = 0x10,
|
||||
T10MMC_READ_CD_FIELD_HEADER = 0x20,
|
||||
T10MMC_READ_CD_FIELD_SUBHEADER = 0x40,
|
||||
T10MMC_READ_CD_FIELD_SYNC = 0x80,
|
||||
};
|
||||
|
||||
enum toc_format_t
|
||||
{
|
||||
TOC_FORMAT_TRACKS = 0,
|
||||
@ -70,6 +90,7 @@ protected:
|
||||
uint32_t m_cur_subblock;
|
||||
int m_audio_sense;
|
||||
int m_sotc;
|
||||
uint8_t m_read_cd_flags;
|
||||
|
||||
device_t *m_device;
|
||||
};
|
||||
|
@ -50,6 +50,7 @@ protected:
|
||||
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_FIELD_IN_CDB = 0x2400,
|
||||
SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK = 0x6400
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */
|
||||
CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */
|
||||
CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */
|
||||
CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */
|
||||
CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes/sector */
|
||||
CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */
|
||||
|
||||
CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */
|
||||
|
Loading…
Reference in New Issue
Block a user