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