|
@@ -22,10 +22,11 @@
|
|
|
/* platform specific MSC routines */
|
|
/* platform specific MSC routines */
|
|
|
#ifdef PLATFORM_MASS_STORAGE
|
|
#ifdef PLATFORM_MASS_STORAGE
|
|
|
|
|
|
|
|
-#include <SdFat.h>
|
|
|
|
|
#include <device/usbd.h>
|
|
#include <device/usbd.h>
|
|
|
#include <hardware/gpio.h>
|
|
#include <hardware/gpio.h>
|
|
|
|
|
+
|
|
|
#include "ZuluSCSI_platform.h"
|
|
#include "ZuluSCSI_platform.h"
|
|
|
|
|
+#include "ZuluSCSI_disk.h"
|
|
|
#include "ZuluSCSI_log.h"
|
|
#include "ZuluSCSI_log.h"
|
|
|
#include "ZuluSCSI_msc.h"
|
|
#include "ZuluSCSI_msc.h"
|
|
|
#include "ZuluSCSI_msc_initiator.h"
|
|
#include "ZuluSCSI_msc_initiator.h"
|
|
@@ -45,11 +46,22 @@ extern mutex_t __usb_mutex;
|
|
|
|
|
|
|
|
// external global SD variable
|
|
// external global SD variable
|
|
|
extern SdFs SD;
|
|
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_lock; // To block re-entrant calls
|
|
|
static bool g_msc_usb_mutex_held;
|
|
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)
|
|
void platform_msc_lock_set(bool block)
|
|
|
{
|
|
{
|
|
|
if (block)
|
|
if (block)
|
|
@@ -59,7 +71,7 @@ void platform_msc_lock_set(bool block)
|
|
|
logmsg("Re-entrant MSC lock!");
|
|
logmsg("Re-entrant MSC lock!");
|
|
|
assert(false);
|
|
assert(false);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
g_msc_usb_mutex_held = mutex_try_enter(&__usb_mutex, NULL); // Blocks USB IRQ if not already blocked
|
|
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
|
|
g_msc_lock = true; // Blocks platform USB polling
|
|
|
}
|
|
}
|
|
@@ -131,22 +143,77 @@ bool platform_sense_msc() {
|
|
|
return tud_connected();
|
|
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() {
|
|
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 */
|
|
/* perform MSC class preinit tasks */
|
|
|
void platform_enter_msc() {
|
|
void platform_enter_msc() {
|
|
|
dbgmsg("USB MSC buffer size: ", CFG_TUD_MSC_EP_BUFSIZE);
|
|
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
|
|
// 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 */
|
|
/* perform any cleanup tasks for the MSC-specific functionality */
|
|
|
void platform_exit_msc() {
|
|
void platform_exit_msc() {
|
|
|
- unitReady = false;
|
|
|
|
|
|
|
+ g_MSC.unitReady = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* TinyUSB mass storage callbacks follow */
|
|
/* TinyUSB mass storage callbacks follow */
|
|
@@ -178,7 +245,7 @@ extern "C" uint8_t tud_msc_get_maxlun_cb(void)
|
|
|
MSCScopedLock lock;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_get_maxlun_cb();
|
|
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
|
|
// return writable status
|
|
@@ -188,9 +255,10 @@ extern "C" bool tud_msc_is_writable_cb (uint8_t lun)
|
|
|
{
|
|
{
|
|
|
MSCScopedLock lock;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_is_writable_cb(lun);
|
|
if (g_msc_initiator) return init_msc_is_writable_cb(lun);
|
|
|
-
|
|
|
|
|
|
|
+ if (g_MSC.SDMode) return g_MSC.unitReady;
|
|
|
|
|
+
|
|
|
(void) lun;
|
|
(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
|
|
// 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
|
|
// load disk storage
|
|
|
// do nothing as we started "loaded"
|
|
// do nothing as we started "loaded"
|
|
|
} else {
|
|
} 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;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_test_unit_ready_cb(lun);
|
|
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
|
|
// 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;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_capacity_cb(lun, block_count, block_size);
|
|
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
|
|
// 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;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_read10_cb(lun, lba, offset, buffer, bufsize);
|
|
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
|
|
// only blink fast on reads; writes will override this
|
|
|
if (MSC_LEDMode == LED_SOLIDON)
|
|
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;
|
|
MSCScopedLock lock;
|
|
|
if (g_msc_initiator) return init_msc_read10_cb(lun, lba, offset, buffer, bufsize);
|
|
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
|
|
// always slow blink
|
|
|
MSC_LEDMode = LED_BLINK_SLOW;
|
|
MSC_LEDMode = LED_BLINK_SLOW;
|