summaryrefslogtreecommitdiff
path: root/gdb/ser-e7kpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/ser-e7kpc.c')
-rw-r--r--gdb/ser-e7kpc.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/gdb/ser-e7kpc.c b/gdb/ser-e7kpc.c
new file mode 100644
index 00000000000..8be5db9b691
--- /dev/null
+++ b/gdb/ser-e7kpc.c
@@ -0,0 +1,470 @@
+/* Remote serial interface using Hitachi E7000 PC ISA card in a PC
+ Copyright 1994, 1999 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if defined __GO32__ || defined _WIN32
+#include "defs.h"
+#include "serial.h"
+#include "gdb_string.h"
+
+/* MSVC uses strnicmp instead of strncasecmp */
+#ifdef _MSC_VER
+#define strncasecmp strnicmp
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef __GO32__
+#include <sys/dos.h>
+#endif
+
+static int e7000pc_open PARAMS ((serial_t scb, const char *name));
+static void e7000pc_raw PARAMS ((serial_t scb));
+static int e7000pc_readchar PARAMS ((serial_t scb, int timeout));
+static int e7000pc_setbaudrate PARAMS ((serial_t scb, int rate));
+static int e7000pc_write PARAMS ((serial_t scb, const char *str, int len));
+static void e7000pc_close PARAMS ((serial_t scb));
+static serial_ttystate e7000pc_get_tty_state PARAMS ((serial_t scb));
+static int e7000pc_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
+#define OFF_DPD 0x0000
+#define OFF_DDP 0x1000
+#define OFF_CPD 0x2000
+#define OFF_CDP 0x2400
+#define OFF_FA 0x3000
+#define OFF_FB 0x3002
+#define OFF_FC 0x3004
+#define OFF_IRQTOD 0x3008
+#define OFF_IRQTOP 0x300a
+#define OFF_READY 0x300c
+#define OFF_PON 0x300e
+
+#define IDLE 0x0000
+#define CMD_CI 0x4349
+#define CMD_CO 0x434f
+#define CMD_LO 0x4c4f
+#define CMD_LS 0x4c53
+#define CMD_SV 0x5356
+#define CMD_SS 0x5353
+#define CMD_OK 0x4f4b
+#define CMD_ER 0x4552
+#define CMD_NF 0x4e46
+#define CMD_AB 0x4142
+#define CMD_ED 0x4544
+#define CMD_CE 0x4345
+
+static unsigned long fa;
+static unsigned long irqtod;
+static unsigned long ready;
+static unsigned long fb;
+static unsigned long cpd ;
+static unsigned long cdp ;
+static unsigned long ready;
+static unsigned long pon;
+static unsigned long irqtop;
+static unsigned long board_at;
+
+#ifdef __GO32__
+
+#define SET_BYTE(x,y) { char _buf = y;dosmemput(&_buf,1, x);}
+#define SET_WORD(x,y) { short _buf = y;dosmemput(&_buf,2, x);}
+#define GET_BYTE(x) ( dosmemget(x,1,&bb), bb)
+#define GET_WORD(x) ( dosmemget(x,2,&sb), sb)
+static unsigned char bb;
+static unsigned short sb;
+
+#else /* win32 */
+
+#define SET_BYTE(x,y) *(volatile unsigned char *)(x) = (y)
+#define SET_WORD(x,y) *(volatile unsigned short *)(x) = (y)
+#define GET_BYTE(x) (*(volatile unsigned char *)(x))
+#define GET_WORD(x) (*(volatile unsigned short *)(x))
+#define dosmemget(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#define dosmemput(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#endif
+
+static struct sw
+{
+ int sw;
+ int addr;
+} sigs[] = {
+ {0x14, 0xd0000},
+ {0x15, 0xd4000},
+ {0x16, 0xd8000},
+ {0x17, 0xdc000},
+ 0};
+
+#ifdef _MSC_VER
+/* Get the base of the data segment. This is needed to calculate the offset
+ between data segment addresses and the base of linear memory, which is where
+ device registers reside. Note that this is really only necessary for
+ Win32s, since Win95 and NT keep the data segment at linear 0. */
+
+static unsigned long
+get_ds_base (void)
+{
+ unsigned short dsval;
+ LDT_ENTRY ldt;
+ unsigned long dsbase;
+
+ __asm
+ {
+ mov dsval,ds
+ }
+
+ dsbase = 0;
+
+ GetThreadSelectorEntry (GetCurrentThread(), dsval, &ldt);
+
+ dsbase = ldt.HighWord.Bits.BaseHi << 24 | ldt.HighWord.Bits.BaseMid << 16
+ | ldt.BaseLow;
+
+ return dsbase;
+}
+#else /* !_MSC_VER */
+#define get_ds_base() 0
+#endif /* _MSC_VER */
+
+static int
+e7000pc_init ()
+{
+ int try;
+ unsigned long dsbase;
+
+ dsbase = get_ds_base ();
+
+ /* Look around in memory for the board's signature */
+
+ for (try = 0; sigs[try].sw; try++)
+ {
+ int val;
+ board_at = sigs[try].addr - dsbase;
+ fa = board_at + OFF_FA;
+ fb = board_at + OFF_FB;
+ cpd = board_at + OFF_CPD;
+ cdp = board_at + OFF_CDP;
+ ready =board_at + OFF_READY;
+ pon = board_at + OFF_PON;
+ irqtop = board_at + OFF_IRQTOP;
+ irqtod = board_at + OFF_IRQTOD;
+
+ val = GET_WORD (ready);
+
+ if (val == (0xaaa0 | sigs[try].sw))
+ {
+ if (GET_WORD (pon) & 0xf)
+ {
+ SET_WORD (fa, 0);
+ SET_WORD (fb, 0);
+
+ SET_WORD (irqtop, 1); /* Disable interrupts from e7000 */
+ SET_WORD (ready, 1);
+ printf_filtered ("\nConnected to the E7000PC at address 0x%x\n",
+ sigs[try].addr);
+ return 1;
+ }
+ error ("The E7000 PC board is working, but the E7000 is turned off.\n");
+ return 0;
+ }
+ }
+
+ error ("GDB cannot connect to the E7000 PC board, check that it is installed\n\
+and that the switch settings are correct. Some other DOS programs can \n\
+stop the board from working. Try starting from a very minimal boot, \n\
+perhaps you need to disable EMM386 over the region where the board has\n\
+its I/O space, remove other unneeded cards, etc etc\n");
+ return 0;
+
+}
+
+static int pbuf_size;
+static int pbuf_index;
+
+/* Return next byte from cdp. If no more, then return -1. */
+
+static int
+e7000_get (void)
+{
+ static char pbuf[1000];
+ char tmp[1000];
+ int x;
+
+ if (pbuf_index < pbuf_size)
+ {
+ x = pbuf[pbuf_index++];
+ }
+ else if ((GET_WORD (fb) & 1))
+ {
+ int i;
+ pbuf_size = GET_WORD (cdp + 2);
+
+ dosmemget (cdp + 8, pbuf_size + 1, tmp);
+
+ /* Tell the E7000 we've eaten */
+ SET_WORD (fb, 0);
+ /* Swap it around */
+ for (i = 0; i < pbuf_size; i++)
+ {
+ pbuf[i] = tmp[i^1];
+ }
+ pbuf_index = 0;
+ x = pbuf[pbuf_index++];
+ }
+ else
+ {
+ x = -1;
+ }
+ return x;
+}
+
+/* Works just like read(), except that it takes a TIMEOUT in seconds. Note
+ that TIMEOUT == 0 is a poll, and TIMEOUT == -1 means wait forever. */
+
+static int
+dosasync_read (fd, buf, len, timeout)
+ int fd;
+ char *buf;
+ int len;
+ int timeout;
+
+{
+ long now;
+ long then;
+ int i = 0;
+
+ /* Then look for some more if we're still hungry */
+ time (&now);
+ then = now + timeout;
+ while (i < len)
+ {
+ int ch = e7000_get();
+
+ /* While there's room in the buffer, and we've already
+ read the stuff in, suck it over */
+ if (ch != -1)
+ {
+ buf[i++] = ch;
+ while (i < len && pbuf_index < pbuf_size )
+ {
+ ch = e7000_get();
+ if (ch == -1)
+ break;
+ buf[i++] = ch;
+ }
+ }
+
+ time (&now);
+
+ if (timeout == 0)
+ return i;
+ if (now >= then && timeout > 0)
+ {
+ return i;
+ }
+ }
+ return len;
+}
+
+
+static int
+dosasync_write (fd, buf, len)
+ int fd;
+ const char *buf;
+ int len;
+{
+ int i;
+ char dummy[1000];
+
+ /* Construct copy locally */
+ ((short *)dummy)[0] = CMD_CI;
+ ((short *)dummy)[1] = len;
+ ((short *)dummy)[2] = 0;
+ ((short *)dummy)[3] = 0;
+ for (i = 0; i < len ; i++)
+ {
+ dummy[8 + i ^ 1] = buf[i];
+ }
+
+ /* Wait for the card to get ready */
+ while (GET_WORD (fa) & 1) ;
+
+ /* Blast onto the ISA card */
+ dosmemput (dummy, 8 + len + 1, cpd);
+
+ SET_WORD (fa, 1);
+ SET_WORD (irqtod, 1); /* Interrupt the E7000 */
+
+ return len;
+}
+
+static int
+e7000pc_open (scb, name)
+ serial_t scb;
+ const char *name;
+{
+ if (strncasecmp (name, "pc", 2) != 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ scb->fd = e7000pc_init ();
+
+ if (!scb->fd)
+ return -1;
+
+ return 0;
+}
+
+static int
+e7000pc_noop (scb)
+ serial_t scb;
+{
+ return 0;
+}
+
+static void
+e7000pc_raw (scb)
+ serial_t scb;
+{
+ /* Always in raw mode */
+}
+
+static int
+e7000pc_readchar (scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ char buf;
+
+ top:
+
+ if (dosasync_read (scb->fd, &buf, 1, timeout))
+ {
+ if (buf == 0) goto top;
+ return buf;
+ }
+ else
+ return SERIAL_TIMEOUT;
+}
+
+struct e7000pc_ttystate {
+ int dummy;
+};
+
+/* e7000pc_{get set}_tty_state() are both dummys to fill out the function
+ vector. Someday, they may do something real... */
+
+static serial_ttystate
+e7000pc_get_tty_state (scb)
+ serial_t scb;
+{
+ struct e7000pc_ttystate *state;
+
+ state = (struct e7000pc_ttystate *) xmalloc (sizeof *state);
+
+ return (serial_ttystate) state;
+}
+
+static int
+e7000pc_set_tty_state (scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ return 0;
+}
+
+static int
+e7000pc_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
+ serial_t scb;
+ serial_ttystate new_ttystate;
+ serial_ttystate old_ttystate;
+{
+ return 0;
+}
+
+static void
+e7000pc_print_tty_state (scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ /* Nothing to print. */
+ return;
+}
+
+static int
+e7000pc_setbaudrate (scb, rate)
+ serial_t scb;
+ int rate;
+{
+ return 0;
+}
+
+static int
+e7000pc_write (scb, str, len)
+ serial_t scb;
+ const char *str;
+ int len;
+{
+ dosasync_write (scb->fd, str, len);
+
+ return 0;
+}
+
+static void
+e7000pc_close (scb)
+ serial_t scb;
+{
+}
+
+static struct serial_ops e7000pc_ops =
+{
+ "pc",
+ 0,
+ e7000pc_open,
+ e7000pc_close,
+ e7000pc_readchar,
+ e7000pc_write,
+ e7000pc_noop, /* flush output */
+ e7000pc_noop, /* flush input */
+ e7000pc_noop, /* send break -- currently used only for nindy */
+ e7000pc_raw,
+ e7000pc_get_tty_state,
+ e7000pc_set_tty_state,
+ e7000pc_print_tty_state,
+ e7000pc_noflush_set_tty_state,
+ e7000pc_setbaudrate,
+ e7000pc_noop, /* wait for output to drain */
+};
+
+void
+_initialize_ser_e7000pc ()
+{
+ serial_add_interface (&e7000pc_ops);
+}
+#else
+
+void
+_initialize_ser_e7000pc ()
+{
+
+}
+#endif