GDB (API)
/home/stan/gdb/src/gdb/ser-go32.c
Go to the documentation of this file.
00001 /* Remote serial interface for local (hardwired) serial ports for GO32.
00002    Copyright (C) 1992-2013 Free Software Foundation, Inc.
00003 
00004    Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
00005 
00006    This version uses DPMI interrupts to handle buffered i/o
00007    without the separate "asynctsr" program.
00008 
00009    This file is part of GDB.
00010 
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 3 of the License, or
00014    (at your option) any later version.
00015 
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020 
00021    You should have received a copy of the GNU General Public License
00022    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00023 
00024 #include "defs.h"
00025 #include "gdbcmd.h"
00026 #include "serial.h"
00027 #include "gdb_string.h"
00028 
00029 
00030 /*
00031  * NS16550 UART registers
00032  */
00033 
00034 #define COM1ADDR        0x3f8
00035 #define COM2ADDR        0x2f8
00036 #define COM3ADDR        0x3e8
00037 #define COM4ADDR        0x3e0
00038 
00039 #define com_data        0       /* data register (R/W) */
00040 #define com_dlbl        0       /* divisor latch low (W) */
00041 #define com_ier         1       /* interrupt enable (W) */
00042 #define com_dlbh        1       /* divisor latch high (W) */
00043 #define com_iir         2       /* interrupt identification (R) */
00044 #define com_fifo        2       /* FIFO control (W) */
00045 #define com_lctl        3       /* line control register (R/W) */
00046 #define com_cfcr        3       /* line control register (R/W) */
00047 #define com_mcr         4       /* modem control register (R/W) */
00048 #define com_lsr         5       /* line status register (R/W) */
00049 #define com_msr         6       /* modem status register (R/W) */
00050 
00051 /*
00052  * Constants for computing 16 bit baud rate divisor (lower byte
00053  * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal.  Divisor is
00054  * 1.8432 MHz / (16 * X) for X bps.  If the baud rate can't be set
00055  * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
00056  */
00057 #define COMTICK         (1843200/16)
00058 #define SPEED_TOLERANCE 30      /* thousandths; real == desired +- 3.0% */
00059 
00060 /* interrupt enable register */
00061 #define IER_ERXRDY      0x1     /* int on rx ready */
00062 #define IER_ETXRDY      0x2     /* int on tx ready */
00063 #define IER_ERLS        0x4     /* int on line status change */
00064 #define IER_EMSC        0x8     /* int on modem status change */
00065 
00066 /* interrupt identification register */
00067 #define IIR_FIFO_MASK   0xc0    /* set if FIFOs are enabled */
00068 #define IIR_IMASK       0xf     /* interrupt cause mask */
00069 #define IIR_NOPEND      0x1     /* nothing pending */
00070 #define IIR_RLS         0x6     /* receive line status */
00071 #define IIR_RXRDY       0x4     /* receive ready */
00072 #define IIR_RXTOUT      0xc     /* receive timeout */
00073 #define IIR_TXRDY       0x2     /* transmit ready */
00074 #define IIR_MLSC        0x0     /* modem status */
00075 
00076 
00077 /* fifo control register */
00078 #define FIFO_ENABLE     0x01    /* enable fifo */
00079 #define FIFO_RCV_RST    0x02    /* reset receive fifo */
00080 #define FIFO_XMT_RST    0x04    /* reset transmit fifo */
00081 #define FIFO_DMA_MODE   0x08    /* enable dma mode */
00082 #define FIFO_TRIGGER_1  0x00    /* trigger at 1 char */
00083 #define FIFO_TRIGGER_4  0x40    /* trigger at 4 chars */
00084 #define FIFO_TRIGGER_8  0x80    /* trigger at 8 chars */
00085 #define FIFO_TRIGGER_14 0xc0    /* trigger at 14 chars */
00086 
00087 /* character format control register */
00088 #define CFCR_DLAB       0x80    /* divisor latch */
00089 #define CFCR_SBREAK     0x40    /* send break */
00090 #define CFCR_PZERO      0x30    /* zero parity */
00091 #define CFCR_PONE       0x20    /* one parity */
00092 #define CFCR_PEVEN      0x10    /* even parity */
00093 #define CFCR_PODD       0x00    /* odd parity */
00094 #define CFCR_PENAB      0x08    /* parity enable */
00095 #define CFCR_STOPB      0x04    /* 2 stop bits */
00096 #define CFCR_8BITS      0x03    /* 8 data bits */
00097 #define CFCR_7BITS      0x02    /* 7 data bits */
00098 #define CFCR_6BITS      0x01    /* 6 data bits */
00099 #define CFCR_5BITS      0x00    /* 5 data bits */
00100 
00101 /* modem control register */
00102 #define MCR_LOOPBACK    0x10    /* loopback */
00103 #define MCR_IENABLE     0x08    /* output 2 = int enable */
00104 #define MCR_DRS         0x04    /* output 1 = xxx */
00105 #define MCR_RTS         0x02    /* enable RTS */
00106 #define MCR_DTR         0x01    /* enable DTR */
00107 
00108 /* line status register */
00109 #define LSR_RCV_FIFO    0x80    /* error in receive fifo */
00110 #define LSR_TSRE        0x40    /* transmitter empty */
00111 #define LSR_TXRDY       0x20    /* transmitter ready */
00112 #define LSR_BI          0x10    /* break detected */
00113 #define LSR_FE          0x08    /* framing error */
00114 #define LSR_PE          0x04    /* parity error */
00115 #define LSR_OE          0x02    /* overrun error */
00116 #define LSR_RXRDY       0x01    /* receiver ready */
00117 #define LSR_RCV_MASK    0x1f
00118 
00119 /* modem status register */
00120 #define MSR_DCD         0x80
00121 #define MSR_RI          0x40
00122 #define MSR_DSR         0x20
00123 #define MSR_CTS         0x10
00124 #define MSR_DDCD        0x08
00125 #define MSR_TERI        0x04
00126 #define MSR_DDSR        0x02
00127 #define MSR_DCTS        0x01
00128 
00129 #include <time.h>
00130 #include <dos.h>
00131 #include <go32.h>
00132 #include <dpmi.h>
00133 typedef unsigned long u_long;
00134 
00135 /* 16550 rx fifo trigger point */
00136 #define FIFO_TRIGGER    FIFO_TRIGGER_4
00137 
00138 /* input buffer size */
00139 #define CBSIZE  4096
00140 
00141 #define RAWHZ   18
00142 
00143 #ifdef DOS_STATS
00144 #define CNT_RX          16
00145 #define CNT_TX          17
00146 #define CNT_STRAY       18
00147 #define CNT_ORUN        19
00148 #define NCNT            20
00149 
00150 static int intrcnt;
00151 static size_t cnts[NCNT];
00152 static char *cntnames[NCNT] =
00153 {
00154   /* h/w interrupt counts.  */
00155   "mlsc", "nopend", "txrdy", "?3",
00156   "rxrdy", "?5", "rls", "?7",
00157   "?8", "?9", "?a", "?b",
00158   "rxtout", "?d", "?e", "?f",
00159   /* s/w counts.  */
00160   "rxcnt", "txcnt", "stray", "swoflo"
00161 };
00162 
00163 #define COUNT(x) cnts[x]++
00164 #else
00165 #define COUNT(x)
00166 #endif
00167 
00168 /* Main interrupt controller port addresses.  */
00169 #define ICU_BASE        0x20
00170 #define ICU_OCW2        (ICU_BASE + 0)
00171 #define ICU_MASK        (ICU_BASE + 1)
00172 
00173 /* Original interrupt controller mask register.  */
00174 unsigned char icu_oldmask;
00175 
00176 /* Maximum of 8 interrupts (we don't handle the slave icu yet).  */
00177 #define NINTR   8
00178 
00179 static struct intrupt
00180   {
00181     char inuse;
00182     struct dos_ttystate *port;
00183     _go32_dpmi_seginfo old_rmhandler;
00184     _go32_dpmi_seginfo old_pmhandler;
00185     _go32_dpmi_seginfo new_rmhandler;
00186     _go32_dpmi_seginfo new_pmhandler;
00187     _go32_dpmi_registers regs;
00188   }
00189 intrupts[NINTR];
00190 
00191 
00192 static struct dos_ttystate
00193   {
00194     int base;
00195     int irq;
00196     int refcnt;
00197     struct intrupt *intrupt;
00198     int fifo;
00199     int baudrate;
00200     unsigned char cbuf[CBSIZE];
00201     unsigned int first;
00202     unsigned int count;
00203     int txbusy;
00204     unsigned char old_mcr;
00205     int ferr;
00206     int perr;
00207     int oflo;
00208     int msr;
00209   }
00210 ports[4] =
00211 {
00212   {
00213     COM1ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
00214   }
00215   ,
00216   {
00217     COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
00218   }
00219   ,
00220   {
00221     COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
00222   }
00223   ,
00224   {
00225     COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
00226   }
00227 };
00228 
00229 static int dos_open (struct serial *scb, const char *name);
00230 static void dos_raw (struct serial *scb);
00231 static int dos_readchar (struct serial *scb, int timeout);
00232 static int dos_setbaudrate (struct serial *scb, int rate);
00233 static int dos_write (struct serial *scb, const void *buf, size_t count);
00234 static void dos_close (struct serial *scb);
00235 static serial_ttystate dos_get_tty_state (struct serial *scb);
00236 static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
00237 static int dos_baudconv (int rate);
00238 
00239 #define inb(p,a)        inportb((p)->base + (a))
00240 #define outb(p,a,v)     outportb((p)->base + (a), (v))
00241 #define disable()       asm volatile ("cli");
00242 #define enable()        asm volatile ("sti");
00243 
00244 
00245 static int
00246 dos_getc (volatile struct dos_ttystate *port)
00247 {
00248   int c;
00249 
00250   if (port->count == 0)
00251     return -1;
00252 
00253   c = port->cbuf[port->first];
00254   disable ();
00255   port->first = (port->first + 1) & (CBSIZE - 1);
00256   port->count--;
00257   enable ();
00258   return c;
00259 }
00260 
00261 
00262 static int
00263 dos_putc (int c, struct dos_ttystate *port)
00264 {
00265   if (port->count >= CBSIZE - 1)
00266     return -1;
00267   port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
00268   port->count++;
00269   return 0;
00270 }
00271 
00272 
00273 
00274 static void
00275 dos_comisr (int irq)
00276 {
00277   struct dos_ttystate *port;
00278   unsigned char iir, lsr, c;
00279 
00280   disable ();                   /* Paranoia */
00281   outportb (ICU_OCW2, 0x20);    /* End-Of-Interrupt */
00282 #ifdef DOS_STATS
00283   ++intrcnt;
00284 #endif
00285 
00286   port = intrupts[irq].port;
00287   if (!port)
00288     {
00289       COUNT (CNT_STRAY);
00290       return;                   /* not open */
00291     }
00292 
00293   while (1)
00294     {
00295       iir = inb (port, com_iir) & IIR_IMASK;
00296       switch (iir)
00297         {
00298 
00299         case IIR_RLS:
00300           lsr = inb (port, com_lsr);
00301           goto rx;
00302 
00303         case IIR_RXTOUT:
00304         case IIR_RXRDY:
00305           lsr = 0;
00306 
00307         rx:
00308           do
00309             {
00310               c = inb (port, com_data);
00311               if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
00312                 {
00313                   if (lsr & (LSR_BI | LSR_FE))
00314                     port->ferr++;
00315                   else if (lsr & LSR_PE)
00316                     port->perr++;
00317                   if (lsr & LSR_OE)
00318                     port->oflo++;
00319                 }
00320 
00321               if (dos_putc (c, port) < 0)
00322                 {
00323                   COUNT (CNT_ORUN);
00324                 }
00325               else
00326                 {
00327                   COUNT (CNT_RX);
00328                 }
00329             }
00330           while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
00331           break;
00332 
00333         case IIR_MLSC:
00334           /* could be used to flowcontrol Tx */
00335           port->msr = inb (port, com_msr);
00336           break;
00337 
00338         case IIR_TXRDY:
00339           port->txbusy = 0;
00340           break;
00341 
00342         case IIR_NOPEND:
00343           /* No more pending interrupts, all done.  */
00344           return;
00345 
00346         default:
00347           /* Unexpected interrupt, ignore.  */
00348           break;
00349         }
00350       COUNT (iir);
00351     }
00352 }
00353 
00354 #define ISRNAME(x) dos_comisr##x
00355 #define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
00356 
00357 ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
00358 ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
00359 
00360 typedef void (*isr_t) (void);
00361 
00362 static isr_t isrs[NINTR] =
00363   {
00364        ISRNAME (0), ISRNAME (1), ISRNAME (2), ISRNAME (3),
00365        ISRNAME (4), ISRNAME (5), ISRNAME (6), ISRNAME (7)
00366   };
00367 
00368 
00369 
00370 static struct intrupt *
00371 dos_hookirq (unsigned int irq)
00372 {
00373   struct intrupt *intr;
00374   unsigned int vec;
00375   isr_t isr;
00376 
00377   if (irq >= NINTR)
00378     return 0;
00379 
00380   intr = &intrupts[irq];
00381   if (intr->inuse)
00382     return 0;
00383 
00384   vec = 0x08 + irq;
00385   isr = isrs[irq];
00386 
00387   /* Setup real mode handler.  */
00388   _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
00389 
00390   intr->new_rmhandler.pm_selector = _go32_my_cs ();
00391   intr->new_rmhandler.pm_offset = (u_long) isr;
00392   if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
00393                                                    &intr->regs))
00394     {
00395       return 0;
00396     }
00397 
00398   if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
00399     {
00400       return 0;
00401     }
00402 
00403   /* Setup protected mode handler.  */
00404   _go32_dpmi_get_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
00405 
00406   intr->new_pmhandler.pm_selector = _go32_my_cs ();
00407   intr->new_pmhandler.pm_offset = (u_long) isr;
00408   _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
00409 
00410   if (_go32_dpmi_set_protected_mode_interrupt_vector (vec,
00411                                                       &intr->new_pmhandler))
00412     {
00413       return 0;
00414     }
00415 
00416   /* Setup interrupt controller mask.  */
00417   disable ();
00418   outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
00419   enable ();
00420 
00421   intr->inuse = 1;
00422   return intr;
00423 }
00424 
00425 
00426 static void
00427 dos_unhookirq (struct intrupt *intr)
00428 {
00429   unsigned int irq, vec;
00430   unsigned char mask;
00431 
00432   irq = intr - intrupts;
00433   vec = 0x08 + irq;
00434 
00435   /* Restore old interrupt mask bit.  */
00436   mask = 1 << irq;
00437   disable ();
00438   outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
00439   enable ();
00440 
00441   /* Remove real mode handler.  */
00442   _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
00443   _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
00444 
00445   /* Remove protected mode handler.  */
00446   _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
00447   _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
00448   intr->inuse = 0;
00449 }
00450 
00451 
00452 
00453 static int
00454 dos_open (struct serial *scb, const char *name)
00455 {
00456   struct dos_ttystate *port;
00457   int fd, i;
00458 
00459   if (strncasecmp (name, "/dev/", 5) == 0)
00460     name += 5;
00461   else if (strncasecmp (name, "\\dev\\", 5) == 0)
00462     name += 5;
00463 
00464   if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
00465     {
00466       errno = ENOENT;
00467       return -1;
00468     }
00469 
00470   if (name[3] < '1' || name[3] > '4')
00471     {
00472       errno = ENOENT;
00473       return -1;
00474     }
00475 
00476   /* FIXME: this is a Bad Idea (tm)!  One should *never* invent file
00477      handles, since they might be already used by other files/devices.
00478      The Right Way to do this is to create a real handle by dup()'ing
00479      some existing one.  */
00480   fd = name[3] - '1';
00481   port = &ports[fd];
00482   if (port->refcnt++ > 0)
00483     {
00484       /* Device already opened another user.  Just point at it.  */
00485       scb->fd = fd;
00486       return 0;
00487     }
00488 
00489   /* Force access to ID reg.  */
00490   outb (port, com_cfcr, 0);
00491   outb (port, com_iir, 0);
00492   for (i = 0; i < 17; i++)
00493     {
00494       if ((inb (port, com_iir) & 0x38) == 0)
00495         goto ok;
00496       (void) inb (port, com_data);      /* clear recv */
00497     }
00498   errno = ENODEV;
00499   return -1;
00500 
00501 ok:
00502   /* Disable all interrupts in chip.  */
00503   outb (port, com_ier, 0);
00504 
00505   /* Tentatively enable 16550 fifo, and see if it responds.  */
00506   outb (port, com_fifo,
00507         FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER);
00508   sleep (1);
00509   port->fifo = ((inb (port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
00510 
00511   /* clear pending status reports.  */
00512   (void) inb (port, com_lsr);
00513   (void) inb (port, com_msr);
00514 
00515   /* Enable external interrupt gate (to avoid floating IRQ).  */
00516   outb (port, com_mcr, MCR_IENABLE);
00517 
00518   /* Hook up interrupt handler and initialise icu.  */
00519   port->intrupt = dos_hookirq (port->irq);
00520   if (!port->intrupt)
00521     {
00522       outb (port, com_mcr, 0);
00523       outb (port, com_fifo, 0);
00524       errno = ENODEV;
00525       return -1;
00526     }
00527 
00528   disable ();
00529 
00530   /* record port */
00531   port->intrupt->port = port;
00532   scb->fd = fd;
00533 
00534   /* Clear rx buffer, tx busy flag and overflow count.  */
00535   port->first = port->count = 0;
00536   port->txbusy = 0;
00537   port->oflo = 0;
00538 
00539   /* Set default baud rate and mode: 9600,8,n,1 */
00540   i = dos_baudconv (port->baudrate = 9600);
00541   outb (port, com_cfcr, CFCR_DLAB);
00542   outb (port, com_dlbl, i & 0xff);
00543   outb (port, com_dlbh, i >> 8);
00544   outb (port, com_cfcr, CFCR_8BITS);
00545 
00546   /* Enable all interrupts.  */
00547   outb (port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
00548 
00549   /* Enable DTR & RTS.  */
00550   outb (port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
00551 
00552   enable ();
00553 
00554   return 0;
00555 }
00556 
00557 
00558 static void
00559 dos_close (struct serial *scb)
00560 {
00561   struct dos_ttystate *port;
00562   struct intrupt *intrupt;
00563 
00564   if (!scb)
00565     return;
00566 
00567   port = &ports[scb->fd];
00568 
00569   if (port->refcnt-- > 1)
00570     return;
00571 
00572   if (!(intrupt = port->intrupt))
00573     return;
00574 
00575   /* Disable interrupts, fifo, flow control.  */
00576   disable ();
00577   port->intrupt = 0;
00578   intrupt->port = 0;
00579   outb (port, com_fifo, 0);
00580   outb (port, com_ier, 0);
00581   enable ();
00582 
00583   /* Unhook handler, and disable interrupt gate.  */
00584   dos_unhookirq (intrupt);
00585   outb (port, com_mcr, 0);
00586 
00587   /* Check for overflow errors.  */
00588   if (port->oflo)
00589     {
00590       fprintf_unfiltered (gdb_stderr,
00591                           "Serial input overruns occurred.\n");
00592       fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
00593                           port->fifo ? "cannot" : "needs a 16550 to",
00594                           port->baudrate);
00595     }
00596 }
00597 
00598 
00599 
00600 static int
00601 dos_noop (struct serial *scb)
00602 {
00603   return 0;
00604 }
00605 
00606 static void
00607 dos_raw (struct serial *scb)
00608 {
00609   /* Always in raw mode.  */
00610 }
00611 
00612 static int
00613 dos_readchar (struct serial *scb, int timeout)
00614 {
00615   struct dos_ttystate *port = &ports[scb->fd];
00616   long then;
00617   int c;
00618 
00619   then = rawclock () + (timeout * RAWHZ);
00620   while ((c = dos_getc (port)) < 0)
00621     {
00622       if (timeout >= 0 && (rawclock () - then) >= 0)
00623         return SERIAL_TIMEOUT;
00624     }
00625 
00626   return c;
00627 }
00628 
00629 
00630 static serial_ttystate
00631 dos_get_tty_state (struct serial *scb)
00632 {
00633   struct dos_ttystate *port = &ports[scb->fd];
00634   struct dos_ttystate *state;
00635 
00636   /* Are they asking about a port we opened?  */
00637   if (port->refcnt <= 0)
00638     {
00639       /* We've never heard about this port.  We should fail this call,
00640          unless they are asking about one of the 3 standard handles,
00641          in which case we pretend the handle was open by us if it is
00642          connected to a terminal device.  This is beacuse Unix
00643          terminals use the serial interface, so GDB expects the
00644          standard handles to go through here.  */
00645       if (scb->fd >= 3 || !isatty (scb->fd))
00646         return NULL;
00647     }
00648 
00649   state = (struct dos_ttystate *) xmalloc (sizeof *state);
00650   *state = *port;
00651   return (serial_ttystate) state;
00652 }
00653 
00654 static serial_ttystate
00655 dos_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
00656 {
00657   struct dos_ttystate *state;
00658 
00659   state = (struct dos_ttystate *) xmalloc (sizeof *state);
00660   *state = *(struct dos_ttystate *) ttystate;
00661 
00662   return (serial_ttystate) state;
00663 }
00664 
00665 static int
00666 dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
00667 {
00668   struct dos_ttystate *state;
00669 
00670   state = (struct dos_ttystate *) ttystate;
00671   dos_setbaudrate (scb, state->baudrate);
00672   return 0;
00673 }
00674 
00675 static int
00676 dos_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate,
00677                            serial_ttystate old_ttystate)
00678 {
00679   struct dos_ttystate *state;
00680 
00681   state = (struct dos_ttystate *) new_ttystate;
00682   dos_setbaudrate (scb, state->baudrate);
00683   return 0;
00684 }
00685 
00686 static int
00687 dos_flush_input (struct serial *scb)
00688 {
00689   struct dos_ttystate *port = &ports[scb->fd];
00690 
00691   disable ();
00692   port->first = port->count = 0;
00693   if (port->fifo)
00694     outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
00695   enable ();
00696   return 0;
00697 }
00698 
00699 static void
00700 dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
00701                      struct ui_file *stream)
00702 {
00703   /* Nothing to print.  */
00704   return;
00705 }
00706 
00707 static int
00708 dos_baudconv (int rate)
00709 {
00710   long x, err;
00711 
00712   if (rate <= 0)
00713     return -1;
00714 
00715 #define divrnd(n, q)    (((n) * 2 / (q) + 1) / 2) /* Divide and round off.  */
00716   x = divrnd (COMTICK, rate);
00717   if (x <= 0)
00718     return -1;
00719 
00720   err = divrnd (1000 * COMTICK, x * rate) - 1000;
00721   if (err < 0)
00722     err = -err;
00723   if (err > SPEED_TOLERANCE)
00724     return -1;
00725 #undef divrnd
00726   return x;
00727 }
00728 
00729 
00730 static int
00731 dos_setbaudrate (struct serial *scb, int rate)
00732 {
00733   struct dos_ttystate *port = &ports[scb->fd];
00734 
00735   if (port->baudrate != rate)
00736     {
00737       int x;
00738       unsigned char cfcr;
00739 
00740       x = dos_baudconv (rate);
00741       if (x <= 0)
00742         {
00743           fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
00744           errno = EINVAL;
00745           return -1;
00746         }
00747 
00748       disable ();
00749       cfcr = inb (port, com_cfcr);
00750 
00751       outb (port, com_cfcr, CFCR_DLAB);
00752       outb (port, com_dlbl, x & 0xff);
00753       outb (port, com_dlbh, x >> 8);
00754       outb (port, com_cfcr, cfcr);
00755       port->baudrate = rate;
00756       enable ();
00757     }
00758 
00759   return 0;
00760 }
00761 
00762 static int
00763 dos_setstopbits (struct serial *scb, int num)
00764 {
00765   struct dos_ttystate *port = &ports[scb->fd];
00766   unsigned char cfcr;
00767 
00768   disable ();
00769   cfcr = inb (port, com_cfcr);
00770 
00771   switch (num)
00772     {
00773     case SERIAL_1_STOPBITS:
00774       outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
00775       break;
00776     case SERIAL_1_AND_A_HALF_STOPBITS:
00777     case SERIAL_2_STOPBITS:
00778       outb (port, com_cfcr, cfcr | CFCR_STOPB);
00779       break;
00780     default:
00781       enable ();
00782       return 1;
00783     }
00784   enable ();
00785 
00786   return 0;
00787 }
00788 
00789 static int
00790 dos_write (struct serial *scb, const void *buf, size_t count)
00791 {
00792   volatile struct dos_ttystate *port = &ports[scb->fd];
00793   size_t fifosize = port->fifo ? 16 : 1;
00794   long then;
00795   size_t cnt;
00796   const char *str = buf;
00797 
00798   while (count > 0)
00799     {
00800       /* Send the data, fifosize bytes at a time.  */
00801       cnt = fifosize > count ? count : fifosize;
00802       port->txbusy = 1;
00803       /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
00804          up the communications with UARTs with FIFOs.  */
00805 #ifdef UART_FIFO_WORKS
00806       outportsb (port->base + com_data, str, cnt);
00807       str += cnt;
00808       count -= cnt;
00809 #else
00810       for ( ; cnt > 0; cnt--, count--)
00811         outportb (port->base + com_data, *str++);
00812 #endif
00813 #ifdef DOS_STATS
00814       cnts[CNT_TX] += cnt;
00815 #endif
00816       /* Wait for transmission to complete (max 1 sec).  */
00817       then = rawclock () + RAWHZ;
00818       while (port->txbusy)
00819         {
00820           if ((rawclock () - then) >= 0)
00821             {
00822               errno = EIO;
00823               return SERIAL_ERROR;
00824             }
00825         }
00826     }
00827   return 0;
00828 }
00829 
00830 
00831 static int
00832 dos_sendbreak (struct serial *scb)
00833 {
00834   volatile struct dos_ttystate *port = &ports[scb->fd];
00835   unsigned char cfcr;
00836   long then;
00837 
00838   cfcr = inb (port, com_cfcr);
00839   outb (port, com_cfcr, cfcr | CFCR_SBREAK);
00840 
00841   /* 0.25 sec delay */
00842   then = rawclock () + RAWHZ / 4;
00843   while ((rawclock () - then) < 0)
00844     continue;
00845 
00846   outb (port, com_cfcr, cfcr);
00847   return 0;
00848 }
00849 
00850 
00851 static struct serial_ops dos_ops =
00852 {
00853   "hardwire",
00854   0,
00855   dos_open,
00856   dos_close,
00857   NULL,                         /* fdopen, not implemented */
00858   dos_readchar,
00859   dos_write,
00860   dos_noop,                     /* flush output */
00861   dos_flush_input,
00862   dos_sendbreak,
00863   dos_raw,
00864   dos_get_tty_state,
00865   dos_copy_tty_state,
00866   dos_set_tty_state,
00867   dos_print_tty_state,
00868   dos_noflush_set_tty_state,
00869   dos_setbaudrate,
00870   dos_setstopbits,
00871   dos_noop,                     /* Wait for output to drain.  */
00872   (void (*)(struct serial *, int))NULL  /* Change into async mode.  */
00873 };
00874 
00875 int
00876 gdb_pipe (int pdes[2])
00877 {
00878   /* No support for pipes.  */
00879   errno = ENOSYS;
00880   return -1;
00881 }
00882 
00883 static void
00884 dos_info (char *arg, int from_tty)
00885 {
00886   struct dos_ttystate *port;
00887 #ifdef DOS_STATS
00888   int i;
00889 #endif
00890 
00891   for (port = ports; port < &ports[4]; port++)
00892     {
00893       if (port->baudrate == 0)
00894         continue;
00895       printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
00896                        port->intrupt ? "" : "not ");
00897       printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
00898       printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
00899       printf_filtered ("Speed:\t%d baud\n", port->baudrate);
00900       printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
00901                        port->ferr, port->perr, port->oflo);
00902     }
00903 
00904 #ifdef DOS_STATS
00905   printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
00906   for (i = 0; i < NCNT; i++)
00907     if (cnts[i])
00908       printf_filtered ("%s:\t%lu\n", cntnames[i], (unsigned long) cnts[i]);
00909 #endif
00910 }
00911 
00912 /* -Wmissing-prototypes */
00913 extern initialize_file_ftype _initialize_ser_dos;
00914 
00915 void
00916 _initialize_ser_dos (void)
00917 {
00918   serial_add_interface (&dos_ops);
00919 
00920   /* Save original interrupt mask register.  */
00921   icu_oldmask = inportb (ICU_MASK);
00922 
00923   /* Mark fixed motherboard irqs as inuse.  */
00924   intrupts[0].inuse =           /* timer tick */
00925     intrupts[1].inuse =         /* keyboard */
00926     intrupts[2].inuse = 1;      /* slave icu */
00927 
00928   add_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
00929 Set COM1 base i/o port address."), _("\
00930 Show COM1 base i/o port address."), NULL,
00931                             NULL,
00932                             NULL, /* FIXME: i18n: */
00933                             &setlist, &showlist);
00934 
00935   add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
00936 Set COM1 interrupt request."), _("\
00937 Show COM1 interrupt request."), NULL,
00938                             NULL,
00939                             NULL, /* FIXME: i18n: */
00940                             &setlist, &showlist);
00941 
00942   add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
00943 Set COM2 base i/o port address."), _("\
00944 Show COM2 base i/o port address."), NULL,
00945                             NULL,
00946                             NULL, /* FIXME: i18n: */
00947                             &setlist, &showlist);
00948 
00949   add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
00950 Set COM2 interrupt request."), _("\
00951 Show COM2 interrupt request."), NULL,
00952                             NULL,
00953                             NULL, /* FIXME: i18n: */
00954                             &setlist, &showlist);
00955 
00956   add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
00957 Set COM3 base i/o port address."), _("\
00958 Show COM3 base i/o port address."), NULL,
00959                             NULL,
00960                             NULL, /* FIXME: i18n: */
00961                             &setlist, &showlist);
00962 
00963   add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
00964 Set COM3 interrupt request."), _("\
00965 Show COM3 interrupt request."), NULL,
00966                             NULL,
00967                             NULL, /* FIXME: i18n: */
00968                             &setlist, &showlist);
00969 
00970   add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
00971 Set COM4 base i/o port address."), _("\
00972 Show COM4 base i/o port address."), NULL,
00973                             NULL,
00974                             NULL, /* FIXME: i18n: */
00975                             &setlist, &showlist);
00976 
00977   add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
00978 Set COM4 interrupt request."), _("\
00979 Show COM4 interrupt request."), NULL,
00980                             NULL,
00981                             NULL, /* FIXME: i18n: */
00982                             &setlist, &showlist);
00983 
00984   add_info ("serial", dos_info,
00985             _("Print DOS serial port status."));
00986 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines