From d7e918dabe9d52b6eeb76d68b099157625bd37c0 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 24 Sep 2025 17:50:05 +0100 Subject: [PATCH] Implement READ BUFFER CAPACITY command for CD-ROM --- src/cdrom/cdrom.c | 35 +++++++++++++++++++++++++++++++++ src/include/86box/cdrom.h | 1 + src/include/86box/scsi_device.h | 1 + src/scsi/scsi_cdrom.c | 22 +++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index f6c7e9297..7f6c299b0 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -3455,4 +3455,39 @@ int cdrom_send_cuesheet(cdrom_t *dev, const uint8_t *buffer, int len) { return dev->ops->send_cuesheet(dev->local, buffer, len); +} + +int +cdrom_read_buffer_capacity(cdrom_t *dev, uint8_t *buffer, int block) +{ + /* Buffer capacity hardcoded to 1MiB */ + + memset(buffer, 0, 12); + + buffer[0] = 0x00; /* Data Length (MSB) */ + buffer[1] = 0x0a; /* Data Length (LSB) */ + buffer[2] = 0x00; /* Reserved */ + buffer[3] = 0x00; /* Reserved */ + if (block) { /* 512 blocks */ + buffer[4] = 0x00; /* Length of the Buffer (MSB...) */ + buffer[5] = 0x00; /* ... */ + buffer[6] = 0x02; /* ... */ + buffer[7] = 0x00; /* Length of the Buffer (...LSB) */ + buffer[8] = 0x00; /* Blank Length of the Buffer (MSB...) */ + buffer[9] = 0x00; /* ... */ + buffer[10] = 0x00; /* ... */ + buffer[11] = 0x00; /* Blank Length of the Buffer (...LSB) */ + } + else { /* 1048576 bytes */ + buffer[4] = 0x00; /* Length of the Buffer (MSB...) */ + buffer[5] = 0x10; /* ... */ + buffer[6] = 0x00; /* ... */ + buffer[7] = 0x00; /* Length of the Buffer (...LSB) */ + buffer[8] = 0x00; /* Blank Length of the Buffer (MSB...) */ + buffer[9] = 0x10; /* ... */ + buffer[10] = 0x00; /* ... */ + buffer[11] = 0x00; /* Blank Length of the Buffer (...LSB) */ + } + + return 12; } \ No newline at end of file diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index d536470a8..e5c4cca80 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -491,6 +491,7 @@ extern void cdrom_compute_ecc_block(cdrom_t *dev, uint8_t *parity, co extern unsigned long cdrom_crc32(unsigned long crc, const unsigned char *buf, size_t len); extern int cdrom_send_cuesheet(cdrom_t *dev, const uint8_t *buffer, int len); +extern int cdrom_read_buffer_capacity(cdrom_t *dev, uint8_t *buffer, int block); extern int cdrom_assigned_letters; diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index a720ca925..203e5af5f 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -92,6 +92,7 @@ #define GPCMD_READ_TRACK_INFORMATION 0x52 #define GPCMD_MODE_SELECT_10 0x55 #define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_READ_BUFFER_CAPACITY 0x5c #define GPCMD_SEND_CUE_SHEET 0x5d #define GPCMD_PLAY_AUDIO_12 0xa5 #define GPCMD_READ_12 0xa8 diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 7e7328fe6..5c090257e 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -98,6 +98,7 @@ uint8_t scsi_cdrom_command_flags[0x100] = { [0x51 ... 0x52] = IMPLEMENTED | CHECK_READY, [0x55] = IMPLEMENTED, [0x5a] = IMPLEMENTED, + [0x5c] = IMPLEMENTED | CHECK_READY, [0x5d] = IMPLEMENTED | CHECK_READY, [0xa5] = IMPLEMENTED | CHECK_READY, [0xa8 ... 0xa9] = IMPLEMENTED | CHECK_READY, @@ -3704,6 +3705,27 @@ atapi_out: scsi_cdrom_command_complete(dev); break; + case GPCMD_READ_BUFFER_CAPACITY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + scsi_cdrom_buf_alloc(dev, 12); + + memset(dev->buffer, 0, 12); + + int block = cdb[1] & 1; + + len = cdrom_read_buffer_capacity(dev->drv, dev->buffer, block); + + if (len < 0) { + scsi_cdrom_invalid_field(dev, cdb[1]); + break; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + default: scsi_cdrom_illegal_opcode(dev, dev->current_cdb[0]); break;