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