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