Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Present images as USB storage on RP2 platform #501

Merged
merged 4 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_msc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ bool platform_sense_msc() {
return false;
}

void platform_set_msc_image_mode(bool image_mode) {
if (image_mode) logmsg("Warning: USB Image mounting not supported on this platform!");
//g_MSC.SDMode = !image_mode;
}

/* perform MSC-specific init tasks */
void platform_enter_msc() {
dbgmsg("USB MSC buffer size: ", (uint32_t) MSC_MEDIA_PACKET_SIZE);
Expand Down
3 changes: 3 additions & 0 deletions lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_msc.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ bool platform_sense_msc();
/* perform MSC-specific init tasks */
void platform_enter_msc();

/* set to present images as storage rather than SD */
void platform_set_msc_image_mode(bool image_mode);

/* return true if we should remain in card reader mode. called in a loop. */
bool platform_run_msc();

Expand Down
5 changes: 5 additions & 0 deletions lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_msc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ bool platform_sense_msc() {
return false;
}

void platform_set_msc_image_mode(bool image_mode) {
if (image_mode) logmsg("Warning: USB Image mounting not supported on this platform!");
//g_MSC.SDMode = !image_mode;
}

/* perform MSC-specific init tasks */
void platform_enter_msc() {
dbgmsg("USB MSC buffer size: ", (uint32_t) MSC_MEDIA_PACKET_SIZE);
Expand Down
3 changes: 3 additions & 0 deletions lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_msc.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ bool platform_sense_msc();
/* perform MSC-specific init tasks */
void platform_enter_msc();

/* set to present images as storage rather than SD */
void platform_set_msc_image_mode(bool image_mode);

/* return true if we should remain in card reader mode. called in a loop. */
bool platform_run_msc();

Expand Down
132 changes: 115 additions & 17 deletions lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_msc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
/* platform specific MSC routines */
#ifdef PLATFORM_MASS_STORAGE

#include <SdFat.h>
#include <device/usbd.h>
#include <hardware/gpio.h>

#include "ZuluSCSI_platform.h"
#include "ZuluSCSI_disk.h"
#include "ZuluSCSI_log.h"
#include "ZuluSCSI_msc.h"
#include "ZuluSCSI_msc_initiator.h"
Expand All @@ -45,11 +46,22 @@ extern mutex_t __usb_mutex;

// external global SD variable
extern SdFs SD;
static bool unitReady = false;

// external images configuration
extern image_config_t g_DiskImages[S2S_MAX_TARGETS];

static bool g_msc_lock; // To block re-entrant calls
static bool g_msc_usb_mutex_held;

/* globals */
static struct {
uint8_t lun_unitReady[S2S_MAX_TARGETS];
image_config_t * lun_config[S2S_MAX_TARGETS];
uint8_t lun_count = 0;
uint8_t unitReady = 0;
uint8_t SDMode = 1;
} g_MSC;

void platform_msc_lock_set(bool block)
{
if (block)
Expand All @@ -59,7 +71,7 @@ void platform_msc_lock_set(bool block)
logmsg("Re-entrant MSC lock!");
assert(false);
}

g_msc_usb_mutex_held = mutex_try_enter(&__usb_mutex, NULL); // Blocks USB IRQ if not already blocked
g_msc_lock = true; // Blocks platform USB polling
}
Expand Down Expand Up @@ -131,22 +143,77 @@ bool platform_sense_msc() {
return tud_connected();
}

/* return true if we should remain in card reader mode and perform periodic tasks */
/* perform periodic tasks, return true if we should remain in card reader mode */
bool platform_run_msc() {
return unitReady;
return g_MSC.unitReady;
}

/* load the setting if we present images or not */
void platform_set_msc_image_mode(bool image_mode) {
g_MSC.SDMode = !image_mode;
}

/* return true if the image type makes sense as a mass-storage device */
bool msc_image_eligble(uint8_t t) {
switch (t) {
case S2S_CFG_FIXED:
case S2S_CFG_REMOVABLE:
case S2S_CFG_MO: /* not actually sure about this and zip */
case S2S_CFG_ZIP100:
return true;

case S2S_CFG_OPTICAL: /* will not contain a MBR */
case S2S_CFG_FLOPPY_14MB: /* will not contain a MBR */
case S2S_CFG_SEQUENTIAL: /* tape drive */
case S2S_CFG_NETWORK: /* always empty */
case S2S_CFG_NOT_SET:
default:
return false;
}
}

/* perform MSC class preinit tasks */
void platform_enter_msc() {
dbgmsg("USB MSC buffer size: ", CFG_TUD_MSC_EP_BUFSIZE);
g_MSC.lun_count = 0;

if (!g_MSC.SDMode) {
logmsg("Presenting configured images as USB storage devices");
for (int i = 0; i < S2S_MAX_TARGETS; i++) {
if (msc_image_eligble(g_DiskImages[i].deviceType) && g_DiskImages[i].file.isOpen()) {
logmsg("USB LUN ", (int)g_MSC.lun_count," => ",g_DiskImages[i].current_image);

// anything but linux probably won't deal gracefully with nonstandard or odd sector sizes, present a warning
if (g_DiskImages[i].bytesPerSector != 512 && g_DiskImages[i].bytesPerSector != 4096) {
logmsg("Warning: USB LUN ",(int)g_MSC.lun_count," uses a sector size of ",g_DiskImages[i].bytesPerSector,". Not all OS can deal with this!");
}

g_MSC.lun_config[g_MSC.lun_count] = &g_DiskImages[i];
g_MSC.lun_unitReady[g_MSC.lun_count] = 1;
g_MSC.lun_count ++;
}
}

if (g_MSC.lun_count == 0) {
logmsg("No images to present, falling back to SD card!");
g_MSC.SDMode = 1;
} else
logmsg("Total USB LUN ", (int)g_MSC.lun_count);
}

if (g_MSC.SDMode) {
logmsg("Presenting SD card as USB storage device");
g_MSC.lun_count = 1;
g_MSC.lun_unitReady[0] = 1;
}

// MSC is ready for read/write
// we don't need any prep, but the var is requried as the MSC callbacks are always active
unitReady = true;
g_MSC.unitReady = g_MSC.lun_count;
}

/* perform any cleanup tasks for the MSC-specific functionality */
void platform_exit_msc() {
unitReady = false;
g_MSC.unitReady = 0;
}

/* TinyUSB mass storage callbacks follow */
Expand Down Expand Up @@ -178,7 +245,7 @@ extern "C" uint8_t tud_msc_get_maxlun_cb(void)
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_get_maxlun_cb();

return 1; // number of LUNs supported
return g_MSC.lun_count; // number of LUNs supported
}

// return writable status
Expand All @@ -188,9 +255,10 @@ extern "C" bool tud_msc_is_writable_cb (uint8_t lun)
{
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_is_writable_cb(lun);

if (g_MSC.SDMode) return g_MSC.unitReady;

(void) lun;
return unitReady;
return g_MSC.unitReady && g_MSC.lun_unitReady[lun] && g_MSC.lun_config[lun]->file.isWritable();
}

// see https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf pg 221
Expand All @@ -204,7 +272,10 @@ extern "C" bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool
// load disk storage
// do nothing as we started "loaded"
} else {
unitReady = false;
g_MSC.lun_unitReady[lun] = false;

if (g_MSC.unitReady) // no more active LUNs -> global not ready flag
g_MSC.unitReady --;
}
}

Expand All @@ -217,7 +288,7 @@ extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun)
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_test_unit_ready_cb(lun);

return unitReady;
return g_MSC.unitReady && g_MSC.lun_unitReady[lun];
}

// return size in blocks and block size
Expand All @@ -227,8 +298,13 @@ extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_capacity_cb(lun, block_count, block_size);

*block_count = unitReady ? (SD.card()->sectorCount()) : 0;
*block_size = SD_SECTOR_SIZE;
if (g_MSC.SDMode) {
*block_count = g_MSC.unitReady ? (SD.card()->sectorCount()) : 0;
*block_size = SD_SECTOR_SIZE;
} else { // present the bytesPerSector of file, though it remains to be seen if host will like this
*block_count = (g_MSC.unitReady && g_MSC.lun_unitReady[lun]) ? (g_MSC.lun_config[lun]->file.size() / g_MSC.lun_config[lun]->bytesPerSector) : 0;
*block_size = g_MSC.lun_config[lun]->bytesPerSector;
}
}

// Callback invoked when received an SCSI command not in built-in list (below) which have their own callbacks
Expand Down Expand Up @@ -278,7 +354,18 @@ extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_read10_cb(lun, lba, offset, buffer, bufsize);

bool rc = SD.card()->readSectors(lba, (uint8_t*) buffer, bufsize/SD_SECTOR_SIZE);
bool rc = 0;

if (g_MSC.SDMode) {
rc = SD.card()->readSectors(lba, (uint8_t*) buffer, bufsize/SD_SECTOR_SIZE);
} else {
if (g_MSC.lun_unitReady[lun]) {
g_MSC.lun_config[lun]->file.seek(lba * g_MSC.lun_config[lun]->bytesPerSector);
rc = g_MSC.lun_config[lun]->file.read(buffer, bufsize);
} else {
logmsg("Attempted read to non-ready LUN ",lun);
}
}

// only blink fast on reads; writes will override this
if (MSC_LEDMode == LED_SOLIDON)
Expand All @@ -295,7 +382,18 @@ extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset
MSCScopedLock lock;
if (g_msc_initiator) return init_msc_read10_cb(lun, lba, offset, buffer, bufsize);

bool rc = SD.card()->writeSectors(lba, buffer, bufsize/SD_SECTOR_SIZE);
bool rc = 0;

if (g_MSC.SDMode) {
rc = SD.card()->writeSectors(lba, buffer, bufsize/SD_SECTOR_SIZE);
} else {
if (g_MSC.lun_unitReady[lun]) {
g_MSC.lun_config[lun]->file.seek(lba * g_MSC.lun_config[lun]->bytesPerSector);
rc = g_MSC.lun_config[lun]->file.write(buffer, bufsize);
} else {
logmsg("Attempted write to non-ready LUN ",lun);
}
}

// always slow blink
MSC_LEDMode = LED_BLINK_SLOW;
Expand Down
3 changes: 3 additions & 0 deletions lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_msc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ bool platform_sense_msc();
/* perform MSC-specific init tasks */
void platform_enter_msc();

/* set to present images as storage rather than SD */
void platform_set_msc_image_mode(bool image_mode);

/* return true if we should remain in card reader mode. called in a loop. */
bool platform_run_msc();

Expand Down
14 changes: 14 additions & 0 deletions lib/ZuluSCSI_platform_RP2MCU/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "ZuluSCSI_platform_RP2MCU",
"version": "1.0",
"repository": { "type": "git", "url": "git://github.com/ZulusCSI/ZuluSCSI-firmware" },
"authors": [{ "name": "Rabbit Hole Computing", "email": "[email protected]" }],
"license": "GPL-3.0-or-later",
"homepage": "http://zuluscsi.com",
"frameworks": "*",
"platforms": "*",
"dependencies":
{
"CUEParser": "https://github.com/rabbitholecomputing/CUEParser"
}
}
2 changes: 1 addition & 1 deletion src/ZuluSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ bool scsiDiskActivateRomDrive()
extern SdFs SD;
SdDevice sdDev = {2, 256 * 1024 * 1024 * 2}; /* For SCSI2SD */

static image_config_t g_DiskImages[S2S_MAX_TARGETS];
image_config_t g_DiskImages[S2S_MAX_TARGETS];

void scsiDiskResetImages()
{
Expand Down
12 changes: 11 additions & 1 deletion src/ZuluSCSI_msc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@
#include "ZuluSCSI_platform.h"
#include "ZuluSCSI_log.h"
#include "ZuluSCSI_msc.h"
#include "ZuluSCSI_settings.h"

// external global SD variable
extern SdFs SD;

// SCSI system and device settings
extern ZuluSCSISettings g_scsi_settings;

// public globals
volatile MSC_LEDState MSC_LEDMode;

Expand All @@ -39,7 +43,13 @@ void zuluscsi_msc_loop() {
// turn LED on to indicate entering card reader mode.
LED_ON();

logmsg("Entering USB Mass storage mode. Eject the USB disk to exit.");
logmsg("Entering USB Mass storage mode. Eject the USB disk(s) to exit.");

// force blink status to inactive (may inhibit our blinking otherwise)
platform_set_blink_status(0);

// pull in the setting for presenting images as USB devices
platform_set_msc_image_mode(g_scsi_settings.getSystem()->usbMassStoragePresentImages);

platform_enter_msc();

Expand Down
2 changes: 2 additions & 0 deletions src/ZuluSCSI_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
cfgSys.enableCDAudio = false;
cfgSys.enableUSBMassStorage = false;
cfgSys.usbMassStorageWaitPeriod = 1000;
cfgSys.usbMassStoragePresentImages = false;
cfgSys.invertStatusLed = false;

// setting set for all or specific devices
Expand Down Expand Up @@ -396,6 +397,7 @@ scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)

cfgSys.enableUSBMassStorage = ini_getbool("SCSI", "EnableUSBMassStorage", cfgSys.enableUSBMassStorage, CONFIGFILE);
cfgSys.usbMassStorageWaitPeriod = ini_getl("SCSI", "USBMassStorageWaitPeriod", cfgSys.usbMassStorageWaitPeriod, CONFIGFILE);
cfgSys.usbMassStoragePresentImages = ini_getbool("SCSI", "USBMassStoragePresentImages", cfgSys.usbMassStoragePresentImages, CONFIGFILE);

cfgSys.invertStatusLed = ini_getbool("SCSI", "InvertStatusLED", cfgSys.invertStatusLed, CONFIGFILE);

Expand Down
3 changes: 2 additions & 1 deletion src/ZuluSCSI_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ typedef struct __attribute__((__packed__)) scsi_system_settings_t
bool enableCDAudio;
bool enableUSBMassStorage;
uint16_t usbMassStorageWaitPeriod;

bool usbMassStoragePresentImages;

bool invertStatusLed;

} scsi_system_settings_t;
Expand Down
Loading