xref: /openbsd-src/sys/dev/fdt/mvuart.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1 /* $OpenBSD: mvuart.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */
2 /*
3  * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
4  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/ioctl.h>
21 #include <sys/proc.h>
22 #include <sys/tty.h>
23 #include <sys/systm.h>
24 #include <sys/device.h>
25 #include <sys/conf.h>
26 #include <sys/fcntl.h>
27 
28 #include <machine/bus.h>
29 #include <machine/fdt.h>
30 
31 #include <dev/cons.h>
32 
33 #include <dev/ofw/openfirm.h>
34 #include <dev/ofw/ofw_clock.h>
35 #include <dev/ofw/ofw_pinctrl.h>
36 #include <dev/ofw/fdt.h>
37 
38 #define MVUART_RBR			0x00
39 #define MVUART_TSH			0x04
40 #define MVUART_CTRL			0x08
41 #define  MVUART_CTRL_RX_RDY_INT			(1 << 4)
42 #define  MVUART_CTRL_TX_RDY_INT			(1 << 5)
43 #define MVUART_STAT			0x0c
44 #define  MVUART_STAT_STD_OVR_ERR		(1 << 0)
45 #define  MVUART_STAT_STD_PAR_ERR		(1 << 1)
46 #define  MVUART_STAT_STD_FRM_ERR		(1 << 2)
47 #define  MVUART_STAT_STD_BRK_DET		(1 << 3)
48 #define  MVUART_STAT_STD_ERROR_MASK		(0xf << 0)
49 #define  MVUART_STAT_STD_RX_RDY			(1 << 4)
50 #define  MVUART_STAT_STD_TX_RDY			(1 << 5)
51 #define  MVUART_STAT_STD_TX_EMPTY		(1 << 6)
52 #define  MVUART_STAT_STD_TX_FIFO_FULL		(1 << 11)
53 #define  MVUART_STAT_STD_TX_FIFO_EMPTY		(1 << 13)
54 #define MVUART_BAUD_RATE_DIV		0x10
55 #define  MVUART_BAUD_RATE_DIV_MASK		0x3ff
56 
57 #define DEVUNIT(x)	(minor(x) & 0x7f)
58 #define DEVCUA(x)	(minor(x) & 0x80)
59 
60 #define HREAD4(sc, reg)							\
61 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
62 #define HWRITE4(sc, reg, val)						\
63 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
64 #define HSET4(sc, reg, bits)						\
65 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
66 #define HCLR4(sc, reg, bits)						\
67 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
68 
69 struct mvuart_softc {
70 	struct device		 sc_dev;
71 	bus_space_tag_t		 sc_iot;
72 	bus_space_handle_t	 sc_ioh;
73 	int			 sc_node;
74 	struct soft_intrhand	*sc_si;
75 	void			*sc_ih;
76 	struct tty		*sc_tty;
77 	int			 sc_floods;
78 	int			 sc_errors;
79 	int			 sc_halt;
80 	uint8_t			 sc_hwflags;
81 #define COM_HW_NOIEN			0x01
82 #define COM_HW_FIFO			0x02
83 #define COM_HW_SIR			0x20
84 #define COM_HW_CONSOLE			0x40
85 	uint8_t			 sc_cua;
86 	uint16_t 		*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
87 #define MVUART_IBUFSIZE			 128
88 #define MVUART_IHIGHWATER		 100
89 	uint16_t		 sc_ibufs[2][MVUART_IBUFSIZE];
90 };
91 
92 int	 mvuart_match(struct device *, void *, void *);
93 void	 mvuart_attach(struct device *, struct device *, void *);
94 
95 void	 mvuartcnprobe(struct consdev *cp);
96 void	 mvuartcninit(struct consdev *cp);
97 int	 mvuartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
98 int	 mvuartcngetc(dev_t dev);
99 void	 mvuartcnputc(dev_t dev, int c);
100 void	 mvuartcnpollc(dev_t dev, int on);
101 int	 mvuart_param(struct tty *, struct termios *);
102 void	 mvuart_start(struct tty *);
103 void	 mvuart_softint(void *arg);
104 
105 struct mvuart_softc *mvuart_sc(dev_t dev);
106 
107 int	 mvuart_intr(void *);
108 int	 mvuart_intr_rx(struct mvuart_softc *);
109 int	 mvuart_intr_tx(struct mvuart_softc *);
110 
111 /* XXX - we imitate 'com' serial ports and take over their entry points */
112 /* XXX: These belong elsewhere */
113 cdev_decl(com);
114 cdev_decl(mvuart);
115 
116 struct cfdriver mvuart_cd = {
117 	NULL, "mvuart", DV_TTY
118 };
119 
120 const struct cfattach mvuart_ca = {
121 	sizeof(struct mvuart_softc), mvuart_match, mvuart_attach
122 };
123 
124 bus_space_tag_t		mvuartconsiot;
125 bus_space_handle_t	mvuartconsioh;
126 bus_addr_t		mvuartconsaddr;
127 
128 struct cdevsw mvuartdev =
129 	cdev_tty_init(3/*XXX NMVUART */, mvuart);		/* 12: serial port */
130 
131 void
mvuart_init_cons(void)132 mvuart_init_cons(void)
133 {
134 	struct fdt_reg reg;
135 	void *node;
136 
137 	if ((node = fdt_find_cons("marvell,armada-3700-uart")) == NULL)
138 		return;
139 
140 	if (fdt_get_reg(node, 0, &reg))
141 		return;
142 
143 	mvuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
144 }
145 
146 int
mvuart_match(struct device * parent,void * match,void * aux)147 mvuart_match(struct device *parent, void *match, void *aux)
148 {
149 	struct fdt_attach_args *faa = aux;
150 
151 	return OF_is_compatible(faa->fa_node, "marvell,armada-3700-uart");
152 }
153 
154 void
mvuart_attach(struct device * parent,struct device * self,void * aux)155 mvuart_attach(struct device *parent, struct device *self, void *aux)
156 {
157 	struct mvuart_softc *sc = (struct mvuart_softc *)self;
158 	struct fdt_attach_args *faa = aux;
159 	int maj;
160 
161 	if (faa->fa_nreg < 1)
162 		return;
163 
164 	pinctrl_byname(faa->fa_node, "default");
165 
166 	sc->sc_node = faa->fa_node;
167 	sc->sc_iot = faa->fa_iot;
168 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
169 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
170 		panic("%s: bus_space_map failed", sc->sc_dev.dv_xname);
171 		return;
172 	}
173 
174 	if (faa->fa_reg[0].addr == mvuartconsaddr) {
175 		/* Locate the major number. */
176 		for (maj = 0; maj < nchrdev; maj++)
177 			if (cdevsw[maj].d_open == mvuartopen)
178 				break;
179 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
180 
181 		printf(": console");
182 	}
183 
184 	printf("\n");
185 
186 	sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
187 	    mvuart_intr, sc, sc->sc_dev.dv_xname);
188 	if (sc->sc_ih == NULL)
189 		panic("%s: can't establish hard interrupt",
190 		    sc->sc_dev.dv_xname);
191 
192 	sc->sc_si = softintr_establish(IPL_TTY, mvuart_softint, sc);
193 	if (sc->sc_si == NULL)
194 		panic("%s: can't establish soft interrupt",
195 		    sc->sc_dev.dv_xname);
196 }
197 
198 int
mvuart_intr(void * arg)199 mvuart_intr(void *arg)
200 {
201 	struct mvuart_softc *sc = arg;
202 	uint32_t stat;
203 	int ret = 0;
204 
205 	if (sc->sc_tty == NULL)
206 		return 0;
207 
208 	stat = HREAD4(sc, MVUART_STAT);
209 
210 	if ((stat & MVUART_STAT_STD_RX_RDY) != 0)
211 		ret |= mvuart_intr_rx(sc);
212 
213 	if ((stat & MVUART_STAT_STD_TX_RDY) != 0)
214 		ret |= mvuart_intr_tx(sc);
215 
216 	return ret;
217 }
218 
219 int
mvuart_intr_rx(struct mvuart_softc * sc)220 mvuart_intr_rx(struct mvuart_softc *sc)
221 {
222 	uint32_t stat;
223 	uint16_t *p, c;
224 
225 	p = sc->sc_ibufp;
226 
227 	stat = HREAD4(sc, MVUART_STAT);
228 	while ((stat & MVUART_STAT_STD_RX_RDY) != 0) {
229 		c = HREAD4(sc, MVUART_RBR);
230 		c |= (stat & MVUART_STAT_STD_ERROR_MASK) << 8;
231 		if (p >= sc->sc_ibufend) {
232 			sc->sc_floods++;
233 		} else {
234 			*p++ = c;
235 		}
236 		stat = HREAD4(sc, MVUART_STAT);
237 	}
238 	sc->sc_ibufp = p;
239 
240 	softintr_schedule(sc->sc_si);
241 	return 1;
242 }
243 
244 int
mvuart_intr_tx(struct mvuart_softc * sc)245 mvuart_intr_tx(struct mvuart_softc *sc)
246 {
247 	struct tty *tp = sc->sc_tty;
248 
249 	HCLR4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
250 	if (ISSET(tp->t_state, TS_BUSY)) {
251 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
252 		if (sc->sc_halt > 0)
253 			wakeup(&tp->t_outq);
254 		(*linesw[tp->t_line].l_start)(tp);
255 	}
256 
257 	return 1;
258 }
259 
260 int
mvuart_param(struct tty * tp,struct termios * t)261 mvuart_param(struct tty *tp, struct termios *t)
262 {
263 	struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
264 	int error, ospeed = t->c_ospeed;
265 	tcflag_t oldcflag;
266 
267 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
268 		return EINVAL;
269 
270 	switch (ISSET(t->c_cflag, CSIZE)) {
271 	case CS5:
272 	case CS6:
273 	case CS7:
274 		return EINVAL;
275 	case CS8:
276 		break;
277 	}
278 
279 	if (ospeed != 0) {
280 		while (ISSET(tp->t_state, TS_BUSY)) {
281 			++sc->sc_halt;
282 			error = ttysleep(tp, &tp->t_outq,
283 			    TTOPRI | PCATCH, "mvuartprm");
284 			--sc->sc_halt;
285 			if (error) {
286 				mvuart_start(tp);
287 				return (error);
288 			}
289 		}
290 	}
291 
292 	/* and copy to tty */
293 	tp->t_ispeed = t->c_ispeed;
294 	tp->t_ospeed = t->c_ospeed;
295 	oldcflag = tp->t_cflag;
296 	tp->t_cflag = t->c_cflag;
297 
298 	mvuart_start(tp);
299 	return 0;
300 }
301 
302 void
mvuart_start(struct tty * tp)303 mvuart_start(struct tty *tp)
304 {
305 	struct mvuart_softc *sc = mvuart_sc(tp->t_dev);
306 	uint8_t buf;
307 	int i, n, s;
308 
309 	s = spltty();
310 	if (ISSET(tp->t_state, TS_BUSY)) {
311 		splx(s);
312 		return;
313 	}
314 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
315 		goto out;
316 	if (tp->t_outq.c_cc <= tp->t_lowat) {
317 		if (ISSET(tp->t_state, TS_ASLEEP)) {
318 			CLR(tp->t_state, TS_ASLEEP);
319 			wakeup(&tp->t_outq);
320 		}
321 		if (tp->t_outq.c_cc == 0)
322 			goto out;
323 		selwakeup(&tp->t_wsel);
324 	}
325 	SET(tp->t_state, TS_BUSY);
326 
327 	for (i = 0; i < 32; i++) {
328 		n = q_to_b(&tp->t_outq, &buf, 1);
329 		if (n < 1)
330 			break;
331 		HWRITE4(sc, MVUART_TSH, buf);
332 		if (HREAD4(sc, MVUART_STAT) & MVUART_STAT_STD_TX_FIFO_FULL)
333 			break;
334 	}
335 	HSET4(sc, MVUART_CTRL, MVUART_CTRL_TX_RDY_INT);
336 
337 out:
338 	splx(s);
339 }
340 
341 void
mvuart_softint(void * arg)342 mvuart_softint(void *arg)
343 {
344 	struct mvuart_softc *sc = arg;
345 	struct tty *tp;
346 	uint16_t *ibufp;
347 	uint16_t *ibufend;
348 	int c, err, s;
349 
350 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
351 		return;
352 
353 	tp = sc->sc_tty;
354 	s = spltty();
355 
356 	ibufp = sc->sc_ibuf;
357 	ibufend = sc->sc_ibufp;
358 
359 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
360 		splx(s);
361 		return;
362 	}
363 
364 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
365 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
366 	sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
367 	sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
368 
369 	splx(s);
370 
371 	while (ibufp < ibufend) {
372 		err = 0;
373 		c = *ibufp++;
374 		if (ISSET(c, (MVUART_STAT_STD_PAR_ERR << 8)))
375 			err |= TTY_PE;
376 		if (ISSET(c, (MVUART_STAT_STD_FRM_ERR << 8)))
377 			err |= TTY_FE;
378 		c = (c & 0xff) | err;
379 		(*linesw[tp->t_line].l_rint)(c, tp);
380 	}
381 }
382 
383 int
mvuartopen(dev_t dev,int flag,int mode,struct proc * p)384 mvuartopen(dev_t dev, int flag, int mode, struct proc *p)
385 {
386 	struct mvuart_softc *sc;
387 	struct tty *tp;
388 	int s, error = 0;
389 
390 	sc = mvuart_sc(dev);
391 	if (sc == NULL)
392 		return ENXIO;
393 
394 	s = spltty();
395 	if (sc->sc_tty == NULL)
396 		tp = sc->sc_tty = ttymalloc(0);
397 	else
398 		tp = sc->sc_tty;
399 
400 	splx(s);
401 
402 	tp->t_oproc = mvuart_start;
403 	tp->t_param = mvuart_param;
404 	tp->t_dev = dev;
405 
406 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
407 		SET(tp->t_state, TS_WOPEN);
408 		ttychars(tp);
409 		tp->t_iflag = TTYDEF_IFLAG;
410 		tp->t_oflag = TTYDEF_OFLAG;
411 
412 		tp->t_cflag = TTYDEF_CFLAG;
413 		tp->t_lflag = TTYDEF_LFLAG;
414 		tp->t_ispeed = tp->t_ospeed = B115200;
415 
416 		s = spltty();
417 
418 		mvuart_param(tp, &tp->t_termios);
419 		ttsetwater(tp);
420 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
421 		sc->sc_ibufhigh = sc->sc_ibuf + MVUART_IHIGHWATER;
422 		sc->sc_ibufend = sc->sc_ibuf + MVUART_IBUFSIZE;
423 
424 		/* Enable interrupts */
425 		HSET4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT);
426 
427 		SET(tp->t_state, TS_CARR_ON); /* XXX */
428 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
429 		return EBUSY;
430 	else
431 		s = spltty();
432 
433 	if (DEVCUA(dev)) {
434 		if (ISSET(tp->t_state, TS_ISOPEN)) {
435 			splx(s);
436 			return EBUSY;
437 		}
438 		sc->sc_cua = 1;
439 	} else {
440 		/* tty (not cua) device; wait for carrier if necessary */
441 		if (ISSET(flag, O_NONBLOCK)) {
442 			if (sc->sc_cua) {
443 				/* Opening TTY non-blocking... but the CUA is busy */
444 				splx(s);
445 				return EBUSY;
446 			}
447 		} else {
448 			while (sc->sc_cua ||
449 			    (!ISSET(tp->t_cflag, CLOCAL) &&
450 				!ISSET(tp->t_state, TS_CARR_ON))) {
451 				SET(tp->t_state, TS_WOPEN);
452 				error = ttysleep(tp, &tp->t_rawq,
453 				    TTIPRI | PCATCH, ttopen);
454 				/*
455 				 * If TS_WOPEN has been reset, that means the
456 				 * cua device has been closed.  We don't want
457 				 * to fail in that case,
458 				 * so just go around again.
459 				 */
460 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
461 					CLR(tp->t_state, TS_WOPEN);
462 					splx(s);
463 					return error;
464 				}
465 			}
466 		}
467 	}
468 	splx(s);
469 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
470 }
471 
472 int
mvuartclose(dev_t dev,int flag,int mode,struct proc * p)473 mvuartclose(dev_t dev, int flag, int mode, struct proc *p)
474 {
475 	struct mvuart_softc *sc = mvuart_sc(dev);
476 	struct tty *tp = sc->sc_tty;
477 	int s;
478 
479 	if (!ISSET(tp->t_state, TS_ISOPEN))
480 		return 0;
481 
482 	(*linesw[tp->t_line].l_close)(tp, flag, p);
483 	s = spltty();
484 	if (!ISSET(tp->t_state, TS_WOPEN)) {
485 		/* Disable interrupts */
486 		HCLR4(sc, MVUART_CTRL, MVUART_CTRL_RX_RDY_INT |
487 		    MVUART_CTRL_TX_RDY_INT);
488 	}
489 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
490 	sc->sc_cua = 0;
491 	splx(s);
492 	ttyclose(tp);
493 
494 	return 0;
495 }
496 
497 int
mvuartread(dev_t dev,struct uio * uio,int flag)498 mvuartread(dev_t dev, struct uio *uio, int flag)
499 {
500 	struct tty *tty;
501 
502 	tty = mvuarttty(dev);
503 	if (tty == NULL)
504 		return ENODEV;
505 
506 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
507 }
508 
509 int
mvuartwrite(dev_t dev,struct uio * uio,int flag)510 mvuartwrite(dev_t dev, struct uio *uio, int flag)
511 {
512 	struct tty *tty;
513 
514 	tty = mvuarttty(dev);
515 	if (tty == NULL)
516 		return ENODEV;
517 
518 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
519 }
520 
521 int
mvuartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)522 mvuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
523 {
524 	struct mvuart_softc *sc;
525 	struct tty *tp;
526 	int error;
527 
528 	sc = mvuart_sc(dev);
529 	if (sc == NULL)
530 		return (ENODEV);
531 
532 	tp = sc->sc_tty;
533 	if (tp == NULL)
534 		return (ENXIO);
535 
536 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
537 	if (error >= 0)
538 		return (error);
539 
540 	error = ttioctl(tp, cmd, data, flag, p);
541 	if (error >= 0)
542 		return (error);
543 
544 	switch(cmd) {
545 	case TIOCSBRK:
546 	case TIOCCBRK:
547 	case TIOCSDTR:
548 	case TIOCCDTR:
549 	case TIOCMSET:
550 	case TIOCMBIS:
551 	case TIOCMBIC:
552 	case TIOCMGET:
553 	case TIOCGFLAGS:
554 		break;
555 	case TIOCSFLAGS:
556 		error = suser(p);
557 		if (error != 0)
558 			return(EPERM);
559 		break;
560 	default:
561 		return (ENOTTY);
562 	}
563 
564 	return 0;
565 }
566 
567 int
mvuartstop(struct tty * tp,int flag)568 mvuartstop(struct tty *tp, int flag)
569 {
570 	return 0;
571 }
572 
573 struct tty *
mvuarttty(dev_t dev)574 mvuarttty(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 
583 struct mvuart_softc *
mvuart_sc(dev_t dev)584 mvuart_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 */
594 void
mvuartcnprobe(struct consdev * cp)595 mvuartcnprobe(struct consdev *cp)
596 {
597 }
598 
599 void
mvuartcninit(struct consdev * cp)600 mvuartcninit(struct consdev *cp)
601 {
602 }
603 
604 int
mvuartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)605 mvuartcnattach(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 
633 int
mvuartcngetc(dev_t dev)634 mvuartcngetc(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 
647 void
mvuartcnputc(dev_t dev,int c)648 mvuartcnputc(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 
662 void
mvuartcnpollc(dev_t dev,int on)663 mvuartcnpollc(dev_t dev, int on)
664 {
665 }
666