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