1*9fdf0c62Smpi /* $OpenBSD: mvuart.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */
263eebed0Spatrick /*
363eebed0Spatrick * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
463eebed0Spatrick * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
563eebed0Spatrick *
663eebed0Spatrick * Permission to use, copy, modify, and distribute this software for any
763eebed0Spatrick * purpose with or without fee is hereby granted, provided that the above
863eebed0Spatrick * copyright notice and this permission notice appear in all copies.
963eebed0Spatrick *
1063eebed0Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1163eebed0Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1263eebed0Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1363eebed0Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1463eebed0Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1563eebed0Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1663eebed0Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1763eebed0Spatrick */
1863eebed0Spatrick
1963eebed0Spatrick #include <sys/param.h>
2063eebed0Spatrick #include <sys/ioctl.h>
2163eebed0Spatrick #include <sys/proc.h>
2263eebed0Spatrick #include <sys/tty.h>
2363eebed0Spatrick #include <sys/systm.h>
2463eebed0Spatrick #include <sys/device.h>
2563eebed0Spatrick #include <sys/conf.h>
2663eebed0Spatrick #include <sys/fcntl.h>
2763eebed0Spatrick
2863eebed0Spatrick #include <machine/bus.h>
2963eebed0Spatrick #include <machine/fdt.h>
3063eebed0Spatrick
3163eebed0Spatrick #include <dev/cons.h>
3263eebed0Spatrick
3363eebed0Spatrick #include <dev/ofw/openfirm.h>
3463eebed0Spatrick #include <dev/ofw/ofw_clock.h>
3563eebed0Spatrick #include <dev/ofw/ofw_pinctrl.h>
3663eebed0Spatrick #include <dev/ofw/fdt.h>
3763eebed0Spatrick
3863eebed0Spatrick #define MVUART_RBR 0x00
3963eebed0Spatrick #define MVUART_TSH 0x04
4063eebed0Spatrick #define MVUART_CTRL 0x08
4163eebed0Spatrick #define MVUART_CTRL_RX_RDY_INT (1 << 4)
4263eebed0Spatrick #define MVUART_CTRL_TX_RDY_INT (1 << 5)
4363eebed0Spatrick #define MVUART_STAT 0x0c
4463eebed0Spatrick #define MVUART_STAT_STD_OVR_ERR (1 << 0)
4563eebed0Spatrick #define MVUART_STAT_STD_PAR_ERR (1 << 1)
4663eebed0Spatrick #define MVUART_STAT_STD_FRM_ERR (1 << 2)
4763eebed0Spatrick #define MVUART_STAT_STD_BRK_DET (1 << 3)
4863eebed0Spatrick #define MVUART_STAT_STD_ERROR_MASK (0xf << 0)
4963eebed0Spatrick #define MVUART_STAT_STD_RX_RDY (1 << 4)
5063eebed0Spatrick #define MVUART_STAT_STD_TX_RDY (1 << 5)
5163eebed0Spatrick #define MVUART_STAT_STD_TX_EMPTY (1 << 6)
5263eebed0Spatrick #define MVUART_STAT_STD_TX_FIFO_FULL (1 << 11)
5363eebed0Spatrick #define MVUART_STAT_STD_TX_FIFO_EMPTY (1 << 13)
5463eebed0Spatrick #define MVUART_BAUD_RATE_DIV 0x10
5563eebed0Spatrick #define MVUART_BAUD_RATE_DIV_MASK 0x3ff
5663eebed0Spatrick
5763eebed0Spatrick #define DEVUNIT(x) (minor(x) & 0x7f)
5863eebed0Spatrick #define DEVCUA(x) (minor(x) & 0x80)
5963eebed0Spatrick
6063eebed0Spatrick #define HREAD4(sc, reg) \
6163eebed0Spatrick (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
6263eebed0Spatrick #define HWRITE4(sc, reg, val) \
6363eebed0Spatrick bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
6463eebed0Spatrick #define HSET4(sc, reg, bits) \
6563eebed0Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
6663eebed0Spatrick #define HCLR4(sc, reg, bits) \
6763eebed0Spatrick HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
6863eebed0Spatrick
6963eebed0Spatrick struct mvuart_softc {
7063eebed0Spatrick struct device sc_dev;
7163eebed0Spatrick bus_space_tag_t sc_iot;
7263eebed0Spatrick bus_space_handle_t sc_ioh;
7363eebed0Spatrick int sc_node;
7463eebed0Spatrick struct soft_intrhand *sc_si;
7563eebed0Spatrick void *sc_ih;
7663eebed0Spatrick struct tty *sc_tty;
7763eebed0Spatrick int sc_floods;
7863eebed0Spatrick int sc_errors;
7963eebed0Spatrick int sc_halt;
8063eebed0Spatrick uint8_t sc_hwflags;
8163eebed0Spatrick #define COM_HW_NOIEN 0x01
8263eebed0Spatrick #define COM_HW_FIFO 0x02
8363eebed0Spatrick #define COM_HW_SIR 0x20
8463eebed0Spatrick #define COM_HW_CONSOLE 0x40
8563eebed0Spatrick uint8_t sc_cua;
8663eebed0Spatrick uint16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
8763eebed0Spatrick #define MVUART_IBUFSIZE 128
8863eebed0Spatrick #define MVUART_IHIGHWATER 100
8963eebed0Spatrick uint16_t sc_ibufs[2][MVUART_IBUFSIZE];
9063eebed0Spatrick };
9163eebed0Spatrick
9263eebed0Spatrick int mvuart_match(struct device *, void *, void *);
9363eebed0Spatrick void mvuart_attach(struct device *, struct device *, void *);
9463eebed0Spatrick
9563eebed0Spatrick void mvuartcnprobe(struct consdev *cp);
9663eebed0Spatrick void mvuartcninit(struct consdev *cp);
9763eebed0Spatrick int mvuartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
9863eebed0Spatrick int mvuartcngetc(dev_t dev);
9963eebed0Spatrick void mvuartcnputc(dev_t dev, int c);
10063eebed0Spatrick void mvuartcnpollc(dev_t dev, int on);
10163eebed0Spatrick int mvuart_param(struct tty *, struct termios *);
10263eebed0Spatrick void mvuart_start(struct tty *);
10363eebed0Spatrick void mvuart_softint(void *arg);
10463eebed0Spatrick
10563eebed0Spatrick struct mvuart_softc *mvuart_sc(dev_t dev);
10663eebed0Spatrick
10763eebed0Spatrick int mvuart_intr(void *);
10863eebed0Spatrick int mvuart_intr_rx(struct mvuart_softc *);
10963eebed0Spatrick int mvuart_intr_tx(struct mvuart_softc *);
11063eebed0Spatrick
11163eebed0Spatrick /* XXX - we imitate 'com' serial ports and take over their entry points */
11263eebed0Spatrick /* XXX: These belong elsewhere */
11363eebed0Spatrick cdev_decl(com);
11463eebed0Spatrick cdev_decl(mvuart);
11563eebed0Spatrick
11663eebed0Spatrick struct cfdriver mvuart_cd = {
11763eebed0Spatrick NULL, "mvuart", DV_TTY
11863eebed0Spatrick };
11963eebed0Spatrick
120*9fdf0c62Smpi const struct cfattach mvuart_ca = {
12163eebed0Spatrick sizeof(struct mvuart_softc), mvuart_match, mvuart_attach
12263eebed0Spatrick };
12363eebed0Spatrick
12463eebed0Spatrick bus_space_tag_t mvuartconsiot;
12563eebed0Spatrick bus_space_handle_t mvuartconsioh;
12663eebed0Spatrick bus_addr_t mvuartconsaddr;
12763eebed0Spatrick
12863eebed0Spatrick struct cdevsw mvuartdev =
12963eebed0Spatrick cdev_tty_init(3/*XXX NMVUART */, mvuart); /* 12: serial port */
13063eebed0Spatrick
13163eebed0Spatrick void
mvuart_init_cons(void)13263eebed0Spatrick mvuart_init_cons(void)
13363eebed0Spatrick {
13463eebed0Spatrick struct fdt_reg reg;
13563eebed0Spatrick void *node;
13663eebed0Spatrick
13763eebed0Spatrick if ((node = fdt_find_cons("marvell,armada-3700-uart")) == NULL)
13863eebed0Spatrick return;
13963eebed0Spatrick
14063eebed0Spatrick if (fdt_get_reg(node, 0, ®))
14163eebed0Spatrick return;
14263eebed0Spatrick
14363eebed0Spatrick mvuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
14463eebed0Spatrick }
14563eebed0Spatrick
14663eebed0Spatrick int
mvuart_match(struct device * parent,void * match,void * aux)14763eebed0Spatrick mvuart_match(struct device *parent, void *match, void *aux)
14863eebed0Spatrick {
14963eebed0Spatrick struct fdt_attach_args *faa = aux;
15063eebed0Spatrick
15163eebed0Spatrick return OF_is_compatible(faa->fa_node, "marvell,armada-3700-uart");
15263eebed0Spatrick }
15363eebed0Spatrick
15463eebed0Spatrick void
mvuart_attach(struct device * parent,struct device * self,void * aux)15563eebed0Spatrick mvuart_attach(struct device *parent, struct device *self, void *aux)
15663eebed0Spatrick {
15763eebed0Spatrick struct mvuart_softc *sc = (struct mvuart_softc *)self;
15863eebed0Spatrick struct fdt_attach_args *faa = aux;
15963eebed0Spatrick int maj;
16063eebed0Spatrick
16163eebed0Spatrick if (faa->fa_nreg < 1)
16263eebed0Spatrick return;
16363eebed0Spatrick
16463eebed0Spatrick pinctrl_byname(faa->fa_node, "default");
16563eebed0Spatrick
16663eebed0Spatrick sc->sc_node = faa->fa_node;
16763eebed0Spatrick sc->sc_iot = faa->fa_iot;
16863eebed0Spatrick if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
16963eebed0Spatrick faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
17063eebed0Spatrick panic("%s: bus_space_map failed", sc->sc_dev.dv_xname);
17163eebed0Spatrick return;
17263eebed0Spatrick }
17363eebed0Spatrick
17463eebed0Spatrick if (faa->fa_reg[0].addr == mvuartconsaddr) {
17563eebed0Spatrick /* Locate the major number. */
17663eebed0Spatrick for (maj = 0; maj < nchrdev; maj++)
17763eebed0Spatrick if (cdevsw[maj].d_open == mvuartopen)
17863eebed0Spatrick break;
17963eebed0Spatrick cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
18063eebed0Spatrick
18163eebed0Spatrick printf(": console");
18263eebed0Spatrick }
18363eebed0Spatrick
18463eebed0Spatrick printf("\n");
18563eebed0Spatrick
18663eebed0Spatrick sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
18763eebed0Spatrick mvuart_intr, sc, sc->sc_dev.dv_xname);
18863eebed0Spatrick if (sc->sc_ih == NULL)
18963eebed0Spatrick panic("%s: can't establish hard interrupt",
19063eebed0Spatrick sc->sc_dev.dv_xname);
19163eebed0Spatrick
19263eebed0Spatrick sc->sc_si = softintr_establish(IPL_TTY, mvuart_softint, sc);
19363eebed0Spatrick if (sc->sc_si == NULL)
19463eebed0Spatrick panic("%s: can't establish soft interrupt",
19563eebed0Spatrick sc->sc_dev.dv_xname);
19663eebed0Spatrick }
19763eebed0Spatrick
19863eebed0Spatrick int
mvuart_intr(void * arg)19963eebed0Spatrick mvuart_intr(void *arg)
20063eebed0Spatrick {
20163eebed0Spatrick struct mvuart_softc *sc = arg;
20263eebed0Spatrick uint32_t stat;
20363eebed0Spatrick int ret = 0;
20463eebed0Spatrick
20563eebed0Spatrick if (sc->sc_tty == NULL)
20663eebed0Spatrick return 0;
20763eebed0Spatrick
20863eebed0Spatrick stat = HREAD4(sc, MVUART_STAT);
20963eebed0Spatrick
21063eebed0Spatrick if ((stat & MVUART_STAT_STD_RX_RDY) != 0)
21163eebed0Spatrick ret |= mvuart_intr_rx(sc);
21263eebed0Spatrick
21363eebed0Spatrick if ((stat & MVUART_STAT_STD_TX_RDY) != 0)
21463eebed0Spatrick ret |= mvuart_intr_tx(sc);
21563eebed0Spatrick
21663eebed0Spatrick return ret;
21763eebed0Spatrick }
21863eebed0Spatrick
21963eebed0Spatrick int
mvuart_intr_rx(struct mvuart_softc * sc)22063eebed0Spatrick mvuart_intr_rx(struct mvuart_softc *sc)
22163eebed0Spatrick {
22263eebed0Spatrick uint32_t stat;
22363eebed0Spatrick uint16_t *p, c;
22463eebed0Spatrick
22563eebed0Spatrick p = sc->sc_ibufp;
22663eebed0Spatrick
22763eebed0Spatrick stat = HREAD4(sc, MVUART_STAT);
22863eebed0Spatrick while ((stat & MVUART_STAT_STD_RX_RDY) != 0) {
22963eebed0Spatrick c = HREAD4(sc, MVUART_RBR);
23063eebed0Spatrick c |= (stat & MVUART_STAT_STD_ERROR_MASK) << 8;
23163eebed0Spatrick if (p >= sc->sc_ibufend) {
23263eebed0Spatrick sc->sc_floods++;
23363eebed0Spatrick } else {
23463eebed0Spatrick *p++ = c;
23563eebed0Spatrick }
23663eebed0Spatrick stat = HREAD4(sc, MVUART_STAT);
23763eebed0Spatrick }
23863eebed0Spatrick sc->sc_ibufp = p;
23963eebed0Spatrick
24063eebed0Spatrick softintr_schedule(sc->sc_si);
24163eebed0Spatrick return 1;
24263eebed0Spatrick }
24363eebed0Spatrick
24463eebed0Spatrick int
mvuart_intr_tx(struct mvuart_softc * sc)24563eebed0Spatrick mvuart_intr_tx(struct mvuart_softc *sc)
24663eebed0Spatrick {
24763eebed0Spatrick struct tty *tp = sc->sc_tty;
24863eebed0Spatrick
24963eebed0Spatrick HCLR4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
25063eebed0Spatrick if (ISSET(tp->t_state, TS_BUSY)) {
25163eebed0Spatrick CLR(tp->t_state, TS_BUSY | TS_FLUSH);
25263eebed0Spatrick if (sc->sc_halt > 0)
25363eebed0Spatrick wakeup(&tp->t_outq);
25463eebed0Spatrick (*linesw[tp->t_line].l_start)(tp);
25563eebed0Spatrick }
25663eebed0Spatrick
25763eebed0Spatrick return 1;
25863eebed0Spatrick }
25963eebed0Spatrick
26063eebed0Spatrick int
mvuart_param(struct tty * tp,struct termios * t)26163eebed0Spatrick mvuart_param(struct tty *tp, struct termios *t)
26263eebed0Spatrick {
26363eebed0Spatrick struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
26463eebed0Spatrick int error, ospeed = t->c_ospeed;
26563eebed0Spatrick tcflag_t oldcflag;
26663eebed0Spatrick
26763eebed0Spatrick if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
26863eebed0Spatrick return EINVAL;
26963eebed0Spatrick
27063eebed0Spatrick switch (ISSET(t->c_cflag, CSIZE)) {
27163eebed0Spatrick case CS5:
27263eebed0Spatrick case CS6:
27363eebed0Spatrick case CS7:
27463eebed0Spatrick return EINVAL;
27563eebed0Spatrick case CS8:
27663eebed0Spatrick break;
27763eebed0Spatrick }
27863eebed0Spatrick
27963eebed0Spatrick if (ospeed != 0) {
28063eebed0Spatrick while (ISSET(tp->t_state, TS_BUSY)) {
28163eebed0Spatrick ++sc->sc_halt;
28263eebed0Spatrick error = ttysleep(tp, &tp->t_outq,
283c8b8fc79Scheloha TTOPRI | PCATCH, "mvuartprm");
28463eebed0Spatrick --sc->sc_halt;
28563eebed0Spatrick if (error) {
28663eebed0Spatrick mvuart_start(tp);
28763eebed0Spatrick return (error);
28863eebed0Spatrick }
28963eebed0Spatrick }
29063eebed0Spatrick }
29163eebed0Spatrick
29263eebed0Spatrick /* and copy to tty */
29363eebed0Spatrick tp->t_ispeed = t->c_ispeed;
29463eebed0Spatrick tp->t_ospeed = t->c_ospeed;
29563eebed0Spatrick oldcflag = tp->t_cflag;
29663eebed0Spatrick tp->t_cflag = t->c_cflag;
29763eebed0Spatrick
29863eebed0Spatrick mvuart_start(tp);
29963eebed0Spatrick return 0;
30063eebed0Spatrick }
30163eebed0Spatrick
30263eebed0Spatrick void
mvuart_start(struct tty * tp)30363eebed0Spatrick mvuart_start(struct tty *tp)
30463eebed0Spatrick {
30563eebed0Spatrick struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
30663eebed0Spatrick uint8_t buf;
30763eebed0Spatrick int i, n, s;
30863eebed0Spatrick
30963eebed0Spatrick s = spltty();
31063eebed0Spatrick if (ISSET(tp->t_state, TS_BUSY)) {
31163eebed0Spatrick splx(s);
31263eebed0Spatrick return;
31363eebed0Spatrick }
31463eebed0Spatrick if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
31563eebed0Spatrick goto out;
31663eebed0Spatrick if (tp->t_outq.c_cc <= tp->t_lowat) {
31763eebed0Spatrick if (ISSET(tp->t_state, TS_ASLEEP)) {
31863eebed0Spatrick CLR(tp->t_state, TS_ASLEEP);
31963eebed0Spatrick wakeup(&tp->t_outq);
32063eebed0Spatrick }
32163eebed0Spatrick if (tp->t_outq.c_cc == 0)
32263eebed0Spatrick goto out;
32363eebed0Spatrick selwakeup(&tp->t_wsel);
32463eebed0Spatrick }
32563eebed0Spatrick SET(tp->t_state, TS_BUSY);
32663eebed0Spatrick
32763eebed0Spatrick for (i = 0; i < 32; i++) {
32863eebed0Spatrick n = q_to_b(&tp->t_outq, &buf, 1);
32963eebed0Spatrick if (n < 1)
33063eebed0Spatrick break;
33163eebed0Spatrick HWRITE4(sc, MVUART_TSH, buf);
33263eebed0Spatrick if (HREAD4(sc, MVUART_STAT) & MVUART_STAT_STD_TX_FIFO_FULL)
33363eebed0Spatrick break;
33463eebed0Spatrick }
33563eebed0Spatrick HSET4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
33663eebed0Spatrick
33763eebed0Spatrick out:
33863eebed0Spatrick splx(s);
33963eebed0Spatrick }
34063eebed0Spatrick
34163eebed0Spatrick void
mvuart_softint(void * arg)34263eebed0Spatrick mvuart_softint(void *arg)
34363eebed0Spatrick {
34463eebed0Spatrick struct mvuart_softc *sc = arg;
34563eebed0Spatrick struct tty *tp;
34663eebed0Spatrick uint16_t *ibufp;
34763eebed0Spatrick uint16_t *ibufend;
34863eebed0Spatrick int c, err, s;
34963eebed0Spatrick
35063eebed0Spatrick if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
35163eebed0Spatrick return;
35263eebed0Spatrick
35363eebed0Spatrick tp = sc->sc_tty;
35463eebed0Spatrick s = spltty();
35563eebed0Spatrick
35663eebed0Spatrick ibufp = sc->sc_ibuf;
35763eebed0Spatrick ibufend = sc->sc_ibufp;
35863eebed0Spatrick
35963eebed0Spatrick if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
36063eebed0Spatrick splx(s);
36163eebed0Spatrick return;
36263eebed0Spatrick }
36363eebed0Spatrick
36463eebed0Spatrick sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
36563eebed0Spatrick sc->sc_ibufs[1] : sc->sc_ibufs[0];
36663eebed0Spatrick sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
36763eebed0Spatrick sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
36863eebed0Spatrick
36963eebed0Spatrick splx(s);
37063eebed0Spatrick
37163eebed0Spatrick while (ibufp < ibufend) {
37263eebed0Spatrick err = 0;
37363eebed0Spatrick c = *ibufp++;
37463eebed0Spatrick if (ISSET(c, (MVUART_STAT_STD_PAR_ERR << 8)))
37563eebed0Spatrick err |= TTY_PE;
37663eebed0Spatrick if (ISSET(c, (MVUART_STAT_STD_FRM_ERR << 8)))
37763eebed0Spatrick err |= TTY_FE;
37863eebed0Spatrick c = (c & 0xff) | err;
37963eebed0Spatrick (*linesw[tp->t_line].l_rint)(c, tp);
38063eebed0Spatrick }
38163eebed0Spatrick }
38263eebed0Spatrick
38363eebed0Spatrick int
mvuartopen(dev_t dev,int flag,int mode,struct proc * p)38463eebed0Spatrick mvuartopen(dev_t dev, int flag, int mode, struct proc *p)
38563eebed0Spatrick {
38663eebed0Spatrick struct mvuart_softc *sc;
38763eebed0Spatrick struct tty *tp;
38863eebed0Spatrick int s, error = 0;
38963eebed0Spatrick
39063eebed0Spatrick sc = mvuart_sc(dev);
39163eebed0Spatrick if (sc == NULL)
39263eebed0Spatrick return ENXIO;
39363eebed0Spatrick
39463eebed0Spatrick s = spltty();
39563eebed0Spatrick if (sc->sc_tty == NULL)
39663eebed0Spatrick tp = sc->sc_tty = ttymalloc(0);
39763eebed0Spatrick else
39863eebed0Spatrick tp = sc->sc_tty;
39963eebed0Spatrick
40063eebed0Spatrick splx(s);
40163eebed0Spatrick
40263eebed0Spatrick tp->t_oproc = mvuart_start;
40363eebed0Spatrick tp->t_param = mvuart_param;
40463eebed0Spatrick tp->t_dev = dev;
40563eebed0Spatrick
40663eebed0Spatrick if (!ISSET(tp->t_state, TS_ISOPEN)) {
40763eebed0Spatrick SET(tp->t_state, TS_WOPEN);
40863eebed0Spatrick ttychars(tp);
40963eebed0Spatrick tp->t_iflag = TTYDEF_IFLAG;
41063eebed0Spatrick tp->t_oflag = TTYDEF_OFLAG;
41163eebed0Spatrick
41263eebed0Spatrick tp->t_cflag = TTYDEF_CFLAG;
41363eebed0Spatrick tp->t_lflag = TTYDEF_LFLAG;
41463eebed0Spatrick tp->t_ispeed = tp->t_ospeed = B115200;
41563eebed0Spatrick
41663eebed0Spatrick s = spltty();
41763eebed0Spatrick
41863eebed0Spatrick mvuart_param(tp, &tp->t_termios);
41963eebed0Spatrick ttsetwater(tp);
42063eebed0Spatrick sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
42163eebed0Spatrick sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
42263eebed0Spatrick sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
42363eebed0Spatrick
42463eebed0Spatrick /* Enable interrupts */
42563eebed0Spatrick HSET4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT);
42663eebed0Spatrick
42763eebed0Spatrick SET(tp->t_state, TS_CARR_ON); /* XXX */
4289ca4957bSjan } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
42963eebed0Spatrick return EBUSY;
43063eebed0Spatrick else
43163eebed0Spatrick s = spltty();
43263eebed0Spatrick
43363eebed0Spatrick if (DEVCUA(dev)) {
43463eebed0Spatrick if (ISSET(tp->t_state, TS_ISOPEN)) {
43563eebed0Spatrick splx(s);
43663eebed0Spatrick return EBUSY;
43763eebed0Spatrick }
43863eebed0Spatrick sc->sc_cua = 1;
43963eebed0Spatrick } else {
44063eebed0Spatrick /* tty (not cua) device; wait for carrier if necessary */
44163eebed0Spatrick if (ISSET(flag, O_NONBLOCK)) {
44263eebed0Spatrick if (sc->sc_cua) {
44363eebed0Spatrick /* Opening TTY non-blocking... but the CUA is busy */
44463eebed0Spatrick splx(s);
44563eebed0Spatrick return EBUSY;
44663eebed0Spatrick }
44763eebed0Spatrick } else {
44863eebed0Spatrick while (sc->sc_cua ||
44963eebed0Spatrick (!ISSET(tp->t_cflag, CLOCAL) &&
45063eebed0Spatrick !ISSET(tp->t_state, TS_CARR_ON))) {
45163eebed0Spatrick SET(tp->t_state, TS_WOPEN);
45263eebed0Spatrick error = ttysleep(tp, &tp->t_rawq,
453c8b8fc79Scheloha TTIPRI | PCATCH, ttopen);
45463eebed0Spatrick /*
45563eebed0Spatrick * If TS_WOPEN has been reset, that means the
45663eebed0Spatrick * cua device has been closed. We don't want
45763eebed0Spatrick * to fail in that case,
45863eebed0Spatrick * so just go around again.
45963eebed0Spatrick */
46063eebed0Spatrick if (error && ISSET(tp->t_state, TS_WOPEN)) {
46163eebed0Spatrick CLR(tp->t_state, TS_WOPEN);
46263eebed0Spatrick splx(s);
46363eebed0Spatrick return error;
46463eebed0Spatrick }
46563eebed0Spatrick }
46663eebed0Spatrick }
46763eebed0Spatrick }
46863eebed0Spatrick splx(s);
46963eebed0Spatrick return (*linesw[tp->t_line].l_open)(dev,tp,p);
47063eebed0Spatrick }
47163eebed0Spatrick
47263eebed0Spatrick int
mvuartclose(dev_t dev,int flag,int mode,struct proc * p)47363eebed0Spatrick mvuartclose(dev_t dev, int flag, int mode, struct proc *p)
47463eebed0Spatrick {
47563eebed0Spatrick struct mvuart_softc *sc = mvuart_sc(dev);
47663eebed0Spatrick struct tty *tp = sc->sc_tty;
47763eebed0Spatrick int s;
47863eebed0Spatrick
47963eebed0Spatrick if (!ISSET(tp->t_state, TS_ISOPEN))
48063eebed0Spatrick return 0;
48163eebed0Spatrick
48263eebed0Spatrick (*linesw[tp->t_line].l_close)(tp, flag, p);
48363eebed0Spatrick s = spltty();
48463eebed0Spatrick if (!ISSET(tp->t_state, TS_WOPEN)) {
48563eebed0Spatrick /* Disable interrupts */
48663eebed0Spatrick HCLR4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT |
48763eebed0Spatrick MVUART_CTRL_TX_RDY_INT);
48863eebed0Spatrick }
48963eebed0Spatrick CLR(tp->t_state, TS_BUSY | TS_FLUSH);
49063eebed0Spatrick sc->sc_cua = 0;
49163eebed0Spatrick splx(s);
49263eebed0Spatrick ttyclose(tp);
49363eebed0Spatrick
49463eebed0Spatrick return 0;
49563eebed0Spatrick }
49663eebed0Spatrick
49763eebed0Spatrick int
mvuartread(dev_t dev,struct uio * uio,int flag)49863eebed0Spatrick mvuartread(dev_t dev, struct uio *uio, int flag)
49963eebed0Spatrick {
50063eebed0Spatrick struct tty *tty;
50163eebed0Spatrick
50263eebed0Spatrick tty = mvuarttty(dev);
50363eebed0Spatrick if (tty == NULL)
50463eebed0Spatrick return ENODEV;
50563eebed0Spatrick
50663eebed0Spatrick return((*linesw[tty->t_line].l_read)(tty, uio, flag));
50763eebed0Spatrick }
50863eebed0Spatrick
50963eebed0Spatrick int
mvuartwrite(dev_t dev,struct uio * uio,int flag)51063eebed0Spatrick mvuartwrite(dev_t dev, struct uio *uio, int flag)
51163eebed0Spatrick {
51263eebed0Spatrick struct tty *tty;
51363eebed0Spatrick
51463eebed0Spatrick tty = mvuarttty(dev);
51563eebed0Spatrick if (tty == NULL)
51663eebed0Spatrick return ENODEV;
51763eebed0Spatrick
51863eebed0Spatrick return((*linesw[tty->t_line].l_write)(tty, uio, flag));
51963eebed0Spatrick }
52063eebed0Spatrick
52163eebed0Spatrick int
mvuartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)52263eebed0Spatrick mvuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
52363eebed0Spatrick {
52463eebed0Spatrick struct mvuart_softc *sc;
52563eebed0Spatrick struct tty *tp;
52663eebed0Spatrick int error;
52763eebed0Spatrick
52863eebed0Spatrick sc = mvuart_sc(dev);
52963eebed0Spatrick if (sc == NULL)
53063eebed0Spatrick return (ENODEV);
53163eebed0Spatrick
53263eebed0Spatrick tp = sc->sc_tty;
53363eebed0Spatrick if (tp == NULL)
53463eebed0Spatrick return (ENXIO);
53563eebed0Spatrick
53663eebed0Spatrick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
53763eebed0Spatrick if (error >= 0)
53863eebed0Spatrick return (error);
53963eebed0Spatrick
54063eebed0Spatrick error = ttioctl(tp, cmd, data, flag, p);
54163eebed0Spatrick if (error >= 0)
54263eebed0Spatrick return (error);
54363eebed0Spatrick
54463eebed0Spatrick switch(cmd) {
54563eebed0Spatrick case TIOCSBRK:
54663eebed0Spatrick case TIOCCBRK:
54763eebed0Spatrick case TIOCSDTR:
54863eebed0Spatrick case TIOCCDTR:
54963eebed0Spatrick case TIOCMSET:
55063eebed0Spatrick case TIOCMBIS:
55163eebed0Spatrick case TIOCMBIC:
55263eebed0Spatrick case TIOCMGET:
55363eebed0Spatrick case TIOCGFLAGS:
55463eebed0Spatrick break;
55563eebed0Spatrick case TIOCSFLAGS:
55663eebed0Spatrick error = suser(p);
55763eebed0Spatrick if (error != 0)
55863eebed0Spatrick return(EPERM);
55963eebed0Spatrick break;
56063eebed0Spatrick default:
56163eebed0Spatrick return (ENOTTY);
56263eebed0Spatrick }
56363eebed0Spatrick
56463eebed0Spatrick return 0;
56563eebed0Spatrick }
56663eebed0Spatrick
56763eebed0Spatrick int
mvuartstop(struct tty * tp,int flag)56863eebed0Spatrick mvuartstop(struct tty *tp, int flag)
56963eebed0Spatrick {
57063eebed0Spatrick return 0;
57163eebed0Spatrick }
57263eebed0Spatrick
57363eebed0Spatrick struct tty *
mvuarttty(dev_t dev)57463eebed0Spatrick mvuarttty(dev_t dev)
57563eebed0Spatrick {
57663eebed0Spatrick struct mvuart_softc *sc;
57763eebed0Spatrick sc = mvuart_sc(dev);
57863eebed0Spatrick if (sc == NULL)
57963eebed0Spatrick return NULL;
58063eebed0Spatrick return sc->sc_tty;
58163eebed0Spatrick }
58263eebed0Spatrick
58363eebed0Spatrick struct mvuart_softc *
mvuart_sc(dev_t dev)58463eebed0Spatrick mvuart_sc(dev_t dev)
58563eebed0Spatrick {
58663eebed0Spatrick int unit;
58763eebed0Spatrick unit = DEVUNIT(dev);
58863eebed0Spatrick if (unit >= mvuart_cd.cd_ndevs)
58963eebed0Spatrick return NULL;
59063eebed0Spatrick return (struct mvuart_softc *)mvuart_cd.cd_devs[unit];
59163eebed0Spatrick }
59263eebed0Spatrick
59363eebed0Spatrick /* serial console */
59463eebed0Spatrick void
mvuartcnprobe(struct consdev * cp)59563eebed0Spatrick mvuartcnprobe(struct consdev *cp)
59663eebed0Spatrick {
59763eebed0Spatrick }
59863eebed0Spatrick
59963eebed0Spatrick void
mvuartcninit(struct consdev * cp)60063eebed0Spatrick mvuartcninit(struct consdev *cp)
60163eebed0Spatrick {
60263eebed0Spatrick }
60363eebed0Spatrick
60463eebed0Spatrick int
mvuartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)60563eebed0Spatrick mvuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
60663eebed0Spatrick {
60763eebed0Spatrick static struct consdev mvuartcons = {
60863eebed0Spatrick NULL, NULL, mvuartcngetc, mvuartcnputc, mvuartcnpollc, NULL,
60963eebed0Spatrick NODEV, CN_MIDPRI
61063eebed0Spatrick };
61163eebed0Spatrick int maj;
61263eebed0Spatrick
61363eebed0Spatrick if (bus_space_map(iot, iobase, 0x200, 0, &mvuartconsioh))
61463eebed0Spatrick return ENOMEM;
61563eebed0Spatrick
61663eebed0Spatrick /* Look for major of com(4) to replace. */
61763eebed0Spatrick for (maj = 0; maj < nchrdev; maj++)
61863eebed0Spatrick if (cdevsw[maj].d_open == comopen)
61963eebed0Spatrick break;
62063eebed0Spatrick if (maj == nchrdev)
62163eebed0Spatrick return ENXIO;
62263eebed0Spatrick
62363eebed0Spatrick cn_tab = &mvuartcons;
62463eebed0Spatrick cn_tab->cn_dev = makedev(maj, 0);
62563eebed0Spatrick cdevsw[maj] = mvuartdev; /* KLUDGE */
62663eebed0Spatrick
62763eebed0Spatrick mvuartconsiot = iot;
62863eebed0Spatrick mvuartconsaddr = iobase;
62963eebed0Spatrick
63063eebed0Spatrick return 0;
63163eebed0Spatrick }
63263eebed0Spatrick
63363eebed0Spatrick int
mvuartcngetc(dev_t dev)63463eebed0Spatrick mvuartcngetc(dev_t dev)
63563eebed0Spatrick {
63663eebed0Spatrick int c;
63763eebed0Spatrick int s;
63863eebed0Spatrick s = splhigh();
63963eebed0Spatrick while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
64063eebed0Spatrick MVUART_STAT_STD_RX_RDY) == 0)
64163eebed0Spatrick ;
64263eebed0Spatrick c = bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_RBR);
64363eebed0Spatrick splx(s);
64463eebed0Spatrick return c;
64563eebed0Spatrick }
64663eebed0Spatrick
64763eebed0Spatrick void
mvuartcnputc(dev_t dev,int c)64863eebed0Spatrick mvuartcnputc(dev_t dev, int c)
64963eebed0Spatrick {
65063eebed0Spatrick int s;
65163eebed0Spatrick s = splhigh();
65263eebed0Spatrick while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
65363eebed0Spatrick MVUART_STAT_STD_TX_FIFO_FULL) != 0)
65463eebed0Spatrick ;
65563eebed0Spatrick bus_space_write_4(mvuartconsiot, mvuartconsioh, MVUART_TSH, (uint8_t)c);
65663eebed0Spatrick while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
65763eebed0Spatrick MVUART_STAT_STD_TX_FIFO_EMPTY) != 0)
65863eebed0Spatrick ;
65963eebed0Spatrick splx(s);
66063eebed0Spatrick }
66163eebed0Spatrick
66263eebed0Spatrick void
mvuartcnpollc(dev_t dev,int on)66363eebed0Spatrick mvuartcnpollc(dev_t dev, int on)
66463eebed0Spatrick {
66563eebed0Spatrick }
666