xref: /openbsd-src/sys/dev/fdt/exuart.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /* $OpenBSD: exuart.c,v 1.11 2022/07/02 08:50:42 visa Exp $ */
2 /*
3  * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/ioctl.h>
20 #include <sys/proc.h>
21 #include <sys/tty.h>
22 #include <sys/uio.h>
23 #include <sys/systm.h>
24 #include <sys/time.h>
25 #include <sys/device.h>
26 #include <sys/syslog.h>
27 #include <sys/conf.h>
28 #include <sys/fcntl.h>
29 #include <sys/kernel.h>
30 
31 #include <machine/bus.h>
32 #include <machine/fdt.h>
33 
34 #include <dev/cons.h>
35 
36 #ifdef DDB
37 #include <ddb/db_var.h>
38 #endif
39 
40 #include <dev/fdt/exuartreg.h>
41 
42 #include <dev/ofw/openfirm.h>
43 #include <dev/ofw/fdt.h>
44 
45 #define DEVUNIT(x)      (minor(x) & 0x7f)
46 #define DEVCUA(x)       (minor(x) & 0x80)
47 
48 struct exuart_softc {
49 	struct device	sc_dev;
50 	bus_space_tag_t sc_iot;
51 	bus_space_handle_t sc_ioh;
52 	struct soft_intrhand *sc_si;
53 	void *sc_irq;
54 	struct tty	*sc_tty;
55 	struct timeout	sc_diag_tmo;
56 	struct timeout	sc_dtr_tmo;
57 
58 	uint32_t	sc_rx_fifo_cnt_mask;
59 	uint32_t	sc_rx_fifo_full;
60 	uint32_t	sc_tx_fifo_full;
61 	int		sc_type;
62 #define EXUART_TYPE_EXYNOS	0
63 #define EXUART_TYPE_S5L		1
64 
65 	int		sc_fifo;
66 	int		sc_overflows;
67 	int		sc_floods;
68 	int		sc_errors;
69 	int		sc_halt;
70 	u_int32_t	sc_ulcon;
71 	u_int32_t	sc_ucon;
72 	u_int32_t	sc_ufcon;
73 	u_int32_t	sc_umcon;
74 	u_int32_t	sc_uintm;
75 	u_int8_t	sc_hwflags;
76 #define COM_HW_NOIEN    0x01
77 #define COM_HW_FIFO     0x02
78 #define COM_HW_SIR      0x20
79 #define COM_HW_CONSOLE  0x40
80 	u_int8_t	sc_swflags;
81 #define COM_SW_SOFTCAR  0x01
82 #define COM_SW_CLOCAL   0x02
83 #define COM_SW_CRTSCTS  0x04
84 #define COM_SW_MDMBUF   0x08
85 #define COM_SW_PPS      0x10
86 
87 	u_int8_t	sc_initialize;
88 	u_int8_t	sc_cua;
89 	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
90 #define EXUART_IBUFSIZE 128
91 #define EXUART_IHIGHWATER 100
92 	u_int16_t		sc_ibufs[2][EXUART_IBUFSIZE];
93 };
94 
95 
96 int	 exuart_match(struct device *, void *, void *);
97 void	 exuart_attach(struct device *, struct device *, void *);
98 
99 void exuartcnprobe(struct consdev *cp);
100 void exuartcninit(struct consdev *cp);
101 int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
102     tcflag_t cflag);
103 int exuartcngetc(dev_t dev);
104 void exuartcnputc(dev_t dev, int c);
105 void exuartcnpollc(dev_t dev, int on);
106 int  exuart_param(struct tty *tp, struct termios *t);
107 void exuart_start(struct tty *);
108 void exuart_diag(void *arg);
109 void exuart_raisedtr(void *arg);
110 void exuart_softint(void *arg);
111 struct exuart_softc *exuart_sc(dev_t dev);
112 
113 int exuart_intr(void *);
114 int exuart_s5l_intr(void *);
115 
116 /* XXX - we imitate 'com' serial ports and take over their entry points */
117 /* XXX: These belong elsewhere */
118 cdev_decl(com);
119 cdev_decl(exuart);
120 
121 struct cfdriver exuart_cd = {
122 	NULL, "exuart", DV_TTY
123 };
124 
125 const struct cfattach exuart_ca = {
126 	sizeof(struct exuart_softc), exuart_match, exuart_attach
127 };
128 
129 bus_space_tag_t	exuartconsiot;
130 bus_space_handle_t exuartconsioh;
131 bus_addr_t	exuartconsaddr;
132 tcflag_t	exuartconscflag = TTYDEF_CFLAG;
133 int		exuartdefaultrate = B115200;
134 
135 uint32_t	exuart_rx_fifo_cnt_mask;
136 uint32_t	exuart_rx_fifo_full;
137 uint32_t	exuart_tx_fifo_full;
138 
139 struct cdevsw exuartdev =
140 	cdev_tty_init(3/*XXX NEXUART */ ,exuart);		/* 12: serial port */
141 
142 void
143 exuart_init_cons(void)
144 {
145 	struct fdt_reg reg;
146 	void *node, *root;
147 
148 	if ((node = fdt_find_cons("apple,s5l-uart")) == NULL &&
149 	    (node = fdt_find_cons("samsung,exynos4210-uart")) == NULL)
150 		return;
151 
152 	/* dtb uses serial2, qemu uses serial0 */
153 	root = fdt_find_node("/");
154 	if (root == NULL)
155 		panic("%s: could not get fdt root node", __func__);
156 	if (fdt_is_compatible(root, "samsung,universal_c210")) {
157 		if ((node = fdt_find_node("/serial@13800000")) == NULL) {
158 			return;
159 		}
160 		stdout_node = OF_finddevice("/serial@13800000");
161 	}
162 
163 	if (fdt_get_reg(node, 0, &reg))
164 		return;
165 
166 	if (fdt_is_compatible(node, "apple,s5l-uart")) {
167 		exuart_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
168 		exuart_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
169 		exuart_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
170 	} else {
171 		exuart_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
172 		exuart_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
173 		exuart_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
174 	}
175 
176 	exuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
177 }
178 
179 int
180 exuart_match(struct device *parent, void *self, void *aux)
181 {
182 	struct fdt_attach_args *faa = aux;
183 
184 	return (OF_is_compatible(faa->fa_node, "apple,s5l-uart") ||
185 	    OF_is_compatible(faa->fa_node, "samsung,exynos4210-uart"));
186 }
187 
188 void
189 exuart_attach(struct device *parent, struct device *self, void *aux)
190 {
191 	struct exuart_softc *sc = (struct exuart_softc *) self;
192 	struct fdt_attach_args *faa = aux;
193 	int maj;
194 
195 	if (faa->fa_nreg < 1)
196 		return;
197 
198 	sc->sc_iot = faa->fa_iot;
199 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
200 	    0, &sc->sc_ioh))
201 		panic("%s: bus_space_map failed!", __func__);
202 
203 	if (stdout_node == faa->fa_node) {
204 		/* Locate the major number. */
205 		for (maj = 0; maj < nchrdev; maj++)
206 			if (cdevsw[maj].d_open == exuartopen)
207 				break;
208 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
209 
210 		printf(": console");
211 	}
212 
213 	if (OF_is_compatible(faa->fa_node, "apple,s5l-uart")) {
214 		sc->sc_type = EXUART_TYPE_S5L;
215 		sc->sc_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK;
216 		sc->sc_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL;
217 		sc->sc_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL;
218 
219 		/* Mask and clear interrupts. */
220 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
221 		    EXUART_UCON);
222 		CLR(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
223 		CLR(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
224 		CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
225 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
226 		    sc->sc_ucon);
227 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UTRSTAT,
228 		    EXUART_S5L_UTRSTAT_RX_TIMEOUT |
229 		    EXUART_S5L_UTRSTAT_RXTHRESH |
230 		    EXUART_S5L_UTRSTAT_TXTHRESH);
231 
232 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
233 		    EXUART_UCON);
234 		SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
235 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
236 		    sc->sc_ucon);
237 
238 		sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
239 		    exuart_s5l_intr, sc, sc->sc_dev.dv_xname);
240 	} else {
241 		sc->sc_type = EXUART_TYPE_EXYNOS;
242 		sc->sc_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK;
243 		sc->sc_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL;
244 		sc->sc_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL;
245 
246 		/* Mask and clear interrupts. */
247 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTM,
248 		    EXUART_UINTM_RXD | EXUART_UINTM_ERROR |
249 		    EXUART_UINTM_TXD | EXUART_UINTM_MODEM);
250 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTP,
251 		    EXUART_UINTP_RXD | EXUART_UINTP_ERROR |
252 		    EXUART_UINTP_TXD | EXUART_UINTP_MODEM);
253 
254 		sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
255 		    EXUART_UCON);
256 		CLR(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO);
257 		SET(sc->sc_ucon, EXUART_UCON_RX_INT_TYPE_LEVEL);
258 		SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
259 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON,
260 		    sc->sc_ucon);
261 
262 		sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
263 		    exuart_intr, sc, sc->sc_dev.dv_xname);
264 	}
265 
266 	timeout_set(&sc->sc_diag_tmo, exuart_diag, sc);
267 	timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc);
268 	sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc);
269 
270 	if(sc->sc_si == NULL)
271 		panic("%s: can't establish soft interrupt.",
272 		    sc->sc_dev.dv_xname);
273 
274 	printf("\n");
275 }
276 
277 void
278 exuart_rx_intr(struct exuart_softc *sc)
279 {
280 	bus_space_tag_t iot = sc->sc_iot;
281 	bus_space_handle_t ioh = sc->sc_ioh;
282 	u_int16_t *p;
283 	u_int16_t c;
284 
285 	p = sc->sc_ibufp;
286 
287 	while (bus_space_read_4(iot, ioh, EXUART_UFSTAT) &
288 	    (sc->sc_rx_fifo_cnt_mask | sc->sc_rx_fifo_full)) {
289 		c = bus_space_read_4(iot, ioh, EXUART_URXH);
290 		if (p >= sc->sc_ibufend) {
291 			sc->sc_floods++;
292 			if (sc->sc_errors++ == 0)
293 				timeout_add_sec(&sc->sc_diag_tmo, 60);
294 		} else {
295 			*p++ = c;
296 #if 0
297 			if (p == sc->sc_ibufhigh &&
298 			    ISSET(tp->t_cflag, CRTSCTS)) {
299 				/* XXX */
300 			}
301 #endif
302 		}
303 	}
304 
305 	sc->sc_ibufp = p;
306 
307 	softintr_schedule(sc->sc_si);
308 }
309 
310 void
311 exuart_tx_intr(struct exuart_softc *sc)
312 {
313 	struct tty *tp = sc->sc_tty;
314 
315 	if (ISSET(tp->t_state, TS_BUSY)) {
316 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
317 		if (sc->sc_halt > 0)
318 			wakeup(&tp->t_outq);
319 		(*linesw[tp->t_line].l_start)(tp);
320 	}
321 }
322 
323 int
324 exuart_intr(void *arg)
325 {
326 	struct exuart_softc *sc = arg;
327 	bus_space_tag_t iot = sc->sc_iot;
328 	bus_space_handle_t ioh = sc->sc_ioh;
329 	u_int32_t uintp;
330 
331 	uintp = bus_space_read_4(iot, ioh, EXUART_UINTP);
332 	if (uintp == 0)
333 		return (0);
334 
335 	if (sc->sc_tty == NULL)
336 		return (0);
337 
338 	if (ISSET(uintp, EXUART_UINTP_RXD)) {
339 		exuart_rx_intr(sc);
340 		bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_RXD);
341 	}
342 
343 	if (ISSET(uintp, EXUART_UINTP_TXD)) {
344 		exuart_tx_intr(sc);
345 		bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_TXD);
346 	}
347 
348 #if 0
349 	if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR))
350 		return 0;
351 
352 	p = sc->sc_ibufp;
353 
354 	while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) {
355 		c = bus_space_read_4(iot, ioh, EXUART_URXH);
356 		if (p >= sc->sc_ibufend) {
357 			sc->sc_floods++;
358 			if (sc->sc_errors++ == 0)
359 				timeout_add_sec(&sc->sc_diag_tmo, 60);
360 		} else {
361 			*p++ = c;
362 			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
363 				/* XXX */
364 				//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
365 				//bus_space_write_2(iot, ioh, EXUART_UCR3,
366 				//    sc->sc_ucr3);
367 
368 		}
369 		/* XXX - msr stuff ? */
370 	}
371 	sc->sc_ibufp = p;
372 
373 	softintr_schedule(sc->sc_si);
374 #endif
375 
376 	return 1;
377 }
378 
379 int
380 exuart_s5l_intr(void *arg)
381 {
382 	struct exuart_softc *sc = arg;
383 	bus_space_tag_t iot = sc->sc_iot;
384 	bus_space_handle_t ioh = sc->sc_ioh;
385 	u_int32_t utrstat;
386 
387 	utrstat = bus_space_read_4(iot, ioh, EXUART_UTRSTAT);
388 
389 	if (sc->sc_tty == NULL)
390 		return (0);
391 
392 	if (utrstat & (EXUART_S5L_UTRSTAT_RXTHRESH |
393 	    EXUART_S5L_UTRSTAT_RX_TIMEOUT))
394 		exuart_rx_intr(sc);
395 
396 	if (utrstat & EXUART_S5L_UTRSTAT_TXTHRESH)
397 		exuart_tx_intr(sc);
398 
399 	bus_space_write_4(iot, ioh, EXUART_UTRSTAT, utrstat);
400 
401 	return 1;
402 }
403 
404 int
405 exuart_param(struct tty *tp, struct termios *t)
406 {
407 	struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
408 	bus_space_tag_t iot = sc->sc_iot;
409 	bus_space_handle_t ioh = sc->sc_ioh;
410 	int ospeed = t->c_ospeed;
411 	int error;
412 	tcflag_t oldcflag;
413 
414 
415 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
416 		return EINVAL;
417 
418 	switch (ISSET(t->c_cflag, CSIZE)) {
419 	case CS5:
420 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
421 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE);
422 		break;
423 	case CS6:
424 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
425 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX);
426 		break;
427 	case CS7:
428 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
429 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN);
430 		break;
431 	case CS8:
432 		CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK);
433 		SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT);
434 		break;
435 	}
436 
437 	CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK);
438 	if (ISSET(t->c_cflag, PARENB)) {
439 		if (ISSET(t->c_cflag, PARODD))
440 			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD);
441 		else
442 			SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN);
443 	}
444 
445 	if (ISSET(t->c_cflag, CSTOPB))
446 		SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO);
447 	else
448 		CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE);
449 
450 	bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon);
451 
452 	if (ospeed == 0) {
453 		/* lower dtr */
454 	}
455 
456 	if (ospeed != 0) {
457 		while (ISSET(tp->t_state, TS_BUSY)) {
458 			++sc->sc_halt;
459 			error = ttysleep(tp, &tp->t_outq,
460 			    TTOPRI | PCATCH, "exuartprm");
461 			--sc->sc_halt;
462 			if (error) {
463 				exuart_start(tp);
464 				return (error);
465 			}
466 		}
467 		/* set speed */
468 	}
469 
470 	/* setup fifo */
471 
472 	/* When not using CRTSCTS, RTS follows DTR. */
473 	/* sc->sc_dtr = MCR_DTR; */
474 
475 
476 	/* and copy to tty */
477 	tp->t_ispeed = t->c_ispeed;
478 	tp->t_ospeed = t->c_ospeed;
479 	oldcflag = tp->t_cflag;
480 	tp->t_cflag = t->c_cflag;
481 
482         /*
483 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
484 	 * stop the device.
485 	 */
486 	 /* XXX */
487 
488 	exuart_start(tp);
489 
490 	return 0;
491 }
492 
493 void
494 exuart_start(struct tty *tp)
495 {
496         struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
497 	bus_space_tag_t iot = sc->sc_iot;
498 	bus_space_handle_t ioh = sc->sc_ioh;
499 	int s;
500 
501 	s = spltty();
502 	if (ISSET(tp->t_state, TS_BUSY))
503 		goto out;
504 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
505 		goto stopped;
506 #ifdef DAMNFUCKSHIT
507 	/* clear to send (IE the RTS pin on this shit) is not directly \
508 	 * readable - skip check for now
509 	 */
510 	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS))
511 		goto stopped;
512 #endif
513 	ttwakeupwr(tp);
514 	if (tp->t_outq.c_cc == 0)
515 		goto stopped;
516 	SET(tp->t_state, TS_BUSY);
517 
518 	{
519 		u_char buffer[16];
520 		int i, n;
521 
522 		n = q_to_b(&tp->t_outq, buffer, sizeof buffer);
523 		for (i = 0; i < n; i++)
524 			bus_space_write_4(iot, ioh, EXUART_UTXH, buffer[i]);
525 		bzero(buffer, n);
526 	}
527 
528 	if (sc->sc_type == EXUART_TYPE_S5L) {
529 		if (!ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
530 			SET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
531 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
532 		}
533 	} else {
534 		if (ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
535 			CLR(sc->sc_uintm, EXUART_UINTM_TXD);
536 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
537 		}
538 	}
539 
540 out:
541 	splx(s);
542 	return;
543 stopped:
544 	if (sc->sc_type == EXUART_TYPE_S5L) {
545 		if (ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) {
546 			CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH);
547 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
548 		}
549 	} else {
550 		if (!ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) {
551 			SET(sc->sc_uintm, EXUART_UINTM_TXD);
552 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
553 		}
554 	}
555 	splx(s);
556 }
557 
558 void
559 exuart_diag(void *arg)
560 {
561 	struct exuart_softc *sc = arg;
562 	int overflows, floods;
563 	int s;
564 
565 	s = spltty();
566 	sc->sc_errors = 0;
567 	overflows = sc->sc_overflows;
568 	sc->sc_overflows = 0;
569 	floods = sc->sc_floods;
570 	sc->sc_floods = 0;
571 	splx(s);
572 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
573 	    sc->sc_dev.dv_xname,
574 	    overflows, overflows == 1 ? "" : "s",
575 	    floods, floods == 1 ? "" : "s");
576 }
577 
578 void
579 exuart_raisedtr(void *arg)
580 {
581 	//struct exuart_softc *sc = arg;
582 
583 	//SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
584 	//bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3);
585 }
586 
587 void
588 exuart_softint(void *arg)
589 {
590 	struct exuart_softc *sc = arg;
591 	struct tty *tp;
592 	u_int16_t *ibufp;
593 	u_int16_t *ibufend;
594 	int c;
595 	int err;
596 	int s;
597 
598 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
599 		return;
600 
601 	tp = sc->sc_tty;
602 
603 	s = spltty();
604 
605 	ibufp = sc->sc_ibuf;
606 	ibufend = sc->sc_ibufp;
607 
608 	if (ibufp == ibufend) {
609 		splx(s);
610 		return;
611 	}
612 
613 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
614 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
615 	sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
616 	sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
617 
618 	if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
619 		splx(s);
620 		return;
621 	}
622 
623 #if 0
624 	if (ISSET(tp->t_cflag, CRTSCTS) &&
625 	    !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) {
626 		/* XXX */
627 		SET(sc->sc_ucr3, EXUART_CR3_DSR);
628 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3,
629 		    sc->sc_ucr3);
630 	}
631 #endif
632 
633 	splx(s);
634 
635 	while (ibufp < ibufend) {
636 		c = *ibufp++;
637 #if 0
638 		if (ISSET(c, EXUART_UERSTAT_OVERRUN)) {
639 			sc->sc_overflows++;
640 			if (sc->sc_errors++ == 0)
641 				timeout_add_sec(&sc->sc_diag_tmo, 60);
642 		}
643 #endif
644 		err = 0;
645 #if 0
646 		if (ISSET(c, EXUART_UERSTAT_PARITY))
647 			err |= TTY_PE;
648 		if (ISSET(c, EXUART_UERSTAT_FRAME))
649 			err |= TTY_FE;
650 #endif
651 		c = (c & 0xff) | err;
652 		(*linesw[tp->t_line].l_rint)(c, tp);
653 	}
654 }
655 
656 int
657 exuartopen(dev_t dev, int flag, int mode, struct proc *p)
658 {
659 	int unit = DEVUNIT(dev);
660 	struct exuart_softc *sc;
661 	bus_space_tag_t iot;
662 	bus_space_handle_t ioh;
663 	struct tty *tp;
664 	int s;
665 	int error = 0;
666 
667 	if (unit >= exuart_cd.cd_ndevs)
668 		return ENXIO;
669 	sc = exuart_cd.cd_devs[unit];
670 	if (sc == NULL)
671 		return ENXIO;
672 
673 	s = spltty();
674 	if (sc->sc_tty == NULL)
675 		tp = sc->sc_tty = ttymalloc(0);
676 	else
677 		tp = sc->sc_tty;
678 	splx(s);
679 
680 	tp->t_oproc = exuart_start;
681 	tp->t_param = exuart_param;
682 	tp->t_dev = dev;
683 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
684 		SET(tp->t_state, TS_WOPEN);
685 		ttychars(tp);
686 		tp->t_iflag = TTYDEF_IFLAG;
687 		tp->t_oflag = TTYDEF_OFLAG;
688 
689 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
690 			tp->t_cflag = exuartconscflag;
691 		else
692 			tp->t_cflag = TTYDEF_CFLAG;
693 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
694 			SET(tp->t_cflag, CLOCAL);
695 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
696 			SET(tp->t_cflag, CRTSCTS);
697 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
698 			SET(tp->t_cflag, MDMBUF);
699 		tp->t_lflag = TTYDEF_LFLAG;
700 		tp->t_ispeed = tp->t_ospeed = exuartdefaultrate;
701 
702 		s = spltty();
703 
704 		sc->sc_initialize = 1;
705 		exuart_param(tp, &tp->t_termios);
706 		ttsetwater(tp);
707 
708 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
709 		sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER;
710 		sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE;
711 
712 		iot = sc->sc_iot;
713 		ioh = sc->sc_ioh;
714 
715 		sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON);
716 		sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON);
717 		sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON);
718 		sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON);
719 
720 		if (sc->sc_type == EXUART_TYPE_S5L) {
721 			SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT);
722 			SET(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH);
723 			SET(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT);
724 			bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon);
725 		} else {
726 			sc->sc_uintm = bus_space_read_4(iot, ioh, EXUART_UINTM);
727 			CLR(sc->sc_uintm, EXUART_UINTM_RXD);
728 			bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm);
729 		}
730 
731 #if 0
732 		/* interrupt after one char on tx/rx */
733 		/* reference frequency divider: 1 */
734 		bus_space_write_2(iot, ioh, EXUART_UFCR,
735 		    1 << EXUART_FCR_TXTL_SH |
736 		    5 << EXUART_FCR_RFDIV_SH |
737 		    1 << EXUART_FCR_RXTL_SH);
738 
739 		bus_space_write_2(iot, ioh, EXUART_UBIR,
740 		    (exuartdefaultrate / 100) - 1);
741 
742 		/* formula: clk / (rfdiv * 1600) */
743 		bus_space_write_2(iot, ioh, EXUART_UBMR,
744 		    (exccm_get_uartclk() * 1000) / 1600);
745 
746 		SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN);
747 		SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN);
748 		bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1);
749 		bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2);
750 
751 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
752 		SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */
753 		bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
754 #endif
755 
756 		SET(tp->t_state, TS_CARR_ON); /* XXX */
757 
758 
759 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
760 		return EBUSY;
761 	else
762 		s = spltty();
763 
764 	if (DEVCUA(dev)) {
765 		if (ISSET(tp->t_state, TS_ISOPEN)) {
766 			splx(s);
767 			return EBUSY;
768 		}
769 		sc->sc_cua = 1;
770 	} else {
771 		/* tty (not cua) device; wait for carrier if necessary */
772 		if (ISSET(flag, O_NONBLOCK)) {
773 			if (sc->sc_cua) {
774 				/* Opening TTY non-blocking... but the CUA is busy */
775 				splx(s);
776 				return EBUSY;
777 			}
778 		} else {
779 			while (sc->sc_cua ||
780 			    (!ISSET(tp->t_cflag, CLOCAL) &&
781 				!ISSET(tp->t_state, TS_CARR_ON))) {
782 				SET(tp->t_state, TS_WOPEN);
783 				error = ttysleep(tp, &tp->t_rawq,
784 				    TTIPRI | PCATCH, ttopen);
785 				/*
786 				 * If TS_WOPEN has been reset, that means the
787 				 * cua device has been closed.  We don't want
788 				 * to fail in that case,
789 				 * so just go around again.
790 				 */
791 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
792 					CLR(tp->t_state, TS_WOPEN);
793 					splx(s);
794 					return error;
795 				}
796 			}
797 		}
798 	}
799 	splx(s);
800 
801 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
802 }
803 
804 int
805 exuartclose(dev_t dev, int flag, int mode, struct proc *p)
806 {
807 	int unit = DEVUNIT(dev);
808 	struct exuart_softc *sc = exuart_cd.cd_devs[unit];
809 	//bus_space_tag_t iot = sc->sc_iot;
810 	//bus_space_handle_t ioh = sc->sc_ioh;
811 	struct tty *tp = sc->sc_tty;
812 	int s;
813 
814 	/* XXX This is for cons.c. */
815 	if (!ISSET(tp->t_state, TS_ISOPEN))
816 		return 0;
817 
818 	(*linesw[tp->t_line].l_close)(tp, flag, p);
819 	s = spltty();
820 	if (ISSET(tp->t_state, TS_WOPEN)) {
821 		/* tty device is waiting for carrier; drop dtr then re-raise */
822 		//CLR(sc->sc_ucr3, EXUART_CR3_DSR);
823 		//bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3);
824 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
825 	}
826 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
827 	sc->sc_cua = 0;
828 	splx(s);
829 	ttyclose(tp);
830 
831 	return 0;
832 }
833 
834 int
835 exuartread(dev_t dev, struct uio *uio, int flag)
836 {
837 	struct tty *tty;
838 
839 	tty = exuarttty(dev);
840 	if (tty == NULL)
841 		return ENODEV;
842 
843 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
844 }
845 
846 int
847 exuartwrite(dev_t dev, struct uio *uio, int flag)
848 {
849 	struct tty *tty;
850 
851 	tty = exuarttty(dev);
852 	if (tty == NULL)
853 		return ENODEV;
854 
855 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
856 }
857 
858 int
859 exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
860 {
861 	struct exuart_softc *sc;
862 	struct tty *tp;
863 	int error;
864 
865 	sc = exuart_sc(dev);
866 	if (sc == NULL)
867 		return (ENODEV);
868 
869 	tp = sc->sc_tty;
870 	if (tp == NULL)
871 		return (ENXIO);
872 
873 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
874 	if (error >= 0)
875 		return (error);
876 
877 	error = ttioctl(tp, cmd, data, flag, p);
878 	if (error >= 0)
879 		return (error);
880 
881 	switch(cmd) {
882 	case TIOCSBRK:
883 		/* */
884 		break;
885 
886 	case TIOCCBRK:
887 		/* */
888 		break;
889 
890 	case TIOCSDTR:
891 #if 0
892 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
893 #endif
894 		break;
895 
896 	case TIOCCDTR:
897 #if 0
898 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
899 #endif
900 		break;
901 
902 	case TIOCMSET:
903 #if 0
904 		(void) clmctl(dev, *(int *) data, DMSET);
905 #endif
906 		break;
907 
908 	case TIOCMBIS:
909 #if 0
910 		(void) clmctl(dev, *(int *) data, DMBIS);
911 #endif
912 		break;
913 
914 	case TIOCMBIC:
915 #if 0
916 		(void) clmctl(dev, *(int *) data, DMBIC);
917 #endif
918 		break;
919 
920         case TIOCMGET:
921 #if 0
922 		*(int *)data = clmctl(dev, 0, DMGET);
923 #endif
924 		break;
925 
926 	case TIOCGFLAGS:
927 #if 0
928 		*(int *)data = cl->cl_swflags;
929 #endif
930 		break;
931 
932 	case TIOCSFLAGS:
933 		error = suser(p);
934 		if (error != 0)
935 			return(EPERM);
936 
937 #if 0
938 		cl->cl_swflags = *(int *)data;
939 		cl->cl_swflags &= /* only allow valid flags */
940 		    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
941 #endif
942 		break;
943 	default:
944 		return (ENOTTY);
945 	}
946 
947 	return 0;
948 }
949 
950 int
951 exuartstop(struct tty *tp, int flag)
952 {
953 	return 0;
954 }
955 
956 struct tty *
957 exuarttty(dev_t dev)
958 {
959 	int unit;
960 	struct exuart_softc *sc;
961 	unit = DEVUNIT(dev);
962 	if (unit >= exuart_cd.cd_ndevs)
963 		return NULL;
964 	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
965 	if (sc == NULL)
966 		return NULL;
967 	return sc->sc_tty;
968 }
969 
970 struct exuart_softc *
971 exuart_sc(dev_t dev)
972 {
973 	int unit;
974 	struct exuart_softc *sc;
975 	unit = DEVUNIT(dev);
976 	if (unit >= exuart_cd.cd_ndevs)
977 		return NULL;
978 	sc = (struct exuart_softc *)exuart_cd.cd_devs[unit];
979 	return sc;
980 }
981 
982 
983 /* serial console */
984 void
985 exuartcnprobe(struct consdev *cp)
986 {
987 }
988 
989 void
990 exuartcninit(struct consdev *cp)
991 {
992 }
993 
994 int
995 exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
996 {
997 	static struct consdev exuartcons = {
998 		NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL,
999 		NODEV, CN_MIDPRI
1000 	};
1001 	int maj;
1002 
1003 	if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh))
1004 		return ENOMEM;
1005 
1006 	/* Look for major of com(4) to replace. */
1007 	for (maj = 0; maj < nchrdev; maj++)
1008 		if (cdevsw[maj].d_open == comopen)
1009 			break;
1010 	if (maj == nchrdev)
1011 		return ENXIO;
1012 
1013 	cn_tab = &exuartcons;
1014 	cn_tab->cn_dev = makedev(maj, 0);
1015 	cdevsw[maj] = exuartdev; 	/* KLUDGE */
1016 
1017 	exuartconsiot = iot;
1018 	exuartconsaddr = iobase;
1019 	exuartconscflag = cflag;
1020 
1021 	return 0;
1022 }
1023 
1024 int
1025 exuartcngetc(dev_t dev)
1026 {
1027 	int c;
1028 	int s;
1029 	s = splhigh();
1030 	while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) &
1031 	    EXUART_UTRSTAT_RXBREADY) == 0 &&
1032 	      (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
1033 	    (exuart_rx_fifo_cnt_mask | exuart_rx_fifo_full)) == 0)
1034 		;
1035 	c = bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_URXH);
1036 	splx(s);
1037 	return c;
1038 }
1039 
1040 void
1041 exuartcnputc(dev_t dev, int c)
1042 {
1043 	int s;
1044 	s = splhigh();
1045 	while (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) &
1046 	   exuart_tx_fifo_full)
1047 		;
1048 	bus_space_write_4(exuartconsiot, exuartconsioh, EXUART_UTXH, c);
1049 	splx(s);
1050 }
1051 
1052 void
1053 exuartcnpollc(dev_t dev, int on)
1054 {
1055 }
1056