xref: /openbsd-src/sys/dev/ic/pluart.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*	$OpenBSD: pluart.c,v 1.2 2018/08/12 18:32:18 kettenis 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 fr;
192 	u_int16_t *p;
193 	u_int16_t c;
194 
195 	bus_space_write_4(iot, ioh, UART_ICR, -1);
196 
197 	if (sc->sc_tty == NULL)
198 		return(0);
199 
200 	fr = bus_space_read_4(iot, ioh, UART_FR);
201 	if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) {
202 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
203 		if (sc->sc_halt > 0)
204 			wakeup(&tp->t_outq);
205 		(*linesw[tp->t_line].l_start)(tp);
206 	}
207 
208 	if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF))
209 		return 0;
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(&sc->sc_diag_tmo, 60 * hz);
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", 0);
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 
330 	int s;
331 	s = spltty();
332 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
333 		goto out;
334 	if (tp->t_outq.c_cc <= tp->t_lowat) {
335 		if (ISSET(tp->t_state, TS_ASLEEP)) {
336 			CLR(tp->t_state, TS_ASLEEP);
337 			wakeup(&tp->t_outq);
338 		}
339 		if (tp->t_outq.c_cc == 0)
340 			goto out;
341 		selwakeup(&tp->t_wsel);
342 	}
343 	SET(tp->t_state, TS_BUSY);
344 
345 	if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
346 		u_char buffer[64];	/* largest fifo */
347 		int i, n;
348 
349 		n = q_to_b(&tp->t_outq, buffer,
350 		    min(sc->sc_fifolen, sizeof buffer));
351 		for (i = 0; i < n; i++) {
352 			bus_space_write_4(iot, ioh, UART_DR, buffer[i]);
353 		}
354 		bzero(buffer, n);
355 	} else if (tp->t_outq.c_cc != 0)
356 		bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
357 
358 out:
359 	splx(s);
360 }
361 
362 void
363 pluart_pwroff(struct pluart_softc *sc)
364 {
365 }
366 
367 void
368 pluart_diag(void *arg)
369 {
370 	struct pluart_softc *sc = arg;
371 	int overflows, floods;
372 	int s;
373 
374 	s = spltty();
375 	sc->sc_errors = 0;
376 	overflows = sc->sc_overflows;
377 	sc->sc_overflows = 0;
378 	floods = sc->sc_floods;
379 	sc->sc_floods = 0;
380 	splx(s);
381 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
382 	    sc->sc_dev.dv_xname,
383 	    overflows, overflows == 1 ? "" : "s",
384 	    floods, floods == 1 ? "" : "s");
385 }
386 
387 void
388 pluart_raisedtr(void *arg)
389 {
390 	//struct pluart_softc *sc = arg;
391 
392 	//SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
393 	//bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
394 }
395 
396 void
397 pluart_softint(void *arg)
398 {
399 	struct pluart_softc *sc = arg;
400 	struct tty *tp;
401 	u_int16_t *ibufp;
402 	u_int16_t *ibufend;
403 	int c;
404 	int err;
405 	int s;
406 
407 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
408 		return;
409 
410 	tp = sc->sc_tty;
411 	s = spltty();
412 
413 	ibufp = sc->sc_ibuf;
414 	ibufend = sc->sc_ibufp;
415 
416 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
417 		splx(s);
418 		return;
419 	}
420 
421 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
422 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
423 	sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
424 	sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
425 
426 #if 0
427 	if (ISSET(tp->t_cflag, CRTSCTS) &&
428 	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
429 		/* XXX */
430 		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
431 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
432 		    sc->sc_ucr3);
433 	}
434 #endif
435 
436 	splx(s);
437 
438 	while (ibufp < ibufend) {
439 		c = *ibufp++;
440 		/*
441 		if (ISSET(c, IMXUART_RX_OVERRUN)) {
442 			sc->sc_overflows++;
443 			if (sc->sc_errors++ == 0)
444 				timeout_add(&sc->sc_diag_tmo, 60 * hz);
445 		}
446 		*/
447 		/* This is ugly, but fast. */
448 
449 		err = 0;
450 		/*
451 		if (ISSET(c, IMXUART_RX_PRERR))
452 			err |= TTY_PE;
453 		if (ISSET(c, IMXUART_RX_FRMERR))
454 			err |= TTY_FE;
455 		*/
456 		c = (c & 0xff) | err;
457 		(*linesw[tp->t_line].l_rint)(c, tp);
458 	}
459 }
460 
461 int
462 pluartopen(dev_t dev, int flag, int mode, struct proc *p)
463 {
464 	int unit = DEVUNIT(dev);
465 	struct pluart_softc *sc;
466 	bus_space_tag_t iot;
467 	bus_space_handle_t ioh;
468 	struct tty *tp;
469 	int s;
470 	int error = 0;
471 
472 	if (unit >= pluart_cd.cd_ndevs)
473 		return ENXIO;
474 	sc = pluart_cd.cd_devs[unit];
475 	if (sc == NULL)
476 		return ENXIO;
477 
478 	s = spltty();
479 	if (sc->sc_tty == NULL)
480 		tp = sc->sc_tty = ttymalloc(0);
481 	else
482 		tp = sc->sc_tty;
483 
484 	splx(s);
485 
486 	tp->t_oproc = pluart_start;
487 	tp->t_param = pluart_param;
488 	tp->t_dev = dev;
489 
490 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
491 		SET(tp->t_state, TS_WOPEN);
492 		ttychars(tp);
493 		tp->t_iflag = TTYDEF_IFLAG;
494 		tp->t_oflag = TTYDEF_OFLAG;
495 
496 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
497 			tp->t_cflag = pluartconscflag;
498 		else
499 			tp->t_cflag = TTYDEF_CFLAG;
500 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
501 			SET(tp->t_cflag, CLOCAL);
502 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
503 			SET(tp->t_cflag, CRTSCTS);
504 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
505 			SET(tp->t_cflag, MDMBUF);
506 		tp->t_lflag = TTYDEF_LFLAG;
507 		tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
508 
509 		s = spltty();
510 
511 		sc->sc_initialize = 1;
512 		pluart_param(tp, &tp->t_termios);
513 		ttsetwater(tp);
514 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
515 		sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
516 		sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
517 
518 		iot = sc->sc_iot;
519 		ioh = sc->sc_ioh;
520 
521 #if 0
522 		sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
523 		sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
524 		sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
525 		sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
526 
527 		/* interrupt after one char on tx/rx */
528 		/* reference frequency divider: 1 */
529 		bus_space_write_4(iot, ioh, IMXUART_UFCR,
530 		    1 << IMXUART_FCR_TXTL_SH |
531 		    5 << IMXUART_FCR_RFDIV_SH |
532 		    1 << IMXUART_FCR_RXTL_SH);
533 
534 		bus_space_write_4(iot, ioh, IMXUART_UBIR,
535 		    (pluartdefaultrate / 100) - 1);
536 
537 		/* formula: clk / (rfdiv * 1600) */
538 		bus_space_write_4(iot, ioh, IMXUART_UBMR,
539 		    (clk_get_rate(sc->sc_clk) * 1000) / 1600);
540 
541 		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
542 		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
543 		bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
544 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
545 
546 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
547 		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
548 		bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
549 #endif
550 
551 		SET(tp->t_state, TS_CARR_ON); /* XXX */
552 
553 
554 	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
555 		return EBUSY;
556 	else
557 		s = spltty();
558 
559 	if (DEVCUA(dev)) {
560 		if (ISSET(tp->t_state, TS_ISOPEN)) {
561 			splx(s);
562 			return EBUSY;
563 		}
564 		sc->sc_cua = 1;
565 	} else {
566 		/* tty (not cua) device; wait for carrier if necessary */
567 		if (ISSET(flag, O_NONBLOCK)) {
568 			if (sc->sc_cua) {
569 				/* Opening TTY non-blocking... but the CUA is busy */
570 				splx(s);
571 				return EBUSY;
572 			}
573 		} else {
574 			while (sc->sc_cua ||
575 			    (!ISSET(tp->t_cflag, CLOCAL) &&
576 				!ISSET(tp->t_state, TS_CARR_ON))) {
577 				SET(tp->t_state, TS_WOPEN);
578 				error = ttysleep(tp, &tp->t_rawq,
579 				    TTIPRI | PCATCH, ttopen, 0);
580 				/*
581 				 * If TS_WOPEN has been reset, that means the
582 				 * cua device has been closed.  We don't want
583 				 * to fail in that case,
584 				 * so just go around again.
585 				 */
586 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
587 					CLR(tp->t_state, TS_WOPEN);
588 					if (!sc->sc_cua && !ISSET(tp->t_state,
589 					    TS_ISOPEN))
590 						pluart_pwroff(sc);
591 					splx(s);
592 					return error;
593 				}
594 			}
595 		}
596 	}
597 	splx(s);
598 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
599 }
600 
601 int
602 pluartclose(dev_t dev, int flag, int mode, struct proc *p)
603 {
604 	int unit = DEVUNIT(dev);
605 	struct pluart_softc *sc = pluart_cd.cd_devs[unit];
606 	//bus_space_tag_t iot = sc->sc_iot;
607 	//bus_space_handle_t ioh = sc->sc_ioh;
608 	struct tty *tp = sc->sc_tty;
609 	int s;
610 
611 	/* XXX This is for cons.c. */
612 	if (!ISSET(tp->t_state, TS_ISOPEN))
613 		return 0;
614 
615 	(*linesw[tp->t_line].l_close)(tp, flag, p);
616 	s = spltty();
617 	if (ISSET(tp->t_state, TS_WOPEN)) {
618 		/* tty device is waiting for carrier; drop dtr then re-raise */
619 		//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
620 		//bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
621 		timeout_add(&sc->sc_dtr_tmo, hz * 2);
622 	} else {
623 		/* no one else waiting; turn off the uart */
624 		pluart_pwroff(sc);
625 	}
626 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
627 
628 	sc->sc_cua = 0;
629 	splx(s);
630 	ttyclose(tp);
631 
632 	return 0;
633 }
634 
635 int
636 pluartread(dev_t dev, struct uio *uio, int flag)
637 {
638 	struct tty *tty;
639 
640 	tty = pluarttty(dev);
641 	if (tty == NULL)
642 		return ENODEV;
643 
644 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
645 }
646 
647 int
648 pluartwrite(dev_t dev, struct uio *uio, int flag)
649 {
650 	struct tty *tty;
651 
652 	tty = pluarttty(dev);
653 	if (tty == NULL)
654 		return ENODEV;
655 
656 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
657 }
658 
659 int
660 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
661 {
662 	struct pluart_softc *sc;
663 	struct tty *tp;
664 	int error;
665 
666 	sc = pluart_sc(dev);
667 	if (sc == NULL)
668 		return (ENODEV);
669 
670 	tp = sc->sc_tty;
671 	if (tp == NULL)
672 		return (ENXIO);
673 
674 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
675 	if (error >= 0)
676 		return (error);
677 
678 	error = ttioctl(tp, cmd, data, flag, p);
679 	if (error >= 0)
680 		return (error);
681 
682 	switch(cmd) {
683 	case TIOCSBRK:
684 		break;
685 	case TIOCCBRK:
686 		break;
687 	case TIOCSDTR:
688 		break;
689 	case TIOCCDTR:
690 		break;
691 	case TIOCMSET:
692 		break;
693 	case TIOCMBIS:
694 		break;
695 	case TIOCMBIC:
696 		break;
697 	case TIOCMGET:
698 		break;
699 	case TIOCGFLAGS:
700 		break;
701 	case TIOCSFLAGS:
702 		error = suser(p);
703 		if (error != 0)
704 			return(EPERM);
705 		break;
706 	default:
707 		return (ENOTTY);
708 	}
709 
710 	return 0;
711 }
712 
713 int
714 pluartstop(struct tty *tp, int flag)
715 {
716 	return 0;
717 }
718 
719 struct tty *
720 pluarttty(dev_t dev)
721 {
722 	int unit;
723 	struct pluart_softc *sc;
724 	unit = DEVUNIT(dev);
725 	if (unit >= pluart_cd.cd_ndevs)
726 		return NULL;
727 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
728 	if (sc == NULL)
729 		return NULL;
730 	return sc->sc_tty;
731 }
732 
733 struct pluart_softc *
734 pluart_sc(dev_t dev)
735 {
736 	int unit;
737 	struct pluart_softc *sc;
738 	unit = DEVUNIT(dev);
739 	if (unit >= pluart_cd.cd_ndevs)
740 		return NULL;
741 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
742 	return sc;
743 }
744 
745 
746 /* serial console */
747 void
748 pluartcnprobe(struct consdev *cp)
749 {
750 }
751 
752 void
753 pluartcninit(struct consdev *cp)
754 {
755 }
756 
757 int
758 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
759 {
760 	static struct consdev pluartcons = {
761 		NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
762 		NODEV, CN_MIDPRI
763 	};
764 	int maj;
765 
766 	if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
767 		return ENOMEM;
768 
769 	/* Disable FIFO. */
770 	bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
771 	    bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
772 
773 	/* Look for major of com(4) to replace. */
774 	for (maj = 0; maj < nchrdev; maj++)
775 		if (cdevsw[maj].d_open == comopen)
776 			break;
777 	if (maj == nchrdev)
778 		return ENXIO;
779 
780 	cn_tab = &pluartcons;
781 	cn_tab->cn_dev = makedev(maj, 0);
782 	cdevsw[maj] = pluartdev;	/* KLUDGE */
783 
784 	pluartconsiot = iot;
785 	pluartconsaddr = iobase;
786 	pluartconscflag = cflag;
787 
788 	return 0;
789 }
790 
791 int
792 pluartcngetc(dev_t dev)
793 {
794 	int c;
795 	int s;
796 	s = splhigh();
797 	while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
798 	    UART_FR_RXFF) == 0)
799 		;
800 	c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
801 	splx(s);
802 	return c;
803 }
804 
805 void
806 pluartcnputc(dev_t dev, int c)
807 {
808 	int s;
809 	s = splhigh();
810 	while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
811 	    UART_FR_TXFE) == 0)
812 		;
813 	bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
814 	splx(s);
815 }
816 
817 void
818 pluartcnpollc(dev_t dev, int on)
819 {
820 }
821