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