|
@@ -219,15 +219,34 @@ static const uint8_t DiscInformation[] =
|
|
|
0x00, // 33: number of opc tables
|
|
0x00, // 33: number of opc tables
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// Convert logical block address to CD-ROM time in formatted TOC format
|
|
|
|
|
|
|
+// Convert logical block address to CD-ROM time
|
|
|
static void LBA2MSF(uint32_t LBA, uint8_t* MSF)
|
|
static void LBA2MSF(uint32_t LBA, uint8_t* MSF)
|
|
|
{
|
|
{
|
|
|
- MSF[0] = 0; // reserved.
|
|
|
|
|
- MSF[3] = LBA % 75; // Frames
|
|
|
|
|
|
|
+ MSF[2] = LBA % 75; // Frames
|
|
|
uint32_t rem = LBA / 75;
|
|
uint32_t rem = LBA / 75;
|
|
|
|
|
|
|
|
- MSF[2] = rem % 60; // Seconds
|
|
|
|
|
- MSF[1] = rem / 60; // Minutes
|
|
|
|
|
|
|
+ MSF[1] = rem % 60; // Seconds
|
|
|
|
|
+ MSF[0] = rem / 60; // Minutes
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Convert logical block address to CD-ROM time in binary coded decimal format
|
|
|
|
|
+static void LBA2MSFBCD(uint32_t LBA, uint8_t* MSF)
|
|
|
|
|
+{
|
|
|
|
|
+ uint8_t fra = LBA % 75;
|
|
|
|
|
+ uint32_t rem = LBA / 75;
|
|
|
|
|
+ uint8_t sec = rem % 60;
|
|
|
|
|
+ uint8_t min = rem / 60;
|
|
|
|
|
+
|
|
|
|
|
+ MSF[0] = ((min / 10) << 4) | (min % 10);
|
|
|
|
|
+ MSF[1] = ((sec / 10) << 4) | (sec % 10);
|
|
|
|
|
+ MSF[2] = ((fra / 10) << 4) | (fra % 10);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Convert CD-ROM time to logical block address
|
|
|
|
|
+static uint32_t MSF2LBA(uint8_t m, uint8_t s, uint8_t f)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t lba = (m * 60 + s) * 75 + f;
|
|
|
|
|
+ return lba;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void doReadTOCSimple(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
static void doReadTOCSimple(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
@@ -246,7 +265,8 @@ static void doReadTOCSimple(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
|
// Replace start of leadout track
|
|
// Replace start of leadout track
|
|
|
if (MSF)
|
|
if (MSF)
|
|
|
{
|
|
{
|
|
|
- LBA2MSF(capacity, scsiDev.data + 8);
|
|
|
|
|
|
|
+ scsiDev.data[8] = 0;
|
|
|
|
|
+ LBA2MSF(capacity, scsiDev.data + 9);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -278,7 +298,8 @@ static void doReadTOCSimple(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
|
// Replace start of leadout track
|
|
// Replace start of leadout track
|
|
|
if (MSF)
|
|
if (MSF)
|
|
|
{
|
|
{
|
|
|
- LBA2MSF(capacity, scsiDev.data + 0x10);
|
|
|
|
|
|
|
+ scsiDev.data[0x10] = 0;
|
|
|
|
|
+ LBA2MSF(capacity, scsiDev.data + 0x11);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -433,7 +454,8 @@ static void formatTrackInfo(const CUETrackInfo *track, uint8_t *dest, bool use_M
|
|
|
if (use_MSF_time)
|
|
if (use_MSF_time)
|
|
|
{
|
|
{
|
|
|
// Time in minute-second-frame format
|
|
// Time in minute-second-frame format
|
|
|
- LBA2MSF(track->data_start, &dest[4]);
|
|
|
|
|
|
|
+ dest[4] = 0;
|
|
|
|
|
+ LBA2MSF(track->data_start, &dest[5]);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -492,7 +514,7 @@ static void doReadTOC(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
|
if (firsttrack < 0) firsttrack = trackinfo->track_number;
|
|
if (firsttrack < 0) firsttrack = trackinfo->track_number;
|
|
|
lasttrack = trackinfo->track_number;
|
|
lasttrack = trackinfo->track_number;
|
|
|
|
|
|
|
|
- if (track == 0 || track == trackinfo->track_number)
|
|
|
|
|
|
|
+ if (track <= trackinfo->track_number)
|
|
|
{
|
|
{
|
|
|
formatTrackInfo(trackinfo, &trackdata[8 * trackcount], MSF);
|
|
formatTrackInfo(trackinfo, &trackdata[8 * trackcount], MSF);
|
|
|
trackcount += 1;
|
|
trackcount += 1;
|
|
@@ -500,15 +522,12 @@ static void doReadTOC(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Format lead-out track info
|
|
// Format lead-out track info
|
|
|
- if (track == 0 || track == 0xAA)
|
|
|
|
|
- {
|
|
|
|
|
- CUETrackInfo leadout = {};
|
|
|
|
|
- leadout.track_number = 0xAA;
|
|
|
|
|
- leadout.track_mode = CUETrack_MODE1_2048;
|
|
|
|
|
- leadout.data_start = img.scsiSectors;
|
|
|
|
|
- formatTrackInfo(&leadout, &trackdata[8 * trackcount], MSF);
|
|
|
|
|
- trackcount += 1;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ CUETrackInfo leadout = {};
|
|
|
|
|
+ leadout.track_number = 0xAA;
|
|
|
|
|
+ leadout.track_mode = CUETrack_MODE1_2048;
|
|
|
|
|
+ leadout.data_start = img.scsiSectors;
|
|
|
|
|
+ formatTrackInfo(&leadout, &trackdata[8 * trackcount], MSF);
|
|
|
|
|
+ trackcount += 1;
|
|
|
|
|
|
|
|
// Format response header
|
|
// Format response header
|
|
|
uint16_t toc_length = 2 + trackcount * 8;
|
|
uint16_t toc_length = 2 + trackcount * 8;
|
|
@@ -517,7 +536,7 @@ static void doReadTOC(bool MSF, uint8_t track, uint16_t allocationLength)
|
|
|
scsiDev.data[2] = firsttrack;
|
|
scsiDev.data[2] = firsttrack;
|
|
|
scsiDev.data[3] = lasttrack;
|
|
scsiDev.data[3] = lasttrack;
|
|
|
|
|
|
|
|
- if (trackcount == 0)
|
|
|
|
|
|
|
+ if (track != 0xAA && trackcount < 2)
|
|
|
{
|
|
{
|
|
|
// Unknown track requested
|
|
// Unknown track requested
|
|
|
scsiDev.status = CHECK_CONDITION;
|
|
scsiDev.status = CHECK_CONDITION;
|
|
@@ -568,29 +587,6 @@ static void doReadSessionInfo(uint8_t session, uint16_t allocationLength)
|
|
|
scsiDev.phase = DATA_IN;
|
|
scsiDev.phase = DATA_IN;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Convert logical block address to CD-ROM time in the raw TOC format
|
|
|
|
|
-static void LBA2MSFRaw(uint32_t LBA, uint8_t* MSF)
|
|
|
|
|
-{
|
|
|
|
|
- MSF[2] = LBA % 75; // Frames
|
|
|
|
|
- uint32_t rem = LBA / 75;
|
|
|
|
|
-
|
|
|
|
|
- MSF[1] = rem % 60; // Seconds
|
|
|
|
|
- MSF[0] = rem / 60; // Minutes
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// Convert logical block address to CD-ROM time in binary coded decimal format
|
|
|
|
|
-static void LBA2MSFBCD(uint32_t LBA, uint8_t* MSF)
|
|
|
|
|
-{
|
|
|
|
|
- uint8_t fra = LBA % 75;
|
|
|
|
|
- uint32_t rem = LBA / 75;
|
|
|
|
|
- uint8_t sec = rem % 60;
|
|
|
|
|
- uint8_t min = rem / 60;
|
|
|
|
|
-
|
|
|
|
|
- MSF[0] = ((min / 10) << 4) | (min % 10);
|
|
|
|
|
- MSF[1] = ((sec / 10) << 4) | (sec % 10);
|
|
|
|
|
- MSF[2] = ((fra / 10) << 4) | (fra % 10);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// Format track info read from cue sheet into the format used by ReadFullTOC command.
|
|
// Format track info read from cue sheet into the format used by ReadFullTOC command.
|
|
|
// Refer to T10/1545-D MMC-4 Revision 5a, "Response Format 0010b: Raw TOC"
|
|
// Refer to T10/1545-D MMC-4 Revision 5a, "Response Format 0010b: Raw TOC"
|
|
|
static void formatRawTrackInfo(const CUETrackInfo *track, uint8_t *dest)
|
|
static void formatRawTrackInfo(const CUETrackInfo *track, uint8_t *dest)
|
|
@@ -606,16 +602,13 @@ static void formatRawTrackInfo(const CUETrackInfo *track, uint8_t *dest)
|
|
|
dest[1] = control_adr;
|
|
dest[1] = control_adr;
|
|
|
dest[2] = 0x00; // "TNO", always 0?
|
|
dest[2] = 0x00; // "TNO", always 0?
|
|
|
dest[3] = track->track_number; // "POINT", contains track number
|
|
dest[3] = track->track_number; // "POINT", contains track number
|
|
|
-
|
|
|
|
|
- if (track->pregap_start > 0)
|
|
|
|
|
- {
|
|
|
|
|
- LBA2MSFRaw(track->pregap_start, &dest[4]);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- LBA2MSFRaw(track->data_start, &dest[4]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // Next three are ATIME. The spec doesn't directly address how these
|
|
|
|
|
+ // should be reported in the TOC, just giving a description of Q-channel
|
|
|
|
|
+ // data from Red Book/ECMA-130. On all disks tested so far these are
|
|
|
|
|
+ // given as 00/00/00.
|
|
|
|
|
+ dest[4] = 0x00;
|
|
|
|
|
+ dest[5] = 0x00;
|
|
|
|
|
+ dest[6] = 0x00;
|
|
|
dest[7] = 0; // HOUR
|
|
dest[7] = 0; // HOUR
|
|
|
|
|
|
|
|
LBA2MSFBCD(track->data_start, &dest[8]);
|
|
LBA2MSFBCD(track->data_start, &dest[8]);
|
|
@@ -719,7 +712,8 @@ void doReadHeader(bool MSF, uint32_t lba, uint16_t allocationLength)
|
|
|
// Track start
|
|
// Track start
|
|
|
if (MSF)
|
|
if (MSF)
|
|
|
{
|
|
{
|
|
|
- LBA2MSF(trackinfo.data_start, &scsiDev.data[4]);
|
|
|
|
|
|
|
+ scsiDev.data[4] = 0;
|
|
|
|
|
+ LBA2MSF(trackinfo.data_start, &scsiDev.data[5]);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -818,6 +812,18 @@ bool cdromValidateCueSheet(image_config_t &img)
|
|
|
/* Ejection and image switching logic */
|
|
/* Ejection and image switching logic */
|
|
|
/**************************************/
|
|
/**************************************/
|
|
|
|
|
|
|
|
|
|
+void cdromPerformEject(image_config_t &img)
|
|
|
|
|
+{
|
|
|
|
|
+ uint8_t target = img.scsiId & 7;
|
|
|
|
|
+#if ENABLE_AUDIO_OUTPUT
|
|
|
|
|
+ // terminate audio playback if active on this target (MMC-1 Annex C)
|
|
|
|
|
+ audio_stop(target);
|
|
|
|
|
+#endif
|
|
|
|
|
+ dbgmsg("------ CDROM open tray on ID ", (int)target);
|
|
|
|
|
+ img.ejected = true;
|
|
|
|
|
+ img.cdrom_events = 3; // Media removal
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Reinsert any ejected CDROMs on reboot
|
|
// Reinsert any ejected CDROMs on reboot
|
|
|
void cdromReinsertFirstImage(image_config_t &img)
|
|
void cdromReinsertFirstImage(image_config_t &img)
|
|
|
{
|
|
{
|
|
@@ -1238,6 +1244,7 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
|
|
|
for (uint32_t idx = 0; idx < length; idx++)
|
|
for (uint32_t idx = 0; idx < length; idx++)
|
|
|
{
|
|
{
|
|
|
platform_poll();
|
|
platform_poll();
|
|
|
|
|
+ diskEjectButtonUpdate(false);
|
|
|
|
|
|
|
|
img.file.seek(offset + idx * trackinfo.sector_length + skip_begin);
|
|
img.file.seek(offset + idx * trackinfo.sector_length + skip_begin);
|
|
|
|
|
|
|
@@ -1253,6 +1260,7 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
|
|
|
scsiDev.resetFlag = 1;
|
|
scsiDev.resetFlag = 1;
|
|
|
}
|
|
}
|
|
|
platform_poll();
|
|
platform_poll();
|
|
|
|
|
+ diskEjectButtonUpdate(false);
|
|
|
}
|
|
}
|
|
|
if (scsiDev.resetFlag) break;
|
|
if (scsiDev.resetFlag) break;
|
|
|
|
|
|
|
@@ -1293,9 +1301,9 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
|
|
|
*buf++ = (trackinfo.track_mode == CUETrack_AUDIO ? 0x10 : 0x14); // Control & ADR
|
|
*buf++ = (trackinfo.track_mode == CUETrack_AUDIO ? 0x10 : 0x14); // Control & ADR
|
|
|
*buf++ = trackinfo.track_number;
|
|
*buf++ = trackinfo.track_number;
|
|
|
*buf++ = (lba + idx >= trackinfo.data_start) ? 1 : 0; // Index number (0 = pregap)
|
|
*buf++ = (lba + idx >= trackinfo.data_start) ? 1 : 0; // Index number (0 = pregap)
|
|
|
- LBA2MSFRaw(lba + idx, buf); buf += 3;
|
|
|
|
|
|
|
+ LBA2MSF(lba + idx, buf); buf += 3;
|
|
|
*buf++ = 0;
|
|
*buf++ = 0;
|
|
|
- LBA2MSFRaw(lba + idx, buf); buf += 3;
|
|
|
|
|
|
|
+ LBA2MSF(lba + idx, buf); buf += 3;
|
|
|
*buf++ = 0; *buf++ = 0; // CRC (optional)
|
|
*buf++ = 0; *buf++ = 0; // CRC (optional)
|
|
|
*buf++ = 0; *buf++ = 0; *buf++ = 0; // (pad)
|
|
*buf++ = 0; *buf++ = 0; *buf++ = 0; // (pad)
|
|
|
*buf++ = 0; // No P subchannel
|
|
*buf++ = 0; // No P subchannel
|
|
@@ -1345,9 +1353,10 @@ static void doReadSubchannel(bool time, bool subq, uint8_t parameter, uint8_t tr
|
|
|
*buf++ = (lba >= trackinfo.data_start) ? 1 : 0; // Index number (0 = pregap)
|
|
*buf++ = (lba >= trackinfo.data_start) ? 1 : 0; // Index number (0 = pregap)
|
|
|
if (time)
|
|
if (time)
|
|
|
{
|
|
{
|
|
|
|
|
+ *buf++ = 0;
|
|
|
LBA2MSF(lba, buf);
|
|
LBA2MSF(lba, buf);
|
|
|
- dbgmsg("------ ABS M ", *(buf+1), " S ", *(buf+2), " F ", *(buf+3));
|
|
|
|
|
- *buf += 4;
|
|
|
|
|
|
|
+ dbgmsg("------ ABS M ", *buf, " S ", *(buf+1), " F ", *(buf+2));
|
|
|
|
|
+ buf += 3;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -1360,9 +1369,10 @@ static void doReadSubchannel(bool time, bool subq, uint8_t parameter, uint8_t tr
|
|
|
uint32_t relpos = (uint32_t)((int32_t)lba - (int32_t)trackinfo.data_start);
|
|
uint32_t relpos = (uint32_t)((int32_t)lba - (int32_t)trackinfo.data_start);
|
|
|
if (time)
|
|
if (time)
|
|
|
{
|
|
{
|
|
|
|
|
+ *buf++ = 0;
|
|
|
LBA2MSF(relpos, buf);
|
|
LBA2MSF(relpos, buf);
|
|
|
- dbgmsg("------ REL M ", *(buf+1), " S ", *(buf+2), " F ", *(buf+3));
|
|
|
|
|
- *buf += 4;
|
|
|
|
|
|
|
+ dbgmsg("------ REL M ", *buf, " S ", *(buf+1), " F ", *(buf+2));
|
|
|
|
|
+ buf += 3;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -1409,25 +1419,19 @@ extern "C" int scsiCDRomCommand()
|
|
|
uint8_t command = scsiDev.cdb[0];
|
|
uint8_t command = scsiDev.cdb[0];
|
|
|
if (command == 0x1B)
|
|
if (command == 0x1B)
|
|
|
{
|
|
{
|
|
|
-#if ENABLE_AUDIO_OUTPUT
|
|
|
|
|
- // terminate audio playback if active on this target (Annex C)
|
|
|
|
|
- audio_stop(img.scsiId & 7);
|
|
|
|
|
-#endif
|
|
|
|
|
if ((scsiDev.cdb[4] & 2))
|
|
if ((scsiDev.cdb[4] & 2))
|
|
|
{
|
|
{
|
|
|
// CD-ROM load & eject
|
|
// CD-ROM load & eject
|
|
|
int start = scsiDev.cdb[4] & 1;
|
|
int start = scsiDev.cdb[4] & 1;
|
|
|
if (start)
|
|
if (start)
|
|
|
{
|
|
{
|
|
|
- dbgmsg("------ CDROM close tray");
|
|
|
|
|
|
|
+ dbgmsg("------ CDROM close tray on ID ", (int)(img.scsiId & 7));
|
|
|
img.ejected = false;
|
|
img.ejected = false;
|
|
|
img.cdrom_events = 2; // New media
|
|
img.cdrom_events = 2; // New media
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- dbgmsg("------ CDROM open tray");
|
|
|
|
|
- img.ejected = true;
|
|
|
|
|
- img.cdrom_events = 3; // Media removal
|
|
|
|
|
|
|
+ cdromPerformEject(img);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -1520,8 +1524,8 @@ extern "C" int scsiCDRomCommand()
|
|
|
else if (command == 0x47)
|
|
else if (command == 0x47)
|
|
|
{
|
|
{
|
|
|
// PLAY AUDIO (MSF)
|
|
// PLAY AUDIO (MSF)
|
|
|
- uint32_t start = (scsiDev.cdb[3] * 60 + scsiDev.cdb[4]) * 75 + scsiDev.cdb[5];
|
|
|
|
|
- uint32_t end = (scsiDev.cdb[6] * 60 + scsiDev.cdb[7]) * 75 + scsiDev.cdb[8];
|
|
|
|
|
|
|
+ uint32_t start = MSF2LBA(scsiDev.cdb[3], scsiDev.cdb[4], scsiDev.cdb[5]);
|
|
|
|
|
+ uint32_t end = MSF2LBA(scsiDev.cdb[6], scsiDev.cdb[7], scsiDev.cdb[8]);
|
|
|
|
|
|
|
|
uint32_t lba = start;
|
|
uint32_t lba = start;
|
|
|
if (scsiDev.cdb[3] == 0xFF
|
|
if (scsiDev.cdb[3] == 0xFF
|
|
@@ -1575,8 +1579,8 @@ extern "C" int scsiCDRomCommand()
|
|
|
{
|
|
{
|
|
|
// ReadCD MSF
|
|
// ReadCD MSF
|
|
|
uint8_t sector_type = (scsiDev.cdb[1] >> 2) & 7;
|
|
uint8_t sector_type = (scsiDev.cdb[1] >> 2) & 7;
|
|
|
- uint32_t start = (scsiDev.cdb[3] * 60 + scsiDev.cdb[4]) * 75 + scsiDev.cdb[5];
|
|
|
|
|
- uint32_t end = (scsiDev.cdb[6] * 60 + scsiDev.cdb[7]) * 75 + scsiDev.cdb[8];
|
|
|
|
|
|
|
+ uint32_t start = MSF2LBA(scsiDev.cdb[3], scsiDev.cdb[4], scsiDev.cdb[5]);
|
|
|
|
|
+ uint32_t end = MSF2LBA(scsiDev.cdb[6], scsiDev.cdb[7], scsiDev.cdb[8]);
|
|
|
uint8_t main_channel = scsiDev.cdb[9];
|
|
uint8_t main_channel = scsiDev.cdb[9];
|
|
|
uint8_t sub_channel = scsiDev.cdb[10];
|
|
uint8_t sub_channel = scsiDev.cdb[10];
|
|
|
|
|
|