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
50struct 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
88int	 imxuart_match(struct device *, void *, void *);
89void	 imxuart_attach(struct device *, struct device *, void *);
90
91void imxuartcnprobe(struct consdev *cp);
92void imxuartcninit(struct consdev *cp);
93int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
94    tcflag_t cflag);
95int imxuartcngetc(dev_t dev);
96void imxuartcnputc(dev_t dev, int c);
97void imxuartcnpollc(dev_t dev, int on);
98int  imxuart_param(struct tty *tp, struct termios *t);
99void imxuart_start(struct tty *);
100void imxuart_diag(void *arg);
101void imxuart_raisedtr(void *arg);
102void imxuart_softint(void *arg);
103struct imxuart_softc *imxuart_sc(dev_t dev);
104
105int imxuart_intr(void *);
106
107/* XXX - we imitate 'com' serial ports and take over their entry points */
108/* XXX: These belong elsewhere */
109cdev_decl(com);
110cdev_decl(imxuart);
111
112struct cfdriver imxuart_cd = {
113	NULL, "imxuart", DV_TTY
114};
115
116const struct cfattach imxuart_ca = {
117	sizeof(struct imxuart_softc), imxuart_match, imxuart_attach
118};
119
120bus_space_tag_t	imxuartconsiot;
121bus_space_handle_t imxuartconsioh;
122bus_addr_t	imxuartconsaddr;
123tcflag_t	imxuartconscflag = TTYDEF_CFLAG;
124int		imxuartdefaultrate = B115200;
125
126struct cdevsw imxuartdev =
127	cdev_tty_init(3/*XXX NIMXUART */ ,imxuart);		/* 12: serial port */
128
129void
130imxuart_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
145int
146imxuart_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
154void
155imxuart_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
197int
198imxuart_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
260int
261imxuart_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
334void
335imxuart_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;
381stopped:
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
389void
390imxuart_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
409void
410imxuart_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
418void
419imxuart_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
477int
478imxuartopen(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
612int
613imxuartclose(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
643int
644imxuartread(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
655int
656imxuartwrite(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
667int
668imxuartioctl( 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
759int
760imxuartstop(struct tty *tp, int flag)
761{
762	return 0;
763}
764
765struct tty *
766imxuarttty(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
779struct imxuart_softc *
780imxuart_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 */
793void
794imxuartcnprobe(struct consdev *cp)
795{
796}
797
798void
799imxuartcninit(struct consdev *cp)
800{
801}
802
803int
804imxuartcnattach(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
841int
842imxuartcngetc(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
855void
856imxuartcnputc(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
867void
868imxuartcnpollc(dev_t dev, int on)
869{
870}
871