gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / ser-go32.c
index 5b3ad9064a8a55f265b040e5b470b9bd2f64190e..9a5b6dcd0e45acfc144c57922288e4fd63915294 100644 (file)
 /* Remote serial interface for local (hardwired) serial ports for GO32.
-   Copyright 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1992-2020 Free Software Foundation, Inc.
 
-This file is part of GDB.
+   Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
 
-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 version uses DPMI interrupts to handle buffered i/o
+   without the separate "asynctsr" program.
 
-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.
+   This file is part of GDB.
 
-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.  */
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "gdbcmd.h"
 #include "serial.h"
-#include <sys/dos.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 <time.h>
+#include <dos.h>
+#include <go32.h>
+#include <dpmi.h>
+typedef unsigned long u_long;
+
+/* 16550 rx fifo trigger point */
+#define FIFO_TRIGGER   FIFO_TRIGGER_4
+
+/* input buffer size */
+#define CBSIZE 4096
+
+#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 size_t 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"
+};
 
-/* This is unused for now.  We just return a placeholder. */
-struct go32_ttystate
+#define COUNT(x) cnts[x]++
+#else
+#define COUNT(x)
+#endif
+
+/* Main interrupt controller port addresses.  */
+#define ICU_BASE       0x20
+#define ICU_OCW2       (ICU_BASE + 0)
+#define ICU_MASK       (ICU_BASE + 1)
+
+/* Original interrupt controller mask register.  */
+unsigned char icu_oldmask;
+
+/* 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 struct dos_ttystate
+  {
+    int base;
+    int irq;
+    int refcnt;
+    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] =
 {
-  int bogus;
+  {
+    COM1ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+  }
+  ,
+  {
+    COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+  }
+  ,
+  {
+    COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+  }
+  ,
+  {
+    COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+  }
 };
 
-typedef struct {
-  short jmp_op;
-  short signature;
-  short version;
-  short buffer_start;
-  short buffer_end;
-  short getp;
-  short putp;
-  short iov;
-} ASYNC_STRUCT;
-
-static int go32_open PARAMS ((serial_t scb, const char *name));
-static void go32_raw PARAMS ((serial_t scb));
-static int wait_for PARAMS ((serial_t scb, int timeout));
-static int go32_readchar PARAMS ((serial_t scb, int timeout));
-static int rate_to_code PARAMS ((int rate));
-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_restore PARAMS ((serial_t scb));
-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 int strncasecmp PARAMS ((char *str1, char *str2, int len));
-static char *aptr PARAMS ((short p));
-static ASYNC_STRUCT *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_ready PARAMS (());
-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
-
-#define peek(a,b) (*(unsigned short *)(0xe0000000 + (a)*16 + (b)))
-
-static ASYNC_STRUCT *async;
-static int iov;
-#define com_rb iov
-#define com_tb iov
-#define com_ier        iov+1
-#define com_ifr        iov+2
-#define com_bfr        iov+3
-#define com_mcr        iov+4
-#define com_lsr        iov+5
-#define com_msr        iov+6
+static int dos_open (struct serial *scb, const char *name);
+static void dos_raw (struct serial *scb);
+static int dos_readchar (struct serial *scb, int timeout);
+static int dos_setbaudrate (struct serial *scb, int rate);
+static int dos_write (struct serial *scb, const void *buf, size_t count);
+static void dos_close (struct serial *scb);
+static serial_ttystate dos_get_tty_state (struct serial *scb);
+static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
+static int dos_baudconv (int rate);
+
+#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");
+
 
 static int
-strncasecmp(str1, str2, len)
-     char *str1, *str2;
-     register int len;
+dos_getc (volatile struct dos_ttystate *port)
 {
-  unsigned char c1, c2;
+  int c;
 
-  for (; len != 0; --len)
-    {
-      c1 = *str1++;
-      c2 = *str2++;
+  if (port->count == 0)
+    return -1;
+
+  c = port->cbuf[port->first];
+  disable ();
+  port->first = (port->first + 1) & (CBSIZE - 1);
+  port->count--;
+  enable ();
+  return c;
+}
 
-      if (toupper(c1) != toupper(c2))
-       return toupper(c1) - toupper(c2);
 
-      if (c1 == '\0')
-       return 0;
-    }
+static int
+dos_putc (int c, struct dos_ttystate *port)
+{
+  if (port->count >= CBSIZE - 1)
+    return -1;
+  port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
+  port->count++;
   return 0;
 }
+\f
+
 
-static char *
-aptr(p)
-     short p;
+static void
+dos_comisr (int irq)
 {
-  return (char *)((unsigned)async - OFFSET + p);
+  struct dos_ttystate *port;
+  unsigned char iir, lsr, c;
+
+  disable ();                  /* Paranoia */
+  outportb (ICU_OCW2, 0x20);   /* End-Of-Interrupt */
+#ifdef DOS_STATS
+  ++intrcnt;
+#endif
+
+  port = intrupts[irq].port;
+  if (!port)
+    {
+      COUNT (CNT_STRAY);
+      return;                  /* not open */
+    }
+
+  while (1)
+    {
+      iir = inb (port, com_iir) & IIR_IMASK;
+      switch (iir)
+       {
+
+       case IIR_RLS:
+         lsr = inb (port, com_lsr);
+         goto rx;
+
+       case IIR_RXTOUT:
+       case IIR_RXRDY:
+         lsr = 0;
+
+       rx:
+         do
+           {
+             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, 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;
+       }
+      COUNT (iir);
+    }
 }
 
-static ASYNC_STRUCT *
-getivec(int which)
-{
-  ASYNC_STRUCT *a;
+#define ISRNAME(x) dos_comisr##x
+#define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
 
-  if (peek(0, which*4) != OFFSET)
-    return 0;
+ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
+ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
 
-  a = (ASYNC_STRUCT *)(0xe0000000 + peek(0, which*4+2)*16 + peek(0, which*4));
+typedef void (*isr_t) (void);
 
-  if (a->signature != SIGNATURE)
+static isr_t isrs[NINTR] =
+  {
+       ISRNAME (0), ISRNAME (1), ISRNAME (2), ISRNAME (3),
+       ISRNAME (4), ISRNAME (5), ISRNAME (6), ISRNAME (7)
+  };
+\f
+
+
+static struct intrupt *
+dos_hookirq (unsigned int irq)
+{
+  struct intrupt *intr;
+  unsigned int vec;
+  isr_t isr;
+
+  if (irq >= NINTR)
     return 0;
 
-  if (a->version != VERSION)
+  intr = &intrupts[irq];
+  if (intr->inuse)
     return 0;
 
-  return a;
+  vec = 0x08 + irq;
+  isr = isrs[irq];
+
+  /* Setup real mode handler.  */
+  _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
+
+  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);
+
+  intr->new_pmhandler.pm_selector = _go32_my_cs ();
+  intr->new_pmhandler.pm_offset = (u_long) isr;
+  _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
+
+  if (_go32_dpmi_set_protected_mode_interrupt_vector (vec,
+                                                     &intr->new_pmhandler))
+    {
+      return 0;
+    }
+
+  /* Setup interrupt controller mask.  */
+  disable ();
+  outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
+  enable ();
+
+  intr->inuse = 1;
+  return intr;
+}
+
+
+static void
+dos_unhookirq (struct intrupt *intr)
+{
+  unsigned int irq, vec;
+  unsigned char mask;
+
+  irq = intr - intrupts;
+  vec = 0x08 + irq;
+
+  /* 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
-dos_async_init(port)
-     int port;
+dos_open (struct serial *scb, const char *name)
 {
-  int i;
+  struct dos_ttystate *port;
+  int fd, i;
+
+  if (strncasecmp (name, "/dev/", 5) == 0)
+    name += 5;
+  else if (strncasecmp (name, "\\dev\\", 5) == 0)
+    name += 5;
 
-  switch (port)
+  if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
     {
-    case 1:
-      async = getivec (12);
-      break;
-    case 2:
-      async = getivec (11);
-      break;
-    default:
+      errno = ENOENT;
+      return -1;
+    }
+
+  if (name[3] < '1' || name[3] > '4')
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  /* FIXME: this is a Bad Idea (tm)!  One should *never* invent file
+     handles, since they might be already used by other files/devices.
+     The Right Way to do this is to create a real handle by dup()'ing
+     some existing one.  */
+  fd = name[3] - '1';
+  port = &ports[fd];
+  if (port->refcnt++ > 0)
+    {
+      /* Device already opened another user.  Just point at it.  */
+      scb->fd = fd;
       return 0;
     }
 
-  if (!async)
+  /* Force access to ID reg.  */
+  outb (port, com_cfcr, 0);
+  outb (port, com_iir, 0);
+  for (i = 0; i < 17; i++)
     {
-      error("GDB can not 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 com2:9600,n,8,1,p\n\
-C> asynctsr 2\n\
-C> gdb \n");
+      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;
     }
 
-  iov = async->iov;
-  outportb(com_ier, 0x0f);
-  outportb(com_bfr, 0x03);
-  outportb(com_mcr, 0x0b);
-  async->getp = async->putp = async->buffer_start;
-  
-  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_async_tx(c)
-     const char c;
+dos_close (struct serial *scb)
 {
-  while (~inportb(com_lsr) & 0x20);
+  struct dos_ttystate *port;
+  struct intrupt *intrupt;
+
+  if (!scb)
+    return;
 
-  outportb(com_tb, c);
+  port = &ports[scb->fd];
+
+  if (port->refcnt-- > 1)
+    return;
+
+  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
+
+/* Implementation of the serial_ops flush_output method.  */
 
 static int
-dos_async_ready()
+dos_flush_output (struct serial *scb)
 {
-  return (async->getp != async->putp);
+  return 0;
 }
 
+/* Implementation of the serial_ops setparity method.  */
+
 static int
-dos_async_rx()
+dos_setparity (struct serial *scb, int parity)
 {
-  char rv;
+  return 0;
+}
 
-  while (!dos_async_ready())
-    if (kbhit())
-      {
-       printf("abort!\n");
-       return 0;
-      }
+/* Implementation of the serial_ops drain_output method.  */
 
-  rv = *aptr(async->getp++);
-  if (async->getp >= async->buffer_end)
-    async->getp = async->buffer_start;
+static int
+dos_drain_output (struct serial *scb)
+{
+  return 0;
+}
 
-  return rv;
+static void
+dos_raw (struct serial *scb)
+{
+  /* Always in raw mode.  */
 }
 
 static int
-dosasync_read (fd, buf, len, timeout)
-     int fd;
-     char *buf;
-     int len;
-     int timeout;
+dos_readchar (struct serial *scb, int timeout)
 {
-  long now, then;
-  int l = len;
+  struct dos_ttystate *port = &ports[scb->fd];
+  long then;
+  int c;
 
-  time (&now);
-  then = now + timeout;
-
-  while (l--)
+  then = rawclock () + (timeout * RAWHZ);
+  while ((c = dos_getc (port)) < 0)
     {
-      if (timeout)
-       {
-         while (!dos_async_ready())
-           {
-             time (&now);
-             if (now >= then)
-               return len - l - 1;
-           }
-       }
-      *buf++ = dos_async_rx();
+      QUIT;
+
+      if (timeout >= 0 && (rawclock () - then) >= 0)
+       return SERIAL_TIMEOUT;
     }
 
-  return len;
+  return c;
 }
 
-static int
-dosasync_write(fd, buf, len)
-     int fd;
-     const char *buf;
-     int len;
+
+static serial_ttystate
+dos_get_tty_state (struct serial *scb)
 {
-  int l = len;
+  struct dos_ttystate *port = &ports[scb->fd];
+  struct dos_ttystate *state;
 
-  while (l--)
-    dos_async_tx (*buf++);
+  /* Are they asking about a port we opened?  */
+  if (port->refcnt <= 0)
+    {
+      /* We've never heard about this port.  We should fail this call,
+        unless they are asking about one of the 3 standard handles,
+        in which case we pretend the handle was open by us if it is
+        connected to a terminal device.  This is because Unix
+        terminals use the serial interface, so GDB expects the
+        standard handles to go through here.  */
+      if (scb->fd >= 3 || !isatty (scb->fd))
+       return NULL;
+    }
 
-  return len;
+  state = XNEW (struct dos_ttystate);
+  *state = *port;
+  return (serial_ttystate) state;
 }
 
-static int
-go32_open (scb, name)
-     serial_t scb;
-     const char *name;
+static serial_ttystate
+dos_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
 {
-  int port;
+  struct dos_ttystate *state;
 
-  if (strncasecmp (name, "com", 3) != 0)
-    {
-      errno = ENOENT;
-      return -1;
-    }
+  state = XNEW (struct dos_ttystate);
+  *state = *(struct dos_ttystate *) ttystate;
 
-  port = name[3] - '0';
+  return (serial_ttystate) state;
+}
 
-  if ((port != 1) && (port != 2))
-    {
-      errno = ENOENT;
-      return -11;
-    }
+static int
+dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+  struct dos_ttystate *state;
 
-  scb->fd = dos_async_init(port);
-  if (!scb->fd)
-    return -1;
+  state = (struct dos_ttystate *) ttystate;
+  dos_setbaudrate (scb, state->baudrate);
+  return 0;
+}
+
+static int
+dos_flush_input (struct serial *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 ();
   return 0;
 }
 
 static void
-go32_raw (scb)
-     serial_t scb;
+dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
+                    struct ui_file *stream)
 {
-  /* Always in raw mode */
+  /* Nothing to print.  */
+  return;
 }
 
 static int
-go32_readchar (scb, timeout)
-     serial_t scb;
-     int timeout;
+dos_baudconv (int rate)
 {
-  char buf;
+  long x, err;
 
-  if (dosasync_read(scb->fd, &buf, 1, timeout))  
-    return buf;
-  else
-    return SERIAL_TIMEOUT;
+  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;
 }
 
-/* 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)
-     serial_t scb;
+static int
+dos_setbaudrate (struct serial *scb, int rate)
 {
-  struct go32_ttystate *state;
+  struct dos_ttystate *port = &ports[scb->fd];
+
+  if (port->baudrate != rate)
+    {
+      int x;
+      unsigned char cfcr;
+
+      x = dos_baudconv (rate);
+      if (x <= 0)
+       {
+         fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
+         errno = EINVAL;
+         return -1;
+       }
 
-  state = (struct go32_ttystate *)xmalloc(sizeof *state);
+      disable ();
+      cfcr = inb (port, com_cfcr);
 
-  return (serial_ttystate)state;
+      outb (port, com_cfcr, CFCR_DLAB);
+      outb (port, com_dlbl, x & 0xff);
+      outb (port, com_dlbh, x >> 8);
+      outb (port, com_cfcr, cfcr);
+      port->baudrate = rate;
+      enable ();
+    }
+
+  return 0;
 }
 
 static int
-go32_set_tty_state(scb, ttystate)
-     serial_t scb;
-     serial_ttystate ttystate;
+dos_setstopbits (struct serial *scb, int num)
 {
-  struct go32_ttystate *state;
+  struct dos_ttystate *port = &ports[scb->fd];
+  unsigned char cfcr;
+
+  disable ();
+  cfcr = inb (port, com_cfcr);
+
+  switch (num)
+    {
+    case SERIAL_1_STOPBITS:
+      outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
+      break;
+    case SERIAL_1_AND_A_HALF_STOPBITS:
+    case SERIAL_2_STOPBITS:
+      outb (port, com_cfcr, cfcr | CFCR_STOPB);
+      break;
+    default:
+      enable ();
+      return 1;
+    }
+  enable ();
 
   return 0;
 }
 
 static int
-go32_setbaudrate (scb, rate)
-     serial_t scb;
-     int rate;
+dos_write (struct serial *scb, const void *buf, size_t count)
 {
+  volatile struct dos_ttystate *port = &ports[scb->fd];
+  size_t fifosize = port->fifo ? 16 : 1;
+  long then;
+  size_t cnt;
+  const char *str = (const char *) buf;
+
+  while (count > 0)
+    {
+      QUIT;
+
+      /* Send the data, fifosize bytes at a time.  */
+      cnt = fifosize > count ? count : fifosize;
+      port->txbusy = 1;
+      /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
+        up the communications with UARTs with FIFOs.  */
+#ifdef UART_FIFO_WORKS
+      outportsb (port->base + com_data, str, cnt);
+      str += cnt;
+      count -= cnt;
+#else
+      for ( ; cnt > 0; cnt--, count--)
+       outportb (port->base + com_data, *str++);
+#endif
+#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 int
-go32_write (scb, str, len)
-     serial_t scb;
-     const char *str;
-     int len;
+dos_sendbreak (struct serial *scb)
 {
-  dosasync_write(scb->fd, str, len);
+  volatile struct dos_ttystate *port = &ports[scb->fd];
+  unsigned char cfcr;
+  long then;
 
+  cfcr = inb (port, com_cfcr);
+  outb (port, com_cfcr, cfcr | CFCR_SBREAK);
+
+  /* 0.25 sec delay */
+  then = rawclock () + RAWHZ / 4;
+  while ((rawclock () - then) < 0)
+    continue;
+
+  outb (port, com_cfcr, cfcr);
   return 0;
 }
 
-static void
-go32_close (scb)
-     serial_t scb;
-{
-}
 
-static struct serial_ops go32_ops =
+static const struct serial_ops dos_ops =
 {
   "hardwire",
-  0,
-  go32_open,
-  go32_close,
-  go32_readchar,
-  go32_write,
-  go32_raw,
-  go32_get_tty_state,
-  go32_set_tty_state,
-  go32_setbaudrate
+  dos_open,
+  dos_close,
+  NULL,                                /* fdopen, not implemented */
+  dos_readchar,
+  dos_write,
+  dos_flush_output,
+  dos_flush_input,
+  dos_sendbreak,
+  dos_raw,
+  dos_get_tty_state,
+  dos_copy_tty_state,
+  dos_set_tty_state,
+  dos_print_tty_state,
+  dos_setbaudrate,
+  dos_setstopbits,
+  dos_setparity,
+  dos_drain_output,
+  (void (*)(struct serial *, int))NULL /* Change into async mode.  */
 };
 
-_initialize_ser_go32 ()
+int
+gdb_pipe (int pdes[2])
+{
+  /* No support for pipes.  */
+  errno = ENOSYS;
+  return -1;
+}
+
+static void
+info_serial_command (const char *arg, int from_tty)
+{
+  struct dos_ttystate *port;
+#ifdef DOS_STATS
+  int i;
+#endif
+
+  for (port = ports; port < &ports[4]; port++)
+    {
+      if (port->baudrate == 0)
+       continue;
+      printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
+                      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\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%lu\n", cntnames[i], (unsigned long) cnts[i]);
+#endif
+}
+
+void _initialize_ser_dos ();
+void
+_initialize_ser_dos ()
 {
-  serial_add_interface (&go32_ops);
+  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_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
+Set COM1 base i/o port address."), _("\
+Show COM1 base i/o port address."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
+Set COM1 interrupt request."), _("\
+Show COM1 interrupt request."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
+Set COM2 base i/o port address."), _("\
+Show COM2 base i/o port address."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
+Set COM2 interrupt request."), _("\
+Show COM2 interrupt request."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
+Set COM3 base i/o port address."), _("\
+Show COM3 base i/o port address."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
+Set COM3 interrupt request."), _("\
+Show COM3 interrupt request."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
+Set COM4 base i/o port address."), _("\
+Show COM4 base i/o port address."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
+Set COM4 interrupt request."), _("\
+Show COM4 interrupt request."), NULL,
+                           NULL,
+                           NULL, /* FIXME: i18n: */
+                           &setlist, &showlist);
+
+  add_info ("serial", info_serial_command,
+           _("Print DOS serial port status."));
 }
This page took 0.036282 seconds and 4 git commands to generate.