From ce11437a7254fc1d3e64e4a1ea403e2d1e7a2636 Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Mon, 27 Oct 2025 16:14:45 -0500 Subject: [PATCH 1/4] update shell.nix --- shell.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/shell.nix b/shell.nix index b5186a5d..d12c0f0d 100644 --- a/shell.nix +++ b/shell.nix @@ -44,6 +44,7 @@ let cmake nodejs git + git-filter-repo gh picotool ]; From fe5d50fbea952ab82b5e83658c0bdc296e2a2959 Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Mon, 3 Nov 2025 19:10:06 -0600 Subject: [PATCH 2/4] feat: CDROM Initiatior passthrough Fixes eject, properly handles inquiry. Use TinyUSB 0.19.0 cb when avalible. Resolves #299 --- .../BlueSCSI_platform_msc.cpp | 36 +++++++- src/BlueSCSI_initiator.cpp | 2 +- src/BlueSCSI_msc_initiator.cpp | 83 ++++++++++++++++++- src/BlueSCSI_msc_initiator.h | 1 + 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/lib/BlueSCSI_platform_RP2MCU/BlueSCSI_platform_msc.cpp b/lib/BlueSCSI_platform_RP2MCU/BlueSCSI_platform_msc.cpp index 9bdc87ab..ae52a48e 100644 --- a/lib/BlueSCSI_platform_RP2MCU/BlueSCSI_platform_msc.cpp +++ b/lib/BlueSCSI_platform_RP2MCU/BlueSCSI_platform_msc.cpp @@ -241,10 +241,30 @@ extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { MSCScopedLock lock; - if (g_msc_initiator) return init_msc_inquiry_cb(lun, vendor_id, product_id, product_rev); + if (g_msc_initiator) { + init_msc_inquiry_cb(lun, vendor_id, product_id, product_rev); + + // Build a temporary inquiry structure to get the device type + uint8_t temp_inquiry[36]; + uint32_t result = init_msc_inquiry2_cb(lun, temp_inquiry, sizeof(temp_inquiry)); + + if (result > 0) { + uint8_t device_type = temp_inquiry[0] & 0x1F; + uint8_t is_removable = temp_inquiry[1] & 0x80; + + // The inquiry response buffer starts 8 bytes before vendor_id + // vendor_id is at offset 8 in scsi_inquiry_resp_t + uint8_t *inquiry_resp = vendor_id - 8; + + // Safely modify the device type fields + inquiry_resp[0] = (inquiry_resp[0] & 0xE0) | (device_type & 0x1F); + inquiry_resp[1] = (inquiry_resp[1] & 0x7F) | is_removable; + } + return; + } const char vid[] = "BlueSCSI"; - const char pid[] = PLATFORM_PID; + const char pid[] = PLATFORM_PID; const char rev[] = PLATFORM_REVISION; memcpy(vendor_id, vid, tu_min32(strlen(vid), 8)); @@ -252,6 +272,18 @@ extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], memcpy(product_rev, rev, tu_min32(strlen(rev), 4)); } +// TODO: When PicoSDK/Arduino-Pico are updated to include TinyUSB 0.19.0+ we can just use this instead of manually manipulating the buffer. +// extern "C" __attribute__((used)) uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t *inquiry_resp, uint32_t bufsize) { +// MSCScopedLock lock; +// logmsg("tud_msc_inquiry2_cb (v2): LUN=", (int)lun, " initiator_mode=", g_msc_initiator ? "YES" : "NO"); +// +// if (g_msc_initiator) { +// uint32_t result = init_msc_inquiry2_cb(lun, inquiry_resp, bufsize); +// return result; +// } +// return 0; +// } + // max LUN supported // we only have the one SD card extern "C" uint8_t tud_msc_get_maxlun_cb(void) diff --git a/src/BlueSCSI_initiator.cpp b/src/BlueSCSI_initiator.cpp index 21107bbc..5bd597dd 100644 --- a/src/BlueSCSI_initiator.cpp +++ b/src/BlueSCSI_initiator.cpp @@ -1,7 +1,7 @@ /** * This file is originally part of ZuluSCSI adopted for BlueSCSI * - * BlueSCSI - Copyright (c) 2024 Eric Helgeson, Androda + * BlueSCSI - Copyright (c) 2024-2025 Eric Helgeson, Androda * ZuluSCSI™ - Copyright (c) 2022-2025 Rabbit Hole Computing™ * * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.  diff --git a/src/BlueSCSI_msc_initiator.cpp b/src/BlueSCSI_msc_initiator.cpp index c3c82c52..73b1fbc9 100644 --- a/src/BlueSCSI_msc_initiator.cpp +++ b/src/BlueSCSI_msc_initiator.cpp @@ -4,6 +4,7 @@ * should be usable with other USB libraries. * * ZuluSCSI™ - Copyright (c) 2023-2025 Rabbit Hole Computing™ + * Eric Helgeson - Copyright (c) 2025 BlueSCSI * * This file is licensed under the GPL version 3 or any later version.  * It is derived from cdrom.c in SCSI2SD V6 @@ -33,6 +34,7 @@ #include #include #include + #include "SdFat.h" bool g_msc_initiator; @@ -43,6 +45,7 @@ bool setup_msc_initiator() { return false; } void poll_msc_initiator() {} void init_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {} +uint32_t init_msc_inquiry2_cb(uint8_t lun, void *inquiry_resp, uint32_t bufsize) { return 0; } uint8_t init_msc_get_maxlun_cb(void) { return 0; } bool init_msc_is_writable_cb (uint8_t lun) { return false; } bool init_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { return false; } @@ -61,6 +64,7 @@ static struct { uint32_t sectorsize; uint32_t sectorcount; bool use_read10; // Always use read10/write10 commands for this target + uint8_t device_type; // SCSI peripheral device type from INQUIRY byte 0 } g_msc_initiator_targets[NUM_SCSIID]; static int g_msc_initiator_target_count; @@ -113,27 +117,39 @@ static void scan_targets() char product_id[17] = {0}; memcpy(vendor_id, &inquiry_data[8], 8); memcpy(product_id, &inquiry_data[16], 16); + uint8_t device_type = inquiry_data[0] & 0x1f; if (inquiryok) { + const char *type_name = (device_type == SCSI_DEVICE_TYPE_CD) ? "CD-ROM" : + (device_type == SCSI_DEVICE_TYPE_DIRECT_ACCESS) ? "DISK" : "OTHER"; + if (readcapok) { logmsg("Found SCSI drive with ID ", target_id, ": ", vendor_id, " ", product_id, " capacity ", (int)(((uint64_t)sectorcount * sectorsize) / 1024 / 1024), " MB"); + logmsg(" Device Type: ", device_type, " (", type_name, ")"); + logmsg(" Will be mapped to USB LUN ", found_count); + g_msc_initiator_targets[found_count].target_id = target_id; g_msc_initiator_targets[found_count].sectorcount = sectorcount; g_msc_initiator_targets[found_count].sectorsize = sectorsize; g_msc_initiator_targets[found_count].use_read10 = scsiInitiatorTestSupportsRead10(target_id, sectorsize); + g_msc_initiator_targets[found_count].device_type = device_type; found_count++; } else { logmsg("Found SCSI drive with ID ", target_id, ": ", vendor_id, " ", product_id, " but failed to read capacity. Assuming SCSI-1 drive up to 1 GB."); + logmsg(" Device Type: ", device_type, " (", type_name, ")"); + logmsg(" Will be mapped to USB LUN ", found_count); + g_msc_initiator_targets[found_count].target_id = target_id; g_msc_initiator_targets[found_count].sectorcount = 2097152; g_msc_initiator_targets[found_count].sectorsize = 512; g_msc_initiator_targets[found_count].use_read10 = false; + g_msc_initiator_targets[found_count].device_type = device_type; found_count++; } } @@ -279,8 +295,67 @@ void init_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[1 memcpy(vendor_id, &response[8], 8); memcpy(product_id, &response[16], 16); memcpy(product_rev, &response[32], 4); + LED_OFF(); +} + +// V2 INQUIRY callback that allows setting device type for optical drives +uint32_t init_msc_inquiry2_cb(uint8_t lun, void *inquiry_resp, uint32_t bufsize) +{ + // Cast to access the inquiry response structure + // We use a local struct definition to avoid including TinyUSB headers + struct { + uint8_t peripheral_device_type : 5; + uint8_t peripheral_qualifier : 3; + uint8_t reserved1 : 7; + uint8_t is_removable : 1; + uint8_t version; + uint8_t response_data_format : 4; + uint8_t hierarchical_support : 1; + uint8_t normal_aca : 1; + uint8_t reserved2 : 2; + uint8_t additional_length; + uint8_t flags1; + uint8_t flags2; + uint8_t flags3; + uint8_t vendor_id[8]; + uint8_t product_id[16]; + uint8_t product_rev[4]; + } *inq_resp = (decltype(inq_resp))inquiry_resp; + + if (g_msc_initiator_target_count == 0 || lun >= g_msc_initiator_target_count) + { + return 0; + } + + LED_ON(); + g_msc_initiator_state.status_reqcount++; + + int target = get_target(lun); + uint8_t response[36] = {0}; + bool status = scsiInquiry(target, response); + if (!status) + { + logmsg("SCSI Inquiry2 to target ", target, " failed"); + LED_OFF(); + return 0; + } + + // Copy the original inquiry response, then override specific fields. + memcpy(inquiry_resp, response, 36); + + // uint8_t original_device_type = response[0] & 0x1f; + uint8_t stored_device_type = g_msc_initiator_targets[lun].device_type; + + inq_resp->peripheral_device_type = stored_device_type; + inq_resp->is_removable = (stored_device_type == SCSI_DEVICE_TYPE_CD) ? 1 : 0; + + char vendor_id[9] = {0}; + char product_id[17] = {0}; + memcpy(vendor_id, &response[8], 8); + memcpy(product_id, &response[16], 16); LED_OFF(); + return 36; // Return standard INQUIRY response length } uint8_t init_msc_get_maxlun_cb(void) @@ -325,21 +400,21 @@ bool init_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bo g_msc_initiator_state.status_reqcount++; int target = get_target(lun); - uint8_t command[6] = {0x1B, 0x1, 0, 0, 0, 0}; + uint8_t command[6] = {0x1B, 0x0, 0, 0, 0, 0}; uint8_t response[4] = {0}; - if (start) { command[4] |= 1; // Start command[1] = 0; // Immediate } - if (load_eject) + if (load_eject && g_msc_initiator_targets[lun].device_type == SCSI_DEVICE_TYPE_CD) { + logmsg("Ejecting"); command[4] |= 2; } - command[4] |= power_condition << 4; + command[4] |= static_cast((power_condition & 0x0F) << 4); int status = scsiInitiatorRunCommand(target, command, sizeof(command), diff --git a/src/BlueSCSI_msc_initiator.h b/src/BlueSCSI_msc_initiator.h index 61158b72..1481d91c 100644 --- a/src/BlueSCSI_msc_initiator.h +++ b/src/BlueSCSI_msc_initiator.h @@ -33,6 +33,7 @@ bool setup_msc_initiator(); void poll_msc_initiator(); void init_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]); +uint32_t init_msc_inquiry2_cb(uint8_t lun, void *inquiry_resp, uint32_t bufsize); uint8_t init_msc_get_maxlun_cb(void); bool init_msc_is_writable_cb (uint8_t lun); bool init_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); From 069fd5600cfcdfef1ac18288f1310d489bb96de9 Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Tue, 11 Nov 2025 16:22:09 -0600 Subject: [PATCH 3/4] feat: Removable/MO/ZipDisk USB passthrough Fixes a number of issues relating to handling eject/inject with real removable drives. --- src/BlueSCSI_initiator.cpp | 11 ++++- src/BlueSCSI_msc_initiator.cpp | 85 ++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/BlueSCSI_initiator.cpp b/src/BlueSCSI_initiator.cpp index 5bd597dd..00e64a65 100644 --- a/src/BlueSCSI_initiator.cpp +++ b/src/BlueSCSI_initiator.cpp @@ -881,8 +881,15 @@ bool scsiTestUnitReady(int target_id) } else if (sense_key == NOT_READY) { - dbgmsg("Target ", target_id, " reports NOT_READY, running STARTSTOPUNIT"); - scsiStartStopUnit(target_id, true); +#ifdef PLATFORM_MASS_STORAGE + // For MSC initiator mode, don't automatically send START_STOP_UNIT + // Removable media (Zip, MO, etc.) can eject if START is sent during loading + if (!g_msc_initiator) +#endif + { + dbgmsg("Target ", target_id, " reports NOT_READY, running STARTSTOPUNIT"); + scsiStartStopUnit(target_id, true); + } } } else diff --git a/src/BlueSCSI_msc_initiator.cpp b/src/BlueSCSI_msc_initiator.cpp index 73b1fbc9..c6656bf1 100644 --- a/src/BlueSCSI_msc_initiator.cpp +++ b/src/BlueSCSI_msc_initiator.cpp @@ -64,7 +64,8 @@ static struct { uint32_t sectorsize; uint32_t sectorcount; bool use_read10; // Always use read10/write10 commands for this target - uint8_t device_type; // SCSI peripheral device type from INQUIRY byte 0 + uint8_t device_type; // SCSI peripheral device type from INQUIRY byte 0 (bits 0-4) + bool is_removable; // RMB bit from INQUIRY byte 1 (bit 7) } g_msc_initiator_targets[NUM_SCSIID]; static int g_msc_initiator_target_count; @@ -107,23 +108,25 @@ static void scan_targets() { uint32_t sectorcount, sectorsize; - bool inquiryok = - scsiStartStopUnit(target_id, true) && - scsiInquiry(target_id, inquiry_data); - bool readcapok = - scsiInitiatorReadCapacity(target_id, §orcount, §orsize); + // Note: We don't send START_STOP_UNIT here anymore. For MSC initiator mode, + // START_STOP_UNIT is disabled in scsiTestUnitReady() to prevent interfering + // with removable media loading. The USB host sends START_STOP via callback. + bool inquiryok = scsiInquiry(target_id, inquiry_data); + bool readcapok = scsiInitiatorReadCapacity(target_id, §orcount, §orsize); char vendor_id[9] = {0}; char product_id[17] = {0}; memcpy(vendor_id, &inquiry_data[8], 8); memcpy(product_id, &inquiry_data[16], 16); uint8_t device_type = inquiry_data[0] & 0x1f; + bool is_removable = (inquiry_data[1] & 0x80) != 0; // RMB bit from INQUIRY byte 1 if (inquiryok) { const char *type_name = (device_type == SCSI_DEVICE_TYPE_CD) ? "CD-ROM" : - (device_type == SCSI_DEVICE_TYPE_DIRECT_ACCESS) ? "DISK" : "OTHER"; - + (device_type == SCSI_DEVICE_TYPE_MO) ? "MO" : + (device_type == SCSI_DEVICE_TYPE_DIRECT_ACCESS) ? + (is_removable ? "REMOVABLE" : "DISK") : "OTHER"; if (readcapok) { logmsg("Found SCSI drive with ID ", target_id, ": ", vendor_id, " ", product_id, @@ -136,6 +139,7 @@ static void scan_targets() g_msc_initiator_targets[found_count].sectorsize = sectorsize; g_msc_initiator_targets[found_count].use_read10 = scsiInitiatorTestSupportsRead10(target_id, sectorsize); g_msc_initiator_targets[found_count].device_type = device_type; + g_msc_initiator_targets[found_count].is_removable = is_removable; found_count++; } else @@ -150,6 +154,7 @@ static void scan_targets() g_msc_initiator_targets[found_count].sectorsize = 512; g_msc_initiator_targets[found_count].use_read10 = false; g_msc_initiator_targets[found_count].device_type = device_type; + g_msc_initiator_targets[found_count].is_removable = is_removable; found_count++; } } @@ -269,6 +274,22 @@ static int get_target(uint8_t lun) } } +// Helper function to determine if a device should be treated as removable for USB MSC +static bool is_removable_device(uint8_t lun) +{ + if (lun >= g_msc_initiator_target_count) + return false; + + uint8_t dtype = g_msc_initiator_targets[lun].device_type; + bool rmb = g_msc_initiator_targets[lun].is_removable; + + // CD-ROM and MO are always removable + // Direct Access devices are removable if RMB bit is set (Zip, removable disks, etc.) + return (dtype == SCSI_DEVICE_TYPE_CD) || + (dtype == SCSI_DEVICE_TYPE_MO) || + (dtype == SCSI_DEVICE_TYPE_DIRECT_ACCESS && rmb); +} + void init_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { dbgmsg("-- MSC Inquiry"); @@ -343,11 +364,15 @@ uint32_t init_msc_inquiry2_cb(uint8_t lun, void *inquiry_resp, uint32_t bufsize) // Copy the original inquiry response, then override specific fields. memcpy(inquiry_resp, response, 36); - // uint8_t original_device_type = response[0] & 0x1f; uint8_t stored_device_type = g_msc_initiator_targets[lun].device_type; + // Set device type from stored value inq_resp->peripheral_device_type = stored_device_type; - inq_resp->is_removable = (stored_device_type == SCSI_DEVICE_TYPE_CD) ? 1 : 0; + + // Set removable bit based on device type: + // - CD-ROM (0x05) and MO (0x07) are always removable + // - Direct Access (0x00) uses the RMB bit from SCSI device (Zip, removable disks) + inq_resp->is_removable = is_removable_device(lun) ? 1 : 0; char vendor_id[9] = {0}; char product_id[17] = {0}; @@ -400,19 +425,25 @@ bool init_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bo g_msc_initiator_state.status_reqcount++; int target = get_target(lun); - uint8_t command[6] = {0x1B, 0x0, 0, 0, 0, 0}; + uint8_t command[6] = {0x1B, 0x00, 0, 0, 0, 0}; uint8_t response[4] = {0}; + if (start) { - command[4] |= 1; // Start - command[1] = 0; // Immediate + command[4] |= 1; // Start bit } - if (load_eject && g_msc_initiator_targets[lun].device_type == SCSI_DEVICE_TYPE_CD) + // Set LoEj bit for removable devices when ejecting + if (load_eject && !start && is_removable_device(lun)) { - logmsg("Ejecting"); + logmsg("Ejecting removable media"); command[4] |= 2; } + else if (load_eject && start && is_removable_device(lun)) + { + logmsg("Loading removable media"); + command[4] |= 3; // Both Start and LoEj bits + } command[4] |= static_cast((power_condition & 0x0F) << 4); @@ -451,18 +482,34 @@ void init_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_si dbgmsg("-- MSC Get Capacity"); g_msc_initiator_state.status_reqcount++; - if (g_msc_initiator_target_count == 0) + if (g_msc_initiator_target_count == 0 || lun >= g_msc_initiator_target_count) { *block_count = 0; *block_size = 0; return; } + // Try to read current capacity from device uint32_t sectorcount = 0; uint32_t sectorsize = 0; - scsiInitiatorReadCapacity(get_target(lun), §orcount, §orsize); - *block_count = sectorcount; - *block_size = sectorsize; + bool success = scsiInitiatorReadCapacity(get_target(lun), §orcount, §orsize); + + if (success && sectorcount > 0) + { + // Update stored capacity with current values + g_msc_initiator_targets[lun].sectorcount = sectorcount; + g_msc_initiator_targets[lun].sectorsize = sectorsize; + *block_count = sectorcount; + *block_size = sectorsize; + } + else + { + // READ CAPACITY failed (media not ready) - return stored values from scan + // For removable media, this prevents USB host from seeing 0 capacity during media loading + *block_count = g_msc_initiator_targets[lun].sectorcount; + *block_size = g_msc_initiator_targets[lun].sectorsize; + dbgmsg("Using stored capacity: ", *block_count, " x ", *block_size); + } } int32_t init_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, uint16_t bufsize) From 2b401094660edd1e7a7fe39661b1db6f5137bee1 Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Sat, 22 Nov 2025 10:49:10 -0600 Subject: [PATCH 4/4] One last try --- platformio.ini | 2 +- src/BlueSCSI_msc_initiator.cpp | 93 +++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2aafb096..3ca88e55 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ build_flags = [env:BlueSCSI_RP2MCU] platform = https://github.com/maxgerhardt/platform-raspberrypi.git#6164ed92d83c1241a1d84ad848158d7b0fb486e3 platform_packages = - framework-arduinopico@https://github.com/BlueSCSI/arduino-pico-internal.git#v4.7.0-DaynaPORT + framework-arduinopico@https://github.com/BlueSCSI/arduino-pico-internal.git#tusb-0.19.0-test extra_scripts = src/build_bootloader.py src/process-linker-script.py diff --git a/src/BlueSCSI_msc_initiator.cpp b/src/BlueSCSI_msc_initiator.cpp index c6656bf1..60248d70 100644 --- a/src/BlueSCSI_msc_initiator.cpp +++ b/src/BlueSCSI_msc_initiator.cpp @@ -290,6 +290,20 @@ static bool is_removable_device(uint8_t lun) (dtype == SCSI_DEVICE_TYPE_DIRECT_ACCESS && rmb); } +// Detect MMC commands that need special handling for CD-ROM +static bool is_mmc_command(uint8_t opcode) +{ + switch (opcode) + { + case 0x43: // READ TOC + case 0x46: // GET CONFIGURATION + case 0x4A: // GET EVENT STATUS NOTIFICATION + return true; + default: + return false; + } +} + void init_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { dbgmsg("-- MSC Inquiry"); @@ -512,6 +526,74 @@ void init_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_si } } +// Handle MMC commands for CD-ROM devices that may not fully support MMC +static int32_t handle_mmc_command(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, uint16_t bufsize) +{ + int target = get_target(lun); + uint8_t opcode = scsi_cmd[0]; + + dbgmsg("-- Handling MMC command 0x", (int)opcode); + + switch (opcode) + { + case 0x43: // READ TOC + { + // Map MMC READ TOC to SCSI-2 format 0 + // MMC uses byte 2 bits 0-3 for format, SCSI-2 only supports format 0 + uint8_t modified_cmd[10]; + memcpy(modified_cmd, scsi_cmd, 10); + modified_cmd[2] &= 0xF0; // Clear format bits, forcing format 0 + + dbgmsg("-- READ TOC: mapping to SCSI-2 format 0"); + int status = scsiInitiatorRunCommand(target, modified_cmd, 10, + NULL, 0, + (const uint8_t*)buffer, bufsize); + return status; + } + + case 0x46: // GET CONFIGURATION + { + // Return minimal stub: 8-byte header with no features + dbgmsg("-- GET CONFIGURATION: returning stub"); + if (bufsize >= 8) + { + uint8_t *resp = (uint8_t*)buffer; + memset(resp, 0, 8); + resp[0] = 0x00; resp[1] = 0x00; resp[2] = 0x00; resp[3] = 0x04; // Data length = 4 + resp[4] = 0x00; resp[5] = 0x00; // Reserved + resp[6] = 0x00; resp[7] = 0x08; // Current profile = CD-ROM + return 8; + } + return 0; + } + + case 0x4A: // GET EVENT STATUS NOTIFICATION + { + // Return "no event" stub: 4 bytes + dbgmsg("-- GET EVENT STATUS: returning no event"); + if (bufsize >= 4) + { + uint8_t *resp = (uint8_t*)buffer; + memset(resp, 0, 4); + resp[0] = 0x00; resp[1] = 0x02; // Event header length = 2 + resp[2] = 0x00; // No events + resp[3] = 0x00; // Supported event classes + return 4; + } + return 0; + } + + default: + // Unknown MMC command - pass through + dbgmsg("-- Unknown MMC command, passing through"); + static const uint8_t CmdGroupBytes[8] = {6, 10, 10, 6, 16, 12, 6, 6}; + int cmdlen = CmdGroupBytes[scsi_cmd[0] >> 5]; + return scsiInitiatorRunCommand(target, scsi_cmd, cmdlen, + NULL, 0, + (const uint8_t*)buffer, bufsize); + } +} + int32_t init_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, uint16_t bufsize) { if (g_msc_initiator_target_count == 0) @@ -523,9 +605,18 @@ int32_t init_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, LED_ON(); g_msc_initiator_state.status_reqcount++; + // Intercept MMC commands for CD-ROM devices + uint8_t device_type = g_msc_initiator_targets[lun].device_type; + if (device_type == SCSI_DEVICE_TYPE_CD && is_mmc_command(scsi_cmd[0])) + { + int status = handle_mmc_command(lun, scsi_cmd, buffer, bufsize); + LED_OFF(); + return status; + } + // NOTE: the TinyUSB API around free-form commands is not very good, // this function could need improvement. - + // Figure out command length static const uint8_t CmdGroupBytes[8] = {6, 10, 10, 6, 16, 12, 6, 6}; // From SCSI2SD int cmdlen = CmdGroupBytes[scsi_cmd[0] >> 5];