Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x68k / dev / com.c
blobc11c15d7795a8296d29c04162d8cf3229526e55d
1 /* $NetBSD: com.c,v 1.55 2009/01/18 02:40:05 isaki Exp $ */
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 /*-
33 * Copyright (c) 1991 The Regents of the University of California.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
60 * @(#)com.c 7.5 (Berkeley) 5/16/91
64 * COM driver, based on HP dca driver
65 * uses National Semiconductor NS16450/NS16550AF UART
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: com.c,v 1.55 2009/01/18 02:40:05 isaki Exp $");
71 #include "opt_ddb.h"
72 #include "opt_kgdb.h"
73 #include "opt_com.h"
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/ioctl.h>
78 #include <sys/select.h>
79 #include <sys/tty.h>
80 #include <sys/proc.h>
81 #include <sys/conf.h>
82 #include <sys/file.h>
83 #include <sys/uio.h>
84 #include <sys/kernel.h>
85 #include <sys/syslog.h>
86 #include <sys/types.h>
87 #include <sys/device.h>
88 #include <sys/kauth.h>
90 #ifdef KGDB
91 #include <machine/remote-sl.h>
92 #include <sys/kgdb.h>
93 #endif
95 #include <machine/cpu.h>
96 #if 0
97 #include <machine/pio.h>
98 #endif
100 #include <x68k/x68k/iodevice.h>
101 #if 0
102 #include <dev/isa/isavar.h>
103 #endif
104 #include <x68k/dev/comreg.h>
105 #include <dev/ic/ns16550reg.h>
106 #ifdef COM_HAYESP
107 #include <dev/ic/hayespreg.h>
108 #endif
109 #define com_lcr com_cfcr
111 #define COM_IBUFSIZE (2 * 512)
112 #define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
114 struct com_softc {
115 device_t sc_dev;
116 void *sc_ih;
117 struct tty *sc_tty;
119 struct callout sc_diag_ch;
121 int sc_overflows;
122 int sc_floods;
123 int sc_errors;
125 int sc_halt;
127 int sc_iobase;
128 #ifdef COM_HAYESP
129 int sc_hayespbase;
130 #endif
131 u_char sc_hwflags;
132 #define COM_HW_NOIEN 0x01
133 #define COM_HW_FIFO 0x02
134 #define COM_HW_HAYESP 0x04
135 #define COM_HW_CONSOLE 0x40
136 u_char sc_swflags;
137 #define COM_SW_SOFTCAR 0x01
138 #define COM_SW_CLOCAL 0x02
139 #define COM_SW_CRTSCTS 0x04
140 #define COM_SW_MDMBUF 0x08
141 u_char sc_msr, sc_mcr, sc_lcr, sc_ier;
142 u_char sc_dtr;
144 u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
145 u_char sc_ibufs[2][COM_IBUFSIZE];
148 struct callout com_poll_ch;
150 int comprobe(device_t, cfdata_t, void *);
151 void comattach(device_t, device_t, void *);
153 static int comprobe1(int);
154 static void comdiag(void *);
155 int comintr(void *);
156 static void compollin(void *);
157 static int comparam(struct tty *, struct termios *);
158 static void comstart(struct tty *);
159 static void cominit(int);
160 static int comspeed(long);
162 static u_char tiocm_xxx2mcr(int);
164 CFATTACH_DECL_NEW(xcom, sizeof(struct com_softc),
165 comprobe, comattach, NULL, NULL);
167 extern struct cfdriver xcom_cd;
169 int com_attached;
171 dev_type_open(comopen);
172 dev_type_close(comclose);
173 dev_type_read(comread);
174 dev_type_write(comwrite);
175 dev_type_ioctl(comioctl);
176 dev_type_stop(comstop);
177 dev_type_tty(comtty);
178 dev_type_poll(compoll);
180 const struct cdevsw xcom_cdevsw = {
181 comopen, comclose, comread, comwrite, comioctl,
182 comstop, comtty, compoll, nommap, ttykqfilter, D_TTY
185 #define outb(addr, val) *(u_char *)(addr) = (val)
186 #define inb(addr) *(u_char *)(addr)
187 #define pio(addr,regno) ((addr)+1+(regno)*2)
189 #ifdef COMCONSOLE
190 int comdefaultrate = CONSPEED;
191 int comconsole = COMCONSOLE;
192 #else
193 int comdefaultrate = TTYDEF_SPEED;
194 int comconsole = -1;
195 #endif
196 int comconsinit;
197 int comsopen = 0;
198 int comevents = 0;
200 #define COMUNIT(x) (minor(x) & 0x7F)
201 #define COMDIALOUT(x) (minor(x) & 0x80)
203 static int
204 comspeed(long speed)
206 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
208 int x, err;
210 if (speed == 0)
211 return 0;
212 if (speed < 0)
213 return -1;
214 x = divrnd((COM_FREQ / 16), speed);
215 if (x <= 0)
216 return -1;
217 err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000;
218 if (err < 0)
219 err = -err;
220 if (err > COM_TOLERANCE)
221 return -1;
222 return x;
224 #undef divrnd
227 static int
228 comprobe1(int iobase)
231 if (badbaddr((void *)pio(iobase, com_lcr)))
232 return 0;
233 /* force access to id reg */
234 outb(pio(iobase , com_lcr), 0);
235 outb(pio(iobase , com_iir), 0);
236 if (inb(pio(iobase , com_iir)) & 0x38)
237 return 0;
239 return 1;
242 #ifdef COM_HAYESP
244 comprobeHAYESP(int iobase, struct com_softc *sc)
246 char val, dips;
247 int combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
250 * Hayes ESP cards have two iobases. One is for compatibility with
251 * 16550 serial chips, and at the same ISA PC base addresses. The
252 * other is for ESP-specific enhanced features, and lies at a
253 * different addressing range entirely (0x140, 0x180, 0x280, or 0x300).
256 /* Test for ESP signature */
257 if ((inb(iobase) & 0xf3) == 0)
258 return 0;
261 * ESP is present at ESP enhanced base address; unknown com port
264 /* Get the dip-switch configurations */
265 outb(iobase + HAYESP_CMD1, HAYESP_GETDIPS);
266 dips = inb(iobase + HAYESP_STATUS1);
268 /* Determine which com port this ESP card services: bits 0,1 of */
269 /* dips is the port # (0-3); combaselist[val] is the com_iobase */
270 if (sc->sc_iobase != combaselist[dips & 0x03])
271 return 0;
273 printf(": ESP");
275 /* Check ESP Self Test bits. */
276 /* Check for ESP version 2.0: bits 4,5,6 == 010 */
277 outb(iobase + HAYESP_CMD1, HAYESP_GETTEST);
278 val = inb(iobase + HAYESP_STATUS1); /* Clear reg 1 */
279 val = inb(iobase + HAYESP_STATUS2);
280 if ((val & 0x70) < 0x20) {
281 printf("-old (%o)", val & 0x70);
282 /* we do not support the necessary features */
283 return 0;
286 /* Check for ability to emulate 16550: bit 8 == 1 */
287 if ((dips & 0x80) == 0) {
288 printf(" slave");
289 /* XXX Does slave really mean no 16550 support?? */
290 return 0;
294 * If we made it this far, we are a full-featured ESP v2.0 (or
295 * better), at the correct com port address.
298 SET(sc->sc_hwflags, COM_HW_HAYESP);
299 printf(", 1024 byte fifo\n");
300 return 1;
302 #endif
305 comprobe(device_t parent, cfdata_t cfp, void *aux)
307 int iobase = (int)&IODEVbase->psx16550;
309 if (strcmp(aux, "com") || com_attached)
310 return 0;
312 if (!comprobe1(iobase))
313 return 0;
315 return 1;
318 void
319 comattach(device_t parent, device_t dev, void *aux)
321 struct com_softc *sc = device_private(dev);
322 int iobase = (int)&IODEVbase->psx16550;
323 #ifdef COM_HAYESP
324 int hayesp_ports[] = { 0x140, 0x180, 0x280, 0x300, 0 };
325 int *hayespp;
326 #endif
328 sc->sc_dev = dev;
329 com_attached = 1;
331 callout_init(&sc->sc_diag_ch, 0);
332 callout_init(&com_poll_ch, 0);
334 sc->sc_iobase = iobase;
335 sc->sc_hwflags = 0;
336 sc->sc_swflags = 0;
337 aprint_normal(": iobase %x", sc->sc_iobase);
339 #ifdef COM_HAYESP
340 /* Look for a Hayes ESP board. */
341 for (hayespp = hayesp_ports; *hayespp != 0; hayespp++)
342 if (comprobeHAYESP(*hayespp, sc)) {
343 sc->sc_hayespbase = *hayespp;
344 break;
346 /* No ESP; look for other things. */
347 if (*hayespp == 0) {
348 #endif
350 /* look for a NS 16550AF UART with FIFOs */
351 outb(pio(iobase , com_fifo),
352 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
353 DELAY(100);
354 if (ISSET(inb(pio(iobase , com_iir)), IIR_FIFO_MASK) == IIR_FIFO_MASK)
355 if (ISSET(inb(pio(iobase , com_fifo)), FIFO_TRIGGER_14) == FIFO_TRIGGER_14) {
356 SET(sc->sc_hwflags, COM_HW_FIFO);
357 aprint_normal(": ns16550a, working fifo\n");
358 } else
359 aprint_normal(": ns16550, broken fifo\n");
360 else
361 aprint_normal(": ns8250 or ns16450, no fifo\n");
362 outb(pio(iobase , com_fifo), 0);
363 #ifdef COM_HAYESP
365 #endif
367 /* disable interrupts */
368 outb(pio(iobase , com_ier), 0);
369 outb(pio(iobase , com_mcr), 0);
371 if (sc->sc_iobase == CONADDR) {
373 * Need to reset baud rate, etc. of next print so reset
374 * comconsinit. Also make sure console is always "hardwired".
376 comconsinit = 0;
377 SET(sc->sc_hwflags, COM_HW_CONSOLE);
378 SET(sc->sc_swflags, COM_SW_SOFTCAR);
383 comopen(dev_t dev, int flag, int mode, struct lwp *l)
385 struct com_softc *sc;
386 int iobase;
387 struct tty *tp;
388 int s;
389 int error = 0;
391 sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
392 if (!sc)
393 return ENXIO;
395 if (!sc->sc_tty) {
396 tp = sc->sc_tty = ttymalloc();
397 tty_attach(tp);
398 } else
399 tp = sc->sc_tty;
401 tp->t_oproc = comstart;
402 tp->t_param = comparam;
403 tp->t_dev = dev;
405 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
406 return (EBUSY);
408 s = spltty();
410 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
411 ttychars(tp);
412 tp->t_iflag = TTYDEF_IFLAG;
413 tp->t_oflag = TTYDEF_OFLAG;
414 tp->t_cflag = TTYDEF_CFLAG;
415 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
416 SET(tp->t_cflag, CLOCAL);
417 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
418 SET(tp->t_cflag, CRTSCTS);
419 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
420 SET(tp->t_cflag, MDMBUF);
421 tp->t_lflag = TTYDEF_LFLAG;
422 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
424 comparam(tp, &tp->t_termios);
425 ttsetwater(tp);
427 if (comsopen++ == 0)
428 callout_reset(&com_poll_ch, 1, compollin, NULL);
430 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
431 sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
432 sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
434 iobase = sc->sc_iobase;
435 #ifdef COM_HAYESP
436 /* Setup the ESP board */
437 if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) {
438 int hayespbase = sc->sc_hayespbase;
440 outb(iobase + com_fifo,
441 FIFO_DMA_MODE|FIFO_ENABLE|
442 FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_8);
444 /* Set 16550 compatibility mode */
445 outb(hayespbase + HAYESP_CMD1, HAYESP_SETMODE);
446 outb(hayespbase + HAYESP_CMD2,
447 HAYESP_MODE_FIFO|HAYESP_MODE_RTS|
448 HAYESP_MODE_SCALE);
450 /* Set RTS/CTS flow control */
451 outb(hayespbase + HAYESP_CMD1, HAYESP_SETFLOWTYPE);
452 outb(hayespbase + HAYESP_CMD2, HAYESP_FLOW_RTS);
453 outb(hayespbase + HAYESP_CMD2, HAYESP_FLOW_CTS);
455 /* Set flow control levels */
456 outb(hayespbase + HAYESP_CMD1, HAYESP_SETRXFLOW);
457 outb(hayespbase + HAYESP_CMD2,
458 HAYESP_HIBYTE(HAYESP_RXHIWMARK));
459 outb(hayespbase + HAYESP_CMD2,
460 HAYESP_LOBYTE(HAYESP_RXHIWMARK));
461 outb(hayespbase + HAYESP_CMD2,
462 HAYESP_HIBYTE(HAYESP_RXLOWMARK));
463 outb(hayespbase + HAYESP_CMD2,
464 HAYESP_LOBYTE(HAYESP_RXLOWMARK));
465 } else
466 #endif
467 if (ISSET(sc->sc_hwflags, COM_HW_FIFO))
468 /* Set the FIFO threshold based on the receive speed. */
469 outb(pio(iobase , com_fifo),
470 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
471 (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
472 /* flush any pending I/O */
473 while (ISSET(inb(pio(iobase , com_lsr)), LSR_RXRDY))
474 (void) inb(pio(iobase , com_data));
475 /* you turn me on, baby */
476 sc->sc_mcr = MCR_DTR | MCR_RTS;
477 if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN))
478 SET(sc->sc_mcr, MCR_IENABLE | MCR_DRS); /* */
479 outb(pio(iobase , com_mcr), sc->sc_mcr);
480 sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC;
481 outb(pio(iobase , com_ier), sc->sc_ier);
483 sc->sc_msr = inb(pio(iobase , com_msr));
484 if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) ||
485 ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF))
486 SET(tp->t_state, TS_CARR_ON);
487 else
488 CLR(tp->t_state, TS_CARR_ON);
490 splx(s);
492 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
494 if (!error)
495 error = (*tp->t_linesw->l_open)(dev, tp);
497 /* XXX cleanup on error */
499 return error;
503 comclose(dev_t dev, int flag, int mode, struct lwp *l)
505 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
506 struct tty *tp = sc->sc_tty;
507 int iobase = sc->sc_iobase;
508 int s;
510 /* XXX This is for cons.c. */
511 if (!ISSET(tp->t_state, TS_ISOPEN))
512 return 0;
514 (*tp->t_linesw->l_close)(tp, flag);
515 s = spltty();
516 CLR(sc->sc_lcr, LCR_SBREAK);
517 outb(pio(iobase , com_lcr), sc->sc_lcr);
518 outb(pio(iobase , com_ier), 0);
519 if (ISSET(tp->t_cflag, HUPCL) &&
520 !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) {
521 /* XXX perhaps only clear DTR */
522 outb(pio(iobase , com_mcr), 0);
524 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
525 if (--comsopen == 0)
526 callout_stop(&com_poll_ch);
527 splx(s);
528 ttyclose(tp);
529 #ifdef notyet /* XXXX */
530 if (unit != comconsole) {
531 ttyfree(tp);
532 sc->sc_tty = 0;
534 #endif
535 return 0;
539 comread(dev_t dev, struct uio *uio, int flag)
541 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
542 struct tty *tp = sc->sc_tty;
544 return ((*tp->t_linesw->l_read)(tp, uio, flag));
548 comwrite(dev_t dev, struct uio *uio, int flag)
550 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
551 struct tty *tp = sc->sc_tty;
553 return ((*tp->t_linesw->l_write)(tp, uio, flag));
557 compoll(dev_t dev, int events, struct lwp *l)
559 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
560 struct tty *tp = sc->sc_tty;
562 return ((*tp->t_linesw->l_poll)(tp, events, l));
565 struct tty *
566 comtty(dev_t dev)
568 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
569 struct tty *tp = sc->sc_tty;
571 return (tp);
574 static u_char
575 tiocm_xxx2mcr(int data)
577 u_char m = 0;
579 if (ISSET(data, TIOCM_DTR))
580 SET(m, MCR_DTR);
581 if (ISSET(data, TIOCM_RTS))
582 SET(m, MCR_RTS);
583 return m;
587 comioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
589 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(dev));
590 struct tty *tp = sc->sc_tty;
591 int iobase = sc->sc_iobase;
592 int error;
594 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
595 if (error != EPASSTHROUGH)
596 return error;
598 error = ttioctl(tp, cmd, data, flag, l);
599 if (error != EPASSTHROUGH)
600 return error;
602 switch (cmd) {
603 case TIOCSBRK:
604 SET(sc->sc_lcr, LCR_SBREAK);
605 outb(pio(iobase , com_lcr), sc->sc_lcr);
606 break;
607 case TIOCCBRK:
608 CLR(sc->sc_lcr, LCR_SBREAK);
609 outb(pio(iobase , com_lcr), sc->sc_lcr);
610 break;
611 case TIOCSDTR:
612 SET(sc->sc_mcr, sc->sc_dtr);
613 outb(pio(iobase , com_mcr), sc->sc_mcr);
614 break;
615 case TIOCCDTR:
616 CLR(sc->sc_mcr, sc->sc_dtr);
617 outb(pio(iobase , com_mcr), sc->sc_mcr);
618 break;
619 case TIOCMSET:
620 CLR(sc->sc_mcr, MCR_DTR | MCR_RTS);
621 case TIOCMBIS:
622 SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
623 outb(pio(iobase , com_mcr), sc->sc_mcr);
624 break;
625 case TIOCMBIC:
626 CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data));
627 outb(pio(iobase , com_mcr), sc->sc_mcr);
628 break;
629 case TIOCMGET: {
630 u_char m;
631 int bits = 0;
633 m = sc->sc_mcr;
634 if (ISSET(m, MCR_DTR))
635 SET(bits, TIOCM_DTR);
636 if (ISSET(m, MCR_RTS))
637 SET(bits, TIOCM_RTS);
638 m = sc->sc_msr;
639 if (ISSET(m, MSR_DCD))
640 SET(bits, TIOCM_CD);
641 if (ISSET(m, MSR_CTS))
642 SET(bits, TIOCM_CTS);
643 if (ISSET(m, MSR_DSR))
644 SET(bits, TIOCM_DSR);
645 if (ISSET(m, MSR_RI | MSR_TERI))
646 SET(bits, TIOCM_RI);
647 if (inb(pio(iobase , com_ier)))
648 SET(bits, TIOCM_LE);
649 *(int *)data = bits;
650 break;
652 case TIOCGFLAGS: {
653 int driverbits, userbits = 0;
655 driverbits = sc->sc_swflags;
656 if (ISSET(driverbits, COM_SW_SOFTCAR))
657 SET(userbits, TIOCFLAG_SOFTCAR);
658 if (ISSET(driverbits, COM_SW_CLOCAL))
659 SET(userbits, TIOCFLAG_CLOCAL);
660 if (ISSET(driverbits, COM_SW_CRTSCTS))
661 SET(userbits, TIOCFLAG_CRTSCTS);
662 if (ISSET(driverbits, COM_SW_MDMBUF))
663 SET(userbits, TIOCFLAG_MDMBUF);
665 *(int *)data = userbits;
666 break;
668 case TIOCSFLAGS: {
669 int userbits, driverbits = 0;
671 error = kauth_authorize_device_tty(l->l_cred,
672 KAUTH_DEVICE_TTY_PRIVSET, tp);
673 if (error != 0)
674 return(EPERM);
676 userbits = *(int *)data;
677 if (ISSET(userbits, TIOCFLAG_SOFTCAR) ||
678 ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
679 SET(driverbits, COM_SW_SOFTCAR);
680 if (ISSET(userbits, TIOCFLAG_CLOCAL))
681 SET(driverbits, COM_SW_CLOCAL);
682 if (ISSET(userbits, TIOCFLAG_CRTSCTS))
683 SET(driverbits, COM_SW_CRTSCTS);
684 if (ISSET(userbits, TIOCFLAG_MDMBUF))
685 SET(driverbits, COM_SW_MDMBUF);
687 sc->sc_swflags = driverbits;
688 break;
690 default:
691 return EPASSTHROUGH;
694 return 0;
697 static int
698 comparam(struct tty *tp, struct termios *t)
700 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(tp->t_dev));
701 int iobase = sc->sc_iobase;
702 int ospeed = comspeed(t->c_ospeed);
703 u_char lcr;
704 tcflag_t oldcflag;
705 int s;
707 /* check requested parameters */
708 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
709 return EINVAL;
711 lcr = ISSET(sc->sc_lcr, LCR_SBREAK);
713 switch (ISSET(t->c_cflag, CSIZE)) {
714 case CS5:
715 SET(lcr, LCR_5BITS);
716 break;
717 case CS6:
718 SET(lcr, LCR_6BITS);
719 break;
720 case CS7:
721 SET(lcr, LCR_7BITS);
722 break;
723 case CS8:
724 SET(lcr, LCR_8BITS);
725 break;
727 if (ISSET(t->c_cflag, PARENB)) {
728 SET(lcr, LCR_PENAB);
729 if (!ISSET(t->c_cflag, PARODD))
730 SET(lcr, LCR_PEVEN);
732 if (ISSET(t->c_cflag, CSTOPB))
733 SET(lcr, LCR_STOPB);
735 sc->sc_lcr = lcr;
737 s = spltty();
739 if (ospeed == 0) {
740 CLR(sc->sc_mcr, MCR_DTR);
741 outb(pio(iobase , com_mcr), sc->sc_mcr);
745 * Set the FIFO threshold based on the receive speed, if we are
746 * changing it.
748 if (tp->t_ispeed != t->c_ispeed) {
749 if (ISSET(sc->sc_hwflags, COM_HW_FIFO))
750 outb(pio(iobase , com_fifo),
751 FIFO_ENABLE |
752 (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
755 if (ospeed != 0) {
756 outb(pio(iobase , com_lcr), lcr | LCR_DLAB);
757 outb(pio(iobase , com_dlbl), ospeed);
758 outb(pio(iobase , com_dlbh), ospeed >> 8);
759 outb(pio(iobase , com_lcr), lcr);
760 SET(sc->sc_mcr, MCR_DTR);
761 outb(pio(iobase , com_mcr), sc->sc_mcr);
762 } else
763 outb(pio(iobase , com_lcr), lcr);
765 /* When not using CRTSCTS, RTS follows DTR. */
766 if (!ISSET(t->c_cflag, CRTSCTS)) {
767 if (ISSET(sc->sc_mcr, MCR_DTR)) {
768 if (!ISSET(sc->sc_mcr, MCR_RTS)) {
769 SET(sc->sc_mcr, MCR_RTS);
770 outb(pio(iobase , com_mcr), sc->sc_mcr);
772 } else {
773 if (ISSET(sc->sc_mcr, MCR_RTS)) {
774 CLR(sc->sc_mcr, MCR_RTS);
775 outb(pio(iobase , com_mcr), sc->sc_mcr);
778 sc->sc_dtr = MCR_DTR | MCR_RTS;
779 } else
780 sc->sc_dtr = MCR_DTR;
782 /* and copy to tty */
783 tp->t_ispeed = t->c_ispeed;
784 tp->t_ospeed = t->c_ospeed;
785 oldcflag = tp->t_cflag;
786 tp->t_cflag = t->c_cflag;
789 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
790 * stop the device.
792 if (!ISSET(sc->sc_msr, MSR_DCD) &&
793 !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
794 ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) &&
795 (*tp->t_linesw->l_modem)(tp, 0) == 0) {
796 CLR(sc->sc_mcr, sc->sc_dtr);
797 outb(pio(iobase , com_mcr), sc->sc_mcr);
800 /* Just to be sure... */
801 splx(s);
802 comstart(tp);
803 return 0;
806 int comdebug = 0;
808 static void
809 comstart(struct tty *tp)
811 struct com_softc *sc = device_lookup_private(&xcom_cd, COMUNIT(tp->t_dev));
812 int iobase = sc->sc_iobase;
813 int s;
815 #ifdef DDB
816 if (comdebug)
817 Debugger();
818 #endif
819 s = spltty();
820 if (ISSET(tp->t_state, TS_BUSY))
821 goto out;
822 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) ||
823 sc->sc_halt > 0)
824 goto stopped;
825 if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS))
826 goto stopped;
827 if (!ttypull(tp))
828 goto stopped;
829 SET(tp->t_state, TS_BUSY);
831 if (!ISSET(sc->sc_ier, IER_ETXRDY)) {
832 SET(sc->sc_ier, IER_ETXRDY);
833 outb(pio(iobase, com_ier), sc->sc_ier);
835 #ifdef COM_HAYESP
836 if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) {
837 u_char buffer[1024], *cp = buffer;
838 int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
840 outb(iobase + com_data, *cp++);
841 while (--n);
843 else
844 #endif
845 if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
846 u_char buffer[16], *cp = buffer;
847 int n = q_to_b(&tp->t_outq, cp, sizeof buffer);
848 do {
849 outb(pio(iobase , com_data), *cp++);
850 } while (--n);
851 } else
852 outb(pio(iobase , com_data), getc(&tp->t_outq));
853 out:
854 splx(s);
855 return;
856 stopped:
857 if (ISSET(sc->sc_ier, IER_ETXRDY)) {
858 CLR(sc->sc_ier, IER_ETXRDY);
859 outb(pio(iobase, com_ier), sc->sc_ier);
861 splx(s);
865 * Stop output on a line.
867 void
868 comstop(struct tty *tp, int flag)
870 int s;
872 s = spltty();
873 if (ISSET(tp->t_state, TS_BUSY))
874 if (!ISSET(tp->t_state, TS_TTSTOP))
875 SET(tp->t_state, TS_FLUSH);
876 splx(s);
879 static void
880 comdiag(void *arg)
882 struct com_softc *sc = arg;
883 int overflows, floods;
884 int s;
886 s = spltty();
887 sc->sc_errors = 0;
888 overflows = sc->sc_overflows;
889 sc->sc_overflows = 0;
890 floods = sc->sc_floods;
891 sc->sc_floods = 0;
892 splx(s);
894 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
895 device_xname(sc->sc_dev),
896 overflows, overflows == 1 ? "" : "s",
897 floods, floods == 1 ? "" : "s");
900 static void
901 compollin(void *arg)
903 int unit;
904 struct com_softc *sc;
905 struct tty *tp;
906 u_char *ibufp;
907 u_char *ibufend;
908 int c;
909 int s;
910 static int lsrmap[8] = {
911 0, TTY_PE,
912 TTY_FE, TTY_PE|TTY_FE,
913 TTY_FE, TTY_PE|TTY_FE,
914 TTY_FE, TTY_PE|TTY_FE
917 s = spltty();
918 if (comevents == 0) {
919 splx(s);
920 goto out;
922 comevents = 0;
923 splx(s);
925 for (unit = 0; unit < xcom_cd.cd_ndevs; unit++) {
926 sc = device_lookup_private(&xcom_cd, unit);
927 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
928 continue;
930 tp = sc->sc_tty;
932 s = spltty();
934 ibufp = sc->sc_ibuf;
935 ibufend = sc->sc_ibufp;
937 if (ibufp == ibufend) {
938 splx(s);
939 continue;
942 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
943 sc->sc_ibufs[1] : sc->sc_ibufs[0];
944 sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER;
945 sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE;
947 if (tp == 0 || !ISSET(tp->t_state, TS_ISOPEN)) {
948 splx(s);
949 continue;
952 if (ISSET(tp->t_cflag, CRTSCTS) &&
953 !ISSET(sc->sc_mcr, MCR_RTS)) {
954 /* XXX */
955 SET(sc->sc_mcr, MCR_RTS);
956 outb(pio(sc->sc_iobase , com_mcr), sc->sc_mcr);
959 splx(s);
961 while (ibufp < ibufend) {
962 c = *ibufp++;
963 if (*ibufp & LSR_OE) {
964 sc->sc_overflows++;
965 if (sc->sc_errors++ == 0)
966 callout_reset(&sc->sc_diag_ch, 60 * hz,
967 comdiag, sc);
969 /* This is ugly, but fast. */
970 c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2];
971 (*tp->t_linesw->l_rint)(c, tp);
975 out:
976 callout_reset(&com_poll_ch, 1, compollin, NULL);
980 comintr(void *arg)
982 struct com_softc *sc = device_lookup_private(&xcom_cd, *((int *)arg));
983 int iobase = sc->sc_iobase;
984 struct tty *tp;
985 u_char lsr, data, msr, delta;
986 int iir;
988 #if 1
989 if ((iir = ISSET(inb(pio(iobase , com_iir)), IIR_NOPEND)))
990 return (0);
991 #endif
993 tp = sc->sc_tty;
995 for (;;) {
996 lsr = inb(pio(iobase , com_lsr));
998 if (ISSET(lsr, LSR_RXRDY)) {
999 u_char *p = sc->sc_ibufp;
1001 comevents = 1;
1002 do {
1003 data = inb(pio(iobase, com_data));
1004 if (ISSET(lsr, LSR_BI)) {
1005 #ifdef DDB
1006 if (iobase == CONADDR) {
1007 Debugger();
1008 goto next;
1010 #endif
1012 if (p >= sc->sc_ibufend) {
1013 sc->sc_floods++;
1014 if (sc->sc_errors++ == 0)
1015 callout_reset(&sc->sc_diag_ch,
1016 60 * hz, comdiag, sc);
1017 } else {
1018 *p++ = data;
1019 *p++ = lsr;
1020 if (p == sc->sc_ibufhigh &&
1021 ISSET(tp->t_cflag, CRTSCTS)) {
1022 /* XXX */
1023 CLR(sc->sc_mcr, MCR_RTS);
1024 outb(pio(iobase , com_mcr),
1025 sc->sc_mcr);
1028 #ifdef DDB
1029 next:
1030 #endif
1031 lsr = inb(pio(iobase , com_lsr));
1032 } while (ISSET(lsr, LSR_RXRDY));
1034 sc->sc_ibufp = p;
1036 #ifdef COMDEBUG
1037 else if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE))
1038 printf("weird lsr %02x\n", lsr);
1039 #endif
1041 msr = inb(pio(iobase , com_msr));
1043 if (msr != sc->sc_msr) {
1044 delta = msr ^ sc->sc_msr;
1045 sc->sc_msr = msr;
1046 if (ISSET(delta, MSR_DCD) &&
1047 !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) &&
1048 (*tp->t_linesw->l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) {
1049 CLR(sc->sc_mcr, sc->sc_dtr);
1050 outb(pio(iobase , com_mcr), sc->sc_mcr);
1052 if (ISSET(delta & msr, MSR_CTS) &&
1053 ISSET(tp->t_cflag, CRTSCTS)) {
1054 /* the line is up and we want to do rts/cts flow control */
1055 (*tp->t_linesw->l_start)(tp);
1059 if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) {
1060 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
1061 if (sc->sc_halt > 0)
1062 cv_broadcast(&tp->t_outcv);
1063 (*tp->t_linesw->l_start)(tp);
1066 if ((iir = ISSET(inb(pio(iobase , com_iir)), IIR_NOPEND)))
1067 return (1);
1072 * Following are all routines needed for COM to act as console
1074 #include <dev/cons.h>
1076 void comcnprobe(struct consdev *);
1077 void comcninit(struct consdev *);
1078 int comcngetc(dev_t);
1079 void comcnputc(dev_t, int);
1080 void comcnpollc(dev_t, int);
1082 void
1083 comcnprobe(struct consdev *cp)
1085 int maj;
1087 if (!comprobe1(CONADDR)) {
1088 cp->cn_pri = CN_DEAD;
1089 return;
1092 /* locate the major number */
1093 maj = cdevsw_lookup_major(&xcom_cdevsw);
1095 /* initialize required fields */
1096 cp->cn_dev = makedev(maj, CONUNIT);
1097 #ifdef COMCONSOLE
1098 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
1099 #else
1100 cp->cn_pri = CN_NORMAL;
1101 #endif
1104 void
1105 comcninit(struct consdev *cp)
1108 cominit(comdefaultrate);
1109 comconsole = CONUNIT;
1110 comconsinit = 0;
1113 static void
1114 cominit(int rate)
1116 int s;
1117 int iobase = CONADDR;
1118 u_char stat;
1120 s = splhigh();
1121 outb(pio(iobase , com_lcr), LCR_DLAB);
1122 rate = comspeed(comdefaultrate);
1123 outb(pio(iobase , com_dlbl), rate);
1124 outb(pio(iobase , com_dlbh), rate >> 8);
1125 outb(pio(iobase , com_lcr), LCR_8BITS);
1126 outb(pio(iobase , com_ier), IER_ERXRDY | IER_ETXRDY);
1127 outb(pio(iobase , com_fifo), FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4);
1128 stat = inb(pio(iobase , com_iir));
1129 splx(s);
1133 comcngetc(dev_t dev)
1135 int s;
1136 int iobase = CONADDR;
1137 u_char stat, c;
1139 s = splhigh();
1140 while (!ISSET(stat = inb(pio(iobase , com_lsr)), LSR_RXRDY))
1142 c = inb(pio(iobase , com_data));
1143 stat = inb(pio(iobase , com_iir));
1144 splx(s);
1145 return c;
1149 * Console kernel output character routine.
1151 void
1152 comcnputc(dev_t dev, int c)
1154 int s;
1155 int iobase = CONADDR;
1156 u_char stat;
1157 int timo;
1159 s = splhigh();
1161 #ifdef KGDB
1162 if (dev != kgdb_dev)
1163 #endif
1164 if (comconsinit == 0) {
1165 (void) cominit(comdefaultrate);
1166 comconsinit = 1;
1169 /* wait for any pending transmission to finish */
1170 timo = 50000;
1171 while (!ISSET(stat = inb(pio(iobase , com_lsr)), LSR_TXRDY) && --timo)
1173 outb(pio(iobase , com_data), c);
1175 /* wait for this transmission to complete */
1176 timo = 1500000;
1177 while (!ISSET(stat = inb(pio(iobase , com_lsr)), LSR_TXRDY) && --timo)
1180 /* clear any interrupts generated by this transmission */
1181 stat = inb(pio(iobase , com_iir));
1182 splx(s);
1185 void
1186 comcnpollc(dev_t dev, int on)