com.c revision 1.26 1 /*-
2 * Copyright (c) 1993, 1994 Charles Hannum.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
35 * $Id: com.c,v 1.26 1994/03/23 01:28:23 cgd Exp $
36 */
37
38 /*
39 * COM driver, based on HP dca driver
40 * uses National Semiconductor NS16450/NS16550AF UART
41 */
42 #include "com.h"
43 #include "ast.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/isa_device.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
70 u_short sc_iobase;
71 u_char sc_hwflags;
72 #define COM_HW_MULTI 0x01
73 #define COM_HW_FIFO 0x02
74 #define COM_HW_CONSOLE 0x40
75 u_char sc_swflags;
76 #define COM_SW_SOFTCAR 0x01
77 #define COM_SW_CLOCAL 0x02
78 #define COM_SW_CRTSCTS 0x04
79 #define COM_SW_MDMBUF 0x08
80 u_char sc_msr, sc_mcr;
81 } com_softc[NCOM];
82 /* XXXX should be in com_softc, but not ready for that yet */
83 struct tty *com_tty[NCOM];
84
85 int comprobe __P((struct isa_device *));
86 int comattach __P((struct isa_device *));
87 int comopen __P((dev_t, int, int, struct proc *));
88 int comclose __P((dev_t, int, int, struct proc *));
89 int comintr __P((int));
90 int comparam __P((struct tty *, struct termios *));
91 void comstart __P((struct tty *));
92
93 struct isa_driver comdriver = {
94 comprobe, comattach, "com"
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 u_short com_ad = (c); \
116 outb(com_ad, inb(com_ad) | (b)); } while(0)
117 #define bic(c, b) do { const register u_short 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 u_short 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(isa_dev)
161 struct isa_device *isa_dev;
162 {
163 struct com_softc *sc = &com_softc[isa_dev->id_unit];
164 u_short iobase = isa_dev->id_iobase;
165
166 if (isa_dev->id_parent) {
167 if (iobase == 0) {
168 /*
169 * For multiport cards, the iobase may be left
170 * unspecified (zero) for slave ports. In
171 * that case we calculate it from the master
172 * (parent) iobase setting and the slave port
173 * number (physid).
174 */
175 iobase = isa_dev->id_iobase
176 = isa_dev->id_parent->id_iobase +
177 (8 * isa_dev->id_physid);
178 }
179 }
180
181 /* XXX HACK */
182 sprintf(sc->sc_dev.dv_xname, "%s%d", comdriver.name, isa_dev->id_unit);
183 sc->sc_dev.dv_unit = isa_dev->id_unit;
184
185 if (!comprobe1(iobase))
186 return 0;
187
188 return COM_NPORTS;
189 }
190
191 int
192 comattach(isa_dev)
193 struct isa_device *isa_dev;
194 {
195 int unit = isa_dev->id_unit;
196 struct com_softc *sc = &com_softc[unit];
197 u_short iobase = isa_dev->id_iobase;
198 struct tty *tp;
199
200 if (unit == comconsole)
201 delay(1000);
202
203 sc->sc_iobase = iobase;
204 sc->sc_hwflags = 0;
205 sc->sc_swflags = 0;
206
207 printf("%s: ", sc->sc_dev.dv_xname);
208
209 printf("%s", sc->sc_dev.dv_xname);
210 #if NAST > 0
211 if (isa_dev->id_parent) {
212 printf(" at 0x%x %s%d slave %d",
213 isa_dev->id_iobase,
214 isa_dev->id_parent->id_driver->name,
215 isa_dev->id_parent->id_unit,
216 isa_dev->id_physid);
217 astslave(isa_dev, unit);
218 sc->sc_hwflags |= COM_HW_MULTI;
219 }
220 #endif
221 printf(": ");
222
223 /* look for a NS 16550AF UART with FIFOs */
224 outb(iobase + com_fifo,
225 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
226 delay(100);
227 if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
228 if ((inb(iobase + com_fifo) & FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
229 sc->sc_hwflags |= COM_HW_FIFO;
230 printf("ns16550a, working fifo\n");
231 } else
232 printf("ns82550 or ns16550, broken fifo\n");
233 else
234 printf("ns82450 or ns16450, no fifo\n");
235 outb(iobase + com_fifo, 0);
236
237 /* disable interrupts */
238 outb(iobase + com_ier, 0);
239 outb(iobase + com_mcr, 0);
240
241 #ifdef KGDB
242 if (kgdb_dev == makedev(commajor, unit)) {
243 if (comconsole == unit)
244 kgdb_dev = -1; /* can't debug over console port */
245 else {
246 (void) cominit(unit, kgdb_rate);
247 if (kgdb_debug_init) {
248 /*
249 * Print prefix of device name,
250 * let kgdb_connect print the rest.
251 */
252 printf("%s: ", sc->sc_dev.dv_xname);
253 kgdb_connect(1);
254 } else
255 printf("%s: kgdb enabled\n",
256 sc->sc_dev.dv_xname);
257 }
258 }
259 #endif
260
261 /*
262 * Need to reset baud rate, etc. of next print so reset comconsinit.
263 * Also make sure console is always "hardwired".
264 */
265 if (unit == comconsole) {
266 comconsinit = 0;
267 sc->sc_hwflags |= COM_HW_CONSOLE;
268 sc->sc_swflags |= COM_SW_SOFTCAR;
269 }
270 }
271
272 int
273 comopen(dev, flag, mode, p)
274 dev_t dev;
275 int flag, mode;
276 struct proc *p;
277 {
278 int unit = COMUNIT(dev);
279 struct com_softc *sc;
280 u_short iobase;
281 struct tty *tp;
282 int s;
283 int error = 0;
284
285 if (unit > NCOM)
286 return ENXIO;
287 sc = &com_softc[unit];
288 if (!sc->sc_iobase)
289 return ENXIO;
290
291 s = spltty();
292
293 if (!com_tty[unit])
294 tp = com_tty[unit] = ttymalloc();
295 else
296 tp = com_tty[unit];
297
298 tp->t_oproc = comstart;
299 tp->t_param = comparam;
300 tp->t_dev = dev;
301 if ((tp->t_state & TS_ISOPEN) == 0) {
302 tp->t_state |= TS_WOPEN;
303 ttychars(tp);
304 tp->t_iflag = TTYDEF_IFLAG;
305 tp->t_oflag = TTYDEF_OFLAG;
306 tp->t_cflag = TTYDEF_CFLAG;
307 if (sc->sc_swflags & COM_SW_CLOCAL)
308 tp->t_cflag |= CLOCAL;
309 if (sc->sc_swflags & COM_SW_CRTSCTS)
310 tp->t_cflag |= CRTSCTS;
311 if (sc->sc_swflags & COM_SW_MDMBUF)
312 tp->t_cflag |= MDMBUF;
313 tp->t_lflag = TTYDEF_LFLAG;
314 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
315 comparam(tp, &tp->t_termios);
316 ttsetwater(tp);
317
318 iobase = sc->sc_iobase;
319 /* flush any pending I/O */
320 if (sc->sc_hwflags & COM_HW_FIFO)
321 outb(iobase + com_fifo,
322 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
323 FIFO_TRIGGER_8);
324 (void) inb(iobase + com_lsr);
325 (void) inb(iobase + com_data);
326 /* you turn me on, baby */
327 sc->sc_mcr = MCR_DTR | MCR_RTS;
328 if (!(sc->sc_hwflags & COM_HW_MULTI))
329 sc->sc_mcr |= MCR_IENABLE;
330 outb(iobase + com_mcr, sc->sc_mcr);
331 outb(iobase + com_ier,
332 IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
333
334 sc->sc_msr = inb(iobase + com_msr);
335 if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD ||
336 tp->t_lflag&MDMBUF)
337 tp->t_state |= TS_CARR_ON;
338 else
339 tp->t_state &= ~TS_CARR_ON;
340 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) {
341 splx(s);
342 return EBUSY;
343 }
344
345 /* wait for carrier if necessary */
346 if ((flag & O_NONBLOCK) == 0)
347 while ((tp->t_cflag & CLOCAL) == 0 &&
348 (tp->t_state & TS_CARR_ON) == 0) {
349 tp->t_state |= TS_WOPEN;
350 error = ttysleep(tp, (caddr_t)&tp->t_rawq,
351 TTIPRI | PCATCH, ttopen, 0);
352 if (error) {
353 /* XXX should turn off chip if we're the
354 only waiter */
355 splx(s);
356 return error;
357 }
358 }
359 splx(s);
360
361 return (*linesw[tp->t_line].l_open)(dev, tp);
362 }
363
364 int
365 comclose(dev, flag, mode, p)
366 dev_t dev;
367 int flag, mode;
368 struct proc *p;
369 {
370 int unit = COMUNIT(dev);
371 struct com_softc *sc = &com_softc[unit];
372 u_short iobase = sc->sc_iobase;
373 struct tty *tp = com_tty[unit];
374
375 (*linesw[tp->t_line].l_close)(tp, flag);
376 #ifdef KGDB
377 /* do not disable interrupts if debugging */
378 if (kgdb_dev != makedev(commajor, unit))
379 #endif
380 {
381 bic(iobase + com_cfcr, CFCR_SBREAK);
382 outb(iobase + com_ier, 0);
383 if (tp->t_cflag & HUPCL &&
384 (sc->sc_swflags & COM_SW_SOFTCAR) == 0)
385 /* XXX perhaps only clear DTR */
386 outb(iobase + com_mcr, 0);
387 }
388 ttyclose(tp);
389 #ifdef notyet /* XXXX */
390 if (unit != comconsole) {
391 ttyfree(tp);
392 com_tty[unit] = (struct tty *)NULL;
393 }
394 #endif
395 return 0;
396 }
397
398 int
399 comread(dev, uio, flag)
400 dev_t dev;
401 struct uio *uio;
402 int flag;
403 {
404 struct tty *tp = com_tty[COMUNIT(dev)];
405
406 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
407 }
408
409 int
410 comwrite(dev, uio, flag)
411 dev_t dev;
412 struct uio *uio;
413 int flag;
414 {
415 struct tty *tp = com_tty[COMUNIT(dev)];
416
417 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
418 }
419
420 static u_char
421 tiocm_xxx2mcr(data)
422 int data;
423 {
424 u_char m = 0;
425
426 if (data & TIOCM_DTR)
427 m |= MCR_DTR;
428 if (data & TIOCM_RTS)
429 m |= MCR_RTS;
430 return m;
431 }
432
433 int
434 comioctl(dev, cmd, data, flag, p)
435 dev_t dev;
436 int cmd;
437 caddr_t data;
438 int flag;
439 struct proc *p;
440 {
441 int unit = COMUNIT(dev);
442 struct com_softc *sc = &com_softc[unit];
443 u_short iobase = sc->sc_iobase;
444 struct tty *tp = com_tty[unit];
445 int error;
446
447 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
448 if (error >= 0)
449 return error;
450 error = ttioctl(tp, cmd, data, flag, p);
451 if (error >= 0)
452 return error;
453
454 switch (cmd) {
455 case TIOCSBRK:
456 bis(iobase + com_cfcr, CFCR_SBREAK);
457 break;
458 case TIOCCBRK:
459 bic(iobase + com_cfcr, CFCR_SBREAK);
460 break;
461 case TIOCSDTR:
462 outb(iobase + com_mcr, sc->sc_mcr |= (MCR_DTR | MCR_RTS));
463 break;
464 case TIOCCDTR:
465 outb(iobase + com_mcr, sc->sc_mcr &= ~(MCR_DTR | MCR_RTS));
466 break;
467 case TIOCMSET:
468 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS);
469 case TIOCMBIS:
470 outb(iobase + com_mcr,
471 sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data));
472 break;
473 case TIOCMBIC:
474 outb(iobase + com_mcr,
475 sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data));
476 break;
477 case TIOCMGET: {
478 u_char m;
479 int bits = 0;
480
481 m = sc->sc_mcr;
482 if (m & MCR_DTR)
483 bits |= TIOCM_DTR;
484 if (m & MCR_RTS)
485 bits |= TIOCM_RTS;
486 m = sc->sc_msr;
487 if (m & MSR_DCD)
488 bits |= TIOCM_CD;
489 if (m & MSR_CTS)
490 bits |= TIOCM_CTS;
491 if (m & MSR_DSR)
492 bits |= TIOCM_DSR;
493 if (m & (MSR_RI | MSR_TERI))
494 bits |= TIOCM_RI;
495 if (inb(iobase + com_ier))
496 bits |= TIOCM_LE;
497 *(int *)data = bits;
498 break;
499 }
500 case TIOCGFLAGS: {
501 int bits = 0;
502
503 if (sc->sc_swflags & COM_SW_SOFTCAR)
504 bits |= TIOCFLAG_SOFTCAR;
505 if (sc->sc_swflags & COM_SW_CLOCAL)
506 bits |= TIOCFLAG_CLOCAL;
507 if (sc->sc_swflags & COM_SW_CRTSCTS)
508 bits |= TIOCFLAG_CRTSCTS;
509 if (sc->sc_swflags & COM_SW_MDMBUF)
510 bits |= TIOCFLAG_MDMBUF;
511
512 *(int *)data = bits;
513 break;
514 }
515 case TIOCSFLAGS: {
516 int userbits, driverbits = 0;
517
518 error = suser(p->p_ucred, &p->p_acflag);
519 if (error != 0)
520 return(EPERM);
521
522 userbits = *(int *)data;
523 if ((userbits & TIOCFLAG_SOFTCAR) ||
524 (sc->sc_hwflags & COM_HW_CONSOLE))
525 driverbits |= COM_SW_SOFTCAR;
526 if (userbits & TIOCFLAG_CLOCAL)
527 driverbits |= COM_SW_CLOCAL;
528 if (userbits & TIOCFLAG_CRTSCTS)
529 driverbits |= COM_SW_CRTSCTS;
530
531 sc->sc_swflags = driverbits;
532 break;
533 }
534 default:
535 return ENOTTY;
536 }
537
538 return 0;
539 }
540
541 int
542 comparam(tp, t)
543 struct tty *tp;
544 struct termios *t;
545 {
546 struct com_softc *sc = &com_softc[COMUNIT(tp->t_dev)];
547 u_short iobase = sc->sc_iobase;
548 int ospeed = comspeed(t->c_ospeed);
549 u_char cfcr;
550 int s;
551
552 /* check requested parameters */
553 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
554 return EINVAL;
555
556 switch (t->c_cflag & CSIZE) {
557 case CS5:
558 cfcr = CFCR_5BITS;
559 break;
560 case CS6:
561 cfcr = CFCR_6BITS;
562 break;
563 case CS7:
564 cfcr = CFCR_7BITS;
565 break;
566 case CS8:
567 cfcr = CFCR_8BITS;
568 break;
569 }
570 if (t->c_cflag & PARENB) {
571 cfcr |= CFCR_PENAB;
572 if ((t->c_cflag & PARODD) == 0)
573 cfcr |= CFCR_PEVEN;
574 }
575 if (t->c_cflag & CSTOPB)
576 cfcr |= CFCR_STOPB;
577
578 s = spltty();
579
580 /* and copy to tty */
581 tp->t_ispeed = t->c_ispeed;
582 tp->t_ospeed = t->c_ospeed;
583 tp->t_cflag = t->c_cflag;
584
585 if (ospeed == 0)
586 outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR);
587 else
588 outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR);
589
590 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
591 outb(iobase + com_dlbl, ospeed);
592 outb(iobase + com_dlbh, ospeed>>8);
593 outb(iobase + com_cfcr, cfcr);
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 ttstart(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 ttstart(tp);
629 } else
630 tp->t_state |= TS_TTSTOP;
631 }
632
633 splx(s);
634 return 0;
635 }
636
637 void
638 comstart(tp)
639 struct tty *tp;
640 {
641 struct com_softc *sc = &com_softc[COMUNIT(tp->t_dev)];
642 u_short 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 u_short 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 log(LOG_WARNING, "%s: silo overflow\n", sc->sc_dev.dv_xname);
718 /* XXXX put in FIFO and process later */
719 (*linesw[tp->t_line].l_rint)(c, tp);
720 }
721
722 static inline void
723 commint(sc)
724 struct com_softc *sc;
725 {
726 u_short iobase = sc->sc_iobase;
727 struct tty *tp = com_tty[sc->sc_dev.dv_unit];
728 u_char msr, delta;
729
730 msr = inb(iobase + com_msr);
731 delta = msr ^ sc->sc_msr;
732 sc->sc_msr = msr;
733
734 if (delta & MSR_DCD && (sc->sc_swflags & COM_SW_SOFTCAR) == 0) {
735 if (msr & MSR_DCD)
736 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
737 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
738 outb(iobase + com_mcr,
739 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS));
740 }
741 if (delta & MSR_CTS && tp->t_cflag & CRTSCTS) {
742 /* the line is up and we want to do rts/cts flow control */
743 if (msr & MSR_CTS) {
744 tp->t_state &= ~TS_TTSTOP;
745 ttstart(tp);
746 } else
747 tp->t_state |= TS_TTSTOP;
748 }
749 }
750
751 int
752 comintr(unit)
753 int unit;
754 {
755 struct com_softc *sc = &com_softc[unit];
756 u_short iobase = sc->sc_iobase;
757 struct tty *tp;
758 u_char code;
759
760 code = inb(iobase + com_iir) & IIR_IMASK;
761 if (code & IIR_NOPEND)
762 return 0;
763
764 for (;;) {
765 if (code & IIR_RXRDY) {
766 tp = com_tty[sc->sc_dev.dv_unit];
767 /* XXXX put in FIFO and process later */
768 while (code = (inb(iobase + com_lsr) & LSR_RCV_MASK)) {
769 if (code == LSR_RXRDY) {
770 code = inb(iobase + com_data);
771 if (tp->t_state & TS_ISOPEN)
772 (*linesw[tp->t_line].l_rint)(code, tp);
773 #ifdef KGDB
774 else {
775 if (kgdb_dev == makedev(commajor, unit) &&
776 code == FRAME_END)
777 kgdb_connect(0);
778 }
779 #endif
780 } else
781 comeint(sc, code);
782 }
783 } else if (code == IIR_TXRDY) {
784 tp = com_tty[sc->sc_dev.dv_unit];
785 tp->t_state &= ~TS_BUSY;
786 if (tp->t_state & TS_FLUSH)
787 tp->t_state &= ~TS_FLUSH;
788 else
789 if (tp->t_line)
790 (*linesw[tp->t_line].l_start)(tp);
791 else
792 comstart(tp);
793 } else if (code == IIR_MLSC) {
794 commint(sc);
795 } else {
796 log(LOG_WARNING, "%s: weird interrupt: iir=0x%02x\n",
797 sc->sc_dev.dv_xname, code);
798 }
799 code = inb(iobase + com_iir) & IIR_IMASK;
800 if (code & IIR_NOPEND)
801 return 1;
802 }
803 }
804
805 /*
806 * Following are all routines needed for COM to act as console
807 */
808 #include <dev/cons.h>
809
810 comcnprobe(cp)
811 struct consdev *cp;
812 {
813 int unit = CONUNIT;
814
815 if (!comprobe1(CONADDR)) {
816 cp->cn_pri = CN_DEAD;
817 return;
818 }
819
820 /* locate the major number */
821 for (commajor = 0; commajor < nchrdev; commajor++)
822 if (cdevsw[commajor].d_open == comopen)
823 break;
824
825 com_softc[unit].sc_iobase = CONADDR;
826
827 /* initialize required fields */
828 cp->cn_dev = makedev(commajor, unit);
829 #ifdef COMCONSOLE
830 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
831 #else
832 cp->cn_pri = CN_NORMAL;
833 #endif
834 }
835
836 comcninit(cp)
837 struct consdev *cp;
838 {
839 int unit = CONUNIT;
840
841 cominit(unit, comdefaultrate);
842 comconsole = unit;
843 comconsinit = 0;
844 }
845
846 cominit(unit, rate)
847 int unit, rate;
848 {
849 int s = splhigh();
850 u_short iobase = com_softc[unit].sc_iobase;
851 u_char stat;
852
853 outb(iobase + com_cfcr, CFCR_DLAB);
854 rate = comspeed(comdefaultrate);
855 outb(iobase + com_dlbl, rate);
856 outb(iobase + com_dlbh, rate >> 8);
857 outb(iobase + com_cfcr, CFCR_8BITS);
858 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY);
859 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
860 stat = inb(iobase + com_iir);
861 splx(s);
862 }
863
864 comcngetc(dev)
865 dev_t dev;
866 {
867 int s = splhigh();
868 u_short iobase = com_softc[COMUNIT(dev)].sc_iobase;
869 u_char stat, c;
870
871 while (((stat = inb(iobase + com_lsr)) & LSR_RXRDY) == 0)
872 ;
873 c = inb(iobase + com_data);
874 stat = inb(iobase + com_iir);
875 splx(s);
876 return c;
877 }
878
879 /*
880 * Console kernel output character routine.
881 */
882 comcnputc(dev, c)
883 dev_t dev;
884 int c;
885 {
886 int s = splhigh();
887 u_short iobase = com_softc[COMUNIT(dev)].sc_iobase;
888 u_char stat;
889 register int timo;
890
891 #ifdef KGDB
892 if (dev != kgdb_dev)
893 #endif
894 if (comconsinit == 0) {
895 (void) cominit(COMUNIT(dev), comdefaultrate);
896 comconsinit = 1;
897 }
898 /* wait for any pending transmission to finish */
899 timo = 50000;
900 while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
901 ;
902 outb(iobase + com_data, c);
903 /* wait for this transmission to complete */
904 timo = 1500000;
905 while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo)
906 ;
907 /* clear any interrupts generated by this transmission */
908 stat = inb(iobase + com_iir);
909 splx(s);
910 }
911