123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /*
- ffe.c - General Front Far East copier routines for uCON64
- Copyright (c) 2002 - 2004 dbjh
- Copyright (c) 2003 JohnDie
- 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 "misc/misc.h"
- #include "misc/parallel.h"
- #include "misc/term.h"
- #include "ucon64.h"
- #include "backup/ffe.h"
- #ifdef USE_PARALLEL
- #define N_TRY_MAX 65536 // # times to test if copier ready
- static void ffe_sendb (unsigned char byte);
- static unsigned char ffe_wait_while_busy (void);
- static unsigned short ffe_port;
- void
- ffe_init_io (unsigned short port)
- /*
- - sets global `ffe_port'. Then the send/receive functions don't need to pass
- `ffe_port' all the way to ffe_sendb()/ffe_receiveb().
- - calls init_conio(). Necessary for kbhit() and DOS-like behaviour of getch().
- */
- {
- ffe_port = port;
- #if 0 // we want to support non-standard parallel port addresses
- if (ffe_port != 0x3bc && ffe_port != 0x378 && ffe_port != 0x278)
- {
- fprintf (stderr, "ERROR: PORT must be 0x3bc, 0x378 or 0x278\n");
- exit (1);
- }
- #endif
- #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
- init_conio ();
- #endif
- if (register_func (ffe_deinit_io) == -1)
- {
- fputs ("ERROR: Could not register function with register_func()\n", stderr);
- exit (1);
- }
- parport_print_info ();
- }
- void
- ffe_deinit_io (void)
- {
- #if (defined __unix__ || defined __BEOS__) && !defined __MSDOS__
- deinit_conio ();
- #endif
- }
- void
- ffe_send_block (unsigned short address, unsigned char *buffer, unsigned short len)
- {
- int n;
- unsigned char checksum = 0x81;
- ffe_send_command (0, address, len);
- for (n = 0; n < len; n++)
- {
- ffe_sendb (buffer[n]);
- checksum ^= buffer[n];
- }
- ffe_sendb (checksum);
- }
- void
- ffe_send_block2 (unsigned short address, unsigned char *buffer, unsigned short len)
- {
- int n;
- unsigned char checksum = 0x81;
- ffe_send_command (2, address, len);
- for (n = 0; n < len; n++)
- {
- ffe_sendb (buffer[n]);
- checksum ^= buffer[n];
- }
- ffe_sendb (checksum);
- }
- void
- ffe_send_command0 (unsigned short address, unsigned char byte)
- // command 0 for 1 byte
- {
- ffe_send_command (0, address, 1);
- ffe_sendb (byte);
- ffe_sendb (0x81 ^ byte);
- }
- unsigned char
- ffe_send_command1 (unsigned short address)
- // command 1 for 1 byte
- {
- unsigned char byte;
- ffe_send_command (1, address, 1);
- byte = ffe_receiveb ();
- if ((0x81 ^ byte) != ffe_receiveb ())
- puts ("received data is corrupt");
- return byte;
- }
- void
- ffe_send_command (unsigned char command_code, unsigned short a, unsigned short l)
- {
- ffe_sendb (0xd5);
- ffe_sendb (0xaa);
- ffe_sendb (0x96);
- ffe_sendb (command_code);
- ffe_sendb ((unsigned char) a); // low byte
- ffe_sendb ((unsigned char) (a >> 8)); // high byte
- ffe_sendb ((unsigned char) l); // low byte
- ffe_sendb ((unsigned char) (l >> 8)); // high byte
- ffe_sendb ((unsigned char) (0x81 ^ command_code ^ a ^ (a >> 8) ^ l ^ (l >> 8))); // checksum
- }
- void
- ffe_sendb (unsigned char byte)
- {
- ffe_wait_for_ready ();
- outportb (ffe_port + PARPORT_DATA, byte);
- outportb (ffe_port + PARPORT_CONTROL,
- inportb (ffe_port + PARPORT_CONTROL) ^ PARPORT_STROBE); // invert strobe
- ffe_wait_for_ready (); // necessary if followed by ffe_receiveb()
- }
- void
- ffe_receive_block (unsigned short address, unsigned char *buffer, unsigned short len)
- {
- volatile int n;
- int n_try = 0;
- unsigned char checksum1, checksum2;
- do
- {
- checksum1 = 0x81;
- ffe_send_command (1, address, len);
- for (n = 0; n < len; n++)
- {
- buffer[n] = ffe_receiveb ();
- checksum1 ^= buffer[n];
- }
- checksum2 = ffe_receiveb ();
- for (n = 0; n < 65536; n++) // a delay is necessary here
- ;
- n_try++;
- }
- while ((checksum1 != checksum2) && (n_try < N_TRY_MAX));
- if (checksum1 != checksum2)
- puts ("\nreceived data is corrupt");
- }
- void
- ffe_receive_block2 (unsigned short address, unsigned char *buffer, unsigned short len)
- {
- volatile int n;
- int n_try = 0;
- unsigned char checksum1, checksum2;
- do
- {
- checksum1 = 0x81;
- ffe_send_command (3, address, len);
- for (n = 0; n < len; n++)
- {
- buffer[n] = ffe_receiveb ();
- checksum1 ^= buffer[n];
- }
- checksum2 = ffe_receiveb ();
- for (n = 0; n < 65536; n++) // a delay is necessary here
- ;
- n_try++;
- }
- while ((checksum1 != checksum2) && (n_try < N_TRY_MAX));
- if (checksum1 != checksum2)
- puts ("\nreceived data is corrupt");
- }
- unsigned char
- ffe_receiveb (void)
- {
- unsigned char byte;
- byte = (ffe_wait_while_busy () & PARPORT_INPUT_MASK) >> 3; // receive low nibble
- outportb (ffe_port + PARPORT_CONTROL,
- inportb (ffe_port + PARPORT_CONTROL) ^ PARPORT_STROBE); // invert strobe
- byte |= (ffe_wait_while_busy () & PARPORT_INPUT_MASK) << 1; // receive high nibble
- outportb (ffe_port + PARPORT_CONTROL,
- inportb (ffe_port + PARPORT_CONTROL) ^ PARPORT_STROBE); // invert strobe
- return byte;
- }
- unsigned char
- ffe_wait_while_busy (void)
- {
- unsigned char input;
- int n_try = 0;
- do
- {
- input = inportb (ffe_port + PARPORT_STATUS);
- n_try++;
- }
- while (input & PARPORT_IBUSY && n_try < N_TRY_MAX);
- #if 0
- /*
- VGS doesn't check for this, and it seems to happen quite regularly, so it
- is currently commented out
- */
- if (n_try >= N_TRY_MAX)
- {
- fputs ("ERROR: The copier is not ready\n" // yes, "ready" :-)
- " Turn it off for a few seconds then turn it on and try again\n",
- stderr);
- exit (1);
- }
- #endif
- // read port again to let data settle down and to delay a little bit - JohnDie
- return inportb (ffe_port + PARPORT_STATUS);
- }
- void
- ffe_wait_for_ready (void)
- {
- unsigned char input;
- int n_try = 0;
- do
- {
- input = inportb (ffe_port + PARPORT_STATUS);
- n_try++;
- }
- while (!(input & PARPORT_IBUSY) && n_try < N_TRY_MAX);
- #if 0
- if (n_try >= N_TRY_MAX)
- {
- fputs ("ERROR: The copier is not ready\n"
- " Turn it off for a few seconds then turn it on and try again\n",
- stderr);
- exit (1);
- }
- #endif
- }
- void
- ffe_checkabort (int status)
- {
- if ((!ucon64.frontend ? kbhit () : 0) && getch () == 'q')
- {
- // ffe_send_command (5, 0, 0); // VGS: when sending/receiving a SNES ROM
- puts ("\nProgram aborted");
- exit (status);
- }
- }
- #endif // USE_PARALLEL
|