some missing error handling
[pcsx_rearmed.git] / libpcsxcore / sio.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21 * SIO functions.
22 */
23
24 #include "sio.h"
25 #include <sys/stat.h>
26
27 #ifdef USE_LIBRETRO_VFS
28 #include <streams/file_stream_transforms.h>
29 #endif
30
31 // Status Flags
32 #define TX_RDY          0x0001
33 #define RX_RDY          0x0002
34 #define TX_EMPTY        0x0004
35 #define PARITY_ERR      0x0008
36 #define RX_OVERRUN      0x0010
37 #define FRAMING_ERR     0x0020
38 #define SYNC_DETECT     0x0040
39 #define DSR                     0x0080
40 #define CTS                     0x0100
41 #define IRQ                     0x0200
42
43 // Control Flags
44 #define TX_PERM         0x0001
45 #define DTR                     0x0002
46 #define RX_PERM         0x0004
47 #define BREAK           0x0008
48 #define RESET_ERR       0x0010
49 #define RTS                     0x0020
50 #define SIO_RESET       0x0040
51
52 // *** FOR WORKS ON PADS AND MEMORY CARDS *****
53
54 static unsigned char buf[256];
55 static unsigned char cardh1[4] = { 0xff, 0x08, 0x5a, 0x5d };
56 static unsigned char cardh2[4] = { 0xff, 0x08, 0x5a, 0x5d };
57
58 // Transfer Ready and the Buffer is Empty
59 // static unsigned short StatReg = 0x002b;
60 static unsigned short StatReg = TX_RDY | TX_EMPTY;
61 static unsigned short ModeReg;
62 static unsigned short CtrlReg;
63 static unsigned short BaudReg;
64
65 static unsigned int bufcount;
66 static unsigned int parp;
67 static unsigned int mcdst, rdwr;
68 static unsigned char adrH, adrL;
69 static unsigned int padst;
70
71 char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
72 char McdDisable[2];
73
74 #define SIO_INT(eCycle) { \
75         psxRegs.interrupt |= (1 << PSXINT_SIO); \
76         psxRegs.intCycle[PSXINT_SIO].cycle = eCycle; \
77         psxRegs.intCycle[PSXINT_SIO].sCycle = psxRegs.cycle; \
78         new_dyna_set_event(PSXINT_SIO, eCycle); \
79 }
80
81 // clk cycle byte
82 // 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
83 // TODO: add SioModePrescaler and BaudReg
84 #define SIO_CYCLES              535
85
86 void sioWrite8(unsigned char value) {
87 #ifdef PAD_LOG
88         PAD_LOG("sio write8 %x\n", value);
89 #endif
90         switch (padst) {
91                 case 1: SIO_INT(SIO_CYCLES);
92                         if ((value & 0x40) == 0x40) {
93                                 padst = 2; parp = 1;
94                                 if (!Config.UseNet) {
95                                         switch (CtrlReg & 0x2002) {
96                                                 case 0x0002:
97                                                         buf[parp] = PAD1_poll(value);
98                                                         break;
99                                                 case 0x2002:
100                                                         buf[parp] = PAD2_poll(value);
101                                                         break;
102                                         }
103                                 }/* else {
104 //                                      SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]);
105                                 }*/
106
107                                 if (!(buf[parp] & 0x0f)) {
108                                         bufcount = 2 + 32;
109                                 } else {
110                                         bufcount = 2 + (buf[parp] & 0x0f) * 2;
111                                 }
112                                 if (buf[parp] == 0x41) {
113                                         switch (value) {
114                                                 case 0x43:
115                                                         buf[1] = 0x43;
116                                                         break;
117                                                 case 0x45:
118                                                         buf[1] = 0xf3;
119                                                         break;
120                                         }
121                                 }
122                         }
123                         else padst = 0;
124                         return;
125                 case 2:
126                         parp++;
127 /*                      if (buf[1] == 0x45) {
128                                 buf[parp] = 0;
129                                 SIO_INT(SIO_CYCLES);
130                                 return;
131                         }*/
132                         if (!Config.UseNet) {
133                                 switch (CtrlReg & 0x2002) {
134                                         case 0x0002: buf[parp] = PAD1_poll(value); break;
135                                         case 0x2002: buf[parp] = PAD2_poll(value); break;
136                                 }
137                         }
138
139                         if (parp == bufcount) { padst = 0; return; }
140                         SIO_INT(SIO_CYCLES);
141                         return;
142         }
143
144         switch (mcdst) {
145                 case 1:
146                         SIO_INT(SIO_CYCLES);
147                         if (rdwr) { parp++; return; }
148                         parp = 1;
149                         switch (value) {
150                                 case 0x52: rdwr = 1; break;
151                                 case 0x57: rdwr = 2; break;
152                                 default: mcdst = 0;
153                         }
154                         return;
155                 case 2: // address H
156                         SIO_INT(SIO_CYCLES);
157                         adrH = value;
158                         *buf = 0;
159                         parp = 0;
160                         bufcount = 1;
161                         mcdst = 3;
162                         return;
163                 case 3: // address L
164                         SIO_INT(SIO_CYCLES);
165                         adrL = value;
166                         *buf = adrH;
167                         parp = 0;
168                         bufcount = 1;
169                         mcdst = 4;
170                         return;
171                 case 4:
172                         SIO_INT(SIO_CYCLES);
173                         parp = 0;
174                         switch (rdwr) {
175                                 case 1: // read
176                                         buf[0] = 0x5c;
177                                         buf[1] = 0x5d;
178                                         buf[2] = adrH;
179                                         buf[3] = adrL;
180                                         switch (CtrlReg & 0x2002) {
181                                                 case 0x0002:
182                                                         memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
183                                                         break;
184                                                 case 0x2002:
185                                                         memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
186                                                         break;
187                                         }
188                                         {
189                                         char xor = 0;
190                                         int i;
191                                         for (i = 2; i < 128 + 4; i++)
192                                                 xor ^= buf[i];
193                                         buf[132] = xor;
194                                         }
195                                         buf[133] = 0x47;
196                                         bufcount = 133;
197                                         break;
198                                 case 2: // write
199                                         buf[0] = adrL;
200                                         buf[1] = value;
201                                         buf[129] = 0x5c;
202                                         buf[130] = 0x5d;
203                                         buf[131] = 0x47;
204                                         bufcount = 131;
205                                         break;
206                         }
207                         mcdst = 5;
208                         return;
209                 case 5:
210                         parp++;
211                         if ((rdwr == 1 && parp == 132) ||
212                             (rdwr == 2 && parp == 129)) {
213                                 // clear "new card" flags
214                                 if (CtrlReg & 0x2000)
215                                         cardh2[1] &= ~8;
216                                 else
217                                         cardh1[1] &= ~8;
218                         }
219                         if (rdwr == 2) {
220                                 if (parp < 128) buf[parp + 1] = value;
221                         }
222                         SIO_INT(SIO_CYCLES);
223                         return;
224         }
225
226         switch (value) {
227                 case 0x01: // start pad
228                         StatReg |= RX_RDY;              // Transfer is Ready
229
230                         if (!Config.UseNet) {
231                                 switch (CtrlReg & 0x2002) {
232                                         case 0x0002: buf[0] = PAD1_startPoll(1); break;
233                                         case 0x2002: buf[0] = PAD2_startPoll(2); break;
234                                 }
235                         } else {
236                                 if ((CtrlReg & 0x2002) == 0x0002) {
237                                         int i, j;
238
239                                         PAD1_startPoll(1);
240                                         buf[0] = 0;
241                                         buf[1] = PAD1_poll(0x42);
242                                         if (!(buf[1] & 0x0f)) {
243                                                 bufcount = 32;
244                                         } else {
245                                                 bufcount = (buf[1] & 0x0f) * 2;
246                                         }
247                                         buf[2] = PAD1_poll(0);
248                                         i = 3;
249                                         j = bufcount;
250                                         while (j--) {
251                                                 buf[i++] = PAD1_poll(0);
252                                         }
253                                         bufcount+= 3;
254
255                                         if (NET_sendPadData(buf, bufcount) == -1)
256                                                 netError();
257
258                                         if (NET_recvPadData(buf, 1) == -1)
259                                                 netError();
260                                         if (NET_recvPadData(buf + 128, 2) == -1)
261                                                 netError();
262                                 } else {
263                                         memcpy(buf, buf + 128, 32);
264                                 }
265                         }
266
267                         bufcount = 2;
268                         parp = 0;
269                         padst = 1;
270                         SIO_INT(SIO_CYCLES);
271                         return;
272                 case 0x81: // start memcard
273                         if (CtrlReg & 0x2000)
274                         {
275                                 if (McdDisable[1])
276                                         goto no_device;
277                                 memcpy(buf, cardh2, 4);
278                         }
279                         else
280                         {
281                                 if (McdDisable[0])
282                                         goto no_device;
283                                 memcpy(buf, cardh1, 4);
284                         }
285                         StatReg |= RX_RDY;
286                         parp = 0;
287                         bufcount = 3;
288                         mcdst = 1;
289                         rdwr = 0;
290                         SIO_INT(SIO_CYCLES);
291                         return;
292                 default:
293                 no_device:
294                         StatReg |= RX_RDY;
295                         buf[0] = 0xff;
296                         parp = 0;
297                         bufcount = 0;
298                         return;
299         }
300 }
301
302 void sioWriteStat16(unsigned short value) {
303 }
304
305 void sioWriteMode16(unsigned short value) {
306         ModeReg = value;
307 }
308
309 void sioWriteCtrl16(unsigned short value) {
310         CtrlReg = value & ~RESET_ERR;
311         if (value & RESET_ERR) StatReg &= ~IRQ;
312         if ((CtrlReg & SIO_RESET) || !(CtrlReg & DTR)) {
313                 padst = 0; mcdst = 0; parp = 0;
314                 StatReg = TX_RDY | TX_EMPTY;
315                 psxRegs.interrupt &= ~(1 << PSXINT_SIO);
316         }
317 }
318
319 void sioWriteBaud16(unsigned short value) {
320         BaudReg = value;
321 }
322
323 unsigned char sioRead8() {
324         unsigned char ret = 0;
325
326         if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
327 //              StatReg &= ~RX_OVERRUN;
328                 ret = buf[parp];
329                 if (parp == bufcount) {
330                         StatReg &= ~RX_RDY;             // Receive is not Ready now
331                         if (mcdst == 5) {
332                                 mcdst = 0;
333                                 if (rdwr == 2) {
334                                         switch (CtrlReg & 0x2002) {
335                                                 case 0x0002:
336                                                         memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
337                                                         SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
338                                                         break;
339                                                 case 0x2002:
340                                                         memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
341                                                         SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
342                                                         break;
343                                         }
344                                 }
345                         }
346                         if (padst == 2) padst = 0;
347                         if (mcdst == 1) {
348                                 mcdst = 2;
349                                 StatReg|= RX_RDY;
350                         }
351                 }
352         }
353
354 #ifdef PAD_LOG
355         PAD_LOG("sio read8 ;ret = %x\n", ret);
356 #endif
357         return ret;
358 }
359
360 unsigned short sioReadStat16() {
361         return StatReg;
362 }
363
364 unsigned short sioReadMode16() {
365         return ModeReg;
366 }
367
368 unsigned short sioReadCtrl16() {
369         return CtrlReg;
370 }
371
372 unsigned short sioReadBaud16() {
373         return BaudReg;
374 }
375
376 void netError() {
377         ClosePlugins();
378         SysMessage(_("Connection closed!\n"));
379
380         CdromId[0] = '\0';
381         CdromLabel[0] = '\0';
382
383         SysRunGui();
384 }
385
386 void sioInterrupt() {
387 #ifdef PAD_LOG
388         PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
389 #endif
390 //      SysPrintf("Sio Interrupt\n");
391         if (!(StatReg & IRQ)) {
392                 StatReg |= IRQ;
393                 psxHu32ref(0x1070) |= SWAPu32(0x80);
394         }
395 }
396
397 void LoadMcd(int mcd, char *str) {
398         FILE *f;
399         char *data = NULL;
400
401         if (mcd != 1 && mcd != 2)
402                 return;
403
404         if (mcd == 1) {
405                 data = Mcd1Data;
406                 cardh1[1] |= 8; // mark as new
407         }
408         if (mcd == 2) {
409                 data = Mcd2Data;
410                 cardh2[1] |= 8;
411         }
412
413         McdDisable[mcd - 1] = 0;
414 #ifdef HAVE_LIBRETRO
415         // memcard1 is handled by libretro
416         if (mcd == 1)
417                 return;
418 #endif
419
420         if (str == NULL || strcmp(str, "none") == 0) {
421                 McdDisable[mcd - 1] = 1;
422                 return;
423         }
424         if (*str == 0)
425                 return;
426
427         f = fopen(str, "rb");
428         if (f == NULL) {
429                 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
430                 CreateMcd(str);
431                 f = fopen(str, "rb");
432                 if (f != NULL) {
433                         struct stat buf;
434
435                         if (stat(str, &buf) != -1) {
436                                 if (buf.st_size == MCD_SIZE + 64)
437                                         fseek(f, 64, SEEK_SET);
438                                 else if(buf.st_size == MCD_SIZE + 3904)
439                                         fseek(f, 3904, SEEK_SET);
440                         }
441                         if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
442 #ifndef NDEBUG
443                                 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
444 #endif
445                                 memset(data, 0x00, MCD_SIZE);
446                         }
447                         fclose(f);
448                 }
449                 else
450                         SysMessage(_("Memory card %s failed to load!\n"), str);
451         }
452         else {
453                 struct stat buf;
454                 SysPrintf(_("Loading memory card %s\n"), str);
455                 if (stat(str, &buf) != -1) {
456                         if (buf.st_size == MCD_SIZE + 64)
457                                 fseek(f, 64, SEEK_SET);
458                         else if(buf.st_size == MCD_SIZE + 3904)
459                                 fseek(f, 3904, SEEK_SET);
460                 }
461                 if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
462 #ifndef NDEBUG
463                         SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
464 #endif
465                         memset(data, 0x00, MCD_SIZE);
466                 }
467                 fclose(f);
468         }
469 }
470
471 void LoadMcds(char *mcd1, char *mcd2) {
472         LoadMcd(1, mcd1);
473         LoadMcd(2, mcd2);
474 }
475
476 void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
477         FILE *f;
478
479         if (mcd == NULL || *mcd == 0 || strcmp(mcd, "none") == 0)
480                 return;
481
482         f = fopen(mcd, "r+b");
483         if (f != NULL) {
484                 struct stat buf;
485
486                 if (stat(mcd, &buf) != -1) {
487                         if (buf.st_size == MCD_SIZE + 64)
488                                 fseek(f, adr + 64, SEEK_SET);
489                         else if (buf.st_size == MCD_SIZE + 3904)
490                                 fseek(f, adr + 3904, SEEK_SET);
491                         else
492                                 fseek(f, adr, SEEK_SET);
493                 } else
494                         fseek(f, adr, SEEK_SET);
495
496                 fwrite(data + adr, 1, size, f);
497                 fclose(f);
498                 return;
499         }
500
501 #if 0
502         // try to create it again if we can't open it
503         f = fopen(mcd, "wb");
504         if (f != NULL) {
505                 fwrite(data, 1, MCD_SIZE, f);
506                 fclose(f);
507         }
508 #endif
509
510         ConvertMcd(mcd, data);
511 }
512
513 void CreateMcd(char *mcd) {
514         FILE *f;
515         struct stat buf;
516         int s = MCD_SIZE;
517         int i = 0, j;
518
519         f = fopen(mcd, "wb");
520         if (f == NULL)
521                 return;
522
523         if (stat(mcd, &buf) != -1) {
524                 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
525                         s = s + 3904;
526                         fputc('1', f);
527                         s--;
528                         fputc('2', f);
529                         s--;
530                         fputc('3', f);
531                         s--;
532                         fputc('-', f);
533                         s--;
534                         fputc('4', f);
535                         s--;
536                         fputc('5', f);
537                         s--;
538                         fputc('6', f);
539                         s--;
540                         fputc('-', f);
541                         s--;
542                         fputc('S', f);
543                         s--;
544                         fputc('T', f);
545                         s--;
546                         fputc('D', f);
547                         s--;
548                         for (i = 0; i < 7; i++) {
549                                 fputc(0, f);
550                                 s--;
551                         }
552                         fputc(1, f);
553                         s--;
554                         fputc(0, f);
555                         s--;
556                         fputc(1, f);
557                         s--;
558                         fputc('M', f);
559                         s--;
560                         fputc('Q', f);
561                         s--;
562                         for (i = 0; i < 14; i++) {
563                                 fputc(0xa0, f);
564                                 s--;
565                         }
566                         fputc(0, f);
567                         s--;
568                         fputc(0xff, f);
569                         while (s-- > (MCD_SIZE + 1))
570                                 fputc(0, f);
571                 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
572                         s = s + 64;
573                         fputc('V', f);
574                         s--;
575                         fputc('g', f);
576                         s--;
577                         fputc('s', f);
578                         s--;
579                         fputc('M', f);
580                         s--;
581                         for (i = 0; i < 3; i++) {
582                                 fputc(1, f);
583                                 s--;
584                                 fputc(0, f);
585                                 s--;
586                                 fputc(0, f);
587                                 s--;
588                                 fputc(0, f);
589                                 s--;
590                         }
591                         fputc(0, f);
592                         s--;
593                         fputc(2, f);
594                         while (s-- > (MCD_SIZE + 1))
595                                 fputc(0, f);
596                 }
597         }
598         fputc('M', f);
599         s--;
600         fputc('C', f);
601         s--;
602         while (s-- > (MCD_SIZE - 127))
603                 fputc(0, f);
604         fputc(0xe, f);
605         s--;
606
607         for (i = 0; i < 15; i++) { // 15 blocks
608                 fputc(0xa0, f);
609                 s--;
610                 fputc(0x00, f);
611                 s--;
612                 fputc(0x00, f);
613                 s--;
614                 fputc(0x00, f);
615                 s--;
616                 fputc(0x00, f);
617                 s--;
618                 fputc(0x00, f);
619                 s--;
620                 fputc(0x00, f);
621                 s--;
622                 fputc(0x00, f);
623                 s--;
624                 fputc(0xff, f);
625                 s--;
626                 fputc(0xff, f);
627                 s--;
628                 for (j = 0; j < 117; j++) {
629                         fputc(0x00, f);
630                         s--;
631                 }
632                 fputc(0xa0, f);
633                 s--;
634         }
635
636         for (i = 0; i < 20; i++) {
637                 fputc(0xff, f);
638                 s--;
639                 fputc(0xff, f);
640                 s--;
641                 fputc(0xff, f);
642                 s--;
643                 fputc(0xff, f);
644                 s--;
645                 fputc(0x00, f);
646                 s--;
647                 fputc(0x00, f);
648                 s--;
649                 fputc(0x00, f);
650                 s--;
651                 fputc(0x00, f);
652                 s--;
653                 fputc(0xff, f);
654                 s--;
655                 fputc(0xff, f);
656                 s--;
657                 for (j = 0; j < 118; j++) {
658                         fputc(0x00, f);
659                         s--;
660                 }
661         }
662
663         while ((s--) >= 0)
664                 fputc(0, f);
665
666         fclose(f);
667 }
668
669 void ConvertMcd(char *mcd, char *data) {
670         FILE *f;
671         int i = 0;
672         int s = MCD_SIZE;
673
674         if (strstr(mcd, ".gme")) {
675                 f = fopen(mcd, "wb");
676                 if (f != NULL) {
677                         fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
678                         fclose(f);
679                 }
680                 f = fopen(mcd, "r+");
681                 if (f == NULL) return;
682                 s = s + 3904;
683                 fputc('1', f); s--;
684                 fputc('2', f); s--;
685                 fputc('3', f); s--;
686                 fputc('-', f); s--;
687                 fputc('4', f); s--;
688                 fputc('5', f); s--;
689                 fputc('6', f); s--;
690                 fputc('-', f); s--;
691                 fputc('S', f); s--;
692                 fputc('T', f); s--;
693                 fputc('D', f); s--;
694                 for (i = 0; i < 7; i++) {
695                         fputc(0, f); s--;
696                 }
697                 fputc(1, f); s--;
698                 fputc(0, f); s--;
699                 fputc(1, f); s--;
700                 fputc('M', f); s--;
701                 fputc('Q', f); s--;
702                 for(i=0;i<14;i++) {
703                         fputc(0xa0, f); s--;
704                 }
705                 fputc(0, f); s--;
706                 fputc(0xff, f);
707                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
708                 fclose(f);
709         } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
710                 f = fopen(mcd, "wb");
711                 if (f != NULL) {
712                         fwrite(data-64, 1, MCD_SIZE+64, f);
713                         fclose(f);
714                 }
715                 f = fopen(mcd, "r+");
716                 if (f == NULL) return;
717                 s = s + 64;
718                 fputc('V', f); s--;
719                 fputc('g', f); s--;
720                 fputc('s', f); s--;
721                 fputc('M', f); s--;
722                 for(i=0;i<3;i++) {
723                         fputc(1, f); s--;
724                         fputc(0, f); s--;
725                         fputc(0, f); s--;
726                         fputc(0, f); s--;
727                 }
728                 fputc(0, f); s--;
729                 fputc(2, f);
730                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
731                 fclose(f);
732         } else {
733                 f = fopen(mcd, "wb");
734                 if (f != NULL) {
735                         fwrite(data, 1, MCD_SIZE, f);
736                         fclose(f);
737                 }
738         }
739 }
740
741 void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
742         char *data = NULL, *ptr, *str, *sstr;
743         unsigned short clut[16];
744         unsigned short c;
745         int i, x;
746
747         memset(Info, 0, sizeof(McdBlock));
748
749         if (mcd != 1 && mcd != 2)
750                 return;
751
752         if (McdDisable[mcd - 1])
753                 return;
754
755         if (mcd == 1) data = Mcd1Data;
756         if (mcd == 2) data = Mcd2Data;
757
758         ptr = data + block * 8192 + 2;
759
760         Info->IconCount = *ptr & 0x3;
761
762         ptr += 2;
763
764         x = 0;
765
766         str = Info->Title;
767         sstr = Info->sTitle;
768
769         for (i = 0; i < 48; i++) {
770                 c = *(ptr) << 8;
771                 c |= *(ptr + 1);
772                 if (!c) break;
773
774                 // Convert ASCII characters to half-width
775                 if (c >= 0x8281 && c <= 0x829A)
776                         c = (c - 0x8281) + 'a';
777                 else if (c >= 0x824F && c <= 0x827A)
778                         c = (c - 0x824F) + '0';
779                 else if (c == 0x8140) c = ' ';
780                 else if (c == 0x8143) c = ',';
781                 else if (c == 0x8144) c = '.';
782                 else if (c == 0x8146) c = ':';
783                 else if (c == 0x8147) c = ';';
784                 else if (c == 0x8148) c = '?';
785                 else if (c == 0x8149) c = '!';
786                 else if (c == 0x815E) c = '/';
787                 else if (c == 0x8168) c = '"';
788                 else if (c == 0x8169) c = '(';
789                 else if (c == 0x816A) c = ')';
790                 else if (c == 0x816D) c = '[';
791                 else if (c == 0x816E) c = ']';
792                 else if (c == 0x817C) c = '-';
793                 else {
794                         str[i] = ' ';
795                         sstr[x++] = *ptr++; sstr[x++] = *ptr++;
796                         continue;
797                 }
798
799                 str[i] = sstr[x++] = c;
800                 ptr += 2;
801         }
802
803         trim(str);
804         trim(sstr);
805
806         ptr = data + block * 8192 + 0x60; // icon palette data
807
808         for (i = 0; i < 16; i++) {
809                 clut[i] = *((unsigned short *)ptr);
810                 ptr += 2;
811         }
812
813         for (i = 0; i < Info->IconCount; i++) {
814                 short *icon = &Info->Icon[i * 16 * 16];
815
816                 ptr = data + block * 8192 + 128 + 128 * i; // icon data
817
818                 for (x = 0; x < 16 * 16; x++) {
819                         icon[x++] = clut[*ptr & 0xf];
820                         icon[x] = clut[*ptr >> 4];
821                         ptr++;
822                 }
823         }
824
825         ptr = data + block * 128;
826
827         Info->Flags = *ptr;
828
829         ptr += 0xa;
830         strncpy(Info->ID, ptr, 12);
831         ptr += 12;
832         strncpy(Info->Name, ptr, 16);
833 }
834
835 int sioFreeze(void *f, int Mode) {
836         gzfreeze(buf, sizeof(buf));
837         gzfreeze(&StatReg, sizeof(StatReg));
838         gzfreeze(&ModeReg, sizeof(ModeReg));
839         gzfreeze(&CtrlReg, sizeof(CtrlReg));
840         gzfreeze(&BaudReg, sizeof(BaudReg));
841         gzfreeze(&bufcount, sizeof(bufcount));
842         gzfreeze(&parp, sizeof(parp));
843         gzfreeze(&mcdst, sizeof(mcdst));
844         gzfreeze(&rdwr, sizeof(rdwr));
845         gzfreeze(&adrH, sizeof(adrH));
846         gzfreeze(&adrL, sizeof(adrL));
847         gzfreeze(&padst, sizeof(padst));
848
849         return 0;
850 }