Explorar o código

Add raw passthrough mode (without FAT filesystem).

If no images are found, the whole SD card is presented as SCSI drive.
Raw passthrough can also be manually specified in config file.
Petteri Aimonen %!s(int64=3) %!d(string=hai) anos
pai
achega
8a47a017ae
Modificáronse 4 ficheiros con 196 adicións e 6 borrados
  1. 17 3
      src/ZuluSCSI.cpp
  2. 6 0
      src/ZuluSCSI_config.h
  3. 165 2
      src/ZuluSCSI_disk.cpp
  4. 8 1
      zuluscsi.ini

+ 17 - 3
src/ZuluSCSI.cpp

@@ -58,6 +58,7 @@ FsFile g_logfile;
 /* Status reporting by blinking led */
 /************************************/
 
+#define BLINK_STATUS_OK 1
 #define BLINK_ERROR_NO_IMAGES  3 
 #define BLINK_ERROR_NO_SD_CARD 5
 
@@ -384,7 +385,15 @@ static void reinitSCSI()
   if (foundImage)
   {
     // Ok, there is an image
-    blinkStatus(1);
+    blinkStatus(BLINK_STATUS_OK);
+  }
+  else
+  {
+#if RAW_FALLBACK_ENABLE
+    azlog("No images found, enabling RAW fallback partition");
+    scsiDiskOpenHDDImage(RAW_FALLBACK_SCSI_ID, "RAW:0:0xFFFFFFFF", RAW_FALLBACK_SCSI_ID, 0,
+                         RAW_FALLBACK_BLOCKSIZE, false);
+#endif
   }
 
   scsiPhyReset();
@@ -398,7 +407,7 @@ extern "C" int zuluscsi_main(void)
   azplatform_init();
   azplatform_late_init();
 
-  if(!SD.begin(SD_CONFIG))
+  if(!SD.begin(SD_CONFIG) && (!SD.card() || SD.sdErrorCode() != 0))
   {
     azlog("SD card init failed, sdErrorCode: ", (int)SD.sdErrorCode(),
            " sdErrorData: ", (int)SD.sdErrorData());
@@ -408,10 +417,15 @@ extern "C" int zuluscsi_main(void)
       blinkStatus(BLINK_ERROR_NO_SD_CARD);
       delay(1000);
       azplatform_reset_watchdog();
-    } while (!SD.begin(SD_CONFIG));
+    } while (!SD.begin(SD_CONFIG) && (!SD.card() || SD.sdErrorCode() != 0));
     azlog("SD card init succeeded after retry");
   }
 
+  if (SD.clusterCount() == 0)
+  {
+    azlog("SD card without filesystem!");
+  }
+
   print_sd_info();
   
   reinitSCSI();

+ 6 - 0
src/ZuluSCSI_config.h

@@ -35,6 +35,12 @@
 #define NUM_SCSILUN 1          // Maximum number of LUNs supported     (Currently has to be 1)
 #define READ_PARITY_CHECK 0    // Perform read parity check (unverified)
 
+// SCSI raw fallback configuration when no image files are detected
+// Presents the whole SD card as an SCSI drive
+#define RAW_FALLBACK_ENABLE 1
+#define RAW_FALLBACK_SCSI_ID 1
+#define RAW_FALLBACK_BLOCKSIZE 512
+
 // Default SCSI drive information (can be overridden in INI file)
 // Selected based on device type (fixed, removable, optical, floppy, mag-optical, tape)
 // Each entry has {vendor, product, version, serial}

+ 165 - 2
src/ZuluSCSI_disk.cpp

@@ -11,6 +11,8 @@
 #include "ZuluSCSI_config.h"
 #include <minIni.h>
 #include <string.h>
+#include <strings.h>
+#include <assert.h>
 #include <SdFat.h>
 
 extern "C" {
@@ -41,6 +43,8 @@ extern "C" {
 #define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 512
 #endif
 
+// SD card sector size is always 512 bytes
+#define SD_SECTOR_SIZE 512
 
 /***********************/
 /* Backing image files */
@@ -49,9 +53,168 @@ extern "C" {
 extern SdFs SD;
 SdDevice sdDev = {2, 256 * 1024 * 1024 * 2}; /* For SCSI2SD */
 
+// This class wraps SdFat library FsFile to allow access
+// through either FAT filesystem or as a raw sector range.
+//
+// Raw access is activated by using filename like "RAW:0:12345"
+// where the numbers are the first and last sector.
+class ImageBackingStore
+{
+public:
+    ImageBackingStore()
+    {
+        m_israw = false;
+        m_blockdev = nullptr;
+        m_bgnsector = m_endsector = m_cursector = 0;
+    }
+
+    ImageBackingStore(const char *filename): ImageBackingStore()
+    {
+        if (strncasecmp(filename, "RAW:", 4) == 0)
+        {
+            char *endptr, *endptr2;
+            m_bgnsector = strtoul(filename + 4, &endptr, 0);
+            m_endsector = strtoul(endptr + 1, &endptr2, 0);
+
+            if (*endptr != ':' || *endptr2 != '\0')
+            {
+                azlog("Invalid format for raw filename: ", filename);
+                return;
+            }
+
+            m_israw = true;
+            m_blockdev = SD.card();
+
+            if (m_endsector >= SD.card()->sectorCount())
+            {
+                m_endsector = SD.card()->sectorCount() - 1;
+            }
+        }
+        else
+        {
+            m_fsfile = SD.open(filename, O_RDWR);
+        }
+    }
+
+    bool isOpen() { return m_israw ? !!m_blockdev : m_fsfile.isOpen(); }
+    bool close()
+    {
+        if (m_israw)
+        {
+            m_blockdev = nullptr;
+            return true;
+        }
+        else
+        {
+            return m_fsfile.close();
+        }
+    }
+
+    uint64_t size()
+    {
+        if (m_israw && m_blockdev)
+        {
+            return (uint64_t)(m_endsector - m_bgnsector + 1) * SD_SECTOR_SIZE;
+        }
+        else
+        {
+            return m_fsfile.size();
+        }
+    }
+
+    bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector)
+    {
+        if (m_israw && m_blockdev)
+        {
+            *bgnSector = m_bgnsector;
+            *endSector = m_endsector;
+            return true;
+        }
+        else
+        {
+            return m_fsfile.contiguousRange(bgnSector, endSector);
+        }
+    }
+
+    bool seek(uint64_t pos)
+    {
+        if (m_israw && m_blockdev)
+        {
+            uint32_t sectornum = pos / SD_SECTOR_SIZE;
+            assert((uint64_t)sectornum * SD_SECTOR_SIZE == pos);
+            m_cursector = m_bgnsector + sectornum;
+            return (m_cursector <= m_endsector);
+        }
+        else
+        {
+            return m_fsfile.seek(pos);
+        }
+    }
+
+    int read(void* buf, size_t count)
+    {
+        if (m_israw && m_blockdev)
+        {
+            uint32_t sectorcount = count / SD_SECTOR_SIZE;
+            assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
+            if (m_blockdev->readSectors(m_cursector, (uint8_t*)buf, sectorcount))
+            {
+                m_cursector += sectorcount;
+                return count;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        else
+        {
+            return m_fsfile.read(buf, count);
+        }
+    }
+
+    size_t write(const void* buf, size_t count)
+    {
+        if (m_israw && m_blockdev)
+        {
+            uint32_t sectorcount = count / SD_SECTOR_SIZE;
+            assert((uint64_t)sectorcount * SD_SECTOR_SIZE == count);
+            if (m_blockdev->writeSectors(m_cursector, (const uint8_t*)buf, sectorcount))
+            {
+                m_cursector += sectorcount;
+                return count;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+        else
+        {
+            return m_fsfile.write(buf, count);
+        }
+    }
+
+    void flush()
+    {
+        if (!m_israw)
+        {
+            m_fsfile.flush();
+        }
+    }
+
+private:
+    bool m_israw;
+    FsFile m_fsfile;
+    SdCard *m_blockdev;
+    uint32_t m_bgnsector;
+    uint32_t m_endsector;
+    uint32_t m_cursector;
+};
+
 struct image_config_t: public S2S_TargetCfg
 {
-    FsFile file;
+    ImageBackingStore file;
 
     // For CD-ROM drive ejection
     bool ejected;
@@ -204,7 +367,7 @@ static void setDefaultDriveInfo(int target_idx)
 bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int scsi_lun, int blocksize, bool is_cd)
 {
     image_config_t &img = g_DiskImages[target_idx];
-    img.file = SD.open(filename, O_RDWR);
+    img.file = ImageBackingStore(filename);
 
     if (img.file.isOpen())
     {

+ 8 - 1
zuluscsi.ini

@@ -35,4 +35,11 @@ Product = "CD-ROM Drive"
 Type = 2
 # If IMG0..IMG9 are specified, they are cycled after each CD eject command.
 #IMG0 = FirstCD.iso
-#IMG1 = SecondCD.iso
+#IMG1 = SecondCD.iso
+
+
+# Raw sector range from SD card can be passed through
+# Format is RAW:first_sector:last_sector where sector numbers can be decimal or hex.
+# If end sector is beyond end of SD card, it will be adjusted automatically.
+# [SCSI4]
+# IMG0 = RAW:0x00000000:0xFFFFFFFF # Whole SD card