xref: /openbsd/sys/dev/ic/com.c (revision df930be7)
1 /*	$NetBSD: com.c,v 1.61 1995/07/04 06:47:18 mycroft Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
5  * Copyright (c) 1991 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)com.c	7.5 (Berkeley) 5/16/91
37  */
38 
39 /*
40  * COM driver, based on HP dca driver
41  * uses National Semiconductor NS16450/NS16550AF UART
42  */
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/ioctl.h>
46 #include <sys/select.h>
47 #include <sys/tty.h>
48 #include <sys/proc.h>
49 #include <sys/user.h>
50 #include <sys/conf.h>
51 #include <sys/file.h>
52 #include <sys/uio.h>
53 #include <sys/kernel.h>
54 #include <sys/syslog.h>
55 #include <sys/types.h>
56 #include <sys/device.h>
57 
58 #include <machine/cpu.h>
59 #include <machine/pio.h>
60 
61 #include <dev/isa/isavar.h>
62 #include <dev/isa/comreg.h>
63 #include <dev/ic/ns16550reg.h>
64 
65 #define	COM_IBUFSIZE	(2 * 256)
66 #define	COM_IHIGHWATER	((3 * COM_IBUFSIZE) / 4)
67 
68 struct com_softc {
69 	struct device sc_dev;
70 	void *sc_ih;
71 	struct tty *sc_tty;
72 
73 	int sc_overflows;
74 	int sc_floods;
75 	int sc_errors;
76 
77 	int sc_iobase;
78 	u_char sc_hwflags;
79 #define	COM_HW_NOIEN	0x01
80 #define	COM_HW_FIFO	0x02
81 #define	COM_HW_CONSOLE	0x40
82 	u_char sc_swflags;
83 #define	COM_SW_SOFTCAR	0x01
84 #define	COM_SW_CLOCAL	0x02
85 #define	COM_SW_CRTSCTS	0x04
86 #define	COM_SW_MDMBUF	0x08
87 	u_char sc_msr, sc_mcr;
88 	u_char sc_dtr;
89 
90 	u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
91 	u_char sc_ibufs[2][COM_IBUFSIZE];
92 };
93 
94 int comprobe __P((struct device *, void *, void *));
95 void comattach __P((struct device *, struct device *, void *));
96 int comopen __P((dev_t, int, int, struct proc *));
97 int comclose __P((dev_t, int, int, struct proc *));
98 void comdiag __P((void *));
99 int comintr __P((void *));
100 void compoll __P((void *));
101 int comparam __P((struct tty *, struct termios *));
102 void comstart __P((struct tty *));
103 
104 struct cfdriver comcd = {
105 	NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc)
106 };
107 
108 int	comdefaultrate = TTYDEF_SPEED;
109 #ifdef COMCONSOLE
110 int	comconsole = COMCONSOLE;
111 #else
112 int	comconsole = -1;
113 #endif
114 int	comconsinit;
115 int	commajor;
116 int	comsopen = 0;
117 int	comevents = 0;
118 
119 #ifdef KGDB
120 #include <machine/remote-sl.h>
121 extern int kgdb_dev;
122 extern int kgdb_rate;
123 extern int kgdb_debug_init;
124 #endif
125 
126 #define	COMUNIT(x)	(minor(x))
127 
128 #define	bis(c, b)	do { const register int com_ad = (c); \
129 			     outb(com_ad, inb(com_ad) | (b)); } while(0)
130 #define	bic(c, b)	do { const register int com_ad = (c); \
131 			     outb(com_ad, inb(com_ad) & ~(b)); } while(0)
132 
133 int
134 comspeed(speed)
135 	long speed;
136 {
137 #define	divrnd(n, q)	(((n)*2/(q)+1)/2)	/* divide and round off */
138 
139 	int x, err;
140 
141 	if (speed == 0)
142 		return 0;
143 	if (speed < 0)
144 		return -1;
145 	x = divrnd((COM_FREQ / 16), speed);
146 	if (x <= 0)
147 		return -1;
148 	err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
149 	if (err < 0)
150 		err = -err;
151 	if (err > COM_TOLERANCE)
152 		return -1;
153 	return x;
154 
155 #undef	divrnd(n, q)
156 }
157 
158 int
159 comprobe1(iobase)
160 	int iobase;
161 {
162 
163 	/* force access to id reg */
164 	outb(iobase + com_cfcr, 0);
165 	outb(iobase + com_iir, 0);
166 	if (inb(iobase + com_iir) & 0x38)
167 		return 0;
168 
169 	return 1;
170 }
171 
172 int
173 comprobe(parent, match, aux)
174 	struct device *parent;
175 	void *match, *aux;
176 {
177 	struct isa_attach_args *ia = aux;
178 	int iobase = ia->ia_iobase;
179 
180 	if (!comprobe1(iobase))
181 		return 0;
182 
183 	ia->ia_iosize = COM_NPORTS;
184 	ia->ia_msize = 0;
185 	return 1;
186 }
187 
188 void
189 comattach(parent, self, aux)
190 	struct device *parent, *self;
191 	void *aux;
192 {
193 	struct com_softc *sc = (void *)self;
194 	struct isa_attach_args *ia = aux;
195 	struct cfdata *cf = sc->sc_dev.dv_cfdata;
196 	int iobase = ia->ia_iobase;
197 	struct tty *tp;
198 
199 	sc->sc_iobase = iobase;
200 	sc->sc_hwflags = cf->cf_flags & COM_HW_NOIEN;
201 	sc->sc_swflags = 0;
202 
203 	if (sc->sc_dev.dv_unit == comconsole)
204 		delay(1000);
205 
206 	/* look for a NS 16550AF UART with FIFOs */
207 	outb(iobase + com_fifo,
208 	    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
209 	delay(100);
210 	if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
211 		if ((inb(iobase + com_fifo) & FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
212 			sc->sc_hwflags |= COM_HW_FIFO;
213 			printf(": ns16550a, working fifo\n");
214 		} else
215 			printf(": ns16550, broken fifo\n");
216 	else
217 		printf(": ns8250 or ns16450, no fifo\n");
218 	outb(iobase + com_fifo, 0);
219 
220 	/* disable interrupts */
221 	outb(iobase + com_ier, 0);
222 	outb(iobase + com_mcr, 0);
223 
224 	if (ia->ia_irq != IRQUNK)
225 		sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE,
226 		    ISA_IPL_TTY, comintr, sc);
227 
228 #ifdef KGDB
229 	if (kgdb_dev == makedev(commajor, unit)) {
230 		if (comconsole == unit)
231 			kgdb_dev = -1;	/* can't debug over console port */
232 		else {
233 			(void) cominit(unit, kgdb_rate);
234 			if (kgdb_debug_init) {
235 				/*
236 				 * Print prefix of device name,
237 				 * let kgdb_connect print the rest.
238 				 */
239 				printf("%s: ", sc->sc_dev.dv_xname);
240 				kgdb_connect(1);
241 			} else
242 				printf("%s: kgdb enabled\n",
243 				    sc->sc_dev.dv_xname);
244 		}
245 	}
246 #endif
247 
248 	if (sc->sc_dev.dv_unit == comconsole) {
249 		/*
250 		 * Need to reset baud rate, etc. of next print so reset
251 		 * comconsinit.  Also make sure console is always "hardwired".
252 		 */
253 		comconsinit = 0;
254 		sc->sc_hwflags |= COM_HW_CONSOLE;
255 		sc->sc_swflags |= COM_SW_SOFTCAR;
256 	}
257 }
258 
259 int
260 comopen(dev, flag, mode, p)
261 	dev_t dev;
262 	int flag, mode;
263 	struct proc *p;
264 {
265 	int unit = COMUNIT(dev);
266 	struct com_softc *sc;
267 	int iobase;
268 	struct tty *tp;
269 	int s;
270 	int error = 0;
271 
272 	if (unit >= comcd.cd_ndevs)
273 		return ENXIO;
274 	sc = comcd.cd_devs[unit];
275 	if (!sc)
276 		return ENXIO;
277 
278 	if (!sc->sc_tty)
279 		tp = sc->sc_tty = ttymalloc();
280 	else
281 		tp = sc->sc_tty;
282 
283 	tp->t_oproc = comstart;
284 	tp->t_param = comparam;
285 	tp->t_dev = dev;
286 	if ((tp->t_state & TS_ISOPEN) == 0) {
287 		tp->t_state |= TS_WOPEN;
288 		ttychars(tp);
289 		tp->t_iflag = TTYDEF_IFLAG;
290 		tp->t_oflag = TTYDEF_OFLAG;
291 		tp->t_cflag = TTYDEF_CFLAG;
292 		if (sc->sc_swflags & COM_SW_CLOCAL)
293 			tp->t_cflag |= CLOCAL;
294 		if (sc->sc_swflags & COM_SW_CRTSCTS)
295 			tp->t_cflag |= CRTSCTS;
296 		if (sc->sc_swflags & COM_SW_MDMBUF)
297 			tp->t_cflag |= MDMBUF;
298 		tp->t_lflag = TTYDEF_LFLAG;
299 		tp->t_ispeed = tp->t_ospeed = comdefaultrate;
300 
301 		s = spltty();
302 
303 		comparam(tp, &tp->t_termios);
304 		ttsetwater(tp);
305 
306 		if (comsopen++ == 0)
307 			timeout(compoll, NULL, 1);
308 
309 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
310 		sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
311 		sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
312 
313 		iobase = sc->sc_iobase;
314 		/* Set the FIFO threshold based on the receive speed. */
315 		if (sc->sc_hwflags & COM_HW_FIFO)
316 			outb(iobase + com_fifo,
317 			    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
318 			    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
319 		/* flush any pending I/O */
320 		while (inb(iobase + com_lsr) & LSR_RXRDY)
321 			(void) inb(iobase + com_data);
322 		/* you turn me on, baby */
323 		sc->sc_mcr = MCR_DTR | MCR_RTS;
324 		if ((sc->sc_hwflags & COM_HW_NOIEN) == 0)
325 			sc->sc_mcr |= MCR_IENABLE;
326 		outb(iobase + com_mcr, sc->sc_mcr);
327 		outb(iobase + com_ier,
328 		    IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
329 
330 		sc->sc_msr = inb(iobase + com_msr);
331 		if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD ||
332 		    tp->t_cflag & MDMBUF)
333 			tp->t_state |= TS_CARR_ON;
334 		else
335 			tp->t_state &= ~TS_CARR_ON;
336 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
337 		return EBUSY;
338 	} else
339 		s = spltty();
340 
341 	/* wait for carrier if necessary */
342 	if ((flag & O_NONBLOCK) == 0)
343 		while ((tp->t_cflag & CLOCAL) == 0 &&
344 		    (tp->t_state & TS_CARR_ON) == 0) {
345 			tp->t_state |= TS_WOPEN;
346 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
347 			    TTIPRI | PCATCH, ttopen, 0);
348 			if (error) {
349 				/* XXX should turn off chip if we're the
350 				   only waiter */
351 				splx(s);
352 				return error;
353 			}
354 		}
355 	splx(s);
356 
357 	return (*linesw[tp->t_line].l_open)(dev, tp);
358 }
359 
360 int
361 comclose(dev, flag, mode, p)
362 	dev_t dev;
363 	int flag, mode;
364 	struct proc *p;
365 {
366 	int unit = COMUNIT(dev);
367 	struct com_softc *sc = comcd.cd_devs[unit];
368 	struct tty *tp = sc->sc_tty;
369 	int iobase = sc->sc_iobase;
370 	int s;
371 
372 	/* XXX This is for cons.c. */
373 	if ((tp->t_state & TS_ISOPEN) == 0)
374 		return 0;
375 
376 	(*linesw[tp->t_line].l_close)(tp, flag);
377 	s = spltty();
378 	bic(iobase + com_cfcr, CFCR_SBREAK);
379 	outb(iobase + com_ier, 0);
380 	if (tp->t_cflag & HUPCL &&
381 	    (sc->sc_swflags & COM_SW_SOFTCAR) == 0) {
382 		/* XXX perhaps only clear DTR */
383 		outb(iobase + com_mcr, 0);
384 	}
385 	tp->t_state &= ~(TS_BUSY | TS_FLUSH);
386 	if (--comsopen == 0)
387 		untimeout(compoll, NULL);
388 	splx(s);
389 	ttyclose(tp);
390 #ifdef notyet /* XXXX */
391 	if (unit != comconsole) {
392 		ttyfree(tp);
393 		sc->sc_tty = 0;
394 	}
395 #endif
396 	return 0;
397 }
398 
399 int
400 comread(dev, uio, flag)
401 	dev_t dev;
402 	struct uio *uio;
403 	int flag;
404 {
405 	struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
406 	struct tty *tp = sc->sc_tty;
407 
408 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
409 }
410 
411 int
412 comwrite(dev, uio, flag)
413 	dev_t dev;
414 	struct uio *uio;
415 	int flag;
416 {
417 	struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
418 	struct tty *tp = sc->sc_tty;
419 
420 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
421 }
422 
423 struct tty *
424 comtty(dev)
425 	dev_t dev;
426 {
427 	struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)];
428 	struct tty *tp = sc->sc_tty;
429 
430 	return (tp);
431 }
432 
433 static u_char
434 tiocm_xxx2mcr(data)
435 	int data;
436 {
437 	u_char m = 0;
438 
439 	if (data & TIOCM_DTR)
440 		m |= MCR_DTR;
441 	if (data & TIOCM_RTS)
442 		m |= MCR_RTS;
443 	return m;
444 }
445 
446 int
447 comioctl(dev, cmd, data, flag, p)
448 	dev_t dev;
449 	u_long cmd;
450 	caddr_t data;
451 	int flag;
452 	struct proc *p;
453 {
454 	int unit = COMUNIT(dev);
455 	struct com_softc *sc = comcd.cd_devs[unit];
456 	struct tty *tp = sc->sc_tty;
457 	int iobase = sc->sc_iobase;
458 	int error;
459 
460 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
461 	if (error >= 0)
462 		return error;
463 	error = ttioctl(tp, cmd, data, flag, p);
464 	if (error >= 0)
465 		return error;
466 
467 	switch (cmd) {
468 	case TIOCSBRK:
469 		bis(iobase + com_cfcr, CFCR_SBREAK);
470 		break;
471 	case TIOCCBRK:
472 		bic(iobase + com_cfcr, CFCR_SBREAK);
473 		break;
474 	case TIOCSDTR:
475 		outb(iobase + com_mcr, sc->sc_mcr |= sc->sc_dtr);
476 		break;
477 	case TIOCCDTR:
478 		outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
479 		break;
480 	case TIOCMSET:
481 		sc->sc_mcr &= ~(MCR_DTR | MCR_RTS);
482 	case TIOCMBIS:
483 		outb(iobase + com_mcr,
484 		    sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data));
485 		break;
486 	case TIOCMBIC:
487 		outb(iobase + com_mcr,
488 		    sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data));
489 		break;
490 	case TIOCMGET: {
491 		u_char m;
492 		int bits = 0;
493 
494 		m = sc->sc_mcr;
495 		if (m & MCR_DTR)
496 			bits |= TIOCM_DTR;
497 		if (m & MCR_RTS)
498 			bits |= TIOCM_RTS;
499 		m = sc->sc_msr;
500 		if (m & MSR_DCD)
501 			bits |= TIOCM_CD;
502 		if (m & MSR_CTS)
503 			bits |= TIOCM_CTS;
504 		if (m & MSR_DSR)
505 			bits |= TIOCM_DSR;
506 		if (m & (MSR_RI | MSR_TERI))
507 			bits |= TIOCM_RI;
508 		if (inb(iobase + com_ier))
509 			bits |= TIOCM_LE;
510 		*(int *)data = bits;
511 		break;
512 	}
513 	case TIOCGFLAGS: {
514 		int bits = 0;
515 
516 		if (sc->sc_swflags & COM_SW_SOFTCAR)
517 			bits |= TIOCFLAG_SOFTCAR;
518 		if (sc->sc_swflags & COM_SW_CLOCAL)
519 			bits |= TIOCFLAG_CLOCAL;
520 		if (sc->sc_swflags & COM_SW_CRTSCTS)
521 			bits |= TIOCFLAG_CRTSCTS;
522 		if (sc->sc_swflags & COM_SW_MDMBUF)
523 			bits |= TIOCFLAG_MDMBUF;
524 
525 		*(int *)data = bits;
526 		break;
527 	}
528 	case TIOCSFLAGS: {
529 		int userbits, driverbits = 0;
530 
531 		error = suser(p->p_ucred, &p->p_acflag);
532 		if (error != 0)
533 			return(EPERM);
534 
535 		userbits = *(int *)data;
536 		if ((userbits & TIOCFLAG_SOFTCAR) ||
537 		    (sc->sc_hwflags & COM_HW_CONSOLE))
538 			driverbits |= COM_SW_SOFTCAR;
539 		if (userbits & TIOCFLAG_CLOCAL)
540 			driverbits |= COM_SW_CLOCAL;
541 		if (userbits & TIOCFLAG_CRTSCTS)
542 			driverbits |= COM_SW_CRTSCTS;
543 		if (userbits & TIOCFLAG_MDMBUF)
544 			driverbits |= COM_SW_MDMBUF;
545 
546 		sc->sc_swflags = driverbits;
547 		break;
548 	}
549 	default:
550 		return ENOTTY;
551 	}
552 
553 	return 0;
554 }
555 
556 int
557 comparam(tp, t)
558 	struct tty *tp;
559 	struct termios *t;
560 {
561 	struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
562 	int iobase = sc->sc_iobase;
563 	int ospeed = comspeed(t->c_ospeed);
564 	u_char cfcr;
565 	tcflag_t oldcflag;
566 	int s;
567 
568 	/* check requested parameters */
569 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
570 		return EINVAL;
571 
572 	switch (t->c_cflag & CSIZE) {
573 	case CS5:
574 		cfcr = CFCR_5BITS;
575 		break;
576 	case CS6:
577 		cfcr = CFCR_6BITS;
578 		break;
579 	case CS7:
580 		cfcr = CFCR_7BITS;
581 		break;
582 	case CS8:
583 		cfcr = CFCR_8BITS;
584 		break;
585 	}
586 	if (t->c_cflag & PARENB) {
587 		cfcr |= CFCR_PENAB;
588 		if ((t->c_cflag & PARODD) == 0)
589 			cfcr |= CFCR_PEVEN;
590 	}
591 	if (t->c_cflag & CSTOPB)
592 		cfcr |= CFCR_STOPB;
593 
594 	s = spltty();
595 
596 	if (ospeed == 0)
597 		outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR);
598 
599 	/*
600 	 * Set the FIFO threshold based on the receive speed, if we are
601 	 * changing it.
602 	 */
603 	if (tp->t_ispeed != t->c_ispeed) {
604 		if (sc->sc_hwflags & COM_HW_FIFO)
605 			outb(iobase + com_fifo,
606 			    FIFO_ENABLE |
607 			    (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
608 	}
609 
610 	if (ospeed != 0) {
611 		outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
612 		outb(iobase + com_dlbl, ospeed);
613 		outb(iobase + com_dlbh, ospeed >> 8);
614 		outb(iobase + com_cfcr, cfcr);
615 		outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR);
616 	} else
617 		outb(iobase + com_cfcr, cfcr);
618 
619 	/* When not using CRTSCTS, RTS follows DTR. */
620 	if ((t->c_cflag & CRTSCTS) == 0) {
621 		if (sc->sc_mcr & MCR_DTR) {
622 			if ((sc->sc_mcr & MCR_RTS) == 0)
623 				outb(iobase + com_mcr, sc->sc_mcr |= MCR_RTS);
624 		} else {
625 			if (sc->sc_mcr & MCR_RTS)
626 				outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS);
627 		}
628 		sc->sc_dtr = MCR_DTR | MCR_RTS;
629 	} else
630 		sc->sc_dtr = MCR_DTR;
631 
632 	/* and copy to tty */
633 	tp->t_ispeed = t->c_ispeed;
634 	tp->t_ospeed = t->c_ospeed;
635 	oldcflag = tp->t_cflag;
636 	tp->t_cflag = t->c_cflag;
637 
638 	/*
639 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
640 	 * stop the device.
641 	 */
642 	if ((sc->sc_msr & MSR_DCD) == 0 &&
643 	    (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
644 	    (oldcflag & MDMBUF) != (tp->t_cflag & MDMBUF) &&
645 	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
646 		outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
647 	}
648 
649 	splx(s);
650 	return 0;
651 }
652 
653 void
654 comstart(tp)
655 	struct tty *tp;
656 {
657 	struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)];
658 	int iobase = sc->sc_iobase;
659 	int s;
660 
661 	s = spltty();
662 	if (tp->t_state & (TS_TTSTOP | TS_BUSY))
663 		goto out;
664 	if ((tp->t_cflag & CRTSCTS) != 0 &&
665 	    (sc->sc_msr & MSR_CTS) == 0)
666 		goto out;
667 	if (tp->t_outq.c_cc <= tp->t_lowat) {
668 		if (tp->t_state & TS_ASLEEP) {
669 			tp->t_state &= ~TS_ASLEEP;
670 			wakeup((caddr_t)&tp->t_outq);
671 		}
672 		if (tp->t_outq.c_cc == 0)
673 			goto out;
674 		selwakeup(&tp->t_wsel);
675 	}
676 	tp->t_state |= TS_BUSY;
677 	if (sc->sc_hwflags & COM_HW_FIFO) {
678 		u_char buffer[16], *cp = buffer;
679 		int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
680 		do {
681 			outb(iobase + com_data, *cp++);
682 		} while (--n);
683 	} else
684 		outb(iobase + com_data, getc(&tp->t_outq));
685 out:
686 	splx(s);
687 }
688 
689 /*
690  * Stop output on a line.
691  */
692 void
693 comstop(tp, flag)
694 	struct tty *tp;
695 {
696 	int s;
697 
698 	s = spltty();
699 	if (tp->t_state & TS_BUSY)
700 		if ((tp->t_state & TS_TTSTOP) == 0)
701 			tp->t_state |= TS_FLUSH;
702 	splx(s);
703 }
704 
705 void
706 comdiag(arg)
707 	void *arg;
708 {
709 	struct com_softc *sc = arg;
710 	int overflows, floods;
711 	int s;
712 
713 	s = spltty();
714 	sc->sc_errors = 0;
715 	overflows = sc->sc_overflows;
716 	sc->sc_overflows = 0;
717 	floods = sc->sc_floods;
718 	sc->sc_floods = 0;
719 	splx(s);
720 
721 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
722 	    sc->sc_dev.dv_xname,
723 	    overflows, overflows == 1 ? "" : "s",
724 	    floods, floods == 1 ? "" : "s");
725 }
726 
727 void
728 compoll(arg)
729 	void *arg;
730 {
731 	int unit;
732 	struct com_softc *sc;
733 	struct tty *tp;
734 	register u_char *ibufp;
735 	u_char *ibufend;
736 	register int c;
737 	int s;
738 	static int lsrmap[8] = {
739 		0,      TTY_PE,
740 		TTY_FE, TTY_PE|TTY_FE,
741 		TTY_FE, TTY_PE|TTY_FE,
742 		TTY_FE, TTY_PE|TTY_FE
743 	};
744 
745 	s = spltty();
746 	if (comevents == 0) {
747 		splx(s);
748 		goto out;
749 	}
750 	comevents = 0;
751 	splx(s);
752 
753 	for (unit = 0; unit < comcd.cd_ndevs; unit++) {
754 		sc = comcd.cd_devs[unit];
755 		if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf)
756 			continue;
757 
758 		tp = sc->sc_tty;
759 
760 		s = spltty();
761 
762 		ibufp = sc->sc_ibuf;
763 		ibufend = sc->sc_ibufp;
764 
765 		if (ibufp == ibufend) {
766 			splx(s);
767 			continue;
768 		}
769 
770 		sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
771 					     sc->sc_ibufs[1] : sc->sc_ibufs[0];
772 		sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
773 		sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
774 
775 		if (tp == 0 || (tp->t_state & TS_ISOPEN) == 0) {
776 			splx(s);
777 			continue;
778 		}
779 
780 		if ((tp->t_cflag & CRTSCTS) != 0 &&
781 		    (sc->sc_mcr & MCR_RTS) == 0)
782 			outb(sc->sc_iobase + com_mcr, sc->sc_mcr |= MCR_RTS);
783 
784 		splx(s);
785 
786 		while (ibufp < ibufend) {
787 			c = *ibufp++;
788 			if (*ibufp & LSR_OE) {
789 				sc->sc_overflows++;
790 				if (sc->sc_errors++ == 0)
791 					timeout(comdiag, sc, 60 * hz);
792 			}
793 			/* This is ugly, but fast. */
794 			c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
795 			(*linesw[tp->t_line].l_rint)(c, tp);
796 		}
797 	}
798 
799 out:
800 	timeout(compoll, NULL, 1);
801 }
802 
803 int
804 comintr(arg)
805 	void *arg;
806 {
807 	struct com_softc *sc = arg;
808 	int iobase = sc->sc_iobase;
809 	struct tty *tp;
810 	u_char lsr, data, msr, delta;
811 
812 	if (inb(iobase + com_iir) & IIR_NOPEND)
813 		return (0);
814 
815 	tp = sc->sc_tty;
816 
817 	for (;;) {
818 		lsr = inb(iobase + com_lsr);
819 
820 		if (lsr & LSR_RCV_MASK) {
821 			register u_char *p = sc->sc_ibufp;
822 
823 			comevents = 1;
824 			do {
825 				if ((lsr & LSR_BI) != 0) {
826 #ifdef DDB
827 					if (sc->sc_dev.dv_unit == comconsole) {
828 						Debugger();
829 						goto next;
830 					}
831 #endif
832 					data = '\0';
833 				} else
834 					data = inb(iobase + com_data);
835 				if (p >= sc->sc_ibufend) {
836 					sc->sc_floods++;
837 					if (sc->sc_errors++ == 0)
838 						timeout(comdiag, sc, 60 * hz);
839 				} else {
840 					*p++ = data;
841 					*p++ = lsr;
842 					if (p == sc->sc_ibufhigh &&
843 					    (tp->t_cflag & CRTSCTS) != 0)
844 						outb(iobase + com_mcr,
845 						     sc->sc_mcr &= ~MCR_RTS);
846 				}
847 			next:
848 				lsr = inb(iobase + com_lsr);
849 			} while (lsr & LSR_RCV_MASK);
850 
851 			sc->sc_ibufp = p;
852 		}
853 
854 		if (lsr & LSR_TXRDY && (tp->t_state & TS_BUSY) != 0) {
855 			tp->t_state &= ~TS_BUSY;
856 			if (tp->t_state & TS_FLUSH)
857 				tp->t_state &= ~TS_FLUSH;
858 			else
859 				(*linesw[tp->t_line].l_start)(tp);
860 		}
861 
862 		msr = inb(iobase + com_msr);
863 
864 		if (msr != sc->sc_msr) {
865 			delta = msr ^ sc->sc_msr;
866 			sc->sc_msr = msr;
867 			if ((delta & MSR_DCD) != 0 &&
868 			    (sc->sc_swflags & COM_SW_SOFTCAR) == 0 &&
869 			    (*linesw[tp->t_line].l_modem)(tp, (msr & MSR_DCD) != 0) == 0) {
870 				outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr);
871 			}
872 			if ((delta & msr & MSR_CTS) != 0 &&
873 			    (tp->t_cflag & CRTSCTS) != 0) {
874 				/* the line is up and we want to do rts/cts flow control */
875 				(*linesw[tp->t_line].l_start)(tp);
876 			}
877 		}
878 
879 		if (inb(iobase + com_iir) & IIR_NOPEND)
880 			return (1);
881 	}
882 }
883 
884 /*
885  * Following are all routines needed for COM to act as console
886  */
887 #include <dev/cons.h>
888 
889 void
890 comcnprobe(cp)
891 	struct consdev *cp;
892 {
893 
894 	if (!comprobe1(CONADDR)) {
895 		cp->cn_pri = CN_DEAD;
896 		return;
897 	}
898 
899 	/* locate the major number */
900 	for (commajor = 0; commajor < nchrdev; commajor++)
901 		if (cdevsw[commajor].d_open == comopen)
902 			break;
903 
904 	/* initialize required fields */
905 	cp->cn_dev = makedev(commajor, CONUNIT);
906 #ifdef	COMCONSOLE
907 	cp->cn_pri = CN_REMOTE;		/* Force a serial port console */
908 #else
909 	cp->cn_pri = CN_NORMAL;
910 #endif
911 }
912 
913 void
914 comcninit(cp)
915 	struct consdev *cp;
916 {
917 
918 	cominit(CONUNIT, comdefaultrate);
919 	comconsole = CONUNIT;
920 	comconsinit = 0;
921 }
922 
923 cominit(unit, rate)
924 	int unit, rate;
925 {
926 	int s = splhigh();
927 	int iobase = CONADDR;
928 	u_char stat;
929 
930 	outb(iobase + com_cfcr, CFCR_DLAB);
931 	rate = comspeed(comdefaultrate);
932 	outb(iobase + com_dlbl, rate);
933 	outb(iobase + com_dlbh, rate >> 8);
934 	outb(iobase + com_cfcr, CFCR_8BITS);
935 	outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY);
936 	outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
937 	stat = inb(iobase + com_iir);
938 	splx(s);
939 }
940 
941 comcngetc(dev)
942 	dev_t dev;
943 {
944 	int s = splhigh();
945 	int iobase = CONADDR;
946 	u_char stat, c;
947 
948 	while (((stat = inb(iobase + com_lsr)) & LSR_RXRDY) == 0)
949 		;
950 	c = inb(iobase + com_data);
951 	stat = inb(iobase + com_iir);
952 	splx(s);
953 	return c;
954 }
955 
956 /*
957  * Console kernel output character routine.
958  */
959 void
960 comcnputc(dev, c)
961 	dev_t dev;
962 	int c;
963 {
964 	int s = splhigh();
965 	int iobase = CONADDR;
966 	u_char stat;
967 	register int timo;
968 
969 #ifdef KGDB
970 	if (dev != kgdb_dev)
971 #endif
972 	if (comconsinit == 0) {
973 		(void) cominit(COMUNIT(dev), comdefaultrate);
974 		comconsinit = 1;
975 	}
976 	/* wait for any pending transmission to finish */
977 	timo = 50000;
978 	while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
979 		;
980 	outb(iobase + com_data, c);
981 	/* wait for this transmission to complete */
982 	timo = 1500000;
983 	while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
984 		;
985 	/* clear any interrupts generated by this transmission */
986 	stat = inb(iobase + com_iir);
987 	splx(s);
988 }
989 
990 void
991 comcnpollc(dev, on)
992 	dev_t dev;
993 	int on;
994 {
995 
996 }
997