GDB (API)
|
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 }