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