ソースを参照

SCSI2SD: Add support for lead-out track in CDROM READTOC (#184)

Petteri Aimonen 2 年 前
コミット
23b389c87a
1 ファイル変更52 行追加8 行削除
  1. 52 8
      lib/SCSI2SD/src/firmware/cdrom.c

+ 52 - 8
lib/SCSI2SD/src/firmware/cdrom.c

@@ -40,6 +40,19 @@ static const uint8_t SimpleTOC[] =
 	0x00,0x00,0x00,0x00, // Track start sector (LBA)
 };
 
+static const uint8_t LeadoutTOC[] =
+{
+	0x00, // toc length, MSB
+	0x0A, // toc length, LSB
+	0x01, // First track number
+	0x01, // Last track number,
+	0x00, // reserved
+	0x14, // Q sub-channel encodes current position, Digital track
+	0xAA, // Leadout Track
+	0x00, // Reserved
+	0x00,0x00,0x00,0x00, // Track start sector (LBA)
+};
+
 static const uint8_t SessionTOC[] =
 {
 	0x00, // toc length, MSB
@@ -148,17 +161,41 @@ static void LBA2MSF(uint32_t LBA, uint8_t* MSF)
 
 static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
 {
-	// We only support track 1.
-	// track 0 means "return all tracks"
-	if (track > 1)
+	if (track == 0xAA)
 	{
-		scsiDev.status = CHECK_CONDITION;
-		scsiDev.target->sense.code = ILLEGAL_REQUEST;
-		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
-		scsiDev.phase = STATUS;
+		// 0xAA requests only lead-out track information (reports capacity)
+		uint32_t len = sizeof(LeadoutTOC);
+		memcpy(scsiDev.data, LeadoutTOC, len);
+
+		uint32_t capacity = getScsiCapacity(
+			scsiDev.target->cfg->sdSectorStart,
+			scsiDev.target->liveCfg.bytesPerSector,
+			scsiDev.target->cfg->scsiSectors);
+
+		// Replace start of leadout track
+		if (MSF)
+		{
+			LBA2MSF(capacity, scsiDev.data + 8);
+		}
+		else
+		{
+			scsiDev.data[8] = capacity >> 24;
+			scsiDev.data[9] = capacity >> 16;
+			scsiDev.data[10] = capacity >> 8;
+			scsiDev.data[11] = capacity;
+		}
+
+		if (len > allocationLength)
+		{
+			len = allocationLength;
+		}
+		scsiDev.dataLen = len;
+		scsiDev.phase = DATA_IN;
 	}
-	else
+	else if (track <= 1)
 	{
+		// We only support track 1.
+		// track 0 means "return all tracks"
 		uint32_t len = sizeof(SimpleTOC);
 		memcpy(scsiDev.data, SimpleTOC, len);
 
@@ -187,6 +224,13 @@ static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
 		scsiDev.dataLen = len;
 		scsiDev.phase = DATA_IN;
 	}
+	else
+	{
+		scsiDev.status = CHECK_CONDITION;
+		scsiDev.target->sense.code = ILLEGAL_REQUEST;
+		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
+		scsiDev.phase = STATUS;
+	}
 }
 
 static void doReadSessionInfo(uint8_t session, uint16_t allocationLength)