xref: /openbsd-src/sys/dev/fdt/exuart.c (revision db862112cd96310e666d5dc80d2d49dd669c3868)
1*db862112Skettenis /* $OpenBSD: exuart.c,v 1.12 2023/07/23 11:16:36 kettenis Exp $ */
213358d45Spatrick /*
313358d45Spatrick  * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
413358d45Spatrick  *
513358d45Spatrick  * Permission to use, copy, modify, and distribute this software for any
613358d45Spatrick  * purpose with or without fee is hereby granted, provided that the above
713358d45Spatrick  * copyright notice and this permission notice appear in all copies.
813358d45Spatrick  *
913358d45Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1013358d45Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1113358d45Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1213358d45Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313358d45Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1413358d45Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1513358d45Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1613358d45Spatrick  */
1713358d45Spatrick 
1813358d45Spatrick #include <sys/param.h>
1913358d45Spatrick #include <sys/ioctl.h>
2013358d45Spatrick #include <sys/proc.h>
2113358d45Spatrick #include <sys/tty.h>
2213358d45Spatrick #include <sys/uio.h>
2313358d45Spatrick #include <sys/systm.h>
2413358d45Spatrick #include <sys/time.h>
2513358d45Spatrick #include <sys/device.h>
2613358d45Spatrick #include <sys/syslog.h>
2713358d45Spatrick #include <sys/conf.h>
2813358d45Spatrick #include <sys/fcntl.h>
2913358d45Spatrick #include <sys/kernel.h>
3013358d45Spatrick 
3113358d45Spatrick #include <machine/bus.h>
3213358d45Spatrick #include <machine/fdt.h>
3313358d45Spatrick 
3413358d45Spatrick #include <dev/cons.h>
3513358d45Spatrick 
3613358d45Spatrick #ifdef DDB
3713358d45Spatrick #include <ddb/db_var.h>
3813358d45Spatrick #endif
3913358d45Spatrick 
4013358d45Spatrick #include <dev/fdt/exuartreg.h>
4113358d45Spatrick 
4213358d45Spatrick #include <dev/ofw/openfirm.h>
43*db862112Skettenis #include <dev/ofw/ofw_power.h>
4413358d45Spatrick #include <dev/ofw/fdt.h>
4513358d45Spatrick 
4613358d45Spatrick #define DEVUNIT(x)      (minor(x) & 0x7f)
4713358d45Spatrick #define DEVCUA(x)       (minor(x) & 0x80)
4813358d45Spatrick 
4913358d45Spatrick struct exuart_softc {
5013358d45Spatrick 	struct device	sc_dev;
5113358d45Spatrick 	bus_space_tag_t sc_iot;
5213358d45Spatrick 	bus_space_handle_t sc_ioh;
5313358d45Spatrick 	struct soft_intrhand *sc_si;
5413358d45Spatrick 	void *sc_irq;
5513358d45Spatrick 	struct tty	*sc_tty;
5613358d45Spatrick 	struct timeout	sc_diag_tmo;
5713358d45Spatrick 	struct timeout	sc_dtr_tmo;
5870a1cc2bSkettenis 
5970a1cc2bSkettenis 	uint32_t	sc_rx_fifo_cnt_mask;
6070a1cc2bSkettenis 	uint32_t	sc_rx_fifo_full;
6170a1cc2bSkettenis 	uint32_t	sc_tx_fifo_full;
62d5a6de06Skettenis 	int		sc_type;
63d5a6de06Skettenis #define EXUART_TYPE_EXYNOS	0
64d5a6de06Skettenis #define EXUART_TYPE_S5L		1
6570a1cc2bSkettenis 
6613358d45Spatrick 	int		sc_fifo;
6713358d45Spatrick 	int		sc_overflows;
6813358d45Spatrick 	int		sc_floods;
6913358d45Spatrick 	int		sc_errors;
7013358d45Spatrick 	int		sc_halt;
7113358d45Spatrick 	u_int32_t	sc_ulcon;
7213358d45Spatrick 	u_int32_t	sc_ucon;
7313358d45Spatrick 	u_int32_t	sc_ufcon;
7413358d45Spatrick 	u_int32_t	sc_umcon;
7513358d45Spatrick 	u_int32_t	sc_uintm;
7613358d45Spatrick 	u_int8_t	sc_hwflags;
7713358d45Spatrick #define COM_HW_NOIEN    0x01
7813358d45Spatrick #define COM_HW_FIFO     0x02
7913358d45Spatrick #define COM_HW_SIR      0x20
8013358d45Spatrick #define COM_HW_CONSOLE  0x40
8113358d45Spatrick 	u_int8_t	sc_swflags;
8213358d45Spatrick #define COM_SW_SOFTCAR  0x01
8313358d45Spatrick #define COM_SW_CLOCAL   0x02
8413358d45Spatrick #define COM_SW_CRTSCTS  0x04
8513358d45Spatrick #define COM_SW_MDMBUF   0x08
8613358d45Spatrick #define COM_SW_PPS      0x10
8713358d45Spatrick 
8813358d45Spatrick 	u_int8_t	sc_initialize;
8913358d45Spatrick 	u_int8_t	sc_cua;
9013358d45Spatrick 	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
9113358d45Spatrick #define EXUART_IBUFSIZE 128
9213358d45Spatrick #define EXUART_IHIGHWATER 100
9313358d45Spatrick 	u_int16_t		sc_ibufs[2][EXUART_IBUFSIZE];
9413358d45Spatrick };
9513358d45Spatrick 
9613358d45Spatrick 
97c81f110bSpatrick int	 exuart_match(struct device *, void *, void *);
98c81f110bSpatrick void	 exuart_attach(struct device *, struct device *, void *);
9913358d45Spatrick 
10013358d45Spatrick void exuartcnprobe(struct consdev *cp);
10113358d45Spatrick void exuartcninit(struct consdev *cp);
10213358d45Spatrick int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
10313358d45Spatrick     tcflag_t cflag);
10413358d45Spatrick int exuartcngetc(dev_t dev);
10513358d45Spatrick void exuartcnputc(dev_t dev, int c);
10613358d45Spatrick void exuartcnpollc(dev_t dev, int on);
10713358d45Spatrick int  exuart_param(struct tty *tp, struct termios *t);
10813358d45Spatrick void exuart_start(struct tty *);
10913358d45Spatrick void exuart_diag(void *arg);
11013358d45Spatrick void exuart_raisedtr(void *arg);
11113358d45Spatrick void exuart_softint(void *arg);
11213358d45Spatrick struct exuart_softc *exuart_sc(dev_t dev);
11313358d45Spatrick 
11413358d45Spatrick int exuart_intr(void *);
115d5a6de06Skettenis int exuart_s5l_intr(void *);
11613358d45Spatrick 
11713358d45Spatrick /* XXX - we imitate 'com' serial ports and take over their entry points */
11813358d45Spatrick /* XXX: These belong elsewhere */
119308e62c2Spatrick cdev_decl(com);
12013358d45Spatrick cdev_decl(exuart);
12113358d45Spatrick 
12213358d45Spatrick struct cfdriver exuart_cd = {
12313358d45Spatrick 	NULL, "exuart", DV_TTY
12413358d45Spatrick };
12513358d45Spatrick 
126471aeecfSnaddy const struct cfattach exuart_ca = {
127c81f110bSpatrick 	sizeof(struct exuart_softc), exuart_match, exuart_attach
12813358d45Spatrick };
12913358d45Spatrick 
13013358d45Spatrick bus_space_tag_t	exuartconsiot;
13113358d45Spatrick bus_space_handle_t exuartconsioh;
13213358d45Spatrick bus_addr_t	exuartconsaddr;
13313358d45Spatrick tcflag_t	exuartconscflag = TTYDEF_CFLAG;
13413358d45Spatrick int		exuartdefaultrate = B115200;
13513358d45Spatrick 
13670a1cc2bSkettenis uint32_t	exuart_rx_fifo_cnt_mask;
13770a1cc2bSkettenis uint32_t	exuart_rx_fifo_full;
13870a1cc2bSkettenis uint32_t	exuart_tx_fifo_full;
13970a1cc2bSkettenis 
140c81f110bSpatrick struct cdevsw exuartdev =
141c81f110bSpatrick 	cdev_tty_init(3/*XXX NEXUART */ ,exuart);		/* 12: serial port */
142c81f110bSpatrick 
14313358d45Spatrick void
exuart_init_cons(void)14413358d45Spatrick exuart_init_cons(void)
14513358d45Spatrick {
14613358d45Spatrick 	struct fdt_reg reg;
14713358d45Spatrick 	void *node, *root;
14813358d45Spatrick 
149af61f688Skettenis 	if ((node = fdt_find_cons("apple,s5l-uart")) == NULL &&
150af61f688Skettenis 	    (node = fdt_find_cons("samsung,exynos4210-uart")) == NULL)
15113358d45Spatrick 		return;
15213358d45Spatrick 
15313358d45Spatrick 	/* dtb uses serial2, qemu uses serial0 */
15413358d45Spatrick 	root = fdt_find_node("/");
15513358d45Spatrick 	if (root == NULL)
15613358d45Spatrick 		panic("%s: could not get fdt root node", __func__);
15713358d45Spatrick 	if (fdt_is_compatible(root, "samsung,universal_c210")) {
15813358d45Spatrick 		if ((node = fdt_find_node("/serial@13800000")) == NULL) {
15913358d45Spatrick 			return;
16013358d45Spatrick 		}
16113358d45Spatrick 		stdout_node = OF_finddevice("/serial@13800000");
16213358d45Spatrick 	}
16313358d45Spatrick 
16413358d45Spatrick 	if (fdt_get_reg(node, 0, &reg))
16513358d45Spatrick 		return;
16613358d45Spatrick 
167af61f688Skettenis 	if (fdt_is_compatible(node, "apple,s5l-uart")) {
168af61f688Skettenis 		exuart_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
169af61f688Skettenis 		exuart_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
170af61f688Skettenis 		exuart_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
171af61f688Skettenis 	} else {
17270a1cc2bSkettenis 		exuart_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
17370a1cc2bSkettenis 		exuart_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
17470a1cc2bSkettenis 		exuart_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
175af61f688Skettenis 	}
17670a1cc2bSkettenis 
177c81f110bSpatrick 	exuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
17813358d45Spatrick }
17913358d45Spatrick 
18013358d45Spatrick int
exuart_match(struct device * parent,void * self,void * aux)181c81f110bSpatrick exuart_match(struct device *parent, void *self, void *aux)
18213358d45Spatrick {
18313358d45Spatrick 	struct fdt_attach_args *faa = aux;
18413358d45Spatrick 
185af61f688Skettenis 	return (OF_is_compatible(faa->fa_node, "apple,s5l-uart") ||
186af61f688Skettenis 	    OF_is_compatible(faa->fa_node, "samsung,exynos4210-uart"));
18713358d45Spatrick }
18813358d45Spatrick 
18913358d45Spatrick void
exuart_attach(struct device * parent,struct device * self,void * aux)190c81f110bSpatrick exuart_attach(struct device *parent, struct device *self, void *aux)
19113358d45Spatrick {
19213358d45Spatrick 	struct exuart_softc *sc = (struct exuart_softc *) self;
193c81f110bSpatrick 	struct fdt_attach_args *faa = aux;
19413358d45Spatrick 	int maj;
19513358d45Spatrick 
19613358d45Spatrick 	if (faa->fa_nreg < 1)
19713358d45Spatrick 		return;
19813358d45Spatrick 
199c81f110bSpatrick 	sc->sc_iot = faa->fa_iot;
20013358d45Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
20113358d45Spatrick 	    0, &sc->sc_ioh))
20213358d45Spatrick 		panic("%s: bus_space_map failed!", __func__);
20313358d45Spatrick 
20413358d45Spatrick 	if (stdout_node == faa->fa_node) {
20513358d45Spatrick 		/* Locate the major number. */
20613358d45Spatrick 		for (maj = 0; maj < nchrdev; maj++)
20713358d45Spatrick 			if (cdevsw[maj].d_open == exuartopen)
20813358d45Spatrick 				break;
20913358d45Spatrick 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
21013358d45Spatrick 
21113358d45Spatrick 		printf(": console");
21213358d45Spatrick 	}
21313358d45Spatrick 
214*db862112Skettenis 	printf("\n");
215*db862112Skettenis 
216*db862112Skettenis 	power_domain_enable(faa->fa_node);
217*db862112Skettenis 
218af61f688Skettenis 	if (OF_is_compatible(faa->fa_node, "apple,s5l-uart")) {
219d5a6de06Skettenis 		sc->sc_type = EXUART_TYPE_S5L;
220af61f688Skettenis 		sc->sc_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
221af61f688Skettenis 		sc->sc_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
222af61f688Skettenis 		sc->sc_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
223d5a6de06Skettenis 
224d5a6de06Skettenis 		/* Mask and clear interrupts. */
225d5a6de06Skettenis 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
226d5a6de06Skettenis 		    EXUART_UCON);
227d5a6de06Skettenis 		CLR(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
228d5a6de06Skettenis 		CLR(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
229d5a6de06Skettenis 		CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
230d5a6de06Skettenis 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
231d5a6de06Skettenis 		    sc->sc_ucon);
232d5a6de06Skettenis 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UTRSTAT,
233d5a6de06Skettenis 		    EXUART_S5L_UTRSTAT_RX_TIMEOUT |
234d5a6de06Skettenis 		    EXUART_S5L_UTRSTAT_RXTHRESH |
235d5a6de06Skettenis 		    EXUART_S5L_UTRSTAT_TXTHRESH);
236d5a6de06Skettenis 
237d5a6de06Skettenis 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
238d5a6de06Skettenis 		    EXUART_UCON);
239d5a6de06Skettenis 		SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
240d5a6de06Skettenis 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
241d5a6de06Skettenis 		    sc->sc_ucon);
242d5a6de06Skettenis 
243d5a6de06Skettenis 		sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
244d5a6de06Skettenis 		    exuart_s5l_intr, sc, sc->sc_dev.dv_xname);
245af61f688Skettenis 	} else {
246d5a6de06Skettenis 		sc->sc_type = EXUART_TYPE_EXYNOS;
24770a1cc2bSkettenis 		sc->sc_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
24870a1cc2bSkettenis 		sc->sc_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
24970a1cc2bSkettenis 		sc->sc_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
25070a1cc2bSkettenis 
25113358d45Spatrick 		/* Mask and clear interrupts. */
25213358d45Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTM,
25313358d45Spatrick 		    EXUART_UINTM_RXD | EXUART_UINTM_ERROR |
25413358d45Spatrick 		    EXUART_UINTM_TXD | EXUART_UINTM_MODEM);
25513358d45Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTP,
25613358d45Spatrick 		    EXUART_UINTP_RXD | EXUART_UINTP_ERROR |
25713358d45Spatrick 		    EXUART_UINTP_TXD | EXUART_UINTP_MODEM);
25813358d45Spatrick 
259d5a6de06Skettenis 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
260d5a6de06Skettenis 		    EXUART_UCON);
26113358d45Spatrick 		CLR(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO);
26213358d45Spatrick 		SET(sc->sc_ucon, EXUART_UCON_RX_INT_TYPE_LEVEL);
26313358d45Spatrick 		SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
264d5a6de06Skettenis 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
265d5a6de06Skettenis 		    sc->sc_ucon);
266d5a6de06Skettenis 
267d5a6de06Skettenis 		sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
268d5a6de06Skettenis 		    exuart_intr, sc, sc->sc_dev.dv_xname);
269d5a6de06Skettenis 	}
27013358d45Spatrick 
27113358d45Spatrick 	timeout_set(&sc->sc_diag_tmo, exuart_diag, sc);
27213358d45Spatrick 	timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc);
27313358d45Spatrick 	sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc);
27413358d45Spatrick 
27513358d45Spatrick 	if(sc->sc_si == NULL)
27613358d45Spatrick 		panic("%s: can't establish soft interrupt.",
27713358d45Spatrick 		    sc->sc_dev.dv_xname);
27813358d45Spatrick }
27913358d45Spatrick 
280d5a6de06Skettenis void
exuart_rx_intr(struct exuart_softc * sc)281d5a6de06Skettenis exuart_rx_intr(struct exuart_softc *sc)
28213358d45Spatrick {
28313358d45Spatrick 	bus_space_tag_t iot = sc->sc_iot;
28413358d45Spatrick 	bus_space_handle_t ioh = sc->sc_ioh;
28513358d45Spatrick 	u_int16_t *p;
28613358d45Spatrick 	u_int16_t c;
28713358d45Spatrick 
28813358d45Spatrick 	p = sc->sc_ibufp;
28913358d45Spatrick 
29013358d45Spatrick 	while (bus_space_read_4(iot, ioh, EXUART_UFSTAT) &
29170a1cc2bSkettenis 	    (sc->sc_rx_fifo_cnt_mask | sc->sc_rx_fifo_full)) {
29270a1cc2bSkettenis 		c = bus_space_read_4(iot, ioh, EXUART_URXH);
29313358d45Spatrick 		if (p >= sc->sc_ibufend) {
29413358d45Spatrick 			sc->sc_floods++;
29513358d45Spatrick 			if (sc->sc_errors++ == 0)
29613358d45Spatrick 				timeout_add_sec(&sc->sc_diag_tmo, 60);
29713358d45Spatrick 		} else {
29813358d45Spatrick 			*p++ = c;
29913358d45Spatrick #if 0
30013358d45Spatrick 			if (p == sc->sc_ibufhigh &&
30113358d45Spatrick 			    ISSET(tp->t_cflag, CRTSCTS)) {
30213358d45Spatrick 				/* XXX */
30313358d45Spatrick 			}
30413358d45Spatrick #endif
30513358d45Spatrick 		}
30613358d45Spatrick 	}
30713358d45Spatrick 
30813358d45Spatrick 	sc->sc_ibufp = p;
30913358d45Spatrick 
31013358d45Spatrick 	softintr_schedule(sc->sc_si);
31113358d45Spatrick }
31213358d45Spatrick 
313d5a6de06Skettenis void
exuart_tx_intr(struct exuart_softc * sc)314d5a6de06Skettenis exuart_tx_intr(struct exuart_softc *sc)
315d5a6de06Skettenis {
316d5a6de06Skettenis 	struct tty *tp = sc->sc_tty;
317d5a6de06Skettenis 
318d5a6de06Skettenis 	if (ISSET(tp->t_state, TS_BUSY)) {
31913358d45Spatrick 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
32013358d45Spatrick 		if (sc->sc_halt > 0)
32113358d45Spatrick 			wakeup(&tp->t_outq);
32213358d45Spatrick 		(*linesw[tp->t_line].l_start)(tp);
323d5a6de06Skettenis 	}
324d5a6de06Skettenis }
325d5a6de06Skettenis 
326d5a6de06Skettenis int
exuart_intr(void * arg)327d5a6de06Skettenis exuart_intr(void *arg)
328d5a6de06Skettenis {
329d5a6de06Skettenis 	struct exuart_softc *sc = arg;
330d5a6de06Skettenis 	bus_space_tag_t iot = sc->sc_iot;
331d5a6de06Skettenis 	bus_space_handle_t ioh = sc->sc_ioh;
332d5a6de06Skettenis 	u_int32_t uintp;
333d5a6de06Skettenis 
334d5a6de06Skettenis 	uintp = bus_space_read_4(iot, ioh, EXUART_UINTP);
335d5a6de06Skettenis 	if (uintp == 0)
336d5a6de06Skettenis 		return (0);
337d5a6de06Skettenis 
338d5a6de06Skettenis 	if (sc->sc_tty == NULL)
339d5a6de06Skettenis 		return (0);
340d5a6de06Skettenis 
341d5a6de06Skettenis 	if (ISSET(uintp, EXUART_UINTP_RXD)) {
342d5a6de06Skettenis 		exuart_rx_intr(sc);
343d5a6de06Skettenis 		bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_RXD);
344d5a6de06Skettenis 	}
345d5a6de06Skettenis 
346d5a6de06Skettenis 	if (ISSET(uintp, EXUART_UINTP_TXD)) {
347d5a6de06Skettenis 		exuart_tx_intr(sc);
34813358d45Spatrick 		bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_TXD);
34913358d45Spatrick 	}
35013358d45Spatrick 
35113358d45Spatrick #if 0
35213358d45Spatrick 	if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR))
35313358d45Spatrick 		return 0;
35413358d45Spatrick 
35513358d45Spatrick 	p = sc->sc_ibufp;
35613358d45Spatrick 
35713358d45Spatrick 	while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) {
35870a1cc2bSkettenis 		c = bus_space_read_4(iot, ioh, EXUART_URXH);
35913358d45Spatrick 		if (p >= sc->sc_ibufend) {
36013358d45Spatrick 			sc->sc_floods++;
36113358d45Spatrick 			if (sc->sc_errors++ == 0)
36213358d45Spatrick 				timeout_add_sec(&sc->sc_diag_tmo, 60);
36313358d45Spatrick 		} else {
36413358d45Spatrick 			*p++ = c;
36513358d45Spatrick 			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
36613358d45Spatrick 				/* XXX */
36713358d45Spatrick 				//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
36813358d45Spatrick 				//bus_space_write_2(iot, ioh, EXUART_UCR3,
36913358d45Spatrick 				//    sc->sc_ucr3);
37013358d45Spatrick 
37113358d45Spatrick 		}
37213358d45Spatrick 		/* XXX - msr stuff ? */
37313358d45Spatrick 	}
37413358d45Spatrick 	sc->sc_ibufp = p;
37513358d45Spatrick 
37613358d45Spatrick 	softintr_schedule(sc->sc_si);
37713358d45Spatrick #endif
37813358d45Spatrick 
37913358d45Spatrick 	return 1;
38013358d45Spatrick }
38113358d45Spatrick 
38213358d45Spatrick int
exuart_s5l_intr(void * arg)383d5a6de06Skettenis exuart_s5l_intr(void *arg)
384d5a6de06Skettenis {
385d5a6de06Skettenis 	struct exuart_softc *sc = arg;
386d5a6de06Skettenis 	bus_space_tag_t iot = sc->sc_iot;
387d5a6de06Skettenis 	bus_space_handle_t ioh = sc->sc_ioh;
388d5a6de06Skettenis 	u_int32_t utrstat;
389d5a6de06Skettenis 
390d5a6de06Skettenis 	utrstat = bus_space_read_4(iot, ioh, EXUART_UTRSTAT);
391d5a6de06Skettenis 
392d5a6de06Skettenis 	if (sc->sc_tty == NULL)
393d5a6de06Skettenis 		return (0);
394d5a6de06Skettenis 
395d5a6de06Skettenis 	if (utrstat & (EXUART_S5L_UTRSTAT_RXTHRESH |
396d5a6de06Skettenis 	    EXUART_S5L_UTRSTAT_RX_TIMEOUT))
397d5a6de06Skettenis 		exuart_rx_intr(sc);
398d5a6de06Skettenis 
399d5a6de06Skettenis 	if (utrstat & EXUART_S5L_UTRSTAT_TXTHRESH)
400d5a6de06Skettenis 		exuart_tx_intr(sc);
401d5a6de06Skettenis 
402d5a6de06Skettenis 	bus_space_write_4(iot, ioh, EXUART_UTRSTAT, utrstat);
403d5a6de06Skettenis 
404d5a6de06Skettenis 	return 1;
405d5a6de06Skettenis }
406d5a6de06Skettenis 
407d5a6de06Skettenis int
exuart_param(struct tty * tp,struct termios * t)40813358d45Spatrick exuart_param(struct tty *tp, struct termios *t)
40913358d45Spatrick {
41013358d45Spatrick 	struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
41113358d45Spatrick 	bus_space_tag_t iot = sc->sc_iot;
41213358d45Spatrick 	bus_space_handle_t ioh = sc->sc_ioh;
41313358d45Spatrick 	int ospeed = t->c_ospeed;
41413358d45Spatrick 	int error;
41513358d45Spatrick 	tcflag_t oldcflag;
41613358d45Spatrick 
41713358d45Spatrick 
41813358d45Spatrick 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
41913358d45Spatrick 		return EINVAL;
42013358d45Spatrick 
42113358d45Spatrick 	switch (ISSET(t->c_cflag, CSIZE)) {
42213358d45Spatrick 	case CS5:
42313358d45Spatrick 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
42413358d45Spatrick 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE);
42513358d45Spatrick 		break;
42613358d45Spatrick 	case CS6:
42713358d45Spatrick 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
42813358d45Spatrick 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX);
42913358d45Spatrick 		break;
43013358d45Spatrick 	case CS7:
43113358d45Spatrick 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
43213358d45Spatrick 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN);
43313358d45Spatrick 		break;
43413358d45Spatrick 	case CS8:
43513358d45Spatrick 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
43613358d45Spatrick 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT);
43713358d45Spatrick 		break;
43813358d45Spatrick 	}
43913358d45Spatrick 
44013358d45Spatrick 	CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK);
44113358d45Spatrick 	if (ISSET(t->c_cflag, PARENB)) {
44213358d45Spatrick 		if (ISSET(t->c_cflag, PARODD))
44313358d45Spatrick 			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD);
44413358d45Spatrick 		else
44513358d45Spatrick 			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN);
44613358d45Spatrick 	}
44713358d45Spatrick 
44813358d45Spatrick 	if (ISSET(t->c_cflag, CSTOPB))
44913358d45Spatrick 		SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO);
45013358d45Spatrick 	else
45113358d45Spatrick 		CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE);
45213358d45Spatrick 
45313358d45Spatrick 	bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon);
45413358d45Spatrick 
45513358d45Spatrick 	if (ospeed == 0) {
45613358d45Spatrick 		/* lower dtr */
45713358d45Spatrick 	}
45813358d45Spatrick 
45913358d45Spatrick 	if (ospeed != 0) {
46013358d45Spatrick 		while (ISSET(tp->t_state, TS_BUSY)) {
46113358d45Spatrick 			++sc->sc_halt;
46213358d45Spatrick 			error = ttysleep(tp, &tp->t_outq,
46313358d45Spatrick 			    TTOPRI | PCATCH, "exuartprm");
46413358d45Spatrick 			--sc->sc_halt;
46513358d45Spatrick 			if (error) {
46613358d45Spatrick 				exuart_start(tp);
46713358d45Spatrick 				return (error);
46813358d45Spatrick 			}
46913358d45Spatrick 		}
47013358d45Spatrick 		/* set speed */
47113358d45Spatrick 	}
47213358d45Spatrick 
47313358d45Spatrick 	/* setup fifo */
47413358d45Spatrick 
47513358d45Spatrick 	/* When not using CRTSCTS, RTS follows DTR. */
47613358d45Spatrick 	/* sc->sc_dtr = MCR_DTR; */
47713358d45Spatrick 
47813358d45Spatrick 
47913358d45Spatrick 	/* and copy to tty */
48013358d45Spatrick 	tp->t_ispeed = t->c_ispeed;
48113358d45Spatrick 	tp->t_ospeed = t->c_ospeed;
48213358d45Spatrick 	oldcflag = tp->t_cflag;
48313358d45Spatrick 	tp->t_cflag = t->c_cflag;
48413358d45Spatrick 
48513358d45Spatrick         /*
48613358d45Spatrick 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
48713358d45Spatrick 	 * stop the device.
48813358d45Spatrick 	 */
48913358d45Spatrick 	 /* XXX */
49013358d45Spatrick 
49113358d45Spatrick 	exuart_start(tp);
49213358d45Spatrick 
49313358d45Spatrick 	return 0;
49413358d45Spatrick }
49513358d45Spatrick 
49613358d45Spatrick void
exuart_start(struct tty * tp)49713358d45Spatrick exuart_start(struct tty *tp)
49813358d45Spatrick {
49913358d45Spatrick         struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
50013358d45Spatrick 	bus_space_tag_t iot = sc->sc_iot;
50113358d45Spatrick 	bus_space_handle_t ioh = sc->sc_ioh;
50213358d45Spatrick 	int s;
50313358d45Spatrick 
50413358d45Spatrick 	s = spltty();
50513358d45Spatrick 	if (ISSET(tp->t_state, TS_BUSY))
50613358d45Spatrick 		goto out;
50713358d45Spatrick 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
50813358d45Spatrick 		goto stopped;
50913358d45Spatrick #ifdef DAMNFUCKSHIT
51013358d45Spatrick 	/* clear to send (IE the RTS pin on this shit) is not directly \
51113358d45Spatrick 	 * readable - skip check for now
51213358d45Spatrick 	 */
51313358d45Spatrick 	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS))
51413358d45Spatrick 		goto stopped;
51513358d45Spatrick #endif
51613358d45Spatrick 	ttwakeupwr(tp);
51713358d45Spatrick 	if (tp->t_outq.c_cc == 0)
51813358d45Spatrick 		goto stopped;
51913358d45Spatrick 	SET(tp->t_state, TS_BUSY);
52013358d45Spatrick 
52113358d45Spatrick 	{
52213358d45Spatrick 		u_char buffer[16];
52313358d45Spatrick 		int i, n;
52413358d45Spatrick 
52513358d45Spatrick 		n = q_to_b(&tp->t_outq, buffer, sizeof buffer);
52613358d45Spatrick 		for (i = 0; i < n; i++)
52770a1cc2bSkettenis 			bus_space_write_4(iot, ioh, EXUART_UTXH, buffer[i]);
52813358d45Spatrick 		bzero(buffer, n);
52913358d45Spatrick 	}
53013358d45Spatrick 
531d5a6de06Skettenis 	if (sc->sc_type == EXUART_TYPE_S5L) {
532d5a6de06Skettenis 		if (!ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
533d5a6de06Skettenis 			SET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
534d5a6de06Skettenis 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
535d5a6de06Skettenis 		}
536d5a6de06Skettenis 	} else {
53713358d45Spatrick 		if (ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
53813358d45Spatrick 			CLR(sc->sc_uintm, EXUART_UINTM_TXD);
53913358d45Spatrick 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
54013358d45Spatrick 		}
541d5a6de06Skettenis 	}
54213358d45Spatrick 
54313358d45Spatrick out:
54413358d45Spatrick 	splx(s);
54513358d45Spatrick 	return;
54613358d45Spatrick stopped:
547d5a6de06Skettenis 	if (sc->sc_type == EXUART_TYPE_S5L) {
548d5a6de06Skettenis 		if (ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
549d5a6de06Skettenis 			CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
550d5a6de06Skettenis 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
551d5a6de06Skettenis 		}
552d5a6de06Skettenis 	} else {
55313358d45Spatrick 		if (!ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
55413358d45Spatrick 			SET(sc->sc_uintm, EXUART_UINTM_TXD);
55513358d45Spatrick 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
55613358d45Spatrick 		}
557d5a6de06Skettenis 	}
55813358d45Spatrick 	splx(s);
55913358d45Spatrick }
56013358d45Spatrick 
56113358d45Spatrick void
exuart_diag(void * arg)56213358d45Spatrick exuart_diag(void *arg)
56313358d45Spatrick {
56413358d45Spatrick 	struct exuart_softc *sc = arg;
56513358d45Spatrick 	int overflows, floods;
56613358d45Spatrick 	int s;
56713358d45Spatrick 
56813358d45Spatrick 	s = spltty();
56913358d45Spatrick 	sc->sc_errors = 0;
57013358d45Spatrick 	overflows = sc->sc_overflows;
57113358d45Spatrick 	sc->sc_overflows = 0;
57213358d45Spatrick 	floods = sc->sc_floods;
57313358d45Spatrick 	sc->sc_floods = 0;
57413358d45Spatrick 	splx(s);
57513358d45Spatrick 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
57613358d45Spatrick 	    sc->sc_dev.dv_xname,
57713358d45Spatrick 	    overflows, overflows == 1 ? "" : "s",
57813358d45Spatrick 	    floods, floods == 1 ? "" : "s");
57913358d45Spatrick }
58013358d45Spatrick 
58113358d45Spatrick void
exuart_raisedtr(void * arg)58213358d45Spatrick exuart_raisedtr(void *arg)
58313358d45Spatrick {
58413358d45Spatrick 	//struct exuart_softc *sc = arg;
58513358d45Spatrick 
58613358d45Spatrick 	//SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
58713358d45Spatrick 	//bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3);
58813358d45Spatrick }
58913358d45Spatrick 
59013358d45Spatrick void
exuart_softint(void * arg)59113358d45Spatrick exuart_softint(void *arg)
59213358d45Spatrick {
59313358d45Spatrick 	struct exuart_softc *sc = arg;
59413358d45Spatrick 	struct tty *tp;
59513358d45Spatrick 	u_int16_t *ibufp;
59613358d45Spatrick 	u_int16_t *ibufend;
59713358d45Spatrick 	int c;
59813358d45Spatrick 	int err;
59913358d45Spatrick 	int s;
60013358d45Spatrick 
60113358d45Spatrick 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
60213358d45Spatrick 		return;
60313358d45Spatrick 
60413358d45Spatrick 	tp = sc->sc_tty;
60513358d45Spatrick 
60613358d45Spatrick 	s = spltty();
60713358d45Spatrick 
60813358d45Spatrick 	ibufp = sc->sc_ibuf;
60913358d45Spatrick 	ibufend = sc->sc_ibufp;
61013358d45Spatrick 
61113358d45Spatrick 	if (ibufp == ibufend) {
61213358d45Spatrick 		splx(s);
61313358d45Spatrick 		return;
61413358d45Spatrick 	}
61513358d45Spatrick 
61613358d45Spatrick 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
61713358d45Spatrick 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
61813358d45Spatrick 	sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
61913358d45Spatrick 	sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
62013358d45Spatrick 
62113358d45Spatrick 	if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
62213358d45Spatrick 		splx(s);
62313358d45Spatrick 		return;
62413358d45Spatrick 	}
62513358d45Spatrick 
62613358d45Spatrick #if 0
62713358d45Spatrick 	if (ISSET(tp->t_cflag, CRTSCTS) &&
62813358d45Spatrick 	    !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) {
62913358d45Spatrick 		/* XXX */
63013358d45Spatrick 		SET(sc->sc_ucr3, EXUART_CR3_DSR);
63113358d45Spatrick 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3,
63213358d45Spatrick 		    sc->sc_ucr3);
63313358d45Spatrick 	}
63413358d45Spatrick #endif
63513358d45Spatrick 
63613358d45Spatrick 	splx(s);
63713358d45Spatrick 
63813358d45Spatrick 	while (ibufp < ibufend) {
63913358d45Spatrick 		c = *ibufp++;
64013358d45Spatrick #if 0
64113358d45Spatrick 		if (ISSET(c, EXUART_UERSTAT_OVERRUN)) {
64213358d45Spatrick 			sc->sc_overflows++;
64313358d45Spatrick 			if (sc->sc_errors++ == 0)
64413358d45Spatrick 				timeout_add_sec(&sc->sc_diag_tmo, 60);
64513358d45Spatrick 		}
64613358d45Spatrick #endif
64713358d45Spatrick 		err = 0;
64813358d45Spatrick #if 0
64913358d45Spatrick 		if (ISSET(c, EXUART_UERSTAT_PARITY))
65013358d45Spatrick 			err |= TTY_PE;
65113358d45Spatrick 		if (ISSET(c, EXUART_UERSTAT_FRAME))
65213358d45Spatrick 			err |= TTY_FE;
65313358d45Spatrick #endif
65413358d45Spatrick 		c = (c & 0xff) | err;
65513358d45Spatrick 		(*linesw[tp->t_line].l_rint)(c, tp);
65613358d45Spatrick 	}
65713358d45Spatrick }
65813358d45Spatrick 
65913358d45Spatrick int
exuartopen(dev_t dev,int flag,int mode,struct proc * p)66013358d45Spatrick exuartopen(dev_t dev, int flag, int mode, struct proc *p)
66113358d45Spatrick {
66213358d45Spatrick 	int unit = DEVUNIT(dev);
66313358d45Spatrick 	struct exuart_softc *sc;
66413358d45Spatrick 	bus_space_tag_t iot;
66513358d45Spatrick 	bus_space_handle_t ioh;
66613358d45Spatrick 	struct tty *tp;
66713358d45Spatrick 	int s;
66813358d45Spatrick 	int error = 0;
66913358d45Spatrick 
67013358d45Spatrick 	if (unit >= exuart_cd.cd_ndevs)
67113358d45Spatrick 		return ENXIO;
67213358d45Spatrick 	sc = exuart_cd.cd_devs[unit];
67313358d45Spatrick 	if (sc == NULL)
67413358d45Spatrick 		return ENXIO;
67513358d45Spatrick 
67613358d45Spatrick 	s = spltty();
67713358d45Spatrick 	if (sc->sc_tty == NULL)
67813358d45Spatrick 		tp = sc->sc_tty = ttymalloc(0);
67913358d45Spatrick 	else
68013358d45Spatrick 		tp = sc->sc_tty;
68113358d45Spatrick 	splx(s);
68213358d45Spatrick 
68313358d45Spatrick 	tp->t_oproc = exuart_start;
68413358d45Spatrick 	tp->t_param = exuart_param;
68513358d45Spatrick 	tp->t_dev = dev;
68613358d45Spatrick 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
68713358d45Spatrick 		SET(tp->t_state, TS_WOPEN);
68813358d45Spatrick 		ttychars(tp);
68913358d45Spatrick 		tp->t_iflag = TTYDEF_IFLAG;
69013358d45Spatrick 		tp->t_oflag = TTYDEF_OFLAG;
69113358d45Spatrick 
69213358d45Spatrick 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
69313358d45Spatrick 			tp->t_cflag = exuartconscflag;
69413358d45Spatrick 		else
69513358d45Spatrick 			tp->t_cflag = TTYDEF_CFLAG;
69613358d45Spatrick 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
69713358d45Spatrick 			SET(tp->t_cflag, CLOCAL);
69813358d45Spatrick 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
69913358d45Spatrick 			SET(tp->t_cflag, CRTSCTS);
70013358d45Spatrick 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
70113358d45Spatrick 			SET(tp->t_cflag, MDMBUF);
70213358d45Spatrick 		tp->t_lflag = TTYDEF_LFLAG;
70313358d45Spatrick 		tp->t_ispeed = tp->t_ospeed = exuartdefaultrate;
70413358d45Spatrick 
70513358d45Spatrick 		s = spltty();
70613358d45Spatrick 
70713358d45Spatrick 		sc->sc_initialize = 1;
70813358d45Spatrick 		exuart_param(tp, &tp->t_termios);
70913358d45Spatrick 		ttsetwater(tp);
71013358d45Spatrick 
71113358d45Spatrick 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
71213358d45Spatrick 		sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
71313358d45Spatrick 		sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
71413358d45Spatrick 
71513358d45Spatrick 		iot = sc->sc_iot;
71613358d45Spatrick 		ioh = sc->sc_ioh;
71713358d45Spatrick 
71813358d45Spatrick 		sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON);
71913358d45Spatrick 		sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON);
72013358d45Spatrick 		sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON);
72113358d45Spatrick 		sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON);
72213358d45Spatrick 
723d5a6de06Skettenis 		if (sc->sc_type == EXUART_TYPE_S5L) {
724d5a6de06Skettenis 			SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
725d5a6de06Skettenis 			SET(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
726d5a6de06Skettenis 			SET(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
727d5a6de06Skettenis 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
728d5a6de06Skettenis 		} else {
72913358d45Spatrick 			sc->sc_uintm = bus_space_read_4(iot, ioh, EXUART_UINTM);
73013358d45Spatrick 			CLR(sc->sc_uintm, EXUART_UINTM_RXD);
73113358d45Spatrick 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
732d5a6de06Skettenis 		}
73313358d45Spatrick 
73413358d45Spatrick #if 0
73513358d45Spatrick 		/* interrupt after one char on tx/rx */
73613358d45Spatrick 		/* reference frequency divider: 1 */
73713358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UFCR,
73813358d45Spatrick 		    1 << EXUART_FCR_TXTL_SH |
73913358d45Spatrick 		    5 << EXUART_FCR_RFDIV_SH |
74013358d45Spatrick 		    1 << EXUART_FCR_RXTL_SH);
74113358d45Spatrick 
74213358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UBIR,
74313358d45Spatrick 		    (exuartdefaultrate / 100) - 1);
74413358d45Spatrick 
74513358d45Spatrick 		/* formula: clk / (rfdiv * 1600) */
74613358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UBMR,
74713358d45Spatrick 		    (exccm_get_uartclk() * 1000) / 1600);
74813358d45Spatrick 
74913358d45Spatrick 		SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN);
75013358d45Spatrick 		SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN);
75113358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
75213358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2);
75313358d45Spatrick 
75413358d45Spatrick 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
75513358d45Spatrick 		SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
75613358d45Spatrick 		bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
75713358d45Spatrick #endif
75813358d45Spatrick 
75913358d45Spatrick 		SET(tp->t_state, TS_CARR_ON); /* XXX */
76013358d45Spatrick 
76113358d45Spatrick 
76213358d45Spatrick 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
76313358d45Spatrick 		return EBUSY;
76413358d45Spatrick 	else
76513358d45Spatrick 		s = spltty();
76613358d45Spatrick 
76713358d45Spatrick 	if (DEVCUA(dev)) {
76813358d45Spatrick 		if (ISSET(tp->t_state, TS_ISOPEN)) {
76913358d45Spatrick 			splx(s);
77013358d45Spatrick 			return EBUSY;
77113358d45Spatrick 		}
77213358d45Spatrick 		sc->sc_cua = 1;
77313358d45Spatrick 	} else {
77413358d45Spatrick 		/* tty (not cua) device; wait for carrier if necessary */
77513358d45Spatrick 		if (ISSET(flag, O_NONBLOCK)) {
77613358d45Spatrick 			if (sc->sc_cua) {
77713358d45Spatrick 				/* Opening TTY non-blocking... but the CUA is busy */
77813358d45Spatrick 				splx(s);
77913358d45Spatrick 				return EBUSY;
78013358d45Spatrick 			}
78113358d45Spatrick 		} else {
78213358d45Spatrick 			while (sc->sc_cua ||
78313358d45Spatrick 			    (!ISSET(tp->t_cflag, CLOCAL) &&
78413358d45Spatrick 				!ISSET(tp->t_state, TS_CARR_ON))) {
78513358d45Spatrick 				SET(tp->t_state, TS_WOPEN);
78613358d45Spatrick 				error = ttysleep(tp, &tp->t_rawq,
78713358d45Spatrick 				    TTIPRI | PCATCH, ttopen);
78813358d45Spatrick 				/*
78913358d45Spatrick 				 * If TS_WOPEN has been reset, that means the
79013358d45Spatrick 				 * cua device has been closed.  We don't want
79113358d45Spatrick 				 * to fail in that case,
79213358d45Spatrick 				 * so just go around again.
79313358d45Spatrick 				 */
79413358d45Spatrick 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
79513358d45Spatrick 					CLR(tp->t_state, TS_WOPEN);
79613358d45Spatrick 					splx(s);
79713358d45Spatrick 					return error;
79813358d45Spatrick 				}
79913358d45Spatrick 			}
80013358d45Spatrick 		}
80113358d45Spatrick 	}
80213358d45Spatrick 	splx(s);
80313358d45Spatrick 
80413358d45Spatrick 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
80513358d45Spatrick }
80613358d45Spatrick 
80713358d45Spatrick int
exuartclose(dev_t dev,int flag,int mode,struct proc * p)80813358d45Spatrick exuartclose(dev_t dev, int flag, int mode, struct proc *p)
80913358d45Spatrick {
81013358d45Spatrick 	int unit = DEVUNIT(dev);
81113358d45Spatrick 	struct exuart_softc *sc = exuart_cd.cd_devs[unit];
81213358d45Spatrick 	//bus_space_tag_t iot = sc->sc_iot;
81313358d45Spatrick 	//bus_space_handle_t ioh = sc->sc_ioh;
81413358d45Spatrick 	struct tty *tp = sc->sc_tty;
81513358d45Spatrick 	int s;
81613358d45Spatrick 
81713358d45Spatrick 	/* XXX This is for cons.c. */
81813358d45Spatrick 	if (!ISSET(tp->t_state, TS_ISOPEN))
81913358d45Spatrick 		return 0;
82013358d45Spatrick 
82113358d45Spatrick 	(*linesw[tp->t_line].l_close)(tp, flag, p);
82213358d45Spatrick 	s = spltty();
82313358d45Spatrick 	if (ISSET(tp->t_state, TS_WOPEN)) {
82413358d45Spatrick 		/* tty device is waiting for carrier; drop dtr then re-raise */
82513358d45Spatrick 		//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
82613358d45Spatrick 		//bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
82713358d45Spatrick 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
82813358d45Spatrick 	}
82913358d45Spatrick 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
83013358d45Spatrick 	sc->sc_cua = 0;
83113358d45Spatrick 	splx(s);
83213358d45Spatrick 	ttyclose(tp);
83313358d45Spatrick 
83413358d45Spatrick 	return 0;
83513358d45Spatrick }
83613358d45Spatrick 
83713358d45Spatrick int
exuartread(dev_t dev,struct uio * uio,int flag)83813358d45Spatrick exuartread(dev_t dev, struct uio *uio, int flag)
83913358d45Spatrick {
84013358d45Spatrick 	struct tty *tty;
84113358d45Spatrick 
84213358d45Spatrick 	tty = exuarttty(dev);
84313358d45Spatrick 	if (tty == NULL)
84413358d45Spatrick 		return ENODEV;
84513358d45Spatrick 
84613358d45Spatrick 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
84713358d45Spatrick }
84813358d45Spatrick 
84913358d45Spatrick int
exuartwrite(dev_t dev,struct uio * uio,int flag)85013358d45Spatrick exuartwrite(dev_t dev, struct uio *uio, int flag)
85113358d45Spatrick {
85213358d45Spatrick 	struct tty *tty;
85313358d45Spatrick 
85413358d45Spatrick 	tty = exuarttty(dev);
85513358d45Spatrick 	if (tty == NULL)
85613358d45Spatrick 		return ENODEV;
85713358d45Spatrick 
85813358d45Spatrick 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
85913358d45Spatrick }
86013358d45Spatrick 
86113358d45Spatrick int
exuartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)86213358d45Spatrick exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
86313358d45Spatrick {
86413358d45Spatrick 	struct exuart_softc *sc;
86513358d45Spatrick 	struct tty *tp;
86613358d45Spatrick 	int error;
86713358d45Spatrick 
86813358d45Spatrick 	sc = exuart_sc(dev);
86913358d45Spatrick 	if (sc == NULL)
87013358d45Spatrick 		return (ENODEV);
87113358d45Spatrick 
87213358d45Spatrick 	tp = sc->sc_tty;
87313358d45Spatrick 	if (tp == NULL)
87413358d45Spatrick 		return (ENXIO);
87513358d45Spatrick 
87613358d45Spatrick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
87713358d45Spatrick 	if (error >= 0)
87813358d45Spatrick 		return (error);
87913358d45Spatrick 
88013358d45Spatrick 	error = ttioctl(tp, cmd, data, flag, p);
88113358d45Spatrick 	if (error >= 0)
88213358d45Spatrick 		return (error);
88313358d45Spatrick 
88413358d45Spatrick 	switch(cmd) {
88513358d45Spatrick 	case TIOCSBRK:
88613358d45Spatrick 		/* */
88713358d45Spatrick 		break;
88813358d45Spatrick 
88913358d45Spatrick 	case TIOCCBRK:
89013358d45Spatrick 		/* */
89113358d45Spatrick 		break;
89213358d45Spatrick 
89313358d45Spatrick 	case TIOCSDTR:
89413358d45Spatrick #if 0
89513358d45Spatrick 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
89613358d45Spatrick #endif
89713358d45Spatrick 		break;
89813358d45Spatrick 
89913358d45Spatrick 	case TIOCCDTR:
90013358d45Spatrick #if 0
90113358d45Spatrick 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
90213358d45Spatrick #endif
90313358d45Spatrick 		break;
90413358d45Spatrick 
90513358d45Spatrick 	case TIOCMSET:
90613358d45Spatrick #if 0
90713358d45Spatrick 		(void) clmctl(dev, *(int *) data, DMSET);
90813358d45Spatrick #endif
90913358d45Spatrick 		break;
91013358d45Spatrick 
91113358d45Spatrick 	case TIOCMBIS:
91213358d45Spatrick #if 0
91313358d45Spatrick 		(void) clmctl(dev, *(int *) data, DMBIS);
91413358d45Spatrick #endif
91513358d45Spatrick 		break;
91613358d45Spatrick 
91713358d45Spatrick 	case TIOCMBIC:
91813358d45Spatrick #if 0
91913358d45Spatrick 		(void) clmctl(dev, *(int *) data, DMBIC);
92013358d45Spatrick #endif
92113358d45Spatrick 		break;
92213358d45Spatrick 
92313358d45Spatrick         case TIOCMGET:
92413358d45Spatrick #if 0
92513358d45Spatrick 		*(int *)data = clmctl(dev, 0, DMGET);
92613358d45Spatrick #endif
92713358d45Spatrick 		break;
92813358d45Spatrick 
92913358d45Spatrick 	case TIOCGFLAGS:
93013358d45Spatrick #if 0
93113358d45Spatrick 		*(int *)data = cl->cl_swflags;
93213358d45Spatrick #endif
93313358d45Spatrick 		break;
93413358d45Spatrick 
93513358d45Spatrick 	case TIOCSFLAGS:
93613358d45Spatrick 		error = suser(p);
93713358d45Spatrick 		if (error != 0)
93813358d45Spatrick 			return(EPERM);
93913358d45Spatrick 
94013358d45Spatrick #if 0
94113358d45Spatrick 		cl->cl_swflags = *(int *)data;
94213358d45Spatrick 		cl->cl_swflags &= /* only allow valid flags */
94313358d45Spatrick 		    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
94413358d45Spatrick #endif
94513358d45Spatrick 		break;
94613358d45Spatrick 	default:
94713358d45Spatrick 		return (ENOTTY);
94813358d45Spatrick 	}
94913358d45Spatrick 
95013358d45Spatrick 	return 0;
95113358d45Spatrick }
95213358d45Spatrick 
95313358d45Spatrick int
exuartstop(struct tty * tp,int flag)95413358d45Spatrick exuartstop(struct tty *tp, int flag)
95513358d45Spatrick {
95613358d45Spatrick 	return 0;
95713358d45Spatrick }
95813358d45Spatrick 
95913358d45Spatrick struct tty *
exuarttty(dev_t dev)96013358d45Spatrick exuarttty(dev_t dev)
96113358d45Spatrick {
96213358d45Spatrick 	int unit;
96313358d45Spatrick 	struct exuart_softc *sc;
96413358d45Spatrick 	unit = DEVUNIT(dev);
96513358d45Spatrick 	if (unit >= exuart_cd.cd_ndevs)
96613358d45Spatrick 		return NULL;
96713358d45Spatrick 	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
96813358d45Spatrick 	if (sc == NULL)
96913358d45Spatrick 		return NULL;
97013358d45Spatrick 	return sc->sc_tty;
97113358d45Spatrick }
97213358d45Spatrick 
97313358d45Spatrick struct exuart_softc *
exuart_sc(dev_t dev)97413358d45Spatrick exuart_sc(dev_t dev)
97513358d45Spatrick {
97613358d45Spatrick 	int unit;
97713358d45Spatrick 	struct exuart_softc *sc;
97813358d45Spatrick 	unit = DEVUNIT(dev);
97913358d45Spatrick 	if (unit >= exuart_cd.cd_ndevs)
98013358d45Spatrick 		return NULL;
98113358d45Spatrick 	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
98213358d45Spatrick 	return sc;
98313358d45Spatrick }
98413358d45Spatrick 
98513358d45Spatrick 
98613358d45Spatrick /* serial console */
98713358d45Spatrick void
exuartcnprobe(struct consdev * cp)98813358d45Spatrick exuartcnprobe(struct consdev *cp)
98913358d45Spatrick {
99013358d45Spatrick }
99113358d45Spatrick 
99213358d45Spatrick void
exuartcninit(struct consdev * cp)99313358d45Spatrick exuartcninit(struct consdev *cp)
99413358d45Spatrick {
99513358d45Spatrick }
99613358d45Spatrick 
99713358d45Spatrick int
exuartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)99813358d45Spatrick exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
99913358d45Spatrick {
100013358d45Spatrick 	static struct consdev exuartcons = {
100113358d45Spatrick 		NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL,
100213358d45Spatrick 		NODEV, CN_MIDPRI
100313358d45Spatrick 	};
1004308e62c2Spatrick 	int maj;
100513358d45Spatrick 
100613358d45Spatrick 	if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh))
100713358d45Spatrick 		return ENOMEM;
100813358d45Spatrick 
1009308e62c2Spatrick 	/* Look for major of com(4) to replace. */
1010308e62c2Spatrick 	for (maj = 0; maj < nchrdev; maj++)
1011308e62c2Spatrick 		if (cdevsw[maj].d_open == comopen)
1012308e62c2Spatrick 			break;
1013308e62c2Spatrick 	if (maj == nchrdev)
1014308e62c2Spatrick 		return ENXIO;
1015308e62c2Spatrick 
101613358d45Spatrick 	cn_tab = &exuartcons;
1017308e62c2Spatrick 	cn_tab->cn_dev = makedev(maj, 0);
1018308e62c2Spatrick 	cdevsw[maj] = exuartdev; 	/* KLUDGE */
101913358d45Spatrick 
102013358d45Spatrick 	exuartconsiot = iot;
102113358d45Spatrick 	exuartconsaddr = iobase;
102213358d45Spatrick 	exuartconscflag = cflag;
102313358d45Spatrick 
102413358d45Spatrick 	return 0;
102513358d45Spatrick }
102613358d45Spatrick 
102713358d45Spatrick int
exuartcngetc(dev_t dev)102813358d45Spatrick exuartcngetc(dev_t dev)
102913358d45Spatrick {
103013358d45Spatrick 	int c;
103113358d45Spatrick 	int s;
103213358d45Spatrick 	s = splhigh();
103313358d45Spatrick 	while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
103413358d45Spatrick 	    EXUART_UTRSTAT_RXBREADY) == 0 &&
103513358d45Spatrick 	      (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
103670a1cc2bSkettenis 	    (exuart_rx_fifo_cnt_mask | exuart_rx_fifo_full)) == 0)
103713358d45Spatrick 		;
103870a1cc2bSkettenis 	c = bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_URXH);
103913358d45Spatrick 	splx(s);
104013358d45Spatrick 	return c;
104113358d45Spatrick }
104213358d45Spatrick 
104313358d45Spatrick void
exuartcnputc(dev_t dev,int c)104413358d45Spatrick exuartcnputc(dev_t dev, int c)
104513358d45Spatrick {
104613358d45Spatrick 	int s;
104713358d45Spatrick 	s = splhigh();
104813358d45Spatrick 	while (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
104970a1cc2bSkettenis 	   exuart_tx_fifo_full)
105013358d45Spatrick 		;
105170a1cc2bSkettenis 	bus_space_write_4(exuartconsiot, exuartconsioh, EXUART_UTXH, c);
105213358d45Spatrick 	splx(s);
105313358d45Spatrick }
105413358d45Spatrick 
105513358d45Spatrick void
exuartcnpollc(dev_t dev,int on)105613358d45Spatrick exuartcnpollc(dev_t dev, int on)
105713358d45Spatrick {
105813358d45Spatrick }
1059