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