| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
- //
- // This file is part of SCSI2SD.
- //
- // SCSI2SD 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.
- //
- // SCSI2SD 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 SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
- #include "ConfigUtil.hh"
- #include <limits>
- #include <sstream>
- #include <stdexcept>
- #include <string.h>
- #include <wx/xml/xml.h>
- using namespace SCSI2SD;
- namespace
- {
- // Endian conversion routines.
- // The Cortex-M3 inside the Cypress PSoC 5LP is a
- // little-endian device.
- bool isHostLE()
- {
- union
- {
- int i;
- char c[sizeof(int)];
- } x;
- x.i = 1;
- return (x.c[0] == 1);
- }
- uint16_t toLE16(uint16_t in)
- {
- if (isHostLE())
- {
- return in;
- }
- else
- {
- return (in >> 8) | (in << 8);
- }
- }
- uint16_t fromLE16(uint16_t in)
- {
- return toLE16(in);
- }
- uint32_t toLE32(uint32_t in)
- {
- if (isHostLE())
- {
- return in;
- }
- else
- {
- return (in >> 24) |
- ((in >> 8) & 0xff00) |
- ((in << 8) & 0xff0000) |
- (in << 24);
- }
- }
- uint32_t fromLE32(uint32_t in)
- {
- return toLE32(in);
- }
- }
- TargetConfig
- ConfigUtil::Default(size_t targetIdx)
- {
- TargetConfig config;
- memset(&config, 0, sizeof(config));
- config.scsiId = targetIdx;
- if (targetIdx == 0)
- {
- config.scsiId = config.scsiId | CONFIG_TARGET_ENABLED;
- }
- config.deviceType = CONFIG_FIXED;
- // Default to maximum fail-safe options.
- config.flags = 0;
- config.deviceTypeModifier = 0;
- config.sdSectorStart = 0;
- // Default to 2GB. Many systems have trouble with > 2GB disks, and
- // a few start to complain at 1GB.
- config.scsiSectors = 4194303; // 2GB - 1 sector
- config.bytesPerSector = 512;
- config.sectorsPerTrack = 63;
- config.headsPerCylinder = 255;
- memcpy(config.vendor, " codesrc", 8);
- memcpy(config.prodId, " SCSI2SD", 16);
- memcpy(config.revision, " 4.2", 4);
- memcpy(config.serial, "1234567812345678", 16);
- // Reserved fields, already set to 0
- // config.reserved
- // not supported yet.
- // config.vpd
- return config;
- }
- TargetConfig
- ConfigUtil::fromBytes(const uint8_t* data)
- {
- TargetConfig result;
- memcpy(&result, data, sizeof(TargetConfig));
- result.sdSectorStart = toLE32(result.sdSectorStart);
- result.scsiSectors = toLE32(result.scsiSectors);
- result.bytesPerSector = toLE16(result.bytesPerSector);
- result.sectorsPerTrack = toLE16(result.sectorsPerTrack);
- result.headsPerCylinder = toLE16(result.headsPerCylinder);
- return result;
- }
- std::vector<uint8_t>
- ConfigUtil::toBytes(const TargetConfig& _config)
- {
- TargetConfig config(_config);
- config.sdSectorStart = fromLE32(config.sdSectorStart);
- config.scsiSectors = fromLE32(config.scsiSectors);
- config.bytesPerSector = fromLE16(config.bytesPerSector);
- config.sectorsPerTrack = fromLE16(config.sectorsPerTrack);
- config.headsPerCylinder = fromLE16(config.headsPerCylinder);
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(&config);
- return std::vector<uint8_t>(begin, begin + sizeof(config));
- }
- std::string
- ConfigUtil::toXML(const TargetConfig& config)
- {
- std::stringstream s;
- s <<
- "<SCSITarget id=\"" <<
- static_cast<int>(config.scsiId & CONFIG_TARGET_ID_BITS) << "\">\n" <<
- " <enabled>" <<
- (config.scsiId & CONFIG_TARGET_ENABLED ? "true" : "false") <<
- "</enabled>\n" <<
- " <unitAttention>" <<
- (config.flags & CONFIG_ENABLE_UNIT_ATTENTION ? "true" : "false") <<
- "</unitAttention>\n" <<
- " <parity>" <<
- (config.flags & CONFIG_ENABLE_PARITY ? "true" : "false") <<
- "</parity>\n" <<
- " <!-- ********************************************************\n" <<
- " Only set to true when using with a fast SCSI2 host\n " <<
- " controller. This can cause problems with older/slower\n" <<
- " hardware.\n" <<
- " ********************************************************* -->\n" <<
- " <enableScsi2>" <<
- (config.flags & CONFIG_ENABLE_SCSI2 ? "true" : "false") <<
- "</enableScsi2>\n" <<
- " <!-- ********************************************************\n" <<
- " Setting to 'true' will result in increased performance at the\n" <<
- " cost of lower noise immunity.\n" <<
- " Only set to true when using short cables with only 1 or two\n" <<
- " devices. This should remain off when using external SCSI1 DB25\n" <<
- " cables.\n" <<
- " ********************************************************* -->\n" <<
- " <disableGlitchFilter>" <<
- (config.flags & CONFIG_DISABLE_GLITCH ? "true" : "false") <<
- "</disableGlitchFilter>\n" <<
- "\n" <<
- " <!-- ********************************************************\n" <<
- " Space separated list. Available options:\n" <<
- " apple\t\tReturns Apple-specific mode pages\n" <<
- " ********************************************************* -->\n" <<
- " <quirks>" <<
- (config.quirks & CONFIG_QUIRKS_APPLE ? "apple" : "") <<
- "</quirks>\n" <<
- "\n\n" <<
- " <!-- ********************************************************\n" <<
- " 0x0 Fixed hard drive.\n" <<
- " 0x1 Removable drive.\n" <<
- " 0x2 Optical drive (ie. CD drive).\n" <<
- " 0x3 1.44MB Floppy Drive.\n" <<
- " ********************************************************* -->\n" <<
- " <deviceType>0x" <<
- std::hex << static_cast<int>(config.deviceType) <<
- "</deviceType>\n" <<
- "\n\n" <<
- " <!-- ********************************************************\n" <<
- " Device type modifier is usually 0x00. Only change this if your\n" <<
- " OS requires some special value.\n" <<
- "\n" <<
- " 0x4C Data General Micropolis disk\n" <<
- " ********************************************************* -->\n" <<
- " <deviceTypeModifier>0x" <<
- std::hex << static_cast<int>(config.deviceTypeModifier) <<
- "</deviceTypeModifier>\n" <<
- "\n\n" <<
- " <!-- ********************************************************\n" <<
- " SD card offset, as a sector number (always 512 bytes).\n" <<
- " ********************************************************* -->\n" <<
- " <sdSectorStart>" << std::dec << config.sdSectorStart << "</sdSectorStart>\n" <<
- "\n\n" <<
- " <!-- ********************************************************\n" <<
- " Drive geometry settings.\n" <<
- " ********************************************************* -->\n" <<
- "\n"
- " <scsiSectors>" << std::dec << config.scsiSectors << "</scsiSectors>\n" <<
- " <bytesPerSector>" << std::dec << config.bytesPerSector << "</bytesPerSector>\n" <<
- " <sectorsPerTrack>" << std::dec << config.sectorsPerTrack<< "</sectorsPerTrack>\n" <<
- " <headsPerCylinder>" << std::dec << config.headsPerCylinder << "</headsPerCylinder>\n" <<
- "\n\n" <<
- " <!-- ********************************************************\n" <<
- " Drive identification information. The SCSI2SD doesn't\n" <<
- " care what these are set to. Use these strings to trick a OS\n" <<
- " thinking a specific hard drive model is attached.\n" <<
- " ********************************************************* -->\n" <<
- "\n"
- " <!-- 8 character vendor string -->\n" <<
- " <!-- For Apple HD SC Setup/Drive Setup, use ' SEAGATE' -->\n" <<
- " <vendor>" << std::string(config.vendor, 8) << "</vendor>\n" <<
- "\n" <<
- " <!-- 16 character produce identifier -->\n" <<
- " <!-- For Apple HD SC Setup/Drive Setup, use ' ST225N' -->\n" <<
- " <prodId>" << std::string(config.prodId, 16) << "</prodId>\n" <<
- "\n" <<
- " <!-- 4 character product revision number -->\n" <<
- " <!-- For Apple HD SC Setup/Drive Setup, use '1.0 ' -->\n" <<
- " <revision>" << std::string(config.revision, 4) << "</revision>\n" <<
- "\n" <<
- " <!-- 16 character serial number -->\n" <<
- " <serial>" << std::string(config.serial, 16) << "</serial>\n" <<
- "</SCSITarget>\n";
- return s.str();
- }
- static uint64_t parseInt(wxXmlNode* node, uint64_t limit)
- {
- std::string str(node->GetNodeContent().mb_str());
- if (str.empty())
- {
- throw std::runtime_error("Empty " + node->GetName());
- }
- std::stringstream s;
- if (str.find("0x") == 0)
- {
- s << std::hex << str.substr(2);
- }
- else
- {
- s << str;
- }
- uint64_t result;
- s >> result;
- if (!s)
- {
- throw std::runtime_error("Invalid value for " + node->GetName());
- }
- if (result > limit)
- {
- std::stringstream msg;
- msg << "Invalid value for " << node->GetName() <<
- " (max=" << limit << ")";
- throw std::runtime_error(msg.str());
- }
- return result;
- }
- static TargetConfig
- parseTarget(wxXmlNode* node)
- {
- int id;
- {
- std::stringstream s;
- s << node->GetAttribute("id", "7");
- s >> id;
- if (!s) throw std::runtime_error("Could not parse SCSITarget id attr");
- }
- TargetConfig result = ConfigUtil::Default(id & 0x7);
- wxXmlNode *child = node->GetChildren();
- while (child)
- {
- if (child->GetName() == "enabled")
- {
- std::string s(child->GetNodeContent().mb_str());
- if (s == "true")
- {
- result.scsiId |= CONFIG_TARGET_ENABLED;
- }
- else
- {
- result.scsiId = result.scsiId & ~CONFIG_TARGET_ENABLED;
- }
- }
- else if (child->GetName() == "unitAttention")
- {
- std::string s(child->GetNodeContent().mb_str());
- if (s == "true")
- {
- result.flags |= CONFIG_ENABLE_UNIT_ATTENTION;
- }
- else
- {
- result.flags = result.flags & ~CONFIG_ENABLE_UNIT_ATTENTION;
- }
- }
- else if (child->GetName() == "parity")
- {
- std::string s(child->GetNodeContent().mb_str());
- if (s == "true")
- {
- result.flags |= CONFIG_ENABLE_PARITY;
- }
- else
- {
- result.flags = result.flags & ~CONFIG_ENABLE_PARITY;
- }
- }
- else if (child->GetName() == "enableScsi2")
- {
- std::string s(child->GetNodeContent().mb_str());
- if (s == "true")
- {
- result.flags |= CONFIG_ENABLE_SCSI2;
- }
- else
- {
- result.flags = result.flags & ~CONFIG_ENABLE_SCSI2;
- }
- }
- else if (child->GetName() == "disableGlitchFilter")
- {
- std::string s(child->GetNodeContent().mb_str());
- if (s == "true")
- {
- result.flags |= CONFIG_DISABLE_GLITCH;
- }
- else
- {
- result.flags = result.flags & ~CONFIG_DISABLE_GLITCH;
- }
- }
- else if (child->GetName() == "quirks")
- {
- std::stringstream s(std::string(child->GetNodeContent().mb_str()));
- std::string quirk;
- while (s >> quirk)
- {
- if (quirk == "apple")
- {
- result.quirks |= CONFIG_QUIRKS_APPLE;
- }
- }
- }
- else if (child->GetName() == "deviceType")
- {
- result.deviceType = parseInt(child, 0xFF);
- }
- else if (child->GetName() == "deviceTypeModifier")
- {
- result.deviceTypeModifier = parseInt(child, 0xFF);
- }
- else if (child->GetName() == "sdSectorStart")
- {
- result.sdSectorStart = parseInt(child, 0xFFFFFFFF);
- }
- else if (child->GetName() == "scsiSectors")
- {
- result.scsiSectors = parseInt(child, 0xFFFFFFFF);
- }
- else if (child->GetName() == "bytesPerSector")
- {
- result.bytesPerSector = parseInt(child, 8192);
- }
- else if (child->GetName() == "sectorsPerTrack")
- {
- result.sectorsPerTrack = parseInt(child, 255);
- }
- else if (child->GetName() == "headsPerCylinder")
- {
- result.headsPerCylinder = parseInt(child, 255);
- }
- else if (child->GetName() == "vendor")
- {
- std::string s(child->GetNodeContent().mb_str());
- s = s.substr(0, sizeof(result.vendor));
- memset(result.vendor, ' ', sizeof(result.vendor));
- memcpy(result.vendor, s.c_str(), s.size());
- }
- else if (child->GetName() == "prodId")
- {
- std::string s(child->GetNodeContent().mb_str());
- s = s.substr(0, sizeof(result.prodId));
- memset(result.prodId, ' ', sizeof(result.prodId));
- memcpy(result.prodId, s.c_str(), s.size());
- }
- else if (child->GetName() == "revision")
- {
- std::string s(child->GetNodeContent().mb_str());
- s = s.substr(0, sizeof(result.revision));
- memset(result.revision, ' ', sizeof(result.revision));
- memcpy(result.revision, s.c_str(), s.size());
- }
- else if (child->GetName() == "serial")
- {
- std::string s(child->GetNodeContent().mb_str());
- s = s.substr(0, sizeof(result.serial));
- memset(result.serial, ' ', sizeof(result.serial));
- memcpy(result.serial, s.c_str(), s.size());
- }
- child = child->GetNext();
- }
- return result;
- }
- std::vector<TargetConfig>
- ConfigUtil::fromXML(const std::string& filename)
- {
- wxXmlDocument doc;
- if (!doc.Load(filename))
- {
- throw std::runtime_error("Could not load XML file");
- }
- // start processing the XML file
- if (doc.GetRoot()->GetName() != "SCSI2SD")
- {
- throw std::runtime_error("Invalid root node, expected <SCSI2SD>");
- }
- std::vector<TargetConfig> result;
- wxXmlNode *child = doc.GetRoot()->GetChildren();
- while (child)
- {
- if (child->GetName() == "SCSITarget")
- {
- result.push_back(parseTarget(child));
- }
- child = child->GetNext();
- }
- return result;
- }
|