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