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