1*467651faSkettenis /* $OpenBSD: amluart.c,v 1.4 2022/07/15 17:14:49 kettenis Exp $ */
29d94a3b6Skettenis /*
39d94a3b6Skettenis * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
49d94a3b6Skettenis *
59d94a3b6Skettenis * Permission to use, copy, modify, and distribute this software for any
69d94a3b6Skettenis * purpose with or without fee is hereby granted, provided that the above
79d94a3b6Skettenis * copyright notice and this permission notice appear in all copies.
89d94a3b6Skettenis *
99d94a3b6Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109d94a3b6Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119d94a3b6Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129d94a3b6Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139d94a3b6Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149d94a3b6Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159d94a3b6Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169d94a3b6Skettenis */
179d94a3b6Skettenis
189d94a3b6Skettenis #include <sys/param.h>
199d94a3b6Skettenis #include <sys/conf.h>
209d94a3b6Skettenis #include <sys/fcntl.h>
219d94a3b6Skettenis #include <sys/proc.h>
229d94a3b6Skettenis #include <sys/systm.h>
239d94a3b6Skettenis #include <sys/tty.h>
249d94a3b6Skettenis
259d94a3b6Skettenis #include <machine/bus.h>
269d94a3b6Skettenis #include <machine/fdt.h>
279d94a3b6Skettenis
289d94a3b6Skettenis #include <dev/cons.h>
299d94a3b6Skettenis
309d94a3b6Skettenis #include <dev/ofw/fdt.h>
319d94a3b6Skettenis #include <dev/ofw/openfirm.h>
329d94a3b6Skettenis
339d94a3b6Skettenis #define UART_WFIFO 0x0000
349d94a3b6Skettenis #define UART_RFIFO 0x0004
359d94a3b6Skettenis #define UART_CONTROL 0x0008
369d94a3b6Skettenis #define UART_CONTROL_TX_INT (1 << 28)
379d94a3b6Skettenis #define UART_CONTROL_RX_INT (1 << 27)
389d94a3b6Skettenis #define UART_CONTROL_CLEAR_ERROR (1 << 24)
399d94a3b6Skettenis #define UART_STATUS 0x000c
409d94a3b6Skettenis #define UART_STATUS_RX_FIFO_OVERFLOW (1 << 24)
419d94a3b6Skettenis #define UART_STATUS_TX_FIFO_FULL (1 << 21)
429d94a3b6Skettenis #define UART_STATUS_RX_FIFO_EMPTY (1 << 20)
439d94a3b6Skettenis #define UART_STATUS_FRAME_ERROR (1 << 17)
449d94a3b6Skettenis #define UART_STATUS_PARITY_ERROR (1 << 16)
459d94a3b6Skettenis #define UART_STATUS_ERROR (1 << 24 | 0x7 << 16)
469d94a3b6Skettenis #define UART_MISC 0x0010
479d94a3b6Skettenis #define UART_MISC_TX_INT_CNT_MASK (0xff << 16)
489d94a3b6Skettenis #define UART_MISC_TX_INT_CNT_SHIFT 16
499d94a3b6Skettenis #define UART_MISC_RX_INT_CNT_MASK (0xff << 0)
509d94a3b6Skettenis #define UART_MISC_RX_INT_CNT_SHIFT 0
519d94a3b6Skettenis
529d94a3b6Skettenis #define UART_SPACE 24
539d94a3b6Skettenis
549d94a3b6Skettenis #define HREAD4(sc, reg) \
559d94a3b6Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
569d94a3b6Skettenis #define HWRITE4(sc, reg, val) \
579d94a3b6Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
589d94a3b6Skettenis #define HSET4(sc, reg, bits) \
599d94a3b6Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
609d94a3b6Skettenis #define HCLR4(sc, reg, bits) \
619d94a3b6Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
629d94a3b6Skettenis
639d94a3b6Skettenis cdev_decl(com);
649d94a3b6Skettenis cdev_decl(amluart);
659d94a3b6Skettenis
669d94a3b6Skettenis #define DEVUNIT(x) (minor(x) & 0x7f)
679d94a3b6Skettenis #define DEVCUA(x) (minor(x) & 0x80)
689d94a3b6Skettenis
699d94a3b6Skettenis struct cdevsw amluartdev = cdev_tty_init(3, amluart);
709d94a3b6Skettenis
719d94a3b6Skettenis struct amluart_softc {
729d94a3b6Skettenis struct device sc_dev;
739d94a3b6Skettenis bus_space_tag_t sc_iot;
749d94a3b6Skettenis bus_space_handle_t sc_ioh;
759d94a3b6Skettenis
769d94a3b6Skettenis struct soft_intrhand *sc_si;
779d94a3b6Skettenis void *sc_ih;
789d94a3b6Skettenis
799d94a3b6Skettenis struct tty *sc_tty;
809d94a3b6Skettenis int sc_conspeed;
819d94a3b6Skettenis int sc_floods;
829d94a3b6Skettenis int sc_overflows;
839d94a3b6Skettenis int sc_halt;
849d94a3b6Skettenis int sc_cua;
859d94a3b6Skettenis int *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
869d94a3b6Skettenis #define AMLUART_IBUFSIZE 128
879d94a3b6Skettenis #define AMLUART_IHIGHWATER 100
889d94a3b6Skettenis int sc_ibufs[2][AMLUART_IBUFSIZE];
899d94a3b6Skettenis };
909d94a3b6Skettenis
919d94a3b6Skettenis int amluart_match(struct device *, void *, void *);
929d94a3b6Skettenis void amluart_attach(struct device *, struct device *, void *);
939d94a3b6Skettenis
949d94a3b6Skettenis struct cfdriver amluart_cd = {
959d94a3b6Skettenis NULL, "amluart", DV_TTY
969d94a3b6Skettenis };
979d94a3b6Skettenis
989fdf0c62Smpi const struct cfattach amluart_ca = {
999d94a3b6Skettenis sizeof(struct amluart_softc), amluart_match, amluart_attach
1009d94a3b6Skettenis };
1019d94a3b6Skettenis
1029d94a3b6Skettenis bus_space_tag_t amluartconsiot;
1039d94a3b6Skettenis bus_space_handle_t amluartconsioh;
1049d94a3b6Skettenis
1059d94a3b6Skettenis struct amluart_softc *amluart_sc(dev_t);
1069d94a3b6Skettenis
1079d94a3b6Skettenis int amluart_intr(void *);
1089d94a3b6Skettenis void amluart_softintr(void *);
1099d94a3b6Skettenis void amluart_start(struct tty *);
1109d94a3b6Skettenis
1119d94a3b6Skettenis int amluartcnattach(bus_space_tag_t, bus_addr_t);
1129d94a3b6Skettenis int amluartcngetc(dev_t);
1139d94a3b6Skettenis void amluartcnputc(dev_t, int);
1149d94a3b6Skettenis void amluartcnpollc(dev_t, int);
1159d94a3b6Skettenis
1169d94a3b6Skettenis void
amluart_init_cons(void)1179d94a3b6Skettenis amluart_init_cons(void)
1189d94a3b6Skettenis {
1199d94a3b6Skettenis struct fdt_reg reg;
1209d94a3b6Skettenis void *node;
1219d94a3b6Skettenis
1229d94a3b6Skettenis if ((node = fdt_find_cons("amlogic,meson-gx-uart")) == NULL)
1239d94a3b6Skettenis return;
1249d94a3b6Skettenis if (fdt_get_reg(node, 0, ®))
1259d94a3b6Skettenis return;
1269d94a3b6Skettenis
1279d94a3b6Skettenis amluartcnattach(fdt_cons_bs_tag, reg.addr);
1289d94a3b6Skettenis }
1299d94a3b6Skettenis
1309d94a3b6Skettenis int
amluart_match(struct device * parent,void * match,void * aux)1319d94a3b6Skettenis amluart_match(struct device *parent, void *match, void *aux)
1329d94a3b6Skettenis {
1339d94a3b6Skettenis struct fdt_attach_args *faa = aux;
1349d94a3b6Skettenis
1359d94a3b6Skettenis return OF_is_compatible(faa->fa_node, "amlogic,meson-gx-uart");
1369d94a3b6Skettenis }
1379d94a3b6Skettenis
1389d94a3b6Skettenis void
amluart_attach(struct device * parent,struct device * self,void * aux)1399d94a3b6Skettenis amluart_attach(struct device *parent, struct device *self, void *aux)
1409d94a3b6Skettenis {
1419d94a3b6Skettenis struct amluart_softc *sc = (struct amluart_softc *)self;
1429d94a3b6Skettenis struct fdt_attach_args *faa = aux;
1439d94a3b6Skettenis uint32_t reg;
1449d94a3b6Skettenis int maj;
1459d94a3b6Skettenis
1469d94a3b6Skettenis if (faa->fa_nreg < 1) {
1479d94a3b6Skettenis printf(": no registers\n");
1489d94a3b6Skettenis return;
1499d94a3b6Skettenis }
1509d94a3b6Skettenis
1519d94a3b6Skettenis sc->sc_iot = faa->fa_iot;
1529d94a3b6Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1539d94a3b6Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1549d94a3b6Skettenis printf(": can't map registers\n");
1559d94a3b6Skettenis return;
1569d94a3b6Skettenis }
1579d94a3b6Skettenis
1589d94a3b6Skettenis if (faa->fa_node == stdout_node) {
1599d94a3b6Skettenis /* Locate the major number. */
1609d94a3b6Skettenis for (maj = 0; maj < nchrdev; maj++)
1619d94a3b6Skettenis if (cdevsw[maj].d_open == amluartopen)
1629d94a3b6Skettenis break;
1639d94a3b6Skettenis cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
1649d94a3b6Skettenis sc->sc_conspeed = stdout_speed;
1659d94a3b6Skettenis printf(": console");
1669d94a3b6Skettenis }
1679d94a3b6Skettenis
1689d94a3b6Skettenis sc->sc_si = softintr_establish(IPL_TTY, amluart_softintr, sc);
1699d94a3b6Skettenis if (sc->sc_si == NULL) {
1709d94a3b6Skettenis printf(": can't establish soft interrupt\n");
1719d94a3b6Skettenis return;
1729d94a3b6Skettenis }
1739d94a3b6Skettenis
1749d94a3b6Skettenis sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
1759d94a3b6Skettenis amluart_intr, sc, sc->sc_dev.dv_xname);
1769d94a3b6Skettenis if (sc->sc_ih == NULL) {
1779d94a3b6Skettenis printf(": can't establish hard interrupt\n");
1789d94a3b6Skettenis return;
1799d94a3b6Skettenis }
1809d94a3b6Skettenis
1819d94a3b6Skettenis printf("\n");
1829d94a3b6Skettenis
1839d94a3b6Skettenis /*
1849d94a3b6Skettenis * Generate interrupts if the Tx FIFO is half-empty or if
1859d94a3b6Skettenis * there is anything in the Rx FIFO.
1869d94a3b6Skettenis */
1879d94a3b6Skettenis reg = HREAD4(sc, UART_MISC);
1889d94a3b6Skettenis reg &= ~UART_MISC_TX_INT_CNT_MASK;
1899d94a3b6Skettenis reg |= (32 << UART_MISC_TX_INT_CNT_SHIFT);
1909d94a3b6Skettenis reg &= ~UART_MISC_RX_INT_CNT_MASK;
1919d94a3b6Skettenis reg |= (1 << UART_MISC_RX_INT_CNT_SHIFT);
1929d94a3b6Skettenis HWRITE4(sc, UART_MISC, reg);
1939d94a3b6Skettenis }
1949d94a3b6Skettenis
1959d94a3b6Skettenis int
amluart_intr(void * arg)1969d94a3b6Skettenis amluart_intr(void *arg)
1979d94a3b6Skettenis {
1989d94a3b6Skettenis struct amluart_softc *sc = arg;
1999d94a3b6Skettenis struct tty *tp = sc->sc_tty;
2009d94a3b6Skettenis int *p;
2019d94a3b6Skettenis u_int32_t stat;
2029d94a3b6Skettenis u_char c;
2039d94a3b6Skettenis int handled = 0;
2049d94a3b6Skettenis
2059d94a3b6Skettenis if (tp == NULL)
2069d94a3b6Skettenis return 0;
2079d94a3b6Skettenis
2089d94a3b6Skettenis stat = HREAD4(sc, UART_STATUS);
2099d94a3b6Skettenis if (!ISSET(stat, UART_STATUS_TX_FIFO_FULL) &&
2109d94a3b6Skettenis ISSET(tp->t_state, TS_BUSY)) {
2119d94a3b6Skettenis CLR(tp->t_state, TS_BUSY | TS_FLUSH);
2129d94a3b6Skettenis if (sc->sc_halt > 0)
2139d94a3b6Skettenis wakeup(&tp->t_outq);
2149d94a3b6Skettenis (*linesw[tp->t_line].l_start)(tp);
2159d94a3b6Skettenis handled = 1;
2169d94a3b6Skettenis }
2179d94a3b6Skettenis
2189d94a3b6Skettenis p = sc->sc_ibufp;
2199d94a3b6Skettenis while (!ISSET(stat, UART_STATUS_RX_FIFO_EMPTY)) {
2209d94a3b6Skettenis c = HREAD4(sc, UART_RFIFO);
2219d94a3b6Skettenis if (ISSET(stat, UART_STATUS_FRAME_ERROR))
2229d94a3b6Skettenis c |= TTY_FE;
2239d94a3b6Skettenis if (ISSET(stat, UART_STATUS_PARITY_ERROR))
2249d94a3b6Skettenis c |= TTY_PE;
2259d94a3b6Skettenis if (ISSET(stat, UART_STATUS_RX_FIFO_OVERFLOW))
2269d94a3b6Skettenis sc->sc_overflows++;
2279d94a3b6Skettenis
2289d94a3b6Skettenis if (p >= sc->sc_ibufend)
2299d94a3b6Skettenis sc->sc_floods++;
2309d94a3b6Skettenis else
2319d94a3b6Skettenis *p++ = c;
2329d94a3b6Skettenis
2339d94a3b6Skettenis if (stat & UART_STATUS_ERROR)
2349d94a3b6Skettenis HSET4(sc, UART_CONTROL, UART_CONTROL_CLEAR_ERROR);
2359d94a3b6Skettenis stat = HREAD4(sc, UART_STATUS);
2369d94a3b6Skettenis handled = 1;
2379d94a3b6Skettenis }
2389d94a3b6Skettenis if (sc->sc_ibufp != p) {
2399d94a3b6Skettenis sc->sc_ibufp = p;
2409d94a3b6Skettenis softintr_schedule(sc->sc_si);
2419d94a3b6Skettenis }
2429d94a3b6Skettenis
2439d94a3b6Skettenis return handled;
2449d94a3b6Skettenis }
2459d94a3b6Skettenis
2469d94a3b6Skettenis void
amluart_softintr(void * arg)2479d94a3b6Skettenis amluart_softintr(void *arg)
2489d94a3b6Skettenis {
2499d94a3b6Skettenis struct amluart_softc *sc = arg;
2509d94a3b6Skettenis struct tty *tp = sc->sc_tty;
2519d94a3b6Skettenis int *ibufp, *ibufend;
2529d94a3b6Skettenis int s;
2539d94a3b6Skettenis
2549d94a3b6Skettenis if (sc->sc_ibufp == sc->sc_ibuf)
2559d94a3b6Skettenis return;
2569d94a3b6Skettenis
2579d94a3b6Skettenis s = spltty();
2589d94a3b6Skettenis
2599d94a3b6Skettenis ibufp = sc->sc_ibuf;
2609d94a3b6Skettenis ibufend = sc->sc_ibufp;
2619d94a3b6Skettenis
2629d94a3b6Skettenis if (ibufp == ibufend) {
2639d94a3b6Skettenis splx(s);
2649d94a3b6Skettenis return;
2659d94a3b6Skettenis }
2669d94a3b6Skettenis
2679d94a3b6Skettenis sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
2689d94a3b6Skettenis sc->sc_ibufs[1] : sc->sc_ibufs[0];
2699d94a3b6Skettenis sc->sc_ibufhigh = sc->sc_ibuf + AMLUART_IHIGHWATER;
2709d94a3b6Skettenis sc->sc_ibufend = sc->sc_ibuf + AMLUART_IBUFSIZE;
2719d94a3b6Skettenis
2729d94a3b6Skettenis if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
2739d94a3b6Skettenis splx(s);
2749d94a3b6Skettenis return;
2759d94a3b6Skettenis }
2769d94a3b6Skettenis
2779d94a3b6Skettenis splx(s);
2789d94a3b6Skettenis
279*467651faSkettenis while (ibufp < ibufend) {
280*467651faSkettenis int i = *ibufp++;
281*467651faSkettenis #ifdef DDB
282*467651faSkettenis if (tp->t_dev == cn_tab->cn_dev) {
283*467651faSkettenis int j = db_rint(i);
284*467651faSkettenis
285*467651faSkettenis if (j == 1) /* Escape received, skip */
286*467651faSkettenis continue;
287*467651faSkettenis if (j == 2) /* Second char wasn't 'D' */
288*467651faSkettenis (*linesw[tp->t_line].l_rint)(27, tp);
289*467651faSkettenis }
290*467651faSkettenis #endif
291*467651faSkettenis (*linesw[tp->t_line].l_rint)(i, tp);
292*467651faSkettenis }
2939d94a3b6Skettenis }
2949d94a3b6Skettenis
2959d94a3b6Skettenis int
amluart_param(struct tty * tp,struct termios * t)2969d94a3b6Skettenis amluart_param(struct tty *tp, struct termios *t)
2979d94a3b6Skettenis {
2989d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(tp->t_dev);
2999d94a3b6Skettenis int ospeed = t->c_ospeed;
3009d94a3b6Skettenis
3019d94a3b6Skettenis /* Check requested parameters. */
3029d94a3b6Skettenis if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
3039d94a3b6Skettenis return EINVAL;
3049d94a3b6Skettenis
3059d94a3b6Skettenis switch (ISSET(t->c_cflag, CSIZE)) {
3069d94a3b6Skettenis case CS5:
3079d94a3b6Skettenis case CS6:
3089d94a3b6Skettenis case CS7:
3099d94a3b6Skettenis return EINVAL;
3109d94a3b6Skettenis case CS8:
3119d94a3b6Skettenis break;
3129d94a3b6Skettenis }
3139d94a3b6Skettenis
3149d94a3b6Skettenis if (ospeed != 0) {
3159d94a3b6Skettenis while (ISSET(tp->t_state, TS_BUSY)) {
3169d94a3b6Skettenis int error;
3179d94a3b6Skettenis
3189d94a3b6Skettenis sc->sc_halt++;
3199d94a3b6Skettenis error = ttysleep(tp, &tp->t_outq,
3209d94a3b6Skettenis TTOPRI | PCATCH, "amluprm");
3219d94a3b6Skettenis sc->sc_halt--;
3229d94a3b6Skettenis if (error) {
3239d94a3b6Skettenis amluart_start(tp);
3249d94a3b6Skettenis return error;
3259d94a3b6Skettenis }
3269d94a3b6Skettenis }
3279d94a3b6Skettenis }
3289d94a3b6Skettenis
3299d94a3b6Skettenis tp->t_ispeed = t->c_ispeed;
3309d94a3b6Skettenis tp->t_ospeed = t->c_ospeed;
3319d94a3b6Skettenis tp->t_cflag = t->c_cflag;
3329d94a3b6Skettenis
3339d94a3b6Skettenis /* Just to be sure... */
3349d94a3b6Skettenis amluart_start(tp);
3359d94a3b6Skettenis return 0;
3369d94a3b6Skettenis }
3379d94a3b6Skettenis
3389d94a3b6Skettenis void
amluart_start(struct tty * tp)3399d94a3b6Skettenis amluart_start(struct tty *tp)
3409d94a3b6Skettenis {
3419d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(tp->t_dev);
3429d94a3b6Skettenis int stat;
3439d94a3b6Skettenis int s;
3449d94a3b6Skettenis
3459d94a3b6Skettenis s = spltty();
3469d94a3b6Skettenis if (ISSET(tp->t_state, TS_BUSY))
3479d94a3b6Skettenis goto out;
3489d94a3b6Skettenis if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
3499d94a3b6Skettenis goto out;
3509d94a3b6Skettenis ttwakeupwr(tp);
3519d94a3b6Skettenis if (tp->t_outq.c_cc == 0)
3529d94a3b6Skettenis goto out;
3539d94a3b6Skettenis SET(tp->t_state, TS_BUSY);
3549d94a3b6Skettenis
3559d94a3b6Skettenis stat = HREAD4(sc, UART_STATUS);
3569d94a3b6Skettenis while ((stat & UART_STATUS_TX_FIFO_FULL) == 0) {
3579d94a3b6Skettenis HWRITE4(sc, UART_WFIFO, getc(&tp->t_outq));
3589d94a3b6Skettenis stat = HREAD4(sc, UART_STATUS);
3599d94a3b6Skettenis }
3609d94a3b6Skettenis out:
3619d94a3b6Skettenis splx(s);
3629d94a3b6Skettenis }
3639d94a3b6Skettenis
3649d94a3b6Skettenis int
amluartopen(dev_t dev,int flag,int mode,struct proc * p)3659d94a3b6Skettenis amluartopen(dev_t dev, int flag, int mode, struct proc *p)
3669d94a3b6Skettenis {
3679d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(dev);
3689d94a3b6Skettenis struct tty *tp;
3699d94a3b6Skettenis int error;
3709d94a3b6Skettenis int s;
3719d94a3b6Skettenis
3729d94a3b6Skettenis if (sc == NULL)
3739d94a3b6Skettenis return ENXIO;
3749d94a3b6Skettenis
3759d94a3b6Skettenis s = spltty();
3769d94a3b6Skettenis if (sc->sc_tty == NULL)
3779d94a3b6Skettenis tp = sc->sc_tty = ttymalloc(0);
3789d94a3b6Skettenis else
3799d94a3b6Skettenis tp = sc->sc_tty;
3809d94a3b6Skettenis splx(s);
3819d94a3b6Skettenis
3829d94a3b6Skettenis tp->t_oproc = amluart_start;
3839d94a3b6Skettenis tp->t_param = amluart_param;
3849d94a3b6Skettenis tp->t_dev = dev;
3859d94a3b6Skettenis
3869d94a3b6Skettenis if (!ISSET(tp->t_state, TS_ISOPEN)) {
3879d94a3b6Skettenis SET(tp->t_state, TS_WOPEN);
3889d94a3b6Skettenis ttychars(tp);
3899d94a3b6Skettenis tp->t_iflag = TTYDEF_IFLAG;
3909d94a3b6Skettenis tp->t_oflag = TTYDEF_OFLAG;
3919d94a3b6Skettenis tp->t_cflag = TTYDEF_CFLAG;
3929d94a3b6Skettenis tp->t_lflag = TTYDEF_LFLAG;
3939d94a3b6Skettenis tp->t_ispeed = tp->t_ospeed =
3949d94a3b6Skettenis sc->sc_conspeed ? sc->sc_conspeed : B115200;
3959d94a3b6Skettenis
3969d94a3b6Skettenis s = spltty();
3979d94a3b6Skettenis
3989d94a3b6Skettenis amluart_param(tp, &tp->t_termios);
3999d94a3b6Skettenis ttsetwater(tp);
4009d94a3b6Skettenis
4019d94a3b6Skettenis sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
4029d94a3b6Skettenis sc->sc_ibufhigh = sc->sc_ibuf + AMLUART_IHIGHWATER;
4039d94a3b6Skettenis sc->sc_ibufend = sc->sc_ibuf + AMLUART_IBUFSIZE;
4049d94a3b6Skettenis
4059d94a3b6Skettenis /* Enable interrupts */
4069d94a3b6Skettenis HSET4(sc, UART_CONTROL,
4079d94a3b6Skettenis UART_CONTROL_TX_INT | UART_CONTROL_RX_INT);
4089d94a3b6Skettenis
4099d94a3b6Skettenis /* No carrier detect support. */
4109d94a3b6Skettenis SET(tp->t_state, TS_CARR_ON);
4119ca4957bSjan } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
4129d94a3b6Skettenis return EBUSY;
4139d94a3b6Skettenis else
4149d94a3b6Skettenis s = spltty();
4159d94a3b6Skettenis
4169d94a3b6Skettenis if (DEVCUA(dev)) {
4179d94a3b6Skettenis if (ISSET(tp->t_state, TS_ISOPEN)) {
4189d94a3b6Skettenis /* Ah, but someone already is dialed in... */
4199d94a3b6Skettenis splx(s);
4209d94a3b6Skettenis return EBUSY;
4219d94a3b6Skettenis }
4229d94a3b6Skettenis sc->sc_cua = 1; /* We go into CUA mode. */
4239d94a3b6Skettenis } else {
4249d94a3b6Skettenis if (ISSET(flag, O_NONBLOCK) && sc->sc_cua) {
4259d94a3b6Skettenis /* Opening TTY non-blocking... but the CUA is busy. */
4269d94a3b6Skettenis splx(s);
4279d94a3b6Skettenis return EBUSY;
4289d94a3b6Skettenis } else {
4299d94a3b6Skettenis while (sc->sc_cua) {
4309d94a3b6Skettenis SET(tp->t_state, TS_WOPEN);
4319d94a3b6Skettenis error = ttysleep(tp, &tp->t_rawq,
4329d94a3b6Skettenis TTIPRI | PCATCH, ttopen);
4339d94a3b6Skettenis /*
4349d94a3b6Skettenis * If TS_WOPEN has been reset, that means the
4359d94a3b6Skettenis * cua device has been closed.
4369d94a3b6Skettenis * We don't want to fail in that case,
4379d94a3b6Skettenis * so just go around again.
4389d94a3b6Skettenis */
4399d94a3b6Skettenis if (error && ISSET(tp->t_state, TS_WOPEN)) {
4409d94a3b6Skettenis CLR(tp->t_state, TS_WOPEN);
4419d94a3b6Skettenis splx(s);
4429d94a3b6Skettenis return error;
4439d94a3b6Skettenis }
4449d94a3b6Skettenis }
4459d94a3b6Skettenis }
4469d94a3b6Skettenis }
4479d94a3b6Skettenis splx(s);
4489d94a3b6Skettenis
4499d94a3b6Skettenis return (*linesw[tp->t_line].l_open)(dev, tp, p);
4509d94a3b6Skettenis }
4519d94a3b6Skettenis
4529d94a3b6Skettenis int
amluartclose(dev_t dev,int flag,int mode,struct proc * p)4539d94a3b6Skettenis amluartclose(dev_t dev, int flag, int mode, struct proc *p)
4549d94a3b6Skettenis {
4559d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(dev);
4569d94a3b6Skettenis struct tty *tp = sc->sc_tty;
4579d94a3b6Skettenis int s;
4589d94a3b6Skettenis
4599d94a3b6Skettenis if (!ISSET(tp->t_state, TS_ISOPEN))
4609d94a3b6Skettenis return 0;
4619d94a3b6Skettenis
4629d94a3b6Skettenis (*linesw[tp->t_line].l_close)(tp, flag, p);
4639d94a3b6Skettenis s = spltty();
4649d94a3b6Skettenis if (!ISSET(tp->t_state, TS_WOPEN)) {
4659d94a3b6Skettenis /* Disable interrupts */
4669d94a3b6Skettenis HCLR4(sc, UART_CONTROL,
4679d94a3b6Skettenis UART_CONTROL_TX_INT | UART_CONTROL_RX_INT);
4689d94a3b6Skettenis }
4699d94a3b6Skettenis CLR(tp->t_state, TS_BUSY | TS_FLUSH);
4709d94a3b6Skettenis sc->sc_cua = 0;
4719d94a3b6Skettenis splx(s);
4729d94a3b6Skettenis ttyclose(tp);
4739d94a3b6Skettenis
4749d94a3b6Skettenis return 0;
4759d94a3b6Skettenis }
4769d94a3b6Skettenis
4779d94a3b6Skettenis int
amluartread(dev_t dev,struct uio * uio,int flag)4789d94a3b6Skettenis amluartread(dev_t dev, struct uio *uio, int flag)
4799d94a3b6Skettenis {
4809d94a3b6Skettenis struct tty *tp = amluarttty(dev);
4819d94a3b6Skettenis
4829d94a3b6Skettenis if (tp == NULL)
4839d94a3b6Skettenis return ENODEV;
4849d94a3b6Skettenis
4859d94a3b6Skettenis return (*linesw[tp->t_line].l_read)(tp, uio, flag);
4869d94a3b6Skettenis }
4879d94a3b6Skettenis
4889d94a3b6Skettenis int
amluartwrite(dev_t dev,struct uio * uio,int flag)4899d94a3b6Skettenis amluartwrite(dev_t dev, struct uio *uio, int flag)
4909d94a3b6Skettenis {
4919d94a3b6Skettenis struct tty *tp = amluarttty(dev);
4929d94a3b6Skettenis
4939d94a3b6Skettenis if (tp == NULL)
4949d94a3b6Skettenis return ENODEV;
4959d94a3b6Skettenis
4969d94a3b6Skettenis return (*linesw[tp->t_line].l_write)(tp, uio, flag);
4979d94a3b6Skettenis }
4989d94a3b6Skettenis
4999d94a3b6Skettenis int
amluartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)5009d94a3b6Skettenis amluartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
5019d94a3b6Skettenis {
5029d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(dev);
5039d94a3b6Skettenis struct tty *tp;
5049d94a3b6Skettenis int error;
5059d94a3b6Skettenis
5069d94a3b6Skettenis if (sc == NULL)
5079d94a3b6Skettenis return ENODEV;
5089d94a3b6Skettenis
5099d94a3b6Skettenis tp = sc->sc_tty;
5109d94a3b6Skettenis if (tp == NULL)
5119d94a3b6Skettenis return ENXIO;
5129d94a3b6Skettenis
5139d94a3b6Skettenis error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
5149d94a3b6Skettenis if (error >= 0)
5159d94a3b6Skettenis return error;
5169d94a3b6Skettenis
5179d94a3b6Skettenis error = ttioctl(tp, cmd, data, flag, p);
5189d94a3b6Skettenis if (error >= 0)
5199d94a3b6Skettenis return error;
5209d94a3b6Skettenis
5219d94a3b6Skettenis switch(cmd) {
5229d94a3b6Skettenis case TIOCSBRK:
5239d94a3b6Skettenis case TIOCCBRK:
5249d94a3b6Skettenis case TIOCSDTR:
5259d94a3b6Skettenis case TIOCCDTR:
5269d94a3b6Skettenis case TIOCMSET:
5279d94a3b6Skettenis case TIOCMBIS:
5289d94a3b6Skettenis case TIOCMBIC:
5299d94a3b6Skettenis case TIOCMGET:
5309d94a3b6Skettenis case TIOCGFLAGS:
5319d94a3b6Skettenis break;
5329d94a3b6Skettenis case TIOCSFLAGS:
5339d94a3b6Skettenis error = suser(p);
5349d94a3b6Skettenis if (error != 0)
5359d94a3b6Skettenis return EPERM;
5369d94a3b6Skettenis break;
5379d94a3b6Skettenis default:
5389d94a3b6Skettenis return ENOTTY;
5399d94a3b6Skettenis }
5409d94a3b6Skettenis
5419d94a3b6Skettenis return 0;
5429d94a3b6Skettenis }
5439d94a3b6Skettenis
5449d94a3b6Skettenis int
amluartstop(struct tty * tp,int flag)5459d94a3b6Skettenis amluartstop(struct tty *tp, int flag)
5469d94a3b6Skettenis {
5479d94a3b6Skettenis return 0;
5489d94a3b6Skettenis }
5499d94a3b6Skettenis
5509d94a3b6Skettenis struct tty *
amluarttty(dev_t dev)5519d94a3b6Skettenis amluarttty(dev_t dev)
5529d94a3b6Skettenis {
5539d94a3b6Skettenis struct amluart_softc *sc = amluart_sc(dev);
5549d94a3b6Skettenis
5559d94a3b6Skettenis if (sc == NULL)
5569d94a3b6Skettenis return NULL;
5579d94a3b6Skettenis return sc->sc_tty;
5589d94a3b6Skettenis }
5599d94a3b6Skettenis
5609d94a3b6Skettenis struct amluart_softc *
amluart_sc(dev_t dev)5619d94a3b6Skettenis amluart_sc(dev_t dev)
5629d94a3b6Skettenis {
5639d94a3b6Skettenis int unit = DEVUNIT(dev);
5649d94a3b6Skettenis
5659d94a3b6Skettenis if (unit >= amluart_cd.cd_ndevs)
5669d94a3b6Skettenis return NULL;
5679d94a3b6Skettenis return (struct amluart_softc *)amluart_cd.cd_devs[unit];
5689d94a3b6Skettenis }
5699d94a3b6Skettenis
5709d94a3b6Skettenis int
amluartcnattach(bus_space_tag_t iot,bus_addr_t iobase)5719d94a3b6Skettenis amluartcnattach(bus_space_tag_t iot, bus_addr_t iobase)
5729d94a3b6Skettenis {
5739d94a3b6Skettenis static struct consdev amluartcons = {
5749d94a3b6Skettenis NULL, NULL, amluartcngetc, amluartcnputc, amluartcnpollc, NULL,
5759d94a3b6Skettenis NODEV, CN_MIDPRI
5769d94a3b6Skettenis };
5779d94a3b6Skettenis int maj;
5789d94a3b6Skettenis
5799d94a3b6Skettenis amluartconsiot = iot;
5809d94a3b6Skettenis if (bus_space_map(iot, iobase, UART_SPACE, 0, &amluartconsioh))
5819d94a3b6Skettenis return ENOMEM;
5829d94a3b6Skettenis
5839d94a3b6Skettenis /* Look for major of com(4) to replace. */
5849d94a3b6Skettenis for (maj = 0; maj < nchrdev; maj++)
5859d94a3b6Skettenis if (cdevsw[maj].d_open == comopen)
5869d94a3b6Skettenis break;
5879d94a3b6Skettenis if (maj == nchrdev)
5889d94a3b6Skettenis return ENXIO;
5899d94a3b6Skettenis
5909d94a3b6Skettenis cn_tab = &amluartcons;
5919d94a3b6Skettenis cn_tab->cn_dev = makedev(maj, 0);
5929d94a3b6Skettenis cdevsw[maj] = amluartdev; /* KLUDGE */
5939d94a3b6Skettenis
5949d94a3b6Skettenis return 0;
5959d94a3b6Skettenis }
5969d94a3b6Skettenis
5979d94a3b6Skettenis int
amluartcngetc(dev_t dev)5989d94a3b6Skettenis amluartcngetc(dev_t dev)
5999d94a3b6Skettenis {
6009d94a3b6Skettenis uint8_t c;
6019d94a3b6Skettenis
6029d94a3b6Skettenis while (bus_space_read_4(amluartconsiot, amluartconsioh, UART_STATUS) &
6039d94a3b6Skettenis UART_STATUS_RX_FIFO_EMPTY)
6049d94a3b6Skettenis CPU_BUSY_CYCLE();
6059d94a3b6Skettenis c = bus_space_read_4(amluartconsiot, amluartconsioh, UART_RFIFO);
6069d94a3b6Skettenis return c;
6079d94a3b6Skettenis }
6089d94a3b6Skettenis
6099d94a3b6Skettenis void
amluartcnputc(dev_t dev,int c)6109d94a3b6Skettenis amluartcnputc(dev_t dev, int c)
6119d94a3b6Skettenis {
6129d94a3b6Skettenis while (bus_space_read_4(amluartconsiot, amluartconsioh, UART_STATUS) &
6139d94a3b6Skettenis UART_STATUS_TX_FIFO_FULL)
6149d94a3b6Skettenis CPU_BUSY_CYCLE();
6159d94a3b6Skettenis bus_space_write_4(amluartconsiot, amluartconsioh, UART_WFIFO, c);
6169d94a3b6Skettenis }
6179d94a3b6Skettenis
6189d94a3b6Skettenis void
amluartcnpollc(dev_t dev,int on)6199d94a3b6Skettenis amluartcnpollc(dev_t dev, int on)
6209d94a3b6Skettenis {
6219d94a3b6Skettenis }
622