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