Mon Jan 23 00:06:57 1995 Steve Chamberlain <sac@splat>
authorSteve Chamberlain <sac@cygnus>
Mon, 23 Jan 1995 08:09:02 +0000 (08:09 +0000)
committerSteve Chamberlain <sac@cygnus>
Mon, 23 Jan 1995 08:09:02 +0000 (08:09 +0000)
* remote-e7000.c, remote-z8k.c, remote-nindy.c (target_ops):
        Define memory_insert/remove_breakpoint.
* xm-go32.h: Remove redundant SIGs.

Thu Jan 19 20:26:58 1995  Steve Chamberlain  <sac@splat>

* ser-go32.c: Rewritten by nigel@algor.co.uk.

gdb/config/i386/xm-go32.h
gdb/remote-nindy.c
gdb/remote-z8k.c
gdb/ser-go32.c

index a36fe91..eee636f 100644 (file)
@@ -30,10 +30,3 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define QUIT  { pollquit(); }
 
 #define GDBINIT_FILENAME "gdb.ini"
-
-#if !defined(SIGURG) & !defined(SIGALRM) & !defined(SIGBUS) & !defined(SIGSTOP)
-#define SIGURG (NSIG)
-#define SIGALRM (NSIG + 1)
-#define SIGBUS (NSIG + 2)
-#define SIGSTOP (NSIG + 3)
-#endif /* missing some signals */
index 0c2c98c..dd3dc0b 100644 (file)
@@ -738,7 +738,8 @@ specified when you started GDB.",
        nindy_fetch_registers, nindy_store_registers,
        nindy_prepare_to_store,
        nindy_xfer_inferior_memory, nindy_files_info,
-       0, 0, /* insert_breakpoint, remove_breakpoint, */
+       memory_insert_breakpoint,
+       memory_remove_breakpoint,
        0, 0, 0, 0, 0,  /* Terminal crud */
        nindy_kill,
        generic_load,
index 0f43db0..df01e54 100644 (file)
@@ -335,7 +335,8 @@ struct target_ops sim_ops =
   sim_prepare_to_store,
   sim_xfer_inferior_memory,
   sim_files_info,
-  0, 0,                                /* Breakpoints */
+  memory_insert_breakpoint,
+  memory_remove_breakpoint,
   0, 0, 0, 0, 0,               /* Terminal handling */
   sim_kill,                    /* FIXME, kill */
   sim_load,
index b1b5331..70887f0 100644 (file)
@@ -1,7 +1,12 @@
-/* Remote serial interface for local (hardwired) serial ports for GO32.
-   Copyright 1992, 1993 Free Software Foundation, Inc.
+/* Remote serial interface for local (hardwired) serial ports for
+   GO32.  Copyright 1992, 1993 Free Software Foundation, Inc.
 
-   This file is part of GDB.
+   Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
+
+   This version uses DPMI interrupts to handle buffered i/o 
+   without the separate "asynctsr" program.
+
+   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
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "defs.h"
+#include "gdbcmd.h"
 #include "serial.h"
+
+
+/*
+ * NS16550 UART registers
+ */
+
+#define COM1ADDR       0x3f8
+#define COM2ADDR       0x2f8
+#define COM3ADDR       0x3e8
+#define COM4ADDR       0x3e0
+
+#define        com_data        0       /* data register (R/W) */
+#define        com_dlbl        0       /* divisor latch low (W) */
+#define        com_ier         1       /* interrupt enable (W) */
+#define        com_dlbh        1       /* divisor latch high (W) */
+#define        com_iir         2       /* interrupt identification (R) */
+#define        com_fifo        2       /* FIFO control (W) */
+#define        com_lctl        3       /* line control register (R/W) */
+#define        com_cfcr        3       /* line control register (R/W) */
+#define        com_mcr         4       /* modem control register (R/W) */
+#define        com_lsr         5       /* line status register (R/W) */
+#define        com_msr         6       /* modem status register (R/W) */
+
+/*
+ * Constants for computing 16 bit baud rate divisor (lower byte
+ * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal.  Divisor is
+ * 1.8432 MHz / (16 * X) for X bps.  If the baud rate can't be set
+ * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
+ */
+#define COMTICK                (1843200/16)
+#define SPEED_TOLERANCE        30      /* thousandths; real == desired +- 3.0% */
+
+/* interrupt enable register */
+#define        IER_ERXRDY      0x1     /* int on rx ready */
+#define        IER_ETXRDY      0x2     /* int on tx ready */
+#define        IER_ERLS        0x4     /* int on line status change */
+#define        IER_EMSC        0x8     /* int on modem status change */
+
+/* interrupt identification register */
+#define        IIR_FIFO_MASK   0xc0    /* set if FIFOs are enabled */
+#define        IIR_IMASK       0xf     /* interrupt cause mask */
+#define        IIR_NOPEND      0x1     /* nothing pending */
+#define        IIR_RLS         0x6     /* receive line status */
+#define        IIR_RXRDY       0x4     /* receive ready */
+#define        IIR_RXTOUT      0xc     /* receive timeout */
+#define        IIR_TXRDY       0x2     /* transmit ready */
+#define        IIR_MLSC        0x0     /* modem status */
+
+
+/* fifo control register */
+#define        FIFO_ENABLE     0x01    /* enable fifo */
+#define        FIFO_RCV_RST    0x02    /* reset receive fifo */
+#define        FIFO_XMT_RST    0x04    /* reset transmit fifo */
+#define        FIFO_DMA_MODE   0x08    /* enable dma mode */
+#define        FIFO_TRIGGER_1  0x00    /* trigger at 1 char */
+#define        FIFO_TRIGGER_4  0x40    /* trigger at 4 chars */
+#define        FIFO_TRIGGER_8  0x80    /* trigger at 8 chars */
+#define        FIFO_TRIGGER_14 0xc0    /* trigger at 14 chars */
+
+/* character format control register */
+#define        CFCR_DLAB       0x80    /* divisor latch */
+#define        CFCR_SBREAK     0x40    /* send break */
+#define        CFCR_PZERO      0x30    /* zero parity */
+#define        CFCR_PONE       0x20    /* one parity */
+#define        CFCR_PEVEN      0x10    /* even parity */
+#define        CFCR_PODD       0x00    /* odd parity */
+#define        CFCR_PENAB      0x08    /* parity enable */
+#define        CFCR_STOPB      0x04    /* 2 stop bits */
+#define        CFCR_8BITS      0x03    /* 8 data bits */
+#define        CFCR_7BITS      0x02    /* 7 data bits */
+#define        CFCR_6BITS      0x01    /* 6 data bits */
+#define        CFCR_5BITS      0x00    /* 5 data bits */
+
+/* modem control register */
+#define        MCR_LOOPBACK    0x10    /* loopback */
+#define        MCR_IENABLE     0x08    /* output 2 = int enable */
+#define        MCR_DRS         0x04    /* output 1 = xxx */
+#define        MCR_RTS         0x02    /* enable RTS */
+#define        MCR_DTR         0x01    /* enable DTR */
+
+/* line status register */
+#define        LSR_RCV_FIFO    0x80    /* error in receive fifo */
+#define        LSR_TSRE        0x40    /* transmitter empty */
+#define        LSR_TXRDY       0x20    /* transmitter ready */
+#define        LSR_BI          0x10    /* break detected */
+#define        LSR_FE          0x08    /* framing error */
+#define        LSR_PE          0x04    /* parity error */
+#define        LSR_OE          0x02    /* overrun error */
+#define        LSR_RXRDY       0x01    /* receiver ready */
+#define        LSR_RCV_MASK    0x1f
+
+/* modem status register */
+#define        MSR_DCD         0x80
+#define        MSR_RI          0x40
+#define        MSR_DSR         0x20
+#define        MSR_CTS         0x10
+#define        MSR_DDCD        0x08
+#define        MSR_TERI        0x04
+#define        MSR_DDSR        0x02
+#define        MSR_DCTS        0x01
+
 #include <sys/dos.h>
+#include <sys/go32.h>
+#include <sys/dpmi.h>
+
+/* DPMI Communication */
+static union REGS dpmi_regs;
+static struct SREGS dpmi_sregs;
+
+/* 16550 rx fifo trigger point */
+#define FIFO_TRIGGER   FIFO_TRIGGER_4
+
+/* input buffer size */
+#define CBSIZE 4096
+
+/* return raw 18Hz clock count */
+extern long rawclock (void);
+
+#define RAWHZ  18
+
+#ifdef DOS_STATS
+#define CNT_RX         16
+#define CNT_TX         17
+#define CNT_STRAY      18
+#define CNT_ORUN       19
+#define NCNT           20
+
+static int     intrcnt;
+static int     cnts[NCNT];
+static char    *cntnames[NCNT] = {
+  /* h/w interrupt counts. */
+  "mlsc",      "nopend",       "txrdy",        "?3",
+  "rxrdy",     "?5",           "rls",          "?7", 
+  "?8",        "?9",           "?a",           "?b", 
+  "rxtout",    "?d",           "?e",           "?f", 
+  /* s/w counts. */
+  "rxcnt",     "txcnt",        "stray",        "swoflo"
+};
 
-#define disable() asm("cli")
-#define enable() asm("sti")
-
-
-struct go32_ttystate
-  {
-    int bogus;
-  };
-typedef struct
-  {
-    short jmp_op;
-    short signature;
-    short version;
-    short buffer_start;
-    short buffer_end;
-    short getp;
-    short putp;
-    short iov;
-    short count;
-    short overflow;
-    short buffer_size;
-    short ovflushes;
-  }
-ASYNC_STRUCT;
-
-#define AOFF_JMP_OP            0
-#define AOFF_SIGNATURE                 2
-#define AOFF_VERSION           4
-#define AOFF_BUFFER_START      6
-#define AOFF_BUFFER_END        8
-#define AOFF_GETP              10
-#define AOFF_PUTP              12
-#define AOFF_IOV               14
-#define AOFF_COUNT             16
-#define AOFF_OVERFLOW          18
-#define AOFF_BUFFER_SIZE       20
-#define AOFF_OVFLUSHES                 22
-
-
-static ASYNC_STRUCT a;         /* Copy in our mem of the struct */
-static long aindex;            /* index into dos space of struct */
-
-static int go32_open PARAMS ((serial_t scb, const char *name));
-static void go32_raw PARAMS ((serial_t scb));
-static int go32_readchar PARAMS ((serial_t scb, int timeout));
-static int go32_setbaudrate PARAMS ((serial_t scb, int rate));
-static int go32_write PARAMS ((serial_t scb, const char *str, int len));
-static void go32_close PARAMS ((serial_t scb));
-static serial_ttystate go32_get_tty_state PARAMS ((serial_t scb));
-static int go32_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
-static unsigned char aptr PARAMS ((short p));
-static unsigned long getivec PARAMS ((int which));
-static int dos_async_init PARAMS ((int port));
-static void dos_async_tx PARAMS ((const char c));
-static int dos_async_rx PARAMS (());
-static int dosasync_read PARAMS ((int fd, char *buf, int len, int timeout));
-static int dosasync_write PARAMS ((int fd, const char *buf, int len));
-
-#define SIGNATURE 0x4154
-#define VERSION 1
-#define OFFSET 0x104
-
-char packet[50];
-int packet_len;
-int packet_idx;
-
-unsigned char bb;
-unsigned short sb;
-unsigned long sl;
-
-#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_LONG(x)     ( dosmemget((x),4,&sl), sl)
-
-static
-unsigned short
-GET_WORD (x)
-{
-  unsigned short sb;
-  dosmemget ((x), 2, &sb);
-  return sb;
-}
+#define COUNT(x) cnts[x]++
+#else
+#define COUNT(x) 
+#endif
 
-static int iov[2];
+/* Main interrupt controller port addresses. */
+#define ICU_BASE       0x20
+#define ICU_OCW2       (ICU_BASE + 0)
+#define ICU_MASK       (ICU_BASE + 1)
 
-#define com_rb(n)      iov[n]
-#define com_tb(n)      iov[n]
-#define com_ier(n)     iov[n]+1
-#define com_ifr(n)     iov[n]+2
-#define com_bfr(n)     iov[n]+3
-#define com_mcr(n)     iov[n]+4
-#define com_lsr(n)     iov[n]+5
-#define com_msr(n)     iov[n]+6
+/* Original interrupt controller mask register. */
+unsigned char  icu_oldmask;
 
-static unsigned char
-aptr (p)
-     short p;
-{
-  return GET_BYTE (aindex - OFFSET + p);
-}
+/* Maximum of 8 interrupts (we don't handle the slave icu yet). */
+#define NINTR  8
+
+static struct intrupt
+{  
+  char                 inuse;
+  struct dos_ttystate  *port;
+  _go32_dpmi_seginfo   old_rmhandler;
+  _go32_dpmi_seginfo   old_pmhandler;
+  _go32_dpmi_seginfo   new_rmhandler;
+  _go32_dpmi_seginfo   new_pmhandler;
+  _go32_dpmi_registers regs;
+} intrupts[NINTR];
 
-static unsigned long
-getivec (int which)
+
+static struct dos_ttystate
 {
-  long tryaindex;
+  int          base;
+  int          irq;
+  struct intrupt *intrupt;
+  int          fifo;
+  int          baudrate;
+  unsigned char        cbuf[CBSIZE];
+  unsigned int first;
+  unsigned int count;
+  int          txbusy;
+  unsigned char        old_mcr;
+  int          ferr;
+  int          perr;
+  int          oflo;
+  int          msr;
+} ports[4] = {
+  {COM1ADDR, 4}, 
+  {COM2ADDR, 3}, 
+  {COM3ADDR, 4}, 
+  {COM4ADDR, 3}
+};
 
-  if (GET_WORD (which * 4) != OFFSET)
-    return 0;
+static int dos_open PARAMS ((serial_t scb, const char *name));
+static void dos_raw PARAMS ((serial_t scb));
+static int dos_readchar PARAMS ((serial_t scb, int timeout));
+static int dos_setbaudrate PARAMS ((serial_t scb, int rate));
+static int dos_write PARAMS ((serial_t scb, const char *str, int len));
+static void dos_close PARAMS ((serial_t scb));
+static serial_ttystate dos_get_tty_state PARAMS ((serial_t scb));
+static int dos_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+static int dos_baudconv PARAMS ((int rate));
 
-  /* Find out where in memory this lives */
-  tryaindex = GET_WORD (which * 4 + 2) * 16 + GET_WORD (which * 4);
+#define inb(p,a)       inportb((p)->base + (a))
+#define outb(p,a,v)    outportb((p)->base + (a), (v))
+#define disable()      asm volatile ("cli");
+#define enable()       asm volatile ("sti");
 
-  if (GET_WORD (tryaindex + 2) != SIGNATURE)
-    return 0;
-  if (GET_WORD (tryaindex + 4) != VERSION)
-    return 0;
-  return tryaindex;
-}
 
 static int
-dos_async_init (port)
-     int port;
+dos_getc (port)
+     volatile struct dos_ttystate *port;
 {
-  switch (port)
-    {
-    case 1:
-      aindex = getivec (12);
-      break;
-    case 2:
-      aindex = getivec (11);
-      break;
-    default:
-      return 0;
-    }
+    int c;
 
-  if (!aindex)
-    {
-      error ("GDB cannot connect to asynctsr program, check that it is installed\n\
-and that serial I/O is not being redirected (perhaps by NFS)\n\n\
-example configuration:\n\
-C> mode com%d:9600,n,8,1,p\n\
-C> asynctsr %d\n\
-C> gdb \n", port, port);
-    }
+    if (port->count == 0)
+      return -1;
 
-  iov[0] = GET_WORD (aindex + AOFF_IOV);
-  outportb (com_ier (0), 0x0f);
-  outportb (com_bfr (0), 0x03);
-  outportb (com_mcr (0), 0x0b);
-  return 1;
+    c = port->cbuf[port->first];
+    disable ();
+    port->first = (port->first + 1) & (CBSIZE - 1);
+    port->count--;
+    enable ();
+    return c;
 }
+    
 
-static void
-dos_async_tx (c)
-     const char c;
+static int 
+dos_putc (c, port)
+     int c;
+     struct dos_ttystate *port;
 {
-  while (~inportb (com_lsr (0)) & 0x20)
-    ;
-  outportb (com_tb (0), c);
+    if (port->count >= CBSIZE - 1)
+       return -1;
+    port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
+    port->count++;
+    return 0;
 }
 
-static int
-dos_async_ready ()
-{
-  int ret;
+\f
 
-  if (packet_idx < packet_len)
-    return 1;
+static void
+dos_comisr (irq)
+     int irq;
+{
+  struct dos_ttystate *port;
+  unsigned char iir, lsr, c;
 
-  disable ();
-#if RDY_CNT
-  ret = GET_WORD (aindex + AOFF_COUNT);
-#else
-  ret = GET_WORD (aindex + AOFF_GETP) != GET_WORD (aindex + AOFF_PUTP);
+  disable ();                  /* Paranoia */
+  outportb (ICU_OCW2, 0x20);   /* End-Of-Interrupt */
+#ifdef DOS_STATS
+  ++intrcnt;
 #endif
-  enable ();
-  return ret;
-
-
-}
 
-static int
-dos_async_rx ()
-{
-  char rv;
-  short idx;
+  port = intrupts[irq].port;
+  if (!port) 
+    {
+      COUNT (CNT_STRAY);
+      return;          /* not open */
+    }
 
   while (1)
     {
-      if (packet_idx < packet_len)
-       {
-         char x = packet[packet_idx++];
-         return x;
-       }
-      while (!dos_async_ready ())
+      iir = inb (port, com_iir) & IIR_IMASK;
+      switch (iir) 
        {
-         if (kbhit ())
+         
+       case IIR_RLS:
+         lsr = inb (port, com_lsr);
+         goto rx;
+         
+       case IIR_RXTOUT:
+       case IIR_RXRDY:
+         lsr = 0;
+         
+      rx:
+         do 
            {
-             printf_unfiltered ("abort!\n");
-             return 0;
+             c = inb (port, com_data);
+             if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
+               {
+                 if (lsr & (LSR_BI | LSR_FE))
+                   port->ferr++;
+                 else if (lsr & LSR_PE)
+                   port->perr++;
+                 if (lsr & LSR_OE)
+                   port->oflo++;
+               }
+
+             if (dos_putc (c & 0x7f, port) < 0)
+               {
+                 COUNT (CNT_ORUN);
+               }
+             else
+               {
+                 COUNT (CNT_RX);
+               }
            }
+         while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
+         break;
+         
+       case IIR_MLSC:
+         /* could be used to flowcontrol Tx */
+         port->msr = inb (port, com_msr);
+         break;
+         
+       case IIR_TXRDY:
+         port->txbusy = 0;
+         break;
+
+       case IIR_NOPEND:
+         /* no more pending interrupts, all done */
+         return;
+
+       default:
+         /* unexpected interrupt, ignore */
+         break;
        }
-      disable ();
-      {
-       /* Sometimes we can read more than one char at a time
-        from the buffer, which is good, cause it'll mean
-        less time with interrupts turned off, which means
-        less dropped characters */
+      COUNT (iir);
+    } 
+}
 
-       /* We only do the simplest case here - not bothering with
-          wrap around */
-       int len;
+#ifdef __STDC__
+#define ISRNAME(x) dos_comisr##x
+#else
+#define ISRNAME(x) dos_comisr/**/x
+#endif
+#define ISR(x) static void ISRNAME(x)() {dos_comisr(x);}
 
-       int getp = GET_WORD (aindex + AOFF_GETP);
-       int putp = GET_WORD (aindex + AOFF_PUTP);
-       int endb = GET_WORD (aindex + AOFF_BUFFER_END);
-       int startb = GET_WORD (aindex + AOFF_BUFFER_START);
+ISR(0) ISR(1) ISR(2) ISR(3)
+ISR(4) ISR(5) ISR(6) ISR(7)
 
-       /* We'd like to grab to the end of the the input,
-        but it may have wrapped, so max is to the end
-        of the buffer */
+typedef void (*isr_t)();
 
-       if (putp > endb || putp < getp)
-         putp = endb;
+static isr_t isrs[NINTR] = {
+  ISRNAME(0), ISRNAME(1), ISRNAME(2), ISRNAME(3),
+  ISRNAME(4), ISRNAME(5), ISRNAME(6), ISRNAME(7)
+};
 
-       /* Work out the length of the suck */
-       len = putp - getp;
+\f
 
-       /* But only suck as many as we can hold in one go */
-       if (len > sizeof (packet))
-         len = sizeof (packet);
+static struct intrupt *
+dos_hookirq (irq)
+     unsigned int irq;
+{
+  struct intrupt *intr;
+  unsigned int vec;
+  isr_t isr;
 
-       dosmemget (aindex - OFFSET + getp, len, packet);
+  if (irq >= NINTR)
+    return 0;
 
-       packet_len = len;
-       packet_idx = 0;
+  intr = &intrupts[irq];
+  if (intr->inuse)
+    return 0;
+  
+  vec = 0x08 + irq;
+  isr = isrs[irq];
 
-       if (getp + len >= endb)
-         {
-           getp = startb;
-         }
-       else
-         {
-           getp = getp + len;
-         }
+  /* setup real mode handler */
+  _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
 
-       SET_WORD (aindex + AOFF_GETP, getp);
-       SET_WORD (aindex + AOFF_COUNT, GET_WORD (aindex + AOFF_COUNT) - len);
-      }
-      enable ();
+  intr->new_rmhandler.pm_selector = _go32_my_cs();
+  intr->new_rmhandler.pm_offset = (u_long)isr;
+  if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
+                                                  &intr->regs))
+    {
+      return 0;
     }
-}
 
+  if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
+    {
+      return 0;
+    }
+      
+  /* setup protected mode handler */
+  _go32_dpmi_get_protected_mode_interrupt_vector(vec, &intr->old_pmhandler);
 
-static int
-dosasync_read (fd, buf, len, timeout)
-     int fd;
-     char *buf;
-     int len;
-     int timeout;
-{
-  long now, then;
-  int i;
-  int its = 0;
-  time (&now);
-  then = now + timeout;
+  intr->new_pmhandler.pm_selector = _go32_my_cs();
+  intr->new_pmhandler.pm_offset = (u_long)isr;
+  _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
 
-  for (i = 0; i < len; i++)
+  if (_go32_dpmi_set_protected_mode_interrupt_vector(vec, &intr->new_pmhandler))
     {
-      if (timeout)
-       {
-         while (!dos_async_ready ())
-           {
-             time (&now);
-             if (now >= then && timeout > 0 && its > 1000)
-               return i;
-             its++;
-           }
-       }
-      *buf++ = dos_async_rx ();
+      return 0;
     }
-  return len;
+
+  /* setup interrupt controller mask */
+  disable ();
+  outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
+  enable ();
+
+  intr->inuse = 1;
+  return intr;
 }
 
-static int
-dosasync_write (fd, buf, len)
-     int fd;
-     const char *buf;
-     int len;
+
+static void
+dos_unhookirq (intr)
+     struct intrupt *intr;
 {
-  int l;
+  unsigned int irq, vec;
+  unsigned char mask;
 
-  for (l = 0; l < len; l++)
-    dos_async_tx (*buf++);
+  irq = intr - intrupts;
+  vec = 0x08 + irq;
 
-  return len;
+  /* restore old interrupt mask bit */
+  mask = 1 << irq;
+  disable ();
+  outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
+  enable ();
+
+  /* remove real mode handler */
+  _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
+  _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
+      
+  /* remove protected mode handler */
+  _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
+  _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
+  intr->inuse = 0;
 }
 
+\f
+
 static int
-go32_open (scb, name)
+dos_open (scb, name)
      serial_t scb;
      const char *name;
 {
-  int port;
+  struct dos_ttystate *port;
+  int fd, i;
+
+  if (strncasecmp (name, "/dev/", 5) == 0)
+    name += 5;
+  else if (strncasecmp (name, "\\dev\\", 5) == 0)
+    name += 5;
 
-  if (strncasecmp (name, "com", 3) != 0)
+  if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
     {
       errno = ENOENT;
       return -1;
     }
 
-  port = name[3] - '0';
-
-  if ((port != 1) && (port != 2))
+  if (name[3] < '1' || name[3] > '4')
     {
       errno = ENOENT;
-      return -11;
+      return -1;
     }
 
-  scb->fd = dos_async_init (port);
-  if (!scb->fd)
-    return -1;
+  fd = name[3] - '1';
+  port = &ports[fd];
+  if (port->intrupt)
+    {
+      /* already open (EBUSY not defined!) */
+      errno = EACCES;
+      return -1;
+    }
+
+  /* force access to ID reg */
+  outb(port, com_cfcr, 0);
+  outb(port, com_iir, 0);
+  for (i = 0; i < 17; i++) {
+    if ((inb(port, com_iir) & 0x38) == 0)
+      goto ok;
+    (void) inb(port, com_data); /* clear recv */
+  }
+  errno = ENODEV;
+  return -1;
+
+ok:
+  /* disable all interrupts in chip */
+  outb(port, com_ier, 0);
+
+  /* tentatively enable 16550 fifo, and see if it responds */
+  outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER);
+  sleep(1);
+  port->fifo = ((inb(port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
+
+  /* clear pending status reports. */
+  (void) inb(port, com_lsr);
+  (void) inb(port, com_msr);
+
+  /* enable external interrupt gate (to avoid floating IRQ) */
+  outb(port, com_mcr, MCR_IENABLE);
+
+  /* hook up interrupt handler and initialise icu */
+  port->intrupt = dos_hookirq (port->irq);
+  if (!port->intrupt)
+    {
+      outb(port, com_mcr, 0);
+      outb(port, com_fifo, 0);
+      errno = ENODEV;
+      return -1;
+    }
+
+  disable ();
+
+  /* record port */
+  port->intrupt->port = port; 
+  scb->fd = fd;
+
+  /* clear rx buffer, tx busy flag and overflow count */
+  port->first = port->count = 0;
+  port->txbusy = 0;
+  port->oflo = 0;
+
+  /* set default baud rate and mode: 9600,8,n,1 */
+  i = dos_baudconv (port->baudrate = 9600);
+  outb(port, com_cfcr, CFCR_DLAB);
+  outb(port, com_dlbl, i & 0xff);
+  outb(port, com_dlbh, i >> 8);
+  outb(port, com_cfcr, CFCR_8BITS);
+
+  /* enable all interrupts */
+  outb(port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
+
+  /* enable DTR & RTS */
+  outb(port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
+
+  enable ();
 
   return 0;
 }
 
+
+static void
+dos_close (scb)
+     serial_t scb;
+{
+    struct dos_ttystate *port = &ports[scb->fd];
+    struct intrupt *intrupt;
+
+    if (!(intrupt = port->intrupt))
+      return;
+
+    /* disable interrupts, fifo, flow control */
+    disable ();
+    port->intrupt = 0;
+    intrupt->port = 0;
+    outb(port, com_fifo, 0);
+    outb(port, com_ier, 0);
+    enable ();
+
+    /* unhook handler, and disable interrupt gate */
+    dos_unhookirq (intrupt);
+    outb(port, com_mcr, 0);
+
+    /* Check for overflow errors */
+    if (port->oflo)
+      {
+       fprintf_unfiltered (gdb_stderr,
+                           "Serial input overruns occurred.\n");
+       fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
+                           port->fifo ? "cannot" : "needs a 16550 to",
+                           port->baudrate);
+      }
+}
+
+\f
+
 static int
-go32_noop (scb)
+dos_noop (scb)
      serial_t scb;
 {
   return 0;
 }
 
 static void
-go32_raw (scb)
+dos_raw (scb)
      serial_t scb;
 {
   /* Always in raw mode */
 }
 
 static int
-go32_readchar (scb, timeout)
+dos_readchar (scb, timeout)
      serial_t scb;
      int timeout;
 {
-  char buf;
+  struct dos_ttystate *port = &ports[scb->fd];
+  long then;
+  int c;
 
-  /* Shortcut for polling */
-  if (timeout == 0)
+  then = rawclock() + (timeout * RAWHZ);
+  while ((c = dos_getc (port)) < 0)
     {
-      if (dos_async_ready ())
-       {
-         return dos_async_rx ();
-       }
-      return SERIAL_TIMEOUT;
+      if (timeout >= 0 && (rawclock () - then) >= 0)
+       return SERIAL_TIMEOUT;
+      notice_quit ();
     }
 
-  if (dosasync_read (scb->fd, &buf, 1, timeout))
-    return buf;
-  else
-    return SERIAL_TIMEOUT;
+  return c;
 }
 
-/* go32_{get set}_tty_state() are both dummys to fill out the function
-   vector.  Someday, they may do something real... */
 
 static serial_ttystate
-go32_get_tty_state (scb)
+dos_get_tty_state (scb)
      serial_t scb;
 {
-  struct go32_ttystate *state;
-
-  state = (struct go32_ttystate *) xmalloc (sizeof *state);
+  struct dos_ttystate *port = &ports[scb->fd];
+  struct dos_ttystate *state;
 
+  state = (struct dos_ttystate *) xmalloc (sizeof *state);
+  *state = *port;
   return (serial_ttystate) state;
 }
 
 static int
-go32_set_tty_state (scb, ttystate)
+dos_set_tty_state (scb, ttystate)
      serial_t scb;
      serial_ttystate ttystate;
 {
+  struct dos_ttystate *state;
+
+  state = (struct dos_ttystate *) ttystate;
+  dos_setbaudrate (scb, state->baudrate);
   return 0;
 }
 
 static int
-go32_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
+dos_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
      serial_t scb;
      serial_ttystate new_ttystate;
      serial_ttystate old_ttystate;
 {
+  struct dos_ttystate *state;
+
+  state = (struct dos_ttystate *) new_ttystate;
+  dos_setbaudrate (scb, state->baudrate);
   return 0;
 }
 
+static int
+dos_flush_input (scb)
+     serial_t scb;
+{
+  struct dos_ttystate *port = &ports[scb->fd];
+  disable();
+  port->first = port->count = 0;
+  if (port->fifo)
+    outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_TRIGGER);
+  enable();
+}
+
 static void
-go32_print_tty_state (scb, ttystate)
+dos_print_tty_state (scb, ttystate)
      serial_t scb;
      serial_ttystate ttystate;
 {
-  /* Nothing to print */
+  /* Nothing to print */
   return;
 }
 
 static int
-go32_setbaudrate (scb, rate)
-     serial_t scb;
+dos_baudconv (rate)
      int rate;
 {
-  return 0;
+  long x, err;
+  
+  if (rate <= 0) 
+    return -1;
+
+#define divrnd(n, q)   (((n) * 2 / (q) + 1) / 2) /* divide and round off */
+  x = divrnd(COMTICK, rate);
+  if (x <= 0)
+    return -1;
+  
+  err = divrnd(1000 * COMTICK, x * rate) - 1000;
+  if (err < 0)
+    err = -err;
+  if (err > SPEED_TOLERANCE)
+    return -1;
+#undef divrnd
+  return x;
 }
 
+
 static int
-go32_write (scb, str, len)
+dos_setbaudrate (scb, rate)
      serial_t scb;
-     const char *str;
-     int len;
+     int rate;
 {
-  dosasync_write (scb->fd, str, len);
+    struct dos_ttystate *port = &ports[scb->fd];
 
-  return 0;
+    if (port->baudrate != rate) 
+      {
+       int x;
+
+       x = dos_baudconv (rate);
+       if (x <= 0)
+         {
+           fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
+           errno = EINVAL;
+           return -1;
+         }
+
+       disable ();
+       outb(port, com_cfcr, CFCR_DLAB);
+       outb(port, com_dlbl, x & 0xff);
+       outb(port, com_dlbh, x >> 8);
+       outb(port, com_cfcr, CFCR_8BITS);
+       port->baudrate = rate;
+       enable ();
+      }
+
+    return 0;
 }
 
-static void
-go32_close (scb)
+
+static int
+dos_write (scb, str, len)
      serial_t scb;
+     const char *str;
+     int len;
 {
+  volatile struct dos_ttystate *port = &ports[scb->fd];
+  int fifosize = port->fifo ? 16 : 1;
+  long then;
+  int cnt;
+
+   while (len > 0) 
+     {
+       /* send the data, fifosize bytes at a time */
+       cnt = fifosize > len ? len : fifosize;
+       port->txbusy = 1;
+       outportsb (port->base + com_data, str, cnt);
+       str += cnt;
+       len -= cnt;
+#ifdef DOS_STATS
+       cnts[CNT_TX] += cnt;
+#endif
+       /* wait for transmission to complete (max 1 sec) */
+       then = rawclock() + RAWHZ;
+       while (port->txbusy)
+         {
+           if ((rawclock () - then) >= 0)
+             {
+                 errno = EIO;
+                 return SERIAL_ERROR;
+             }
+         }
+    }
+  return 0;
 }
 
-static struct serial_ops go32_ops =
+static struct serial_ops dos_ops =
 {
   "hardwire",
   0,
-  go32_open,
-  go32_close,
-  go32_readchar,
-  go32_write,
-  go32_noop,                   /* flush output */
-  go32_noop,                   /* flush input */
-  go32_noop,                   /* send break -- currently used only for nindy */
-  go32_raw,
-  go32_get_tty_state,
-  go32_set_tty_state,
-  go32_print_tty_state,
-  go32_noflush_set_tty_state,
-  go32_setbaudrate,
+  dos_open,
+  dos_close,
+  dos_readchar,
+  dos_write,
+  dos_noop,                    /* flush output */
+  dos_flush_input,
+  dos_noop,                    /* send break -- currently used only for nindy */
+  dos_raw,
+  dos_get_tty_state,
+  dos_set_tty_state,
+  dos_print_tty_state,
+  dos_noflush_set_tty_state,
+  dos_setbaudrate,
 };
 
+
+static void
+dos_info (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct dos_ttystate *port;
+  int i;
+
+  for (port = ports; port < &ports[4]; port++) 
+    {
+      if (port->baudrate == 0)
+       continue;
+      printf_filtered ("Port:\tCOM%d (%sactive)\n", port - ports,
+                      port->intrupt ? "" : "not ");
+      printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
+      printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
+      printf_filtered ("Speed:\t%d baud\n", port->baudrate);
+      printf_filtered ("Errs:\tframing %d parity %d overflow %d\n", 
+                      port->ferr, port->perr, port->oflo);
+    }
+
+#ifdef DOS_STATS
+  printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
+  for (i = 0; i < NCNT; i++)
+    if (cnts[i])
+      printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
+#endif
+}
+
+
 void
-_initialize_ser_go32 ()
+_initialize_ser_dos ()
 {
-  serial_add_interface (&go32_ops);
+  struct cmd_list_element *c;
+
+  serial_add_interface (&dos_ops);
+
+  /* Save original interrupt mask register. */
+  icu_oldmask = inportb (ICU_MASK);
+
+  /* Mark fixed motherboard irqs as inuse. */
+  intrupts[0].inuse =          /* timer tick */
+    intrupts[1].inuse =                /* keyboard */
+      intrupts[2].inuse = 1;   /* slave icu */
+    
+  add_show_from_set (
+    add_set_cmd ("com1base", class_obscure, var_zinteger,
+                (char *) &ports[0].base,
+                "Set COM1 base i/o port address.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com1irq", class_obscure, var_zinteger,
+                (char *) &ports[0].irq,
+                "Set COM1 interrupt request.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com2base", class_obscure, var_zinteger,
+                (char *) &ports[1].base,
+                "Set COM2 base i/o port address.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com2irq", class_obscure, var_zinteger,
+                (char *) &ports[1].irq,
+                "Set COM2 interrupt request.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com3base", class_obscure, var_zinteger,
+                (char *) &ports[2].base,
+                "Set COM3 base i/o port address.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com3irq", class_obscure, var_zinteger,
+                (char *) &ports[2].irq,
+                "Set COM3 interrupt request.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com4base", class_obscure, var_zinteger,
+                (char *) &ports[3].base,
+                "Set COM4 base i/o port address.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("com4irq", class_obscure, var_zinteger,
+                (char *) &ports[3].irq,
+                "Set COM4 interrupt request.",
+                &setlist),
+       &showlist);
+
+  add_info ("serial", dos_info,
+           "Print DOS serial port status.");
 }