1 /*
2 pl.c - Pocket Linker support for uCON64
3 
4 Copyright (c) 2004                                           Walter van Niftrik <w.f.b.w.v.niftrik@stud.tue.nl>
5 Partly based on PokeLink - Copyright (c)                     Dark Fader / BlackThunder
6 Portions copyright (c) 2004 - 2005, 2015 - 2017, 2020 - 2021 dbjh
7 
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #ifdef  HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #ifdef  _MSC_VER
27 #pragma warning(push)
28 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
29 #endif
30 #include <stdlib.h>
31 #ifdef  _MSC_VER
32 #pragma warning(pop)
33 #endif
34 #include <string.h>
35 #include "misc/archive.h"
36 #include "ucon64.h"
37 #include "ucon64_misc.h"
38 #include "backup/pl.h"
39 
40 
41 #ifdef  USE_PARALLEL
42 static st_ucon64_obj_t pl_obj[] =
43   {
44     {UCON64_NGP, WF_DEFAULT | WF_STOP | WF_NO_ROM},
45     {UCON64_NGP, WF_STOP | WF_NO_ROM},
46     {UCON64_NGP, WF_SWITCH}
47   };
48 #endif
49 
50 const st_getopt2_t pl_usage[] =
51   {
52     {
53       NULL, 0, 0, 0,
54       NULL, "Pocket Linker"/*"19XX Bung Enterprises Ltd"*/,
55       NULL
56     },
57 #ifdef  USE_PARALLEL
58     {
59       "xpl", 0, 0, UCON64_XPL,
60       NULL, "send/receive ROM to/from Pocket Linker; " OPTION_LONG_S "port" OPTARG_S "PORT\n"
61       "receives automatically when ROM does not exist",
62       &pl_obj[0]
63     },
64     {
65       "xpli", 0, 0, UCON64_XPLI,
66       NULL, "show information about inserted cartridge; " OPTION_LONG_S "port" OPTARG_S "PORT",
67       &pl_obj[1]
68     },
69     {
70       "xplm", 0, 0, UCON64_XPLM,
71       NULL, "use SPP mode, default is EPP mode",
72       &pl_obj[2]
73     },
74 #endif // USE_PARALLEL
75     {NULL, 0, 0, 0, NULL, NULL, NULL}
76   };
77 
78 
79 #ifdef  USE_PARALLEL
80 
81 // flash unlock addresses with chip select
82 #define fx0002aa(A) (((A) & 0x200000) | 0x0002aa)
83 #define fx000555(A) (((A) & 0x200000) | 0x000555)
84 #define fx000aaa(A) (((A) & 0x200000) | 0x000aaa)
85 #define fx002aaa(A) (((A) & 0x200000) | 0x002aaa)
86 #define fx005555(A) (((A) & 0x200000) | 0x005555)
87 
88 #define set_data_read outportb (port_a, 0);
89 #define set_data_write outportb (port_a, 1);
90 #define reset_port outportb (port_a, 4);
91 
92 #define CMD_READ       0xf0
93 #define CMD_INFO       0x90
94 #define CMD_ERASE      0x80
95 
96 #define TYPE_BW        0x00
97 #define TYPE_COLOR     0x01
98 #define TYPE_MULTI     0x02
99 
100 static unsigned short port_8, port_9, port_a, port_b, port_c;
101 static int current_ai;
102 static unsigned char ai_value[4];
103 
104 
105 static void
epp_write_data(unsigned char data)106 epp_write_data (unsigned char data)
107 {
108   outportb (port_c, data);
109 }
110 
111 
112 static void
spp_write_data(unsigned char data)113 spp_write_data (unsigned char data)
114 {
115   outportb (port_8, data);
116   outportb (port_a, 3);
117   outportb (port_a, 1);
118 }
119 
120 
121 static void
write_data(unsigned char data)122 write_data (unsigned char data)
123 {
124   ai_value[current_ai] = data;
125   if (ucon64.parport_mode != PPMODE_EPP)
126     spp_write_data (data);
127   else
128     epp_write_data (data);
129 }
130 
131 
132 static unsigned char
epp_read_data(void)133 epp_read_data (void)
134 {
135   return inportb (port_c);
136 }
137 
138 
139 static unsigned char
spp_read_data(void)140 spp_read_data (void)
141 {
142   unsigned char byte;
143 
144   outportb (port_a, 2);
145   byte = (inportb (port_9) >> 3) & 0x0f;
146   outportb (port_a, 6);
147   byte |= (inportb (port_9) << 1) & 0xf0;
148   outportb (port_a, 0);
149 
150   return byte;
151 }
152 
153 
154 static unsigned char
read_data(void)155 read_data (void)
156 {
157   if (ucon64.parport_mode != PPMODE_EPP)
158     return spp_read_data ();
159   else
160     return epp_read_data ();
161 }
162 
163 
164 static void
epp_set_ai(unsigned char ai)165 epp_set_ai (unsigned char ai)
166 {
167   current_ai = ai;
168   outportb (port_b, ai);
169 }
170 
171 
172 static void
spp_set_ai(unsigned char ai)173 spp_set_ai (unsigned char ai)
174 {
175   current_ai = ai;
176   outportb (port_8, ai);
177   outportb (port_a, 9);
178   outportb (port_a, 1);
179 }
180 
181 
182 static void
set_ai(unsigned char ai)183 set_ai (unsigned char ai)
184 {
185   if (ucon64.parport_mode != PPMODE_EPP)
186     spp_set_ai (ai);
187   else
188     epp_set_ai (ai);
189 }
190 
191 
192 static void
epp_set_ai_data(unsigned char ai,unsigned char data)193 epp_set_ai_data (unsigned char ai, unsigned char data)
194 {
195   epp_set_ai (ai);
196   epp_write_data (data);
197 }
198 
199 
200 static void
spp_set_ai_data(unsigned char ai,unsigned char data)201 spp_set_ai_data (unsigned char ai, unsigned char data)
202 {
203   spp_set_ai (ai);
204   spp_write_data (data);
205 }
206 
207 
208 static void
set_ai_data(unsigned char ai,unsigned char data)209 set_ai_data (unsigned char ai, unsigned char data)
210 {
211   if (ucon64.parport_mode != PPMODE_EPP)
212     spp_set_ai_data (ai, data);
213   else
214     epp_set_ai_data (ai, data);
215 }
216 
217 
218 static void
init_port(void)219 init_port (void)
220 {
221   parport_reset_timeout (port_8);
222   set_data_write
223   set_ai_data (2, 0);
224 }
225 
226 
227 static void
end_port(void)228 end_port (void)
229 {
230   set_data_write
231   set_ai_data (2, 0);
232   reset_port
233 }
234 
235 
236 static int
detect_linker(void)237 detect_linker (void)
238 {
239   init_port ();
240   set_data_write
241   set_ai_data (1, 0x12);
242   set_ai_data (0, 0x34);
243   set_ai (1);
244   set_data_read
245   if (read_data () != 0x12)
246     return 0;
247   set_data_write
248   set_ai (0);
249   set_data_read
250   if (read_data () != 0x34)
251     return 0;
252   end_port ();
253   return 1;
254 }
255 
256 
257 static void
select_address(unsigned int addr,int inc)258 select_address (unsigned int addr, int inc)
259 {
260   unsigned char data = (((addr >> 14) & 0x3c) | ((addr >> 13) & 0x80) |
261                         (inc ? 0x01 : 0x00));   // a[20..16], auto-increment
262 
263   if (data != ai_value[2])
264     set_ai_data (2, data);
265   set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
266   set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
267 }
268 
269 
270 static void
write_address_data(unsigned int addr,unsigned char data)271 write_address_data (unsigned int addr, unsigned char data)
272 {
273   select_address (addr, 0);
274   set_ai_data (3, data);
275 }
276 
277 
278 static void
send_command(unsigned char cmd)279 send_command (unsigned char cmd)
280 {
281   set_data_write
282   write_address_data (0x5555, 0xaa);
283   write_address_data (0x2aaa, 0x55);
284   write_address_data (0x5555, cmd);
285 }
286 
287 
288 static void
reset_read(void)289 reset_read (void)
290 {
291   send_command (CMD_READ);
292 }
293 
294 
295 static unsigned char
read_ai3_data(void)296 read_ai3_data (void)
297 {
298   set_ai (3);
299   set_data_read
300   return read_data ();
301 }
302 
303 
304 static int
detect_chip(void)305 detect_chip (void)
306 {
307   int ai;
308   unsigned char info[4];
309 
310   reset_read ();
311   reset_read ();
312   reset_read ();
313   send_command (CMD_INFO);
314   for (ai = 0; ai < 4; ai++)
315     {
316       set_data_write
317       select_address (ai, 0);
318       info[ai] = read_ai3_data ();
319     }
320   reset_read ();
321   if (((info[0] & 0x90) == 0x90) && (info[2] == 0x01) && (info[3] & 0x80))
322     return 1;
323   else
324     return 0;
325 }
326 
327 
328 static void
select_chip(unsigned int addr)329 select_chip (unsigned int addr)
330 {
331   set_data_write
332   set_ai_data (2, 2);
333   set_ai_data (3, (unsigned char) ((addr & 0x200000) ? 1 : 2));
334   set_ai_data (2, 0);
335 }
336 
337 
338 static unsigned int
cart_size(void)339 cart_size (void)
340 {
341   select_chip (0x000000);
342   if (!detect_chip ())
343     return 0;                                   // no cartridge found
344   select_chip (0x200000);
345   if (!detect_chip ())
346     return 0x200000;                            // 16 megabit
347   return 0x400000;                              // 32 megabit
348 }
349 
350 
351 static void
read_blocks(unsigned int addr,unsigned char * buf,int blocks)352 read_blocks (unsigned int addr, unsigned char *buf, int blocks)
353 {
354   int block, i, offset = 0;
355 
356   select_chip (addr);
357   for (block = 0; block < blocks; block++)
358     {
359       set_data_write
360       select_address (addr | (block << 8), 1);
361       set_ai (3);
362       set_data_read
363       for (i = 0; i < 0x100; i++)
364         buf[offset++] = read_data ();
365     }
366 }
367 
368 
369 static int
is_erased(unsigned char * buf,unsigned int len)370 is_erased (unsigned char *buf, unsigned int len)
371 {
372   unsigned int i;
373 
374   for (i = 0; i < len; i++)
375     if (buf[i] != 0xff)
376       return 0;
377 
378   return 1;
379 }
380 
381 
382 static int
is_header(unsigned char * buf)383 is_header (unsigned char *buf)
384 {
385   char msg[0x1d];
386 
387 #if     defined __GNUC__ && __GNUC__ >= 8
388 #pragma GCC diagnostic push
389 #pragma GCC diagnostic ignored "-Wstringop-truncation"
390 #endif
391   strncpy (msg, (char *) buf, 0x1c)[0x1c] = '\0';
392 #if     defined __GNUC__ && __GNUC__ >= 8
393 #pragma GCC diagnostic pop
394 #endif
395   if (strstr (msg, "COPYRIGHT") || strstr (msg, "SNK") ||
396       strstr (msg, "LICENSED") || strstr (msg, "CORPORATION"))
397     return 1;                                   // header found
398 
399   return 0;                                     // other data found
400 }
401 
402 
403 static int
same_header(unsigned char * header,unsigned char * buf)404 same_header (unsigned char *header, unsigned char *buf)
405 {
406   return (!memcmp (header, buf, 0x100));
407 }
408 
409 
410 static unsigned int
game_info(unsigned int cart_size,char name[13],int * type)411 game_info (unsigned int cart_size, char name[13], int *type)
412 {
413   unsigned char header[0x100], buf[0x8000];
414 
415   select_chip (0x000000);
416   read_blocks (0x000000, header, 1);
417 
418   if (!is_header (header))
419     return 0;                                   // no game found
420 
421   if (name)
422 #if     defined __GNUC__ && __GNUC__ >= 8
423 #pragma GCC diagnostic push
424 #pragma GCC diagnostic ignored "-Wstringop-truncation"
425 #endif
426     strncpy (name, (char *) (header + 0x24), 12)[12] = '\0';
427 #if     defined __GNUC__ && __GNUC__ >= 8
428 #pragma GCC diagnostic pop
429 #endif
430 
431   if (type)
432     {
433       if (name && strstr (name, "Multi"))
434         *type = TYPE_MULTI;
435       else if (header[0x23] == 0x10)
436         *type = TYPE_COLOR;
437       else
438         *type = TYPE_BW;
439     }
440 
441   read_blocks (0x080000, buf, 128);
442   if ((same_header (buf, header)) || is_erased (buf, 0x8000))
443     return 0x080000;                            // 4 megabit
444 
445   read_blocks (0x100000, buf, 128);
446   if ((same_header (buf, header)) || is_erased (buf, 0x8000))
447     return 0x100000;                            // 8 megabit
448 
449   if (cart_size == 0x400000)
450     {
451       read_blocks (0x200000, buf, 128);
452       if (is_erased (buf, 0x8000))
453         return 0x200000;                        // 16 megabit
454       return 0x400000;                          // 32 megabit
455     }
456   return 0x200000;                              // 16 megabit
457 }
458 
459 
460 static void
deinit_io(void)461 deinit_io (void)
462 {
463   end_port ();
464 }
465 
466 
467 static void
init_io(unsigned short port)468 init_io (unsigned short port)
469 {
470   port_8 = port;
471   port_9 = port + 1;
472   port_a = port + 2;
473   port_b = port + 3;
474   port_c = port + 4;
475 
476   parport_print_info ();
477 
478   if (!detect_linker ())
479     {
480       ucon64.parport_mode = parport_setup (port_8, PPMODE_SPP);
481       if (!detect_linker ())
482         {
483           fputs ("ERROR: Pocket Linker not found or not turned on\n", stderr);
484           deinit_io ();
485           exit (1);
486         }
487     }
488 
489   // If we get here, a Pocket Linker was detected
490   if (ucon64.parport_mode == PPMODE_EPP)
491     puts ("Pocket Linker found. EPP found");
492   else
493     puts ("Pocket Linker found. EPP not found or not enabled - SPP used");
494 }
495 
496 
497 static void
set_address(unsigned int addr,int inc)498 set_address (unsigned int addr, int inc)
499 {
500   set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
501   set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
502   set_ai_data (2, 0x02);                        // latch chip select
503   set_ai_data (3, (unsigned char) ~(1 << (addr >> 21))); // a[23..21]
504   set_ai_data (2, (unsigned char) ((((addr >> 16) & 0x0f) << 2) | // a[20..16], auto-increment
505                                    (((addr >> 20) & 0x01) << 7) |
506                                    (inc ? 0x01 : 0x00)));
507   set_ai (3);
508 }
509 
510 
511 static int
program(unsigned int addr,unsigned char data,int retries)512 program (unsigned int addr, unsigned char data, int retries)
513 {
514   int to = 10000;
515 
516   set_data_write
517   set_address (fx005555 (addr), 0);             // program byte
518   write_data (0xaa);
519   set_address (fx002aaa (addr), 0);
520   write_data (0x55);
521   set_address (fx005555 (addr), 0);
522   write_data (0xa0);
523   set_address (addr, 0);
524   write_data (data);
525 
526   set_data_read
527   while (to--)
528     {
529       unsigned char s = read_data ();
530       if ((s & 128) == 0)
531         return 0;                               // OK
532       if (s & 32)
533         {
534           s = read_data ();
535           if ((s & 128) == 0)
536             return 0;                           // OK
537           if (data == read_data ())
538             return 0;                           // OK
539         }
540     }
541 
542   set_data_write
543   set_address (addr, 0);
544   set_data_read
545   if (data == read_data ())
546     return 0;                                   // OK
547   if (retries == 0)
548     return 1;                                   // error
549   return program (addr, data, retries - 1);
550 }
551 
552 
553 static int
write_block(unsigned int addr,unsigned char * buf)554 write_block (unsigned int addr, unsigned char *buf)
555 {
556   int count;
557 
558   select_address (addr, 1);
559   for (count = 0; count < 0x100; count++)
560     {
561       if (buf[count] == 0xff)
562         continue;                               // nothing to write
563       if (program (addr + count, buf[count], 3))
564         {
565           select_address (addr + count, 0);
566           set_data_read
567           fprintf (stderr, "\nERROR: Programming failed at 0x%06x (w:0x%02x, "
568                            "r:0x%02x)\n", addr + count, buf[count], read_data ());
569           return 1;
570         }
571     }
572   return 0;
573 }
574 
575 
576 #if 0
577 static int
578 wait_erased (void)
579 {
580   int i = 0;
581   unsigned char cur_byte, prev_byte;
582 
583   prev_byte = read_ai3_data () & 0x40;
584   while (++i < 0x7ffffff)
585     {
586       cur_byte = read_data () & 0x40;
587       if (cur_byte == prev_byte)
588         return 0;                               // OK
589       prev_byte = cur_byte;
590     }
591   return 1;                                     // erase error
592 }
593 
594 
595 static int
596 erase_chip (void)
597 {
598   reset_read ();
599   send_command (CMD_ERASE);
600   write_address_data (0x5555, 0xaa);
601   write_address_data (0x2aaa, 0x55);
602   write_address_data (0x5555, 0x10);
603   return wait_erased ();
604 }
605 
606 
607 static int
608 erase_cart (unsigned int size)
609 {
610   unsigned int addr;
611   unsigned char buf[0x8000];
612 
613   for (addr = 0x000000; addr < size; addr += 0x200000)
614     {
615       select_chip (addr);
616       if (erase_chip ())
617         {
618           fprintf (stderr, "ERROR: Erase chip %d failed\n", addr >> 21);
619           return 1;
620         }
621 
622       read_blocks (0x000000, buf, 128);
623       if (!is_erased (buf, 0x8000))
624         {
625           fprintf (stderr, "ERROR: Erase chip %d verify failed\n", addr >> 21);
626           return 1;
627         }
628     }
629 }
630 #endif
631 
632 
633 static int
erase(void)634 erase (void)
635 {
636   unsigned int addr;
637 
638   for (addr = 0; addr < 0x400000; addr += 0x200000)
639     {
640       set_data_write
641       set_address (fx005555 (addr), 0);
642       write_data (0xaa);
643       set_address (fx002aaa (addr), 0);
644       write_data (0x55);
645       set_address (fx005555 (addr), 0);
646       write_data (0x80);
647       set_address (fx005555 (addr), 0);
648       write_data (0xaa);
649       set_address (fx002aaa (addr), 0);
650       write_data (0x55);
651       set_address (fx005555 (addr), 0);
652       write_data (0x10);
653 
654       set_data_read
655       while (~read_data () & 0x80)              // wait for completion
656         ;
657     }
658   return 0;
659 }
660 
661 
662 int
pl_read_rom(const char * filename,unsigned short parport)663 pl_read_rom (const char *filename, unsigned short parport)
664 {
665   FILE *file;
666   unsigned int blocksleft, c_size, size, address = 0;
667   unsigned char buffer[0x8000];
668   time_t starttime;
669 
670   if ((file = fopen (filename, "wb")) == NULL)
671     {
672       fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
673       exit (1);
674     }
675   init_io (parport);
676 
677   c_size = cart_size ();
678 
679   if (c_size == 0x00)                           // Check for cartridge
680     {
681       fputs ("ERROR: No cartridge detected\n", stderr);
682       deinit_io ();
683       exit (1);
684     }
685 
686   size = game_info (c_size, NULL, NULL);
687 
688   if (size == 0x00)
689     {
690       fputs ("ERROR: No game detected\n", stderr);
691       deinit_io ();
692       exit (1);
693     }
694 
695   reset_read ();
696 
697   printf ("Receive: %u Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
698 
699   blocksleft = size >> 15;
700   starttime = time (NULL);
701 
702   while (blocksleft-- > 0)
703     {
704       read_blocks (address, buffer, 128);
705       fwrite (buffer, 1, 0x8000, file);
706       address += 0x8000;
707       ucon64_gauge (starttime, address, size);
708     }
709 
710   fclose (file);
711   deinit_io ();
712 
713   return 0;
714 }
715 
716 
717 int
pl_write_rom(const char * filename,unsigned short parport)718 pl_write_rom (const char *filename, unsigned short parport)
719 {
720   FILE *file;
721   unsigned int size, address = 0;
722   size_t bytesread, bytessent = 0;
723   unsigned char buffer[0x100];
724   time_t starttime;
725 
726   if ((file = fopen (filename, "rb")) == NULL)
727     {
728       fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
729       exit (1);
730     }
731   init_io (parport);
732   size = (int) ucon64.fsize;
733 
734   erase ();
735   reset_read ();
736 
737   printf ("Send: %u Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
738 
739   starttime = time (NULL);
740 
741   while ((bytesread = fread (buffer, 1, 0x100, file)) != 0)
742     {
743       if (write_block (address, buffer))
744         break;                                  // write failed
745       bytessent += bytesread;
746       address += 0x100;
747       ucon64_gauge (starttime, bytessent, size);
748     }
749 
750   fclose (file);
751   deinit_io ();
752 
753   return 0;
754 }
755 
756 
757 int
pl_info(unsigned short parport)758 pl_info (unsigned short parport)
759 {
760   unsigned int c_size, g_size;
761   int g_type;
762   char g_name[13];
763 
764   init_io (parport);
765 
766   c_size = cart_size ();
767   if (c_size == 0)
768     {
769       printf ("No cartridge found\n");
770       deinit_io ();
771       return 0;
772     }
773 
774   g_size = game_info (c_size, g_name, &g_type);
775 
776   if (g_size == 0)
777     printf ("No game found\n");
778   else
779     {
780       printf ("Game name: \"%s\"\n", g_name);
781       printf ("Game type: %s\n", (g_type == TYPE_COLOR) ? "Color" : "B&W");
782       printf ("Game size: %u Bytes (%.4f Mb)\n", g_size, (float) g_size / MBIT);
783     }
784   deinit_io ();
785 
786   return 0;
787 }
788 
789 #endif // USE_PARALLEL
790