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, ®))
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