1272343Sngie/* $OpenBSD: mvuart.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */
2272343Sngie/*
3272343Sngie * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
4272343Sngie * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
5272343Sngie *
6272343Sngie * Permission to use, copy, modify, and distribute this software for any
7272343Sngie * purpose with or without fee is hereby granted, provided that the above
8272343Sngie * copyright notice and this permission notice appear in all copies.
9272343Sngie *
10272343Sngie * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11272343Sngie * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12272343Sngie * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13272343Sngie * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14272343Sngie * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15272343Sngie * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16272343Sngie * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17272343Sngie */
18272343Sngie
19272343Sngie#include <sys/param.h>
20272343Sngie#include <sys/ioctl.h>
21272343Sngie#include <sys/proc.h>
22272343Sngie#include <sys/tty.h>
23272343Sngie#include <sys/systm.h>
24272343Sngie#include <sys/device.h>
25272343Sngie#include <sys/conf.h>
26272343Sngie#include <sys/fcntl.h>
27272343Sngie
28272343Sngie#include <machine/bus.h>
29272343Sngie#include <machine/fdt.h>
30272343Sngie
31272343Sngie#include <dev/cons.h>
32272343Sngie
33272343Sngie#include <dev/ofw/openfirm.h>
34272343Sngie#include <dev/ofw/ofw_clock.h>
35272343Sngie#include <dev/ofw/ofw_pinctrl.h>
36272343Sngie#include <dev/ofw/fdt.h>
37272343Sngie
38272343Sngie#define MVUART_RBR			0x00
39272343Sngie#define MVUART_TSH			0x04
40272343Sngie#define MVUART_CTRL			0x08
41272343Sngie#define  MVUART_CTRL_RX_RDY_INT			(1 << 4)
42272343Sngie#define  MVUART_CTRL_TX_RDY_INT			(1 << 5)
43272343Sngie#define MVUART_STAT			0x0c
44272343Sngie#define  MVUART_STAT_STD_OVR_ERR		(1 << 0)
45272343Sngie#define  MVUART_STAT_STD_PAR_ERR		(1 << 1)
46272343Sngie#define  MVUART_STAT_STD_FRM_ERR		(1 << 2)
47272343Sngie#define  MVUART_STAT_STD_BRK_DET		(1 << 3)
48272343Sngie#define  MVUART_STAT_STD_ERROR_MASK		(0xf << 0)
49272343Sngie#define  MVUART_STAT_STD_RX_RDY			(1 << 4)
50272343Sngie#define  MVUART_STAT_STD_TX_RDY			(1 << 5)
51272343Sngie#define  MVUART_STAT_STD_TX_EMPTY		(1 << 6)
52272343Sngie#define  MVUART_STAT_STD_TX_FIFO_FULL		(1 << 11)
53272343Sngie#define  MVUART_STAT_STD_TX_FIFO_EMPTY		(1 << 13)
54272343Sngie#define MVUART_BAUD_RATE_DIV		0x10
55272343Sngie#define  MVUART_BAUD_RATE_DIV_MASK		0x3ff
56272343Sngie
57272343Sngie#define DEVUNIT(x)	(minor(x) & 0x7f)
58272343Sngie#define DEVCUA(x)	(minor(x) & 0x80)
59272343Sngie
60272343Sngie#define HREAD4(sc, reg)							\
61272343Sngie	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
62272343Sngie#define HWRITE4(sc, reg, val)						\
63272343Sngie	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
64272343Sngie#define HSET4(sc, reg, bits)						\
65272343Sngie	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
66272343Sngie#define HCLR4(sc, reg, bits)						\
67272343Sngie	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
68272343Sngie
69272343Sngiestruct mvuart_softc {
70272343Sngie	struct device		 sc_dev;
71272343Sngie	bus_space_tag_t		 sc_iot;
72272343Sngie	bus_space_handle_t	 sc_ioh;
73272343Sngie	int			 sc_node;
74272343Sngie	struct soft_intrhand	*sc_si;
75272343Sngie	void			*sc_ih;
76272343Sngie	struct tty		*sc_tty;
77272343Sngie	int			 sc_floods;
78272343Sngie	int			 sc_errors;
79272343Sngie	int			 sc_halt;
80272343Sngie	uint8_t			 sc_hwflags;
81272343Sngie#define COM_HW_NOIEN			0x01
82272343Sngie#define COM_HW_FIFO			0x02
83272343Sngie#define COM_HW_SIR			0x20
84272343Sngie#define COM_HW_CONSOLE			0x40
85272343Sngie	uint8_t			 sc_cua;
86272343Sngie	uint16_t 		*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
87272343Sngie#define MVUART_IBUFSIZE			 128
88272343Sngie#define MVUART_IHIGHWATER		 100
89272343Sngie	uint16_t		 sc_ibufs[2][MVUART_IBUFSIZE];
90272343Sngie};
91272343Sngie
92272343Sngieint	 mvuart_match(struct device *, void *, void *);
93272343Sngievoid	 mvuart_attach(struct device *, struct device *, void *);
94272343Sngie
95272343Sngievoid	 mvuartcnprobe(struct consdev *cp);
96272343Sngievoid	 mvuartcninit(struct consdev *cp);
97272343Sngieint	 mvuartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
98272343Sngieint	 mvuartcngetc(dev_t dev);
99272343Sngievoid	 mvuartcnputc(dev_t dev, int c);
100272343Sngievoid	 mvuartcnpollc(dev_t dev, int on);
101272343Sngieint	 mvuart_param(struct tty *, struct termios *);
102272343Sngievoid	 mvuart_start(struct tty *);
103272343Sngievoid	 mvuart_softint(void *arg);
104272343Sngie
105272343Sngiestruct mvuart_softc *mvuart_sc(dev_t dev);
106272343Sngie
107272343Sngieint	 mvuart_intr(void *);
108272343Sngieint	 mvuart_intr_rx(struct mvuart_softc *);
109272343Sngieint	 mvuart_intr_tx(struct mvuart_softc *);
110272343Sngie
111272343Sngie/* XXX - we imitate 'com' serial ports and take over their entry points */
112272343Sngie/* XXX: These belong elsewhere */
113272343Sngiecdev_decl(com);
114272343Sngiecdev_decl(mvuart);
115272343Sngie
116272343Sngiestruct cfdriver mvuart_cd = {
117272343Sngie	NULL, "mvuart", DV_TTY
118272343Sngie};
119272343Sngie
120272343Sngieconst struct cfattach mvuart_ca = {
121272343Sngie	sizeof(struct mvuart_softc), mvuart_match, mvuart_attach
122272343Sngie};
123272343Sngie
124272343Sngiebus_space_tag_t		mvuartconsiot;
125272343Sngiebus_space_handle_t	mvuartconsioh;
126272343Sngiebus_addr_t		mvuartconsaddr;
127272343Sngie
128272343Sngiestruct cdevsw mvuartdev =
129272343Sngie	cdev_tty_init(3/*XXX NMVUART */, mvuart);		/* 12: serial port */
130272343Sngie
131272343Sngievoid
132272343Sngiemvuart_init_cons(void)
133272343Sngie{
134272343Sngie	struct fdt_reg reg;
135272343Sngie	void *node;
136272343Sngie
137272343Sngie	if ((node = fdt_find_cons("marvell,armada-3700-uart")) == NULL)
138272343Sngie		return;
139272343Sngie
140272343Sngie	if (fdt_get_reg(node, 0, &reg))
141272343Sngie		return;
142272343Sngie
143272343Sngie	mvuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
144272343Sngie}
145272343Sngie
146272343Sngieint
147272343Sngiemvuart_match(struct device *parent, void *match, void *aux)
148272343Sngie{
149272343Sngie	struct fdt_attach_args *faa = aux;
150272343Sngie
151272343Sngie	return OF_is_compatible(faa->fa_node, "marvell,armada-3700-uart");
152272343Sngie}
153272343Sngie
154272343Sngievoid
155272343Sngiemvuart_attach(struct device *parent, struct device *self, void *aux)
156272343Sngie{
157272343Sngie	struct mvuart_softc *sc = (struct mvuart_softc *)self;
158272343Sngie	struct fdt_attach_args *faa = aux;
159272343Sngie	int maj;
160272343Sngie
161272343Sngie	if (faa->fa_nreg < 1)
162272343Sngie		return;
163272343Sngie
164272343Sngie	pinctrl_byname(faa->fa_node, "default");
165272343Sngie
166272343Sngie	sc->sc_node = faa->fa_node;
167272343Sngie	sc->sc_iot = faa->fa_iot;
168272343Sngie	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
169272343Sngie	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
170272343Sngie		panic("%s: bus_space_map failed", sc->sc_dev.dv_xname);
171272343Sngie		return;
172272343Sngie	}
173272343Sngie
174272343Sngie	if (faa->fa_reg[0].addr == mvuartconsaddr) {
175272343Sngie		/* Locate the major number. */
176272343Sngie		for (maj = 0; maj < nchrdev; maj++)
177272343Sngie			if (cdevsw[maj].d_open == mvuartopen)
178272343Sngie				break;
179272343Sngie		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
180272343Sngie
181272343Sngie		printf(": console");
182272343Sngie	}
183272343Sngie
184272343Sngie	printf("\n");
185272343Sngie
186272343Sngie	sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
187272343Sngie	    mvuart_intr, sc, sc->sc_dev.dv_xname);
188272343Sngie	if (sc->sc_ih == NULL)
189272343Sngie		panic("%s: can't establish hard interrupt",
190272343Sngie		    sc->sc_dev.dv_xname);
191272343Sngie
192272343Sngie	sc->sc_si = softintr_establish(IPL_TTY, mvuart_softint, sc);
193272343Sngie	if (sc->sc_si == NULL)
194272343Sngie		panic("%s: can't establish soft interrupt",
195272343Sngie		    sc->sc_dev.dv_xname);
196272343Sngie}
197272343Sngie
198272343Sngieint
199272343Sngiemvuart_intr(void *arg)
200272343Sngie{
201272343Sngie	struct mvuart_softc *sc = arg;
202272343Sngie	uint32_t stat;
203272343Sngie	int ret = 0;
204272343Sngie
205272343Sngie	if (sc->sc_tty == NULL)
206272343Sngie		return 0;
207272343Sngie
208272343Sngie	stat = HREAD4(sc, MVUART_STAT);
209272343Sngie
210272343Sngie	if ((stat & MVUART_STAT_STD_RX_RDY) != 0)
211272343Sngie		ret |= mvuart_intr_rx(sc);
212272343Sngie
213272343Sngie	if ((stat & MVUART_STAT_STD_TX_RDY) != 0)
214272343Sngie		ret |= mvuart_intr_tx(sc);
215272343Sngie
216272343Sngie	return ret;
217272343Sngie}
218272343Sngie
219272343Sngieint
220272343Sngiemvuart_intr_rx(struct mvuart_softc *sc)
221272343Sngie{
222272343Sngie	uint32_t stat;
223272343Sngie	uint16_t *p, c;
224272343Sngie
225272343Sngie	p = sc->sc_ibufp;
226272343Sngie
227272343Sngie	stat = HREAD4(sc, MVUART_STAT);
228272343Sngie	while ((stat & MVUART_STAT_STD_RX_RDY) != 0) {
229272343Sngie		c = HREAD4(sc, MVUART_RBR);
230272343Sngie		c |= (stat & MVUART_STAT_STD_ERROR_MASK) << 8;
231272343Sngie		if (p >= sc->sc_ibufend) {
232272343Sngie			sc->sc_floods++;
233272343Sngie		} else {
234272343Sngie			*p++ = c;
235272343Sngie		}
236272343Sngie		stat = HREAD4(sc, MVUART_STAT);
237272343Sngie	}
238272343Sngie	sc->sc_ibufp = p;
239272343Sngie
240272343Sngie	softintr_schedule(sc->sc_si);
241272343Sngie	return 1;
242272343Sngie}
243272343Sngie
244272343Sngieint
245272343Sngiemvuart_intr_tx(struct mvuart_softc *sc)
246272343Sngie{
247272343Sngie	struct tty *tp = sc->sc_tty;
248272343Sngie
249272343Sngie	HCLR4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
250272343Sngie	if (ISSET(tp->t_state, TS_BUSY)) {
251272343Sngie		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
252272343Sngie		if (sc->sc_halt > 0)
253272343Sngie			wakeup(&tp->t_outq);
254272343Sngie		(*linesw[tp->t_line].l_start)(tp);
255272343Sngie	}
256272343Sngie
257272343Sngie	return 1;
258272343Sngie}
259272343Sngie
260272343Sngieint
261272343Sngiemvuart_param(struct tty *tp, struct termios *t)
262272343Sngie{
263272343Sngie	struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
264272343Sngie	int error, ospeed = t->c_ospeed;
265272343Sngie	tcflag_t oldcflag;
266272343Sngie
267272343Sngie	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
268272343Sngie		return EINVAL;
269272343Sngie
270272343Sngie	switch (ISSET(t->c_cflag, CSIZE)) {
271272343Sngie	case CS5:
272272343Sngie	case CS6:
273272343Sngie	case CS7:
274272343Sngie		return EINVAL;
275272343Sngie	case CS8:
276272343Sngie		break;
277272343Sngie	}
278272343Sngie
279272343Sngie	if (ospeed != 0) {
280272343Sngie		while (ISSET(tp->t_state, TS_BUSY)) {
281272343Sngie			++sc->sc_halt;
282272343Sngie			error = ttysleep(tp, &tp->t_outq,
283272343Sngie			    TTOPRI | PCATCH, "mvuartprm");
284272343Sngie			--sc->sc_halt;
285272343Sngie			if (error) {
286272343Sngie				mvuart_start(tp);
287272343Sngie				return (error);
288272343Sngie			}
289272343Sngie		}
290272343Sngie	}
291272343Sngie
292272343Sngie	/* and copy to tty */
293272343Sngie	tp->t_ispeed = t->c_ispeed;
294272343Sngie	tp->t_ospeed = t->c_ospeed;
295272343Sngie	oldcflag = tp->t_cflag;
296272343Sngie	tp->t_cflag = t->c_cflag;
297272343Sngie
298272343Sngie	mvuart_start(tp);
299272343Sngie	return 0;
300272343Sngie}
301272343Sngie
302272343Sngievoid
303272343Sngiemvuart_start(struct tty *tp)
304272343Sngie{
305272343Sngie	struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
306272343Sngie	uint8_t buf;
307272343Sngie	int i, n, s;
308272343Sngie
309272343Sngie	s = spltty();
310272343Sngie	if (ISSET(tp->t_state, TS_BUSY)) {
311272343Sngie		splx(s);
312272343Sngie		return;
313272343Sngie	}
314272343Sngie	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
315272343Sngie		goto out;
316272343Sngie	if (tp->t_outq.c_cc <= tp->t_lowat) {
317272343Sngie		if (ISSET(tp->t_state, TS_ASLEEP)) {
318272343Sngie			CLR(tp->t_state, TS_ASLEEP);
319272343Sngie			wakeup(&tp->t_outq);
320272343Sngie		}
321272343Sngie		if (tp->t_outq.c_cc == 0)
322272343Sngie			goto out;
323272343Sngie		selwakeup(&tp->t_wsel);
324272343Sngie	}
325272343Sngie	SET(tp->t_state, TS_BUSY);
326272343Sngie
327272343Sngie	for (i = 0; i < 32; i++) {
328272343Sngie		n = q_to_b(&tp->t_outq, &buf, 1);
329272343Sngie		if (n < 1)
330272343Sngie			break;
331272343Sngie		HWRITE4(sc, MVUART_TSH, buf);
332272343Sngie		if (HREAD4(sc, MVUART_STAT) & MVUART_STAT_STD_TX_FIFO_FULL)
333272343Sngie			break;
334272343Sngie	}
335272343Sngie	HSET4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
336272343Sngie
337272343Sngieout:
338272343Sngie	splx(s);
339272343Sngie}
340272343Sngie
341272343Sngievoid
342272343Sngiemvuart_softint(void *arg)
343272343Sngie{
344272343Sngie	struct mvuart_softc *sc = arg;
345272343Sngie	struct tty *tp;
346272343Sngie	uint16_t *ibufp;
347272343Sngie	uint16_t *ibufend;
348272343Sngie	int c, err, s;
349272343Sngie
350272343Sngie	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
351272343Sngie		return;
352272343Sngie
353272343Sngie	tp = sc->sc_tty;
354272343Sngie	s = spltty();
355272343Sngie
356272343Sngie	ibufp = sc->sc_ibuf;
357272343Sngie	ibufend = sc->sc_ibufp;
358272343Sngie
359272343Sngie	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
360272343Sngie		splx(s);
361272343Sngie		return;
362272343Sngie	}
363272343Sngie
364272343Sngie	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
365272343Sngie	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
366272343Sngie	sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
367272343Sngie	sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
368272343Sngie
369272343Sngie	splx(s);
370272343Sngie
371272343Sngie	while (ibufp < ibufend) {
372272343Sngie		err = 0;
373272343Sngie		c = *ibufp++;
374272343Sngie		if (ISSET(c, (MVUART_STAT_STD_PAR_ERR << 8)))
375272343Sngie			err |= TTY_PE;
376272343Sngie		if (ISSET(c, (MVUART_STAT_STD_FRM_ERR << 8)))
377272343Sngie			err |= TTY_FE;
378272343Sngie		c = (c & 0xff) | err;
379272343Sngie		(*linesw[tp->t_line].l_rint)(c, tp);
380272343Sngie	}
381272343Sngie}
382272343Sngie
383272343Sngieint
384272343Sngiemvuartopen(dev_t dev, int flag, int mode, struct proc *p)
385272343Sngie{
386272343Sngie	struct mvuart_softc *sc;
387272343Sngie	struct tty *tp;
388272343Sngie	int s, error = 0;
389272343Sngie
390272343Sngie	sc = mvuart_sc(dev);
391272343Sngie	if (sc == NULL)
392272343Sngie		return ENXIO;
393272343Sngie
394272343Sngie	s = spltty();
395272343Sngie	if (sc->sc_tty == NULL)
396272343Sngie		tp = sc->sc_tty = ttymalloc(0);
397272343Sngie	else
398272343Sngie		tp = sc->sc_tty;
399272343Sngie
400272343Sngie	splx(s);
401272343Sngie
402272343Sngie	tp->t_oproc = mvuart_start;
403272343Sngie	tp->t_param = mvuart_param;
404272343Sngie	tp->t_dev = dev;
405272343Sngie
406272343Sngie	if (!ISSET(tp->t_state, TS_ISOPEN)) {
407272343Sngie		SET(tp->t_state, TS_WOPEN);
408272343Sngie		ttychars(tp);
409272343Sngie		tp->t_iflag = TTYDEF_IFLAG;
410272343Sngie		tp->t_oflag = TTYDEF_OFLAG;
411272343Sngie
412272343Sngie		tp->t_cflag = TTYDEF_CFLAG;
413272343Sngie		tp->t_lflag = TTYDEF_LFLAG;
414272343Sngie		tp->t_ispeed = tp->t_ospeed = B115200;
415272343Sngie
416272343Sngie		s = spltty();
417272343Sngie
418272343Sngie		mvuart_param(tp, &tp->t_termios);
419272343Sngie		ttsetwater(tp);
420272343Sngie		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
421272343Sngie		sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
422272343Sngie		sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
423272343Sngie
424272343Sngie		/* Enable interrupts */
425272343Sngie		HSET4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT);
426272343Sngie
427272343Sngie		SET(tp->t_state, TS_CARR_ON); /* XXX */
428272343Sngie	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
429272343Sngie		return EBUSY;
430272343Sngie	else
431272343Sngie		s = spltty();
432272343Sngie
433272343Sngie	if (DEVCUA(dev)) {
434272343Sngie		if (ISSET(tp->t_state, TS_ISOPEN)) {
435272343Sngie			splx(s);
436272343Sngie			return EBUSY;
437272343Sngie		}
438272343Sngie		sc->sc_cua = 1;
439272343Sngie	} else {
440272343Sngie		/* tty (not cua) device; wait for carrier if necessary */
441272343Sngie		if (ISSET(flag, O_NONBLOCK)) {
442272343Sngie			if (sc->sc_cua) {
443272343Sngie				/* Opening TTY non-blocking... but the CUA is busy */
444272343Sngie				splx(s);
445272343Sngie				return EBUSY;
446272343Sngie			}
447272343Sngie		} else {
448272343Sngie			while (sc->sc_cua ||
449272343Sngie			    (!ISSET(tp->t_cflag, CLOCAL) &&
450272343Sngie				!ISSET(tp->t_state, TS_CARR_ON))) {
451272343Sngie				SET(tp->t_state, TS_WOPEN);
452272343Sngie				error = ttysleep(tp, &tp->t_rawq,
453272343Sngie				    TTIPRI | PCATCH, ttopen);
454272343Sngie				/*
455272343Sngie				 * If TS_WOPEN has been reset, that means the
456272343Sngie				 * cua device has been closed.  We don't want
457272343Sngie				 * to fail in that case,
458272343Sngie				 * so just go around again.
459272343Sngie				 */
460272343Sngie				if (error && ISSET(tp->t_state, TS_WOPEN)) {
461272343Sngie					CLR(tp->t_state, TS_WOPEN);
462272343Sngie					splx(s);
463272343Sngie					return error;
464272343Sngie				}
465272343Sngie			}
466272343Sngie		}
467272343Sngie	}
468272343Sngie	splx(s);
469272343Sngie	return (*linesw[tp->t_line].l_open)(dev,tp,p);
470272343Sngie}
471272343Sngie
472272343Sngieint
473272343Sngiemvuartclose(dev_t dev, int flag, int mode, struct proc *p)
474272343Sngie{
475272343Sngie	struct mvuart_softc *sc = mvuart_sc(dev);
476272343Sngie	struct tty *tp = sc->sc_tty;
477272343Sngie	int s;
478272343Sngie
479272343Sngie	if (!ISSET(tp->t_state, TS_ISOPEN))
480272343Sngie		return 0;
481272343Sngie
482272343Sngie	(*linesw[tp->t_line].l_close)(tp, flag, p);
483272343Sngie	s = spltty();
484272343Sngie	if (!ISSET(tp->t_state, TS_WOPEN)) {
485272343Sngie		/* Disable interrupts */
486272343Sngie		HCLR4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT |
487272343Sngie		    MVUART_CTRL_TX_RDY_INT);
488272343Sngie	}
489272343Sngie	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
490272343Sngie	sc->sc_cua = 0;
491272343Sngie	splx(s);
492272343Sngie	ttyclose(tp);
493272343Sngie
494272343Sngie	return 0;
495272343Sngie}
496272343Sngie
497272343Sngieint
498272343Sngiemvuartread(dev_t dev, struct uio *uio, int flag)
499272343Sngie{
500272343Sngie	struct tty *tty;
501272343Sngie
502272343Sngie	tty = mvuarttty(dev);
503272343Sngie	if (tty == NULL)
504272343Sngie		return ENODEV;
505272343Sngie
506272343Sngie	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
507272343Sngie}
508272343Sngie
509272343Sngieint
510272343Sngiemvuartwrite(dev_t dev, struct uio *uio, int flag)
511272343Sngie{
512272343Sngie	struct tty *tty;
513272343Sngie
514272343Sngie	tty = mvuarttty(dev);
515272343Sngie	if (tty == NULL)
516272343Sngie		return ENODEV;
517272343Sngie
518272343Sngie	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
519272343Sngie}
520272343Sngie
521272343Sngieint
522272343Sngiemvuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
523272343Sngie{
524272343Sngie	struct mvuart_softc *sc;
525272343Sngie	struct tty *tp;
526272343Sngie	int error;
527272343Sngie
528272343Sngie	sc = mvuart_sc(dev);
529272343Sngie	if (sc == NULL)
530272343Sngie		return (ENODEV);
531272343Sngie
532272343Sngie	tp = sc->sc_tty;
533272343Sngie	if (tp == NULL)
534272343Sngie		return (ENXIO);
535272343Sngie
536272343Sngie	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
537272343Sngie	if (error >= 0)
538272343Sngie		return (error);
539272343Sngie
540272343Sngie	error = ttioctl(tp, cmd, data, flag, p);
541272343Sngie	if (error >= 0)
542272343Sngie		return (error);
543272343Sngie
544272343Sngie	switch(cmd) {
545272343Sngie	case TIOCSBRK:
546272343Sngie	case TIOCCBRK:
547272343Sngie	case TIOCSDTR:
548272343Sngie	case TIOCCDTR:
549272343Sngie	case TIOCMSET:
550272343Sngie	case TIOCMBIS:
551272343Sngie	case TIOCMBIC:
552272343Sngie	case TIOCMGET:
553272343Sngie	case TIOCGFLAGS:
554272343Sngie		break;
555272343Sngie	case TIOCSFLAGS:
556272343Sngie		error = suser(p);
557272343Sngie		if (error != 0)
558272343Sngie			return(EPERM);
559272343Sngie		break;
560272343Sngie	default:
561272343Sngie		return (ENOTTY);
562272343Sngie	}
563272343Sngie
564	return 0;
565}
566
567int
568mvuartstop(struct tty *tp, int flag)
569{
570	return 0;
571}
572
573struct tty *
574mvuarttty(dev_t dev)
575{
576	struct mvuart_softc *sc;
577	sc = mvuart_sc(dev);
578	if (sc == NULL)
579		return NULL;
580	return sc->sc_tty;
581}
582
583struct mvuart_softc *
584mvuart_sc(dev_t dev)
585{
586	int unit;
587	unit = DEVUNIT(dev);
588	if (unit >= mvuart_cd.cd_ndevs)
589		return NULL;
590	return (struct mvuart_softc *)mvuart_cd.cd_devs[unit];
591}
592
593/* serial console */
594void
595mvuartcnprobe(struct consdev *cp)
596{
597}
598
599void
600mvuartcninit(struct consdev *cp)
601{
602}
603
604int
605mvuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
606{
607	static struct consdev mvuartcons = {
608		NULL, NULL, mvuartcngetc, mvuartcnputc, mvuartcnpollc, NULL,
609		NODEV, CN_MIDPRI
610	};
611	int maj;
612
613	if (bus_space_map(iot, iobase, 0x200, 0, &mvuartconsioh))
614		return ENOMEM;
615
616	/* Look for major of com(4) to replace. */
617	for (maj = 0; maj < nchrdev; maj++)
618		if (cdevsw[maj].d_open == comopen)
619			break;
620	if (maj == nchrdev)
621		return ENXIO;
622
623	cn_tab = &mvuartcons;
624	cn_tab->cn_dev = makedev(maj, 0);
625	cdevsw[maj] = mvuartdev; 	/* KLUDGE */
626
627	mvuartconsiot = iot;
628	mvuartconsaddr = iobase;
629
630	return 0;
631}
632
633int
634mvuartcngetc(dev_t dev)
635{
636	int c;
637	int s;
638	s = splhigh();
639	while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
640	    MVUART_STAT_STD_RX_RDY) == 0)
641		;
642	c = bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_RBR);
643	splx(s);
644	return c;
645}
646
647void
648mvuartcnputc(dev_t dev, int c)
649{
650	int s;
651	s = splhigh();
652	while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
653	    MVUART_STAT_STD_TX_FIFO_FULL) != 0)
654		;
655	bus_space_write_4(mvuartconsiot, mvuartconsioh, MVUART_TSH, (uint8_t)c);
656	while ((bus_space_read_4(mvuartconsiot, mvuartconsioh, MVUART_STAT) &
657	    MVUART_STAT_STD_TX_FIFO_EMPTY) != 0)
658		;
659	splx(s);
660}
661
662void
663mvuartcnpollc(dev_t dev, int on)
664{
665}
666