123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784 |
- /*
- pl.c - Pocket Linker support for uCON64
- Copyright (c) 2004 Walter van Niftrik <w.f.b.w.v.niftrik@stud.tue.nl>
- Partly based on PokeLink - Copyright (c) Dark Fader / BlackThunder
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include <stdlib.h>
- #include <string.h>
- #include "misc/archive.h"
- #include "misc/parallel.h"
- #include "ucon64.h"
- #include "ucon64_misc.h"
- #include "backup/pl.h"
- #ifdef USE_PARALLEL
- static st_ucon64_obj_t pl_obj[] =
- {
- {UCON64_NGP, WF_DEFAULT | WF_STOP | WF_NO_ROM},
- {UCON64_NGP, WF_STOP | WF_NO_ROM},
- {UCON64_NGP, WF_SWITCH}
- };
- #endif
- const st_getopt2_t pl_usage[] =
- {
- {
- NULL, 0, 0, 0,
- NULL, "Pocket Linker"/*"19XX Bung Enterprises Ltd"*/,
- NULL
- },
- #ifdef USE_PARALLEL
- {
- "xpl", 0, 0, UCON64_XPL,
- NULL, "send/receive ROM to/from Pocket Linker; " OPTION_LONG_S "port=PORT\n"
- "receives automatically when ROM does not exist",
- &pl_obj[0]
- },
- {
- "xpli", 0, 0, UCON64_XPLI,
- NULL, "show information about inserted cartridge; " OPTION_LONG_S "port=PORT",
- &pl_obj[1]
- },
- {
- "xplm", 0, 0, UCON64_XPLM,
- NULL, "try to enable EPP mode, default is SPP mode",
- &pl_obj[2]
- },
- #endif // USE_PARALLEL
- {NULL, 0, 0, 0, NULL, NULL, NULL}
- };
- #ifdef USE_PARALLEL
- // flash unlock addresses with chip select
- #define fx0002aa(A) (((A) & 0x200000) | 0x0002aa)
- #define fx000555(A) (((A) & 0x200000) | 0x000555)
- #define fx000aaa(A) (((A) & 0x200000) | 0x000aaa)
- #define fx002aaa(A) (((A) & 0x200000) | 0x002aaa)
- #define fx005555(A) (((A) & 0x200000) | 0x005555)
- #define set_data_read outportb (port_a, 0);
- #define set_data_write outportb (port_a, 1);
- #define reset_port outportb (port_a, 4);
- #define clear_timeout outportb (port_9, 1);
- #define CMD_READ 0xf0
- #define CMD_INFO 0x90
- #define CMD_ERASE 0x80
- #define TYPE_BW 0x00
- #define TYPE_COLOR 0x01
- #define TYPE_MULTI 0x02
- static unsigned short port_8, port_9, port_a, port_b, port_c;
- static parport_mode_t port_mode;
- static int current_ai;
- static unsigned char ai_value[4];
- static void
- epp_write_data (unsigned char data)
- {
- outportb (port_c, data);
- }
- static void
- spp_write_data (unsigned char data)
- {
- outportb (port_8, data);
- outportb (port_a, 3);
- outportb (port_a, 1);
- }
- static void
- write_data (unsigned char data)
- {
- ai_value[current_ai] = data;
- if (port_mode == UCON64_SPP)
- spp_write_data (data);
- else
- epp_write_data (data);
- }
- static unsigned char
- epp_read_data (void)
- {
- return inportb (port_c);
- }
- static unsigned char
- spp_read_data (void)
- {
- unsigned char byte;
- outportb (port_a, 2);
- byte = (inportb (port_9) >> 3) & 0x0f;
- outportb (port_a, 6);
- byte |= (inportb (port_9) << 1) & 0xf0;
- outportb (port_a, 0);
- return byte;
- }
- static unsigned char
- read_data (void)
- {
- if (port_mode == UCON64_SPP)
- return spp_read_data ();
- else
- return epp_read_data ();
- }
- static void
- epp_set_ai (unsigned char ai)
- {
- current_ai = ai;
- outportb (port_b, ai);
- }
- static void
- spp_set_ai (unsigned char ai)
- {
- current_ai = ai;
- outportb (port_8, ai);
- outportb (port_a, 9);
- outportb (port_a, 1);
- }
- static void
- set_ai (unsigned char ai)
- {
- if (port_mode == UCON64_SPP)
- spp_set_ai (ai);
- else
- epp_set_ai (ai);
- }
- static void
- epp_set_ai_data (unsigned char ai, unsigned char data)
- {
- epp_set_ai (ai);
- epp_write_data (data);
- }
- static void
- spp_set_ai_data (unsigned char ai, unsigned char data)
- {
- spp_set_ai (ai);
- spp_write_data (data);
- }
- static void
- set_ai_data (unsigned char ai, unsigned char data)
- {
- if (port_mode == UCON64_SPP)
- spp_set_ai_data (ai, data);
- else
- epp_set_ai_data (ai, data);
- }
- static void
- init_port (void)
- {
- #ifndef USE_PPDEV
- clear_timeout
- #endif
- set_data_write
- set_ai_data (2, 0);
- }
- static void
- end_port (void)
- {
- set_data_write
- set_ai_data (2, 0);
- reset_port
- }
- static int
- detect_linker (void)
- {
- init_port ();
- set_data_write
- set_ai_data (1, 0x12);
- set_ai_data (0, 0x34);
- set_ai (1);
- set_data_read
- if (read_data () != 0x12)
- return 0;
- set_data_write
- set_ai (0);
- set_data_read
- if (read_data () != 0x34)
- return 0;
- end_port ();
- return 1;
- }
- static void
- select_address (unsigned int addr, int inc)
- {
- unsigned char data = (((addr >> 14) & 0x3c) | ((addr >> 13) & 0x80) |
- (inc ? 0x01 : 0x00)); // a[20..16], auto-increment
- if (data != ai_value[2])
- set_ai_data (2, data);
- set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
- set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
- }
- static void
- write_address_data (unsigned int addr, unsigned char data)
- {
- select_address (addr, 0);
- set_ai_data (3, data);
- }
- static void
- send_command (unsigned char cmd)
- {
- set_data_write
- write_address_data (0x5555, 0xaa);
- write_address_data (0x2aaa, 0x55);
- write_address_data (0x5555, cmd);
- }
- static void
- reset_read (void)
- {
- send_command (CMD_READ);
- }
- static unsigned char
- read_ai3_data (void)
- {
- set_ai (3);
- set_data_read
- return read_data ();
- }
- static int
- detect_chip (void)
- {
- int ai;
- unsigned char info[4];
- reset_read ();
- reset_read ();
- reset_read ();
- send_command (CMD_INFO);
- for (ai = 0; ai < 4; ai++)
- {
- set_data_write
- select_address (ai, 0);
- info[ai] = read_ai3_data ();
- }
- reset_read ();
- if (((info[0] & 0x90) == 0x90) && (info[2] == 0x01) && (info[3] & 0x80))
- return 1;
- else
- return 0;
- }
- static void
- select_chip (unsigned int addr)
- {
- set_data_write
- set_ai_data (2, 2);
- set_ai_data (3, (unsigned char) ((addr & 0x200000) ? 1 : 2));
- set_ai_data (2, 0);
- }
- static unsigned int
- cart_size (void)
- {
- select_chip (0x000000);
- if (!detect_chip ())
- return 0; // no cartridge found
- select_chip (0x200000);
- if (!detect_chip ())
- return 0x200000; // 16 megabit
- return 0x400000; // 32 megabit
- }
- static void
- read_blocks (unsigned int addr, unsigned char *buf, int blocks)
- {
- int block, i, offset = 0;
- select_chip (addr);
- for (block = 0; block < blocks; block++)
- {
- set_data_write
- select_address (addr | (block << 8), 1);
- set_ai (3);
- set_data_read
- for (i = 0; i < 0x100; i++)
- buf[offset++] = read_data ();
- }
- }
- static int
- is_erased (unsigned char *buf, unsigned int len)
- {
- unsigned int i;
- for (i = 0; i < len; i++)
- if (buf[i] != 0xff)
- return 0;
- return 1;
- }
- static int
- is_header (unsigned char *buf)
- {
- char msg[0x1d];
- strncpy (msg, (char *) buf, 0x1c);
- msg[0x1c] = '\0';
- if (strstr (msg, "COPYRIGHT") || strstr (msg, "SNK") ||
- strstr (msg, "LICENSED") || strstr (msg, "CORPORATION"))
- return 1; // header found
- return 0; // other data found
- }
- static int
- same_header (unsigned char *header, unsigned char *buf)
- {
- return (!memcmp (header, buf, 0x100));
- }
- static unsigned int
- game_info (unsigned int cart_size, char name[13], int *type)
- {
- unsigned char header[0x100];
- unsigned char buf[0x8000];
- select_chip (0x000000);
- read_blocks (0x000000, header, 1);
- if (!is_header (header))
- return 0; // no game found
- if (name)
- {
- strncpy (name, (char *) (header + 0x24), 12);
- name[12] = '\0';
- }
- if (type)
- {
- if (strstr (name, "Multi"))
- *type = TYPE_MULTI;
- else if (header[0x23] == 0x10)
- *type = TYPE_COLOR;
- else
- *type = TYPE_BW;
- }
- read_blocks (0x080000, buf, 128);
- if ((same_header (buf, header)) || is_erased (buf, 0x8000))
- return 0x080000; // 4 megabit
- read_blocks (0x100000, buf, 128);
- if ((same_header (buf, header)) || is_erased (buf, 0x8000))
- return 0x100000; // 8 megabit
- if (cart_size == 0x400000)
- {
- read_blocks (0x200000, buf, 128);
- if (is_erased (buf, 0x8000))
- return 0x200000; // 16 megabit
- return 0x400000; // 32 megabit
- }
- return 0x200000; // 16 megabit
- }
- static void
- deinit_io (void)
- {
- end_port ();
- }
- static void
- init_io (unsigned short port)
- {
- #ifndef USE_PPDEV
- outportb ((unsigned short) (port_8 + 0x402), 0); // Set EPP mode for ECP chipsets
- #endif
- port_8 = port;
- port_9 = port + 1;
- port_a = port + 2;
- port_b = port + 3;
- port_c = port + 4;
- parport_print_info ();
- if (ucon64.parport_mode == UCON64_EPP && port_8 != 0x3bc)
- port_mode = UCON64_EPP; // if port == 0x3bc => no EPP available
- else
- port_mode = UCON64_SPP;
- if (!detect_linker ())
- {
- port_mode = UCON64_SPP;
- if (!detect_linker ())
- {
- fputs ("ERROR: Pocket Linker not found or not turned on\n", stderr);
- deinit_io ();
- exit (1);
- }
- }
- // If we get here, a Pocket Linker was detected
- if (port_mode == UCON64_EPP)
- puts ("Pocket Linker found. EPP found");
- else
- puts ("Pocket Linker found. EPP not found or not enabled - SPP used");
- }
- static void
- set_address (unsigned int addr, int inc)
- {
- set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
- set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
- set_ai_data (2, 0x02); // latch chip select
- set_ai_data (3, (unsigned char) ~(1 << (addr >> 21))); // a[23..21]
- set_ai_data (2, (unsigned char) ((((addr >> 16) & 0x0f) << 2) | // a[20..16], auto-increment
- (((addr >> 20) & 0x01) << 7) |
- (inc ? 0x01 : 0x00)));
- set_ai (3);
- }
- static int
- program (unsigned int addr, unsigned char data, int retries)
- {
- int to = 10000;
- set_data_write
- set_address (fx005555 (addr), 0); // program byte
- write_data (0xaa);
- set_address (fx002aaa (addr), 0);
- write_data (0x55);
- set_address (fx005555 (addr), 0);
- write_data (0xa0);
- set_address (addr, 0);
- write_data (data);
- set_data_read
- while (to--)
- {
- unsigned char s = read_data ();
- if ((s & 128) == 0)
- return 0; // OK
- if (s & 32)
- {
- s = read_data ();
- if ((s & 128) == 0)
- return 0; // OK
- if (data == read_data ())
- return 0; // OK
- }
- }
- set_data_write
- set_address (addr, 0);
- set_data_read
- if (data == read_data ())
- return 0; // OK
- if (retries == 0)
- return 1; // error
- return program (addr, data, retries - 1);
- }
- static int
- write_block (unsigned int addr, unsigned char *buf)
- {
- int count;
- select_address (addr, 1);
- for (count = 0; count < 0x100; count++)
- {
- if (buf[count] == 0xff)
- continue; // nothing to write
- if (program (addr + count, buf[count], 3))
- {
- select_address (addr + count, 0);
- set_data_read
- fprintf (stderr, "\nERROR: Programming failed at 0x%06x (w:0x%02x, "
- "r:0x%02x)\n", addr + count, buf[count], read_data ());
- return 1;
- }
- }
- return 0;
- }
- #if 0
- static int
- wait_erased (void)
- {
- int i = 0;
- unsigned char cur_byte, prev_byte;
- prev_byte = read_ai3_data () & 0x40;
- while (++i < 0x7ffffff)
- {
- cur_byte = read_data () & 0x40;
- if (cur_byte == prev_byte)
- return 0; // OK
- prev_byte = cur_byte;
- }
- return 1; // erase error
- }
- static int
- erase_chip (void)
- {
- reset_read ();
- send_command (CMD_ERASE);
- write_address_data (0x5555, 0xaa);
- write_address_data (0x2aaa, 0x55);
- write_address_data (0x5555, 0x10);
- return wait_erased ();
- }
- static int
- erase_cart (unsigned int size)
- {
- unsigned int addr;
- unsigned char buf[0x8000];
- for (addr = 0x000000; addr < size; addr += 0x200000)
- {
- select_chip (addr);
- if (erase_chip ())
- {
- fprintf (stderr, "ERROR: Erase chip %d failed\n", addr >> 21);
- return 1;
- }
- read_blocks (0x000000, buf, 128);
- if (!is_erased (buf, 0x8000))
- {
- fprintf (stderr, "ERROR: Erase chip %d verify failed\n", addr >> 21);
- return 1;
- }
- }
- }
- #endif
- static int
- erase (void)
- {
- unsigned int addr;
- for (addr = 0; addr < 0x400000; addr += 0x200000)
- {
- set_data_write
- set_address (fx005555 (addr), 0);
- write_data (0xaa);
- set_address (fx002aaa (addr), 0);
- write_data (0x55);
- set_address (fx005555 (addr), 0);
- write_data (0x80);
- set_address (fx005555 (addr), 0);
- write_data (0xaa);
- set_address (fx002aaa (addr), 0);
- write_data (0x55);
- set_address (fx005555 (addr), 0);
- write_data (0x10);
- set_data_read
- while (~read_data () & 0x80) // wait for completion
- ;
- }
- return 0;
- }
- int
- pl_read_rom (const char *filename, unsigned short parport)
- {
- FILE *file;
- unsigned int blocksleft, c_size, size, address = 0;
- unsigned char buffer[0x8000];
- time_t starttime;
- if ((file = fopen (filename, "wb")) == NULL)
- {
- fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
- exit (1);
- }
- init_io (parport);
- c_size = cart_size ();
- if (c_size == 0x00) // Check for cartridge
- {
- fputs ("ERROR: No cartridge detected\n", stderr);
- deinit_io ();
- exit (1);
- }
- size = game_info (c_size, NULL, NULL);
- if (size == 0x00)
- {
- fputs ("ERROR: No game detected\n", stderr);
- deinit_io ();
- exit (1);
- }
- reset_read ();
- printf ("Receive: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
- blocksleft = size >> 15;
- starttime = time (NULL);
- while (blocksleft-- > 0)
- {
- read_blocks (address, buffer, 128);
- fwrite (buffer, 1, 0x8000, file);
- address += 0x8000;
- ucon64_gauge (starttime, address, size);
- }
- fclose (file);
- deinit_io ();
- return 0;
- }
- int
- pl_write_rom (const char *filename, unsigned short parport)
- {
- FILE *file;
- unsigned int size, bytesread, bytessent = 0, address = 0;
- unsigned char buffer[0x100];
- time_t starttime;
- if ((file = fopen (filename, "rb")) == NULL)
- {
- fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
- exit (1);
- }
- init_io (parport);
- size = ucon64.file_size;
- erase ();
- reset_read ();
- printf ("Send: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
- starttime = time (NULL);
- while ((bytesread = fread (buffer, 1, 0x100, file)) != 0)
- {
- if (write_block (address, buffer))
- break; // write failed
- bytessent += bytesread;
- address += 0x100;
- ucon64_gauge (starttime, bytessent, size);
- }
- fclose (file);
- deinit_io ();
- return 0;
- }
- int
- pl_info (unsigned short parport)
- {
- unsigned int c_size, g_size;
- int g_type;
- char g_name[13];
- init_io (parport);
- c_size = cart_size ();
- if (c_size == 0)
- {
- printf ("No cartridge found\n");
- deinit_io ();
- return 0;
- }
- g_size = game_info (c_size, g_name, &g_type);
- if (g_size == 0)
- printf ("No game found\n");
- else
- {
- printf ("Game name: \"%s\"\n", g_name);
- printf ("Game type: %s\n", (g_type == TYPE_COLOR) ? "Color" : "B&W");
- printf ("Game size: %d Bytes (%.4f Mb)\n", g_size, (float) g_size / MBIT);
- }
- deinit_io ();
- return 0;
- }
- #endif // USE_PARALLEL
|