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