xref: /openbsd-src/sys/dev/fdt/imxuart.c (revision ffcef06798eb7b98532e76a80212f0772bebc4f6)
1 /* $OpenBSD: imxuart.c,v 1.11 2021/09/01 09:29:31 jan 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/select.h>
30 #include <sys/kernel.h>
31 
32 #include <machine/bus.h>
33 #include <machine/fdt.h>
34 
35 #include <dev/cons.h>
36 
37 #ifdef DDB
38 #include <ddb/db_var.h>
39 #endif
40 
41 #include <dev/fdt/imxuartreg.h>
42 
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/ofw_clock.h>
45 #include <dev/ofw/ofw_pinctrl.h>
46 #include <dev/ofw/fdt.h>
47 
48 #define DEVUNIT(x)      (minor(x) & 0x7f)
49 #define DEVCUA(x)       (minor(x) & 0x80)
50 
51 struct imxuart_softc {
52 	struct device	sc_dev;
53 	bus_space_tag_t sc_iot;
54 	bus_space_handle_t sc_ioh;
55 	int		sc_node;
56 	struct soft_intrhand *sc_si;
57 	void *sc_irq;
58 	struct tty	*sc_tty;
59 	struct timeout	sc_diag_tmo;
60 	struct timeout	sc_dtr_tmo;
61 	int		sc_overflows;
62 	int		sc_floods;
63 	int		sc_errors;
64 	int		sc_halt;
65 	u_int16_t	sc_ucr1;
66 	u_int16_t	sc_ucr2;
67 	u_int16_t	sc_ucr3;
68 	u_int16_t	sc_ucr4;
69 	u_int8_t	sc_hwflags;
70 #define COM_HW_NOIEN    0x01
71 #define COM_HW_FIFO     0x02
72 #define COM_HW_SIR      0x20
73 #define COM_HW_CONSOLE  0x40
74 	u_int8_t	sc_swflags;
75 #define COM_SW_SOFTCAR  0x01
76 #define COM_SW_CLOCAL   0x02
77 #define COM_SW_CRTSCTS  0x04
78 #define COM_SW_MDMBUF   0x08
79 #define COM_SW_PPS      0x10
80 
81 	u_int8_t	sc_initialize;
82 	u_int8_t	sc_cua;
83 	u_int16_t 	*sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
84 #define IMXUART_IBUFSIZE 128
85 #define IMXUART_IHIGHWATER 100
86 	u_int16_t		sc_ibufs[2][IMXUART_IBUFSIZE];
87 };
88 
89 int	 imxuart_match(struct device *, void *, void *);
90 void	 imxuart_attach(struct device *, struct device *, void *);
91 
92 void imxuartcnprobe(struct consdev *cp);
93 void imxuartcninit(struct consdev *cp);
94 int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
95     tcflag_t cflag);
96 int imxuartcngetc(dev_t dev);
97 void imxuartcnputc(dev_t dev, int c);
98 void imxuartcnpollc(dev_t dev, int on);
99 int  imxuart_param(struct tty *tp, struct termios *t);
100 void imxuart_start(struct tty *);
101 void imxuart_diag(void *arg);
102 void imxuart_raisedtr(void *arg);
103 void imxuart_softint(void *arg);
104 struct imxuart_softc *imxuart_sc(dev_t dev);
105 
106 int imxuart_intr(void *);
107 
108 /* XXX - we imitate 'com' serial ports and take over their entry points */
109 /* XXX: These belong elsewhere */
110 cdev_decl(com);
111 cdev_decl(imxuart);
112 
113 struct cfdriver imxuart_cd = {
114 	NULL, "imxuart", DV_TTY
115 };
116 
117 struct cfattach imxuart_ca = {
118 	sizeof(struct imxuart_softc), imxuart_match, imxuart_attach
119 };
120 
121 bus_space_tag_t	imxuartconsiot;
122 bus_space_handle_t imxuartconsioh;
123 bus_addr_t	imxuartconsaddr;
124 tcflag_t	imxuartconscflag = TTYDEF_CFLAG;
125 int		imxuartdefaultrate = B115200;
126 
127 struct cdevsw imxuartdev =
128 	cdev_tty_init(3/*XXX NIMXUART */ ,imxuart);		/* 12: serial port */
129 
130 void
131 imxuart_init_cons(void)
132 {
133 	struct fdt_reg reg;
134 	void *node;
135 
136 	if ((node = fdt_find_cons("fsl,imx21-uart")) == NULL &&
137 	    (node = fdt_find_cons("fsl,imx6q-uart")) == NULL)
138 		return;
139 
140 	if (fdt_get_reg(node, 0, &reg))
141 		return;
142 
143 	imxuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
144 }
145 
146 int
147 imxuart_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, "fsl,imx21-uart") ||
152 	    OF_is_compatible(faa->fa_node, "fsl,imx6q-uart"));
153 }
154 
155 void
156 imxuart_attach(struct device *parent, struct device *self, void *aux)
157 {
158 	struct imxuart_softc *sc = (struct imxuart_softc *) self;
159 	struct fdt_attach_args *faa = aux;
160 	int maj;
161 
162 	if (faa->fa_nreg < 1)
163 		return;
164 
165 	pinctrl_byname(faa->fa_node, "default");
166 
167 	sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY,
168 	    imxuart_intr, sc, sc->sc_dev.dv_xname);
169 
170 	sc->sc_node = faa->fa_node;
171 	sc->sc_iot = faa->fa_iot;
172 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
173 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
174 		panic("imxuartattach: bus_space_map failed!");
175 
176 	if (faa->fa_reg[0].addr == imxuartconsaddr) {
177 		/* Locate the major number. */
178 		for (maj = 0; maj < nchrdev; maj++)
179 			if (cdevsw[maj].d_open == imxuartopen)
180 				break;
181 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
182 
183 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
184 		printf(": console");
185 	}
186 
187 	timeout_set(&sc->sc_diag_tmo, imxuart_diag, sc);
188 	timeout_set(&sc->sc_dtr_tmo, imxuart_raisedtr, sc);
189 	sc->sc_si = softintr_establish(IPL_TTY, imxuart_softint, sc);
190 
191 	if(sc->sc_si == NULL)
192 		panic("%s: can't establish soft interrupt.",
193 		    sc->sc_dev.dv_xname);
194 
195 	printf("\n");
196 }
197 
198 int
199 imxuart_intr(void *arg)
200 {
201 	struct imxuart_softc *sc = arg;
202 	bus_space_tag_t iot = sc->sc_iot;
203 	bus_space_handle_t ioh = sc->sc_ioh;
204 	struct tty *tp = sc->sc_tty;
205 	u_int16_t sr1;
206 	u_int16_t *p;
207 	u_int16_t c;
208 
209 	sr1 = bus_space_read_2(iot, ioh, IMXUART_USR1);
210 	if (ISSET(sr1, IMXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) {
211 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
212 		if (sc->sc_halt > 0)
213 			wakeup(&tp->t_outq);
214 		(*linesw[tp->t_line].l_start)(tp);
215 	}
216 
217 	if (sc->sc_tty == NULL)
218 		return(0);
219 
220 	if(!ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR))
221 		return 0;
222 
223 	p = sc->sc_ibufp;
224 
225 	while(ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) {
226 		c = bus_space_read_2(iot, ioh, IMXUART_URXD);
227 		if (ISSET(c, IMXUART_RX_BRK)) {
228 #ifdef DDB
229 			if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
230 				if (db_console)
231 					db_enter();
232 				continue;
233 			}
234 #endif
235 			c &= ~0xff;
236 		}
237 		if (p >= sc->sc_ibufend) {
238 			sc->sc_floods++;
239 			if (sc->sc_errors++ == 0)
240 				timeout_add_sec(&sc->sc_diag_tmo, 60);
241 		} else {
242 			*p++ = c;
243 			if (p == sc->sc_ibufhigh &&
244 			    ISSET(tp->t_cflag, CRTSCTS)) {
245 				/* XXX */
246 				CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
247 				bus_space_write_2(iot, ioh, IMXUART_UCR3,
248 				    sc->sc_ucr3);
249 			}
250 
251 		}
252 		/* XXX - msr stuff ? */
253 	}
254 	sc->sc_ibufp = p;
255 
256 	softintr_schedule(sc->sc_si);
257 
258 	return 1;
259 }
260 
261 int
262 imxuart_param(struct tty *tp, struct termios *t)
263 {
264 	struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
265 	bus_space_tag_t iot = sc->sc_iot;
266 	bus_space_handle_t ioh = sc->sc_ioh;
267 	int ospeed = t->c_ospeed;
268 	int error;
269 	tcflag_t oldcflag;
270 
271 
272 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
273 		return EINVAL;
274 
275 	switch (ISSET(t->c_cflag, CSIZE)) {
276 	case CS5:
277 		return EINVAL;
278 	case CS6:
279 		return EINVAL;
280 	case CS7:
281 		CLR(sc->sc_ucr2, IMXUART_CR2_WS);
282 		break;
283 	case CS8:
284 		SET(sc->sc_ucr2, IMXUART_CR2_WS);
285 		break;
286 	}
287 //	bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
288 
289 	if (ISSET(t->c_cflag, PARENB)) {
290 		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
291 		bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
292 	}
293 	/* STOPB - XXX */
294 	if (ospeed == 0) {
295 		/* lower dtr */
296 	}
297 
298 	if (ospeed != 0) {
299 		while (ISSET(tp->t_state, TS_BUSY)) {
300 			++sc->sc_halt;
301 			error = ttysleep(tp, &tp->t_outq,
302 			    TTOPRI | PCATCH, "imxuartprm");
303 			--sc->sc_halt;
304 			if (error) {
305 				imxuart_start(tp);
306 				return (error);
307 			}
308 		}
309 		/* set speed */
310 	}
311 
312 	/* setup fifo */
313 
314 	/* When not using CRTSCTS, RTS follows DTR. */
315 	/* sc->sc_dtr = MCR_DTR; */
316 
317 
318 	/* and copy to tty */
319 	tp->t_ispeed = t->c_ispeed;
320 	tp->t_ospeed = t->c_ospeed;
321 	oldcflag = tp->t_cflag;
322 	tp->t_cflag = t->c_cflag;
323 
324         /*
325 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
326 	 * stop the device.
327 	 */
328 	 /* XXX */
329 
330 	imxuart_start(tp);
331 
332 	return 0;
333 }
334 
335 void
336 imxuart_start(struct tty *tp)
337 {
338         struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
339 	bus_space_tag_t iot = sc->sc_iot;
340 	bus_space_handle_t ioh = sc->sc_ioh;
341 
342 	int s;
343 	s = spltty();
344 	if (ISSET(tp->t_state, TS_BUSY)) {
345 		splx(s);
346 		return;
347 	}
348 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
349 		goto stopped;
350 #ifdef DAMNFUCKSHIT
351 	/* clear to send (IE the RTS pin on this shit) is not directly \
352 	 * readable - skip check for now
353 	 */
354 	if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, IMXUART_CTS))
355 		goto stopped;
356 #endif
357 	if (tp->t_outq.c_cc <= tp->t_lowat) {
358 		if (ISSET(tp->t_state, TS_ASLEEP)) {
359 			CLR(tp->t_state, TS_ASLEEP);
360 			wakeup(&tp->t_outq);
361 		}
362 		if (tp->t_outq.c_cc == 0)
363 			goto stopped;
364 		selwakeup(&tp->t_wsel);
365 	}
366 	SET(tp->t_state, TS_BUSY);
367 
368 	if (!ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
369 		SET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
370 		bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
371 	}
372 
373 	{
374 		u_char buf[32];
375 		int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
376 		int i;
377 		for (i = 0; i < n; i++)
378 			bus_space_write_1(iot, ioh, IMXUART_UTXD, buf[i]);
379 	}
380 	splx(s);
381 	return;
382 stopped:
383 	if (ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
384 		CLR(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
385 		bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
386 	}
387 	splx(s);
388 }
389 
390 void
391 imxuart_diag(void *arg)
392 {
393 	struct imxuart_softc *sc = arg;
394 	int overflows, floods;
395 	int s;
396 
397 	s = spltty();
398 	sc->sc_errors = 0;
399 	overflows = sc->sc_overflows;
400 	sc->sc_overflows = 0;
401 	floods = sc->sc_floods;
402 	sc->sc_floods = 0;
403 	splx(s);
404 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
405 	    sc->sc_dev.dv_xname,
406 	    overflows, overflows == 1 ? "" : "s",
407 	    floods, floods == 1 ? "" : "s");
408 }
409 
410 void
411 imxuart_raisedtr(void *arg)
412 {
413 	struct imxuart_softc *sc = arg;
414 
415 	SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
416 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
417 }
418 
419 void
420 imxuart_softint(void *arg)
421 {
422 	struct imxuart_softc *sc = arg;
423 	struct tty *tp;
424 	u_int16_t *ibufp;
425 	u_int16_t *ibufend;
426 	int c;
427 	int err;
428 	int s;
429 
430 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
431 		return;
432 
433 	tp = sc->sc_tty;
434 	s = spltty();
435 
436 	ibufp = sc->sc_ibuf;
437 	ibufend = sc->sc_ibufp;
438 
439 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
440 		splx(s);
441 		return;
442 	}
443 
444 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
445 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
446 	sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
447 	sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
448 
449 	if (ISSET(tp->t_cflag, CRTSCTS) &&
450 	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
451 		/* XXX */
452 		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
453 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
454 		    sc->sc_ucr3);
455 	}
456 
457 	splx(s);
458 
459 	while (ibufp < ibufend) {
460 		c = *ibufp++;
461 		if (ISSET(c, IMXUART_RX_OVERRUN)) {
462 			sc->sc_overflows++;
463 			if (sc->sc_errors++ == 0)
464 				timeout_add_sec(&sc->sc_diag_tmo, 60);
465 		}
466 		/* This is ugly, but fast. */
467 
468 		err = 0;
469 		if (ISSET(c, IMXUART_RX_PRERR))
470 			err |= TTY_PE;
471 		if (ISSET(c, IMXUART_RX_FRMERR))
472 			err |= TTY_FE;
473 		c = (c & 0xff) | err;
474 		(*linesw[tp->t_line].l_rint)(c, tp);
475 	}
476 }
477 
478 int
479 imxuartopen(dev_t dev, int flag, int mode, struct proc *p)
480 {
481 	int unit = DEVUNIT(dev);
482 	struct imxuart_softc *sc;
483 	bus_space_tag_t iot;
484 	bus_space_handle_t ioh;
485 	struct tty *tp;
486 	int s;
487 	int error = 0;
488 
489 	if (unit >= imxuart_cd.cd_ndevs)
490 		return ENXIO;
491 	sc = imxuart_cd.cd_devs[unit];
492 	if (sc == NULL)
493 		return ENXIO;
494 
495 	s = spltty();
496 	if (sc->sc_tty == NULL)
497 		tp = sc->sc_tty = ttymalloc(0);
498 	else
499 		tp = sc->sc_tty;
500 
501 	splx(s);
502 
503 	tp->t_oproc = imxuart_start;
504 	tp->t_param = imxuart_param;
505 	tp->t_dev = dev;
506 
507 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
508 		SET(tp->t_state, TS_WOPEN);
509 		ttychars(tp);
510 		tp->t_iflag = TTYDEF_IFLAG;
511 		tp->t_oflag = TTYDEF_OFLAG;
512 
513 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
514 			tp->t_cflag = imxuartconscflag;
515 		else
516 			tp->t_cflag = TTYDEF_CFLAG;
517 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
518 			SET(tp->t_cflag, CLOCAL);
519 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
520 			SET(tp->t_cflag, CRTSCTS);
521 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
522 			SET(tp->t_cflag, MDMBUF);
523 		tp->t_lflag = TTYDEF_LFLAG;
524 		tp->t_ispeed = tp->t_ospeed = imxuartdefaultrate;
525 
526 		s = spltty();
527 
528 		sc->sc_initialize = 1;
529 		imxuart_param(tp, &tp->t_termios);
530 		ttsetwater(tp);
531 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
532 		sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
533 		sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
534 
535 		iot = sc->sc_iot;
536 		ioh = sc->sc_ioh;
537 
538 		sc->sc_ucr1 = bus_space_read_2(iot, ioh, IMXUART_UCR1);
539 		sc->sc_ucr2 = bus_space_read_2(iot, ioh, IMXUART_UCR2);
540 		sc->sc_ucr3 = bus_space_read_2(iot, ioh, IMXUART_UCR3);
541 		sc->sc_ucr4 = bus_space_read_2(iot, ioh, IMXUART_UCR4);
542 
543 		/* interrupt after one char on tx/rx */
544 		/* reference frequency divider: 1 */
545 		bus_space_write_2(iot, ioh, IMXUART_UFCR,
546 		    1 << IMXUART_FCR_TXTL_SH |
547 		    5 << IMXUART_FCR_RFDIV_SH |
548 		    1 << IMXUART_FCR_RXTL_SH);
549 
550 		bus_space_write_2(iot, ioh, IMXUART_UBIR,
551 		    (imxuartdefaultrate / 100) - 1);
552 
553 		/* formula: clk / (rfdiv * 1600) */
554 		bus_space_write_2(iot, ioh, IMXUART_UBMR,
555 		    clock_get_frequency(sc->sc_node, "per") / 1600);
556 
557 		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
558 		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
559 		bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
560 		bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
561 
562 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
563 		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
564 		bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
565 
566 		SET(tp->t_state, TS_CARR_ON); /* XXX */
567 
568 
569 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
570 		return EBUSY;
571 	else
572 		s = spltty();
573 
574 	if (DEVCUA(dev)) {
575 		if (ISSET(tp->t_state, TS_ISOPEN)) {
576 			splx(s);
577 			return EBUSY;
578 		}
579 		sc->sc_cua = 1;
580 	} else {
581 		/* tty (not cua) device; wait for carrier if necessary */
582 		if (ISSET(flag, O_NONBLOCK)) {
583 			if (sc->sc_cua) {
584 				/* Opening TTY non-blocking... but the CUA is busy */
585 				splx(s);
586 				return EBUSY;
587 			}
588 		} else {
589 			while (sc->sc_cua ||
590 			    (!ISSET(tp->t_cflag, CLOCAL) &&
591 				!ISSET(tp->t_state, TS_CARR_ON))) {
592 				SET(tp->t_state, TS_WOPEN);
593 				error = ttysleep(tp, &tp->t_rawq,
594 				    TTIPRI | PCATCH, ttopen);
595 				/*
596 				 * If TS_WOPEN has been reset, that means the
597 				 * cua device has been closed.  We don't want
598 				 * to fail in that case,
599 				 * so just go around again.
600 				 */
601 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
602 					CLR(tp->t_state, TS_WOPEN);
603 					splx(s);
604 					return error;
605 				}
606 			}
607 		}
608 	}
609 	splx(s);
610 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
611 }
612 
613 int
614 imxuartclose(dev_t dev, int flag, int mode, struct proc *p)
615 {
616 	int unit = DEVUNIT(dev);
617 	struct imxuart_softc *sc = imxuart_cd.cd_devs[unit];
618 	bus_space_tag_t iot = sc->sc_iot;
619 	bus_space_handle_t ioh = sc->sc_ioh;
620 	struct tty *tp = sc->sc_tty;
621 	int s;
622 
623 	/* XXX This is for cons.c. */
624 	if (!ISSET(tp->t_state, TS_ISOPEN))
625 		return 0;
626 
627 	(*linesw[tp->t_line].l_close)(tp, flag, p);
628 	s = spltty();
629 	if (ISSET(tp->t_state, TS_WOPEN)) {
630 		/* tty device is waiting for carrier; drop dtr then re-raise */
631 		CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
632 		bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
633 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
634 	}
635 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
636 
637 	sc->sc_cua = 0;
638 	splx(s);
639 	ttyclose(tp);
640 
641 	return 0;
642 }
643 
644 int
645 imxuartread(dev_t dev, struct uio *uio, int flag)
646 {
647 	struct tty *tty;
648 
649 	tty = imxuarttty(dev);
650 	if (tty == NULL)
651 		return ENODEV;
652 
653 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
654 }
655 
656 int
657 imxuartwrite(dev_t dev, struct uio *uio, int flag)
658 {
659 	struct tty *tty;
660 
661 	tty = imxuarttty(dev);
662 	if (tty == NULL)
663 		return ENODEV;
664 
665 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
666 }
667 
668 int
669 imxuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
670 {
671 	struct imxuart_softc *sc;
672 	struct tty *tp;
673 	int error;
674 
675 	sc = imxuart_sc(dev);
676 	if (sc == NULL)
677 		return (ENODEV);
678 
679 	tp = sc->sc_tty;
680 	if (tp == NULL)
681 		return (ENXIO);
682 
683 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
684 	if (error >= 0)
685 		return (error);
686 
687 	error = ttioctl(tp, cmd, data, flag, p);
688 	if (error >= 0)
689 		return (error);
690 
691 	switch(cmd) {
692 	case TIOCSBRK:
693 		/* */
694 		break;
695 
696 	case TIOCCBRK:
697 		/* */
698 		break;
699 
700 	case TIOCSDTR:
701 #if 0
702 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
703 #endif
704 		break;
705 
706 	case TIOCCDTR:
707 #if 0
708 		(void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
709 #endif
710 		break;
711 
712 	case TIOCMSET:
713 #if 0
714 		(void) clmctl(dev, *(int *) data, DMSET);
715 #endif
716 		break;
717 
718 	case TIOCMBIS:
719 #if 0
720 		(void) clmctl(dev, *(int *) data, DMBIS);
721 #endif
722 		break;
723 
724 	case TIOCMBIC:
725 #if 0
726 		(void) clmctl(dev, *(int *) data, DMBIC);
727 #endif
728 		break;
729 
730         case TIOCMGET:
731 #if 0
732 		*(int *)data = clmctl(dev, 0, DMGET);
733 #endif
734 		break;
735 
736 	case TIOCGFLAGS:
737 #if 0
738 		*(int *)data = cl->cl_swflags;
739 #endif
740 		break;
741 
742 	case TIOCSFLAGS:
743 		error = suser(p);
744 		if (error != 0)
745 			return(EPERM);
746 
747 #if 0
748 		cl->cl_swflags = *(int *)data;
749 		cl->cl_swflags &= /* only allow valid flags */
750 		    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
751 #endif
752 		break;
753 	default:
754 		return (ENOTTY);
755 	}
756 
757 	return 0;
758 }
759 
760 int
761 imxuartstop(struct tty *tp, int flag)
762 {
763 	return 0;
764 }
765 
766 struct tty *
767 imxuarttty(dev_t dev)
768 {
769 	int unit;
770 	struct imxuart_softc *sc;
771 	unit = DEVUNIT(dev);
772 	if (unit >= imxuart_cd.cd_ndevs)
773 		return NULL;
774 	sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
775 	if (sc == NULL)
776 		return NULL;
777 	return sc->sc_tty;
778 }
779 
780 struct imxuart_softc *
781 imxuart_sc(dev_t dev)
782 {
783 	int unit;
784 	struct imxuart_softc *sc;
785 	unit = DEVUNIT(dev);
786 	if (unit >= imxuart_cd.cd_ndevs)
787 		return NULL;
788 	sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
789 	return sc;
790 }
791 
792 
793 /* serial console */
794 void
795 imxuartcnprobe(struct consdev *cp)
796 {
797 }
798 
799 void
800 imxuartcninit(struct consdev *cp)
801 {
802 }
803 
804 int
805 imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
806 {
807 	static struct consdev imxuartcons = {
808 		NULL, NULL, imxuartcngetc, imxuartcnputc, imxuartcnpollc, NULL,
809 		NODEV, CN_MIDPRI
810 	};
811 	int maj;
812 
813 	if (bus_space_map(iot, iobase, IMXUART_SPACE, 0, &imxuartconsioh))
814 		return ENOMEM;
815 
816 	/* Look for major of com(4) to replace. */
817 	for (maj = 0; maj < nchrdev; maj++)
818 		if (cdevsw[maj].d_open == comopen)
819 			break;
820 	if (maj == nchrdev)
821 		return ENXIO;
822 
823 	cn_tab = &imxuartcons;
824 	cn_tab->cn_dev = makedev(maj, 0);
825 	cdevsw[maj] = imxuartdev; 	/* KLUDGE */
826 
827 	imxuartconsiot = iot;
828 	imxuartconsaddr = iobase;
829 	imxuartconscflag = cflag;
830 
831 	// XXXX: Overwrites some sensitive bits, recheck later.
832 	/*
833 	bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR1,
834 	    IMXUART_CR1_EN);
835 	bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR2,
836 	    IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
837 	*/
838 
839 	return 0;
840 }
841 
842 int
843 imxuartcngetc(dev_t dev)
844 {
845 	int c;
846 	int s;
847 	s = splhigh();
848 	while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
849 	    IMXUART_SR2_RDR) == 0)
850 		;
851 	c = bus_space_read_1(imxuartconsiot, imxuartconsioh, IMXUART_URXD);
852 	splx(s);
853 	return c;
854 }
855 
856 void
857 imxuartcnputc(dev_t dev, int c)
858 {
859 	int s;
860 	s = splhigh();
861 	bus_space_write_1(imxuartconsiot, imxuartconsioh, IMXUART_UTXD, (uint8_t)c);
862 	while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
863 	    IMXUART_SR2_TXDC) == 0)
864 		;
865 	splx(s);
866 }
867 
868 void
869 imxuartcnpollc(dev_t dev, int on)
870 {
871 }
872