147752Swilliam /*- 249570Swilliam * Copyright (c) 1991 The Regents of the University of California. 349570Swilliam * All rights reserved. 447752Swilliam * 547752Swilliam * %sccs.include.redist.c% 647752Swilliam * 7*49697Swilliam * @(#)com.c 7.4 (Berkeley) 05/12/91 847752Swilliam */ 947752Swilliam 1049569Swilliam #include "com.h" 1149569Swilliam #if NCOM > 0 1247752Swilliam /* 1349570Swilliam * COM driver, based on HP dca driver 1449570Swilliam * uses National Semiconductor NS16450/NS16550AF UART 1547752Swilliam */ 1649570Swilliam #include "param.h" 1749570Swilliam #include "systm.h" 1849570Swilliam #include "ioctl.h" 1949570Swilliam #include "tty.h" 2049570Swilliam #include "proc.h" 2149570Swilliam #include "user.h" 2249570Swilliam #include "conf.h" 2349570Swilliam #include "file.h" 2449570Swilliam #include "uio.h" 2549570Swilliam #include "kernel.h" 2649570Swilliam #include "syslog.h" 2747752Swilliam 2847752Swilliam #include "i386/isa/isa_device.h" 2947752Swilliam #include "i386/isa/comreg.h" 3049570Swilliam #include "i386/isa/ic/ns16550.h" 3147752Swilliam 3247752Swilliam int comprobe(), comattach(), comintr(), comstart(), comparam(); 3347752Swilliam 3447752Swilliam struct isa_driver comdriver = { 3547752Swilliam comprobe, comattach, "com" 3647752Swilliam }; 3747752Swilliam 3847752Swilliam int comsoftCAR; 3947752Swilliam int com_active; 4049570Swilliam int com_hasfifo; 4149569Swilliam int ncom = NCOM; 4249570Swilliam #ifdef COMCONSOLE 4349570Swilliam int comconsole = COMCONSOLE; 4449570Swilliam #else 4547752Swilliam int comconsole = -1; 4649570Swilliam #endif 4749570Swilliam int comconsinit; 4847752Swilliam int comdefaultrate = TTYDEF_SPEED; 4949570Swilliam int commajor; 5049569Swilliam short com_addr[NCOM]; 5149569Swilliam struct tty com_tty[NCOM]; 5247752Swilliam 5347752Swilliam struct speedtab comspeedtab[] = { 5447752Swilliam 0, 0, 5547752Swilliam 50, COMBRD(50), 5647752Swilliam 75, COMBRD(75), 5747752Swilliam 110, COMBRD(110), 5847752Swilliam 134, COMBRD(134), 5947752Swilliam 150, COMBRD(150), 6047752Swilliam 200, COMBRD(200), 6147752Swilliam 300, COMBRD(300), 6247752Swilliam 600, COMBRD(600), 6347752Swilliam 1200, COMBRD(1200), 6447752Swilliam 1800, COMBRD(1800), 6547752Swilliam 2400, COMBRD(2400), 6647752Swilliam 4800, COMBRD(4800), 6747752Swilliam 9600, COMBRD(9600), 6847752Swilliam 19200, COMBRD(19200), 6947752Swilliam 38400, COMBRD(38400), 7047752Swilliam 57600, COMBRD(57600), 7147752Swilliam -1, -1 7247752Swilliam }; 7347752Swilliam 7447752Swilliam extern struct tty *constty; 7547752Swilliam #ifdef KGDB 7649570Swilliam #include "machine/remote-sl.h" 7749570Swilliam 7847752Swilliam extern int kgdb_dev; 7947752Swilliam extern int kgdb_rate; 8047752Swilliam extern int kgdb_debug_init; 8147752Swilliam #endif 8247752Swilliam 8347752Swilliam #define UNIT(x) minor(x) 8447752Swilliam 8547752Swilliam comprobe(dev) 8647752Swilliam struct isa_device *dev; 8747752Swilliam { 88*49697Swilliam /* force access to id reg */ 89*49697Swilliam outb(dev->id_iobase+com_cfcr, 0); 90*49697Swilliam outb(dev->id_iobase+com_iir, 0); 91*49697Swilliam if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) 9247752Swilliam return(1); 9349570Swilliam return(1); 9447752Swilliam 9547752Swilliam } 9647752Swilliam 9747752Swilliam 9847752Swilliam int 9947752Swilliam comattach(isdp) 10047752Swilliam struct isa_device *isdp; 10147752Swilliam { 10247752Swilliam struct tty *tp; 10347752Swilliam u_char unit; 10447752Swilliam int port = isdp->id_iobase; 10547752Swilliam 10649570Swilliam unit = isdp->id_unit; 10747752Swilliam if (unit == comconsole) 10847752Swilliam DELAY(100000); 10947752Swilliam com_addr[unit] = port; 11047752Swilliam com_active |= 1 << unit; 11149570Swilliam comsoftCAR |= 1 << unit; /* XXX */ 11249570Swilliam 11349570Swilliam /* look for a NS 16550AF UART with FIFOs */ 11449570Swilliam outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 11549570Swilliam DELAY(100); 11649570Swilliam if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) 11749570Swilliam com_hasfifo |= 1 << unit; 11849570Swilliam 11947752Swilliam outb(port+com_ier, 0); 12047752Swilliam outb(port+com_mcr, 0 | MCR_IENABLE); 12147752Swilliam #ifdef KGDB 122*49697Swilliam if (kgdb_dev == makedev(commajor, unit)) { 12347752Swilliam if (comconsole == unit) 12447752Swilliam kgdb_dev = -1; /* can't debug over console port */ 12547752Swilliam else { 12649570Swilliam (void) cominit(unit, kgdb_rate); 12747752Swilliam if (kgdb_debug_init) { 12849570Swilliam /* 12949570Swilliam * Print prefix of device name, 13049570Swilliam * let kgdb_connect print the rest. 13149570Swilliam */ 13249570Swilliam printf("com%d: ", unit); 13349570Swilliam kgdb_connect(1); 13447752Swilliam } else 13547752Swilliam printf("com%d: kgdb enabled\n", unit); 13647752Swilliam } 13747752Swilliam } 13847752Swilliam #endif 13947752Swilliam /* 14049570Swilliam * Need to reset baud rate, etc. of next print so reset comconsinit. 14147752Swilliam * Also make sure console is always "hardwired" 14247752Swilliam */ 14347752Swilliam if (unit == comconsole) { 14449570Swilliam comconsinit = 0; 14547752Swilliam comsoftCAR |= (1 << unit); 14647752Swilliam } 14747752Swilliam return (1); 14847752Swilliam } 14947752Swilliam 15049569Swilliam /* ARGSUSED */ 15149569Swilliam #ifdef __STDC__ 15249569Swilliam comopen(dev_t dev, int flag, int mode, struct proc *p) 15349569Swilliam #else 15449569Swilliam comopen(dev, flag, mode, p) 15547752Swilliam dev_t dev; 15649569Swilliam int flag, mode; 15749569Swilliam struct proc *p; 15849569Swilliam #endif 15947752Swilliam { 16047752Swilliam register struct tty *tp; 16147752Swilliam register int unit; 16247752Swilliam int error = 0; 16347752Swilliam 16447752Swilliam unit = UNIT(dev); 16549569Swilliam if (unit >= NCOM || (com_active & (1 << unit)) == 0) 16647752Swilliam return (ENXIO); 16747752Swilliam tp = &com_tty[unit]; 16847752Swilliam tp->t_oproc = comstart; 16947752Swilliam tp->t_param = comparam; 17047752Swilliam tp->t_dev = dev; 17147752Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { 17247752Swilliam tp->t_state |= TS_WOPEN; 17347752Swilliam ttychars(tp); 17449570Swilliam if (tp->t_ispeed == 0) { 17549570Swilliam tp->t_iflag = TTYDEF_IFLAG; 17649570Swilliam tp->t_oflag = TTYDEF_OFLAG; 17749570Swilliam tp->t_cflag = TTYDEF_CFLAG; 17849570Swilliam tp->t_lflag = TTYDEF_LFLAG; 17949570Swilliam tp->t_ispeed = tp->t_ospeed = comdefaultrate; 18049570Swilliam } 18147752Swilliam comparam(tp, &tp->t_termios); 18247752Swilliam ttsetwater(tp); 18349569Swilliam } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 18447752Swilliam return (EBUSY); 18547752Swilliam (void) spltty(); 18647752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); 18747752Swilliam if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) 18847752Swilliam tp->t_state |= TS_CARR_ON; 18947752Swilliam while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 19047752Swilliam (tp->t_state & TS_CARR_ON) == 0) { 19147752Swilliam tp->t_state |= TS_WOPEN; 19247752Swilliam if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 19347752Swilliam ttopen, 0)) 19447752Swilliam break; 19547752Swilliam } 19647752Swilliam (void) spl0(); 19747752Swilliam if (error == 0) 19847752Swilliam error = (*linesw[tp->t_line].l_open)(dev, tp); 19947752Swilliam return (error); 20047752Swilliam } 20147752Swilliam 20247752Swilliam /*ARGSUSED*/ 20347752Swilliam comclose(dev, flag) 20447752Swilliam dev_t dev; 20547752Swilliam { 20647752Swilliam register struct tty *tp; 20747752Swilliam register com; 20847752Swilliam register int unit; 20947752Swilliam 21047752Swilliam unit = UNIT(dev); 21147752Swilliam com = com_addr[unit]; 21247752Swilliam tp = &com_tty[unit]; 21347752Swilliam (*linesw[tp->t_line].l_close)(tp); 21447752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 21547752Swilliam #ifdef KGDB 21647752Swilliam /* do not disable interrupts if debugging */ 21749570Swilliam if (kgdb_dev != makedev(commajor, unit)) 21847752Swilliam #endif 21947752Swilliam outb(com+com_ier, 0); 22047752Swilliam if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 22147752Swilliam (tp->t_state&TS_ISOPEN) == 0) 22247752Swilliam (void) commctl(dev, 0, DMSET); 22347752Swilliam ttyclose(tp); 22447752Swilliam return(0); 22547752Swilliam } 22647752Swilliam 22747752Swilliam comread(dev, uio, flag) 22847752Swilliam dev_t dev; 22947752Swilliam struct uio *uio; 23047752Swilliam { 23147752Swilliam register struct tty *tp = &com_tty[UNIT(dev)]; 23247752Swilliam 23347752Swilliam return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 23447752Swilliam } 23547752Swilliam 23647752Swilliam comwrite(dev, uio, flag) 23747752Swilliam dev_t dev; 23847752Swilliam struct uio *uio; 23947752Swilliam { 24047752Swilliam int unit = UNIT(dev); 24147752Swilliam register struct tty *tp = &com_tty[unit]; 24247752Swilliam 24347752Swilliam /* 24447752Swilliam * (XXX) We disallow virtual consoles if the physical console is 24547752Swilliam * a serial port. This is in case there is a display attached that 24647752Swilliam * is not the console. In that situation we don't need/want the X 24747752Swilliam * server taking over the console. 24847752Swilliam */ 24947752Swilliam if (constty && unit == comconsole) 25047752Swilliam constty = NULL; 25147752Swilliam return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 25247752Swilliam } 25347752Swilliam 25447752Swilliam comintr(unit) 25547752Swilliam register int unit; 25647752Swilliam { 25747752Swilliam register com; 25847752Swilliam register u_char code; 25947752Swilliam register struct tty *tp; 26047752Swilliam 26147752Swilliam com = com_addr[unit]; 26247752Swilliam while (1) { 26347752Swilliam code = inb(com+com_iir); 26449570Swilliam switch (code & IIR_IMASK) { 26547752Swilliam case IIR_NOPEND: 26647752Swilliam return (1); 26749570Swilliam case IIR_RXTOUT: 26847752Swilliam case IIR_RXRDY: 26947752Swilliam tp = &com_tty[unit]; 27049570Swilliam /* 27149570Swilliam * Process received bytes. Inline for speed... 27249570Swilliam */ 27347752Swilliam #ifdef KGDB 27449570Swilliam #define RCVBYTE() \ 27549570Swilliam code = inb(com+com_data); \ 27649570Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { \ 27749570Swilliam if (kgdb_dev == makedev(commajor, unit) && \ 27849570Swilliam code == FRAME_END) \ 27949570Swilliam kgdb_connect(0); /* trap into kgdb */ \ 28049570Swilliam } else \ 28149570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 28249570Swilliam #else 28349570Swilliam #define RCVBYTE() \ 28449570Swilliam code = inb(com+com_data); \ 28549570Swilliam if (tp->t_state & TS_ISOPEN) \ 28649570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 28749570Swilliam #endif 28849570Swilliam 28949570Swilliam RCVBYTE(); 29049570Swilliam 29149570Swilliam if (com_hasfifo & (1 << unit)) 29249570Swilliam while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 29349570Swilliam if (code == LSR_RXRDY) { 29449570Swilliam RCVBYTE(); 29549570Swilliam } else 29649570Swilliam comeint(unit, code, com); 29747752Swilliam } 29847752Swilliam break; 29947752Swilliam case IIR_TXRDY: 30047752Swilliam tp = &com_tty[unit]; 30147752Swilliam tp->t_state &=~ (TS_BUSY|TS_FLUSH); 30247752Swilliam if (tp->t_line) 30347752Swilliam (*linesw[tp->t_line].l_start)(tp); 30447752Swilliam else 30547752Swilliam comstart(tp); 30647752Swilliam break; 30747752Swilliam case IIR_RLS: 30849570Swilliam comeint(unit, inb(com+com_lsr), com); 30947752Swilliam break; 31047752Swilliam default: 31147752Swilliam if (code & IIR_NOPEND) 31247752Swilliam return (1); 31347752Swilliam log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 31447752Swilliam unit, code); 31547752Swilliam /* fall through */ 31647752Swilliam case IIR_MLSC: 31747752Swilliam commint(unit, com); 31847752Swilliam break; 31947752Swilliam } 32047752Swilliam } 32147752Swilliam } 32247752Swilliam 32349570Swilliam comeint(unit, stat, com) 32449570Swilliam register int unit, stat; 32547752Swilliam register com; 32647752Swilliam { 32747752Swilliam register struct tty *tp; 32849570Swilliam register int c; 32947752Swilliam 33047752Swilliam tp = &com_tty[unit]; 33147752Swilliam c = inb(com+com_data); 33247752Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { 33347752Swilliam #ifdef KGDB 33447752Swilliam /* we don't care about parity errors */ 33547752Swilliam if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 33649570Swilliam kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 33749570Swilliam kgdb_connect(0); /* trap into kgdb */ 33847752Swilliam #endif 33947752Swilliam return; 34047752Swilliam } 34147752Swilliam if (stat & (LSR_BI | LSR_FE)) 34247752Swilliam c |= TTY_FE; 34347752Swilliam else if (stat & LSR_PE) 34447752Swilliam c |= TTY_PE; 34547752Swilliam else if (stat & LSR_OE) 34647752Swilliam log(LOG_WARNING, "com%d: silo overflow\n", unit); 34747752Swilliam (*linesw[tp->t_line].l_rint)(c, tp); 34847752Swilliam } 34947752Swilliam 35047752Swilliam commint(unit, com) 35147752Swilliam register int unit; 35247752Swilliam register com; 35347752Swilliam { 35447752Swilliam register struct tty *tp; 35547752Swilliam register int stat; 35647752Swilliam 35747752Swilliam tp = &com_tty[unit]; 35847752Swilliam stat = inb(com+com_msr); 35947752Swilliam if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 36047752Swilliam if (stat & MSR_DCD) 36147752Swilliam (void)(*linesw[tp->t_line].l_modem)(tp, 1); 36247752Swilliam else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36347752Swilliam outb(com+com_mcr, 36447752Swilliam inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 36547752Swilliam } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 36647752Swilliam (tp->t_flags & CRTSCTS)) { 36747752Swilliam /* the line is up and we want to do rts/cts flow control */ 36847752Swilliam if (stat & MSR_CTS) { 36947752Swilliam tp->t_state &=~ TS_TTSTOP; 37047752Swilliam ttstart(tp); 37147752Swilliam } else 37247752Swilliam tp->t_state |= TS_TTSTOP; 37347752Swilliam } 37447752Swilliam } 37547752Swilliam 37647752Swilliam comioctl(dev, cmd, data, flag) 37747752Swilliam dev_t dev; 37847752Swilliam caddr_t data; 37947752Swilliam { 38047752Swilliam register struct tty *tp; 38147752Swilliam register int unit = UNIT(dev); 38247752Swilliam register com; 38347752Swilliam register int error; 38447752Swilliam 38547752Swilliam tp = &com_tty[unit]; 38647752Swilliam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38747752Swilliam if (error >= 0) 38847752Swilliam return (error); 38947752Swilliam error = ttioctl(tp, cmd, data, flag); 39047752Swilliam if (error >= 0) 39147752Swilliam return (error); 39247752Swilliam 39347752Swilliam com = com_addr[unit]; 39447752Swilliam switch (cmd) { 39547752Swilliam 39647752Swilliam case TIOCSBRK: 39747752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 39847752Swilliam break; 39947752Swilliam 40047752Swilliam case TIOCCBRK: 40147752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 40247752Swilliam break; 40347752Swilliam 40447752Swilliam case TIOCSDTR: 40547752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 40647752Swilliam break; 40747752Swilliam 40847752Swilliam case TIOCCDTR: 40947752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 41047752Swilliam break; 41147752Swilliam 41247752Swilliam case TIOCMSET: 41347752Swilliam (void) commctl(dev, *(int *)data, DMSET); 41447752Swilliam break; 41547752Swilliam 41647752Swilliam case TIOCMBIS: 41747752Swilliam (void) commctl(dev, *(int *)data, DMBIS); 41847752Swilliam break; 41947752Swilliam 42047752Swilliam case TIOCMBIC: 42147752Swilliam (void) commctl(dev, *(int *)data, DMBIC); 42247752Swilliam break; 42347752Swilliam 42447752Swilliam case TIOCMGET: 42547752Swilliam *(int *)data = commctl(dev, 0, DMGET); 42647752Swilliam break; 42747752Swilliam 42847752Swilliam default: 42947752Swilliam return (ENOTTY); 43047752Swilliam } 43147752Swilliam return (0); 43247752Swilliam } 43347752Swilliam 43447752Swilliam comparam(tp, t) 43547752Swilliam register struct tty *tp; 43647752Swilliam register struct termios *t; 43747752Swilliam { 43847752Swilliam register com; 43947752Swilliam register int cfcr, cflag = t->c_cflag; 44047752Swilliam int unit = UNIT(tp->t_dev); 44147752Swilliam int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 44247752Swilliam 44347752Swilliam /* check requested parameters */ 44447752Swilliam if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 44547752Swilliam return(EINVAL); 44647752Swilliam /* and copy to tty */ 44747752Swilliam tp->t_ispeed = t->c_ispeed; 44847752Swilliam tp->t_ospeed = t->c_ospeed; 44947752Swilliam tp->t_cflag = cflag; 45047752Swilliam 45147752Swilliam com = com_addr[unit]; 45247752Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 45347752Swilliam if (ospeed == 0) { 45447752Swilliam (void) commctl(unit, 0, DMSET); /* hang up line */ 45547752Swilliam return(0); 45647752Swilliam } 45747752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 45847752Swilliam outb(com+com_data, ospeed & 0xFF); 45947752Swilliam outb(com+com_ier, ospeed >> 8); 46047752Swilliam switch (cflag&CSIZE) { 46147752Swilliam case CS5: 46247752Swilliam cfcr = CFCR_5BITS; break; 46347752Swilliam case CS6: 46447752Swilliam cfcr = CFCR_6BITS; break; 46547752Swilliam case CS7: 46647752Swilliam cfcr = CFCR_7BITS; break; 46747752Swilliam case CS8: 46847752Swilliam cfcr = CFCR_8BITS; break; 46947752Swilliam } 47047752Swilliam if (cflag&PARENB) { 47147752Swilliam cfcr |= CFCR_PENAB; 47247752Swilliam if ((cflag&PARODD) == 0) 47347752Swilliam cfcr |= CFCR_PEVEN; 47447752Swilliam } 47547752Swilliam if (cflag&CSTOPB) 47647752Swilliam cfcr |= CFCR_STOPB; 47747752Swilliam outb(com+com_cfcr, cfcr); 47849570Swilliam 47949570Swilliam if (com_hasfifo & (1 << unit)) 48049570Swilliam outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); 48149570Swilliam 48247752Swilliam return(0); 48347752Swilliam } 48447752Swilliam 48547752Swilliam comstart(tp) 48647752Swilliam register struct tty *tp; 48747752Swilliam { 48847752Swilliam register com; 48947752Swilliam int s, unit, c; 49047752Swilliam 49147752Swilliam unit = UNIT(tp->t_dev); 49247752Swilliam com = com_addr[unit]; 49347752Swilliam s = spltty(); 49447752Swilliam if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 49547752Swilliam goto out; 49647752Swilliam if (tp->t_outq.c_cc <= tp->t_lowat) { 49747752Swilliam if (tp->t_state&TS_ASLEEP) { 49847752Swilliam tp->t_state &= ~TS_ASLEEP; 49947752Swilliam wakeup((caddr_t)&tp->t_outq); 50047752Swilliam } 50147752Swilliam if (tp->t_wsel) { 50247752Swilliam selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 50347752Swilliam tp->t_wsel = 0; 50447752Swilliam tp->t_state &= ~TS_WCOLL; 50547752Swilliam } 50647752Swilliam } 50747752Swilliam if (tp->t_outq.c_cc == 0) 50847752Swilliam goto out; 50947752Swilliam if (inb(com+com_lsr) & LSR_TXRDY) { 51047752Swilliam c = getc(&tp->t_outq); 51147752Swilliam tp->t_state |= TS_BUSY; 51247752Swilliam outb(com+com_data, c); 51349570Swilliam if (com_hasfifo & (1 << unit)) 51449570Swilliam for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 51549570Swilliam outb(com+com_data, getc(&tp->t_outq)); 51647752Swilliam } 51747752Swilliam out: 51847752Swilliam splx(s); 51947752Swilliam } 52047752Swilliam 52147752Swilliam /* 52247752Swilliam * Stop output on a line. 52347752Swilliam */ 52447752Swilliam /*ARGSUSED*/ 52547752Swilliam comstop(tp, flag) 52647752Swilliam register struct tty *tp; 52747752Swilliam { 52847752Swilliam register int s; 52947752Swilliam 53047752Swilliam s = spltty(); 53147752Swilliam if (tp->t_state & TS_BUSY) { 53247752Swilliam if ((tp->t_state&TS_TTSTOP)==0) 53347752Swilliam tp->t_state |= TS_FLUSH; 53447752Swilliam } 53547752Swilliam splx(s); 53647752Swilliam } 53747752Swilliam 53847752Swilliam commctl(dev, bits, how) 53947752Swilliam dev_t dev; 54047752Swilliam int bits, how; 54147752Swilliam { 54247752Swilliam register com; 54347752Swilliam register int unit; 54447752Swilliam int s; 54547752Swilliam 54647752Swilliam unit = UNIT(dev); 54747752Swilliam com = com_addr[unit]; 54847752Swilliam s = spltty(); 54947752Swilliam switch (how) { 55047752Swilliam 55147752Swilliam case DMSET: 55247752Swilliam outb(com+com_mcr, bits | MCR_IENABLE); 55347752Swilliam break; 55447752Swilliam 55547752Swilliam case DMBIS: 55647752Swilliam outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE); 55747752Swilliam break; 55847752Swilliam 55947752Swilliam case DMBIC: 56047752Swilliam outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE); 56147752Swilliam break; 56247752Swilliam 56347752Swilliam case DMGET: 56447752Swilliam bits = inb(com+com_msr); 56547752Swilliam break; 56647752Swilliam } 56747752Swilliam (void) splx(s); 56847752Swilliam return(bits); 56947752Swilliam } 57049570Swilliam 57149570Swilliam /* 57249570Swilliam * Following are all routines needed for COM to act as console 57349570Swilliam */ 57449570Swilliam #include "i386/i386/cons.h" 57549570Swilliam 57649570Swilliam comcnprobe(cp) 57749570Swilliam struct consdev *cp; 57849570Swilliam { 57949570Swilliam int unit; 58049570Swilliam 58149570Swilliam /* locate the major number */ 58249570Swilliam for (commajor = 0; commajor < nchrdev; commajor++) 58349570Swilliam if (cdevsw[commajor].d_open == comopen) 58449570Swilliam break; 58549570Swilliam 58649570Swilliam /* XXX: ick */ 58749570Swilliam unit = CONUNIT; 58849570Swilliam com_addr[CONUNIT] = CONADDR; 58949570Swilliam 59049570Swilliam /* make sure hardware exists? XXX */ 59149570Swilliam 59249570Swilliam /* initialize required fields */ 59349570Swilliam cp->cn_dev = makedev(commajor, unit); 59449570Swilliam cp->cn_tp = &com_tty[unit]; 59549570Swilliam #ifdef COMCONSOLE 59649570Swilliam cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 59749570Swilliam #else 59849570Swilliam cp->cn_pri = CN_NORMAL; 59947752Swilliam #endif 60049570Swilliam } 60149570Swilliam 60249570Swilliam comcninit(cp) 60349570Swilliam struct consdev *cp; 60449570Swilliam { 60549570Swilliam int unit = UNIT(cp->cn_dev); 60649570Swilliam 60749570Swilliam cominit(unit, comdefaultrate); 60849570Swilliam comconsole = unit; 60949570Swilliam comconsinit = 1; 61049570Swilliam } 61149570Swilliam 61249570Swilliam cominit(unit, rate) 61349570Swilliam int unit, rate; 61449570Swilliam { 61549570Swilliam register int com; 61649570Swilliam int s; 61749570Swilliam short stat; 61849570Swilliam 61949570Swilliam #ifdef lint 62049570Swilliam stat = unit; if (stat) return; 62149570Swilliam #endif 62249570Swilliam com = com_addr[unit]; 62349570Swilliam s = splhigh(); 62449570Swilliam outb(com+com_cfcr, CFCR_DLAB); 62549570Swilliam rate = ttspeedtab(comdefaultrate, comspeedtab); 62649570Swilliam outb(com+com_data, rate & 0xFF); 62749570Swilliam outb(com+com_ier, rate >> 8); 62849570Swilliam outb(com+com_cfcr, CFCR_8BITS); 62949570Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); 63049570Swilliam outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 63149570Swilliam stat = inb(com+com_iir); 63249570Swilliam splx(s); 63349570Swilliam } 63449570Swilliam 63549570Swilliam comcngetc(dev) 63649570Swilliam { 63749570Swilliam register com = com_addr[UNIT(dev)]; 63849570Swilliam short stat; 63949570Swilliam int c, s; 64049570Swilliam 64149570Swilliam #ifdef lint 64249570Swilliam stat = dev; if (stat) return(0); 64349570Swilliam #endif 64449570Swilliam s = splhigh(); 64549570Swilliam while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0) 64649570Swilliam ; 64749570Swilliam c = inb(com+com_data); 64849570Swilliam stat = inb(com+com_iir); 64949570Swilliam splx(s); 65049570Swilliam return(c); 65149570Swilliam } 65249570Swilliam 65349570Swilliam /* 65449570Swilliam * Console kernel output character routine. 65549570Swilliam */ 65649570Swilliam comcnputc(dev, c) 65749570Swilliam dev_t dev; 65849570Swilliam register int c; 65949570Swilliam { 66049570Swilliam register com = com_addr[UNIT(dev)]; 66149570Swilliam register int timo; 66249570Swilliam short stat; 66349570Swilliam int s = splhigh(); 66449570Swilliam 66549570Swilliam #ifdef lint 66649570Swilliam stat = dev; if (stat) return; 66749570Swilliam #endif 66849570Swilliam #ifdef KGDB 66949570Swilliam if (dev != kgdb_dev) 67049570Swilliam #endif 67149570Swilliam if (comconsinit == 0) { 67249570Swilliam (void) cominit(UNIT(dev), comdefaultrate); 67349570Swilliam comconsinit = 1; 67449570Swilliam } 67549570Swilliam /* wait for any pending transmission to finish */ 67649570Swilliam timo = 50000; 67749570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 67849570Swilliam ; 67949570Swilliam outb(com+com_data, c); 68049570Swilliam /* wait for this transmission to complete */ 68149570Swilliam timo = 1500000; 68249570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 68349570Swilliam ; 68449570Swilliam /* clear any interrupts generated by this transmission */ 68549570Swilliam stat = inb(com+com_iir); 68649570Swilliam splx(s); 68749570Swilliam } 68849570Swilliam #endif 689