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