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