Quellcode durchsuchen

Centralizing SCSI settings

Putting most of setting that can be configured in the `zuluscsi.ini`
in ZuluSCSI_settings.cpp.

Adding the ability to use device specific presets.
Morio vor 2 Jahren
Ursprung
Commit
7f4104cfb5

+ 3 - 3
lib/ZuluSCSI_platform_GD32F205/scsiPhy.cpp

@@ -33,6 +33,7 @@
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 
 #include <scsi2sd.h>
@@ -154,10 +155,8 @@ static void selectPhyMode()
 {
     int oldmode = g_scsi_phy_mode;
 
-    int default_mode = PHY_MODE_BEST_AVAILABLE;
-
     // Read overriding setting from configuration file
-    int wanted_mode = ini_getl("SCSI", "PhyMode", default_mode, CONFIGFILE);
+    int wanted_mode = getSystemSetting()->phyMode;
 
     // Default: software GPIO bitbang, available on all revisions
     g_scsi_phy_mode = PHY_MODE_PIO;
@@ -194,6 +193,7 @@ static void selectPhyMode()
     {
         logmsg("SCSI PHY operating mode: ", g_scsi_phy_mode_names[g_scsi_phy_mode]);
     }
+    getSystemSetting()->phyMode = g_scsi_phy_mode;
 }
 
 extern "C" void scsiPhyReset(void)

+ 3 - 1
lib/ZuluSCSI_platform_GD32F450/scsiPhy.cpp

@@ -33,6 +33,7 @@
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 
 #include <scsi2sd.h>
@@ -152,7 +153,7 @@ static void selectPhyMode()
     int default_mode = PHY_MODE_BEST_AVAILABLE;
 
     // Read overriding setting from configuration file
-    int wanted_mode = ini_getl("SCSI", "PhyMode", default_mode, CONFIGFILE);
+    int wanted_mode = getSystemSetting()->deviceType;
 
     // Default: software GPIO bitbang, available on all revisions
     g_scsi_phy_mode = PHY_MODE_PIO;
@@ -189,6 +190,7 @@ static void selectPhyMode()
     {
         logmsg("SCSI PHY operating mode: ", g_scsi_phy_mode_names[g_scsi_phy_mode]);
     }
+    getSystemSetting()->deviceType = g_scsi_phy_mode;
 }
 
 extern "C" void scsiPhyReset(void)

+ 1 - 1
platformio.ini

@@ -166,7 +166,7 @@ build_flags =
     -DZULUSCSI_DAYNAPORT
 ; These take a large portion of the SRAM and can be adjusted
     -DLOGBUFSIZE=8192
-    -DPREFETCH_BUFFER_SIZE=8192
+    -DPREFETCH_BUFFER_SIZE=6144
     -DSCSI2SD_BUFFER_SIZE=57344
     ; This controls the depth of 2 x NETWORK_PACKET_MAX_SIZE (1520 bytes)
     ; For example a queue size of 10 would be 10 x 2 x 1520 = 30400 bytes

+ 2 - 1
src/ImageBackingStore.cpp

@@ -25,6 +25,7 @@
 #include <ZuluSCSI_platform.h>
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_settings.h"
 #include <minIni.h>
 #include <strings.h>
 #include <string.h>
@@ -113,7 +114,7 @@ ImageBackingStore::ImageBackingStore(const char *filename, uint32_t scsi_block_s
                 // If the drive was formatted using those versions, you may have problems accessing it with newer firmware.
                 // The old behavior can be restored with setting  [SCSI] UseFATAllocSize = 1 in config file.
 
-                if (ini_getbool("SCSI", "UseFATAllocSize", 0, CONFIGFILE))
+                if (getSystemSetting()->useFATAllocSize)
                 {
                     sectorcount = allocsize;
                 }

+ 2 - 1
src/QuirksCheck.cpp

@@ -24,6 +24,7 @@
 #include <minIni.h>
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_log.h"
+#include "ZuluSCSI_settings.h"
 #include "QuirksCheck.h"
 #include <assert.h>
 #include <stdint.h>
@@ -84,7 +85,7 @@ static bool isValidMacintoshImage(image_config_t *img)
 static void macQuirksSanityCheck(image_config_t *img)
 {
 
-    if(ini_getbool("SCSI", "DisableMacSanityCheck", false, CONFIGFILE))
+    if(getDeviceSettings(img->scsiId & 7)->disableMacSanityCheck)
     {
         dbgmsg("---- Skipping Mac sanity check due to DisableMacSanityCheck");
         return;

+ 13 - 7
src/ZuluSCSI.cpp

@@ -53,7 +53,7 @@
 #include "ZuluSCSI_platform.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_log_trace.h"
-#include "ZuluSCSI_presets.h"
+#include "ZuluSCSI_settings.h"
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_initiator.h"
 #include "ROMDrive.h"
@@ -511,6 +511,12 @@ bool findHDDImages()
         else if(id < NUM_SCSIID && lun < NUM_SCSILUN) {
           logmsg("-- Opening ", fullname, " for id:", id, " lun:", lun);
 
+          const char* devPresetName = getDevicePresetName(id);
+          if (devPresetName[0])
+          {
+              logmsg("---- Using device preset: ", devPresetName);
+          }
+
           imageReady = scsiDiskOpenHDDImage(id, fullname, id, lun, blk, type);
           if(imageReady)
           {
@@ -735,17 +741,17 @@ extern "C" void zuluscsi_setup(void)
     
     char presetName[32];
     ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(presetName);
-    int boot_delay_ms = ini_getl("SCSI", "InitPreDelay", defaults.initPreDelay, CONFIGFILE);
-
+    scsi_system_settings_t *cfg = initSystemSetting(presetName);
+    int boot_delay_ms = cfg->initPreDelay;
     if (boot_delay_ms > 0)
     {
-    logmsg("Pre SCSI init boot delay in millis: ", boot_delay_ms);
+      logmsg("Pre SCSI init boot delay in millis: ", boot_delay_ms);
       delay(boot_delay_ms);
     }
     reinitSCSI();
-
-    boot_delay_ms = ini_getl("SCSI", "InitPostDelay", 0, CONFIGFILE);
+    
+    
+    boot_delay_ms = cfg->initPostDelay;
     if (boot_delay_ms > 0)
     {
       logmsg("Post SCSI init boot delay in millis: ", boot_delay_ms);

+ 73 - 253
src/ZuluSCSI_disk.cpp

@@ -30,7 +30,7 @@
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
-#include "ZuluSCSI_presets.h"
+#include "ZuluSCSI_settings.h"
 #ifdef ENABLE_AUDIO_OUTPUT
 #include "ZuluSCSI_audio.h"
 #endif
@@ -193,46 +193,6 @@ void scsiDiskCloseSDCardImages()
     }
 }
 
-// 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)
-    {
-        // Right align and trim spaces on either side
-        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
-    {
-        // Left align, preserve spaces in case config tries to manually right-align
-        int dst = 0;
-        for (int src = 0; src < fieldsize; src++)
-        {
-            char c = field[src];
-            if (c < 0x20 || c > 0x7E) c = 0x20;
-            field[dst++] = c;
-        }
-        while (dst < fieldsize)
-        {
-            field[dst++] = 0x20;
-        }
-    }
-}
 
 // remove path and extension from filename
 void extractFileName(const char* path, char* output) {
@@ -265,115 +225,6 @@ void setNameFromImage(image_config_t &img, const char *filename) {
     strncpy(img.prodId, image_name+8, 8);
 }
 
-// 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_network[4]   = DRIVEINFO_NETWORK;
-    static const char *driveinfo_tape[4]      = DRIVEINFO_TAPE;
-
-    static const char *apl_driveinfo_fixed[4]     = APPLE_DRIVEINFO_FIXED;
-    static const char *apl_driveinfo_removable[4] = APPLE_DRIVEINFO_REMOVABLE;
-    static const char *apl_driveinfo_optical[4]   = APPLE_DRIVEINFO_OPTICAL;
-    static const char *apl_driveinfo_floppy[4]    = APPLE_DRIVEINFO_FLOPPY;
-    static const char *apl_driveinfo_magopt[4]    = APPLE_DRIVEINFO_MAGOPT;
-    static const char *apl_driveinfo_network[4]   = APPLE_DRIVEINFO_NETWORK;
-    static const char *apl_driveinfo_tape[4]      = APPLE_DRIVEINFO_TAPE;
-
-    const char **driveinfo = NULL;
-
-    if (img.quirks == S2S_CFG_QUIRKS_APPLE)
-    {
-        // Use default drive IDs that are recognized by Apple machines
-        switch (img.deviceType)
-        {
-            case S2S_CFG_FIXED:         driveinfo = apl_driveinfo_fixed; break;
-            case S2S_CFG_REMOVABLE:     driveinfo = apl_driveinfo_removable; break;
-            case S2S_CFG_OPTICAL:       driveinfo = apl_driveinfo_optical; break;
-            case S2S_CFG_FLOPPY_14MB:   driveinfo = apl_driveinfo_floppy; break;
-            case S2S_CFG_MO:            driveinfo = apl_driveinfo_magopt; break;
-            case S2S_CFG_NETWORK:       driveinfo = apl_driveinfo_network; break;
-            case S2S_CFG_SEQUENTIAL:    driveinfo = apl_driveinfo_tape; break;
-            default:                    driveinfo = apl_driveinfo_fixed; break;
-        }
-    }
-    else
-    {
-        // Generic IDs
-        switch (img.deviceType)
-        {
-            case S2S_CFG_FIXED:         driveinfo = driveinfo_fixed; break;
-            case S2S_CFG_REMOVABLE:     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_NETWORK:       driveinfo = driveinfo_network; 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];
-    }
-
-    int rightAlign = img.rightAlignStrings;
-
-    formatDriveInfoField(img.vendor, sizeof(img.vendor), rightAlign);
-    formatDriveInfoField(img.prodId, sizeof(img.prodId), rightAlign);
-    formatDriveInfoField(img.revision, sizeof(img.revision), rightAlign);
-    formatDriveInfoField(img.serial, sizeof(img.serial), true);
-}
-
 bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int scsi_lun, int blocksize, S2S_CFG_TYPE type)
 {
     image_config_t &img = g_DiskImages[target_idx];
@@ -445,9 +296,6 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
             img.deviceType = S2S_CFG_SEQUENTIAL;
         }
 
-#ifdef PLATFORM_CONFIG_HOOK
-        PLATFORM_CONFIG_HOOK(&img);
-#endif
         quirksCheck(&img);
 
         if (img.name_from_image)
@@ -456,8 +304,6 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
             logmsg("---- Vendor / product id set from image file name");
         }
 
-        setDefaultDriveInfo(target_idx);
-
         if (type == S2S_CFG_NETWORK)
         {
             // prefetch not used, skip emitting log message
@@ -563,30 +409,6 @@ bool scsiDiskFilenameValid(const char* name)
     return true;
 }
 
-// Set target configuration to default values
-static void scsiDiskConfigDefaults(int target_idx)
-{
-    // Get default values from system preset, if any
-    char presetName[32];
-    ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(presetName);
-
-    image_config_t &img = g_DiskImages[target_idx];
-    img.scsiId = target_idx;
-    img.deviceType = S2S_CFG_FIXED;
-    img.deviceTypeModifier = defaults.deviceTypeModifier;
-    img.sectorsPerTrack = defaults.sectorsPerTrack;
-    img.headsPerCylinder = defaults.headsPerCylinder;
-    img.quirks = defaults.quirks;
-    img.prefetchbytes = defaults.prefetchBytes;
-    img.reinsert_on_inquiry = true;
-    img.reinsert_after_eject = true;
-    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));
-}
-
 static void scsiDiskCheckDir(char * dir_name, int target_idx, image_config_t* img, S2S_CFG_TYPE type, const char* type_name)
 {
     if (SD.exists(dir_name))
@@ -606,77 +428,76 @@ static void scsiDiskCheckDir(char * dir_name, int target_idx, image_config_t* im
 
 // Load values for target configuration from given section if they exist.
 // Otherwise keep current settings.
-static void scsiDiskLoadConfig(int target_idx, const char *section)
+static void scsiDiskSetConfig(int target_idx)
 {
+  
     image_config_t &img = g_DiskImages[target_idx];
-    img.deviceType = ini_getl(section, "Type", img.deviceType, CONFIGFILE);
-    img.deviceTypeModifier = ini_getl(section, "TypeModifier", img.deviceTypeModifier, CONFIGFILE);
-    img.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", img.sectorsPerTrack, CONFIGFILE);
-    img.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", img.headsPerCylinder, CONFIGFILE);
-    img.quirks = ini_getl(section, "Quirks", img.quirks, CONFIGFILE);
-    img.rightAlignStrings = ini_getbool(section, "RightAlignStrings", 0, CONFIGFILE);
-    img.name_from_image = ini_getbool(section, "NameFromImage", 0, CONFIGFILE);
-    img.prefetchbytes = ini_getl(section, "PrefetchBytes", img.prefetchbytes, CONFIGFILE);
-    img.reinsert_on_inquiry = ini_getbool(section, "ReinsertCDOnInquiry", img.reinsert_on_inquiry, CONFIGFILE);
-    img.reinsert_after_eject = ini_getbool(section, "ReinsertAfterEject", img.reinsert_after_eject, CONFIGFILE);
-    img.ejectButton = ini_getl(section, "EjectButton", 0, CONFIGFILE);
+    scsi_system_settings_t *devSys = getSystemSetting();
+    scsi_device_settings_t *devCfg = getDeviceSettings(target_idx);
+    img.scsiId = target_idx;
+    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));
+
+    img.deviceType = devCfg->deviceType;
+    img.deviceTypeModifier = devCfg->deviceTypeModifier;
+    img.sectorsPerTrack = devCfg->sectorsPerTrack;
+    img.headsPerCylinder = devCfg->headsPerCylinder;
+    img.quirks = devSys->quirks;
+    img.rightAlignStrings = devCfg->rightAlignStrings;
+    img.name_from_image = devCfg->nameFromImage;
+    img.prefetchbytes = devCfg->prefetchBytes;
+    img.reinsert_on_inquiry = devCfg->reinsertOnInquiry;
+    img.reinsert_after_eject = devCfg->reinsertAfterEject;
+    img.ejectButton = devCfg->ejectButton;
 #ifdef ENABLE_AUDIO_OUTPUT
-    uint16_t vol = ini_getl(section, "CDAVolume", DEFAULT_VOLUME_LEVEL, CONFIGFILE) & 0xFF;
+    uint16_t vol = devCfg->vol;
     // Set volume on both channels
     audio_set_volume(target_idx, (vol << 8) | vol);
 #endif
 
-    char tmp[32];
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
-    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, sizeof(img.prodId));
+    memcpy(img.vendor, devCfg->vendor, sizeof(img.vendor));
+    memcpy(img.prodId, devCfg->prodId, sizeof(img.prodId));
+    memcpy(img.revision, devCfg->revision, sizeof(img.revision));
+    memcpy(img.serial, devCfg->serial, sizeof(img.serial));
 
-    memset(tmp, 0, sizeof(tmp));
-    ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
-    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, sizeof(img.serial));
+    char section[6] = "SCSI0";
+    section[4] += target_idx;
+    char tmp[32];
 
-    if (strlen(section) == 5 && strncmp(section, "SCSI", 4) == 0) // allow within target [SCSIx] blocks only
+    ini_gets(section, "ImgDir", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
     {
-        ini_gets(section, "ImgDir", "", tmp, sizeof(tmp), CONFIGFILE);
-        if (tmp[0])
-        {
-            logmsg("SCSI", target_idx, " using image directory '", tmp, "'");
-            img.image_directory = true;
-        }
-        else
-        {
-            strcpy(tmp, "HD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FIXED, "disk");
+        logmsg("SCSI", target_idx, " using image directory '", tmp, "'");
+        img.image_directory = true;
+    }
+    else
+    {
+        strcpy(tmp, "HD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FIXED, "disk");
 
-            strcpy(tmp, "CD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_OPTICAL, "optical");
+        strcpy(tmp, "CD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_OPTICAL, "optical");
 
-            strcpy(tmp, "RE0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_REMOVABLE, "removable");
+        strcpy(tmp, "RE0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_REMOVABLE, "removable");
 
-            strcpy(tmp, "MO0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_MO, "magneto-optical");
+        strcpy(tmp, "MO0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_MO, "magneto-optical");
 
-            strcpy(tmp, "TP0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_SEQUENTIAL, "tape");
+        strcpy(tmp, "TP0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_SEQUENTIAL, "tape");
 
-            strcpy(tmp, "FD0");
-            tmp[2] += target_idx;
-            scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FLOPPY_14MB, "floppy");
-        }
+        strcpy(tmp, "FD0");
+        tmp[2] += target_idx;
+        scsiDiskCheckDir(tmp, target_idx, &img, S2S_CFG_FLOPPY_14MB, "floppy");
     }
 }
 
@@ -875,17 +696,17 @@ int scsiDiskGetNextImageName(image_config_t &img, char *buf, size_t buflen)
 
 void scsiDiskLoadConfig(int target_idx)
 {
+    // Get values from system preset, if any
+    char presetName[32];
+
+    // Get values from device preset, if any
     char section[6] = "SCSI0";
     section[4] = '0' + target_idx;
-
-    // Set default settings
-    scsiDiskConfigDefaults(target_idx);
-
-    // First load global settings
-    scsiDiskLoadConfig(target_idx, "SCSI");
+    ini_gets(section, "Device", "", presetName, sizeof(presetName), CONFIGFILE);
+    initDeviceSettings(target_idx, presetName);
 
     // Then settings specific to target ID
-    scsiDiskLoadConfig(target_idx, section);
+    scsiDiskSetConfig(target_idx);
 
     // Check if we have image specified by name
     char filename[MAX_FILE_PATH];
@@ -1008,11 +829,11 @@ void s2s_configInit(S2S_BoardCfg* config)
 
     // Get default values from system preset, if any
     ini_gets("SCSI", "System", "", tmp, sizeof(tmp), CONFIGFILE);
-    preset_config_t defaults = getSystemPreset(tmp);
-
-    if (defaults.presetName)
+    scsi_system_settings_t *sysCfg = initSystemSetting(tmp);
+    const char* sysPresetName = getSystemPresetName(); 
+    if (sysPresetName[0])
     {
-        logmsg("Active configuration (using system preset \"", defaults.presetName, "\"):");
+        logmsg("Active configuration (using system preset \"", sysPresetName, "\"):");
     }
     else
     {
@@ -1023,11 +844,11 @@ void s2s_configInit(S2S_BoardCfg* config)
     memcpy(config->magic, "BCFG", 4);
     config->flags = 0;
     config->startupDelay = 0;
-    config->selectionDelay = ini_getl("SCSI", "SelectionDelay", defaults.selectionDelay, CONFIGFILE);
+    config->selectionDelay = sysCfg->selectionDelay;
     config->flags6 = 0;
     config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;
 
-    int maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", defaults.maxSyncSpeed, CONFIGFILE);
+    int maxSyncSpeed = sysCfg->maxSyncSpeed;
     if (maxSyncSpeed < 5 && config->scsiSpeed > S2S_CFG_SPEED_ASYNC_50)
         config->scsiSpeed = S2S_CFG_SPEED_ASYNC_50;
     else if (maxSyncSpeed < 10 && config->scsiSpeed > S2S_CFG_SPEED_SYNC_5)
@@ -1035,7 +856,7 @@ void s2s_configInit(S2S_BoardCfg* config)
 
     logmsg("-- SelectionDelay = ", (int)config->selectionDelay);
 
-    if (ini_getbool("SCSI", "EnableUnitAttention", defaults.enableUnitAttention, CONFIGFILE))
+    if (sysCfg->enableUnitAttention)
     {
         logmsg("-- EnableUnitAttention = Yes");
         config->flags |= S2S_CFG_ENABLE_UNIT_ATTENTION;
@@ -1045,7 +866,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableUnitAttention = No");
     }
 
-    if (ini_getbool("SCSI", "EnableSCSI2", defaults.enableSCSI2, CONFIGFILE))
+    if (sysCfg->enableSCSI2)
     {
         logmsg("-- EnableSCSI2 = Yes");
         config->flags |= S2S_CFG_ENABLE_SCSI2;
@@ -1055,7 +876,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableSCSI2 = No");
     }
 
-    if (ini_getbool("SCSI", "EnableSelLatch", defaults.enableSelLatch, CONFIGFILE))
+    if (sysCfg->enableSelLatch)
     {
         logmsg("-- EnableSelLatch = Yes");
         config->flags |= S2S_CFG_ENABLE_SEL_LATCH;
@@ -1065,7 +886,7 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableSelLatch = No");
     }
 
-    if (ini_getbool("SCSI", "MapLunsToIDs", defaults.mapLunsToIDs, CONFIGFILE))
+    if (sysCfg->mapLunsToIDs)
     {
         logmsg("-- MapLunsToIDs = Yes");
         config->flags |= S2S_CFG_MAP_LUNS_TO_IDS;
@@ -1076,7 +897,7 @@ void s2s_configInit(S2S_BoardCfg* config)
     }
 
 #ifdef PLATFORM_HAS_PARITY_CHECK
-    if (ini_getbool("SCSI", "EnableParity", defaults.enableParity, CONFIGFILE))
+    if (sysCfg->enableParity)
     {
         logmsg("-- EnableParity = Yes");
         config->flags |= S2S_CFG_ENABLE_PARITY;
@@ -1086,7 +907,6 @@ void s2s_configInit(S2S_BoardCfg* config)
         logmsg("-- EnableParity = No");
     }
 #endif
-
     memset(tmp, 0, sizeof(tmp));
     ini_gets("SCSI", "WiFiMACAddress", "", tmp, sizeof(tmp), CONFIGFILE);
     if (tmp[0])

+ 0 - 60
src/ZuluSCSI_presets.cpp

@@ -1,60 +0,0 @@
-#include "ZuluSCSI_presets.h"
-#include "ZuluSCSI_disk.h"
-#include "ZuluSCSI_log.h"
-#include "ZuluSCSI_config.h"
-#include <strings.h>
-
-// Helper function for case-insensitive string compare
-static bool strequals(const char *a, const char *b)
-{
-    return strcasecmp(a, b) == 0;
-}
-
-preset_config_t getSystemPreset(const char *presetName)
-{
-    // Default configuration
-    preset_config_t cfg = {};
-    cfg.quirks = S2S_CFG_QUIRKS_NONE;
-    cfg.deviceTypeModifier = 0;
-    cfg.sectorsPerTrack = 63;
-    cfg.headsPerCylinder = 255;
-    cfg.prefetchBytes = PREFETCH_BUFFER_SIZE;
-
-    cfg.selectionDelay = 255;
-    cfg.maxSyncSpeed = 10;
-    cfg.enableUnitAttention = false;
-    cfg.enableSCSI2 = true;
-    cfg.enableSelLatch = false;
-    cfg.mapLunsToIDs = false;
-    cfg.enableParity = true;
-    cfg.initPreDelay = 0;
-
-    // System-specific defaults
-    if (strequals(presetName, ""))
-    {
-        // Preset name is empty, use default configuration
-    }
-    else if (strequals(presetName, "Mac"))
-    {
-        cfg.presetName = "Mac";
-        cfg.quirks = S2S_CFG_QUIRKS_APPLE;
-    }
-    else if (strequals(presetName, "MacPlus"))
-    {
-        cfg.presetName = "MacPlus";
-        cfg.quirks = S2S_CFG_QUIRKS_APPLE;
-        cfg.enableSelLatch = true;
-        cfg.enableSCSI2 = false;
-        cfg.selectionDelay = 0;
-    }
-    else if (strequals(presetName, "MPC3000"))
-    {
-        cfg.initPreDelay = 600;
-    }
-    else
-    {
-        logmsg("Unknown preset name ", presetName, ", using default settings");
-    }
-
-    return cfg;
-}

+ 0 - 33
src/ZuluSCSI_presets.h

@@ -1,33 +0,0 @@
-// Preset configurations for various system types.
-// Set by "System" config option in config ini.
-
-#pragma once
-
-// The settings set here will be used as defaults but
-// can be overridden by the ini file settings.
-struct preset_config_t {
-    // Informative name of the preset configuration, or NULL for defaults
-    const char *presetName;
-
-    // Default settings that apply per SCSI ID
-    int quirks;
-    int deviceTypeModifier;
-    int sectorsPerTrack;
-    int headsPerCylinder;
-    int prefetchBytes;
-    bool rightAlignStrings;
-    bool reinsertOnInquiry;
-
-    // Default settings that apply to all SCSI IDs
-    int selectionDelay;
-    int maxSyncSpeed;
-    int initPreDelay;
-    bool enableUnitAttention;
-    bool enableSCSI2;
-    bool enableSelLatch;
-    bool mapLunsToIDs;
-    bool enableParity;
-};
-
-// Fetch a preset configuration, or return the default config if unknown system type.
-preset_config_t getSystemPreset(const char *presetName);

+ 391 - 0
src/ZuluSCSI_settings.cpp

@@ -0,0 +1,391 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
+ * 
+ * This file is licensed under the GPL version 3 or any later version.  
+ * It is derived from scsiPhy.c in SCSI2SD V6.
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+
+#include "ZuluSCSI_settings.h"
+#include "ZuluSCSI_disk.h"
+#include "ZuluSCSI_audio.h"
+#include "ZuluSCSI_log.h"
+#include "ZuluSCSI_config.h"
+#include <strings.h>
+#include <minIni.h>
+#include <minIni_cache.h>
+
+// SCSI system and device settings
+static scsi_settings_t scsiSetting;
+
+// Helper function for case-insensitive string compare
+static bool strequals(const char *a, const char *b)
+{
+    return strcasecmp(a, b) == 0;
+}
+
+// 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)
+    {
+        // Right align and trim spaces on either side
+        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
+    {
+        // Left align, preserve spaces in case config tries to manually right-align
+        int dst = 0;
+        for (int src = 0; src < fieldsize; src++)
+        {
+            char c = field[src];
+            if (c < 0x20 || c > 0x7E) c = 0x20;
+            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(uint8_t scsiId, const char *presetName)
+{
+    char section[6] = "SCSI0";
+    section[4] += scsiId;
+
+    scsi_device_settings_t &cfg = scsiSetting.dev[scsiId];
+    scsi_device_settings_t &cfgDefault = scsiSetting.dev[SCSI_SETTINGS_SYS_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_network[4]   = DRIVEINFO_NETWORK;
+    static const char *driveinfo_tape[4]      = DRIVEINFO_TAPE;
+
+    static const char *apl_driveinfo_fixed[4]     = APPLE_DRIVEINFO_FIXED;
+    static const char *apl_driveinfo_removable[4] = APPLE_DRIVEINFO_REMOVABLE;
+    static const char *apl_driveinfo_optical[4]   = APPLE_DRIVEINFO_OPTICAL;
+    static const char *apl_driveinfo_floppy[4]    = APPLE_DRIVEINFO_FLOPPY;
+    static const char *apl_driveinfo_magopt[4]    = APPLE_DRIVEINFO_MAGOPT;
+    static const char *apl_driveinfo_network[4]   = APPLE_DRIVEINFO_NETWORK;
+    static const char *apl_driveinfo_tape[4]      = APPLE_DRIVEINFO_TAPE;
+
+    const char **driveinfo = NULL;
+    bool known_preset = false;
+    scsi_system_settings_t& cfgSys = scsiSetting.sys;
+
+    strncpy(scsiSetting.presetName[scsiId], presetName, sizeof(scsiSetting.presetName[scsiId]));
+    // Make sure string is null terminated
+    scsiSetting.presetName[scsiId][sizeof(scsiSetting.presetName[scsiId])-1] = '\0';
+
+    if (strequals("", presetName))
+    {
+        // empty preset, use default
+        known_preset = true;
+    }
+
+    if (strequals("ST32430N", presetName))
+    {
+        static const char *st32430n[4] = {"SEAGATE", "STN32F30N", PLATFORM_REVISION, ""};
+        driveinfo = st32430n;
+        known_preset = true;
+    }
+    else if (cfgSys.quirks == S2S_CFG_QUIRKS_APPLE)
+    {
+        // Use default drive IDs that are recognized by Apple machines
+        switch (cfg.deviceType)
+        {
+            case S2S_CFG_FIXED:         driveinfo = apl_driveinfo_fixed; break;
+            case S2S_CFG_REMOVABLE:     driveinfo = apl_driveinfo_removable; break;
+            case S2S_CFG_OPTICAL:       driveinfo = apl_driveinfo_optical; break;
+            case S2S_CFG_FLOPPY_14MB:   driveinfo = apl_driveinfo_floppy; break;
+            case S2S_CFG_MO:            driveinfo = apl_driveinfo_magopt; break;
+            case S2S_CFG_NETWORK:       driveinfo = apl_driveinfo_network; break;
+            case S2S_CFG_SEQUENTIAL:    driveinfo = apl_driveinfo_tape; break;
+            default:                    driveinfo = apl_driveinfo_fixed; break;
+        }
+    }
+    else
+    {
+        // Generic IDs
+        switch (cfg.deviceType)
+        {
+            case S2S_CFG_FIXED:         driveinfo = driveinfo_fixed; break;
+            case S2S_CFG_REMOVABLE:     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_NETWORK:       driveinfo = driveinfo_network; break;
+            case S2S_CFG_SEQUENTIAL:    driveinfo = driveinfo_tape; break;
+            default:                    driveinfo = driveinfo_fixed; break;
+        }
+    }
+
+    if (!known_preset)
+    {
+        scsiSetting.presetName[scsiId][0] = '\0';
+        logmsg("Unknown Device preset name ", presetName, ", using default settings");
+    }
+
+    // If the scsi string has not been set system wide use default scsi string
+    if (!cfgDefault.vendor[0] && driveinfo[0][0])
+        strncpy(cfg.vendor, driveinfo[0], sizeof(cfg.vendor));
+    if (!cfgDefault.prodId[0] &&driveinfo[1][0])
+        strncpy(cfg.prodId, driveinfo[1], sizeof(cfg.prodId));
+    if (!cfgDefault.revision[0] &&driveinfo[2][0])
+        strncpy(cfg.revision, driveinfo[2], sizeof(cfg.revision));
+    if (!cfgDefault.serial[0] &&driveinfo[3][0])
+        strncpy(cfg.serial, driveinfo[3], sizeof(cfg.serial));
+}
+
+// Read device settings
+static void readIniSCSIDeviceSetting(scsi_device_settings_t &cfg, const char *section)
+{
+    cfg.deviceType = ini_getl(section, "Type", cfg.deviceType, CONFIGFILE);
+    cfg.deviceTypeModifier = ini_getl(section, "TypeModifier", cfg.deviceTypeModifier, CONFIGFILE);
+    cfg.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", cfg.sectorsPerTrack, CONFIGFILE);
+    cfg.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", cfg.headsPerCylinder, CONFIGFILE);
+    cfg.prefetchBytes = ini_getl(section, "PrefetchBytes", cfg.prefetchBytes, CONFIGFILE);
+    cfg.ejectButton = ini_getl(section, "EjectButton", cfg.ejectButton, CONFIGFILE);
+
+    cfg.vol = ini_getl(section, "CDAVolume", cfg.vol, CONFIGFILE) & 0xFF;
+
+    cfg.nameFromImage = ini_getbool(section, "NameFromImage", cfg.nameFromImage, CONFIGFILE);
+    cfg.rightAlignStrings = ini_getbool(section, "RightAlignStrings", cfg.rightAlignStrings , CONFIGFILE);
+    cfg.reinsertOnInquiry = ini_getbool(section, "ReinsertCDOnInquiry", cfg.reinsertOnInquiry, CONFIGFILE);
+    cfg.reinsertAfterEject = ini_getbool(section, "ReinsertAfterEject", cfg.reinsertAfterEject, CONFIGFILE);
+    cfg.disableMacSanityCheck = ini_getbool(section, "DisableMacSanityCheck", cfg.disableMacSanityCheck, CONFIGFILE);
+
+    char tmp[32];
+    ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.vendor, 0, sizeof(cfg.vendor));
+        strncpy(cfg.vendor, tmp, sizeof(cfg.vendor));
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Product", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.prodId, 0, sizeof(cfg.prodId));
+        strncpy(cfg.prodId, tmp, sizeof(cfg.prodId));
+
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.revision, 0, sizeof(cfg.revision));
+        strncpy(cfg.revision, tmp, sizeof(cfg.revision));
+    }
+    memset(tmp, 0, sizeof(tmp));
+
+    ini_gets(section, "Serial", "", tmp, sizeof(tmp), CONFIGFILE);
+    if (tmp[0])
+    {
+        memset(cfg.serial, 0, sizeof(cfg.serial));
+        strncpy(cfg.serial, tmp, sizeof(cfg.serial));
+    }
+}
+
+scsi_system_settings_t *initSystemSetting(const char *presetName)
+{
+    scsi_system_settings_t &cfgSys = scsiSetting.sys;
+    scsi_device_settings_t &cfgDev = scsiSetting.dev[SCSI_SETTINGS_SYS_IDX];
+    // This is a hack to figure out if apple quirks is on via a dip switch
+    S2S_TargetCfg img;
+
+    img.quirks = S2S_CFG_QUIRKS_NONE;
+    #ifdef PLATFORM_CONFIG_HOOK
+            PLATFORM_CONFIG_HOOK(&img);
+    #endif
+
+    // Default settings for host compatibility 
+    cfgSys.quirks = img.quirks;
+    cfgSys.selectionDelay = 255;
+    cfgSys.maxSyncSpeed = 10;
+    cfgSys.initPreDelay = 0;
+    cfgSys.initPostDelay = 0;
+    cfgSys.phyMode = 0;
+
+    cfgSys.enableUnitAttention = false;
+    cfgSys.enableSCSI2 = true;
+    cfgSys.enableSelLatch = false;
+    cfgSys.mapLunsToIDs = false;
+    cfgSys.enableParity = true;
+    cfgSys.useFATAllocSize = false;
+    
+    // setting set for all or specific devices
+    cfgDev.deviceType = 0;
+    cfgDev.deviceTypeModifier = 0;
+    cfgDev.sectorsPerTrack = 63;
+    cfgDev.headsPerCylinder = 255;
+    cfgDev.prefetchBytes = PREFETCH_BUFFER_SIZE;
+    cfgDev.ejectButton = 0;
+    cfgDev.vol = DEFAULT_VOLUME_LEVEL;
+    
+    cfgDev.nameFromImage = false;
+    cfgDev.rightAlignStrings = false;
+    cfgDev.reinsertOnInquiry = true;
+    cfgDev.reinsertAfterEject = true;
+    cfgDev.disableMacSanityCheck = false;
+
+    // System-specific defaults
+    strncpy(scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX],
+            presetName,
+            sizeof(scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX]));
+    // Make sure string is null terminated
+    scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX][sizeof(scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX])-1] = '\0';
+
+    if (strequals(presetName, ""))
+    {
+        // Preset name is empty, use default configuration
+    }
+    else if (strequals(presetName, "Mac"))
+    {
+        cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
+    }
+    else if (strequals(presetName, "MacPlus"))
+    {
+        cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
+        cfgSys.enableSelLatch = true;
+        cfgSys.enableSCSI2 = false;
+        cfgSys.selectionDelay = 0;
+    }
+    else if (strequals(presetName, "MPC3000"))
+    {
+        cfgSys.initPreDelay = 600;
+    }
+    else
+    {
+        scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX][0] = '\0';
+        logmsg("Unknown System preset name ", presetName, ", using default settings");
+    }
+
+    // Clear SCSI device strings
+    memset(cfgDev.vendor, 0, sizeof(cfgDev.vendor));
+    memset(cfgDev.prodId, 0, sizeof(cfgDev.prodId));
+    memset(cfgDev.revision, 0, sizeof(cfgDev.revision));
+    memset(cfgDev.serial, 0, sizeof(cfgDev.serial));
+
+    // Read default setting overrides from ini file for each SCSI device
+    readIniSCSIDeviceSetting(cfgDev, "SCSI");
+
+    // Read settings from ini file that apply to all SCSI device
+    cfgSys.quirks = ini_getl("SCSI", "Quirks", cfgSys.quirks, CONFIGFILE);
+    cfgSys.selectionDelay = ini_getl("SCSI", "SelectionDelay", cfgSys.selectionDelay, CONFIGFILE);
+    cfgSys.maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", cfgSys.maxSyncSpeed, CONFIGFILE);
+    cfgSys.initPreDelay = ini_getl("SCSI", "InitPreDelay", cfgSys.initPreDelay, CONFIGFILE);
+    cfgSys.initPostDelay = ini_getl("SCSI", "InitPostDelay", cfgSys.initPostDelay, CONFIGFILE);
+    cfgSys.phyMode = ini_getl("SCSI", "PhyMode", cfgSys.phyMode, CONFIGFILE);
+
+    cfgSys.enableUnitAttention = ini_getbool("SCSI", "EnableUnitAttention", cfgSys.enableUnitAttention, CONFIGFILE);
+    cfgSys.enableSCSI2 = ini_getbool("SCSI", "EnableSCSI2", cfgSys.enableSCSI2, CONFIGFILE);
+    cfgSys.enableSelLatch = ini_getbool("SCSI", "EnableSelLatch", cfgSys.enableSelLatch, CONFIGFILE);
+    cfgSys.mapLunsToIDs = ini_getbool("SCSI", "MapLunsToIDs", cfgSys.mapLunsToIDs, CONFIGFILE);
+    cfgSys.enableParity =  ini_getbool("SCSI", "EnableParity", cfgSys.enableParity, CONFIGFILE);
+    cfgSys.useFATAllocSize = ini_getbool("SCSI", "UseFATAllocSize", cfgSys.useFATAllocSize, CONFIGFILE);
+
+    return &cfgSys;
+}
+
+scsi_device_settings_t* initDeviceSettings(uint8_t scsiId, const char *presetName)
+{
+    scsi_device_settings_t& cfg = scsiSetting.dev[scsiId];
+
+    // Write default configuration from system setting initialization
+    memcpy(&cfg, &scsiSetting.dev[SCSI_SETTINGS_SYS_IDX], sizeof(cfg));
+    
+    char section[6] = "SCSI0";
+    section[4] += scsiId;
+    setDefaultDriveInfo(scsiId, presetName);
+    readIniSCSIDeviceSetting(cfg, section);
+
+    if (cfg.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(cfg.serial, 0, sizeof(cfg.serial));
+        const char *nibble = "0123456789ABCDEF";
+        cfg.serial[0] = nibble[(sd_sn >> 28) & 0xF];
+        cfg.serial[1] = nibble[(sd_sn >> 24) & 0xF];
+        cfg.serial[2] = nibble[(sd_sn >> 20) & 0xF];
+        cfg.serial[3] = nibble[(sd_sn >> 16) & 0xF];
+        cfg.serial[4] = nibble[(sd_sn >> 12) & 0xF];
+        cfg.serial[5] = nibble[(sd_sn >>  8) & 0xF];
+        cfg.serial[6] = nibble[(sd_sn >>  4) & 0xF];
+        cfg.serial[7] = nibble[(sd_sn >>  0) & 0xF];
+    }
+
+
+    formatDriveInfoField(cfg.vendor, sizeof(cfg.vendor), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.prodId, sizeof(cfg.prodId), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.revision, sizeof(cfg.revision), cfg.rightAlignStrings);
+    formatDriveInfoField(cfg.serial, sizeof(cfg.serial), true);
+
+    return &cfg;
+}
+
+scsi_system_settings_t* getSystemSetting()
+{
+    return &scsiSetting.sys;
+}
+
+scsi_device_settings_t *getDeviceSettings(uint8_t scsiId)
+{
+    return &scsiSetting.dev[scsiId];
+}
+
+const char* getSystemPresetName()
+{
+    return scsiSetting.presetName[SCSI_SETTINGS_SYS_IDX];
+}
+
+const char* getDevicePresetName(uint8_t scsiId)
+{
+    return scsiSetting.presetName[scsiId];
+}

+ 110 - 0
src/ZuluSCSI_settings.h

@@ -0,0 +1,110 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
+ * 
+ * This file is licensed under the GPL version 3 or any later version.  
+ * It is derived from scsiPhy.c in SCSI2SD V6.
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+#include <stdint.h>
+
+// Index 8 is the system defaults
+// Index 0-7 represent device settings
+#define SCSI_SETTINGS_SYS_IDX 8
+
+// This struct should only have new settings added to the end
+// as it maybe saved and restored directly from flash memory
+struct __attribute__((__packed__)) scsi_system_settings_t 
+{
+    // Settings for host compatibility 
+    uint8_t quirks;
+    uint8_t selectionDelay;
+    uint8_t maxSyncSpeed;
+    uint8_t phyMode;
+    uint16_t initPreDelay;
+    uint16_t initPostDelay;
+
+    bool enableUnitAttention;
+    bool enableSCSI2;
+    bool enableSelLatch;
+    bool mapLunsToIDs;
+    bool enableParity;
+    bool useFATAllocSize;
+};
+
+// This struct should only have new setting added to the end
+// as it maybe saved and restored directly from flash memory
+struct __attribute__((__packed__)) scsi_device_settings_t
+{
+    // Settings that can be set on all or specific device
+    int prefetchBytes;
+    uint16_t sectorsPerTrack;
+    uint16_t headsPerCylinder;
+
+    char prodId[16];
+    char serial[16];
+    char vendor[8];
+    char revision[4];
+
+    uint16_t vol;
+    uint8_t deviceType;
+    uint8_t deviceTypeModifier;
+    uint8_t ejectButton;
+    bool nameFromImage;
+    bool rightAlignStrings;
+    bool reinsertOnInquiry;
+    bool reinsertAfterEject;
+    bool disableMacSanityCheck;
+};
+
+
+struct scsi_settings_t {
+    // Informative name of the preset configuration, or NULL for defaults
+    // The last presetName is for the System preset name. The rest are for
+    // corresponding SCSI Ids.
+    char presetName[9][32];
+
+    // These are setting for host compatibility
+    scsi_system_settings_t sys;
+
+    // The last dev will be copied over the other dev scsi Id for device defaults.
+    // It is set during when the system settings are initialized
+    scsi_device_settings_t dev[9];
+};
+
+
+// Initialize settings for all devices with a preset configuration,
+//  or return the default config if unknown system type.
+// Then overwrite any settings with those in the CONFIGFILE
+scsi_system_settings_t *initSystemSetting(const char *presetName);
+
+// Copy any shared device setting done the initSystemSettings as default settings, 
+// or return the default config if unknown device type.
+// Then overwrite any settings with those in the CONFIGFILE
+scsi_device_settings_t *initDeviceSettings(uint8_t scsiId, const char *presetName);
+
+// return the system settings struct to read values
+scsi_system_settings_t *getSystemSetting();
+
+// return the device settings struct to read values
+scsi_device_settings_t *getDeviceSettings(uint8_t scsiId);
+
+// return the system preset name
+const char* getSystemPresetName();
+
+// return the device preset name
+const char* getDevicePresetName(uint8_t scsiId);

+ 1 - 1
zuluscsi.ini

@@ -3,7 +3,7 @@
 # Settings that apply to all SCSI IDs
 
 # Select a system preset to apply default settings
-# Known systems: "Mac", "MacPlus"
+# Known systems: "Mac", "MacPlus", "MPC3000"
 #System="Mac"
 
 #Debug = 0   # Same effect as DIPSW2, enables verbose log messages