xref: /openbsd-src/sys/dev/fdt/mvuart.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
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, &reg))
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