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