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