ZuluSCSI_settings.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2023 Rabbit Hole Computing™
  3. *
  4. * This file is licensed under the GPL version 3 or any later version.  
  5. * It is derived from scsiPhy.c in SCSI2SD V6.
  6. *
  7. * https://www.gnu.org/licenses/gpl-3.0.html
  8. * ----
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version. 
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. * GNU General Public License for more details. 
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  21. **/
  22. #include "ZuluSCSI_disk.h"
  23. #include "ZuluSCSI_audio.h"
  24. #include "ZuluSCSI_log.h"
  25. #include "ZuluSCSI_config.h"
  26. #include "ZuluSCSI_settings.h"
  27. #include <strings.h>
  28. #include <minIni.h>
  29. #include <minIni_cache.h>
  30. // SCSI system and device settings
  31. ZuluSCSISettings g_scsi_settings;
  32. const char *systemPresetName[] = {"", "Mac", "MacPlus", "MPC3000"};
  33. const char *devicePresetName[] = {"", "ST32430N"};
  34. // Helper function for case-insensitive string compare
  35. static bool strequals(const char *a, const char *b)
  36. {
  37. return strcasecmp(a, b) == 0;
  38. }
  39. // Verify format conformance to SCSI spec:
  40. // - Empty bytes filled with 0x20 (space)
  41. // - Only values 0x20 to 0x7E
  42. // - Left alignment for vendor/product/revision, right alignment for serial.
  43. static void formatDriveInfoField(char *field, int fieldsize, bool align_right)
  44. {
  45. if (align_right)
  46. {
  47. // Right align and trim spaces on either side
  48. int dst = fieldsize - 1;
  49. for (int src = fieldsize - 1; src >= 0; src--)
  50. {
  51. char c = field[src];
  52. if (c < 0x20 || c > 0x7E) c = 0x20;
  53. if (c != 0x20 || dst != fieldsize - 1)
  54. {
  55. field[dst--] = c;
  56. }
  57. }
  58. while (dst >= 0)
  59. {
  60. field[dst--] = 0x20;
  61. }
  62. }
  63. else
  64. {
  65. // Left align, preserve spaces in case config tries to manually right-align
  66. int dst = 0;
  67. for (int src = 0; src < fieldsize; src++)
  68. {
  69. char c = field[src];
  70. if (c < 0x20 || c > 0x7E) c = 0x20;
  71. field[dst++] = c;
  72. }
  73. while (dst < fieldsize)
  74. {
  75. field[dst++] = 0x20;
  76. }
  77. }
  78. }
  79. const char **ZuluSCSISettings::deviceInitST32430N(uint8_t scsiId)
  80. {
  81. static const char *st32430n[4] = {"SEAGATE", devicePresetName[DEV_PRESET_ST32430N], PLATFORM_REVISION, ""};
  82. m_dev[scsiId].deviceType = S2S_CFG_FIXED;
  83. m_devPreset[scsiId] = DEV_PRESET_ST32430N;
  84. return st32430n;
  85. }
  86. void ZuluSCSISettings::setDefaultDriveInfo(uint8_t scsiId, const char *presetName)
  87. {
  88. char section[6] = "SCSI0";
  89. section[4] += scsiId;
  90. scsi_device_settings_t &cfgDev = m_dev[scsiId];
  91. scsi_device_settings_t &cfgDefault = m_dev[SCSI_SETTINGS_SYS_IDX];
  92. static const char *driveinfo_fixed[4] = DRIVEINFO_FIXED;
  93. static const char *driveinfo_removable[4] = DRIVEINFO_REMOVABLE;
  94. static const char *driveinfo_optical[4] = DRIVEINFO_OPTICAL;
  95. static const char *driveinfo_floppy[4] = DRIVEINFO_FLOPPY;
  96. static const char *driveinfo_magopt[4] = DRIVEINFO_MAGOPT;
  97. static const char *driveinfo_network[4] = DRIVEINFO_NETWORK;
  98. static const char *driveinfo_tape[4] = DRIVEINFO_TAPE;
  99. static const char *apl_driveinfo_fixed[4] = APPLE_DRIVEINFO_FIXED;
  100. static const char *apl_driveinfo_removable[4] = APPLE_DRIVEINFO_REMOVABLE;
  101. static const char *apl_driveinfo_optical[4] = APPLE_DRIVEINFO_OPTICAL;
  102. static const char *apl_driveinfo_floppy[4] = APPLE_DRIVEINFO_FLOPPY;
  103. static const char *apl_driveinfo_magopt[4] = APPLE_DRIVEINFO_MAGOPT;
  104. static const char *apl_driveinfo_network[4] = APPLE_DRIVEINFO_NETWORK;
  105. static const char *apl_driveinfo_tape[4] = APPLE_DRIVEINFO_TAPE;
  106. const char **driveinfo = NULL;
  107. bool known_preset = false;
  108. scsi_system_settings_t& cfgSys = m_sys;
  109. #ifdef ZULUSCSI_HARDWARE_CONFIG
  110. if (g_hw_config.is_active() && g_hw_config.device_preset() == DEV_PRESET_NONE)
  111. {
  112. // empty preset, use default
  113. known_preset = true;
  114. m_devPreset[scsiId] = DEV_PRESET_NONE;
  115. }
  116. else if (g_hw_config.is_active() && g_hw_config.device_preset() == DEV_PRESET_ST32430N)
  117. {
  118. driveinfo = deviceInitST32430N(scsiId);
  119. known_preset = true;
  120. }
  121. else
  122. #endif //ZULUSCSI_HARDWARE_CONFIG
  123. if (strequals(devicePresetName[DEV_PRESET_NONE], presetName))
  124. {
  125. // empty preset, use default
  126. known_preset = true;
  127. m_devPreset[scsiId] = DEV_PRESET_NONE;
  128. }
  129. else if (strequals(devicePresetName[DEV_PRESET_ST32430N], presetName))
  130. {
  131. driveinfo = deviceInitST32430N(scsiId);
  132. known_preset = true;
  133. }
  134. if (!known_preset)
  135. {
  136. m_devPreset[scsiId] = DEV_PRESET_NONE;
  137. logmsg("Unknown Device preset name ", presetName, ", using default settings");
  138. }
  139. if (m_devPreset[scsiId] == DEV_PRESET_NONE)
  140. {
  141. if (cfgSys.quirks == S2S_CFG_QUIRKS_APPLE)
  142. {
  143. // Use default drive IDs that are recognized by Apple machines
  144. switch (cfgDev.deviceType)
  145. {
  146. case S2S_CFG_FIXED: driveinfo = apl_driveinfo_fixed; break;
  147. case S2S_CFG_REMOVABLE: driveinfo = apl_driveinfo_removable; break;
  148. case S2S_CFG_OPTICAL: driveinfo = apl_driveinfo_optical; break;
  149. case S2S_CFG_FLOPPY_14MB: driveinfo = apl_driveinfo_floppy; break;
  150. case S2S_CFG_MO: driveinfo = apl_driveinfo_magopt; break;
  151. case S2S_CFG_NETWORK: driveinfo = apl_driveinfo_network; break;
  152. case S2S_CFG_SEQUENTIAL: driveinfo = apl_driveinfo_tape; break;
  153. default: driveinfo = apl_driveinfo_fixed; break;
  154. }
  155. }
  156. else
  157. {
  158. // Generic IDs
  159. switch (cfgDev.deviceType)
  160. {
  161. case S2S_CFG_FIXED: driveinfo = driveinfo_fixed; break;
  162. case S2S_CFG_REMOVABLE: driveinfo = driveinfo_removable; break;
  163. case S2S_CFG_OPTICAL: driveinfo = driveinfo_optical; break;
  164. case S2S_CFG_FLOPPY_14MB: driveinfo = driveinfo_floppy; break;
  165. case S2S_CFG_MO: driveinfo = driveinfo_magopt; break;
  166. case S2S_CFG_NETWORK: driveinfo = driveinfo_network; break;
  167. case S2S_CFG_SEQUENTIAL: driveinfo = driveinfo_tape; break;
  168. default: driveinfo = driveinfo_fixed; break;
  169. }
  170. }
  171. }
  172. // If the scsi string has not been set system wide use default scsi string
  173. if (!cfgDefault.vendor[0] && driveinfo[0][0])
  174. strncpy(cfgDev.vendor, driveinfo[0], sizeof(cfgDev.vendor));
  175. if (!cfgDefault.prodId[0] && driveinfo[1][0])
  176. strncpy(cfgDev.prodId, driveinfo[1], sizeof(cfgDev.prodId));
  177. if (!cfgDefault.revision[0] && driveinfo[2][0])
  178. strncpy(cfgDev.revision, driveinfo[2], sizeof(cfgDev.revision));
  179. if (!cfgDefault.serial[0] && driveinfo[3][0])
  180. strncpy(cfgDev.serial, driveinfo[3], sizeof(cfgDev.serial));
  181. }
  182. // Read device settings
  183. static void readIniSCSIDeviceSetting(scsi_device_settings_t &cfg, const char *section)
  184. {
  185. cfg.deviceType = ini_getl(section, "Type", cfg.deviceType, CONFIGFILE);
  186. cfg.deviceTypeModifier = ini_getl(section, "TypeModifier", cfg.deviceTypeModifier, CONFIGFILE);
  187. cfg.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", cfg.sectorsPerTrack, CONFIGFILE);
  188. cfg.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", cfg.headsPerCylinder, CONFIGFILE);
  189. cfg.prefetchBytes = ini_getl(section, "PrefetchBytes", cfg.prefetchBytes, CONFIGFILE);
  190. cfg.ejectButton = ini_getl(section, "EjectButton", cfg.ejectButton, CONFIGFILE);
  191. cfg.vol = ini_getl(section, "CDAVolume", cfg.vol, CONFIGFILE) & 0xFF;
  192. cfg.nameFromImage = ini_getbool(section, "NameFromImage", cfg.nameFromImage, CONFIGFILE);
  193. cfg.rightAlignStrings = ini_getbool(section, "RightAlignStrings", cfg.rightAlignStrings , CONFIGFILE);
  194. cfg.reinsertOnInquiry = ini_getbool(section, "ReinsertCDOnInquiry", cfg.reinsertOnInquiry, CONFIGFILE);
  195. cfg.reinsertAfterEject = ini_getbool(section, "ReinsertAfterEject", cfg.reinsertAfterEject, CONFIGFILE);
  196. cfg.disableMacSanityCheck = ini_getbool(section, "DisableMacSanityCheck", cfg.disableMacSanityCheck, CONFIGFILE);
  197. char tmp[32];
  198. ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
  199. if (tmp[0])
  200. {
  201. memset(cfg.vendor, 0, sizeof(cfg.vendor));
  202. strncpy(cfg.vendor, tmp, sizeof(cfg.vendor));
  203. }
  204. memset(tmp, 0, sizeof(tmp));
  205. ini_gets(section, "Product", "", tmp, sizeof(tmp), CONFIGFILE);
  206. if (tmp[0])
  207. {
  208. memset(cfg.prodId, 0, sizeof(cfg.prodId));
  209. strncpy(cfg.prodId, tmp, sizeof(cfg.prodId));
  210. }
  211. memset(tmp, 0, sizeof(tmp));
  212. ini_gets(section, "Version", "", tmp, sizeof(tmp), CONFIGFILE);
  213. if (tmp[0])
  214. {
  215. memset(cfg.revision, 0, sizeof(cfg.revision));
  216. strncpy(cfg.revision, tmp, sizeof(cfg.revision));
  217. }
  218. memset(tmp, 0, sizeof(tmp));
  219. ini_gets(section, "Serial", "", tmp, sizeof(tmp), CONFIGFILE);
  220. if (tmp[0])
  221. {
  222. memset(cfg.serial, 0, sizeof(cfg.serial));
  223. strncpy(cfg.serial, tmp, sizeof(cfg.serial));
  224. }
  225. }
  226. scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
  227. {
  228. scsi_system_settings_t &cfgSys = m_sys;
  229. scsi_device_settings_t &cfgDev = m_dev[SCSI_SETTINGS_SYS_IDX];
  230. // This is a hack to figure out if apple quirks is on via a dip switch
  231. S2S_TargetCfg img;
  232. img.quirks = S2S_CFG_QUIRKS_NONE;
  233. #ifdef PLATFORM_CONFIG_HOOK
  234. PLATFORM_CONFIG_HOOK(&img);
  235. #endif
  236. // Default settings for host compatibility
  237. cfgSys.quirks = img.quirks;
  238. cfgSys.selectionDelay = 255;
  239. cfgSys.maxSyncSpeed = 10;
  240. cfgSys.initPreDelay = 0;
  241. cfgSys.initPostDelay = 0;
  242. cfgSys.phyMode = 0;
  243. cfgSys.enableUnitAttention = false;
  244. cfgSys.enableSCSI2 = true;
  245. cfgSys.enableSelLatch = false;
  246. cfgSys.mapLunsToIDs = false;
  247. cfgSys.enableParity = true;
  248. cfgSys.useFATAllocSize = false;
  249. // setting set for all or specific devices
  250. cfgDev.deviceType = 0;
  251. cfgDev.deviceTypeModifier = 0;
  252. cfgDev.sectorsPerTrack = 63;
  253. cfgDev.headsPerCylinder = 255;
  254. cfgDev.prefetchBytes = PREFETCH_BUFFER_SIZE;
  255. cfgDev.ejectButton = 0;
  256. cfgDev.vol = DEFAULT_VOLUME_LEVEL;
  257. cfgDev.nameFromImage = false;
  258. cfgDev.rightAlignStrings = false;
  259. cfgDev.reinsertOnInquiry = true;
  260. cfgDev.reinsertAfterEject = true;
  261. cfgDev.disableMacSanityCheck = false;
  262. // System-specific defaults
  263. if (strequals(systemPresetName[SYS_PRESET_NONE], ""))
  264. {
  265. // Preset name is empty, use default configuration
  266. m_sysPreset = SYS_PRESET_NONE;
  267. }
  268. else if (strequals(systemPresetName[SYS_PRESET_MAC], "Mac"))
  269. {
  270. m_sysPreset = SYS_PRESET_MAC;
  271. cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
  272. }
  273. else if (strequals(systemPresetName[SYS_PRESET_MACPLUS], "MacPlus"))
  274. {
  275. m_sysPreset = SYS_PRESET_MACPLUS;
  276. cfgSys.quirks = S2S_CFG_QUIRKS_APPLE;
  277. cfgSys.enableSelLatch = true;
  278. cfgSys.enableSCSI2 = false;
  279. cfgSys.selectionDelay = 0;
  280. }
  281. else if (strequals(systemPresetName[SYS_PRESET_MPC3000], "MPC3000"))
  282. {
  283. cfgSys.initPreDelay = 600;
  284. }
  285. else
  286. {
  287. m_sysPreset = SYS_PRESET_NONE;
  288. logmsg("Unknown System preset name ", presetName, ", using default settings");
  289. }
  290. // Clear SCSI device strings
  291. memset(cfgDev.vendor, 0, sizeof(cfgDev.vendor));
  292. memset(cfgDev.prodId, 0, sizeof(cfgDev.prodId));
  293. memset(cfgDev.revision, 0, sizeof(cfgDev.revision));
  294. memset(cfgDev.serial, 0, sizeof(cfgDev.serial));
  295. // Read default setting overrides from ini file for each SCSI device
  296. readIniSCSIDeviceSetting(cfgDev, "SCSI");
  297. // Read settings from ini file that apply to all SCSI device
  298. cfgSys.quirks = ini_getl("SCSI", "Quirks", cfgSys.quirks, CONFIGFILE);
  299. cfgSys.selectionDelay = ini_getl("SCSI", "SelectionDelay", cfgSys.selectionDelay, CONFIGFILE);
  300. cfgSys.maxSyncSpeed = ini_getl("SCSI", "MaxSyncSpeed", cfgSys.maxSyncSpeed, CONFIGFILE);
  301. cfgSys.initPreDelay = ini_getl("SCSI", "InitPreDelay", cfgSys.initPreDelay, CONFIGFILE);
  302. cfgSys.initPostDelay = ini_getl("SCSI", "InitPostDelay", cfgSys.initPostDelay, CONFIGFILE);
  303. cfgSys.phyMode = ini_getl("SCSI", "PhyMode", cfgSys.phyMode, CONFIGFILE);
  304. cfgSys.enableUnitAttention = ini_getbool("SCSI", "EnableUnitAttention", cfgSys.enableUnitAttention, CONFIGFILE);
  305. cfgSys.enableSCSI2 = ini_getbool("SCSI", "EnableSCSI2", cfgSys.enableSCSI2, CONFIGFILE);
  306. cfgSys.enableSelLatch = ini_getbool("SCSI", "EnableSelLatch", cfgSys.enableSelLatch, CONFIGFILE);
  307. cfgSys.mapLunsToIDs = ini_getbool("SCSI", "MapLunsToIDs", cfgSys.mapLunsToIDs, CONFIGFILE);
  308. cfgSys.enableParity = ini_getbool("SCSI", "EnableParity", cfgSys.enableParity, CONFIGFILE);
  309. cfgSys.useFATAllocSize = ini_getbool("SCSI", "UseFATAllocSize", cfgSys.useFATAllocSize, CONFIGFILE);
  310. return &cfgSys;
  311. }
  312. scsi_device_settings_t* ZuluSCSISettings::initDevicePName(uint8_t scsiId, const char *presetName)
  313. {
  314. scsi_device_settings_t& cfg = m_dev[scsiId];
  315. // Write default configuration from system setting initialization
  316. memcpy(&cfg, &m_dev[SCSI_SETTINGS_SYS_IDX], sizeof(cfg));
  317. char section[6] = "SCSI0";
  318. section[4] += scsiId;
  319. setDefaultDriveInfo(scsiId, presetName);
  320. readIniSCSIDeviceSetting(cfg, section);
  321. if (cfg.serial[0] == '\0')
  322. {
  323. // Use SD card serial number
  324. cid_t sd_cid;
  325. uint32_t sd_sn = 0;
  326. if (SD.card()->readCID(&sd_cid))
  327. {
  328. sd_sn = sd_cid.psn();
  329. }
  330. memset(cfg.serial, 0, sizeof(cfg.serial));
  331. const char *nibble = "0123456789ABCDEF";
  332. cfg.serial[0] = nibble[(sd_sn >> 28) & 0xF];
  333. cfg.serial[1] = nibble[(sd_sn >> 24) & 0xF];
  334. cfg.serial[2] = nibble[(sd_sn >> 20) & 0xF];
  335. cfg.serial[3] = nibble[(sd_sn >> 16) & 0xF];
  336. cfg.serial[4] = nibble[(sd_sn >> 12) & 0xF];
  337. cfg.serial[5] = nibble[(sd_sn >> 8) & 0xF];
  338. cfg.serial[6] = nibble[(sd_sn >> 4) & 0xF];
  339. cfg.serial[7] = nibble[(sd_sn >> 0) & 0xF];
  340. }
  341. formatDriveInfoField(cfg.vendor, sizeof(cfg.vendor), cfg.rightAlignStrings);
  342. formatDriveInfoField(cfg.prodId, sizeof(cfg.prodId), cfg.rightAlignStrings);
  343. formatDriveInfoField(cfg.revision, sizeof(cfg.revision), cfg.rightAlignStrings);
  344. formatDriveInfoField(cfg.serial, sizeof(cfg.serial), true);
  345. return &cfg;
  346. }
  347. scsi_device_settings_t *ZuluSCSISettings::initDevicePreset(uint8_t scsiId, const scsi_device_preset_t preset)
  348. {
  349. return initDevicePName(scsiId, devicePresetName[preset]);
  350. }
  351. scsi_system_settings_t *ZuluSCSISettings::getSystem()
  352. {
  353. return &m_sys;
  354. }
  355. scsi_device_settings_t *ZuluSCSISettings::getDevice(uint8_t scsiId)
  356. {
  357. return &m_dev[scsiId];
  358. }
  359. scsi_system_preset_t ZuluSCSISettings::getSystemPreset()
  360. {
  361. return m_sysPreset;
  362. }
  363. const char* ZuluSCSISettings::getSystemPresetName()
  364. {
  365. return systemPresetName[m_sysPreset];
  366. }
  367. scsi_device_preset_t ZuluSCSISettings::getDevicePreset(uint8_t scsiId)
  368. {
  369. return m_devPreset[scsiId];
  370. }
  371. const char* ZuluSCSISettings::getDevicePresetName(uint8_t scsiId)
  372. {
  373. return devicePresetName[m_devPreset[scsiId]];
  374. }