Fix for VMS 5.5-2 for incorrect Inquiry command allocation lengths
[SCSI2SD.git] / software / scsi2sd-util / ConfigUtil.cc
1 //      Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
2 //
3 //      This file is part of SCSI2SD.
4 //
5 //      SCSI2SD is free software: you can redistribute it and/or modify
6 //      it under the terms of the GNU General Public License as published by
7 //      the Free Software Foundation, either version 3 of the License, or
8 //      (at your option) any later version.
9 //
10 //      SCSI2SD is distributed in the hope that it will be useful,
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //      GNU General Public License for more details.
14 //
15 //      You should have received a copy of the GNU General Public License
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include "ConfigUtil.hh"
19
20 #include <limits>
21 #include <sstream>
22 #include <stdexcept>
23
24 #include <string.h>
25
26 #include <wx/wxprec.h>
27 #ifndef WX_PRECOMP
28 #include <wx/wx.h>
29 #endif
30 #include <wx/base64.h>
31 #include <wx/buffer.h>
32 #include <wx/xml/xml.h>
33
34
35 using namespace SCSI2SD;
36
37 namespace
38 {
39         // Endian conversion routines.
40         // The Cortex-M3 inside the Cypress PSoC 5LP is a
41         // little-endian device.
42
43         bool isHostLE()
44         {
45                 union
46                 {
47                         int i;
48                         char c[sizeof(int)];
49                 } x;
50                 x.i = 1;
51                 return (x.c[0] == 1);
52         }
53
54         uint16_t toLE16(uint16_t in)
55         {
56                 if (isHostLE())
57                 {
58                         return in;
59                 }
60                 else
61                 {
62                         return (in >> 8) | (in << 8);
63                 }
64         }
65         uint16_t fromLE16(uint16_t in)
66         {
67                 return toLE16(in);
68         }
69
70         uint32_t toLE32(uint32_t in)
71         {
72                 if (isHostLE())
73                 {
74                         return in;
75                 }
76                 else
77                 {
78                         return (in >> 24) |
79                                 ((in >> 8) & 0xff00) |
80                                 ((in << 8) & 0xff0000) |
81                                 (in << 24);
82                 }
83         }
84         uint32_t fromLE32(uint32_t in)
85         {
86                 return toLE32(in);
87         }
88
89         std::vector<uint8_t> getModePages(const TargetConfig& cfg)
90         {
91                 std::vector<uint8_t> result;
92                 unsigned i = 0;
93                 while (i < sizeof(cfg.modePages) - 2)
94                 {
95                         int pageLen = cfg.modePages[i+1];
96                         if (pageLen == 0) break;
97                         std::copy(
98                                 &cfg.modePages[i],
99                                 &cfg.modePages[i+pageLen+2],
100                                 std::back_inserter(result));
101                         i += pageLen + 2;
102                 }
103                 return result;
104         }
105
106         std::vector<uint8_t> getVPDPages(const TargetConfig& cfg)
107         {
108                 std::vector<uint8_t> result;
109                 unsigned i = 0;
110                 while (i < sizeof(cfg.vpd) - 4)
111                 {
112                         int pageLen = cfg.vpd[i+3];
113                         if (pageLen == 0) break;
114                         std::copy(
115                                 &cfg.vpd[i],
116                                 &cfg.vpd[i+pageLen+4],
117                                 std::back_inserter(result));
118                         i += pageLen + 4;
119                 }
120                 return result;
121         }
122 }
123
124 BoardConfig
125 ConfigUtil::DefaultBoardConfig()
126 {
127         BoardConfig config;
128         memset(&config, 0, sizeof(config));
129
130         memcpy(config.magic, "BCFG", 4);
131
132
133         // Default to maximum fail-safe options.
134         config.flags = 0;
135         config.flags6 = S2S_CFG_ENABLE_TERMINATOR;
136         config.selectionDelay = 255; // auto
137
138         return config;
139 }
140
141 TargetConfig
142 ConfigUtil::Default(size_t targetIdx)
143 {
144         TargetConfig config;
145         memset(&config, 0, sizeof(config));
146
147         config.scsiId = targetIdx;
148         if (targetIdx == 0)
149         {
150                 config.scsiId = config.scsiId | CONFIG_TARGET_ENABLED;
151         }
152         config.deviceType = CONFIG_FIXED;
153
154         // Default to maximum fail-safe options.
155         config.flagsDEPRECATED = 0;
156         config.deviceTypeModifier = 0;
157         config.sdSectorStart = 0;
158
159         // Default to 2GB. Many systems have trouble with > 2GB disks, and
160         // a few start to complain at 1GB.
161         config.scsiSectors = 4194303; // 2GB - 1 sector
162         config.bytesPerSector = 512;
163         config.sectorsPerTrack = 63;
164         config.headsPerCylinder = 255;
165         memcpy(config.vendor, " codesrc", 8);
166         memcpy(config.prodId, "         SCSI2SD", 16);
167         memcpy(config.revision, " 4.2", 4);
168         memcpy(config.serial, "1234567812345678", 16);
169
170         // Reserved fields, already set to 0
171         // config.reserved
172
173         // not supported yet.
174         // config.vpd
175
176         return config;
177 }
178
179
180 TargetConfig
181 ConfigUtil::fromBytes(const uint8_t* data)
182 {
183         TargetConfig result;
184         memcpy(&result, data, sizeof(TargetConfig));
185         result.sdSectorStart = toLE32(result.sdSectorStart);
186         result.scsiSectors = toLE32(result.scsiSectors);
187         result.bytesPerSector = toLE16(result.bytesPerSector);
188         result.sectorsPerTrack = toLE16(result.sectorsPerTrack);
189         result.headsPerCylinder = toLE16(result.headsPerCylinder);
190         return result;
191 }
192
193
194 std::vector<uint8_t>
195 ConfigUtil::toBytes(const TargetConfig& _config)
196 {
197         TargetConfig config(_config);
198         config.sdSectorStart = fromLE32(config.sdSectorStart);
199         config.scsiSectors = fromLE32(config.scsiSectors);
200         config.bytesPerSector = fromLE16(config.bytesPerSector);
201         config.sectorsPerTrack = fromLE16(config.sectorsPerTrack);
202         config.headsPerCylinder = fromLE16(config.headsPerCylinder);
203
204         const uint8_t* begin = reinterpret_cast<const uint8_t*>(&config);
205         return std::vector<uint8_t>(begin, begin + sizeof(config));
206 }
207
208 BoardConfig
209 ConfigUtil::boardConfigFromBytes(const uint8_t* data)
210 {
211         BoardConfig result;
212         memcpy(&result, data, sizeof(BoardConfig));
213
214         if (memcmp("BCFG", result.magic, 4))
215         {
216                 return DefaultBoardConfig();
217         }
218
219         return result;
220 }
221
222
223 std::vector<uint8_t>
224 ConfigUtil::boardConfigToBytes(const BoardConfig& _config)
225 {
226         BoardConfig config(_config);
227
228         memcpy(config.magic, "BCFG", 4);
229         const uint8_t* begin = reinterpret_cast<const uint8_t*>(&config);
230         return std::vector<uint8_t>(begin, begin + sizeof(config));
231 }
232
233 std::string
234 ConfigUtil::toXML(const TargetConfig& config)
235 {
236         std::stringstream s;
237         std::vector<uint8_t> modePages(getModePages(config));
238         std::vector<uint8_t> vpd(getVPDPages(config));
239
240         s <<
241                 "<SCSITarget id=\"" <<
242                         static_cast<int>(config.scsiId & CONFIG_TARGET_ID_BITS) << "\">\n" <<
243
244                 "       <enabled>" <<
245                         (config.scsiId & CONFIG_TARGET_ENABLED ? "true" : "false") <<
246                         "</enabled>\n" <<
247
248                 "\n" <<
249                 "       <!-- ********************************************************\n" <<
250                 "       Space separated list. Available options:\n" <<
251                 "       apple\t\tReturns Apple-specific mode pages\n" <<
252                 "       omti\t\tOMTI host non-standard link control\n" <<
253                 "       xebec\t\tXEBEC ignore step options in control byte\n" <<
254                 "       vms\t\tVMS output max 254 bytes inquiry data\n" <<
255                 "       ********************************************************* -->\n" <<
256                 "       <quirks>";
257         if (config.quirks == CONFIG_QUIRKS_APPLE)
258         {
259                 s << "apple";
260         }
261         else if (config.quirks == CONFIG_QUIRKS_OMTI)
262         {
263                 s << "omti";
264         }
265         else if (config.quirks == CONFIG_QUIRKS_XEBEC)
266         {
267                 s << "xebec";
268         }
269         else if (config.quirks == CONFIG_QUIRKS_VMS)
270         {
271                 s << "vms";
272         }
273
274         s <<
275                         "</quirks>\n" <<
276
277                 "\n\n" <<
278                 "       <!-- ********************************************************\n" <<
279                 "       0x0    Fixed hard drive.\n" <<
280                 "       0x1    Removable drive.\n" <<
281                 "       0x2    Optical drive  (ie. CD drive).\n" <<
282                 "       0x3    1.44MB Floppy Drive.\n" <<
283                 "       ********************************************************* -->\n" <<
284                 "       <deviceType>0x" <<
285                                 std::hex << static_cast<int>(config.deviceType) <<
286                         "</deviceType>\n" <<
287
288                 "\n\n" <<
289                 "       <!-- ********************************************************\n" <<
290                 "       Device type modifier is usually 0x00. Only change this if your\n" <<
291                 "       OS requires some special value.\n" <<
292                 "\n" <<
293                 "       0x4C    Data General Micropolis disk\n" <<
294                 "       ********************************************************* -->\n" <<
295                 "       <deviceTypeModifier>0x" <<
296                                 std::hex << static_cast<int>(config.deviceTypeModifier) <<
297                         "</deviceTypeModifier>\n" <<
298
299                 "\n\n" <<
300                 "       <!-- ********************************************************\n" <<
301                 "       SD card offset, as a sector number (always 512 bytes).\n" <<
302                 "       ********************************************************* -->\n" <<
303                 "       <sdSectorStart>" << std::dec << config.sdSectorStart << "</sdSectorStart>\n" <<
304                 "\n\n" <<
305                 "       <!-- ********************************************************\n" <<
306                 "       Drive geometry settings.\n" <<
307                 "       ********************************************************* -->\n" <<
308                 "\n"
309                 "       <scsiSectors>" << std::dec << config.scsiSectors << "</scsiSectors>\n" <<
310                 "       <bytesPerSector>" << std::dec << config.bytesPerSector << "</bytesPerSector>\n" <<
311                 "       <sectorsPerTrack>" << std::dec << config.sectorsPerTrack<< "</sectorsPerTrack>\n" <<
312                 "       <headsPerCylinder>" << std::dec << config.headsPerCylinder << "</headsPerCylinder>\n" <<
313                 "\n\n" <<
314                 "       <!-- ********************************************************\n" <<
315                 "       Drive identification information. The SCSI2SD doesn't\n" <<
316                 "       care what these are set to. Use these strings to trick a OS\n" <<
317                 "       thinking a specific hard drive model is attached.\n" <<
318                 "       ********************************************************* -->\n" <<
319                 "\n"
320                 "       <!-- 8 character vendor string -->\n" <<
321                 "       <!-- For Apple HD SC Setup/Drive Setup, use ' SEAGATE' -->\n" <<
322                 "       <vendor>" << std::string(config.vendor, 8) << "</vendor>\n" <<
323                 "\n" <<
324                 "       <!-- 16 character produce identifier -->\n" <<
325                 "       <!-- For Apple HD SC Setup/Drive Setup, use '          ST225N' -->\n" <<
326                 "       <prodId>" << std::string(config.prodId, 16) << "</prodId>\n" <<
327                 "\n" <<
328                 "       <!-- 4 character product revision number -->\n" <<
329                 "       <!-- For Apple HD SC Setup/Drive Setup, use '1.0 ' -->\n" <<
330                 "       <revision>" << std::string(config.revision, 4) << "</revision>\n" <<
331                 "\n" <<
332                 "       <!-- 16 character serial number -->\n" <<
333                 "       <serial>" << std::string(config.serial, 16) << "</serial>\n" <<
334                 "\n" <<
335                 "       <!-- Custom mode pages, base64 encoded, up to 1024 bytes.-->\n" <<
336                 "       <modePages>\n" <<
337                         (modePages.size() == 0 ? "" :
338                                 wxBase64Encode(&modePages[0], modePages.size())) <<
339                                 "\n" <<
340                 "       </modePages>\n" <<
341                 "\n" <<
342                 "       <!-- Custom inquiry VPD pages, base64 encoded, up to 1024 bytes.-->\n" <<
343                 "       <vpd>\n" <<
344                         (vpd.size() == 0 ? "" :
345                                 wxBase64Encode(&vpd[0], vpd.size())) <<
346                                 "\n" <<
347                 "       </vpd>\n" <<
348                 "</SCSITarget>\n";
349
350         return s.str();
351 }
352
353 std::string
354 ConfigUtil::toXML(const BoardConfig& config)
355 {
356         std::stringstream s;
357
358         s << "<BoardConfig>\n" <<
359
360                 "       <!-- ********************************************************\n" <<
361                 "       Enable the onboard active terminator (v5.1 or greater).\n"
362                 "       Both ends of the SCSI chain should be terminated. Disable\n" <<
363                 "       only if the SCSI2SD is in the middle of a chain with other\n" <<
364                 "       devices.\n" <<
365                 "       ********************************************************* -->\n" <<
366                 "       <enableTerminator>" <<
367                         (config.flags6 & S2S_CFG_ENABLE_TERMINATOR ? "true" : "false") <<
368                         "</enableTerminator>\n" <<
369
370                 "       <unitAttention>" <<
371                         (config.flags & CONFIG_ENABLE_UNIT_ATTENTION ? "true" : "false") <<
372                         "</unitAttention>\n" <<
373
374                 "       <parity>" <<
375                         (config.flags & CONFIG_ENABLE_PARITY ? "true" : "false") <<
376                         "</parity>\n" <<
377
378                 "       <!-- ********************************************************\n" <<
379                 "       Only set to true when using with a fast SCSI2 host\n " <<
380                 "       controller. This can cause problems with older/slower\n" <<
381                 "       hardware.\n" <<
382                 "       ********************************************************* -->\n" <<
383                 "       <enableScsi2>" <<
384                         (config.flags & CONFIG_ENABLE_SCSI2 ? "true" : "false") <<
385                         "</enableScsi2>\n" <<
386
387                 "       <!-- ********************************************************\n" <<
388                 "       Setting to 'true' will result in increased performance at the\n" <<
389                 "       cost of lower noise immunity.\n" <<
390                 "       Only set to true when using short cables with only 1 or two\n" <<
391                 "       devices. This should remain off when using external SCSI1 DB25\n" <<
392                 "       cables.\n" <<
393                 "       ********************************************************* -->\n" <<
394                 "       <disableGlitchFilter>" <<
395                         (config.flags & CONFIG_DISABLE_GLITCH ? "true" : "false") <<
396                         "</disableGlitchFilter>\n" <<
397
398                 "       <enableCache>" <<
399                         (config.flags & CONFIG_ENABLE_CACHE ? "true" : "false") <<
400                         "</enableCache>\n" <<
401
402                 "       <enableDisconnect>" <<
403                         (config.flags & CONFIG_ENABLE_DISCONNECT ? "true" : "false") <<
404                         "</enableDisconnect>\n" <<
405
406                 "       <!-- ********************************************************\n" <<
407                 "       Respond to very short duration selection attempts. This supports\n" <<
408                 "       non-standard hardware, but is generally safe to enable.\n" <<
409                 "       Required for Philips P2000C.\n" <<
410                 "       ********************************************************* -->\n" <<
411                 "       <selLatch>" <<
412                         (config.flags & CONFIG_ENABLE_SEL_LATCH? "true" : "false") <<
413                         "</selLatch>\n" <<
414
415
416                 "       <!-- ********************************************************\n" <<
417                 "       Convert luns to IDs. The unit must already be configured to respond\n" <<
418                 "       on the ID. Allows dual drives to be accessed from a \n" <<
419                 "       XEBEC S1410 SASI bridge.\n" <<
420                 "       eg. Configured for dual drives as IDs 0 and 1, but the XEBEC will\n" <<
421                 "       access the second disk as ID0, lun 1.\n" <<
422                 "       See ttp://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf\n" <<
423                 "       ********************************************************* -->\n" <<
424                 "       <mapLunsToIds>" <<
425                         (config.flags & CONFIG_MAP_LUNS_TO_IDS ? "true" : "false") <<
426                         "</mapLunsToIds>\n" <<
427
428                 "       <!-- ********************************************************\n" <<
429                 "       Delay (in milliseconds) before responding to a SCSI selection.\n" <<
430                 "       255 (auto) sets it to 0 for SCSI2 hosts and 1ms otherwise.\n" <<
431                 "       Some samplers need this set to 1 manually.\n" <<
432                 "       ********************************************************* -->\n" <<
433                 "       <selectionDelay>" << static_cast<int>(config.selectionDelay) << "</selectionDelay>\n" <<
434
435                 "       <!-- ********************************************************\n" <<
436                 "       Startup delay (in seconds) before responding to the SCSI bus \n" <<
437                 "       after power on. Default = 0.\n" <<
438                 "       ********************************************************* -->\n" <<
439                 "       <startupDelay>" << static_cast<int>(config.startupDelay) << "</startupDelay>\n" <<
440
441                 "       <!-- ********************************************************\n" <<
442                 "       Speed limit the SCSI interface. This is the -max- speed the \n" <<
443                 "       device will run at. The actual spee depends on the capability\n" <<
444                 "       of the host controller.\n" <<
445                 "       0       No limit\n" <<
446                 "       1       Async 1.5MB/s\n" <<
447                 "       ********************************************************* -->\n" <<
448                 "       <scsiSpeed>" << static_cast<int>(config.scsiSpeed) << "</scsiSpeed>\n" <<
449                 "</BoardConfig>\n";
450
451         return s.str();
452 }
453
454
455 static uint64_t parseInt(wxXmlNode* node, uint64_t limit)
456 {
457         std::string str(node->GetNodeContent().mb_str());
458         if (str.empty())
459         {
460                 throw std::runtime_error("Empty " + node->GetName());
461         }
462
463         std::stringstream s;
464         if (str.find("0x") == 0)
465         {
466                 s << std::hex << str.substr(2);
467         }
468         else
469         {
470                 s << str;
471         }
472
473         uint64_t result;
474         s >> result;
475         if (!s)
476         {
477                 throw std::runtime_error("Invalid value for " + node->GetName());
478         }
479
480         if (result > limit)
481         {
482                 std::stringstream msg;
483                 msg << "Invalid value for " << node->GetName() <<
484                         " (max=" << limit << ")";
485                 throw std::runtime_error(msg.str());
486         }
487         return result;
488 }
489
490 static TargetConfig
491 parseTarget(wxXmlNode* node)
492 {
493         int id;
494         {
495                 std::stringstream s;
496                 s << node->GetAttribute("id", "7");
497                 s >> id;
498                 if (!s) throw std::runtime_error("Could not parse SCSITarget id attr");
499         }
500         TargetConfig result = ConfigUtil::Default(id & 0x7);
501
502         wxXmlNode *child = node->GetChildren();
503         while (child)
504         {
505                 if (child->GetName() == "enabled")
506                 {
507                         std::string s(child->GetNodeContent().mb_str());
508                         if (s == "true")
509                         {
510                                 result.scsiId |= CONFIG_TARGET_ENABLED;
511                         }
512                         else
513                         {
514                                 result.scsiId = result.scsiId & ~CONFIG_TARGET_ENABLED;
515                         }
516                 }
517                 else if (child->GetName() == "quirks")
518                 {
519                         std::stringstream s(std::string(child->GetNodeContent().mb_str()));
520                         std::string quirk;
521                         while (s >> quirk)
522                         {
523                                 if (quirk == "apple")
524                                 {
525                                         result.quirks |= CONFIG_QUIRKS_APPLE;
526                                 }
527                                 else if (quirk == "omti")
528                                 {
529                                         result.quirks |= CONFIG_QUIRKS_OMTI;
530                                 }
531                                 else if (quirk == "xebec")
532                                 {
533                                         result.quirks |= CONFIG_QUIRKS_XEBEC;
534                                 }
535                                 else if (quirk == "vms")
536                                 {
537                                         result.quirks |= CONFIG_QUIRKS_VMS;
538                                 }
539                         }
540                 }
541                 else if (child->GetName() == "deviceType")
542                 {
543                         result.deviceType = parseInt(child, 0xFF);
544                 }
545                 else if (child->GetName() == "deviceTypeModifier")
546                 {
547                         result.deviceTypeModifier = parseInt(child, 0xFF);
548                 }
549                 else if (child->GetName() == "sdSectorStart")
550                 {
551                         result.sdSectorStart = parseInt(child, 0xFFFFFFFF);
552                 }
553                 else if (child->GetName() == "scsiSectors")
554                 {
555                         result.scsiSectors = parseInt(child, 0xFFFFFFFF);
556                 }
557                 else if (child->GetName() == "bytesPerSector")
558                 {
559                         result.bytesPerSector = parseInt(child, 8192);
560                 }
561                 else if (child->GetName() == "sectorsPerTrack")
562                 {
563                         result.sectorsPerTrack = parseInt(child, 255);
564                 }
565                 else if (child->GetName() == "headsPerCylinder")
566                 {
567                         result.headsPerCylinder = parseInt(child, 255);
568                 }
569                 else if (child->GetName() == "vendor")
570                 {
571                         std::string s(child->GetNodeContent().mb_str());
572                         s = s.substr(0, sizeof(result.vendor));
573                         memset(result.vendor, ' ', sizeof(result.vendor));
574                         memcpy(result.vendor, s.c_str(), s.size());
575                 }
576                 else if (child->GetName() == "prodId")
577                 {
578                         std::string s(child->GetNodeContent().mb_str());
579                         s = s.substr(0, sizeof(result.prodId));
580                         memset(result.prodId, ' ', sizeof(result.prodId));
581                         memcpy(result.prodId, s.c_str(), s.size());
582                 }
583                 else if (child->GetName() == "revision")
584                 {
585                         std::string s(child->GetNodeContent().mb_str());
586                         s = s.substr(0, sizeof(result.revision));
587                         memset(result.revision, ' ', sizeof(result.revision));
588                         memcpy(result.revision, s.c_str(), s.size());
589                 }
590                 else if (child->GetName() == "serial")
591                 {
592                         std::string s(child->GetNodeContent().mb_str());
593                         s = s.substr(0, sizeof(result.serial));
594                         memset(result.serial, ' ', sizeof(result.serial));
595                         memcpy(result.serial, s.c_str(), s.size());
596                 }
597                 else if (child->GetName() == "modePages")
598                 {
599                         wxMemoryBuffer buf =
600                                 wxBase64Decode(child->GetNodeContent(), wxBase64DecodeMode_SkipWS);
601                         size_t len = std::min(buf.GetDataLen(), sizeof(result.modePages));
602                         memcpy(result.modePages, buf.GetData(), len);
603                 }
604                 else if (child->GetName() == "vpd")
605                 {
606                         wxMemoryBuffer buf =
607                                 wxBase64Decode(child->GetNodeContent(), wxBase64DecodeMode_SkipWS);
608                         size_t len = std::min(buf.GetDataLen(), sizeof(result.vpd));
609                         memcpy(result.vpd, buf.GetData(), len);
610                 }
611
612
613
614                 child = child->GetNext();
615         }
616         return result;
617 }
618
619 static BoardConfig
620 parseBoardConfig(wxXmlNode* node)
621 {
622         BoardConfig result = ConfigUtil::DefaultBoardConfig();
623
624         wxXmlNode *child = node->GetChildren();
625         while (child)
626         {
627                 if (child->GetName() == "selectionDelay")
628                 {
629                         result.selectionDelay = parseInt(child, 255);
630                 }
631                 else if (child->GetName() == "startupDelay")
632                 {
633                         result.startupDelay = parseInt(child, 255);
634                 }
635                 else if (child->GetName() == "unitAttention")
636                 {
637                         std::string s(child->GetNodeContent().mb_str());
638                         if (s == "true")
639                         {
640                                 result.flags |= CONFIG_ENABLE_UNIT_ATTENTION;
641                         }
642                         else
643                         {
644                                 result.flags = result.flags & ~CONFIG_ENABLE_UNIT_ATTENTION;
645                         }
646                 }
647                 else if (child->GetName() == "parity")
648                 {
649                         std::string s(child->GetNodeContent().mb_str());
650                         if (s == "true")
651                         {
652                                 result.flags |= CONFIG_ENABLE_PARITY;
653                         }
654                         else
655                         {
656                                 result.flags = result.flags & ~CONFIG_ENABLE_PARITY;
657                         }
658                 }
659                 else if (child->GetName() == "enableScsi2")
660                 {
661                         std::string s(child->GetNodeContent().mb_str());
662                         if (s == "true")
663                         {
664                                 result.flags |= CONFIG_ENABLE_SCSI2;
665                         }
666                         else
667                         {
668                                 result.flags = result.flags & ~CONFIG_ENABLE_SCSI2;
669                         }
670                 }
671                 else if (child->GetName() == "disableGlitchFilter")
672                 {
673                         std::string s(child->GetNodeContent().mb_str());
674                         if (s == "true")
675                         {
676                                 result.flags |= CONFIG_DISABLE_GLITCH;
677                         }
678                         else
679                         {
680                                 result.flags = result.flags & ~CONFIG_DISABLE_GLITCH;
681                         }
682                 }
683                 else if (child->GetName() == "enableCache")
684                 {
685                         std::string s(child->GetNodeContent().mb_str());
686                         if (s == "true")
687                         {
688                                 result.flags |= CONFIG_ENABLE_CACHE;
689                         }
690                         else
691                         {
692                                 result.flags = result.flags & ~CONFIG_ENABLE_CACHE;
693                         }
694                 }
695                 else if (child->GetName() == "enableDisconnect")
696                 {
697                         std::string s(child->GetNodeContent().mb_str());
698                         if (s == "true")
699                         {
700                                 result.flags |= CONFIG_ENABLE_DISCONNECT;
701                         }
702                         else
703                         {
704                                 result.flags = result.flags & ~CONFIG_ENABLE_DISCONNECT;
705                         }
706                 }
707                 else if (child->GetName() == "enableTerminator")
708                 {
709                         std::string s(child->GetNodeContent().mb_str());
710                         if (s == "true")
711                         {
712                                 result.flags6 |= S2S_CFG_ENABLE_TERMINATOR;
713                         }
714                         else
715                         {
716                                 result.flags6 = result.flags & ~S2S_CFG_ENABLE_TERMINATOR;
717                         }
718                 }
719                 else if (child->GetName() == "selLatch")
720                 {
721                         std::string s(child->GetNodeContent().mb_str());
722                         if (s == "true")
723                         {
724                                 result.flags |= CONFIG_ENABLE_SEL_LATCH;
725                         }
726                         else
727                         {
728                                 result.flags = result.flags & ~CONFIG_ENABLE_SEL_LATCH;
729                         }
730                 }
731                 else if (child->GetName() == "mapLunsToIds")
732                 {
733                         std::string s(child->GetNodeContent().mb_str());
734                         if (s == "true")
735                         {
736                                 result.flags |= CONFIG_MAP_LUNS_TO_IDS;
737                         }
738                         else
739                         {
740                                 result.flags = result.flags & ~CONFIG_MAP_LUNS_TO_IDS;
741                         }
742                 }
743                 else if (child->GetName() == "scsiSpeed")
744                 {
745                         result.scsiSpeed = parseInt(child, CONFIG_SPEED_ASYNC_15);
746                 }
747                 child = child->GetNext();
748         }
749         return result;
750 }
751
752
753 std::pair<BoardConfig, std::vector<TargetConfig>>
754 ConfigUtil::fromXML(const std::string& filename)
755 {
756         wxXmlDocument doc;
757         if (!doc.Load(filename))
758         {
759                 throw std::runtime_error("Could not load XML file");
760         }
761
762         // start processing the XML file
763         if (doc.GetRoot()->GetName() != "SCSI2SD")
764         {
765                 throw std::runtime_error("Invalid root node, expected <SCSI2SD>");
766         }
767
768         BoardConfig boardConfig = DefaultBoardConfig();
769         int boardConfigFound = 0;
770
771         std::vector<TargetConfig> targets;
772         wxXmlNode *child = doc.GetRoot()->GetChildren();
773         while (child)
774         {
775                 if (child->GetName() == "SCSITarget")
776                 {
777                         targets.push_back(parseTarget(child));
778                 }
779                 else if (child->GetName() == "BoardConfig")
780                 {
781                         boardConfig = parseBoardConfig(child);
782                         boardConfigFound = 1;
783                 }
784                 child = child->GetNext();
785         }
786
787         if (!boardConfigFound && targets.size() > 0)
788         {
789                 boardConfig.flags = targets[0].flagsDEPRECATED;
790         }
791         return make_pair(boardConfig, targets);
792 }
793