Преглед изворни кода

Set default driveinfo based on device type (#33)

Also made the firmware automatically ensure the format
of drive info strings conforms to the SCSI spec requirements
of alignment and allowed bytes. Otherwise e.g. user provided
serial number did not show up in Linux if it was not aligned
correctly.

Default drive serial number is now the SD card serial number.
Petteri Aimonen пре 3 година
родитељ
комит
f6705aeced
4 измењених фајлова са 150 додато и 22 уклоњено
  1. 10 10
      azulscsi.ini
  2. 2 0
      lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h
  3. 9 4
      src/AzulSCSI_config.h
  4. 129 8
      src/AzulSCSI_disk.cpp

+ 10 - 10
azulscsi.ini

@@ -2,8 +2,8 @@
 # Settings that apply to all devices
 Debug = 0   # Same effect as DIPSW2, enables verbose log messages
 SelectionDelay = 255   # Millisecond delay after selection, 255 = automatic, 0 = no delay
-Dir = "/"   # Optionally look for image files in subdirectory
-# Dir2 = "/images"  # Multiple directories can be specified Dir1...Dir9
+#Dir = "/"   # Optionally look for image files in subdirectory
+#Dir2 = "/images"  # Multiple directories can be specified Dir1...Dir9
 
 # Settings that can be needed for compatibility with some hosts
 Quirks = 0   # 0: Standard, 1: Apple, 2: OMTI, 4: Xebec, 8: VMS
@@ -13,14 +13,14 @@ EnableSelLatch = 0 # For Philips P2000C and other devices that release SEL signa
 MapLunsToIDs = 0 # For Philips P2000C simulate multiple LUNs
 
 # Settings that can be specified either per-device or for all devices.
-Vendor = "QUANTUM"
-Product = "FIREBALL1"
-Version = "1.0"
-Serial = "0123456789ABCDEF"
-Type = 0     # 0: Fixed, 1: Removable, 2: Optical, 3: Floppy, 4: Mag-optical, 5: Tape
-TypeModifier = 0  # Affects only INQUIRY response
-SectorsPerTrack = 63
-HeadsPerCylinder = 255
+#Vendor = "QUANTUM"
+#Product = "FIREBALL1"
+#Version = "1.0"
+#Serial = "0123456789ABCDEF"
+#Type = 0     # 0: Fixed, 1: Removable, 2: Optical, 3: Floppy, 4: Mag-optical, 5: Tape
+#TypeModifier = 0  # Affects only INQUIRY response
+#SectorsPerTrack = 63
+#HeadsPerCylinder = 255
 
 # Settings can be overriden for individual devices.
 [SCSI2]

+ 2 - 0
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h

@@ -15,10 +15,12 @@ extern const char *g_azplatform_name;
 
 #if defined(AZULSCSI_V1_0)
 #   define PLATFORM_NAME "AzulSCSI v1.0"
+#   define PLATFORM_REVISION "1.0"
 #   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_ASYNC_50
 #   include "AzulSCSI_v1_0_gpio.h"
 #elif defined(AZULSCSI_V1_1)
 #   define PLATFORM_NAME "AzulSCSI v1.1"
+#   define PLATFORM_REVISION "1.1"
 #   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_ASYNC_50
 #   include "AzulSCSI_v1_1_gpio.h"
 #endif

+ 9 - 4
src/AzulSCSI_config.h

@@ -30,10 +30,15 @@
 #define READ_PARITY_CHECK 0    // Perform read parity check (unverified)
 
 // Default SCSI drive information (can be overridden in INI file)
-#define DEFAULT_VENDOR "QUANTUM "
-#define DEFAULT_PRODUCT "FIREBALL1       "
-#define DEFAULT_VERSION "1.0 "
-#define DEFAULT_SERIAL  "0123456789ABCDEF"
+// Selected based on device type (fixed, removable, optical, floppy, mag-optical, tape)
+// Each entry has {vendor, product, version, serial}
+// If serial number is left empty, SD card serial number is used.
+#define DRIVEINFO_FIXED     {"AZULSCSI", "HARDDRIVE", PLATFORM_REVISION, ""}
+#define DRIVEINFO_REMOVABLE {"AZULSCSI", "REMOVABLE", PLATFORM_REVISION, ""}
+#define DRIVEINFO_OPTICAL   {"AZULSCSI", "CDROM",     PLATFORM_REVISION, ""}
+#define DRIVEINFO_FLOPPY    {"AZULSCSI", "FLOPPY",    PLATFORM_REVISION, ""}
+#define DRIVEINFO_MAGOPT    {"AZULSCSI", "MO_DRIVE",  PLATFORM_REVISION, ""}
+#define DRIVEINFO_TAPE      {"AZULSCSI", "TAPE",      PLATFORM_REVISION, ""}
 
 // Default delay for SCSI phases.
 // Can be adjusted in ini file

+ 129 - 8
src/AzulSCSI_disk.cpp

@@ -40,6 +40,125 @@ void scsiDiskResetImages()
     memset(g_DiskImages, 0, sizeof(g_DiskImages));
 }
 
+// Verify format conformance to SCSI spec:
+// - Empty bytes filled with 0x20 (space)
+// - Only values 0x20 to 0x7E
+// - Left alignment for vendor/product/revision, right alignment for serial.
+static void formatDriveInfoField(char *field, int fieldsize, bool align_right)
+{
+    if (align_right)
+    {
+        int dst = fieldsize - 1;
+        for (int src = fieldsize - 1; src >= 0; src--)
+        {
+            char c = field[src];
+            if (c < 0x20 || c > 0x7E) c = 0x20;
+            if (c != 0x20 || dst != fieldsize - 1)
+            {
+                field[dst--] = c;
+            }
+        }
+        while (dst >= 0)
+        {
+            field[dst--] = 0x20;
+        }
+    }
+    else
+    {
+        int dst = 0;
+        for (int src = 0; src < fieldsize; src++)
+        {
+            char c = field[src];
+            if (c < 0x20 || c > 0x7E) c = 0x20;
+            if (c != 0x20 || dst != 0)
+            {
+                field[dst++] = c;
+            }
+        }
+        while (dst < fieldsize)
+        {
+            field[dst++] = 0x20;
+        }
+    }
+}
+
+// Set default drive vendor / product info after the image file
+// is loaded and the device type is known.
+static void setDefaultDriveInfo(int target_idx)
+{
+    image_config_t &img = g_DiskImages[target_idx];
+
+    static const char *driveinfo_fixed[4] = DRIVEINFO_FIXED;
+    static const char *driveinfo_removable[4] = DRIVEINFO_REMOVABLE;
+    static const char *driveinfo_optical[4] = DRIVEINFO_OPTICAL;
+    static const char *driveinfo_floppy[4] = DRIVEINFO_FLOPPY;
+    static const char *driveinfo_magopt[4] = DRIVEINFO_MAGOPT;
+    static const char *driveinfo_tape[4] = DRIVEINFO_TAPE;
+    const char **driveinfo = NULL;
+
+    switch (img.deviceType)
+    {
+        case S2S_CFG_FIXED:         driveinfo = driveinfo_fixed; break;
+        case S2S_CFG_REMOVEABLE:    driveinfo = driveinfo_removable; break;
+        case S2S_CFG_OPTICAL:       driveinfo = driveinfo_optical; break;
+        case S2S_CFG_FLOPPY_14MB:   driveinfo = driveinfo_floppy; break;
+        case S2S_CFG_MO:            driveinfo = driveinfo_magopt; break;
+        case S2S_CFG_SEQUENTIAL:    driveinfo = driveinfo_tape; break;
+        default:                    driveinfo = driveinfo_fixed; break;
+    }
+
+    if (img.vendor[0] == '\0')
+    {
+        memset(img.vendor, 0, sizeof(img.vendor));
+        strncpy(img.vendor, driveinfo[0], sizeof(img.vendor));
+    }
+
+    if (img.prodId[0] == '\0')
+    {
+        memset(img.prodId, 0, sizeof(img.prodId));
+        strncpy(img.prodId, driveinfo[1], sizeof(img.prodId));
+    }
+
+    if (img.revision[0] == '\0')
+    {
+        memset(img.revision, 0, sizeof(img.revision));
+        strncpy(img.revision, driveinfo[2], sizeof(img.revision));
+    }
+
+    if (img.serial[0] == '\0')
+    {
+        memset(img.serial, 0, sizeof(img.serial));
+        strncpy(img.serial, driveinfo[3], sizeof(img.serial));
+    }
+
+    if (img.serial[0] == '\0')
+    {
+        // Use SD card serial number
+        cid_t sd_cid;
+        uint32_t sd_sn = 0;
+        if (SD.card()->readCID(&sd_cid))
+        {
+            sd_sn = sd_cid.psn;
+        }
+
+        memset(img.serial, 0, sizeof(img.serial));
+        const char *nibble = "0123456789ABCDEF";
+        img.serial[0] = nibble[(sd_sn >> 28) & 0xF];
+        img.serial[1] = nibble[(sd_sn >> 24) & 0xF];
+        img.serial[2] = nibble[(sd_sn >> 20) & 0xF];
+        img.serial[3] = nibble[(sd_sn >> 16) & 0xF];
+        img.serial[4] = nibble[(sd_sn >> 12) & 0xF];
+        img.serial[5] = nibble[(sd_sn >>  8) & 0xF];
+        img.serial[6] = nibble[(sd_sn >>  4) & 0xF];
+        img.serial[7] = nibble[(sd_sn >>  0) & 0xF];
+    }
+
+    formatDriveInfoField(img.vendor, sizeof(img.vendor), false);
+    formatDriveInfoField(img.prodId, sizeof(img.prodId), false);
+    formatDriveInfoField(img.revision, sizeof(img.revision), false);
+    formatDriveInfoField(img.serial, sizeof(img.serial), true);
+}
+
 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];
@@ -83,6 +202,8 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
             img.deviceType = S2S_CFG_OPTICAL;
         }
 
+        setDefaultDriveInfo(target_idx);
+
         return true;
     }
 
@@ -98,10 +219,10 @@ static void scsiDiskConfigDefaults(int target_idx)
     img.sectorsPerTrack = 63;
     img.headsPerCylinder = 255;
     img.quirks = S2S_CFG_QUIRKS_NONE;
-    memcpy(img.vendor, DEFAULT_VENDOR, 8);
-    memcpy(img.prodId, DEFAULT_PRODUCT, 16);
-    memcpy(img.revision, DEFAULT_VERSION, 4);
-    memcpy(img.serial, DEFAULT_SERIAL, 16);
+    memset(img.vendor, 0, sizeof(img.vendor));
+    memset(img.prodId, 0, sizeof(img.prodId));
+    memset(img.revision, 0, sizeof(img.revision));
+    memset(img.serial, 0, sizeof(img.serial));
 }
 
 // Load values for target configuration from given section if they exist.
@@ -118,19 +239,19 @@ static void scsiDiskLoadConfig(int target_idx, const char *section)
     char tmp[32];
     memset(tmp, 0, sizeof(tmp));
     ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.vendor, tmp, 8);
+    if (tmp[0]) memcpy(img.vendor, tmp, sizeof(img.vendor));
 
     memset(tmp, 0, sizeof(tmp));
     ini_gets(section, "Product", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.prodId, tmp, 16);
+    if (tmp[0]) memcpy(img.prodId, tmp, sizeof(img.prodId));
 
     memset(tmp, 0, sizeof(tmp));
     ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.revision, tmp, 4);
+    if (tmp[0]) memcpy(img.revision, tmp, sizeof(img.revision));
     
     memset(tmp, 0, sizeof(tmp));
     ini_gets(section, "Serial", "", tmp, sizeof(tmp), CONFIGFILE);
-    if (tmp[0]) memcpy(img.serial, tmp, 16);
+    if (tmp[0]) memcpy(img.serial, tmp, sizeof(img.serial));
 }
 
 void scsiDiskLoadConfig(int target_idx)