Explorar el Código

Merge pull request #501 from ZuluSCSI/msc-images

Present images as USB storage on RP2040+RP350 platforms
Alex Perez hace 9 meses
padre
commit
7994b34833

+ 5 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_msc.cpp

@@ -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);

+ 3 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_msc.h

@@ -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();
 

+ 5 - 0
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_msc.cpp

@@ -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);

+ 3 - 0
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_msc.h

@@ -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();
 

+ 115 - 17
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_msc.cpp

@@ -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"
@@ -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)
@@ -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
   }
@@ -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 */
@@ -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
@@ -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
@@ -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 --;
     }
   }
 
@@ -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
@@ -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
@@ -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)
@@ -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;

+ 3 - 0
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_msc.h

@@ -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();
 

+ 14 - 0
lib/ZuluSCSI_platform_RP2MCU/library.json

@@ -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": "support@zuluscsi.com" }],
+    "license": "GPL-3.0-or-later",
+    "homepage": "http://zuluscsi.com",
+    "frameworks": "*",
+    "platforms": "*",
+    "dependencies":
+    {
+        "CUEParser": "https://github.com/rabbitholecomputing/CUEParser"
+    }
+}

+ 1 - 1
src/ZuluSCSI_disk.cpp

@@ -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()
 {

+ 11 - 1
src/ZuluSCSI_msc.cpp

@@ -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;
 
@@ -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();
   

+ 2 - 0
src/ZuluSCSI_settings.cpp

@@ -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
@@ -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);
 

+ 2 - 1
src/ZuluSCSI_settings.h

@@ -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;