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