147752Swilliam /*- 2*49570Swilliam * Copyright (c) 1991 The Regents of the University of California. 3*49570Swilliam * All rights reserved. 447752Swilliam * 547752Swilliam * %sccs.include.redist.c% 647752Swilliam * 7*49570Swilliam * @(#)com.c 7.3 (Berkeley) 05/09/91 847752Swilliam */ 947752Swilliam 1049569Swilliam #include "com.h" 1149569Swilliam #if NCOM > 0 1247752Swilliam /* 13*49570Swilliam * COM driver, based on HP dca driver 14*49570Swilliam * uses National Semiconductor NS16450/NS16550AF UART 1547752Swilliam */ 16*49570Swilliam #include "param.h" 17*49570Swilliam #include "systm.h" 18*49570Swilliam #include "ioctl.h" 19*49570Swilliam #include "tty.h" 20*49570Swilliam #include "proc.h" 21*49570Swilliam #include "user.h" 22*49570Swilliam #include "conf.h" 23*49570Swilliam #include "file.h" 24*49570Swilliam #include "uio.h" 25*49570Swilliam #include "kernel.h" 26*49570Swilliam #include "syslog.h" 2747752Swilliam 2847752Swilliam #include "i386/isa/isa_device.h" 2947752Swilliam #include "i386/isa/comreg.h" 30*49570Swilliam #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; 40*49570Swilliam int com_hasfifo; 4149569Swilliam int ncom = NCOM; 42*49570Swilliam #ifdef COMCONSOLE 43*49570Swilliam int comconsole = COMCONSOLE; 44*49570Swilliam #else 4547752Swilliam int comconsole = -1; 46*49570Swilliam #endif 47*49570Swilliam int comconsinit; 4847752Swilliam int comdefaultrate = TTYDEF_SPEED; 49*49570Swilliam 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 76*49570Swilliam #include "machine/remote-sl.h" 77*49570Swilliam 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*49570Swilliam /*if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) 8947752Swilliam return(1); 90*49570Swilliam printf("base %x val %x ", dev->id_iobase, 91*49570Swilliam inb(dev->id_iobase+com_iir));*/ 92*49570Swilliam return(1); 9347752Swilliam 9447752Swilliam } 9547752Swilliam 9647752Swilliam 9747752Swilliam int 9847752Swilliam comattach(isdp) 9947752Swilliam struct isa_device *isdp; 10047752Swilliam { 10147752Swilliam struct tty *tp; 10247752Swilliam u_char unit; 10347752Swilliam int port = isdp->id_iobase; 10447752Swilliam 105*49570Swilliam unit = isdp->id_unit; 10647752Swilliam if (unit == comconsole) 10747752Swilliam DELAY(100000); 10847752Swilliam com_addr[unit] = port; 10947752Swilliam com_active |= 1 << unit; 110*49570Swilliam comsoftCAR |= 1 << unit; /* XXX */ 111*49570Swilliam 112*49570Swilliam /* look for a NS 16550AF UART with FIFOs */ 113*49570Swilliam outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 114*49570Swilliam DELAY(100); 115*49570Swilliam if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) 116*49570Swilliam com_hasfifo |= 1 << unit; 117*49570Swilliam 11847752Swilliam outb(port+com_ier, 0); 11947752Swilliam outb(port+com_mcr, 0 | MCR_IENABLE); 12047752Swilliam #ifdef KGDB 121*49570Swilliam if (1/*kgdb_dev == makedev(commajor, unit)*/) { 12247752Swilliam if (comconsole == unit) 12347752Swilliam kgdb_dev = -1; /* can't debug over console port */ 12447752Swilliam else { 125*49570Swilliam (void) cominit(unit, kgdb_rate); 12647752Swilliam if (kgdb_debug_init) { 127*49570Swilliam /* 128*49570Swilliam * Print prefix of device name, 129*49570Swilliam * let kgdb_connect print the rest. 130*49570Swilliam */ 131*49570Swilliam printf("com%d: ", unit); 132*49570Swilliam kgdb_connect(1); 13347752Swilliam } else 13447752Swilliam printf("com%d: kgdb enabled\n", unit); 13547752Swilliam } 13647752Swilliam } 13747752Swilliam #endif 13847752Swilliam /* 139*49570Swilliam * Need to reset baud rate, etc. of next print so reset comconsinit. 14047752Swilliam * Also make sure console is always "hardwired" 14147752Swilliam */ 14247752Swilliam if (unit == comconsole) { 143*49570Swilliam comconsinit = 0; 14447752Swilliam comsoftCAR |= (1 << unit); 14547752Swilliam } 14647752Swilliam return (1); 14747752Swilliam } 14847752Swilliam 14949569Swilliam /* ARGSUSED */ 15049569Swilliam #ifdef __STDC__ 15149569Swilliam comopen(dev_t dev, int flag, int mode, struct proc *p) 15249569Swilliam #else 15349569Swilliam comopen(dev, flag, mode, p) 15447752Swilliam dev_t dev; 15549569Swilliam int flag, mode; 15649569Swilliam struct proc *p; 15749569Swilliam #endif 15847752Swilliam { 15947752Swilliam register struct tty *tp; 16047752Swilliam register int unit; 16147752Swilliam int error = 0; 16247752Swilliam 16347752Swilliam unit = UNIT(dev); 16449569Swilliam if (unit >= NCOM || (com_active & (1 << unit)) == 0) 16547752Swilliam return (ENXIO); 16647752Swilliam tp = &com_tty[unit]; 16747752Swilliam tp->t_oproc = comstart; 16847752Swilliam tp->t_param = comparam; 16947752Swilliam tp->t_dev = dev; 17047752Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { 17147752Swilliam tp->t_state |= TS_WOPEN; 17247752Swilliam ttychars(tp); 173*49570Swilliam if (tp->t_ispeed == 0) { 174*49570Swilliam tp->t_iflag = TTYDEF_IFLAG; 175*49570Swilliam tp->t_oflag = TTYDEF_OFLAG; 176*49570Swilliam tp->t_cflag = TTYDEF_CFLAG; 177*49570Swilliam tp->t_lflag = TTYDEF_LFLAG; 178*49570Swilliam tp->t_ispeed = tp->t_ospeed = comdefaultrate; 179*49570Swilliam } 18047752Swilliam comparam(tp, &tp->t_termios); 18147752Swilliam ttsetwater(tp); 18249569Swilliam } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 18347752Swilliam return (EBUSY); 18447752Swilliam (void) spltty(); 18547752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); 18647752Swilliam if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) 18747752Swilliam tp->t_state |= TS_CARR_ON; 18847752Swilliam while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 18947752Swilliam (tp->t_state & TS_CARR_ON) == 0) { 19047752Swilliam tp->t_state |= TS_WOPEN; 19147752Swilliam if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 19247752Swilliam ttopen, 0)) 19347752Swilliam break; 19447752Swilliam } 19547752Swilliam (void) spl0(); 19647752Swilliam if (error == 0) 19747752Swilliam error = (*linesw[tp->t_line].l_open)(dev, tp); 19847752Swilliam return (error); 19947752Swilliam } 20047752Swilliam 20147752Swilliam /*ARGSUSED*/ 20247752Swilliam comclose(dev, flag) 20347752Swilliam dev_t dev; 20447752Swilliam { 20547752Swilliam register struct tty *tp; 20647752Swilliam register com; 20747752Swilliam register int unit; 20847752Swilliam 20947752Swilliam unit = UNIT(dev); 21047752Swilliam com = com_addr[unit]; 21147752Swilliam tp = &com_tty[unit]; 21247752Swilliam (*linesw[tp->t_line].l_close)(tp); 21347752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 21447752Swilliam #ifdef KGDB 21547752Swilliam /* do not disable interrupts if debugging */ 216*49570Swilliam if (kgdb_dev != makedev(commajor, unit)) 21747752Swilliam #endif 21847752Swilliam outb(com+com_ier, 0); 21947752Swilliam if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 22047752Swilliam (tp->t_state&TS_ISOPEN) == 0) 22147752Swilliam (void) commctl(dev, 0, DMSET); 22247752Swilliam ttyclose(tp); 22347752Swilliam return(0); 22447752Swilliam } 22547752Swilliam 22647752Swilliam comread(dev, uio, flag) 22747752Swilliam dev_t dev; 22847752Swilliam struct uio *uio; 22947752Swilliam { 23047752Swilliam register struct tty *tp = &com_tty[UNIT(dev)]; 23147752Swilliam 23247752Swilliam return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 23347752Swilliam } 23447752Swilliam 23547752Swilliam comwrite(dev, uio, flag) 23647752Swilliam dev_t dev; 23747752Swilliam struct uio *uio; 23847752Swilliam { 23947752Swilliam int unit = UNIT(dev); 24047752Swilliam register struct tty *tp = &com_tty[unit]; 24147752Swilliam 24247752Swilliam /* 24347752Swilliam * (XXX) We disallow virtual consoles if the physical console is 24447752Swilliam * a serial port. This is in case there is a display attached that 24547752Swilliam * is not the console. In that situation we don't need/want the X 24647752Swilliam * server taking over the console. 24747752Swilliam */ 24847752Swilliam if (constty && unit == comconsole) 24947752Swilliam constty = NULL; 25047752Swilliam return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 25147752Swilliam } 25247752Swilliam 25347752Swilliam comintr(unit) 25447752Swilliam register int unit; 25547752Swilliam { 25647752Swilliam register com; 25747752Swilliam register u_char code; 25847752Swilliam register struct tty *tp; 25947752Swilliam 26047752Swilliam com = com_addr[unit]; 26147752Swilliam while (1) { 26247752Swilliam code = inb(com+com_iir); 263*49570Swilliam switch (code & IIR_IMASK) { 26447752Swilliam case IIR_NOPEND: 26547752Swilliam return (1); 266*49570Swilliam case IIR_RXTOUT: 26747752Swilliam case IIR_RXRDY: 26847752Swilliam tp = &com_tty[unit]; 269*49570Swilliam /* 270*49570Swilliam * Process received bytes. Inline for speed... 271*49570Swilliam */ 27247752Swilliam #ifdef KGDB 273*49570Swilliam #define RCVBYTE() \ 274*49570Swilliam code = inb(com+com_data); \ 275*49570Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { \ 276*49570Swilliam if (kgdb_dev == makedev(commajor, unit) && \ 277*49570Swilliam code == FRAME_END) \ 278*49570Swilliam kgdb_connect(0); /* trap into kgdb */ \ 279*49570Swilliam } else \ 280*49570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 281*49570Swilliam #else 282*49570Swilliam #define RCVBYTE() \ 283*49570Swilliam code = inb(com+com_data); \ 284*49570Swilliam if (tp->t_state & TS_ISOPEN) \ 285*49570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 286*49570Swilliam #endif 287*49570Swilliam 288*49570Swilliam RCVBYTE(); 289*49570Swilliam 290*49570Swilliam if (com_hasfifo & (1 << unit)) 291*49570Swilliam while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 292*49570Swilliam if (code == LSR_RXRDY) { 293*49570Swilliam RCVBYTE(); 294*49570Swilliam } else 295*49570Swilliam comeint(unit, code, com); 29647752Swilliam } 29747752Swilliam break; 29847752Swilliam case IIR_TXRDY: 29947752Swilliam tp = &com_tty[unit]; 30047752Swilliam tp->t_state &=~ (TS_BUSY|TS_FLUSH); 30147752Swilliam if (tp->t_line) 30247752Swilliam (*linesw[tp->t_line].l_start)(tp); 30347752Swilliam else 30447752Swilliam comstart(tp); 30547752Swilliam break; 30647752Swilliam case IIR_RLS: 307*49570Swilliam comeint(unit, inb(com+com_lsr), com); 30847752Swilliam break; 30947752Swilliam default: 31047752Swilliam if (code & IIR_NOPEND) 31147752Swilliam return (1); 31247752Swilliam log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 31347752Swilliam unit, code); 31447752Swilliam /* fall through */ 31547752Swilliam case IIR_MLSC: 31647752Swilliam commint(unit, com); 31747752Swilliam break; 31847752Swilliam } 31947752Swilliam } 32047752Swilliam } 32147752Swilliam 322*49570Swilliam comeint(unit, stat, com) 323*49570Swilliam register int unit, stat; 32447752Swilliam register com; 32547752Swilliam { 32647752Swilliam register struct tty *tp; 327*49570Swilliam register int c; 32847752Swilliam 32947752Swilliam tp = &com_tty[unit]; 33047752Swilliam c = inb(com+com_data); 33147752Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { 33247752Swilliam #ifdef KGDB 33347752Swilliam /* we don't care about parity errors */ 33447752Swilliam if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 335*49570Swilliam kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 336*49570Swilliam kgdb_connect(0); /* trap into kgdb */ 33747752Swilliam #endif 33847752Swilliam return; 33947752Swilliam } 34047752Swilliam if (stat & (LSR_BI | LSR_FE)) 34147752Swilliam c |= TTY_FE; 34247752Swilliam else if (stat & LSR_PE) 34347752Swilliam c |= TTY_PE; 34447752Swilliam else if (stat & LSR_OE) 34547752Swilliam log(LOG_WARNING, "com%d: silo overflow\n", unit); 34647752Swilliam (*linesw[tp->t_line].l_rint)(c, tp); 34747752Swilliam } 34847752Swilliam 34947752Swilliam commint(unit, com) 35047752Swilliam register int unit; 35147752Swilliam register com; 35247752Swilliam { 35347752Swilliam register struct tty *tp; 35447752Swilliam register int stat; 35547752Swilliam 35647752Swilliam tp = &com_tty[unit]; 35747752Swilliam stat = inb(com+com_msr); 35847752Swilliam if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 35947752Swilliam if (stat & MSR_DCD) 36047752Swilliam (void)(*linesw[tp->t_line].l_modem)(tp, 1); 36147752Swilliam else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36247752Swilliam outb(com+com_mcr, 36347752Swilliam inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 36447752Swilliam } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 36547752Swilliam (tp->t_flags & CRTSCTS)) { 36647752Swilliam /* the line is up and we want to do rts/cts flow control */ 36747752Swilliam if (stat & MSR_CTS) { 36847752Swilliam tp->t_state &=~ TS_TTSTOP; 36947752Swilliam ttstart(tp); 37047752Swilliam } else 37147752Swilliam tp->t_state |= TS_TTSTOP; 37247752Swilliam } 37347752Swilliam } 37447752Swilliam 37547752Swilliam comioctl(dev, cmd, data, flag) 37647752Swilliam dev_t dev; 37747752Swilliam caddr_t data; 37847752Swilliam { 37947752Swilliam register struct tty *tp; 38047752Swilliam register int unit = UNIT(dev); 38147752Swilliam register com; 38247752Swilliam register int error; 38347752Swilliam 38447752Swilliam tp = &com_tty[unit]; 38547752Swilliam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38647752Swilliam if (error >= 0) 38747752Swilliam return (error); 38847752Swilliam error = ttioctl(tp, cmd, data, flag); 38947752Swilliam if (error >= 0) 39047752Swilliam return (error); 39147752Swilliam 39247752Swilliam com = com_addr[unit]; 39347752Swilliam switch (cmd) { 39447752Swilliam 39547752Swilliam case TIOCSBRK: 39647752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 39747752Swilliam break; 39847752Swilliam 39947752Swilliam case TIOCCBRK: 40047752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 40147752Swilliam break; 40247752Swilliam 40347752Swilliam case TIOCSDTR: 40447752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 40547752Swilliam break; 40647752Swilliam 40747752Swilliam case TIOCCDTR: 40847752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 40947752Swilliam break; 41047752Swilliam 41147752Swilliam case TIOCMSET: 41247752Swilliam (void) commctl(dev, *(int *)data, DMSET); 41347752Swilliam break; 41447752Swilliam 41547752Swilliam case TIOCMBIS: 41647752Swilliam (void) commctl(dev, *(int *)data, DMBIS); 41747752Swilliam break; 41847752Swilliam 41947752Swilliam case TIOCMBIC: 42047752Swilliam (void) commctl(dev, *(int *)data, DMBIC); 42147752Swilliam break; 42247752Swilliam 42347752Swilliam case TIOCMGET: 42447752Swilliam *(int *)data = commctl(dev, 0, DMGET); 42547752Swilliam break; 42647752Swilliam 42747752Swilliam default: 42847752Swilliam return (ENOTTY); 42947752Swilliam } 43047752Swilliam return (0); 43147752Swilliam } 43247752Swilliam 43347752Swilliam comparam(tp, t) 43447752Swilliam register struct tty *tp; 43547752Swilliam register struct termios *t; 43647752Swilliam { 43747752Swilliam register com; 43847752Swilliam register int cfcr, cflag = t->c_cflag; 43947752Swilliam int unit = UNIT(tp->t_dev); 44047752Swilliam int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 44147752Swilliam 44247752Swilliam /* check requested parameters */ 44347752Swilliam if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 44447752Swilliam return(EINVAL); 44547752Swilliam /* and copy to tty */ 44647752Swilliam tp->t_ispeed = t->c_ispeed; 44747752Swilliam tp->t_ospeed = t->c_ospeed; 44847752Swilliam tp->t_cflag = cflag; 44947752Swilliam 45047752Swilliam com = com_addr[unit]; 45147752Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 45247752Swilliam if (ospeed == 0) { 45347752Swilliam (void) commctl(unit, 0, DMSET); /* hang up line */ 45447752Swilliam return(0); 45547752Swilliam } 45647752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 45747752Swilliam outb(com+com_data, ospeed & 0xFF); 45847752Swilliam outb(com+com_ier, ospeed >> 8); 45947752Swilliam switch (cflag&CSIZE) { 46047752Swilliam case CS5: 46147752Swilliam cfcr = CFCR_5BITS; break; 46247752Swilliam case CS6: 46347752Swilliam cfcr = CFCR_6BITS; break; 46447752Swilliam case CS7: 46547752Swilliam cfcr = CFCR_7BITS; break; 46647752Swilliam case CS8: 46747752Swilliam cfcr = CFCR_8BITS; break; 46847752Swilliam } 46947752Swilliam if (cflag&PARENB) { 47047752Swilliam cfcr |= CFCR_PENAB; 47147752Swilliam if ((cflag&PARODD) == 0) 47247752Swilliam cfcr |= CFCR_PEVEN; 47347752Swilliam } 47447752Swilliam if (cflag&CSTOPB) 47547752Swilliam cfcr |= CFCR_STOPB; 47647752Swilliam outb(com+com_cfcr, cfcr); 477*49570Swilliam 478*49570Swilliam if (com_hasfifo & (1 << unit)) 479*49570Swilliam outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); 480*49570Swilliam 48147752Swilliam return(0); 48247752Swilliam } 48347752Swilliam 48447752Swilliam comstart(tp) 48547752Swilliam register struct tty *tp; 48647752Swilliam { 48747752Swilliam register com; 48847752Swilliam int s, unit, c; 48947752Swilliam 49047752Swilliam unit = UNIT(tp->t_dev); 49147752Swilliam com = com_addr[unit]; 49247752Swilliam s = spltty(); 49347752Swilliam if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 49447752Swilliam goto out; 49547752Swilliam if (tp->t_outq.c_cc <= tp->t_lowat) { 49647752Swilliam if (tp->t_state&TS_ASLEEP) { 49747752Swilliam tp->t_state &= ~TS_ASLEEP; 49847752Swilliam wakeup((caddr_t)&tp->t_outq); 49947752Swilliam } 50047752Swilliam if (tp->t_wsel) { 50147752Swilliam selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 50247752Swilliam tp->t_wsel = 0; 50347752Swilliam tp->t_state &= ~TS_WCOLL; 50447752Swilliam } 50547752Swilliam } 50647752Swilliam if (tp->t_outq.c_cc == 0) 50747752Swilliam goto out; 50847752Swilliam if (inb(com+com_lsr) & LSR_TXRDY) { 50947752Swilliam c = getc(&tp->t_outq); 51047752Swilliam tp->t_state |= TS_BUSY; 51147752Swilliam outb(com+com_data, c); 512*49570Swilliam if (com_hasfifo & (1 << unit)) 513*49570Swilliam for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 514*49570Swilliam outb(com+com_data, getc(&tp->t_outq)); 51547752Swilliam } 51647752Swilliam out: 51747752Swilliam splx(s); 51847752Swilliam } 51947752Swilliam 52047752Swilliam /* 52147752Swilliam * Stop output on a line. 52247752Swilliam */ 52347752Swilliam /*ARGSUSED*/ 52447752Swilliam comstop(tp, flag) 52547752Swilliam register struct tty *tp; 52647752Swilliam { 52747752Swilliam register int s; 52847752Swilliam 52947752Swilliam s = spltty(); 53047752Swilliam if (tp->t_state & TS_BUSY) { 53147752Swilliam if ((tp->t_state&TS_TTSTOP)==0) 53247752Swilliam tp->t_state |= TS_FLUSH; 53347752Swilliam } 53447752Swilliam splx(s); 53547752Swilliam } 53647752Swilliam 53747752Swilliam commctl(dev, bits, how) 53847752Swilliam dev_t dev; 53947752Swilliam int bits, how; 54047752Swilliam { 54147752Swilliam register com; 54247752Swilliam register int unit; 54347752Swilliam int s; 54447752Swilliam 54547752Swilliam unit = UNIT(dev); 54647752Swilliam com = com_addr[unit]; 54747752Swilliam s = spltty(); 54847752Swilliam switch (how) { 54947752Swilliam 55047752Swilliam case DMSET: 55147752Swilliam outb(com+com_mcr, bits | MCR_IENABLE); 55247752Swilliam break; 55347752Swilliam 55447752Swilliam case DMBIS: 55547752Swilliam outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE); 55647752Swilliam break; 55747752Swilliam 55847752Swilliam case DMBIC: 55947752Swilliam outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE); 56047752Swilliam break; 56147752Swilliam 56247752Swilliam case DMGET: 56347752Swilliam bits = inb(com+com_msr); 56447752Swilliam break; 56547752Swilliam } 56647752Swilliam (void) splx(s); 56747752Swilliam return(bits); 56847752Swilliam } 569*49570Swilliam 570*49570Swilliam /* 571*49570Swilliam * Following are all routines needed for COM to act as console 572*49570Swilliam */ 573*49570Swilliam #include "i386/i386/cons.h" 574*49570Swilliam 575*49570Swilliam comcnprobe(cp) 576*49570Swilliam struct consdev *cp; 577*49570Swilliam { 578*49570Swilliam int unit; 579*49570Swilliam extern int comopen(); 580*49570Swilliam 581*49570Swilliam /* locate the major number */ 582*49570Swilliam for (commajor = 0; commajor < nchrdev; commajor++) 583*49570Swilliam if (cdevsw[commajor].d_open == comopen) 584*49570Swilliam break; 585*49570Swilliam 586*49570Swilliam /* XXX: ick */ 587*49570Swilliam unit = CONUNIT; 588*49570Swilliam com_addr[CONUNIT] = CONADDR; 589*49570Swilliam 590*49570Swilliam /* make sure hardware exists? XXX */ 591*49570Swilliam 592*49570Swilliam /* initialize required fields */ 593*49570Swilliam cp->cn_dev = makedev(commajor, unit); 594*49570Swilliam cp->cn_tp = &com_tty[unit]; 595*49570Swilliam #ifdef COMCONSOLE 596*49570Swilliam cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 597*49570Swilliam #else 598*49570Swilliam cp->cn_pri = CN_NORMAL; 59947752Swilliam #endif 600*49570Swilliam } 601*49570Swilliam 602*49570Swilliam comcninit(cp) 603*49570Swilliam struct consdev *cp; 604*49570Swilliam { 605*49570Swilliam int unit = UNIT(cp->cn_dev); 606*49570Swilliam 607*49570Swilliam cominit(unit, comdefaultrate); 608*49570Swilliam comconsole = unit; 609*49570Swilliam comconsinit = 1; 610*49570Swilliam } 611*49570Swilliam 612*49570Swilliam cominit(unit, rate) 613*49570Swilliam int unit, rate; 614*49570Swilliam { 615*49570Swilliam register int com; 616*49570Swilliam int s; 617*49570Swilliam short stat; 618*49570Swilliam 619*49570Swilliam #ifdef lint 620*49570Swilliam stat = unit; if (stat) return; 621*49570Swilliam #endif 622*49570Swilliam com = com_addr[unit]; 623*49570Swilliam s = splhigh(); 624*49570Swilliam outb(com+com_cfcr, CFCR_DLAB); 625*49570Swilliam rate = ttspeedtab(comdefaultrate, comspeedtab); 626*49570Swilliam outb(com+com_data, rate & 0xFF); 627*49570Swilliam outb(com+com_ier, rate >> 8); 628*49570Swilliam outb(com+com_cfcr, CFCR_8BITS); 629*49570Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); 630*49570Swilliam outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 631*49570Swilliam stat = inb(com+com_iir); 632*49570Swilliam splx(s); 633*49570Swilliam } 634*49570Swilliam 635*49570Swilliam comcngetc(dev) 636*49570Swilliam { 637*49570Swilliam register com = com_addr[UNIT(dev)]; 638*49570Swilliam short stat; 639*49570Swilliam int c, s; 640*49570Swilliam 641*49570Swilliam #ifdef lint 642*49570Swilliam stat = dev; if (stat) return(0); 643*49570Swilliam #endif 644*49570Swilliam s = splhigh(); 645*49570Swilliam while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0) 646*49570Swilliam ; 647*49570Swilliam c = inb(com+com_data); 648*49570Swilliam stat = inb(com+com_iir); 649*49570Swilliam splx(s); 650*49570Swilliam return(c); 651*49570Swilliam } 652*49570Swilliam 653*49570Swilliam /* 654*49570Swilliam * Console kernel output character routine. 655*49570Swilliam */ 656*49570Swilliam comcnputc(dev, c) 657*49570Swilliam dev_t dev; 658*49570Swilliam register int c; 659*49570Swilliam { 660*49570Swilliam register com = com_addr[UNIT(dev)]; 661*49570Swilliam register int timo; 662*49570Swilliam short stat; 663*49570Swilliam int s = splhigh(); 664*49570Swilliam 665*49570Swilliam #ifdef lint 666*49570Swilliam stat = dev; if (stat) return; 667*49570Swilliam #endif 668*49570Swilliam #ifdef KGDB 669*49570Swilliam if (dev != kgdb_dev) 670*49570Swilliam #endif 671*49570Swilliam if (comconsinit == 0) { 672*49570Swilliam (void) cominit(UNIT(dev), comdefaultrate); 673*49570Swilliam comconsinit = 1; 674*49570Swilliam } 675*49570Swilliam /* wait for any pending transmission to finish */ 676*49570Swilliam timo = 50000; 677*49570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 678*49570Swilliam ; 679*49570Swilliam outb(com+com_data, c); 680*49570Swilliam /* wait for this transmission to complete */ 681*49570Swilliam timo = 1500000; 682*49570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 683*49570Swilliam ; 684*49570Swilliam /* clear any interrupts generated by this transmission */ 685*49570Swilliam stat = inb(com+com_iir); 686*49570Swilliam splx(s); 687*49570Swilliam } 688*49570Swilliam #endif 689