xref: /openbsd/sys/dev/ic/pluart.c (revision 3cab2bb3)
1 /*	$OpenBSD: pluart.c,v 1.5 2020/01/10 04:10:15 cheloha Exp $	*/
2 /*
3  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
4  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/ioctl.h>
21 #include <sys/proc.h>
22 #include <sys/tty.h>
23 #include <sys/uio.h>
24 #include <sys/systm.h>
25 #include <sys/time.h>
26 #include <sys/device.h>
27 #include <sys/syslog.h>
28 #include <sys/conf.h>
29 #include <sys/fcntl.h>
30 #include <sys/select.h>
31 #include <sys/kernel.h>
32 
33 #include <machine/bus.h>
34 
35 #include <dev/ic/pluartvar.h>
36 #include <dev/cons.h>
37 
38 #ifdef DDB
39 #include <ddb/db_var.h>
40 #endif
41 
42 #define DEVUNIT(x)      (minor(x) & 0x7f)
43 #define DEVCUA(x)       (minor(x) & 0x80)
44 
45 #define UART_DR			0x00		/* Data register */
46 #define UART_DR_DATA(x)		((x) & 0xf)
47 #define UART_DR_FE		(1 << 8)	/* Framing error */
48 #define UART_DR_PE		(1 << 9)	/* Parity error */
49 #define UART_DR_BE		(1 << 10)	/* Break error */
50 #define UART_DR_OE		(1 << 11)	/* Overrun error */
51 #define UART_RSR		0x04		/* Receive status register */
52 #define UART_RSR_FE		(1 << 0)	/* Framing error */
53 #define UART_RSR_PE		(1 << 1)	/* Parity error */
54 #define UART_RSR_BE		(1 << 2)	/* Break error */
55 #define UART_RSR_OE		(1 << 3)	/* Overrun error */
56 #define UART_ECR		0x04		/* Error clear register */
57 #define UART_ECR_FE		(1 << 0)	/* Framing error */
58 #define UART_ECR_PE		(1 << 1)	/* Parity error */
59 #define UART_ECR_BE		(1 << 2)	/* Break error */
60 #define UART_ECR_OE		(1 << 3)	/* Overrun error */
61 #define UART_FR			0x18		/* Flag register */
62 #define UART_FR_CTS		(1 << 0)	/* Clear to send */
63 #define UART_FR_DSR		(1 << 1)	/* Data set ready */
64 #define UART_FR_DCD		(1 << 2)	/* Data carrier detect */
65 #define UART_FR_BUSY		(1 << 3)	/* UART busy */
66 #define UART_FR_RXFE		(1 << 4)	/* Receive FIFO empty */
67 #define UART_FR_TXFF		(1 << 5)	/* Transmit FIFO full */
68 #define UART_FR_RXFF		(1 << 6)	/* Receive FIFO full */
69 #define UART_FR_TXFE		(1 << 7)	/* Transmit FIFO empty */
70 #define UART_FR_RI		(1 << 8)	/* Ring indicator */
71 #define UART_ILPR		0x20		/* IrDA low-power counter register */
72 #define UART_ILPR_ILPDVSR	((x) & 0xf)	/* IrDA low-power divisor */
73 #define UART_IBRD		0x24		/* Integer baud rate register */
74 #define UART_IBRD_DIVINT	((x) & 0xff)	/* Integer baud rate divisor */
75 #define UART_FBRD		0x28		/* Fractional baud rate register */
76 #define UART_FBRD_DIVFRAC	((x) & 0x3f)	/* Fractional baud rate divisor */
77 #define UART_LCR_H		0x2c		/* Line control register */
78 #define UART_LCR_H_BRK		(1 << 0)	/* Send break */
79 #define UART_LCR_H_PEN		(1 << 1)	/* Parity enable */
80 #define UART_LCR_H_EPS		(1 << 2)	/* Even parity select */
81 #define UART_LCR_H_STP2		(1 << 3)	/* Two stop bits select */
82 #define UART_LCR_H_FEN		(1 << 4)	/* Enable FIFOs */
83 #define UART_LCR_H_WLEN5	(0x0 << 5)	/* Word length: 5 bits */
84 #define UART_LCR_H_WLEN6	(0x1 << 5)	/* Word length: 6 bits */
85 #define UART_LCR_H_WLEN7	(0x2 << 5)	/* Word length: 7 bits */
86 #define UART_LCR_H_WLEN8	(0x3 << 5)	/* Word length: 8 bits */
87 #define UART_LCR_H_SPS		(1 << 7)	/* Stick parity select */
88 #define UART_CR			0x30		/* Control register */
89 #define UART_CR_UARTEN		(1 << 0)	/* UART enable */
90 #define UART_CR_SIREN		(1 << 1)	/* SIR enable */
91 #define UART_CR_SIRLP		(1 << 2)	/* IrDA SIR low power mode */
92 #define UART_CR_LBE		(1 << 7)	/* Loop back enable */
93 #define UART_CR_TXE		(1 << 8)	/* Transmit enable */
94 #define UART_CR_RXE		(1 << 9)	/* Receive enable */
95 #define UART_CR_DTR		(1 << 10)	/* Data transmit enable */
96 #define UART_CR_RTS		(1 << 11)	/* Request to send */
97 #define UART_CR_OUT1		(1 << 12)
98 #define UART_CR_OUT2		(1 << 13)
99 #define UART_CR_CTSE		(1 << 14)	/* CTS hardware flow control enable */
100 #define UART_CR_RTSE		(1 << 15)	/* RTS hardware flow control enable */
101 #define UART_IFLS		0x34		/* Interrupt FIFO level select register */
102 #define UART_IMSC		0x38		/* Interrupt mask set/clear register */
103 #define UART_IMSC_RIMIM		(1 << 0)
104 #define UART_IMSC_CTSMIM	(1 << 1)
105 #define UART_IMSC_DCDMIM	(1 << 2)
106 #define UART_IMSC_DSRMIM	(1 << 3)
107 #define UART_IMSC_RXIM		(1 << 4)
108 #define UART_IMSC_TXIM		(1 << 5)
109 #define UART_IMSC_RTIM		(1 << 6)
110 #define UART_IMSC_FEIM		(1 << 7)
111 #define UART_IMSC_PEIM		(1 << 8)
112 #define UART_IMSC_BEIM		(1 << 9)
113 #define UART_IMSC_OEIM		(1 << 10)
114 #define UART_RIS		0x3c		/* Raw interrupt status register */
115 #define UART_MIS		0x40		/* Masked interrupt status register */
116 #define UART_ICR		0x44		/* Interrupt clear register */
117 #define UART_DMACR		0x48		/* DMA control register */
118 #define UART_SPACE		0x100
119 
120 void pluartcnprobe(struct consdev *cp);
121 void pluartcninit(struct consdev *cp);
122 int pluartcngetc(dev_t dev);
123 void pluartcnputc(dev_t dev, int c);
124 void pluartcnpollc(dev_t dev, int on);
125 int  pluart_param(struct tty *tp, struct termios *t);
126 void pluart_start(struct tty *);
127 void pluart_pwroff(struct pluart_softc *sc);
128 void pluart_diag(void *arg);
129 void pluart_raisedtr(void *arg);
130 void pluart_softint(void *arg);
131 struct pluart_softc *pluart_sc(dev_t dev);
132 
133 /* XXX - we imitate 'com' serial ports and take over their entry points */
134 /* XXX: These belong elsewhere */
135 cdev_decl(com);
136 cdev_decl(pluart);
137 
138 struct cfdriver pluart_cd = {
139 	NULL, "pluart", DV_TTY
140 };
141 
142 bus_space_tag_t	pluartconsiot;
143 bus_space_handle_t pluartconsioh;
144 bus_addr_t	pluartconsaddr;
145 tcflag_t	pluartconscflag = TTYDEF_CFLAG;
146 int		pluartdefaultrate = B38400;
147 
148 struct cdevsw pluartdev =
149 	cdev_tty_init(3/*XXX NUART */ ,pluart);		/* 12: serial port */
150 
151 void
152 pluart_attach_common(struct pluart_softc *sc, int console)
153 {
154 	int maj;
155 
156 	if (console) {
157 		/* Locate the major number. */
158 		for (maj = 0; maj < nchrdev; maj++)
159 			if (cdevsw[maj].d_open == pluartopen)
160 				break;
161 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
162 
163 		printf(": console");
164 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
165 	}
166 
167 	timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
168 	timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
169 	sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
170 
171 	if(sc->sc_si == NULL)
172 		panic("%s: can't establish soft interrupt.",
173 		    sc->sc_dev.dv_xname);
174 
175 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM));
176 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
177 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
178 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
179 	    ~UART_LCR_H_FEN);
180 
181 	printf("\n");
182 }
183 
184 int
185 pluart_intr(void *arg)
186 {
187 	struct pluart_softc *sc = arg;
188 	bus_space_tag_t iot = sc->sc_iot;
189 	bus_space_handle_t ioh = sc->sc_ioh;
190 	struct tty *tp = sc->sc_tty;
191 	u_int16_t is;
192 	u_int16_t *p;
193 	u_int16_t c;
194 
195 	is = bus_space_read_4(iot, ioh, UART_RIS);
196 	bus_space_write_4(iot, ioh, UART_ICR, is);
197 
198 	if (sc->sc_tty == NULL)
199 		return 0;
200 
201 	if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM))
202 		return 0;
203 
204 	if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) {
205 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
206 		if (sc->sc_halt > 0)
207 			wakeup(&tp->t_outq);
208 		(*linesw[tp->t_line].l_start)(tp);
209 	}
210 
211 	p = sc->sc_ibufp;
212 
213 	while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
214 		c = bus_space_read_2(iot, ioh, UART_DR);
215 		if (c & UART_DR_BE) {
216 #ifdef DDB
217 			if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
218 				if (db_console)
219 					db_enter();
220 				continue;
221 			}
222 #endif
223 			c = 0;
224 		}
225 		if (p >= sc->sc_ibufend) {
226 			sc->sc_floods++;
227 			if (sc->sc_errors++ == 0)
228 				timeout_add_sec(&sc->sc_diag_tmo, 60);
229 		} else {
230 			*p++ = c;
231 			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
232 				/* XXX */
233 				//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
234 				//bus_space_write_4(iot, ioh, IMXUART_UCR3,
235 				//    sc->sc_ucr3);
236 			}
237 		}
238 		/* XXX - msr stuff ? */
239 	}
240 	sc->sc_ibufp = p;
241 
242 	softintr_schedule(sc->sc_si);
243 
244 	return 1;
245 }
246 
247 int
248 pluart_param(struct tty *tp, struct termios *t)
249 {
250 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
251 	//bus_space_tag_t iot = sc->sc_iot;
252 	//bus_space_handle_t ioh = sc->sc_ioh;
253 	int ospeed = t->c_ospeed;
254 	int error;
255 	tcflag_t oldcflag;
256 
257 
258 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
259 		return EINVAL;
260 
261 	switch (ISSET(t->c_cflag, CSIZE)) {
262 	case CS5:
263 		return EINVAL;
264 	case CS6:
265 		return EINVAL;
266 	case CS7:
267 		//CLR(sc->sc_ucr2, IMXUART_CR2_WS);
268 		break;
269 	case CS8:
270 		//SET(sc->sc_ucr2, IMXUART_CR2_WS);
271 		break;
272 	}
273 //	bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
274 
275 	/*
276 	if (ISSET(t->c_cflag, PARENB)) {
277 		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
278 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
279 	}
280 	*/
281 	/* STOPB - XXX */
282 	if (ospeed == 0) {
283 		/* lower dtr */
284 	}
285 
286 	if (ospeed != 0) {
287 		while (ISSET(tp->t_state, TS_BUSY)) {
288 			++sc->sc_halt;
289 			error = ttysleep(tp, &tp->t_outq,
290 			    TTOPRI | PCATCH, "pluartprm");
291 			--sc->sc_halt;
292 			if (error) {
293 				pluart_start(tp);
294 				return (error);
295 			}
296 		}
297 		/* set speed */
298 	}
299 
300 	/* setup fifo */
301 
302 	/* When not using CRTSCTS, RTS follows DTR. */
303 	/* sc->sc_dtr = MCR_DTR; */
304 
305 
306 	/* and copy to tty */
307 	tp->t_ispeed = t->c_ispeed;
308 	tp->t_ospeed = t->c_ospeed;
309 	oldcflag = tp->t_cflag;
310 	tp->t_cflag = t->c_cflag;
311 
312         /*
313 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
314 	 * stop the device.
315 	 */
316 	 /* XXX */
317 
318 	pluart_start(tp);
319 
320 	return 0;
321 }
322 
323 void
324 pluart_start(struct tty *tp)
325 {
326 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
327 	bus_space_tag_t iot = sc->sc_iot;
328 	bus_space_handle_t ioh = sc->sc_ioh;
329 	u_int16_t fr;
330 	int s;
331 
332 	s = spltty();
333 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
334 		goto out;
335 	ttwakeupwr(tp);
336 	if (tp->t_outq.c_cc == 0)
337 		goto out;
338 	SET(tp->t_state, TS_BUSY);
339 
340 	fr = bus_space_read_4(iot, ioh, UART_FR);
341 	while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) {
342 		bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
343 		fr = bus_space_read_4(iot, ioh, UART_FR);
344 	}
345 out:
346 	splx(s);
347 }
348 
349 void
350 pluart_pwroff(struct pluart_softc *sc)
351 {
352 }
353 
354 void
355 pluart_diag(void *arg)
356 {
357 	struct pluart_softc *sc = arg;
358 	int overflows, floods;
359 	int s;
360 
361 	s = spltty();
362 	sc->sc_errors = 0;
363 	overflows = sc->sc_overflows;
364 	sc->sc_overflows = 0;
365 	floods = sc->sc_floods;
366 	sc->sc_floods = 0;
367 	splx(s);
368 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
369 	    sc->sc_dev.dv_xname,
370 	    overflows, overflows == 1 ? "" : "s",
371 	    floods, floods == 1 ? "" : "s");
372 }
373 
374 void
375 pluart_raisedtr(void *arg)
376 {
377 	//struct pluart_softc *sc = arg;
378 
379 	//SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
380 	//bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
381 }
382 
383 void
384 pluart_softint(void *arg)
385 {
386 	struct pluart_softc *sc = arg;
387 	struct tty *tp;
388 	u_int16_t *ibufp;
389 	u_int16_t *ibufend;
390 	int c;
391 	int err;
392 	int s;
393 
394 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
395 		return;
396 
397 	tp = sc->sc_tty;
398 	s = spltty();
399 
400 	ibufp = sc->sc_ibuf;
401 	ibufend = sc->sc_ibufp;
402 
403 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
404 		splx(s);
405 		return;
406 	}
407 
408 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
409 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
410 	sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
411 	sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
412 
413 #if 0
414 	if (ISSET(tp->t_cflag, CRTSCTS) &&
415 	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
416 		/* XXX */
417 		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
418 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
419 		    sc->sc_ucr3);
420 	}
421 #endif
422 
423 	splx(s);
424 
425 	while (ibufp < ibufend) {
426 		c = *ibufp++;
427 		/*
428 		if (ISSET(c, IMXUART_RX_OVERRUN)) {
429 			sc->sc_overflows++;
430 			if (sc->sc_errors++ == 0)
431 				timeout_add_sec(&sc->sc_diag_tmo, 60);
432 		}
433 		*/
434 		/* This is ugly, but fast. */
435 
436 		err = 0;
437 		/*
438 		if (ISSET(c, IMXUART_RX_PRERR))
439 			err |= TTY_PE;
440 		if (ISSET(c, IMXUART_RX_FRMERR))
441 			err |= TTY_FE;
442 		*/
443 		c = (c & 0xff) | err;
444 		(*linesw[tp->t_line].l_rint)(c, tp);
445 	}
446 }
447 
448 int
449 pluartopen(dev_t dev, int flag, int mode, struct proc *p)
450 {
451 	int unit = DEVUNIT(dev);
452 	struct pluart_softc *sc;
453 	bus_space_tag_t iot;
454 	bus_space_handle_t ioh;
455 	struct tty *tp;
456 	int s;
457 	int error = 0;
458 
459 	if (unit >= pluart_cd.cd_ndevs)
460 		return ENXIO;
461 	sc = pluart_cd.cd_devs[unit];
462 	if (sc == NULL)
463 		return ENXIO;
464 
465 	s = spltty();
466 	if (sc->sc_tty == NULL)
467 		tp = sc->sc_tty = ttymalloc(0);
468 	else
469 		tp = sc->sc_tty;
470 
471 	splx(s);
472 
473 	tp->t_oproc = pluart_start;
474 	tp->t_param = pluart_param;
475 	tp->t_dev = dev;
476 
477 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
478 		SET(tp->t_state, TS_WOPEN);
479 		ttychars(tp);
480 		tp->t_iflag = TTYDEF_IFLAG;
481 		tp->t_oflag = TTYDEF_OFLAG;
482 
483 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
484 			tp->t_cflag = pluartconscflag;
485 		else
486 			tp->t_cflag = TTYDEF_CFLAG;
487 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
488 			SET(tp->t_cflag, CLOCAL);
489 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
490 			SET(tp->t_cflag, CRTSCTS);
491 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
492 			SET(tp->t_cflag, MDMBUF);
493 		tp->t_lflag = TTYDEF_LFLAG;
494 		tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
495 
496 		s = spltty();
497 
498 		sc->sc_initialize = 1;
499 		pluart_param(tp, &tp->t_termios);
500 		ttsetwater(tp);
501 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
502 		sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
503 		sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
504 
505 		iot = sc->sc_iot;
506 		ioh = sc->sc_ioh;
507 
508 #if 0
509 		sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
510 		sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
511 		sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
512 		sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
513 
514 		/* interrupt after one char on tx/rx */
515 		/* reference frequency divider: 1 */
516 		bus_space_write_4(iot, ioh, IMXUART_UFCR,
517 		    1 << IMXUART_FCR_TXTL_SH |
518 		    5 << IMXUART_FCR_RFDIV_SH |
519 		    1 << IMXUART_FCR_RXTL_SH);
520 
521 		bus_space_write_4(iot, ioh, IMXUART_UBIR,
522 		    (pluartdefaultrate / 100) - 1);
523 
524 		/* formula: clk / (rfdiv * 1600) */
525 		bus_space_write_4(iot, ioh, IMXUART_UBMR,
526 		    (clk_get_rate(sc->sc_clk) * 1000) / 1600);
527 
528 		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
529 		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
530 		bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
531 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
532 
533 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
534 		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
535 		bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
536 #endif
537 
538 		SET(tp->t_state, TS_CARR_ON); /* XXX */
539 
540 
541 	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
542 		return EBUSY;
543 	else
544 		s = spltty();
545 
546 	if (DEVCUA(dev)) {
547 		if (ISSET(tp->t_state, TS_ISOPEN)) {
548 			splx(s);
549 			return EBUSY;
550 		}
551 		sc->sc_cua = 1;
552 	} else {
553 		/* tty (not cua) device; wait for carrier if necessary */
554 		if (ISSET(flag, O_NONBLOCK)) {
555 			if (sc->sc_cua) {
556 				/* Opening TTY non-blocking... but the CUA is busy */
557 				splx(s);
558 				return EBUSY;
559 			}
560 		} else {
561 			while (sc->sc_cua ||
562 			    (!ISSET(tp->t_cflag, CLOCAL) &&
563 				!ISSET(tp->t_state, TS_CARR_ON))) {
564 				SET(tp->t_state, TS_WOPEN);
565 				error = ttysleep(tp, &tp->t_rawq,
566 				    TTIPRI | PCATCH, ttopen);
567 				/*
568 				 * If TS_WOPEN has been reset, that means the
569 				 * cua device has been closed.  We don't want
570 				 * to fail in that case,
571 				 * so just go around again.
572 				 */
573 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
574 					CLR(tp->t_state, TS_WOPEN);
575 					if (!sc->sc_cua && !ISSET(tp->t_state,
576 					    TS_ISOPEN))
577 						pluart_pwroff(sc);
578 					splx(s);
579 					return error;
580 				}
581 			}
582 		}
583 	}
584 	splx(s);
585 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
586 }
587 
588 int
589 pluartclose(dev_t dev, int flag, int mode, struct proc *p)
590 {
591 	int unit = DEVUNIT(dev);
592 	struct pluart_softc *sc = pluart_cd.cd_devs[unit];
593 	//bus_space_tag_t iot = sc->sc_iot;
594 	//bus_space_handle_t ioh = sc->sc_ioh;
595 	struct tty *tp = sc->sc_tty;
596 	int s;
597 
598 	/* XXX This is for cons.c. */
599 	if (!ISSET(tp->t_state, TS_ISOPEN))
600 		return 0;
601 
602 	(*linesw[tp->t_line].l_close)(tp, flag, p);
603 	s = spltty();
604 	if (ISSET(tp->t_state, TS_WOPEN)) {
605 		/* tty device is waiting for carrier; drop dtr then re-raise */
606 		//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
607 		//bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
608 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
609 	} else {
610 		/* no one else waiting; turn off the uart */
611 		pluart_pwroff(sc);
612 	}
613 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
614 
615 	sc->sc_cua = 0;
616 	splx(s);
617 	ttyclose(tp);
618 
619 	return 0;
620 }
621 
622 int
623 pluartread(dev_t dev, struct uio *uio, int flag)
624 {
625 	struct tty *tty;
626 
627 	tty = pluarttty(dev);
628 	if (tty == NULL)
629 		return ENODEV;
630 
631 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
632 }
633 
634 int
635 pluartwrite(dev_t dev, struct uio *uio, int flag)
636 {
637 	struct tty *tty;
638 
639 	tty = pluarttty(dev);
640 	if (tty == NULL)
641 		return ENODEV;
642 
643 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
644 }
645 
646 int
647 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
648 {
649 	struct pluart_softc *sc;
650 	struct tty *tp;
651 	int error;
652 
653 	sc = pluart_sc(dev);
654 	if (sc == NULL)
655 		return (ENODEV);
656 
657 	tp = sc->sc_tty;
658 	if (tp == NULL)
659 		return (ENXIO);
660 
661 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
662 	if (error >= 0)
663 		return (error);
664 
665 	error = ttioctl(tp, cmd, data, flag, p);
666 	if (error >= 0)
667 		return (error);
668 
669 	switch(cmd) {
670 	case TIOCSBRK:
671 		break;
672 	case TIOCCBRK:
673 		break;
674 	case TIOCSDTR:
675 		break;
676 	case TIOCCDTR:
677 		break;
678 	case TIOCMSET:
679 		break;
680 	case TIOCMBIS:
681 		break;
682 	case TIOCMBIC:
683 		break;
684 	case TIOCMGET:
685 		break;
686 	case TIOCGFLAGS:
687 		break;
688 	case TIOCSFLAGS:
689 		error = suser(p);
690 		if (error != 0)
691 			return(EPERM);
692 		break;
693 	default:
694 		return (ENOTTY);
695 	}
696 
697 	return 0;
698 }
699 
700 int
701 pluartstop(struct tty *tp, int flag)
702 {
703 	return 0;
704 }
705 
706 struct tty *
707 pluarttty(dev_t dev)
708 {
709 	int unit;
710 	struct pluart_softc *sc;
711 	unit = DEVUNIT(dev);
712 	if (unit >= pluart_cd.cd_ndevs)
713 		return NULL;
714 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
715 	if (sc == NULL)
716 		return NULL;
717 	return sc->sc_tty;
718 }
719 
720 struct pluart_softc *
721 pluart_sc(dev_t dev)
722 {
723 	int unit;
724 	struct pluart_softc *sc;
725 	unit = DEVUNIT(dev);
726 	if (unit >= pluart_cd.cd_ndevs)
727 		return NULL;
728 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
729 	return sc;
730 }
731 
732 
733 /* serial console */
734 void
735 pluartcnprobe(struct consdev *cp)
736 {
737 }
738 
739 void
740 pluartcninit(struct consdev *cp)
741 {
742 }
743 
744 int
745 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
746 {
747 	static struct consdev pluartcons = {
748 		NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
749 		NODEV, CN_MIDPRI
750 	};
751 	int maj;
752 
753 	if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
754 		return ENOMEM;
755 
756 	/* Disable FIFO. */
757 	bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
758 	    bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
759 
760 	/* Look for major of com(4) to replace. */
761 	for (maj = 0; maj < nchrdev; maj++)
762 		if (cdevsw[maj].d_open == comopen)
763 			break;
764 	if (maj == nchrdev)
765 		return ENXIO;
766 
767 	cn_tab = &pluartcons;
768 	cn_tab->cn_dev = makedev(maj, 0);
769 	cdevsw[maj] = pluartdev;	/* KLUDGE */
770 
771 	pluartconsiot = iot;
772 	pluartconsaddr = iobase;
773 	pluartconscflag = cflag;
774 
775 	return 0;
776 }
777 
778 int
779 pluartcngetc(dev_t dev)
780 {
781 	int c;
782 	int s;
783 	s = splhigh();
784 	while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
785 	    UART_FR_RXFF) == 0)
786 		;
787 	c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
788 	splx(s);
789 	return c;
790 }
791 
792 void
793 pluartcnputc(dev_t dev, int c)
794 {
795 	int s;
796 	s = splhigh();
797 	while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
798 	    UART_FR_TXFE) == 0)
799 		;
800 	bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
801 	splx(s);
802 }
803 
804 void
805 pluartcnpollc(dev_t dev, int on)
806 {
807 }
808