home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / gdb-4.14-src.lha / gdb-4.14 / gdb / ser-go32.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-01  |  20.4 KB  |  921 lines

  1. /* Remote serial interface for local (hardwired) serial ports for
  2.    GO32.  Copyright 1992, 1993 Free Software Foundation, Inc.
  3.  
  4.    Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
  5.  
  6.    This version uses DPMI interrupts to handle buffered i/o 
  7.    without the separate "asynctsr" program.
  8.  
  9.    This file is part of GDB.  
  10.  
  11.    This program is free software; you can redistribute it and/or modify
  12.    it under the terms of the GNU General Public License as published by
  13.    the Free Software Foundation; either version 2 of the License, or
  14.    (at your option) any later version.
  15.  
  16.    This program is distributed in the hope that it will be useful,
  17.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.    GNU General Public License for more details.
  20.  
  21.    You should have received a copy of the GNU General Public License
  22.    along with this program; if not, write to the Free Software
  23.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24.  
  25. #include "defs.h"
  26. #include "gdbcmd.h"
  27. #include "serial.h"
  28.  
  29.  
  30. /*
  31.  * NS16550 UART registers
  32.  */
  33.  
  34. #define COM1ADDR    0x3f8
  35. #define COM2ADDR    0x2f8
  36. #define COM3ADDR    0x3e8
  37. #define COM4ADDR    0x3e0
  38.  
  39. #define    com_data    0    /* data register (R/W) */
  40. #define    com_dlbl    0    /* divisor latch low (W) */
  41. #define    com_ier        1    /* interrupt enable (W) */
  42. #define    com_dlbh    1    /* divisor latch high (W) */
  43. #define    com_iir        2    /* interrupt identification (R) */
  44. #define    com_fifo    2    /* FIFO control (W) */
  45. #define    com_lctl    3    /* line control register (R/W) */
  46. #define    com_cfcr    3    /* line control register (R/W) */
  47. #define    com_mcr        4    /* modem control register (R/W) */
  48. #define    com_lsr        5    /* line status register (R/W) */
  49. #define    com_msr        6    /* modem status register (R/W) */
  50.  
  51. /*
  52.  * Constants for computing 16 bit baud rate divisor (lower byte
  53.  * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal.  Divisor is
  54.  * 1.8432 MHz / (16 * X) for X bps.  If the baud rate can't be set
  55.  * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
  56.  */
  57. #define COMTICK        (1843200/16)
  58. #define SPEED_TOLERANCE    30    /* thousandths; real == desired +- 3.0% */
  59.  
  60. /* interrupt enable register */
  61. #define    IER_ERXRDY    0x1    /* int on rx ready */
  62. #define    IER_ETXRDY    0x2    /* int on tx ready */
  63. #define    IER_ERLS    0x4    /* int on line status change */
  64. #define    IER_EMSC    0x8    /* int on modem status change */
  65.  
  66. /* interrupt identification register */
  67. #define    IIR_FIFO_MASK    0xc0    /* set if FIFOs are enabled */
  68. #define    IIR_IMASK    0xf    /* interrupt cause mask */
  69. #define    IIR_NOPEND    0x1    /* nothing pending */
  70. #define    IIR_RLS        0x6    /* receive line status */
  71. #define    IIR_RXRDY    0x4    /* receive ready */
  72. #define    IIR_RXTOUT    0xc    /* receive timeout */
  73. #define    IIR_TXRDY    0x2    /* transmit ready */
  74. #define    IIR_MLSC    0x0    /* modem status */
  75.  
  76.  
  77. /* fifo control register */
  78. #define    FIFO_ENABLE    0x01    /* enable fifo */
  79. #define    FIFO_RCV_RST    0x02    /* reset receive fifo */
  80. #define    FIFO_XMT_RST    0x04    /* reset transmit fifo */
  81. #define    FIFO_DMA_MODE    0x08    /* enable dma mode */
  82. #define    FIFO_TRIGGER_1    0x00    /* trigger at 1 char */
  83. #define    FIFO_TRIGGER_4    0x40    /* trigger at 4 chars */
  84. #define    FIFO_TRIGGER_8    0x80    /* trigger at 8 chars */
  85. #define    FIFO_TRIGGER_14    0xc0    /* trigger at 14 chars */
  86.  
  87. /* character format control register */
  88. #define    CFCR_DLAB    0x80    /* divisor latch */
  89. #define    CFCR_SBREAK    0x40    /* send break */
  90. #define    CFCR_PZERO    0x30    /* zero parity */
  91. #define    CFCR_PONE    0x20    /* one parity */
  92. #define    CFCR_PEVEN    0x10    /* even parity */
  93. #define    CFCR_PODD    0x00    /* odd parity */
  94. #define    CFCR_PENAB    0x08    /* parity enable */
  95. #define    CFCR_STOPB    0x04    /* 2 stop bits */
  96. #define    CFCR_8BITS    0x03    /* 8 data bits */
  97. #define    CFCR_7BITS    0x02    /* 7 data bits */
  98. #define    CFCR_6BITS    0x01    /* 6 data bits */
  99. #define    CFCR_5BITS    0x00    /* 5 data bits */
  100.  
  101. /* modem control register */
  102. #define    MCR_LOOPBACK    0x10    /* loopback */
  103. #define    MCR_IENABLE    0x08    /* output 2 = int enable */
  104. #define    MCR_DRS        0x04    /* output 1 = xxx */
  105. #define    MCR_RTS        0x02    /* enable RTS */
  106. #define    MCR_DTR        0x01    /* enable DTR */
  107.  
  108. /* line status register */
  109. #define    LSR_RCV_FIFO    0x80    /* error in receive fifo */
  110. #define    LSR_TSRE    0x40    /* transmitter empty */
  111. #define    LSR_TXRDY    0x20    /* transmitter ready */
  112. #define    LSR_BI        0x10    /* break detected */
  113. #define    LSR_FE        0x08    /* framing error */
  114. #define    LSR_PE        0x04    /* parity error */
  115. #define    LSR_OE        0x02    /* overrun error */
  116. #define    LSR_RXRDY    0x01    /* receiver ready */
  117. #define    LSR_RCV_MASK    0x1f
  118.  
  119. /* modem status register */
  120. #define    MSR_DCD        0x80
  121. #define    MSR_RI        0x40
  122. #define    MSR_DSR        0x20
  123. #define    MSR_CTS        0x10
  124. #define    MSR_DDCD    0x08
  125. #define    MSR_TERI    0x04
  126. #define    MSR_DDSR    0x02
  127. #define    MSR_DCTS    0x01
  128.  
  129. #include <sys/dos.h>
  130. #include <sys/go32.h>
  131. #include <sys/dpmi.h>
  132.  
  133. /* DPMI Communication */
  134. static union REGS dpmi_regs;
  135. static struct SREGS dpmi_sregs;
  136.  
  137. /* 16550 rx fifo trigger point */
  138. #define FIFO_TRIGGER    FIFO_TRIGGER_4
  139.  
  140. /* input buffer size */
  141. #define CBSIZE    4096
  142.  
  143. /* return raw 18Hz clock count */
  144. extern long rawclock (void);
  145.  
  146. #define RAWHZ    18
  147.  
  148. #ifdef DOS_STATS
  149. #define CNT_RX        16
  150. #define CNT_TX        17
  151. #define CNT_STRAY    18
  152. #define CNT_ORUN    19
  153. #define NCNT        20
  154.  
  155. static int    intrcnt;
  156. static int    cnts[NCNT];
  157. static char    *cntnames[NCNT] = {
  158.   /* h/w interrupt counts. */
  159.   "mlsc",    "nopend",    "txrdy",    "?3",
  160.   "rxrdy",    "?5",        "rls",         "?7", 
  161.   "?8",     "?9",         "?a",         "?b", 
  162.   "rxtout",     "?d",         "?e",        "?f", 
  163.   /* s/w counts. */
  164.   "rxcnt",    "txcnt",    "stray",    "swoflo"
  165. };
  166.  
  167. #define COUNT(x) cnts[x]++
  168. #else
  169. #define COUNT(x) 
  170. #endif
  171.  
  172. /* Main interrupt controller port addresses. */
  173. #define ICU_BASE    0x20
  174. #define ICU_OCW2    (ICU_BASE + 0)
  175. #define ICU_MASK    (ICU_BASE + 1)
  176.  
  177. /* Original interrupt controller mask register. */
  178. unsigned char    icu_oldmask;
  179.  
  180. /* Maximum of 8 interrupts (we don't handle the slave icu yet). */
  181. #define NINTR    8
  182.  
  183. static struct intrupt
  184. {  
  185.   char            inuse;
  186.   struct dos_ttystate    *port;
  187.   _go32_dpmi_seginfo    old_rmhandler;
  188.   _go32_dpmi_seginfo    old_pmhandler;
  189.   _go32_dpmi_seginfo    new_rmhandler;
  190.   _go32_dpmi_seginfo    new_pmhandler;
  191.   _go32_dpmi_registers    regs;
  192. } intrupts[NINTR];
  193.  
  194.  
  195. static struct dos_ttystate
  196. {
  197.   int        base;
  198.   int        irq;
  199.   struct intrupt *intrupt;
  200.   int        fifo;
  201.   int        baudrate;
  202.   unsigned char    cbuf[CBSIZE];
  203.   unsigned int    first;
  204.   unsigned int    count;
  205.   int        txbusy;
  206.   unsigned char    old_mcr;
  207.   int        ferr;
  208.   int        perr;
  209.   int        oflo;
  210.   int        msr;
  211. } ports[4] = {
  212.   {COM1ADDR, 4}, 
  213.   {COM2ADDR, 3}, 
  214.   {COM3ADDR, 4}, 
  215.   {COM4ADDR, 3}
  216. };
  217.  
  218. static int dos_open PARAMS ((serial_t scb, const char *name));
  219. static void dos_raw PARAMS ((serial_t scb));
  220. static int dos_readchar PARAMS ((serial_t scb, int timeout));
  221. static int dos_setbaudrate PARAMS ((serial_t scb, int rate));
  222. static int dos_write PARAMS ((serial_t scb, const char *str, int len));
  223. static void dos_close PARAMS ((serial_t scb));
  224. static serial_ttystate dos_get_tty_state PARAMS ((serial_t scb));
  225. static int dos_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
  226. static int dos_baudconv PARAMS ((int rate));
  227.  
  228. #define inb(p,a)    inportb((p)->base + (a))
  229. #define outb(p,a,v)    outportb((p)->base + (a), (v))
  230. #define disable()    asm volatile ("cli");
  231. #define enable()    asm volatile ("sti");
  232.  
  233.  
  234. static int
  235. dos_getc (port)
  236.      volatile struct dos_ttystate *port;
  237. {
  238.     int c;
  239.  
  240.     if (port->count == 0)
  241.       return -1;
  242.  
  243.     c = port->cbuf[port->first];
  244.     disable ();
  245.     port->first = (port->first + 1) & (CBSIZE - 1);
  246.     port->count--;
  247.     enable ();
  248.     return c;
  249. }
  250.     
  251.  
  252. static int 
  253. dos_putc (c, port)
  254.      int c;
  255.      struct dos_ttystate *port;
  256. {
  257.     if (port->count >= CBSIZE - 1)
  258.     return -1;
  259.     port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
  260.     port->count++;
  261.     return 0;
  262. }
  263.  
  264.  
  265.  
  266. static void
  267. dos_comisr (irq)
  268.      int irq;
  269. {
  270.   struct dos_ttystate *port;
  271.   unsigned char iir, lsr, c;
  272.  
  273.   disable ();            /* Paranoia */
  274.   outportb (ICU_OCW2, 0x20);    /* End-Of-Interrupt */
  275. #ifdef DOS_STATS
  276.   ++intrcnt;
  277. #endif
  278.  
  279.   port = intrupts[irq].port;
  280.   if (!port) 
  281.     {
  282.       COUNT (CNT_STRAY);
  283.       return;        /* not open */
  284.     }
  285.  
  286.   while (1)
  287.     {
  288.       iir = inb (port, com_iir) & IIR_IMASK;
  289.       switch (iir) 
  290.     {
  291.       
  292.     case IIR_RLS:
  293.       lsr = inb (port, com_lsr);
  294.       goto rx;
  295.       
  296.     case IIR_RXTOUT:
  297.     case IIR_RXRDY:
  298.       lsr = 0;
  299.       
  300.       rx:
  301.       do 
  302.         {
  303.           c = inb (port, com_data);
  304.           if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
  305.         {
  306.           if (lsr & (LSR_BI | LSR_FE))
  307.             port->ferr++;
  308.           else if (lsr & LSR_PE)
  309.             port->perr++;
  310.           if (lsr & LSR_OE)
  311.             port->oflo++;
  312.         }
  313.  
  314.           if (dos_putc (c & 0x7f, port) < 0)
  315.         {
  316.           COUNT (CNT_ORUN);
  317.         }
  318.           else
  319.         {
  320.           COUNT (CNT_RX);
  321.         }
  322.         }
  323.       while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
  324.       break;
  325.       
  326.     case IIR_MLSC:
  327.       /* could be used to flowcontrol Tx */
  328.       port->msr = inb (port, com_msr);
  329.       break;
  330.       
  331.     case IIR_TXRDY:
  332.       port->txbusy = 0;
  333.       break;
  334.  
  335.     case IIR_NOPEND:
  336.       /* no more pending interrupts, all done */
  337.       return;
  338.  
  339.     default:
  340.       /* unexpected interrupt, ignore */
  341.       break;
  342.     }
  343.       COUNT (iir);
  344.     } 
  345. }
  346.  
  347. #ifdef __STDC__
  348. #define ISRNAME(x) dos_comisr##x
  349. #else
  350. #define ISRNAME(x) dos_comisr/**/x
  351. #endif
  352. #define ISR(x) static void ISRNAME(x)() {dos_comisr(x);}
  353.  
  354. ISR(0) ISR(1) ISR(2) ISR(3)
  355. ISR(4) ISR(5) ISR(6) ISR(7)
  356.  
  357. typedef void (*isr_t)();
  358.  
  359. static isr_t isrs[NINTR] = {
  360.   ISRNAME(0), ISRNAME(1), ISRNAME(2), ISRNAME(3),
  361.   ISRNAME(4), ISRNAME(5), ISRNAME(6), ISRNAME(7)
  362. };
  363.  
  364.  
  365.  
  366. static struct intrupt *
  367. dos_hookirq (irq)
  368.      unsigned int irq;
  369. {
  370.   struct intrupt *intr;
  371.   unsigned int vec;
  372.   isr_t isr;
  373.  
  374.   if (irq >= NINTR)
  375.     return 0;
  376.  
  377.   intr = &intrupts[irq];
  378.   if (intr->inuse)
  379.     return 0;
  380.   
  381.   vec = 0x08 + irq;
  382.   isr = isrs[irq];
  383.  
  384.   /* setup real mode handler */
  385.   _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
  386.  
  387.   intr->new_rmhandler.pm_selector = _go32_my_cs();
  388.   intr->new_rmhandler.pm_offset = (u_long)isr;
  389.   if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
  390.                            &intr->regs))
  391.     {
  392.       return 0;
  393.     }
  394.  
  395.   if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
  396.     {
  397.       return 0;
  398.     }
  399.       
  400.   /* setup protected mode handler */
  401.   _go32_dpmi_get_protected_mode_interrupt_vector(vec, &intr->old_pmhandler);
  402.  
  403.   intr->new_pmhandler.pm_selector = _go32_my_cs();
  404.   intr->new_pmhandler.pm_offset = (u_long)isr;
  405.   _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
  406.  
  407.   if (_go32_dpmi_set_protected_mode_interrupt_vector(vec, &intr->new_pmhandler))
  408.     {
  409.       return 0;
  410.     }
  411.  
  412.   /* setup interrupt controller mask */
  413.   disable ();
  414.   outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
  415.   enable ();
  416.  
  417.   intr->inuse = 1;
  418.   return intr;
  419. }
  420.  
  421.  
  422. static void
  423. dos_unhookirq (intr)
  424.      struct intrupt *intr;
  425. {
  426.   unsigned int irq, vec;
  427.   unsigned char mask;
  428.  
  429.   irq = intr - intrupts;
  430.   vec = 0x08 + irq;
  431.  
  432.   /* restore old interrupt mask bit */
  433.   mask = 1 << irq;
  434.   disable ();
  435.   outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
  436.   enable ();
  437.  
  438.   /* remove real mode handler */
  439.   _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
  440.   _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
  441.       
  442.   /* remove protected mode handler */
  443.   _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
  444.   _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
  445.   intr->inuse = 0;
  446. }
  447.  
  448.  
  449.  
  450. static int
  451. dos_open (scb, name)
  452.      serial_t scb;
  453.      const char *name;
  454. {
  455.   struct dos_ttystate *port;
  456.   int fd, i;
  457.  
  458.   if (strncasecmp (name, "/dev/", 5) == 0)
  459.     name += 5;
  460.   else if (strncasecmp (name, "\\dev\\", 5) == 0)
  461.     name += 5;
  462.  
  463.   if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
  464.     {
  465.       errno = ENOENT;
  466.       return -1;
  467.     }
  468.  
  469.   if (name[3] < '1' || name[3] > '4')
  470.     {
  471.       errno = ENOENT;
  472.       return -1;
  473.     }
  474.  
  475.   fd = name[3] - '1';
  476.   port = &ports[fd];
  477.   if (port->intrupt)
  478.     {
  479.       /* already open (EBUSY not defined!) */
  480.       errno = EACCES;
  481.       return -1;
  482.     }
  483.  
  484.   /* force access to ID reg */
  485.   outb(port, com_cfcr, 0);
  486.   outb(port, com_iir, 0);
  487.   for (i = 0; i < 17; i++) {
  488.     if ((inb(port, com_iir) & 0x38) == 0)
  489.       goto ok;
  490.     (void) inb(port, com_data); /* clear recv */
  491.   }
  492.   errno = ENODEV;
  493.   return -1;
  494.  
  495. ok:
  496.   /* disable all interrupts in chip */
  497.   outb(port, com_ier, 0);
  498.  
  499.   /* tentatively enable 16550 fifo, and see if it responds */
  500.   outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER);
  501.   sleep(1);
  502.   port->fifo = ((inb(port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
  503.  
  504.   /* clear pending status reports. */
  505.   (void) inb(port, com_lsr);
  506.   (void) inb(port, com_msr);
  507.  
  508.   /* enable external interrupt gate (to avoid floating IRQ) */
  509.   outb(port, com_mcr, MCR_IENABLE);
  510.  
  511.   /* hook up interrupt handler and initialise icu */
  512.   port->intrupt = dos_hookirq (port->irq);
  513.   if (!port->intrupt)
  514.     {
  515.       outb(port, com_mcr, 0);
  516.       outb(port, com_fifo, 0);
  517.       errno = ENODEV;
  518.       return -1;
  519.     }
  520.  
  521.   disable ();
  522.  
  523.   /* record port */
  524.   port->intrupt->port = port; 
  525.   scb->fd = fd;
  526.  
  527.   /* clear rx buffer, tx busy flag and overflow count */
  528.   port->first = port->count = 0;
  529.   port->txbusy = 0;
  530.   port->oflo = 0;
  531.  
  532.   /* set default baud rate and mode: 9600,8,n,1 */
  533.   i = dos_baudconv (port->baudrate = 9600);
  534.   outb(port, com_cfcr, CFCR_DLAB);
  535.   outb(port, com_dlbl, i & 0xff);
  536.   outb(port, com_dlbh, i >> 8);
  537.   outb(port, com_cfcr, CFCR_8BITS);
  538.  
  539.   /* enable all interrupts */
  540.   outb(port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
  541.  
  542.   /* enable DTR & RTS */
  543.   outb(port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
  544.  
  545.   enable ();
  546.  
  547.   return 0;
  548. }
  549.  
  550.  
  551. static void
  552. dos_close (scb)
  553.      serial_t scb;
  554. {
  555.     struct dos_ttystate *port;
  556.     struct intrupt *intrupt;
  557.  
  558.     if (!scb)
  559.       return;
  560.  
  561.     port = &ports[scb->fd];
  562.     if (!(intrupt = port->intrupt))
  563.       return;
  564.  
  565.     /* disable interrupts, fifo, flow control */
  566.     disable ();
  567.     port->intrupt = 0;
  568.     intrupt->port = 0;
  569.     outb(port, com_fifo, 0);
  570.     outb(port, com_ier, 0);
  571.     enable ();
  572.  
  573.     /* unhook handler, and disable interrupt gate */
  574.     dos_unhookirq (intrupt);
  575.     outb(port, com_mcr, 0);
  576.  
  577.     /* Check for overflow errors */
  578.     if (port->oflo)
  579.       {
  580.     fprintf_unfiltered (gdb_stderr,
  581.                 "Serial input overruns occurred.\n");
  582.     fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
  583.                 port->fifo ? "cannot" : "needs a 16550 to",
  584.                 port->baudrate);
  585.       }
  586. }
  587.  
  588.  
  589.  
  590. static int
  591. dos_noop (scb)
  592.      serial_t scb;
  593. {
  594.   return 0;
  595. }
  596.  
  597. static void
  598. dos_raw (scb)
  599.      serial_t scb;
  600. {
  601.   /* Always in raw mode */
  602. }
  603.  
  604. static int
  605. dos_readchar (scb, timeout)
  606.      serial_t scb;
  607.      int timeout;
  608. {
  609.   struct dos_ttystate *port = &ports[scb->fd];
  610.   long then;
  611.   int c;
  612.  
  613.   then = rawclock() + (timeout * RAWHZ);
  614.   while ((c = dos_getc (port)) < 0)
  615.     {
  616.       if (timeout >= 0 && (rawclock () - then) >= 0)
  617.     return SERIAL_TIMEOUT;
  618.       notice_quit ();
  619.     }
  620.  
  621.   return c;
  622. }
  623.  
  624.  
  625. static serial_ttystate
  626. dos_get_tty_state (scb)
  627.      serial_t scb;
  628. {
  629.   struct dos_ttystate *port = &ports[scb->fd];
  630.   struct dos_ttystate *state;
  631.  
  632.   state = (struct dos_ttystate *) xmalloc (sizeof *state);
  633.   *state = *port;
  634.   return (serial_ttystate) state;
  635. }
  636.  
  637. static int
  638. dos_set_tty_state (scb, ttystate)
  639.      serial_t scb;
  640.      serial_ttystate ttystate;
  641. {
  642.   struct dos_ttystate *state;
  643.  
  644.   state = (struct dos_ttystate *) ttystate;
  645.   dos_setbaudrate (scb, state->baudrate);
  646.   return 0;
  647. }
  648.  
  649. static int
  650. dos_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
  651.      serial_t scb;
  652.      serial_ttystate new_ttystate;
  653.      serial_ttystate old_ttystate;
  654. {
  655.   struct dos_ttystate *state;
  656.  
  657.   state = (struct dos_ttystate *) new_ttystate;
  658.   dos_setbaudrate (scb, state->baudrate);
  659.   return 0;
  660. }
  661.  
  662. static int
  663. dos_flush_input (scb)
  664.      serial_t scb;
  665. {
  666.   struct dos_ttystate *port = &ports[scb->fd];
  667.   disable();
  668.   port->first = port->count = 0;
  669.   if (port->fifo)
  670.     outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_TRIGGER);
  671.   enable();
  672. }
  673.  
  674. static void
  675. dos_print_tty_state (scb, ttystate)
  676.      serial_t scb;
  677.      serial_ttystate ttystate;
  678. {
  679.   /* Nothing to print */
  680.   return;
  681. }
  682.  
  683. static int
  684. dos_baudconv (rate)
  685.      int rate;
  686. {
  687.   long x, err;
  688.   
  689.   if (rate <= 0) 
  690.     return -1;
  691.  
  692. #define divrnd(n, q)    (((n) * 2 / (q) + 1) / 2) /* divide and round off */
  693.   x = divrnd(COMTICK, rate);
  694.   if (x <= 0)
  695.     return -1;
  696.   
  697.   err = divrnd(1000 * COMTICK, x * rate) - 1000;
  698.   if (err < 0)
  699.     err = -err;
  700.   if (err > SPEED_TOLERANCE)
  701.     return -1;
  702. #undef divrnd
  703.   return x;
  704. }
  705.  
  706.  
  707. static int
  708. dos_setbaudrate (scb, rate)
  709.      serial_t scb;
  710.      int rate;
  711. {
  712.     struct dos_ttystate *port = &ports[scb->fd];
  713.  
  714.     if (port->baudrate != rate) 
  715.       {
  716.     int x;
  717.  
  718.     x = dos_baudconv (rate);
  719.     if (x <= 0)
  720.       {
  721.         fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
  722.         errno = EINVAL;
  723.         return -1;
  724.       }
  725.  
  726.     disable ();
  727.     outb(port, com_cfcr, CFCR_DLAB);
  728.     outb(port, com_dlbl, x & 0xff);
  729.     outb(port, com_dlbh, x >> 8);
  730.     outb(port, com_cfcr, CFCR_8BITS);
  731.     port->baudrate = rate;
  732.     enable ();
  733.       }
  734.  
  735.     return 0;
  736. }
  737.  
  738.  
  739. static int
  740. dos_write (scb, str, len)
  741.      serial_t scb;
  742.      const char *str;
  743.      int len;
  744. {
  745.   volatile struct dos_ttystate *port = &ports[scb->fd];
  746.   int fifosize = port->fifo ? 16 : 1;
  747.   long then;
  748.   int cnt;
  749.  
  750.    while (len > 0) 
  751.      {
  752.     /* send the data, fifosize bytes at a time */
  753.     cnt = fifosize > len ? len : fifosize;
  754.     port->txbusy = 1;
  755.     outportsb (port->base + com_data, str, cnt);
  756.     str += cnt;
  757.     len -= cnt;
  758. #ifdef DOS_STATS
  759.     cnts[CNT_TX] += cnt;
  760. #endif
  761.     /* wait for transmission to complete (max 1 sec) */
  762.     then = rawclock() + RAWHZ;
  763.     while (port->txbusy)
  764.       {
  765.         if ((rawclock () - then) >= 0)
  766.           {
  767.           errno = EIO;
  768.           return SERIAL_ERROR;
  769.           }
  770.       }
  771.     }
  772.   return 0;
  773. }
  774.  
  775.  
  776. static int
  777. dos_sendbreak (scb)
  778.      serial_t scb;
  779. {
  780.   volatile struct dos_ttystate *port = &ports[scb->fd];
  781.   unsigned char cfcr;
  782.   long then;
  783.  
  784.   cfcr = inb(port, com_cfcr);
  785.   outb(port, com_cfcr, cfcr | CFCR_SBREAK);
  786.  
  787.   /* 0.25 sec delay */
  788.   then = rawclock () + RAWHZ / 4;
  789.   while ((rawclock () - then) < 0)
  790.     continue;
  791.  
  792.   outb(port, com_cfcr, cfcr);
  793.   return 0;
  794. }
  795.  
  796.  
  797. static struct serial_ops dos_ops =
  798. {
  799.   "hardwire",
  800.   0,
  801.   dos_open,
  802.   dos_close,
  803.   dos_readchar,
  804.   dos_write,
  805.   dos_noop,            /* flush output */
  806.   dos_flush_input,
  807.   dos_sendbreak,
  808.   dos_raw,
  809.   dos_get_tty_state,
  810.   dos_set_tty_state,
  811.   dos_print_tty_state,
  812.   dos_noflush_set_tty_state,
  813.   dos_setbaudrate,
  814. };
  815.  
  816.  
  817. static void
  818. dos_info (arg, from_tty)
  819.      char *arg;
  820.      int from_tty;
  821. {
  822.   struct dos_ttystate *port;
  823.   int i;
  824.  
  825.   for (port = ports; port < &ports[4]; port++) 
  826.     {
  827.       if (port->baudrate == 0)
  828.     continue;
  829.       printf_filtered ("Port:\tCOM%d (%sactive)\n", port - ports + 1,
  830.                port->intrupt ? "" : "not ");
  831.       printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
  832.       printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
  833.       printf_filtered ("Speed:\t%d baud\n", port->baudrate);
  834.       printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n", 
  835.                port->ferr, port->perr, port->oflo);
  836.     }
  837.  
  838. #ifdef DOS_STATS
  839.   printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
  840.   for (i = 0; i < NCNT; i++)
  841.     if (cnts[i])
  842.       printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
  843. #endif
  844. }
  845.  
  846.  
  847. void
  848. _initialize_ser_dos ()
  849. {
  850.   struct cmd_list_element *c;
  851.  
  852.   serial_add_interface (&dos_ops);
  853.  
  854.   /* Save original interrupt mask register. */
  855.   icu_oldmask = inportb (ICU_MASK);
  856.  
  857.   /* Mark fixed motherboard irqs as inuse. */
  858.   intrupts[0].inuse =        /* timer tick */
  859.     intrupts[1].inuse =        /* keyboard */
  860.       intrupts[2].inuse = 1;    /* slave icu */
  861.     
  862.   add_show_from_set (
  863.     add_set_cmd ("com1base", class_obscure, var_zinteger,
  864.          (char *) &ports[0].base,
  865.          "Set COM1 base i/o port address.",
  866.          &setlist),
  867.     &showlist);
  868.  
  869.   add_show_from_set (
  870.     add_set_cmd ("com1irq", class_obscure, var_zinteger,
  871.          (char *) &ports[0].irq,
  872.          "Set COM1 interrupt request.",
  873.          &setlist),
  874.     &showlist);
  875.  
  876.   add_show_from_set (
  877.     add_set_cmd ("com2base", class_obscure, var_zinteger,
  878.          (char *) &ports[1].base,
  879.          "Set COM2 base i/o port address.",
  880.          &setlist),
  881.     &showlist);
  882.  
  883.   add_show_from_set (
  884.     add_set_cmd ("com2irq", class_obscure, var_zinteger,
  885.          (char *) &ports[1].irq,
  886.          "Set COM2 interrupt request.",
  887.          &setlist),
  888.     &showlist);
  889.  
  890.   add_show_from_set (
  891.     add_set_cmd ("com3base", class_obscure, var_zinteger,
  892.          (char *) &ports[2].base,
  893.          "Set COM3 base i/o port address.",
  894.          &setlist),
  895.     &showlist);
  896.  
  897.   add_show_from_set (
  898.     add_set_cmd ("com3irq", class_obscure, var_zinteger,
  899.          (char *) &ports[2].irq,
  900.          "Set COM3 interrupt request.",
  901.          &setlist),
  902.     &showlist);
  903.  
  904.   add_show_from_set (
  905.     add_set_cmd ("com4base", class_obscure, var_zinteger,
  906.          (char *) &ports[3].base,
  907.          "Set COM4 base i/o port address.",
  908.          &setlist),
  909.     &showlist);
  910.  
  911.   add_show_from_set (
  912.     add_set_cmd ("com4irq", class_obscure, var_zinteger,
  913.          (char *) &ports[3].irq,
  914.          "Set COM4 interrupt request.",
  915.          &setlist),
  916.     &showlist);
  917.  
  918.   add_info ("serial", dos_info,
  919.         "Print DOS serial port status.");
  920. }
  921.