1 /* $NetBSD: com.c,v 1.55 2009/01/18 02:40:05 isaki Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
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
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.
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
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
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 $");
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/ioctl.h>
78 #include <sys/select.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>
91 #include <machine/remote-sl.h>
95 #include <machine/cpu.h>
97 #include <machine/pio.h>
100 #include <x68k/x68k/iodevice.h>
102 #include <dev/isa/isavar.h>
104 #include <x68k/dev/comreg.h>
105 #include <dev/ic/ns16550reg.h>
107 #include <dev/ic/hayespreg.h>
109 #define com_lcr com_cfcr
111 #define COM_IBUFSIZE (2 * 512)
112 #define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4)
119 struct callout sc_diag_ch
;
132 #define COM_HW_NOIEN 0x01
133 #define COM_HW_FIFO 0x02
134 #define COM_HW_HAYESP 0x04
135 #define COM_HW_CONSOLE 0x40
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
;
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 *);
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
;
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)
190 int comdefaultrate
= CONSPEED
;
191 int comconsole
= COMCONSOLE
;
193 int comdefaultrate
= TTYDEF_SPEED
;
200 #define COMUNIT(x) (minor(x) & 0x7F)
201 #define COMDIALOUT(x) (minor(x) & 0x80)
206 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
214 x
= divrnd((COM_FREQ
/ 16), speed
);
217 err
= divrnd((COM_FREQ
/ 16) * 1000, speed
* x
) - 1000;
220 if (err
> COM_TOLERANCE
)
228 comprobe1(int iobase
)
231 if (badbaddr((void *)pio(iobase
, com_lcr
)))
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)
244 comprobeHAYESP(int iobase
, struct com_softc
*sc
)
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)
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])
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 */
286 /* Check for ability to emulate 16550: bit 8 == 1 */
287 if ((dips
& 0x80) == 0) {
289 /* XXX Does slave really mean no 16550 support?? */
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");
305 comprobe(device_t parent
, cfdata_t cfp
, void *aux
)
307 int iobase
= (int)&IODEVbase
->psx16550
;
309 if (strcmp(aux
, "com") || com_attached
)
312 if (!comprobe1(iobase
))
319 comattach(device_t parent
, device_t dev
, void *aux
)
321 struct com_softc
*sc
= device_private(dev
);
322 int iobase
= (int)&IODEVbase
->psx16550
;
324 int hayesp_ports
[] = { 0x140, 0x180, 0x280, 0x300, 0 };
331 callout_init(&sc
->sc_diag_ch
, 0);
332 callout_init(&com_poll_ch
, 0);
334 sc
->sc_iobase
= iobase
;
337 aprint_normal(": iobase %x", sc
->sc_iobase
);
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
;
346 /* No ESP; look for other things. */
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
);
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");
359 aprint_normal(": ns16550, broken fifo\n");
361 aprint_normal(": ns8250 or ns16450, no fifo\n");
362 outb(pio(iobase
, com_fifo
), 0);
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".
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
;
391 sc
= device_lookup_private(&xcom_cd
, COMUNIT(dev
));
396 tp
= sc
->sc_tty
= ttymalloc();
401 tp
->t_oproc
= comstart
;
402 tp
->t_param
= comparam
;
405 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
410 if (!ISSET(tp
->t_state
, TS_ISOPEN
) && tp
->t_wopen
== 0) {
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
);
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
;
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
|
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
));
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
);
488 CLR(tp
->t_state
, TS_CARR_ON
);
492 error
= ttyopen(tp
, COMDIALOUT(dev
), ISSET(flag
, O_NONBLOCK
));
495 error
= (*tp
->t_linesw
->l_open
)(dev
, tp
);
497 /* XXX cleanup on 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
;
510 /* XXX This is for cons.c. */
511 if (!ISSET(tp
->t_state
, TS_ISOPEN
))
514 (*tp
->t_linesw
->l_close
)(tp
, flag
);
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
);
526 callout_stop(&com_poll_ch
);
529 #ifdef notyet /* XXXX */
530 if (unit
!= comconsole
) {
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
));
568 struct com_softc
*sc
= device_lookup_private(&xcom_cd
, COMUNIT(dev
));
569 struct tty
*tp
= sc
->sc_tty
;
575 tiocm_xxx2mcr(int data
)
579 if (ISSET(data
, TIOCM_DTR
))
581 if (ISSET(data
, TIOCM_RTS
))
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
;
594 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
595 if (error
!= EPASSTHROUGH
)
598 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
599 if (error
!= EPASSTHROUGH
)
604 SET(sc
->sc_lcr
, LCR_SBREAK
);
605 outb(pio(iobase
, com_lcr
), sc
->sc_lcr
);
608 CLR(sc
->sc_lcr
, LCR_SBREAK
);
609 outb(pio(iobase
, com_lcr
), sc
->sc_lcr
);
612 SET(sc
->sc_mcr
, sc
->sc_dtr
);
613 outb(pio(iobase
, com_mcr
), sc
->sc_mcr
);
616 CLR(sc
->sc_mcr
, sc
->sc_dtr
);
617 outb(pio(iobase
, com_mcr
), sc
->sc_mcr
);
620 CLR(sc
->sc_mcr
, MCR_DTR
| MCR_RTS
);
622 SET(sc
->sc_mcr
, tiocm_xxx2mcr(*(int *)data
));
623 outb(pio(iobase
, com_mcr
), sc
->sc_mcr
);
626 CLR(sc
->sc_mcr
, tiocm_xxx2mcr(*(int *)data
));
627 outb(pio(iobase
, com_mcr
), 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
);
639 if (ISSET(m
, MSR_DCD
))
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
))
647 if (inb(pio(iobase
, com_ier
)))
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
;
669 int userbits
, driverbits
= 0;
671 error
= kauth_authorize_device_tty(l
->l_cred
,
672 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
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
;
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
);
707 /* check requested parameters */
708 if (ospeed
< 0 || (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
))
711 lcr
= ISSET(sc
->sc_lcr
, LCR_SBREAK
);
713 switch (ISSET(t
->c_cflag
, CSIZE
)) {
727 if (ISSET(t
->c_cflag
, PARENB
)) {
729 if (!ISSET(t
->c_cflag
, PARODD
))
732 if (ISSET(t
->c_cflag
, CSTOPB
))
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
748 if (tp
->t_ispeed
!= t
->c_ispeed
) {
749 if (ISSET(sc
->sc_hwflags
, COM_HW_FIFO
))
750 outb(pio(iobase
, com_fifo
),
752 (t
->c_ispeed
<= 1200 ? FIFO_TRIGGER_1
: FIFO_TRIGGER_8
));
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
);
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
);
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
;
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
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... */
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
;
820 if (ISSET(tp
->t_state
, TS_BUSY
))
822 if (ISSET(tp
->t_state
, TS_TIMEOUT
| TS_TTSTOP
) ||
825 if (ISSET(tp
->t_cflag
, CRTSCTS
) && !ISSET(sc
->sc_msr
, MSR_CTS
))
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
);
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
++);
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
);
849 outb(pio(iobase
, com_data
), *cp
++);
852 outb(pio(iobase
, com_data
), getc(&tp
->t_outq
));
857 if (ISSET(sc
->sc_ier
, IER_ETXRDY
)) {
858 CLR(sc
->sc_ier
, IER_ETXRDY
);
859 outb(pio(iobase
, com_ier
), sc
->sc_ier
);
865 * Stop output on a line.
868 comstop(struct tty
*tp
, int flag
)
873 if (ISSET(tp
->t_state
, TS_BUSY
))
874 if (!ISSET(tp
->t_state
, TS_TTSTOP
))
875 SET(tp
->t_state
, TS_FLUSH
);
882 struct com_softc
*sc
= arg
;
883 int overflows
, floods
;
888 overflows
= sc
->sc_overflows
;
889 sc
->sc_overflows
= 0;
890 floods
= sc
->sc_floods
;
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");
904 struct com_softc
*sc
;
910 static int lsrmap
[8] = {
912 TTY_FE
, TTY_PE
|TTY_FE
,
913 TTY_FE
, TTY_PE
|TTY_FE
,
914 TTY_FE
, TTY_PE
|TTY_FE
918 if (comevents
== 0) {
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
)
935 ibufend
= sc
->sc_ibufp
;
937 if (ibufp
== ibufend
) {
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
)) {
952 if (ISSET(tp
->t_cflag
, CRTSCTS
) &&
953 !ISSET(sc
->sc_mcr
, MCR_RTS
)) {
955 SET(sc
->sc_mcr
, MCR_RTS
);
956 outb(pio(sc
->sc_iobase
, com_mcr
), sc
->sc_mcr
);
961 while (ibufp
< ibufend
) {
963 if (*ibufp
& LSR_OE
) {
965 if (sc
->sc_errors
++ == 0)
966 callout_reset(&sc
->sc_diag_ch
, 60 * hz
,
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
);
976 callout_reset(&com_poll_ch
, 1, compollin
, NULL
);
982 struct com_softc
*sc
= device_lookup_private(&xcom_cd
, *((int *)arg
));
983 int iobase
= sc
->sc_iobase
;
985 u_char lsr
, data
, msr
, delta
;
989 if ((iir
= ISSET(inb(pio(iobase
, com_iir
)), IIR_NOPEND
)))
996 lsr
= inb(pio(iobase
, com_lsr
));
998 if (ISSET(lsr
, LSR_RXRDY
)) {
999 u_char
*p
= sc
->sc_ibufp
;
1003 data
= inb(pio(iobase
, com_data
));
1004 if (ISSET(lsr
, LSR_BI
)) {
1006 if (iobase
== CONADDR
) {
1012 if (p
>= sc
->sc_ibufend
) {
1014 if (sc
->sc_errors
++ == 0)
1015 callout_reset(&sc
->sc_diag_ch
,
1016 60 * hz
, comdiag
, sc
);
1020 if (p
== sc
->sc_ibufhigh
&&
1021 ISSET(tp
->t_cflag
, CRTSCTS
)) {
1023 CLR(sc
->sc_mcr
, MCR_RTS
);
1024 outb(pio(iobase
, com_mcr
),
1031 lsr
= inb(pio(iobase
, com_lsr
));
1032 } while (ISSET(lsr
, LSR_RXRDY
));
1037 else if (ISSET(lsr
, LSR_BI
|LSR_FE
|LSR_PE
|LSR_OE
))
1038 printf("weird lsr %02x\n", lsr
);
1041 msr
= inb(pio(iobase
, com_msr
));
1043 if (msr
!= sc
->sc_msr
) {
1044 delta
= msr
^ sc
->sc_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
)))
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);
1083 comcnprobe(struct consdev
*cp
)
1087 if (!comprobe1(CONADDR
)) {
1088 cp
->cn_pri
= CN_DEAD
;
1092 /* locate the major number */
1093 maj
= cdevsw_lookup_major(&xcom_cdevsw
);
1095 /* initialize required fields */
1096 cp
->cn_dev
= makedev(maj
, CONUNIT
);
1098 cp
->cn_pri
= CN_REMOTE
; /* Force a serial port console */
1100 cp
->cn_pri
= CN_NORMAL
;
1105 comcninit(struct consdev
*cp
)
1108 cominit(comdefaultrate
);
1109 comconsole
= CONUNIT
;
1117 int iobase
= CONADDR
;
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
));
1133 comcngetc(dev_t dev
)
1136 int iobase
= CONADDR
;
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
));
1149 * Console kernel output character routine.
1152 comcnputc(dev_t dev
, int c
)
1155 int iobase
= CONADDR
;
1162 if (dev
!= kgdb_dev
)
1164 if (comconsinit
== 0) {
1165 (void) cominit(comdefaultrate
);
1169 /* wait for any pending transmission to finish */
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 */
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
));
1186 comcnpollc(dev_t dev
, int on
)