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> 135typedef 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 152static int intrcnt; 153static int cnts[NCNT]; 154static 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. */ 176unsigned char icu_oldmask; 177 178/* Maximum of 8 interrupts (we don't handle the slave icu yet). */ 179#define NINTR 8 180 181static 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 } 191intrupts[NINTR]; 192 193 194static 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 } 212ports[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 231static int dos_open (struct serial *scb, const char *name); 232static void dos_raw (struct serial *scb); 233static int dos_readchar (struct serial *scb, int timeout); 234static int dos_setbaudrate (struct serial *scb, int rate); 235static int dos_write (struct serial *scb, const char *str, int len); 236static void dos_close (struct serial *scb); 237static serial_ttystate dos_get_tty_state (struct serial *scb); 238static int dos_set_tty_state (struct serial *scb, serial_ttystate state); 239static 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 247static int 248dos_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 264static int 265dos_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 276static void 277dos_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 359ISR (0) ISR (1) ISR (2) ISR (3) /* OK */ 360ISR (4) ISR (5) ISR (6) ISR (7) /* OK */ 361 362typedef void (*isr_t) (void); 363 364static 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 372static struct intrupt * 373dos_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 428static void 429dos_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 455static int 456dos_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 503ok: 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 560static void 561dos_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 602static int 603dos_noop (struct serial *scb) 604{ 605 return 0; 606} 607 608static void 609dos_raw (struct serial *scb) 610{ 611 /* Always in raw mode */ 612} 613 614static int 615dos_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 632static serial_ttystate 633dos_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 656static int 657dos_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 666static int 667dos_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 677static int 678dos_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 689static void 690dos_print_tty_state (struct serial *scb, serial_ttystate ttystate, 691 struct ui_file *stream) 692{ 693 /* Nothing to print */ 694 return; 695} 696 697static int 698dos_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 720static int 721dos_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 752static int 753dos_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 779static int 780dos_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 820static int 821dos_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 840static 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 863static void 864dos_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 893void 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 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 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 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 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 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 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 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 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