com.c revision 1.12.2.6 1 /*-
2 * Copyright (c) 1993 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.12.2.6 1993/10/11 01:51:19 mycroft Exp $
36 */
37
38 /*
39 * COM driver, based originally on HP dca driver
40 * uses National Semiconductor NS16450/NS16550AF UART
41 */
42 #include "param.h"
43 #include "systm.h"
44 #include "ioctl.h"
45 #include "select.h"
46 #include "tty.h"
47 #include "proc.h"
48 #include "user.h"
49 #include "conf.h"
50 #include "file.h"
51 #include "uio.h"
52 #include "kernel.h"
53 #include "syslog.h"
54 #include "types.h"
55 #include "sys/device.h"
56
57 #include "machine/cpu.h"
58 #include "machine/pio.h"
59
60 #include "i386/isa/isavar.h"
61 #include "i386/isa/icu.h"
62 #include "i386/isa/comreg.h"
63 #include "i386/isa/ic/ns16550.h"
64
65 struct com_softc {
66 struct device sc_dev;
67 struct isadev sc_id;
68 struct intrhand sc_ih;
69
70 struct ringbuf {
71 int rb_count, rb_first, rb_last, rb_size;
72 char *rb_data;
73 } sc_q;
74 u_short sc_iobase;
75 u_char sc_flags;
76 #define COM_SOFTCAR 0x01
77 #define COM_FIFO 0x02
78 };
79 /* XXXX should be in com_softc, but not ready for that yet */
80 #include "com.h"
81 struct tty *com_tty[NCOM];
82
83 int comdefaultrate = TTYDEF_SPEED;
84
85 static int comprobe __P((struct device *, struct cfdata *, void *));
86 static void comforceintr __P((void *));
87 static void comattach __P((struct device *, struct device *, void *));
88 static int comintr __P((void *));
89
90 struct cfdriver comcd =
91 { NULL, "com", comprobe, comattach, sizeof (struct com_softc) };
92
93 int comparam __P((struct tty *, struct termios *));
94 void comstart __P((struct tty *));
95
96 int comconsole = -1;
97 int comconsinit;
98 int commajor;
99 extern struct tty *constty;
100
101 #define COMUNIT(x) (minor(x))
102
103 #define bis(c, b) do { const register u_short com_ad = (c); \
104 outb(com_ad, inb(com_ad) | (b)); } while(0)
105 #define bic(c, b) do { const register u_short com_ad = (c); \
106 outb(com_ad, inb(com_ad) &~ (b)); } while(0)
107
108 static int
109 comspeed(speed)
110 int speed;
111 {
112 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
113
114 int x, err;
115
116 if (speed == 0)
117 return 0;
118 if (speed < 0)
119 return -1;
120 x = divrnd((COM_FREQ / 16), speed);
121 if (x <= 0)
122 return -1;
123 err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
124 if (err < 0)
125 err = -err;
126 if (err > COM_TOLERANCE)
127 return -1;
128 return x;
129
130 #undef divrnd(n, q)
131 }
132
133 static int
134 _comprobe(iobase)
135 u_short iobase;
136 {
137
138 /* force access to id reg */
139 outb(iobase + com_cfcr, 0);
140 outb(iobase + com_iir, 0);
141 if (inb(iobase + com_iir) & 0x38)
142 return 0;
143 outb(iobase + com_ier, 0);
144 return 1;
145 }
146
147 static int
148 comprobe(parent, cf, aux)
149 struct device *parent;
150 struct cfdata *cf;
151 void *aux;
152 {
153 struct isa_attach_args *ia = aux;
154 u_short iobase = ia->ia_iobase;
155
156 if (iobase == IOBASEUNK)
157 return 0;
158
159 if (!_comprobe(iobase))
160 return 0;
161
162 if (ia->ia_irq == IRQUNK) {
163 ia->ia_irq = isa_discoverintr(comforceintr, aux);
164 if (ia->ia_irq == IRQNONE)
165 return 0;
166 }
167
168 /* disable interrupts */
169 outb(iobase + com_mcr, 0);
170 outb(iobase + com_ier, 0);
171
172 ia->ia_iosize = COM_NPORTS;
173 ia->ia_drq = DRQUNK;
174 ia->ia_msize = 0;
175 return 1;
176 }
177
178 static void
179 comforceintr(aux)
180 void *aux;
181 {
182 struct isa_attach_args *ia = aux;
183 u_short iobase = ia->ia_iobase;
184
185 #if 0
186 /*
187 * As usual, the PC compatible world isn't. We'd like to use the
188 * loopback feature to generate an interrupt, but alas, some lame
189 * clones don't support it.
190 */
191 outb(iobase + com_mcr, MCR_IENABLE | MCR_LOOPBACK);
192 outb(iobase + com_ier, IER_EMSC);
193 outb(iobase + com_mcr, MCR_IENABLE | MCR_LOOPBACK | MCR_DRS);
194 outb(iobase + com_mcr, MCR_IENABLE | MCR_LOOPBACK);
195 #else
196 /*
197 * So instead we try to force the transmit buffer empty (though
198 * it probably is already).
199 */
200 outb(iobase + com_cfcr, CFCR_8BITS); /* turn off DLAB */
201 outb(iobase + com_ier, 0);
202 outb(iobase + com_fifo, 0);
203 outb(iobase + com_lsr, LSR_TXRDY | LSR_TSRE);
204 outb(iobase + com_mcr, MCR_IENABLE);
205 outb(iobase + com_ier, IER_ETXRDY);
206 #endif
207 }
208
209 static void
210 comattach(parent, self, aux)
211 struct device *parent, *self;
212 void *aux;
213 {
214 struct com_softc *sc = (struct com_softc *)self;
215 struct isa_attach_args *ia = aux;
216 u_short iobase = ia->ia_iobase;
217 struct tty *tp;
218 u_char unit = sc->sc_dev.dv_unit;
219
220 if (iobase == comconsole)
221 delay(1000);
222
223 sc->sc_iobase = iobase;
224 sc->sc_flags = 0;
225
226 /* look for a NS 16550AF UART with FIFOs */
227 outb(iobase + com_fifo,
228 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
229 delay(100);
230 if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) {
231 sc->sc_flags |= COM_FIFO;
232 printf(": ns16550\n");
233 } else
234 printf(": ns8250 or ns16450\n");
235 isa_establish(&sc->sc_id, &sc->sc_dev);
236
237 sc->sc_ih.ih_fun = comintr;
238 sc->sc_ih.ih_arg = sc;
239 intr_establish(ia->ia_irq, &sc->sc_ih, DV_TTY);
240
241 outb(iobase + com_ier, 0);
242 outb(iobase + com_mcr, MCR_IENABLE);
243
244 /*
245 * Need to reset baud rate, etc. of next print so reset comconsinit.
246 * Also make sure console is always "hardwired"
247 */
248 if (iobase == comconsole) {
249 constty = com_tty[unit] = ttymalloc();
250 comconsinit = 0;
251 sc->sc_flags |= COM_SOFTCAR;
252 }
253 }
254
255 int
256 comopen(dev, flag, mode, p)
257 dev_t dev;
258 int flag, mode;
259 struct proc *p;
260 {
261 int unit = COMUNIT(dev);
262 struct com_softc *sc;
263 u_short iobase;
264 struct tty *tp;
265 int s;
266 int error = 0;
267
268 if (unit >= comcd.cd_ndevs)
269 return ENXIO;
270 sc = comcd.cd_devs[unit];
271 if (!sc)
272 return ENXIO;
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 /* preserve previous speed, if any */
286 if (tp->t_ispeed == 0) {
287 tp->t_iflag = TTYDEF_IFLAG;
288 tp->t_oflag = TTYDEF_OFLAG;
289 tp->t_cflag = TTYDEF_CFLAG;
290 tp->t_lflag = TTYDEF_LFLAG;
291 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
292 }
293 comparam(tp, &tp->t_termios);
294 ttsetwater(tp);
295 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
296 return EBUSY;
297
298 s = spltty();
299 iobase = sc->sc_iobase;
300 outb(iobase + com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
301 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
302
303 if (sc->sc_flags & COM_SOFTCAR || inb(iobase + com_msr) & MSR_DCD)
304 tp->t_state |= TS_CARR_ON;
305 else
306 tp->t_state &= ~TS_CARR_ON;
307 while ((flag & O_NONBLOCK) == 0 && (tp->t_cflag & CLOCAL) == 0 &&
308 (tp->t_state & TS_CARR_ON) == 0) {
309 /* wait for carrier; allow signals */
310 tp->t_state |= TS_WOPEN;
311 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
312 ttopen, 0)) {
313 splx(s);
314 return error;
315 }
316 }
317 splx(s);
318
319 return (*linesw[tp->t_line].l_open)(dev, tp);
320 }
321
322 int
323 comclose(dev, flag)
324 dev_t dev;
325 int flag;
326 {
327 int unit = COMUNIT(dev);
328 struct com_softc *sc = comcd.cd_devs[unit];
329 u_short iobase = sc->sc_iobase;
330 struct tty *tp = com_tty[unit];
331
332 (*linesw[tp->t_line].l_close)(tp, flag);
333 bic(iobase + com_cfcr, CFCR_SBREAK);
334 outb(iobase + com_ier, 0);
335 if (tp->t_cflag & HUPCL)
336 bic(iobase + com_mcr, MCR_DTR | MCR_RTS);
337 ttyclose(tp);
338 tp->t_state &= ~(TS_ISOPEN | TS_WOPEN);
339 #ifdef notyet /* XXXX */
340 if (iobase != comconsole) {
341 ttyfree(tp);
342 com_tty[unit] = (struct tty *)NULL;
343 }
344 #endif
345 return 0;
346 }
347
348 int
349 comread(dev, uio, flag)
350 dev_t dev;
351 struct uio *uio;
352 int flag;
353 {
354 struct tty *tp = com_tty[COMUNIT(dev)];
355
356 return (*linesw[tp->t_line].l_read)(tp, uio, flag);
357 }
358
359 int
360 comwrite(dev, uio, flag)
361 dev_t dev;
362 struct uio *uio;
363 int flag;
364 {
365 struct tty *tp = com_tty[COMUNIT(dev)];
366
367 /* XXXX what is this for? */
368 if (constty == tp)
369 constty = NULL;
370 return (*linesw[tp->t_line].l_write)(tp, uio, flag);
371 }
372
373 static u_char
374 tiocm_xxx2mcr(data)
375 int data;
376 {
377 u_char m = 0;
378 if (data & TIOCM_DTR)
379 m |= MCR_DTR;
380 if (data & TIOCM_RTS)
381 m |= MCR_RTS;
382 return m;
383 }
384
385 int
386 comioctl(dev, cmd, data, flag)
387 dev_t dev;
388 int cmd;
389 caddr_t data;
390 int flag;
391 {
392 int unit = COMUNIT(dev);
393 struct com_softc *sc = comcd.cd_devs[unit];
394 u_short iobase = sc->sc_iobase;
395 struct tty *tp = com_tty[unit];
396 int error;
397
398 if (error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag))
399 return error;
400 if (error = ttioctl(tp, cmd, data, flag))
401 return error;
402
403 switch (cmd) {
404 case TIOCSBRK:
405 bis(iobase + com_cfcr, CFCR_SBREAK);
406 break;
407 case TIOCCBRK:
408 bic(iobase + com_cfcr, CFCR_SBREAK);
409 break;
410 case TIOCSDTR:
411 bis(iobase + com_mcr, MCR_DTR | MCR_RTS);
412 break;
413 case TIOCCDTR:
414 bic(iobase + com_mcr, MCR_DTR | MCR_RTS);
415 break;
416 case TIOCMSET:
417 outb(iobase + com_mcr, tiocm_xxx2mcr(*(int *)data) | MCR_IENABLE);
418 break;
419 case TIOCMBIS:
420 bis(iobase + com_mcr, tiocm_xxx2mcr(*(int *)data));
421 break;
422 case TIOCMBIC:
423 bic(iobase + com_mcr, tiocm_xxx2mcr(*(int *)data));
424 break;
425 case TIOCMGET:
426 {
427 u_char m = inb(iobase + com_mcr);
428 int bits = 0;
429
430 m = inb(iobase + com_mcr);
431 if (m & MCR_DTR)
432 bits |= TIOCM_DTR;
433 if (m & MCR_RTS)
434 bits |= TIOCM_RTS;
435 m = inb(iobase + com_msr);
436 if (m & MSR_CTS)
437 bits |= TIOCM_CTS;
438 if (m & MSR_DSR)
439 bits |= TIOCM_DSR;
440 if (m & (MSR_RI | MSR_TERI))
441 bits |= TIOCM_RI;
442 if (inb(iobase + com_ier))
443 bits |= TIOCM_LE;
444 *(int *)data = bits;
445 break;
446 }
447 break;
448 default:
449 return ENOTTY;
450 }
451
452 return 0;
453 }
454
455 int
456 comparam(tp, t)
457 struct tty *tp;
458 struct termios *t;
459 {
460 int unit = COMUNIT(tp->t_dev);
461 struct com_softc *sc = comcd.cd_devs[unit];
462 u_short iobase = sc->sc_iobase;
463 int ospeed = comspeed(t->c_ospeed);
464 u_char cflag = t->c_cflag;
465 u_char cfcr;
466
467 /* check requested parameters */
468 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
469 return EINVAL;
470
471 /* and copy to tty */
472 tp->t_ispeed = t->c_ispeed;
473 tp->t_ospeed = t->c_ospeed;
474 tp->t_cflag = cflag;
475
476 if (ospeed == 0)
477 bic(iobase + com_mcr, MCR_DTR | MCR_RTS);
478 else
479 bis(iobase + com_mcr, MCR_DTR | MCR_RTS);
480
481 outb(iobase + com_cfcr, CFCR_DLAB);
482 outb(iobase + com_dlbl, ospeed & 0xff);
483 outb(iobase + com_dlbh, ospeed >> 8);
484
485 switch (cflag & CSIZE) {
486 case CS5:
487 cfcr = CFCR_5BITS;
488 break;
489 case CS6:
490 cfcr = CFCR_6BITS;
491 break;
492 case CS7:
493 cfcr = CFCR_7BITS;
494 break;
495 case CS8:
496 cfcr = CFCR_8BITS;
497 break;
498 }
499 if (cflag & PARENB) {
500 cfcr |= CFCR_PENAB;
501 if ((cflag & PARODD) == 0)
502 cfcr |= CFCR_PEVEN;
503 }
504 if (cflag & CSTOPB)
505 cfcr |= CFCR_STOPB;
506 outb(iobase + com_cfcr, cfcr);
507
508 /* when not using CRTS_IFLOW, RTS follows DTR */
509 if ((cflag & CRTS_IFLOW) == 0) {
510 u_char mcr = inb(iobase + com_mcr);
511
512 if (mcr & MCR_DTR)
513 if ((mcr & MCR_RTS) == 0)
514 outb(iobase + com_mcr, mcr | MCR_RTS);
515 else
516 ;
517 else
518 if (mcr & MCR_RTS)
519 outb(iobase + com_mcr, mcr &~ MCR_RTS);
520 else
521 ;
522 }
523
524 return 0;
525 }
526
527 void
528 comstart(tp)
529 struct tty *tp;
530 {
531 int unit = COMUNIT(tp->t_dev);
532 struct com_softc *sc = comcd.cd_devs[unit];
533 u_short iobase = sc->sc_iobase;
534 int s;
535
536 s = spltty();
537 if (tp->t_state & (TS_TTSTOP | TS_BUSY))
538 goto out;
539 if (tp->t_cflag & CCTS_OFLOW && (inb(iobase + com_mcr) & MSR_CTS) == 0)
540 goto out;
541 if (tp->t_outq.c_cc <= tp->t_lowat) {
542 if (tp->t_state & TS_ASLEEP) {
543 tp->t_state &= ~TS_ASLEEP;
544 wakeup((caddr_t)&tp->t_outq);
545 }
546 selwakeup(&tp->t_wsel);
547 }
548 if (tp->t_outq.c_cc == 0)
549 goto out;
550 tp->t_state |= TS_BUSY;
551 if ((inb(iobase + com_lsr) & LSR_TXRDY) == 0)
552 goto out;
553 if (sc->sc_flags & COM_FIFO) {
554 u_char buffer[16], *cp = buffer;
555 int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
556 do {
557 outb(iobase + com_data, *cp++);
558 } while (--n);
559 } else
560 outb(iobase + com_data, getc(&tp->t_outq));
561 out:
562 splx(s);
563 }
564
565 /*
566 * Stop output on a line.
567 */
568 void
569 comstop(tp, flag)
570 struct tty *tp;
571 {
572 int s;
573
574 s = spltty();
575 if (tp->t_state & TS_BUSY) {
576 if ((tp->t_state & TS_TTSTOP) == 0)
577 tp->t_state |= TS_FLUSH;
578 }
579 splx(s);
580 }
581
582 static void
583 comeint(sc, stat)
584 struct com_softc *sc;
585 int stat;
586 {
587 u_short iobase = sc->sc_iobase;
588 struct tty *tp = com_tty[sc->sc_dev.dv_unit];
589 int c;
590
591 c = inb(iobase + com_data);
592 if ((tp->t_state & TS_ISOPEN) == 0)
593 return;
594 if (stat & (LSR_BI | LSR_FE))
595 c |= TTY_FE;
596 else if (stat & LSR_PE)
597 c |= TTY_PE;
598 else if (stat & LSR_OE) {
599 c |= TTY_PE; /* XXX ought to have its own define */
600 log(LOG_WARNING, "com%d: silo overflow\n", sc->sc_dev.dv_unit);
601 }
602 /* XXXX put in FIFO and process later */
603 (*linesw[tp->t_line].l_rint)(c, tp);
604 }
605
606 static void
607 commint(sc)
608 struct com_softc *sc;
609 {
610 u_short iobase = sc->sc_iobase;
611 struct tty *tp = com_tty[sc->sc_dev.dv_unit];
612 u_char stat;
613
614 stat = inb(iobase + com_msr);
615 if (stat & MSR_DDCD && (sc->sc_flags & COM_SOFTCAR) == 0) {
616 if (stat & MSR_DCD)
617 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
618 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
619 bic(iobase + com_mcr, MCR_DTR | MCR_RTS);
620 } else if (stat & MSR_DCTS && tp->t_state & TS_ISOPEN &&
621 tp->t_cflag & CRTSCTS) {
622 /* the line is up and we want to do rts/cts flow control */
623 if (stat & MSR_CTS) {
624 tp->t_state &=~ TS_TTSTOP;
625 ttstart(tp);
626 } else
627 tp->t_state |= TS_TTSTOP;
628 }
629 }
630
631 static int
632 comintr(arg)
633 void *arg;
634 {
635 struct com_softc *sc = arg;
636 u_short iobase = sc->sc_iobase;
637 struct tty *tp;
638 u_char code;
639
640 code = inb(iobase + com_iir);
641 if (code & IIR_NOPEND)
642 return 0;
643
644 for (;;) {
645 switch (code & IIR_IMASK) {
646 case IIR_RXRDY:
647 case IIR_RXTOUT:
648 tp = com_tty[sc->sc_dev.dv_unit];
649 /* XXXX put in FIFO and process later */
650 #define RCVBYTE() \
651 code = inb(iobase + com_data); \
652 if (tp->t_state & TS_ISOPEN) \
653 (*linesw[tp->t_line].l_rint)(code, tp)
654 RCVBYTE();
655 if (sc->sc_flags & COM_FIFO)
656 while (code = inb(iobase + com_lsr) & LSR_RCV_MASK) {
657 if (code == LSR_RXRDY) {
658 RCVBYTE();
659 } else
660 comeint(sc, code);
661 }
662 break;
663 case IIR_TXRDY:
664 tp = com_tty[sc->sc_dev.dv_unit];
665 tp->t_state &=~ (TS_BUSY | TS_FLUSH);
666 if (tp->t_line)
667 (*linesw[tp->t_line].l_start)(tp);
668 else
669 comstart(tp);
670 break;
671 case IIR_RLS:
672 comeint(sc, inb(iobase + com_lsr));
673 break;
674 default:
675 log(LOG_WARNING, "com%d: weird iir=0x%x\n",
676 sc->sc_dev.dv_unit, code);
677 /* fall through */
678 case IIR_MLSC:
679 commint(sc);
680 break;
681 }
682
683 code = inb(iobase + com_iir);
684 if (code & IIR_NOPEND)
685 return 1;
686 }
687 }
688
689 /* XXXXXXXXXXXXXXXX ---- gremlins below here ---- XXXXXXXXXXXXXXXX */
690
691 #if 0
692 /*
693 * Following are all routines needed for COM to act as console
694 */
695 #include "i386/i386/cons.h"
696
697 comcnprobe(cp)
698 struct consdev *cp;
699 {
700 /* XXXX */
701 if (!_comprobe(CONADDR))
702 return CN_DEAD;
703
704 /* locate the major number */
705 for (commajor = 0; commajor < nchrdev; commajor++)
706 if (cdevsw[commajor].d_open == comopen)
707 break;
708
709 /* initialize required fields */
710 cp->cn_dev = makedev(commajor, unit);
711 #ifdef COMCONSOLE
712 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
713 #else
714 cp->cn_pri = CN_NORMAL;
715 #endif
716 }
717
718 comcninit(cp)
719 struct consdev *cp;
720 {
721 int unit = COMUNIT(cp->cn_dev);
722
723 comconsole = CONADDR;
724 comconsinit = 0;
725 }
726
727 cominit(unit, rate)
728 int unit, rate;
729 {
730 int com;
731 int s;
732 short stat;
733
734 com = com_addr[unit];
735 s = splhigh();
736 outb(com+com_cfcr, CFCR_DLAB);
737 rate = COM_BAUDDIV(rate);
738 outb(com+com_data, rate & 0xFF);
739 outb(com+com_ier, rate >> 8);
740 outb(com+com_cfcr, CFCR_8BITS);
741 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
742 outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4);
743 stat = inb(com+com_iir);
744 splx(s);
745 }
746
747 comcngetc(dev)
748 {
749 com = com_addr[COMUNIT(dev)];
750 short stat;
751 int c, s;
752
753 s = splhigh();
754 while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
755 ;
756 c = inb(com+com_data);
757 stat = inb(com+com_iir);
758 splx(s);
759 return c;
760 }
761
762 /*
763 * Console kernel output character routine.
764 */
765 comcnputc(dev, c)
766 dev_t dev;
767 int c;
768 {
769 com = com_addr[COMUNIT(dev)];
770 int timo;
771 short stat;
772 int s = splhigh();
773
774 if (comconsinit == 0) {
775 (void) cominit(COMUNIT(dev), comdefaultrate);
776 comconsinit = 1;
777 }
778 /* wait for any pending transmission to finish */
779 timo = 50000;
780 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
781 ;
782 outb(com+com_data, c);
783 /* wait for this transmission to complete */
784 timo = 1500000;
785 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
786 ;
787 /* clear any interrupts generated by this transmission */
788 stat = inb(com+com_iir);
789 splx(s);
790 }
791 #endif
792