147752Swilliam /*- 249570Swilliam * Copyright (c) 1991 The Regents of the University of California. 349570Swilliam * All rights reserved. 447752Swilliam * 547752Swilliam * %sccs.include.redist.c% 647752Swilliam * 7*52660Storek * @(#)com.c 7.6 (Berkeley) 02/25/92 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 { 8849697Swilliam /* force access to id reg */ 8949697Swilliam outb(dev->id_iobase+com_cfcr, 0); 9049697Swilliam outb(dev->id_iobase+com_iir, 0); 9149697Swilliam 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 12249697Swilliam 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*/ 20349751Smarc comclose(dev, flag, mode, p) 20447752Swilliam dev_t dev; 20549751Smarc int flag, mode; 20649751Smarc struct proc *p; 20747752Swilliam { 20847752Swilliam register struct tty *tp; 20947752Swilliam register com; 21047752Swilliam register int unit; 21147752Swilliam 21247752Swilliam unit = UNIT(dev); 21347752Swilliam com = com_addr[unit]; 21447752Swilliam tp = &com_tty[unit]; 21549751Smarc (*linesw[tp->t_line].l_close)(tp, flag); 21647752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 21747752Swilliam #ifdef KGDB 21847752Swilliam /* do not disable interrupts if debugging */ 21949570Swilliam if (kgdb_dev != makedev(commajor, unit)) 22047752Swilliam #endif 22147752Swilliam outb(com+com_ier, 0); 22247752Swilliam if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 22347752Swilliam (tp->t_state&TS_ISOPEN) == 0) 22447752Swilliam (void) commctl(dev, 0, DMSET); 22547752Swilliam ttyclose(tp); 22647752Swilliam return(0); 22747752Swilliam } 22847752Swilliam 22947752Swilliam comread(dev, uio, flag) 23047752Swilliam dev_t dev; 23147752Swilliam struct uio *uio; 23247752Swilliam { 23347752Swilliam register struct tty *tp = &com_tty[UNIT(dev)]; 23447752Swilliam 23547752Swilliam return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 23647752Swilliam } 23747752Swilliam 23847752Swilliam comwrite(dev, uio, flag) 23947752Swilliam dev_t dev; 24047752Swilliam struct uio *uio; 24147752Swilliam { 24247752Swilliam int unit = UNIT(dev); 24347752Swilliam register struct tty *tp = &com_tty[unit]; 24447752Swilliam 24547752Swilliam /* 24647752Swilliam * (XXX) We disallow virtual consoles if the physical console is 24747752Swilliam * a serial port. This is in case there is a display attached that 24847752Swilliam * is not the console. In that situation we don't need/want the X 24947752Swilliam * server taking over the console. 25047752Swilliam */ 25147752Swilliam if (constty && unit == comconsole) 25247752Swilliam constty = NULL; 25347752Swilliam return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 25447752Swilliam } 25547752Swilliam 25647752Swilliam comintr(unit) 25747752Swilliam register int unit; 25847752Swilliam { 25947752Swilliam register com; 26047752Swilliam register u_char code; 26147752Swilliam register struct tty *tp; 26247752Swilliam 26347752Swilliam com = com_addr[unit]; 26447752Swilliam while (1) { 26547752Swilliam code = inb(com+com_iir); 26649570Swilliam switch (code & IIR_IMASK) { 26747752Swilliam case IIR_NOPEND: 26847752Swilliam return (1); 26949570Swilliam case IIR_RXTOUT: 27047752Swilliam case IIR_RXRDY: 27147752Swilliam tp = &com_tty[unit]; 27249570Swilliam /* 27349570Swilliam * Process received bytes. Inline for speed... 27449570Swilliam */ 27547752Swilliam #ifdef KGDB 27649570Swilliam #define RCVBYTE() \ 27749570Swilliam code = inb(com+com_data); \ 27849570Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { \ 27949570Swilliam if (kgdb_dev == makedev(commajor, unit) && \ 28049570Swilliam code == FRAME_END) \ 28149570Swilliam kgdb_connect(0); /* trap into kgdb */ \ 28249570Swilliam } else \ 28349570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 28449570Swilliam #else 28549570Swilliam #define RCVBYTE() \ 28649570Swilliam code = inb(com+com_data); \ 28749570Swilliam if (tp->t_state & TS_ISOPEN) \ 28849570Swilliam (*linesw[tp->t_line].l_rint)(code, tp) 28949570Swilliam #endif 29049570Swilliam 29149570Swilliam RCVBYTE(); 29249570Swilliam 29349570Swilliam if (com_hasfifo & (1 << unit)) 29449570Swilliam while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 29549570Swilliam if (code == LSR_RXRDY) { 29649570Swilliam RCVBYTE(); 29749570Swilliam } else 29849570Swilliam comeint(unit, code, com); 29947752Swilliam } 30047752Swilliam break; 30147752Swilliam case IIR_TXRDY: 30247752Swilliam tp = &com_tty[unit]; 30347752Swilliam tp->t_state &=~ (TS_BUSY|TS_FLUSH); 30447752Swilliam if (tp->t_line) 30547752Swilliam (*linesw[tp->t_line].l_start)(tp); 30647752Swilliam else 30747752Swilliam comstart(tp); 30847752Swilliam break; 30947752Swilliam case IIR_RLS: 31049570Swilliam comeint(unit, inb(com+com_lsr), com); 31147752Swilliam break; 31247752Swilliam default: 31347752Swilliam if (code & IIR_NOPEND) 31447752Swilliam return (1); 31547752Swilliam log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 31647752Swilliam unit, code); 31747752Swilliam /* fall through */ 31847752Swilliam case IIR_MLSC: 31947752Swilliam commint(unit, com); 32047752Swilliam break; 32147752Swilliam } 32247752Swilliam } 32347752Swilliam } 32447752Swilliam 32549570Swilliam comeint(unit, stat, com) 32649570Swilliam register int unit, stat; 32747752Swilliam register com; 32847752Swilliam { 32947752Swilliam register struct tty *tp; 33049570Swilliam register int c; 33147752Swilliam 33247752Swilliam tp = &com_tty[unit]; 33347752Swilliam c = inb(com+com_data); 33447752Swilliam if ((tp->t_state & TS_ISOPEN) == 0) { 33547752Swilliam #ifdef KGDB 33647752Swilliam /* we don't care about parity errors */ 33747752Swilliam if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 33849570Swilliam kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 33949570Swilliam kgdb_connect(0); /* trap into kgdb */ 34047752Swilliam #endif 34147752Swilliam return; 34247752Swilliam } 34347752Swilliam if (stat & (LSR_BI | LSR_FE)) 34447752Swilliam c |= TTY_FE; 34547752Swilliam else if (stat & LSR_PE) 34647752Swilliam c |= TTY_PE; 34747752Swilliam else if (stat & LSR_OE) 34847752Swilliam log(LOG_WARNING, "com%d: silo overflow\n", unit); 34947752Swilliam (*linesw[tp->t_line].l_rint)(c, tp); 35047752Swilliam } 35147752Swilliam 35247752Swilliam commint(unit, com) 35347752Swilliam register int unit; 35447752Swilliam register com; 35547752Swilliam { 35647752Swilliam register struct tty *tp; 35747752Swilliam register int stat; 35847752Swilliam 35947752Swilliam tp = &com_tty[unit]; 36047752Swilliam stat = inb(com+com_msr); 36147752Swilliam if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 36247752Swilliam if (stat & MSR_DCD) 36347752Swilliam (void)(*linesw[tp->t_line].l_modem)(tp, 1); 36447752Swilliam else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 36547752Swilliam outb(com+com_mcr, 36647752Swilliam inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 36747752Swilliam } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 36847752Swilliam (tp->t_flags & CRTSCTS)) { 36947752Swilliam /* the line is up and we want to do rts/cts flow control */ 37047752Swilliam if (stat & MSR_CTS) { 37147752Swilliam tp->t_state &=~ TS_TTSTOP; 37247752Swilliam ttstart(tp); 37347752Swilliam } else 37447752Swilliam tp->t_state |= TS_TTSTOP; 37547752Swilliam } 37647752Swilliam } 37747752Swilliam 37847752Swilliam comioctl(dev, cmd, data, flag) 37947752Swilliam dev_t dev; 38047752Swilliam caddr_t data; 38147752Swilliam { 38247752Swilliam register struct tty *tp; 38347752Swilliam register int unit = UNIT(dev); 38447752Swilliam register com; 38547752Swilliam register int error; 38647752Swilliam 38747752Swilliam tp = &com_tty[unit]; 38847752Swilliam error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 38947752Swilliam if (error >= 0) 39047752Swilliam return (error); 39147752Swilliam error = ttioctl(tp, cmd, data, flag); 39247752Swilliam if (error >= 0) 39347752Swilliam return (error); 39447752Swilliam 39547752Swilliam com = com_addr[unit]; 39647752Swilliam switch (cmd) { 39747752Swilliam 39847752Swilliam case TIOCSBRK: 39947752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 40047752Swilliam break; 40147752Swilliam 40247752Swilliam case TIOCCBRK: 40347752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 40447752Swilliam break; 40547752Swilliam 40647752Swilliam case TIOCSDTR: 40747752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 40847752Swilliam break; 40947752Swilliam 41047752Swilliam case TIOCCDTR: 41147752Swilliam (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 41247752Swilliam break; 41347752Swilliam 41447752Swilliam case TIOCMSET: 41547752Swilliam (void) commctl(dev, *(int *)data, DMSET); 41647752Swilliam break; 41747752Swilliam 41847752Swilliam case TIOCMBIS: 41947752Swilliam (void) commctl(dev, *(int *)data, DMBIS); 42047752Swilliam break; 42147752Swilliam 42247752Swilliam case TIOCMBIC: 42347752Swilliam (void) commctl(dev, *(int *)data, DMBIC); 42447752Swilliam break; 42547752Swilliam 42647752Swilliam case TIOCMGET: 42747752Swilliam *(int *)data = commctl(dev, 0, DMGET); 42847752Swilliam break; 42947752Swilliam 43047752Swilliam default: 43147752Swilliam return (ENOTTY); 43247752Swilliam } 43347752Swilliam return (0); 43447752Swilliam } 43547752Swilliam 43647752Swilliam comparam(tp, t) 43747752Swilliam register struct tty *tp; 43847752Swilliam register struct termios *t; 43947752Swilliam { 44047752Swilliam register com; 44147752Swilliam register int cfcr, cflag = t->c_cflag; 44247752Swilliam int unit = UNIT(tp->t_dev); 44347752Swilliam int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 44447752Swilliam 44547752Swilliam /* check requested parameters */ 44647752Swilliam if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 44747752Swilliam return(EINVAL); 44847752Swilliam /* and copy to tty */ 44947752Swilliam tp->t_ispeed = t->c_ispeed; 45047752Swilliam tp->t_ospeed = t->c_ospeed; 45147752Swilliam tp->t_cflag = cflag; 45247752Swilliam 45347752Swilliam com = com_addr[unit]; 45447752Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 45547752Swilliam if (ospeed == 0) { 45647752Swilliam (void) commctl(unit, 0, DMSET); /* hang up line */ 45747752Swilliam return(0); 45847752Swilliam } 45947752Swilliam outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 46047752Swilliam outb(com+com_data, ospeed & 0xFF); 46147752Swilliam outb(com+com_ier, ospeed >> 8); 46247752Swilliam switch (cflag&CSIZE) { 46347752Swilliam case CS5: 46447752Swilliam cfcr = CFCR_5BITS; break; 46547752Swilliam case CS6: 46647752Swilliam cfcr = CFCR_6BITS; break; 46747752Swilliam case CS7: 46847752Swilliam cfcr = CFCR_7BITS; break; 46947752Swilliam case CS8: 47047752Swilliam cfcr = CFCR_8BITS; break; 47147752Swilliam } 47247752Swilliam if (cflag&PARENB) { 47347752Swilliam cfcr |= CFCR_PENAB; 47447752Swilliam if ((cflag&PARODD) == 0) 47547752Swilliam cfcr |= CFCR_PEVEN; 47647752Swilliam } 47747752Swilliam if (cflag&CSTOPB) 47847752Swilliam cfcr |= CFCR_STOPB; 47947752Swilliam outb(com+com_cfcr, cfcr); 48049570Swilliam 48149570Swilliam if (com_hasfifo & (1 << unit)) 48249570Swilliam outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); 48349570Swilliam 48447752Swilliam return(0); 48547752Swilliam } 48647752Swilliam 48747752Swilliam comstart(tp) 48847752Swilliam register struct tty *tp; 48947752Swilliam { 49047752Swilliam register com; 49147752Swilliam int s, unit, c; 49247752Swilliam 49347752Swilliam unit = UNIT(tp->t_dev); 49447752Swilliam com = com_addr[unit]; 49547752Swilliam s = spltty(); 49647752Swilliam if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 49747752Swilliam goto out; 49847752Swilliam if (tp->t_outq.c_cc <= tp->t_lowat) { 49947752Swilliam if (tp->t_state&TS_ASLEEP) { 50047752Swilliam tp->t_state &= ~TS_ASLEEP; 50147752Swilliam wakeup((caddr_t)&tp->t_outq); 50247752Swilliam } 503*52660Storek selwakeup(&tp->t_wsel); 50447752Swilliam } 50547752Swilliam if (tp->t_outq.c_cc == 0) 50647752Swilliam goto out; 50747752Swilliam if (inb(com+com_lsr) & LSR_TXRDY) { 50847752Swilliam c = getc(&tp->t_outq); 50947752Swilliam tp->t_state |= TS_BUSY; 51047752Swilliam outb(com+com_data, c); 51149570Swilliam if (com_hasfifo & (1 << unit)) 51249570Swilliam for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 51349570Swilliam outb(com+com_data, getc(&tp->t_outq)); 51447752Swilliam } 51547752Swilliam out: 51647752Swilliam splx(s); 51747752Swilliam } 51847752Swilliam 51947752Swilliam /* 52047752Swilliam * Stop output on a line. 52147752Swilliam */ 52247752Swilliam /*ARGSUSED*/ 52347752Swilliam comstop(tp, flag) 52447752Swilliam register struct tty *tp; 52547752Swilliam { 52647752Swilliam register int s; 52747752Swilliam 52847752Swilliam s = spltty(); 52947752Swilliam if (tp->t_state & TS_BUSY) { 53047752Swilliam if ((tp->t_state&TS_TTSTOP)==0) 53147752Swilliam tp->t_state |= TS_FLUSH; 53247752Swilliam } 53347752Swilliam splx(s); 53447752Swilliam } 53547752Swilliam 53647752Swilliam commctl(dev, bits, how) 53747752Swilliam dev_t dev; 53847752Swilliam int bits, how; 53947752Swilliam { 54047752Swilliam register com; 54147752Swilliam register int unit; 54247752Swilliam int s; 54347752Swilliam 54447752Swilliam unit = UNIT(dev); 54547752Swilliam com = com_addr[unit]; 54647752Swilliam s = spltty(); 54747752Swilliam switch (how) { 54847752Swilliam 54947752Swilliam case DMSET: 55047752Swilliam outb(com+com_mcr, bits | MCR_IENABLE); 55147752Swilliam break; 55247752Swilliam 55347752Swilliam case DMBIS: 55447752Swilliam outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE); 55547752Swilliam break; 55647752Swilliam 55747752Swilliam case DMBIC: 55847752Swilliam outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE); 55947752Swilliam break; 56047752Swilliam 56147752Swilliam case DMGET: 56247752Swilliam bits = inb(com+com_msr); 56347752Swilliam break; 56447752Swilliam } 56547752Swilliam (void) splx(s); 56647752Swilliam return(bits); 56747752Swilliam } 56849570Swilliam 56949570Swilliam /* 57049570Swilliam * Following are all routines needed for COM to act as console 57149570Swilliam */ 57249570Swilliam #include "i386/i386/cons.h" 57349570Swilliam 57449570Swilliam comcnprobe(cp) 57549570Swilliam struct consdev *cp; 57649570Swilliam { 57749570Swilliam int unit; 57849570Swilliam 57949570Swilliam /* locate the major number */ 58049570Swilliam for (commajor = 0; commajor < nchrdev; commajor++) 58149570Swilliam if (cdevsw[commajor].d_open == comopen) 58249570Swilliam break; 58349570Swilliam 58449570Swilliam /* XXX: ick */ 58549570Swilliam unit = CONUNIT; 58649570Swilliam com_addr[CONUNIT] = CONADDR; 58749570Swilliam 58849570Swilliam /* make sure hardware exists? XXX */ 58949570Swilliam 59049570Swilliam /* initialize required fields */ 59149570Swilliam cp->cn_dev = makedev(commajor, unit); 59249570Swilliam cp->cn_tp = &com_tty[unit]; 59349570Swilliam #ifdef COMCONSOLE 59449570Swilliam cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 59549570Swilliam #else 59649570Swilliam cp->cn_pri = CN_NORMAL; 59747752Swilliam #endif 59849570Swilliam } 59949570Swilliam 60049570Swilliam comcninit(cp) 60149570Swilliam struct consdev *cp; 60249570Swilliam { 60349570Swilliam int unit = UNIT(cp->cn_dev); 60449570Swilliam 60549570Swilliam cominit(unit, comdefaultrate); 60649570Swilliam comconsole = unit; 60749570Swilliam comconsinit = 1; 60849570Swilliam } 60949570Swilliam 61049570Swilliam cominit(unit, rate) 61149570Swilliam int unit, rate; 61249570Swilliam { 61349570Swilliam register int com; 61449570Swilliam int s; 61549570Swilliam short stat; 61649570Swilliam 61749570Swilliam #ifdef lint 61849570Swilliam stat = unit; if (stat) return; 61949570Swilliam #endif 62049570Swilliam com = com_addr[unit]; 62149570Swilliam s = splhigh(); 62249570Swilliam outb(com+com_cfcr, CFCR_DLAB); 62349570Swilliam rate = ttspeedtab(comdefaultrate, comspeedtab); 62449570Swilliam outb(com+com_data, rate & 0xFF); 62549570Swilliam outb(com+com_ier, rate >> 8); 62649570Swilliam outb(com+com_cfcr, CFCR_8BITS); 62749570Swilliam outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); 62849570Swilliam outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 62949570Swilliam stat = inb(com+com_iir); 63049570Swilliam splx(s); 63149570Swilliam } 63249570Swilliam 63349570Swilliam comcngetc(dev) 63449570Swilliam { 63549570Swilliam register com = com_addr[UNIT(dev)]; 63649570Swilliam short stat; 63749570Swilliam int c, s; 63849570Swilliam 63949570Swilliam #ifdef lint 64049570Swilliam stat = dev; if (stat) return(0); 64149570Swilliam #endif 64249570Swilliam s = splhigh(); 64349570Swilliam while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0) 64449570Swilliam ; 64549570Swilliam c = inb(com+com_data); 64649570Swilliam stat = inb(com+com_iir); 64749570Swilliam splx(s); 64849570Swilliam return(c); 64949570Swilliam } 65049570Swilliam 65149570Swilliam /* 65249570Swilliam * Console kernel output character routine. 65349570Swilliam */ 65449570Swilliam comcnputc(dev, c) 65549570Swilliam dev_t dev; 65649570Swilliam register int c; 65749570Swilliam { 65849570Swilliam register com = com_addr[UNIT(dev)]; 65949570Swilliam register int timo; 66049570Swilliam short stat; 66149570Swilliam int s = splhigh(); 66249570Swilliam 66349570Swilliam #ifdef lint 66449570Swilliam stat = dev; if (stat) return; 66549570Swilliam #endif 66649570Swilliam #ifdef KGDB 66749570Swilliam if (dev != kgdb_dev) 66849570Swilliam #endif 66949570Swilliam if (comconsinit == 0) { 67049570Swilliam (void) cominit(UNIT(dev), comdefaultrate); 67149570Swilliam comconsinit = 1; 67249570Swilliam } 67349570Swilliam /* wait for any pending transmission to finish */ 67449570Swilliam timo = 50000; 67549570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 67649570Swilliam ; 67749570Swilliam outb(com+com_data, c); 67849570Swilliam /* wait for this transmission to complete */ 67949570Swilliam timo = 1500000; 68049570Swilliam while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 68149570Swilliam ; 68249570Swilliam /* clear any interrupts generated by this transmission */ 68349570Swilliam stat = inb(com+com_iir); 68449570Swilliam splx(s); 68549570Swilliam } 68649570Swilliam #endif 687