From 5e0b8d508ed51004bd836384293be00950ee62c9 Mon Sep 17 00:00:00 2001 From: Pasha Date: Tue, 20 Feb 2024 18:49:50 +0000 Subject: init gnumach copy --- i386/i386at/com.c | 900 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 900 insertions(+) create mode 100644 i386/i386at/com.c (limited to 'i386/i386at/com.c') diff --git a/i386/i386at/com.c b/i386/i386at/com.c new file mode 100644 index 0000000..bfe353c --- /dev/null +++ b/i386/i386at/com.c @@ -0,0 +1,900 @@ +/* + * Mach Operating System + * Copyright (c) 1994,1993,1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#if NCOM > 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static void comparam(int); + +static vm_offset_t com_std[NCOM] = { 0 }; +struct bus_device *cominfo[NCOM]; +struct bus_driver comdriver = { + comprobe, 0, comattach, 0, com_std, "com", cominfo, 0, 0, 0}; + +struct tty com_tty[NCOM]; +int commodem[NCOM]; +int comcarrier[NCOM] = {0, 0,}; +boolean_t comfifo[NCOM]; +boolean_t comtimer_active; +int comtimer_state[NCOM]; + +#define RCBAUD B115200 +static int rcline = -1; +static struct bus_device *comcndev; + +/* XX */ +extern char *kernel_cmdline; + +#define ISPEED B115200 +#define IFLAGS (EVENP|ODDP|ECHO|CRMOD|XTABS|LITOUT) + +u_short divisorreg[] = { + 0, 2304, 1536, 1047, /* 0, 50, 75, 110*/ + 857, 768, 576, 384, 192, /* 134.5, 150, 200, 300, 600*/ + 96, 64, 48, /* 1200, 1800, 2000, 2400 */ + 24, 12, /* 3600, 4800, 7200, 9600 */ + 6, 3, 2, 1}; /* 19200, 38400, 56000,115200 */ + + +/* + * + * Probes are called during kernel boot: return 1 to mean that + * the relevant device is present today. + * + */ +static int +comprobe_general(struct bus_device *dev, int noisy) +{ + u_short addr = dev->address; + int unit = dev->unit; + int oldctl, oldmsb; + char *type = "8250"; + int i; + + if ((unit < 0) || (unit >= NCOM)) { + printf("com %d out of range\n", unit); + return(0); + } + oldctl = inb(LINE_CTL(addr)); /* Save old value of LINE_CTL */ + oldmsb = inb(BAUD_MSB(addr)); /* Save old value of BAUD_MSB */ + outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */ + outb(BAUD_MSB(addr), 0); + if (inb(BAUD_MSB(addr)) != 0) + { + outb(LINE_CTL(addr), oldctl); + outb(BAUD_MSB(addr), oldmsb); + return 0; + } + outb(LINE_CTL(addr), iDLAB); /* Select BAUD_MSB */ + outb(BAUD_MSB(addr), 255); + if (inb(BAUD_MSB(addr)) != 255) + { + outb(LINE_CTL(addr), oldctl); + outb(BAUD_MSB(addr), oldmsb); + return 0; + } + outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */ + if (inb(BAUD_MSB(addr)) != 0) /* Check that it has kept its value*/ + { + outb(LINE_CTL(addr), oldctl); + outb(BAUD_MSB(addr), oldmsb); + return 0; + } + + /* Com port found, now check what chip it has */ + + for(i = 0; i < 256; i++) /* Is there Scratch register */ + { + outb(SCR(addr), i); + if (inb(SCR(addr)) != i) + break; + } + if (i == 256) + { /* Yes == 450 or 460 */ + outb(SCR(addr), 0); + type = "82450 or 16450"; + outb(FIFO_CTL(addr), iFIFOENA | iFIFO14CH); /* Enable fifo */ + if ((inb(FIFO_CTL(addr)) & iFIFO14CH) != 0) + { /* Was it successful */ + /* if both bits are not set then broken xx550 */ + if ((inb(FIFO_CTL(addr)) & iFIFO14CH) == iFIFO14CH) + { + type = "82550 or 16550"; + comfifo[unit] = TRUE; + } + else + { + type = "82550 or 16550 with non-working FIFO"; + } + outb(INTR_ID(addr), 0x00); /* Disable fifos */ + } + } + if (noisy) + printf("com%d: %s chip.\n", unit, type); + return 1; +} + +/* + * Probe routine for use during kernel startup when it is probing + * all of bus_device_init + */ +int +comprobe(vm_offset_t port, struct bus_ctlr *dev) +{ + return comprobe_general((struct bus_device *)dev, /*noisy*/ 0); +} + +/* + * Probe routine for use by the console + */ +int +comcnprobe(struct consdev *cp) +{ + struct bus_device *b; + int maj, unit, pri; + +#define CONSOLE_PARAMETER " console=com" + u_char *console = (u_char *) strstr(kernel_cmdline, CONSOLE_PARAMETER); + + if (console) + mach_atoi(console + strlen(CONSOLE_PARAMETER), &rcline); + + if (strncmp(kernel_cmdline, CONSOLE_PARAMETER + 1, + strlen(CONSOLE_PARAMETER) - 1) == 0) + mach_atoi((u_char*)kernel_cmdline + strlen(CONSOLE_PARAMETER) - 1, + &rcline); + + maj = 0; + unit = -1; + pri = CN_DEAD; + + for (b = bus_device_init; b->driver; b++) + if (strcmp(b->name, "com") == 0 + && b->unit == rcline + && comprobe_general(b, /*quiet*/ 0)) + { + /* Found one */ + comcndev = b; + unit = b->unit; + pri = CN_REMOTE; + break; + } + + cp->cn_dev = makedev(maj, unit); + cp->cn_pri = pri; + + return 0; +} + + +/* + * + * Device Attach's are called during kernel boot, but only if the matching + * device Probe returned a 1. + * + */ +void +comattach(struct bus_device *dev) +{ + u_char unit = dev->unit; + u_short addr = dev->address; + + if (unit >= NCOM) { + printf(", disabled by NCOM configuration\n"); + return; + } + + take_dev_irq(dev); + printf(", port = %zx, spl = %zu, pic = %d. (DOS COM%d)", + dev->address, dev->sysdep, dev->sysdep1, unit+1); + +/* comcarrier[unit] = addr->flags;*/ + commodem[unit] = 0; + + outb(INTR_ENAB(addr), 0); + outb(MODEM_CTL(addr), 0); + while (!(inb(INTR_ID(addr))&1)) { + (void) inb(LINE_STAT (addr)); /* reset overrun error etc */ + (void) inb(TXRX (addr)); /* reset data-ready */ + (void) inb(MODEM_STAT(addr)); /* reset modem status reg */ + } +} + +/* + * Attach/init routine for console. This isn't called by + * configure_bus_device which sets the alive, adaptor, and minfo + * fields of the bus_device struct (comattach is), therefore we do + * that by hand. + */ +int +comcninit(struct consdev *cp) +{ + u_char unit = comcndev->unit; + u_short addr = comcndev->address; + + take_dev_irq(comcndev); + + comcndev->alive = 1; + comcndev->adaptor = 0; + cominfo[minor(cp->cn_dev)] = comcndev; + + outb(LINE_CTL(addr), iDLAB); + outb(BAUD_LSB(addr), divisorreg[RCBAUD] & 0xff); + outb(BAUD_MSB(addr), divisorreg[RCBAUD] >>8); + outb(LINE_CTL(addr), i8BITS); + outb(INTR_ENAB(addr), 0); + outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2); + + { + char msg[128]; + volatile unsigned char *p = (volatile unsigned char *)phystokv(0xb8000); + int i; + + sprintf(msg, " **** using COM port %d for console ****", + unit+1); + for (i = 0; msg[i]; i++) { + p[2*i] = msg[i]; + p[2*i+1] = (0<<7) /* blink */ + | (0x0<<4) /* bg */ + | (1<<3) /* hi-intensity */ + | 0x4; /* fg */ + } + } + + return 0; +} + +/* + * Probe for COM after autoconfiguration. + * Used to handle PCMCIA modems, which may appear + * at any time. + */ +static boolean_t com_reprobe( + int unit) +{ + struct bus_device *device; + + /* + * Look for COM device in the device + * initialization list. It must not be alive + * (otherwise we would have opened it already). + */ + for (device = bus_device_init; device->driver; device++) { + if (device->driver == &comdriver && device->unit == unit && + !device->alive && device->ctlr == (char)-1) + { + /* + * Found an entry for com port . + * Probe it. + */ + if (configure_bus_device(device->name, + device->address, + device->phys_address, + 0, + "atbus")) + return TRUE; + } + } + return FALSE; +} + +io_return_t comopen( + dev_t dev, + int flag, + io_req_t ior) +{ + int unit = minor(dev); + u_short addr; + struct bus_device *isai; + struct tty *tp; + spl_t s; + io_return_t result; + + if (unit >= NCOM) + return D_NO_SUCH_DEVICE; /* no such device */ + if ((isai = cominfo[unit]) == 0 || isai->alive == 0) { + /* + * Try to probe it again + */ + if (!com_reprobe(unit)) + return D_NO_SUCH_DEVICE; + if ((isai = cominfo[unit]) == 0 || isai->alive == 0) + return D_NO_SUCH_DEVICE; + } + tp = &com_tty[unit]; + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0) { + ttychars(tp); + tp->t_addr = (char *)isai->address; + tp->t_dev = dev; + tp->t_oproc = comstart; + tp->t_stop = comstop; + tp->t_mctl = commctl; + tp->t_getstat = comgetstat; + tp->t_setstat = comsetstat; + if (tp->t_ispeed == 0) { + tp->t_ispeed = ISPEED; + tp->t_ospeed = ISPEED; + tp->t_flags = IFLAGS; + tp->t_state &= ~TS_BUSY; + } + } +/*rvb tp->t_state |= TS_WOPEN; */ + if ((tp->t_state & TS_ISOPEN) == 0) + comparam(unit); + addr = (uintptr_t)tp->t_addr; + + s = spltty(); + if (!comcarrier[unit]) /* not originating */ + tp->t_state |= TS_CARR_ON; + else { + int modem_stat = inb(MODEM_STAT(addr)); + if (modem_stat & iRLSD) + tp->t_state |= TS_CARR_ON; + else + tp->t_state &= ~TS_CARR_ON; + fix_modem_state(unit, modem_stat); + } + splx(s); + + result = char_open(dev, tp, flag, ior); + + if (!comtimer_active) { + comtimer_active = TRUE; + comtimer(NULL); + } + + s = spltty(); + while(!(inb(INTR_ID(addr))&1)) { /* while pending interrupts */ + (void) inb(LINE_STAT (addr)); /* reset overrun error */ + (void) inb(TXRX (addr)); /* reset data-ready */ + (void) inb(MODEM_STAT(addr)); /* reset modem status */ + } + splx(s); + return result; +} + +void comclose(dev_t dev, int flag) +{ + struct tty *tp = &com_tty[minor(dev)]; + u_short addr = (uintptr_t)tp->t_addr; + + ttyclose(tp); + if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) { + outb(INTR_ENAB(addr), 0); + outb(MODEM_CTL(addr), 0); + tp->t_state &= ~TS_BUSY; + commodem[minor(dev)] = 0; + if (comfifo[minor(dev)] != 0) + outb(INTR_ID(addr), 0x00); /* Disable fifos */ + } + return; +} + +io_return_t comread(dev_t dev, io_req_t ior) +{ + return char_read(&com_tty[minor(dev)], ior); +} + +io_return_t comwrite(dev_t dev, io_req_t ior) +{ + return char_write(&com_tty[minor(dev)], ior); +} + +io_return_t comportdeath(dev_t dev, mach_port_t port) +{ + return (tty_portdeath(&com_tty[minor(dev)], (ipc_port_t)port)); +} + +io_return_t +comgetstat( + dev_t dev, + dev_flavor_t flavor, + dev_status_t data, /* pointer to OUT array */ + mach_msg_type_number_t *count /* out */ + ) +{ + io_return_t result = D_SUCCESS; + int unit = minor(dev); + + switch (flavor) { + case TTY_MODEM: + fix_modem_state(unit, inb(MODEM_STAT(cominfo[unit]->address))); + *data = commodem[unit]; + *count = 1; + break; + default: + result = tty_get_status(&com_tty[unit], flavor, data, count); + break; + } + return (result); +} + +io_return_t +comsetstat( + dev_t dev, + dev_flavor_t flavor, + dev_status_t data, + mach_msg_type_number_t count) +{ + io_return_t result = D_SUCCESS; + int unit = minor(dev); + struct tty *tp = &com_tty[unit]; + + switch (flavor) { + case TTY_SET_BREAK: + commctl(tp, TM_BRK, DMBIS); + break; + case TTY_CLEAR_BREAK: + commctl(tp, TM_BRK, DMBIC); + break; + case TTY_MODEM: + commctl(tp, *data, DMSET); + break; + default: + result = tty_set_status(&com_tty[unit], flavor, data, count); + if (result == D_SUCCESS && flavor == TTY_STATUS) + comparam(unit); + return (result); + } + return (D_SUCCESS); +} + +void +comintr(int unit) +{ + struct tty *tp = &com_tty[unit]; + u_short addr = cominfo[unit]->address; + static char comoverrun = 0; + char c, line, intr_id; + int line_stat; + + while (! ((intr_id=(inb(INTR_ID(addr))&MASKi)) & 1)) + switch (intr_id) { + case MODi: + /* modem change */ + commodem_intr(unit, inb(MODEM_STAT(addr))); + break; + + case TRAi: + comtimer_state[unit] = 0; + tp->t_state &= ~(TS_BUSY|TS_FLUSH); + tt_write_wakeup(tp); + (void) comstart(tp); + break; + case RECi: + case CTIi: /* Character timeout indication */ + if (tp->t_state&TS_ISOPEN) { + int escape = 0; + while ((line = inb(LINE_STAT(addr))) & iDR) { + c = inb(TXRX(addr)); + + if (c == 0x1b) { + escape = 1; + continue; + } + +#if MACH_KDB + if (escape && c == 'D'-('A'-1)) + /* ctrl-alt-d pressed, + invoke debugger */ + kdb_kintr(); + else +#endif /* MACH_KDB */ + if (escape) { + ttyinput(0x1b, tp); + ttyinput(c, tp); + } + else + ttyinput(c, tp); + + escape = 0; + } + + if (escape) + /* just escape */ + ttyinput(0x1b, tp); + } else + tt_open_wakeup(tp); + break; + case LINi: + line_stat = inb(LINE_STAT(addr)); + + if ((line_stat & iPE) && + ((tp->t_flags&(EVENP|ODDP)) == EVENP || + (tp->t_flags&(EVENP|ODDP)) == ODDP)) { + /* parity error */; + } else if (line_stat&iOR && !comoverrun) { + printf("com%d: overrun\n", unit); + comoverrun = 1; + } else if (line_stat & (iFE | iBRKINTR)) { + /* framing error or break */ + ttyinput(tp->t_breakc, tp); + } + break; + } +} + +static void +comparam(int unit) +{ + struct tty *tp = &com_tty[unit]; + u_short addr = (uintptr_t)tp->t_addr; + spl_t s = spltty(); + int mode; + + if (tp->t_ispeed == B0) { + tp->t_state |= TS_HUPCLS; + outb(MODEM_CTL(addr), iOUT2); + commodem[unit] = 0; + splx(s); + return; + } + + /* Do input buffering */ + if (tp->t_ispeed >= B300) + tp->t_state |= TS_MIN; + + outb(LINE_CTL(addr), iDLAB); + outb(BAUD_LSB(addr), divisorreg[tp->t_ispeed] & 0xff); + outb(BAUD_MSB(addr), divisorreg[tp->t_ispeed] >> 8); + + if (tp->t_flags & (RAW|LITOUT|PASS8)) + mode = i8BITS; + else + mode = i7BITS | iPEN; + if (tp->t_flags & EVENP) + mode |= iEPS; + if (tp->t_ispeed == B110) + /* + * 110 baud uses two stop bits - + * all other speeds use one + */ + mode |= iSTB; + + outb(LINE_CTL(addr), mode); + + outb(INTR_ENAB(addr), iTX_ENAB|iRX_ENAB|iMODEM_ENAB|iERROR_ENAB); + if (comfifo[unit]) + outb(FIFO_CTL(addr), iFIFOENA|iFIFO14CH); + outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2); + commodem[unit] |= (TM_DTR|TM_RTS); + splx(s); +} + +int comst_1, comst_2, comst_3, comst_4, comst_5 = 14; + +void +comstart(struct tty *tp) +{ + int nch; +#if 0 + int i; +#endif + + if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) { +comst_1++; + return; + } + if ((!queue_empty(&tp->t_delayed_write)) && + (tp->t_outq.c_cc <= TTLOWAT(tp))) { +comst_2++; + tt_write_wakeup(tp); + } + if (!tp->t_outq.c_cc) { +comst_3++; + return; + } + +#if 0 + i = (comfifo[minor(tp->t_dev)]) ? /*14*/comst_5 : 1; + + tp->t_state |= TS_BUSY; + while (i-- > 0) { + nch = getc(&tp->t_outq); + if (nch == -1) break; + if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) { + timeout(ttrstrt, (char *)tp, (nch & 0x7f) + 6); + tp->t_state |= TS_TIMEOUT; +comst_4++; + return(0); + } + outb(TXRX((uintptr_t)tp->t_addr), nch); + } +#else + nch = getc(&tp->t_outq); + if (nch == -1) + return; + if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) { + timeout((timer_func_t *)ttrstrt, (char *)tp, (nch & 0x7f) + 6); + tp->t_state |= TS_TIMEOUT; +comst_4++; + return; + } + outb(TXRX((uintptr_t)tp->t_addr), nch); + tp->t_state |= TS_BUSY; +#endif +} + +/* Check for stuck xmitters */ +int comtimer_interval = 5; + +void +comtimer(void * param) +{ + spl_t s = spltty(); + struct tty *tp = com_tty; + int i, nch; + + for (i = 0; i < NCOM; i++, tp++) { + if ((tp->t_state & TS_ISOPEN) == 0) + continue; + if (!tp->t_outq.c_cc) + continue; + if (++comtimer_state[i] < 2) + continue; + /* Its stuck */ +printf("Tty %p was stuck\n", tp); + nch = getc(&tp->t_outq); + outb(TXRX((uintptr_t)tp->t_addr), nch); + } + + splx(s); + timeout(comtimer, 0, comtimer_interval*hz); +} + +/* + * Set receive modem state from modem status register. + */ +void +fix_modem_state( + int unit, + int modem_stat) +{ + int stat = 0; + + if (modem_stat & iCTS) + stat |= TM_CTS; /* clear to send */ + if (modem_stat & iDSR) + stat |= TM_DSR; /* data set ready */ + if (modem_stat & iRI) + stat |= TM_RNG; /* ring indicator */ + if (modem_stat & iRLSD) + stat |= TM_CAR; /* carrier? */ + + commodem[unit] = (commodem[unit] & ~(TM_CTS|TM_DSR|TM_RNG|TM_CAR)) + | stat; +} + +/* + * Modem change (input signals) + */ +void +commodem_intr( + int unit, + int stat) +{ + int changed; + + changed = commodem[unit]; + fix_modem_state(unit, stat); + stat = commodem[unit]; + + /* Assumption: if the other party can handle + modem signals then it should handle all + the necessary ones. Else fix the cable. */ + + changed ^= stat; /* what changed ? */ + + if (changed & TM_CTS) + tty_cts( &com_tty[unit], stat & TM_CTS ); + +#if 0 + if (changed & TM_CAR) + ttymodem( &com_tty[unit], stat & TM_CAR ); +#endif + +} + +/* + * Set/get modem bits + */ +int +commctl( + struct tty *tp, + int bits, + int how) +{ + spl_t s; + int unit; + vm_offset_t dev_addr; + int b = 0; /* Suppress gcc warning */ + + unit = minor(tp->t_dev); + + if (bits == TM_HUP) { /* close line (internal) */ + bits = TM_DTR | TM_RTS; + how = DMBIC; + } + + if (how == DMGET) return commodem[unit]; + + dev_addr = cominfo[unit]->address; + + s = spltty(); + + switch (how) { + case DMSET: + b = bits; break; + case DMBIS: + b = commodem[unit] | bits; break; + case DMBIC: + b = commodem[unit] & ~bits; break; + } + commodem[unit] = b; + + if (bits & TM_BRK) { + if (b & TM_BRK) { + outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) | iSETBREAK); + } else { + outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) & ~iSETBREAK); + } + } + +#if 0 + /* do I need to do something on this ? */ + if (bits & TM_LE) { /* line enable */ + } +#endif +#if 0 + /* Unsupported */ + if (bits & TM_ST) { /* secondary transmit */ + } + if (bits & TM_SR) { /* secondary receive */ + } +#endif + if (bits & (TM_DTR|TM_RTS)) { /* data terminal ready, request to send */ + how = iOUT2; + if (b & TM_DTR) how |= iDTR; + if (b & TM_RTS) how |= iRTS; + outb(MODEM_CTL(dev_addr), how); + } + + splx(s); + + /* the rest are inputs */ + return commodem[unit]; +} + +void +comstop( + struct tty *tp, + int flags) +{ + if ((tp->t_state & TS_BUSY) && (tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; +} + +/* + * + * Code to be called from debugger. + * + */ +void compr_addr(vm_offset_t addr) +{ + /* The two line_stat prints may show different values, since + * touching some of the registers constitutes changing them. + */ + printf("LINE_STAT(%zu) %x\n", + LINE_STAT(addr), inb(LINE_STAT(addr))); + + printf("TXRX(%zu) %x, INTR_ENAB(%zu) %x, INTR_ID(%zu) %x, LINE_CTL(%zu) %x,\n\ +MODEM_CTL(%zu) %x, LINE_STAT(%zu) %x, MODEM_STAT(%zu) %x\n", + TXRX(addr), inb(TXRX(addr)), + INTR_ENAB(addr), inb(INTR_ENAB(addr)), + INTR_ID(addr), inb(INTR_ID(addr)), + LINE_CTL(addr), inb(LINE_CTL(addr)), + MODEM_CTL(addr), inb(MODEM_CTL(addr)), + LINE_STAT(addr), inb(LINE_STAT(addr)), + MODEM_STAT(addr),inb(MODEM_STAT(addr))); +} + +int compr(int unit) +{ + compr_addr(cominfo[unit]->address); + return(0); +} + +int +comgetc(int unit) +{ + u_short addr = (u_short)(cominfo[unit]->address); + spl_t s = spltty(); + int c; + + while((inb(LINE_STAT(addr)) & iDR) == 0) ; + + c = inb(TXRX(addr)); + splx(s); + return c; +} + +/* + * Routines for the console + */ +int +comcnputc(dev_t dev, int c) +{ + u_short addr = (u_short)(cominfo[minor(dev)]->address); + + /* Wait for transmitter to empty */ + while((inb(LINE_STAT(addr)) & iTHRE) == 0) + continue; + + /* send the char */ + if (c == '\n') + comcnputc(dev, '\r'); + outb(addr, c); + + return 0; +} + +int +comcngetc(dev_t dev, int wait) +{ + u_short addr = (u_short)(cominfo[minor(dev)]->address); + int c; + + while((inb(LINE_STAT(addr)) & iDR) == 0) + if (! wait) + return 0; + + c = inb(TXRX(addr)); + return c & 0x7f; +} + +#endif /* NCOM */ -- cgit v1.2.1