Home | History | Annotate | Line # | Download | only in gdb
ser-go32.c revision 1.1
      1 /* Remote serial interface for local (hardwired) serial ports for GO32.
      2    Copyright (C) 1992-2014 Free Software Foundation, Inc.
      3 
      4    Contributed by Nigel Stephens, Algorithmics Ltd. (nigel (at) 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 3 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, see <http://www.gnu.org/licenses/>.  */
     23 
     24 #include "defs.h"
     25 #include "gdbcmd.h"
     26 #include "serial.h"
     27 #include <string.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 <time.h>
    130 #include <dos.h>
    131 #include <go32.h>
    132 #include <dpmi.h>
    133 typedef unsigned long u_long;
    134 
    135 /* 16550 rx fifo trigger point */
    136 #define FIFO_TRIGGER	FIFO_TRIGGER_4
    137 
    138 /* input buffer size */
    139 #define CBSIZE	4096
    140 
    141 #define RAWHZ	18
    142 
    143 #ifdef DOS_STATS
    144 #define CNT_RX		16
    145 #define CNT_TX		17
    146 #define CNT_STRAY	18
    147 #define CNT_ORUN	19
    148 #define NCNT		20
    149 
    150 static int intrcnt;
    151 static size_t cnts[NCNT];
    152 static char *cntnames[NCNT] =
    153 {
    154   /* h/w interrupt counts.  */
    155   "mlsc", "nopend", "txrdy", "?3",
    156   "rxrdy", "?5", "rls", "?7",
    157   "?8", "?9", "?a", "?b",
    158   "rxtout", "?d", "?e", "?f",
    159   /* s/w counts.  */
    160   "rxcnt", "txcnt", "stray", "swoflo"
    161 };
    162 
    163 #define COUNT(x) cnts[x]++
    164 #else
    165 #define COUNT(x)
    166 #endif
    167 
    168 /* Main interrupt controller port addresses.  */
    169 #define ICU_BASE	0x20
    170 #define ICU_OCW2	(ICU_BASE + 0)
    171 #define ICU_MASK	(ICU_BASE + 1)
    172 
    173 /* Original interrupt controller mask register.  */
    174 unsigned char icu_oldmask;
    175 
    176 /* Maximum of 8 interrupts (we don't handle the slave icu yet).  */
    177 #define NINTR	8
    178 
    179 static struct intrupt
    180   {
    181     char inuse;
    182     struct dos_ttystate *port;
    183     _go32_dpmi_seginfo old_rmhandler;
    184     _go32_dpmi_seginfo old_pmhandler;
    185     _go32_dpmi_seginfo new_rmhandler;
    186     _go32_dpmi_seginfo new_pmhandler;
    187     _go32_dpmi_registers regs;
    188   }
    189 intrupts[NINTR];
    190 
    191 
    192 static struct dos_ttystate
    193   {
    194     int base;
    195     int irq;
    196     int refcnt;
    197     struct intrupt *intrupt;
    198     int fifo;
    199     int baudrate;
    200     unsigned char cbuf[CBSIZE];
    201     unsigned int first;
    202     unsigned int count;
    203     int txbusy;
    204     unsigned char old_mcr;
    205     int ferr;
    206     int perr;
    207     int oflo;
    208     int msr;
    209   }
    210 ports[4] =
    211 {
    212   {
    213     COM1ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
    214   }
    215   ,
    216   {
    217     COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
    218   }
    219   ,
    220   {
    221     COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
    222   }
    223   ,
    224   {
    225     COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
    226   }
    227 };
    228 
    229 static int dos_open (struct serial *scb, const char *name);
    230 static void dos_raw (struct serial *scb);
    231 static int dos_readchar (struct serial *scb, int timeout);
    232 static int dos_setbaudrate (struct serial *scb, int rate);
    233 static int dos_write (struct serial *scb, const void *buf, size_t count);
    234 static void dos_close (struct serial *scb);
    235 static serial_ttystate dos_get_tty_state (struct serial *scb);
    236 static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
    237 static int dos_baudconv (int rate);
    238 
    239 #define inb(p,a)	inportb((p)->base + (a))
    240 #define outb(p,a,v)	outportb((p)->base + (a), (v))
    241 #define disable()	asm volatile ("cli");
    242 #define enable()	asm volatile ("sti");
    243 
    244 
    245 static int
    246 dos_getc (volatile struct dos_ttystate *port)
    247 {
    248   int c;
    249 
    250   if (port->count == 0)
    251     return -1;
    252 
    253   c = port->cbuf[port->first];
    254   disable ();
    255   port->first = (port->first + 1) & (CBSIZE - 1);
    256   port->count--;
    257   enable ();
    258   return c;
    259 }
    260 
    261 
    262 static int
    263 dos_putc (int c, struct dos_ttystate *port)
    264 {
    265   if (port->count >= CBSIZE - 1)
    266     return -1;
    267   port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
    268   port->count++;
    269   return 0;
    270 }
    271 
    272 
    274 
    275 static void
    276 dos_comisr (int irq)
    277 {
    278   struct dos_ttystate *port;
    279   unsigned char iir, lsr, c;
    280 
    281   disable ();			/* Paranoia */
    282   outportb (ICU_OCW2, 0x20);	/* End-Of-Interrupt */
    283 #ifdef DOS_STATS
    284   ++intrcnt;
    285 #endif
    286 
    287   port = intrupts[irq].port;
    288   if (!port)
    289     {
    290       COUNT (CNT_STRAY);
    291       return;			/* not open */
    292     }
    293 
    294   while (1)
    295     {
    296       iir = inb (port, com_iir) & IIR_IMASK;
    297       switch (iir)
    298 	{
    299 
    300 	case IIR_RLS:
    301 	  lsr = inb (port, com_lsr);
    302 	  goto rx;
    303 
    304 	case IIR_RXTOUT:
    305 	case IIR_RXRDY:
    306 	  lsr = 0;
    307 
    308 	rx:
    309 	  do
    310 	    {
    311 	      c = inb (port, com_data);
    312 	      if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
    313 		{
    314 		  if (lsr & (LSR_BI | LSR_FE))
    315 		    port->ferr++;
    316 		  else if (lsr & LSR_PE)
    317 		    port->perr++;
    318 		  if (lsr & LSR_OE)
    319 		    port->oflo++;
    320 		}
    321 
    322 	      if (dos_putc (c, port) < 0)
    323 		{
    324 		  COUNT (CNT_ORUN);
    325 		}
    326 	      else
    327 		{
    328 		  COUNT (CNT_RX);
    329 		}
    330 	    }
    331 	  while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
    332 	  break;
    333 
    334 	case IIR_MLSC:
    335 	  /* could be used to flowcontrol Tx */
    336 	  port->msr = inb (port, com_msr);
    337 	  break;
    338 
    339 	case IIR_TXRDY:
    340 	  port->txbusy = 0;
    341 	  break;
    342 
    343 	case IIR_NOPEND:
    344 	  /* No more pending interrupts, all done.  */
    345 	  return;
    346 
    347 	default:
    348 	  /* Unexpected interrupt, ignore.  */
    349 	  break;
    350 	}
    351       COUNT (iir);
    352     }
    353 }
    354 
    355 #define ISRNAME(x) dos_comisr##x
    356 #define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
    357 
    358 ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
    359 ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
    360 
    361 typedef void (*isr_t) (void);
    362 
    363 static isr_t isrs[NINTR] =
    364   {
    365        ISRNAME (0), ISRNAME (1), ISRNAME (2), ISRNAME (3),
    366        ISRNAME (4), ISRNAME (5), ISRNAME (6), ISRNAME (7)
    367   };
    368 
    369 
    371 
    372 static struct intrupt *
    373 dos_hookirq (unsigned int irq)
    374 {
    375   struct intrupt *intr;
    376   unsigned int vec;
    377   isr_t isr;
    378 
    379   if (irq >= NINTR)
    380     return 0;
    381 
    382   intr = &intrupts[irq];
    383   if (intr->inuse)
    384     return 0;
    385 
    386   vec = 0x08 + irq;
    387   isr = isrs[irq];
    388 
    389   /* Setup real mode handler.  */
    390   _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
    391 
    392   intr->new_rmhandler.pm_selector = _go32_my_cs ();
    393   intr->new_rmhandler.pm_offset = (u_long) isr;
    394   if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
    395 						   &intr->regs))
    396     {
    397       return 0;
    398     }
    399 
    400   if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
    401     {
    402       return 0;
    403     }
    404 
    405   /* Setup protected mode handler.  */
    406   _go32_dpmi_get_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
    407 
    408   intr->new_pmhandler.pm_selector = _go32_my_cs ();
    409   intr->new_pmhandler.pm_offset = (u_long) isr;
    410   _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
    411 
    412   if (_go32_dpmi_set_protected_mode_interrupt_vector (vec,
    413 						      &intr->new_pmhandler))
    414     {
    415       return 0;
    416     }
    417 
    418   /* Setup interrupt controller mask.  */
    419   disable ();
    420   outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
    421   enable ();
    422 
    423   intr->inuse = 1;
    424   return intr;
    425 }
    426 
    427 
    428 static void
    429 dos_unhookirq (struct intrupt *intr)
    430 {
    431   unsigned int irq, vec;
    432   unsigned char mask;
    433 
    434   irq = intr - intrupts;
    435   vec = 0x08 + irq;
    436 
    437   /* Restore old interrupt mask bit.  */
    438   mask = 1 << irq;
    439   disable ();
    440   outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
    441   enable ();
    442 
    443   /* Remove real mode handler.  */
    444   _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
    445   _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
    446 
    447   /* Remove protected mode handler.  */
    448   _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
    449   _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
    450   intr->inuse = 0;
    451 }
    452 
    453 
    455 
    456 static int
    457 dos_open (struct serial *scb, const char *name)
    458 {
    459   struct dos_ttystate *port;
    460   int fd, i;
    461 
    462   if (strncasecmp (name, "/dev/", 5) == 0)
    463     name += 5;
    464   else if (strncasecmp (name, "\\dev\\", 5) == 0)
    465     name += 5;
    466 
    467   if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
    468     {
    469       errno = ENOENT;
    470       return -1;
    471     }
    472 
    473   if (name[3] < '1' || name[3] > '4')
    474     {
    475       errno = ENOENT;
    476       return -1;
    477     }
    478 
    479   /* FIXME: this is a Bad Idea (tm)!  One should *never* invent file
    480      handles, since they might be already used by other files/devices.
    481      The Right Way to do this is to create a real handle by dup()'ing
    482      some existing one.  */
    483   fd = name[3] - '1';
    484   port = &ports[fd];
    485   if (port->refcnt++ > 0)
    486     {
    487       /* Device already opened another user.  Just point at it.  */
    488       scb->fd = fd;
    489       return 0;
    490     }
    491 
    492   /* Force access to ID reg.  */
    493   outb (port, com_cfcr, 0);
    494   outb (port, com_iir, 0);
    495   for (i = 0; i < 17; i++)
    496     {
    497       if ((inb (port, com_iir) & 0x38) == 0)
    498 	goto ok;
    499       (void) inb (port, com_data);	/* clear recv */
    500     }
    501   errno = ENODEV;
    502   return -1;
    503 
    504 ok:
    505   /* Disable all interrupts in chip.  */
    506   outb (port, com_ier, 0);
    507 
    508   /* Tentatively enable 16550 fifo, and see if it responds.  */
    509   outb (port, com_fifo,
    510 	FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER);
    511   sleep (1);
    512   port->fifo = ((inb (port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
    513 
    514   /* clear pending status reports.  */
    515   (void) inb (port, com_lsr);
    516   (void) inb (port, com_msr);
    517 
    518   /* Enable external interrupt gate (to avoid floating IRQ).  */
    519   outb (port, com_mcr, MCR_IENABLE);
    520 
    521   /* Hook up interrupt handler and initialise icu.  */
    522   port->intrupt = dos_hookirq (port->irq);
    523   if (!port->intrupt)
    524     {
    525       outb (port, com_mcr, 0);
    526       outb (port, com_fifo, 0);
    527       errno = ENODEV;
    528       return -1;
    529     }
    530 
    531   disable ();
    532 
    533   /* record port */
    534   port->intrupt->port = port;
    535   scb->fd = fd;
    536 
    537   /* Clear rx buffer, tx busy flag and overflow count.  */
    538   port->first = port->count = 0;
    539   port->txbusy = 0;
    540   port->oflo = 0;
    541 
    542   /* Set default baud rate and mode: 9600,8,n,1 */
    543   i = dos_baudconv (port->baudrate = 9600);
    544   outb (port, com_cfcr, CFCR_DLAB);
    545   outb (port, com_dlbl, i & 0xff);
    546   outb (port, com_dlbh, i >> 8);
    547   outb (port, com_cfcr, CFCR_8BITS);
    548 
    549   /* Enable all interrupts.  */
    550   outb (port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
    551 
    552   /* Enable DTR & RTS.  */
    553   outb (port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
    554 
    555   enable ();
    556 
    557   return 0;
    558 }
    559 
    560 
    561 static void
    562 dos_close (struct serial *scb)
    563 {
    564   struct dos_ttystate *port;
    565   struct intrupt *intrupt;
    566 
    567   if (!scb)
    568     return;
    569 
    570   port = &ports[scb->fd];
    571 
    572   if (port->refcnt-- > 1)
    573     return;
    574 
    575   if (!(intrupt = port->intrupt))
    576     return;
    577 
    578   /* Disable interrupts, fifo, flow control.  */
    579   disable ();
    580   port->intrupt = 0;
    581   intrupt->port = 0;
    582   outb (port, com_fifo, 0);
    583   outb (port, com_ier, 0);
    584   enable ();
    585 
    586   /* Unhook handler, and disable interrupt gate.  */
    587   dos_unhookirq (intrupt);
    588   outb (port, com_mcr, 0);
    589 
    590   /* Check for overflow errors.  */
    591   if (port->oflo)
    592     {
    593       fprintf_unfiltered (gdb_stderr,
    594 			  "Serial input overruns occurred.\n");
    595       fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
    596 			  port->fifo ? "cannot" : "needs a 16550 to",
    597 			  port->baudrate);
    598     }
    599 }
    600 
    601 
    603 
    604 static int
    605 dos_noop (struct serial *scb)
    606 {
    607   return 0;
    608 }
    609 
    610 static void
    611 dos_raw (struct serial *scb)
    612 {
    613   /* Always in raw mode.  */
    614 }
    615 
    616 static int
    617 dos_readchar (struct serial *scb, int timeout)
    618 {
    619   struct dos_ttystate *port = &ports[scb->fd];
    620   long then;
    621   int c;
    622 
    623   then = rawclock () + (timeout * RAWHZ);
    624   while ((c = dos_getc (port)) < 0)
    625     {
    626       if (timeout >= 0 && (rawclock () - then) >= 0)
    627 	return SERIAL_TIMEOUT;
    628     }
    629 
    630   return c;
    631 }
    632 
    633 
    634 static serial_ttystate
    635 dos_get_tty_state (struct serial *scb)
    636 {
    637   struct dos_ttystate *port = &ports[scb->fd];
    638   struct dos_ttystate *state;
    639 
    640   /* Are they asking about a port we opened?  */
    641   if (port->refcnt <= 0)
    642     {
    643       /* We've never heard about this port.  We should fail this call,
    644 	 unless they are asking about one of the 3 standard handles,
    645 	 in which case we pretend the handle was open by us if it is
    646 	 connected to a terminal device.  This is beacuse Unix
    647 	 terminals use the serial interface, so GDB expects the
    648 	 standard handles to go through here.  */
    649       if (scb->fd >= 3 || !isatty (scb->fd))
    650 	return NULL;
    651     }
    652 
    653   state = (struct dos_ttystate *) xmalloc (sizeof *state);
    654   *state = *port;
    655   return (serial_ttystate) state;
    656 }
    657 
    658 static serial_ttystate
    659 dos_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
    660 {
    661   struct dos_ttystate *state;
    662 
    663   state = (struct dos_ttystate *) xmalloc (sizeof *state);
    664   *state = *(struct dos_ttystate *) ttystate;
    665 
    666   return (serial_ttystate) state;
    667 }
    668 
    669 static int
    670 dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
    671 {
    672   struct dos_ttystate *state;
    673 
    674   state = (struct dos_ttystate *) ttystate;
    675   dos_setbaudrate (scb, state->baudrate);
    676   return 0;
    677 }
    678 
    679 static int
    680 dos_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate,
    681 			   serial_ttystate old_ttystate)
    682 {
    683   struct dos_ttystate *state;
    684 
    685   state = (struct dos_ttystate *) new_ttystate;
    686   dos_setbaudrate (scb, state->baudrate);
    687   return 0;
    688 }
    689 
    690 static int
    691 dos_flush_input (struct serial *scb)
    692 {
    693   struct dos_ttystate *port = &ports[scb->fd];
    694 
    695   disable ();
    696   port->first = port->count = 0;
    697   if (port->fifo)
    698     outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
    699   enable ();
    700   return 0;
    701 }
    702 
    703 static void
    704 dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
    705 		     struct ui_file *stream)
    706 {
    707   /* Nothing to print.  */
    708   return;
    709 }
    710 
    711 static int
    712 dos_baudconv (int rate)
    713 {
    714   long x, err;
    715 
    716   if (rate <= 0)
    717     return -1;
    718 
    719 #define divrnd(n, q)	(((n) * 2 / (q) + 1) / 2) /* Divide and round off.  */
    720   x = divrnd (COMTICK, rate);
    721   if (x <= 0)
    722     return -1;
    723 
    724   err = divrnd (1000 * COMTICK, x * rate) - 1000;
    725   if (err < 0)
    726     err = -err;
    727   if (err > SPEED_TOLERANCE)
    728     return -1;
    729 #undef divrnd
    730   return x;
    731 }
    732 
    733 
    734 static int
    735 dos_setbaudrate (struct serial *scb, int rate)
    736 {
    737   struct dos_ttystate *port = &ports[scb->fd];
    738 
    739   if (port->baudrate != rate)
    740     {
    741       int x;
    742       unsigned char cfcr;
    743 
    744       x = dos_baudconv (rate);
    745       if (x <= 0)
    746 	{
    747 	  fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
    748 	  errno = EINVAL;
    749 	  return -1;
    750 	}
    751 
    752       disable ();
    753       cfcr = inb (port, com_cfcr);
    754 
    755       outb (port, com_cfcr, CFCR_DLAB);
    756       outb (port, com_dlbl, x & 0xff);
    757       outb (port, com_dlbh, x >> 8);
    758       outb (port, com_cfcr, cfcr);
    759       port->baudrate = rate;
    760       enable ();
    761     }
    762 
    763   return 0;
    764 }
    765 
    766 static int
    767 dos_setstopbits (struct serial *scb, int num)
    768 {
    769   struct dos_ttystate *port = &ports[scb->fd];
    770   unsigned char cfcr;
    771 
    772   disable ();
    773   cfcr = inb (port, com_cfcr);
    774 
    775   switch (num)
    776     {
    777     case SERIAL_1_STOPBITS:
    778       outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
    779       break;
    780     case SERIAL_1_AND_A_HALF_STOPBITS:
    781     case SERIAL_2_STOPBITS:
    782       outb (port, com_cfcr, cfcr | CFCR_STOPB);
    783       break;
    784     default:
    785       enable ();
    786       return 1;
    787     }
    788   enable ();
    789 
    790   return 0;
    791 }
    792 
    793 static int
    794 dos_write (struct serial *scb, const void *buf, size_t count)
    795 {
    796   volatile struct dos_ttystate *port = &ports[scb->fd];
    797   size_t fifosize = port->fifo ? 16 : 1;
    798   long then;
    799   size_t cnt;
    800   const char *str = buf;
    801 
    802   while (count > 0)
    803     {
    804       /* Send the data, fifosize bytes at a time.  */
    805       cnt = fifosize > count ? count : fifosize;
    806       port->txbusy = 1;
    807       /* Francisco Pastor <fpastor.etra-id (at) etra.es> says OUTSB messes
    808 	 up the communications with UARTs with FIFOs.  */
    809 #ifdef UART_FIFO_WORKS
    810       outportsb (port->base + com_data, str, cnt);
    811       str += cnt;
    812       count -= cnt;
    813 #else
    814       for ( ; cnt > 0; cnt--, count--)
    815 	outportb (port->base + com_data, *str++);
    816 #endif
    817 #ifdef DOS_STATS
    818       cnts[CNT_TX] += cnt;
    819 #endif
    820       /* Wait for transmission to complete (max 1 sec).  */
    821       then = rawclock () + RAWHZ;
    822       while (port->txbusy)
    823 	{
    824 	  if ((rawclock () - then) >= 0)
    825 	    {
    826 	      errno = EIO;
    827 	      return SERIAL_ERROR;
    828 	    }
    829 	}
    830     }
    831   return 0;
    832 }
    833 
    834 
    835 static int
    836 dos_sendbreak (struct serial *scb)
    837 {
    838   volatile struct dos_ttystate *port = &ports[scb->fd];
    839   unsigned char cfcr;
    840   long then;
    841 
    842   cfcr = inb (port, com_cfcr);
    843   outb (port, com_cfcr, cfcr | CFCR_SBREAK);
    844 
    845   /* 0.25 sec delay */
    846   then = rawclock () + RAWHZ / 4;
    847   while ((rawclock () - then) < 0)
    848     continue;
    849 
    850   outb (port, com_cfcr, cfcr);
    851   return 0;
    852 }
    853 
    854 
    855 static const struct serial_ops dos_ops =
    856 {
    857   "hardwire",
    858   dos_open,
    859   dos_close,
    860   NULL,				/* fdopen, not implemented */
    861   dos_readchar,
    862   dos_write,
    863   dos_noop,			/* flush output */
    864   dos_flush_input,
    865   dos_sendbreak,
    866   dos_raw,
    867   dos_get_tty_state,
    868   dos_copy_tty_state,
    869   dos_set_tty_state,
    870   dos_print_tty_state,
    871   dos_noflush_set_tty_state,
    872   dos_setbaudrate,
    873   dos_setstopbits,
    874   dos_noop,			/* Wait for output to drain.  */
    875   (void (*)(struct serial *, int))NULL	/* Change into async mode.  */
    876 };
    877 
    878 int
    879 gdb_pipe (int pdes[2])
    880 {
    881   /* No support for pipes.  */
    882   errno = ENOSYS;
    883   return -1;
    884 }
    885 
    886 static void
    887 dos_info (char *arg, int from_tty)
    888 {
    889   struct dos_ttystate *port;
    890 #ifdef DOS_STATS
    891   int i;
    892 #endif
    893 
    894   for (port = ports; port < &ports[4]; port++)
    895     {
    896       if (port->baudrate == 0)
    897 	continue;
    898       printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
    899 		       port->intrupt ? "" : "not ");
    900       printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
    901       printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
    902       printf_filtered ("Speed:\t%d baud\n", port->baudrate);
    903       printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
    904 		       port->ferr, port->perr, port->oflo);
    905     }
    906 
    907 #ifdef DOS_STATS
    908   printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
    909   for (i = 0; i < NCNT; i++)
    910     if (cnts[i])
    911       printf_filtered ("%s:\t%lu\n", cntnames[i], (unsigned long) cnts[i]);
    912 #endif
    913 }
    914 
    915 /* -Wmissing-prototypes */
    916 extern initialize_file_ftype _initialize_ser_dos;
    917 
    918 void
    919 _initialize_ser_dos (void)
    920 {
    921   serial_add_interface (&dos_ops);
    922 
    923   /* Save original interrupt mask register.  */
    924   icu_oldmask = inportb (ICU_MASK);
    925 
    926   /* Mark fixed motherboard irqs as inuse.  */
    927   intrupts[0].inuse =		/* timer tick */
    928     intrupts[1].inuse =		/* keyboard */
    929     intrupts[2].inuse = 1;	/* slave icu */
    930 
    931   add_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
    932 Set COM1 base i/o port address."), _("\
    933 Show COM1 base i/o port address."), NULL,
    934 			    NULL,
    935 			    NULL, /* FIXME: i18n: */
    936 			    &setlist, &showlist);
    937 
    938   add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
    939 Set COM1 interrupt request."), _("\
    940 Show COM1 interrupt request."), NULL,
    941 			    NULL,
    942 			    NULL, /* FIXME: i18n: */
    943 			    &setlist, &showlist);
    944 
    945   add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
    946 Set COM2 base i/o port address."), _("\
    947 Show COM2 base i/o port address."), NULL,
    948 			    NULL,
    949 			    NULL, /* FIXME: i18n: */
    950 			    &setlist, &showlist);
    951 
    952   add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
    953 Set COM2 interrupt request."), _("\
    954 Show COM2 interrupt request."), NULL,
    955 			    NULL,
    956 			    NULL, /* FIXME: i18n: */
    957 			    &setlist, &showlist);
    958 
    959   add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
    960 Set COM3 base i/o port address."), _("\
    961 Show COM3 base i/o port address."), NULL,
    962 			    NULL,
    963 			    NULL, /* FIXME: i18n: */
    964 			    &setlist, &showlist);
    965 
    966   add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
    967 Set COM3 interrupt request."), _("\
    968 Show COM3 interrupt request."), NULL,
    969 			    NULL,
    970 			    NULL, /* FIXME: i18n: */
    971 			    &setlist, &showlist);
    972 
    973   add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
    974 Set COM4 base i/o port address."), _("\
    975 Show COM4 base i/o port address."), NULL,
    976 			    NULL,
    977 			    NULL, /* FIXME: i18n: */
    978 			    &setlist, &showlist);
    979 
    980   add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
    981 Set COM4 interrupt request."), _("\
    982 Show COM4 interrupt request."), NULL,
    983 			    NULL,
    984 			    NULL, /* FIXME: i18n: */
    985 			    &setlist, &showlist);
    986 
    987   add_info ("serial", dos_info,
    988 	    _("Print DOS serial port status."));
    989 }
    990