xref: /openbsd-src/sys/dev/ic/pluart.c (revision 1525749fb89da5e6992ed4d61159727e5f0e49b5)
1*1525749fSvisa /*	$OpenBSD: pluart.c,v 1.14 2022/07/02 08:50:42 visa Exp $	*/
2e474e71dSkettenis /*
3e474e71dSkettenis  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
4e474e71dSkettenis  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
5e474e71dSkettenis  *
6e474e71dSkettenis  * Permission to use, copy, modify, and distribute this software for any
7e474e71dSkettenis  * purpose with or without fee is hereby granted, provided that the above
8e474e71dSkettenis  * copyright notice and this permission notice appear in all copies.
9e474e71dSkettenis  *
10e474e71dSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e474e71dSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e474e71dSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e474e71dSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e474e71dSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e474e71dSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e474e71dSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e474e71dSkettenis  */
18e474e71dSkettenis 
19e474e71dSkettenis #include <sys/param.h>
20e474e71dSkettenis #include <sys/ioctl.h>
21e474e71dSkettenis #include <sys/proc.h>
22e474e71dSkettenis #include <sys/tty.h>
23e474e71dSkettenis #include <sys/uio.h>
24e474e71dSkettenis #include <sys/systm.h>
25e474e71dSkettenis #include <sys/time.h>
26e474e71dSkettenis #include <sys/device.h>
27e474e71dSkettenis #include <sys/syslog.h>
28e474e71dSkettenis #include <sys/conf.h>
29e474e71dSkettenis #include <sys/fcntl.h>
30e474e71dSkettenis #include <sys/kernel.h>
31e474e71dSkettenis 
32e474e71dSkettenis #include <machine/bus.h>
33e474e71dSkettenis 
34e474e71dSkettenis #include <dev/ic/pluartvar.h>
35e474e71dSkettenis #include <dev/cons.h>
36e474e71dSkettenis 
37e474e71dSkettenis #ifdef DDB
38e474e71dSkettenis #include <ddb/db_var.h>
39e474e71dSkettenis #endif
40e474e71dSkettenis 
41e474e71dSkettenis #define DEVUNIT(x)      (minor(x) & 0x7f)
42e474e71dSkettenis #define DEVCUA(x)       (minor(x) & 0x80)
43e474e71dSkettenis 
44e474e71dSkettenis #define UART_DR			0x00		/* Data register */
45e474e71dSkettenis #define UART_DR_DATA(x)		((x) & 0xf)
46e474e71dSkettenis #define UART_DR_FE		(1 << 8)	/* Framing error */
47e474e71dSkettenis #define UART_DR_PE		(1 << 9)	/* Parity error */
48e474e71dSkettenis #define UART_DR_BE		(1 << 10)	/* Break error */
49e474e71dSkettenis #define UART_DR_OE		(1 << 11)	/* Overrun error */
50e474e71dSkettenis #define UART_RSR		0x04		/* Receive status register */
51e474e71dSkettenis #define UART_RSR_FE		(1 << 0)	/* Framing error */
52e474e71dSkettenis #define UART_RSR_PE		(1 << 1)	/* Parity error */
53e474e71dSkettenis #define UART_RSR_BE		(1 << 2)	/* Break error */
54e474e71dSkettenis #define UART_RSR_OE		(1 << 3)	/* Overrun error */
55e474e71dSkettenis #define UART_ECR		0x04		/* Error clear register */
56e474e71dSkettenis #define UART_ECR_FE		(1 << 0)	/* Framing error */
57e474e71dSkettenis #define UART_ECR_PE		(1 << 1)	/* Parity error */
58e474e71dSkettenis #define UART_ECR_BE		(1 << 2)	/* Break error */
59e474e71dSkettenis #define UART_ECR_OE		(1 << 3)	/* Overrun error */
60e474e71dSkettenis #define UART_FR			0x18		/* Flag register */
61e474e71dSkettenis #define UART_FR_CTS		(1 << 0)	/* Clear to send */
62e474e71dSkettenis #define UART_FR_DSR		(1 << 1)	/* Data set ready */
63e474e71dSkettenis #define UART_FR_DCD		(1 << 2)	/* Data carrier detect */
64e474e71dSkettenis #define UART_FR_BUSY		(1 << 3)	/* UART busy */
65e474e71dSkettenis #define UART_FR_RXFE		(1 << 4)	/* Receive FIFO empty */
66e474e71dSkettenis #define UART_FR_TXFF		(1 << 5)	/* Transmit FIFO full */
67e474e71dSkettenis #define UART_FR_RXFF		(1 << 6)	/* Receive FIFO full */
68e474e71dSkettenis #define UART_FR_TXFE		(1 << 7)	/* Transmit FIFO empty */
69e474e71dSkettenis #define UART_FR_RI		(1 << 8)	/* Ring indicator */
70e474e71dSkettenis #define UART_ILPR		0x20		/* IrDA low-power counter register */
71e474e71dSkettenis #define UART_ILPR_ILPDVSR	((x) & 0xf)	/* IrDA low-power divisor */
72e474e71dSkettenis #define UART_IBRD		0x24		/* Integer baud rate register */
73c1f87e31Santon #define UART_IBRD_DIVINT(x)	((x) & 0xffff)	/* Integer baud rate divisor */
74e474e71dSkettenis #define UART_FBRD		0x28		/* Fractional baud rate register */
75c1f87e31Santon #define UART_FBRD_DIVFRAC(x)	((x) & 0x3f)	/* Fractional baud rate divisor */
76e474e71dSkettenis #define UART_LCR_H		0x2c		/* Line control register */
77e474e71dSkettenis #define UART_LCR_H_BRK		(1 << 0)	/* Send break */
78e474e71dSkettenis #define UART_LCR_H_PEN		(1 << 1)	/* Parity enable */
79e474e71dSkettenis #define UART_LCR_H_EPS		(1 << 2)	/* Even parity select */
80e474e71dSkettenis #define UART_LCR_H_STP2		(1 << 3)	/* Two stop bits select */
81e474e71dSkettenis #define UART_LCR_H_FEN		(1 << 4)	/* Enable FIFOs */
82e474e71dSkettenis #define UART_LCR_H_WLEN5	(0x0 << 5)	/* Word length: 5 bits */
83e474e71dSkettenis #define UART_LCR_H_WLEN6	(0x1 << 5)	/* Word length: 6 bits */
84e474e71dSkettenis #define UART_LCR_H_WLEN7	(0x2 << 5)	/* Word length: 7 bits */
85e474e71dSkettenis #define UART_LCR_H_WLEN8	(0x3 << 5)	/* Word length: 8 bits */
86e474e71dSkettenis #define UART_LCR_H_SPS		(1 << 7)	/* Stick parity select */
87e474e71dSkettenis #define UART_CR			0x30		/* Control register */
88e474e71dSkettenis #define UART_CR_UARTEN		(1 << 0)	/* UART enable */
89e474e71dSkettenis #define UART_CR_SIREN		(1 << 1)	/* SIR enable */
90e474e71dSkettenis #define UART_CR_SIRLP		(1 << 2)	/* IrDA SIR low power mode */
91e474e71dSkettenis #define UART_CR_LBE		(1 << 7)	/* Loop back enable */
92e474e71dSkettenis #define UART_CR_TXE		(1 << 8)	/* Transmit enable */
93e474e71dSkettenis #define UART_CR_RXE		(1 << 9)	/* Receive enable */
94e474e71dSkettenis #define UART_CR_DTR		(1 << 10)	/* Data transmit enable */
95e474e71dSkettenis #define UART_CR_RTS		(1 << 11)	/* Request to send */
96e474e71dSkettenis #define UART_CR_OUT1		(1 << 12)
97e474e71dSkettenis #define UART_CR_OUT2		(1 << 13)
98e474e71dSkettenis #define UART_CR_CTSE		(1 << 14)	/* CTS hardware flow control enable */
99e474e71dSkettenis #define UART_CR_RTSE		(1 << 15)	/* RTS hardware flow control enable */
100e474e71dSkettenis #define UART_IFLS		0x34		/* Interrupt FIFO level select register */
1016a0d4444Santon #define UART_IFLS_RX_SHIFT	3		/* RX level in bits [5:3] */
1026a0d4444Santon #define UART_IFLS_TX_SHIFT	0		/* TX level in bits [2:0] */
1036a0d4444Santon #define UART_IFLS_1_8		0		/* FIFO 1/8 full */
1046a0d4444Santon #define UART_IFLS_1_4		1		/* FIFO 1/4 full */
1056a0d4444Santon #define UART_IFLS_1_2		2		/* FIFO 1/2 full */
1066a0d4444Santon #define UART_IFLS_3_4		3		/* FIFO 3/4 full */
1076a0d4444Santon #define UART_IFLS_7_8		4		/* FIFO 7/8 full */
108e474e71dSkettenis #define UART_IMSC		0x38		/* Interrupt mask set/clear register */
109e474e71dSkettenis #define UART_IMSC_RIMIM		(1 << 0)
110e474e71dSkettenis #define UART_IMSC_CTSMIM	(1 << 1)
111e474e71dSkettenis #define UART_IMSC_DCDMIM	(1 << 2)
112e474e71dSkettenis #define UART_IMSC_DSRMIM	(1 << 3)
113e474e71dSkettenis #define UART_IMSC_RXIM		(1 << 4)
114e474e71dSkettenis #define UART_IMSC_TXIM		(1 << 5)
115e474e71dSkettenis #define UART_IMSC_RTIM		(1 << 6)
116e474e71dSkettenis #define UART_IMSC_FEIM		(1 << 7)
117e474e71dSkettenis #define UART_IMSC_PEIM		(1 << 8)
118e474e71dSkettenis #define UART_IMSC_BEIM		(1 << 9)
119e474e71dSkettenis #define UART_IMSC_OEIM		(1 << 10)
120e474e71dSkettenis #define UART_RIS		0x3c		/* Raw interrupt status register */
121e474e71dSkettenis #define UART_MIS		0x40		/* Masked interrupt status register */
122e474e71dSkettenis #define UART_ICR		0x44		/* Interrupt clear register */
123e474e71dSkettenis #define UART_DMACR		0x48		/* DMA control register */
1246a0d4444Santon #define UART_PID0		0xfe0		/* Peripheral identification register 0 */
1256a0d4444Santon #define UART_PID1		0xfe4		/* Peripheral identification register 1 */
1266a0d4444Santon #define UART_PID2		0xfe8		/* Peripheral identification register 2 */
1276a0d4444Santon #define UART_PID2_REV(x)	(((x) & 0xf0) >> 4)
1286a0d4444Santon #define UART_PID3		0xfec		/* Peripheral identification register 3 */
129e474e71dSkettenis #define UART_SPACE		0x100
130e474e71dSkettenis 
1316a0d4444Santon #define UART_FIFO_SIZE		16
1326a0d4444Santon #define UART_FIFO_SIZE_R3	32
1336a0d4444Santon 
134e474e71dSkettenis void pluartcnprobe(struct consdev *cp);
135e474e71dSkettenis void pluartcninit(struct consdev *cp);
136e474e71dSkettenis int pluartcngetc(dev_t dev);
137e474e71dSkettenis void pluartcnputc(dev_t dev, int c);
138e474e71dSkettenis void pluartcnpollc(dev_t dev, int on);
139e474e71dSkettenis int  pluart_param(struct tty *tp, struct termios *t);
140e474e71dSkettenis void pluart_start(struct tty *);
141e474e71dSkettenis void pluart_diag(void *arg);
142e474e71dSkettenis void pluart_raisedtr(void *arg);
143e474e71dSkettenis void pluart_softint(void *arg);
144e474e71dSkettenis struct pluart_softc *pluart_sc(dev_t dev);
145e474e71dSkettenis 
146e474e71dSkettenis /* XXX - we imitate 'com' serial ports and take over their entry points */
147e474e71dSkettenis /* XXX: These belong elsewhere */
148e474e71dSkettenis cdev_decl(com);
149e474e71dSkettenis cdev_decl(pluart);
150e474e71dSkettenis 
151e474e71dSkettenis struct cfdriver pluart_cd = {
152e474e71dSkettenis 	NULL, "pluart", DV_TTY
153e474e71dSkettenis };
154e474e71dSkettenis 
155fbe20e63Santon int		pluartdefaultrate = B38400;
156fbe20e63Santon int		pluartconsrate = B38400;
157e474e71dSkettenis bus_space_tag_t	pluartconsiot;
158e474e71dSkettenis bus_space_handle_t pluartconsioh;
159e474e71dSkettenis bus_addr_t	pluartconsaddr;
160e474e71dSkettenis tcflag_t	pluartconscflag = TTYDEF_CFLAG;
161e474e71dSkettenis 
162e474e71dSkettenis struct cdevsw pluartdev =
163e474e71dSkettenis 	cdev_tty_init(3/*XXX NUART */ ,pluart);		/* 12: serial port */
164e474e71dSkettenis 
165e474e71dSkettenis void
pluart_attach_common(struct pluart_softc * sc,int console)166e474e71dSkettenis pluart_attach_common(struct pluart_softc *sc, int console)
167e474e71dSkettenis {
1686a0d4444Santon 	int fifolen, fr, lcr, maj;
1696a0d4444Santon 
1706a0d4444Santon 	if ((sc->sc_hwflags & COM_HW_SBSA) == 0) {
1716a0d4444Santon 		if (sc->sc_hwrev == 0)
1726a0d4444Santon 			sc->sc_hwrev = UART_PID2_REV(bus_space_read_4(sc->sc_iot,
1736a0d4444Santon 			    sc->sc_ioh, UART_PID2));
1746a0d4444Santon 		if (sc->sc_hwrev < 3)
1756a0d4444Santon 			fifolen = UART_FIFO_SIZE;
1766a0d4444Santon 		else
1776a0d4444Santon 			fifolen = UART_FIFO_SIZE_R3;
1786a0d4444Santon 		printf(": rev %d, %d byte fifo\n", sc->sc_hwrev, fifolen);
1796a0d4444Santon 	} else {
1806a0d4444Santon 		/*
1816a0d4444Santon 		 * The SBSA UART is PL011 r1p5 compliant which implies revision
1826a0d4444Santon 		 * 3 with a 32 byte FIFO. However, we cannot expect to configure
1836a0d4444Santon 		 * RX/TX interrupt levels using the UARTIFLS register making it
1846a0d4444Santon 		 * impossible to make assumptions about the number of available
1856a0d4444Santon 		 * bytes in the FIFO. Therefore disable FIFO support for such
1866a0d4444Santon 		 * devices.
1876a0d4444Santon 		 */
1886a0d4444Santon 		fifolen = 0;
1896a0d4444Santon 		printf("\n");
1906a0d4444Santon 	}
191e474e71dSkettenis 
192e474e71dSkettenis 	if (console) {
193e474e71dSkettenis 		/* Locate the major number. */
194e474e71dSkettenis 		for (maj = 0; maj < nchrdev; maj++)
195e474e71dSkettenis 			if (cdevsw[maj].d_open == pluartopen)
196e474e71dSkettenis 				break;
197e474e71dSkettenis 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
198e474e71dSkettenis 
1996a0d4444Santon 		printf("%s: console\n", sc->sc_dev.dv_xname);
200e474e71dSkettenis 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
201e474e71dSkettenis 	}
202e474e71dSkettenis 
203e474e71dSkettenis 	timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
204e474e71dSkettenis 	timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
205e474e71dSkettenis 	sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
206e474e71dSkettenis 
207e474e71dSkettenis 	if(sc->sc_si == NULL)
208e474e71dSkettenis 		panic("%s: can't establish soft interrupt.",
209e474e71dSkettenis 		    sc->sc_dev.dv_xname);
210e474e71dSkettenis 
2116a0d4444Santon 	/* Flush transmit before enabling FIFO. */
2126a0d4444Santon 	for (;;) {
2136a0d4444Santon 		fr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_FR);
2146a0d4444Santon 		if (fr & UART_FR_TXFE)
2156a0d4444Santon 			break;
2166a0d4444Santon 		delay(100);
2176a0d4444Santon 	}
218cbaa0f69Skettenis 
2196a0d4444Santon 	if (fifolen > 0) {
2206a0d4444Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS,
2216a0d4444Santon 		    (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) |
2226a0d4444Santon 		    (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT));
2236a0d4444Santon 	}
2246a0d4444Santon 	sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM;
2256a0d4444Santon 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc);
2266a0d4444Santon 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
2276a0d4444Santon 
2286a0d4444Santon 
2296a0d4444Santon 	lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
2306a0d4444Santon 	if (fifolen > 0)
2316a0d4444Santon 		lcr |= UART_LCR_H_FEN;
2326a0d4444Santon 	else
2336a0d4444Santon 		lcr &= ~UART_LCR_H_FEN;
2346a0d4444Santon 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
235e474e71dSkettenis }
236e474e71dSkettenis 
237e474e71dSkettenis int
pluart_intr(void * arg)238e474e71dSkettenis pluart_intr(void *arg)
239e474e71dSkettenis {
240e474e71dSkettenis 	struct pluart_softc *sc = arg;
241e474e71dSkettenis 	bus_space_tag_t iot = sc->sc_iot;
242e474e71dSkettenis 	bus_space_handle_t ioh = sc->sc_ioh;
243e474e71dSkettenis 	struct tty *tp = sc->sc_tty;
24426e19086Skettenis 	u_int16_t is;
245e474e71dSkettenis 	u_int16_t *p;
246e474e71dSkettenis 	u_int16_t c;
247e474e71dSkettenis 
2486a0d4444Santon 	is = bus_space_read_4(iot, ioh, UART_MIS);
2496a0d4444Santon 	bus_space_write_4(iot, ioh, UART_ICR, is & ~UART_IMSC_TXIM);
250e474e71dSkettenis 
251e474e71dSkettenis 	if (sc->sc_tty == NULL)
25226e19086Skettenis 		return 0;
253e474e71dSkettenis 
2546a0d4444Santon 	if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) &&
2556a0d4444Santon 	    !ISSET(is, UART_IMSC_TXIM))
25626e19086Skettenis 		return 0;
25726e19086Skettenis 
258cbaa0f69Skettenis 	if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) {
259e474e71dSkettenis 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
260e474e71dSkettenis 		if (sc->sc_halt > 0)
261e474e71dSkettenis 			wakeup(&tp->t_outq);
262e474e71dSkettenis 		(*linesw[tp->t_line].l_start)(tp);
263e474e71dSkettenis 	}
264e474e71dSkettenis 
265e474e71dSkettenis 	p = sc->sc_ibufp;
266e474e71dSkettenis 
2676a0d4444Santon 	while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) {
268e474e71dSkettenis 		c = bus_space_read_2(iot, ioh, UART_DR);
269e474e71dSkettenis 		if (c & UART_DR_BE) {
270e474e71dSkettenis #ifdef DDB
271e474e71dSkettenis 			if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
272e474e71dSkettenis 				if (db_console)
273e474e71dSkettenis 					db_enter();
274e474e71dSkettenis 				continue;
275e474e71dSkettenis 			}
276e474e71dSkettenis #endif
277e474e71dSkettenis 			c = 0;
278e474e71dSkettenis 		}
279e474e71dSkettenis 		if (p >= sc->sc_ibufend) {
280e474e71dSkettenis 			sc->sc_floods++;
281e474e71dSkettenis 			if (sc->sc_errors++ == 0)
2826b43a008Scheloha 				timeout_add_sec(&sc->sc_diag_tmo, 60);
283e474e71dSkettenis 		} else {
284e474e71dSkettenis 			*p++ = c;
285e474e71dSkettenis 			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
286e474e71dSkettenis 				/* XXX */
287e474e71dSkettenis 				//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
288e474e71dSkettenis 				//bus_space_write_4(iot, ioh, IMXUART_UCR3,
289e474e71dSkettenis 				//    sc->sc_ucr3);
290e474e71dSkettenis 			}
291e474e71dSkettenis 		}
292e474e71dSkettenis 		/* XXX - msr stuff ? */
293e474e71dSkettenis 	}
294e474e71dSkettenis 	sc->sc_ibufp = p;
295e474e71dSkettenis 
296e474e71dSkettenis 	softintr_schedule(sc->sc_si);
297e474e71dSkettenis 
298e474e71dSkettenis 	return 1;
299e474e71dSkettenis }
300e474e71dSkettenis 
301e474e71dSkettenis int
pluart_param(struct tty * tp,struct termios * t)302e474e71dSkettenis pluart_param(struct tty *tp, struct termios *t)
303e474e71dSkettenis {
304e474e71dSkettenis 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
305e474e71dSkettenis 	int ospeed = t->c_ospeed;
306e474e71dSkettenis 	int error;
307e474e71dSkettenis 	tcflag_t oldcflag;
308e474e71dSkettenis 
309e474e71dSkettenis 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
310e474e71dSkettenis 		return EINVAL;
311e474e71dSkettenis 
312e474e71dSkettenis 	switch (ISSET(t->c_cflag, CSIZE)) {
313e474e71dSkettenis 	case CS5:
314e474e71dSkettenis 		return EINVAL;
315e474e71dSkettenis 	case CS6:
316e474e71dSkettenis 		return EINVAL;
317e474e71dSkettenis 	case CS7:
318e474e71dSkettenis 		//CLR(sc->sc_ucr2, IMXUART_CR2_WS);
319e474e71dSkettenis 		break;
320e474e71dSkettenis 	case CS8:
321e474e71dSkettenis 		//SET(sc->sc_ucr2, IMXUART_CR2_WS);
322e474e71dSkettenis 		break;
323e474e71dSkettenis 	}
324e474e71dSkettenis //	bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
325e474e71dSkettenis 
326e474e71dSkettenis 	/*
327e474e71dSkettenis 	if (ISSET(t->c_cflag, PARENB)) {
328e474e71dSkettenis 		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
329e474e71dSkettenis 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
330e474e71dSkettenis 	}
331e474e71dSkettenis 	*/
332e474e71dSkettenis 	/* STOPB - XXX */
333e474e71dSkettenis 	if (ospeed == 0) {
334e474e71dSkettenis 		/* lower dtr */
335e474e71dSkettenis 	}
336e474e71dSkettenis 
337c1f87e31Santon 	if (sc->sc_clkfreq != 0 && ospeed != 0 && ospeed != tp->t_ospeed) {
338c1f87e31Santon 		int cr, div, lcr;
339c1f87e31Santon 
340e474e71dSkettenis 		while (ISSET(tp->t_state, TS_BUSY)) {
341e474e71dSkettenis 			++sc->sc_halt;
342e474e71dSkettenis 			error = ttysleep(tp, &tp->t_outq,
343c8b8fc79Scheloha 			    TTOPRI | PCATCH, "pluartprm");
344e474e71dSkettenis 			--sc->sc_halt;
345e474e71dSkettenis 			if (error) {
346e474e71dSkettenis 				pluart_start(tp);
347e474e71dSkettenis 				return (error);
348e474e71dSkettenis 			}
349e474e71dSkettenis 		}
350c1f87e31Santon 
351c1f87e31Santon 		/*
352c1f87e31Santon 		 * Writes to IBRD and FBRD are made effective first when LCR_H
353c1f87e31Santon 		 * is written.
354c1f87e31Santon 		 */
355c1f87e31Santon 		lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
356c1f87e31Santon 
357c1f87e31Santon 		/* The UART must be disabled while changing the baud rate. */
358c1f87e31Santon 		cr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_CR);
359c1f87e31Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR,
360c1f87e31Santon 		    cr & ~UART_CR_UARTEN);
361c1f87e31Santon 
362c1f87e31Santon 		/*
363c1f87e31Santon 		 * The baud rate divisor is expressed relative to the UART clock
364c1f87e31Santon 		 * frequency where IBRD represents the quotient using 16 bits
365c1f87e31Santon 		 * and FBRD the remainder using 6 bits. The PL011 specification
366c1f87e31Santon 		 * provides the following formula:
367c1f87e31Santon 		 *
368c1f87e31Santon 		 *	uartclk/(16 * baudrate)
369c1f87e31Santon 		 *
370c1f87e31Santon 		 * The formula can be estimated by scaling it with the
371c1f87e31Santon 		 * precision 64 (2^6) and letting the resulting upper 16 bits
372c1f87e31Santon 		 * represents the quotient and the lower 6 bits the remainder:
373c1f87e31Santon 		 *
374c1f87e31Santon 		 *	64 * uartclk/(16 * baudrate) = 4 * uartclk/baudrate
375c1f87e31Santon 		 */
376c1f87e31Santon 		div = 4 * sc->sc_clkfreq / ospeed;
377c1f87e31Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IBRD,
378c1f87e31Santon 		    UART_IBRD_DIVINT(div >> 6));
379c1f87e31Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_FBRD,
380c1f87e31Santon 		    UART_FBRD_DIVFRAC(div));
381c1f87e31Santon 		/* Commit baud rate change. */
382c1f87e31Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
383c1f87e31Santon 		/* Enable UART. */
384c1f87e31Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR, cr);
385e474e71dSkettenis 	}
386e474e71dSkettenis 
387e474e71dSkettenis 	/* setup fifo */
388e474e71dSkettenis 
389e474e71dSkettenis 	/* When not using CRTSCTS, RTS follows DTR. */
390e474e71dSkettenis 	/* sc->sc_dtr = MCR_DTR; */
391e474e71dSkettenis 
392e474e71dSkettenis 	/* and copy to tty */
393e474e71dSkettenis 	tp->t_ispeed = t->c_ispeed;
394e474e71dSkettenis 	tp->t_ospeed = t->c_ospeed;
395e474e71dSkettenis 	oldcflag = tp->t_cflag;
396e474e71dSkettenis 	tp->t_cflag = t->c_cflag;
397e474e71dSkettenis 
398e474e71dSkettenis         /*
399e474e71dSkettenis 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
400e474e71dSkettenis 	 * stop the device.
401e474e71dSkettenis 	 */
402e474e71dSkettenis 	 /* XXX */
403e474e71dSkettenis 
404e474e71dSkettenis 	pluart_start(tp);
405e474e71dSkettenis 
406e474e71dSkettenis 	return 0;
407e474e71dSkettenis }
408e474e71dSkettenis 
409e474e71dSkettenis void
pluart_start(struct tty * tp)410e474e71dSkettenis pluart_start(struct tty *tp)
411e474e71dSkettenis {
412e474e71dSkettenis 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
413e474e71dSkettenis 	bus_space_tag_t iot = sc->sc_iot;
414e474e71dSkettenis 	bus_space_handle_t ioh = sc->sc_ioh;
415e474e71dSkettenis 	int s;
41626e19086Skettenis 
417e474e71dSkettenis 	s = spltty();
4186a0d4444Santon 	if (ISSET(tp->t_state, TS_BUSY))
419e474e71dSkettenis 		goto out;
4206a0d4444Santon 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
4216a0d4444Santon 		goto stopped;
42226e19086Skettenis 	ttwakeupwr(tp);
423e474e71dSkettenis 	if (tp->t_outq.c_cc == 0)
4246a0d4444Santon 		goto stopped;
425e474e71dSkettenis 	SET(tp->t_state, TS_BUSY);
426e474e71dSkettenis 
4276a0d4444Santon 	/* Enable transmit interrupt. */
4286a0d4444Santon 	if (!ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
4296a0d4444Santon 		sc->sc_imsc |= UART_IMSC_TXIM;
4306a0d4444Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
4316a0d4444Santon 		    sc->sc_imsc);
43226e19086Skettenis 	}
4336a0d4444Santon 
4346a0d4444Santon 	while (tp->t_outq.c_cc > 0) {
4356a0d4444Santon 		uint16_t fr;
4366a0d4444Santon 
4376a0d4444Santon 		fr = bus_space_read_4(iot, ioh, UART_FR);
4386a0d4444Santon 		if (ISSET(fr, UART_FR_TXFF))
4396a0d4444Santon 			break;
4406a0d4444Santon 
4416a0d4444Santon 		bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
4426a0d4444Santon 	}
4436a0d4444Santon 
444e474e71dSkettenis out:
445e474e71dSkettenis 	splx(s);
4466a0d4444Santon 	return;
4476a0d4444Santon 
4486a0d4444Santon stopped:
4496a0d4444Santon 	/* Disable transmit interrupt. */
4506a0d4444Santon 	if (ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
4516a0d4444Santon 		sc->sc_imsc &= ~UART_IMSC_TXIM;
4526a0d4444Santon 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
4536a0d4444Santon 		    sc->sc_imsc);
4546a0d4444Santon 	}
4556a0d4444Santon 	splx(s);
456e474e71dSkettenis }
457e474e71dSkettenis 
458e474e71dSkettenis void
pluart_diag(void * arg)459e474e71dSkettenis pluart_diag(void *arg)
460e474e71dSkettenis {
461e474e71dSkettenis 	struct pluart_softc *sc = arg;
462e474e71dSkettenis 	int overflows, floods;
463e474e71dSkettenis 	int s;
464e474e71dSkettenis 
465e474e71dSkettenis 	s = spltty();
466e474e71dSkettenis 	sc->sc_errors = 0;
467e474e71dSkettenis 	overflows = sc->sc_overflows;
468e474e71dSkettenis 	sc->sc_overflows = 0;
469e474e71dSkettenis 	floods = sc->sc_floods;
470e474e71dSkettenis 	sc->sc_floods = 0;
471e474e71dSkettenis 	splx(s);
472e474e71dSkettenis 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
473e474e71dSkettenis 	    sc->sc_dev.dv_xname,
474e474e71dSkettenis 	    overflows, overflows == 1 ? "" : "s",
475e474e71dSkettenis 	    floods, floods == 1 ? "" : "s");
476e474e71dSkettenis }
477e474e71dSkettenis 
478e474e71dSkettenis void
pluart_raisedtr(void * arg)479e474e71dSkettenis pluart_raisedtr(void *arg)
480e474e71dSkettenis {
481e474e71dSkettenis 	//struct pluart_softc *sc = arg;
482e474e71dSkettenis 
483e474e71dSkettenis 	//SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
484e474e71dSkettenis 	//bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
485e474e71dSkettenis }
486e474e71dSkettenis 
487e474e71dSkettenis void
pluart_softint(void * arg)488e474e71dSkettenis pluart_softint(void *arg)
489e474e71dSkettenis {
490e474e71dSkettenis 	struct pluart_softc *sc = arg;
491e474e71dSkettenis 	struct tty *tp;
492e474e71dSkettenis 	u_int16_t *ibufp;
493e474e71dSkettenis 	u_int16_t *ibufend;
494e474e71dSkettenis 	int c;
495e474e71dSkettenis 	int err;
496e474e71dSkettenis 	int s;
497e474e71dSkettenis 
498e474e71dSkettenis 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
499e474e71dSkettenis 		return;
500e474e71dSkettenis 
501e474e71dSkettenis 	tp = sc->sc_tty;
502e474e71dSkettenis 	s = spltty();
503e474e71dSkettenis 
504e474e71dSkettenis 	ibufp = sc->sc_ibuf;
505e474e71dSkettenis 	ibufend = sc->sc_ibufp;
506e474e71dSkettenis 
507e474e71dSkettenis 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
508e474e71dSkettenis 		splx(s);
509e474e71dSkettenis 		return;
510e474e71dSkettenis 	}
511e474e71dSkettenis 
512e474e71dSkettenis 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
513e474e71dSkettenis 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
514e474e71dSkettenis 	sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
515e474e71dSkettenis 	sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
516e474e71dSkettenis 
517e474e71dSkettenis #if 0
518e474e71dSkettenis 	if (ISSET(tp->t_cflag, CRTSCTS) &&
519e474e71dSkettenis 	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
520e474e71dSkettenis 		/* XXX */
521e474e71dSkettenis 		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
522e474e71dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
523e474e71dSkettenis 		    sc->sc_ucr3);
524e474e71dSkettenis 	}
525e474e71dSkettenis #endif
526e474e71dSkettenis 
527e474e71dSkettenis 	splx(s);
528e474e71dSkettenis 
529e474e71dSkettenis 	while (ibufp < ibufend) {
530e474e71dSkettenis 		c = *ibufp++;
531e474e71dSkettenis 		/*
532e474e71dSkettenis 		if (ISSET(c, IMXUART_RX_OVERRUN)) {
533e474e71dSkettenis 			sc->sc_overflows++;
534e474e71dSkettenis 			if (sc->sc_errors++ == 0)
5356b43a008Scheloha 				timeout_add_sec(&sc->sc_diag_tmo, 60);
536e474e71dSkettenis 		}
537e474e71dSkettenis 		*/
538e474e71dSkettenis 		/* This is ugly, but fast. */
539e474e71dSkettenis 
540e474e71dSkettenis 		err = 0;
541e474e71dSkettenis 		/*
542e474e71dSkettenis 		if (ISSET(c, IMXUART_RX_PRERR))
543e474e71dSkettenis 			err |= TTY_PE;
544e474e71dSkettenis 		if (ISSET(c, IMXUART_RX_FRMERR))
545e474e71dSkettenis 			err |= TTY_FE;
546e474e71dSkettenis 		*/
547e474e71dSkettenis 		c = (c & 0xff) | err;
548e474e71dSkettenis 		(*linesw[tp->t_line].l_rint)(c, tp);
549e474e71dSkettenis 	}
550e474e71dSkettenis }
551e474e71dSkettenis 
552e474e71dSkettenis int
pluartopen(dev_t dev,int flag,int mode,struct proc * p)553e474e71dSkettenis pluartopen(dev_t dev, int flag, int mode, struct proc *p)
554e474e71dSkettenis {
555e474e71dSkettenis 	int unit = DEVUNIT(dev);
556e474e71dSkettenis 	struct pluart_softc *sc;
557e474e71dSkettenis 	bus_space_tag_t iot;
558e474e71dSkettenis 	bus_space_handle_t ioh;
559e474e71dSkettenis 	struct tty *tp;
560e474e71dSkettenis 	int s;
561e474e71dSkettenis 	int error = 0;
562e474e71dSkettenis 
563e474e71dSkettenis 	if (unit >= pluart_cd.cd_ndevs)
564e474e71dSkettenis 		return ENXIO;
565e474e71dSkettenis 	sc = pluart_cd.cd_devs[unit];
566e474e71dSkettenis 	if (sc == NULL)
567e474e71dSkettenis 		return ENXIO;
568e474e71dSkettenis 
569e474e71dSkettenis 	s = spltty();
570e474e71dSkettenis 	if (sc->sc_tty == NULL)
571e474e71dSkettenis 		tp = sc->sc_tty = ttymalloc(0);
572e474e71dSkettenis 	else
573e474e71dSkettenis 		tp = sc->sc_tty;
574e474e71dSkettenis 
575e474e71dSkettenis 	splx(s);
576e474e71dSkettenis 
577e474e71dSkettenis 	tp->t_oproc = pluart_start;
578e474e71dSkettenis 	tp->t_param = pluart_param;
579e474e71dSkettenis 	tp->t_dev = dev;
580e474e71dSkettenis 
581e474e71dSkettenis 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
582e474e71dSkettenis 		SET(tp->t_state, TS_WOPEN);
583e474e71dSkettenis 		ttychars(tp);
584e474e71dSkettenis 		tp->t_iflag = TTYDEF_IFLAG;
585e474e71dSkettenis 		tp->t_oflag = TTYDEF_OFLAG;
586e474e71dSkettenis 
587e474e71dSkettenis 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
588e474e71dSkettenis 			tp->t_cflag = pluartconscflag;
589e474e71dSkettenis 		else
590e474e71dSkettenis 			tp->t_cflag = TTYDEF_CFLAG;
591e474e71dSkettenis 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
592e474e71dSkettenis 			SET(tp->t_cflag, CLOCAL);
593e474e71dSkettenis 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
594e474e71dSkettenis 			SET(tp->t_cflag, CRTSCTS);
595e474e71dSkettenis 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
596e474e71dSkettenis 			SET(tp->t_cflag, MDMBUF);
597e474e71dSkettenis 		tp->t_lflag = TTYDEF_LFLAG;
598fbe20e63Santon 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
599fbe20e63Santon 			tp->t_ispeed = tp->t_ospeed = pluartconsrate;
600fbe20e63Santon 		else
601e474e71dSkettenis 			tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
602e474e71dSkettenis 
603e474e71dSkettenis 		s = spltty();
604e474e71dSkettenis 
605e474e71dSkettenis 		sc->sc_initialize = 1;
606e474e71dSkettenis 		pluart_param(tp, &tp->t_termios);
607e474e71dSkettenis 		ttsetwater(tp);
608e474e71dSkettenis 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
609e474e71dSkettenis 		sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
610e474e71dSkettenis 		sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
611e474e71dSkettenis 
612e474e71dSkettenis 		iot = sc->sc_iot;
613e474e71dSkettenis 		ioh = sc->sc_ioh;
614e474e71dSkettenis 
615e474e71dSkettenis #if 0
616e474e71dSkettenis 		sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
617e474e71dSkettenis 		sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
618e474e71dSkettenis 		sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
619e474e71dSkettenis 		sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
620e474e71dSkettenis 
621e474e71dSkettenis 		/* interrupt after one char on tx/rx */
622e474e71dSkettenis 		/* reference frequency divider: 1 */
623e474e71dSkettenis 		bus_space_write_4(iot, ioh, IMXUART_UFCR,
624e474e71dSkettenis 		    1 << IMXUART_FCR_TXTL_SH |
625e474e71dSkettenis 		    5 << IMXUART_FCR_RFDIV_SH |
626e474e71dSkettenis 		    1 << IMXUART_FCR_RXTL_SH);
627e474e71dSkettenis 
628e474e71dSkettenis 		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
629e474e71dSkettenis 		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
630e474e71dSkettenis 		bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
631e474e71dSkettenis 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
632e474e71dSkettenis 
633e474e71dSkettenis 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
634e474e71dSkettenis 		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
635e474e71dSkettenis 		bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
636e474e71dSkettenis #endif
637e474e71dSkettenis 
638e474e71dSkettenis 		SET(tp->t_state, TS_CARR_ON); /* XXX */
639e474e71dSkettenis 
640e474e71dSkettenis 
6419ca4957bSjan 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
642e474e71dSkettenis 		return EBUSY;
643e474e71dSkettenis 	else
644e474e71dSkettenis 		s = spltty();
645e474e71dSkettenis 
646e474e71dSkettenis 	if (DEVCUA(dev)) {
647e474e71dSkettenis 		if (ISSET(tp->t_state, TS_ISOPEN)) {
648e474e71dSkettenis 			splx(s);
649e474e71dSkettenis 			return EBUSY;
650e474e71dSkettenis 		}
651e474e71dSkettenis 		sc->sc_cua = 1;
652e474e71dSkettenis 	} else {
653e474e71dSkettenis 		/* tty (not cua) device; wait for carrier if necessary */
654e474e71dSkettenis 		if (ISSET(flag, O_NONBLOCK)) {
655e474e71dSkettenis 			if (sc->sc_cua) {
656e474e71dSkettenis 				/* Opening TTY non-blocking... but the CUA is busy */
657e474e71dSkettenis 				splx(s);
658e474e71dSkettenis 				return EBUSY;
659e474e71dSkettenis 			}
660e474e71dSkettenis 		} else {
661e474e71dSkettenis 			while (sc->sc_cua ||
662e474e71dSkettenis 			    (!ISSET(tp->t_cflag, CLOCAL) &&
663e474e71dSkettenis 				!ISSET(tp->t_state, TS_CARR_ON))) {
664e474e71dSkettenis 				SET(tp->t_state, TS_WOPEN);
665e474e71dSkettenis 				error = ttysleep(tp, &tp->t_rawq,
666c8b8fc79Scheloha 				    TTIPRI | PCATCH, ttopen);
667e474e71dSkettenis 				/*
668e474e71dSkettenis 				 * If TS_WOPEN has been reset, that means the
669e474e71dSkettenis 				 * cua device has been closed.  We don't want
670e474e71dSkettenis 				 * to fail in that case,
671e474e71dSkettenis 				 * so just go around again.
672e474e71dSkettenis 				 */
673e474e71dSkettenis 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
674e474e71dSkettenis 					CLR(tp->t_state, TS_WOPEN);
675e474e71dSkettenis 					splx(s);
676e474e71dSkettenis 					return error;
677e474e71dSkettenis 				}
678e474e71dSkettenis 			}
679e474e71dSkettenis 		}
680e474e71dSkettenis 	}
681e474e71dSkettenis 	splx(s);
682e474e71dSkettenis 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
683e474e71dSkettenis }
684e474e71dSkettenis 
685e474e71dSkettenis int
pluartclose(dev_t dev,int flag,int mode,struct proc * p)686e474e71dSkettenis pluartclose(dev_t dev, int flag, int mode, struct proc *p)
687e474e71dSkettenis {
688e474e71dSkettenis 	int unit = DEVUNIT(dev);
689e474e71dSkettenis 	struct pluart_softc *sc = pluart_cd.cd_devs[unit];
690e474e71dSkettenis 	//bus_space_tag_t iot = sc->sc_iot;
691e474e71dSkettenis 	//bus_space_handle_t ioh = sc->sc_ioh;
692e474e71dSkettenis 	struct tty *tp = sc->sc_tty;
693e474e71dSkettenis 	int s;
694e474e71dSkettenis 
695e474e71dSkettenis 	/* XXX This is for cons.c. */
696e474e71dSkettenis 	if (!ISSET(tp->t_state, TS_ISOPEN))
697e474e71dSkettenis 		return 0;
698e474e71dSkettenis 
699e474e71dSkettenis 	(*linesw[tp->t_line].l_close)(tp, flag, p);
700e474e71dSkettenis 	s = spltty();
701e474e71dSkettenis 	if (ISSET(tp->t_state, TS_WOPEN)) {
702e474e71dSkettenis 		/* tty device is waiting for carrier; drop dtr then re-raise */
703e474e71dSkettenis 		//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
704e474e71dSkettenis 		//bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
7056b43a008Scheloha 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
706e474e71dSkettenis 	}
707e474e71dSkettenis 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
708e474e71dSkettenis 
709e474e71dSkettenis 	sc->sc_cua = 0;
710e474e71dSkettenis 	splx(s);
711e474e71dSkettenis 	ttyclose(tp);
712e474e71dSkettenis 
713e474e71dSkettenis 	return 0;
714e474e71dSkettenis }
715e474e71dSkettenis 
716e474e71dSkettenis int
pluartread(dev_t dev,struct uio * uio,int flag)717e474e71dSkettenis pluartread(dev_t dev, struct uio *uio, int flag)
718e474e71dSkettenis {
719e474e71dSkettenis 	struct tty *tty;
720e474e71dSkettenis 
721e474e71dSkettenis 	tty = pluarttty(dev);
722e474e71dSkettenis 	if (tty == NULL)
723e474e71dSkettenis 		return ENODEV;
724e474e71dSkettenis 
725e474e71dSkettenis 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
726e474e71dSkettenis }
727e474e71dSkettenis 
728e474e71dSkettenis int
pluartwrite(dev_t dev,struct uio * uio,int flag)729e474e71dSkettenis pluartwrite(dev_t dev, struct uio *uio, int flag)
730e474e71dSkettenis {
731e474e71dSkettenis 	struct tty *tty;
732e474e71dSkettenis 
733e474e71dSkettenis 	tty = pluarttty(dev);
734e474e71dSkettenis 	if (tty == NULL)
735e474e71dSkettenis 		return ENODEV;
736e474e71dSkettenis 
737e474e71dSkettenis 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
738e474e71dSkettenis }
739e474e71dSkettenis 
740e474e71dSkettenis int
pluartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)741e474e71dSkettenis pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
742e474e71dSkettenis {
743e474e71dSkettenis 	struct pluart_softc *sc;
744e474e71dSkettenis 	struct tty *tp;
745e474e71dSkettenis 	int error;
746e474e71dSkettenis 
747e474e71dSkettenis 	sc = pluart_sc(dev);
748e474e71dSkettenis 	if (sc == NULL)
749e474e71dSkettenis 		return (ENODEV);
750e474e71dSkettenis 
751e474e71dSkettenis 	tp = sc->sc_tty;
752e474e71dSkettenis 	if (tp == NULL)
753e474e71dSkettenis 		return (ENXIO);
754e474e71dSkettenis 
755e474e71dSkettenis 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
756e474e71dSkettenis 	if (error >= 0)
757e474e71dSkettenis 		return (error);
758e474e71dSkettenis 
759e474e71dSkettenis 	error = ttioctl(tp, cmd, data, flag, p);
760e474e71dSkettenis 	if (error >= 0)
761e474e71dSkettenis 		return (error);
762e474e71dSkettenis 
763e474e71dSkettenis 	switch(cmd) {
764e474e71dSkettenis 	case TIOCSBRK:
765e474e71dSkettenis 		break;
766e474e71dSkettenis 	case TIOCCBRK:
767e474e71dSkettenis 		break;
768e474e71dSkettenis 	case TIOCSDTR:
769e474e71dSkettenis 		break;
770e474e71dSkettenis 	case TIOCCDTR:
771e474e71dSkettenis 		break;
772e474e71dSkettenis 	case TIOCMSET:
773e474e71dSkettenis 		break;
774e474e71dSkettenis 	case TIOCMBIS:
775e474e71dSkettenis 		break;
776e474e71dSkettenis 	case TIOCMBIC:
777e474e71dSkettenis 		break;
778e474e71dSkettenis 	case TIOCMGET:
779e474e71dSkettenis 		break;
780e474e71dSkettenis 	case TIOCGFLAGS:
781e474e71dSkettenis 		break;
782e474e71dSkettenis 	case TIOCSFLAGS:
783e474e71dSkettenis 		error = suser(p);
784e474e71dSkettenis 		if (error != 0)
785e474e71dSkettenis 			return(EPERM);
786e474e71dSkettenis 		break;
787e474e71dSkettenis 	default:
788e474e71dSkettenis 		return (ENOTTY);
789e474e71dSkettenis 	}
790e474e71dSkettenis 
791e474e71dSkettenis 	return 0;
792e474e71dSkettenis }
793e474e71dSkettenis 
794e474e71dSkettenis int
pluartstop(struct tty * tp,int flag)795e474e71dSkettenis pluartstop(struct tty *tp, int flag)
796e474e71dSkettenis {
797e474e71dSkettenis 	return 0;
798e474e71dSkettenis }
799e474e71dSkettenis 
800e474e71dSkettenis struct tty *
pluarttty(dev_t dev)801e474e71dSkettenis pluarttty(dev_t dev)
802e474e71dSkettenis {
803e474e71dSkettenis 	int unit;
804e474e71dSkettenis 	struct pluart_softc *sc;
805e474e71dSkettenis 	unit = DEVUNIT(dev);
806e474e71dSkettenis 	if (unit >= pluart_cd.cd_ndevs)
807e474e71dSkettenis 		return NULL;
808e474e71dSkettenis 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
809e474e71dSkettenis 	if (sc == NULL)
810e474e71dSkettenis 		return NULL;
811e474e71dSkettenis 	return sc->sc_tty;
812e474e71dSkettenis }
813e474e71dSkettenis 
814e474e71dSkettenis struct pluart_softc *
pluart_sc(dev_t dev)815e474e71dSkettenis pluart_sc(dev_t dev)
816e474e71dSkettenis {
817e474e71dSkettenis 	int unit;
818e474e71dSkettenis 	struct pluart_softc *sc;
819e474e71dSkettenis 	unit = DEVUNIT(dev);
820e474e71dSkettenis 	if (unit >= pluart_cd.cd_ndevs)
821e474e71dSkettenis 		return NULL;
822e474e71dSkettenis 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
823e474e71dSkettenis 	return sc;
824e474e71dSkettenis }
825e474e71dSkettenis 
826e474e71dSkettenis 
827e474e71dSkettenis /* serial console */
828e474e71dSkettenis void
pluartcnprobe(struct consdev * cp)829e474e71dSkettenis pluartcnprobe(struct consdev *cp)
830e474e71dSkettenis {
831e474e71dSkettenis }
832e474e71dSkettenis 
833e474e71dSkettenis void
pluartcninit(struct consdev * cp)834e474e71dSkettenis pluartcninit(struct consdev *cp)
835e474e71dSkettenis {
836e474e71dSkettenis }
837e474e71dSkettenis 
838e474e71dSkettenis int
pluartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)839e474e71dSkettenis pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
840e474e71dSkettenis {
841e474e71dSkettenis 	static struct consdev pluartcons = {
842e474e71dSkettenis 		NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
843e474e71dSkettenis 		NODEV, CN_MIDPRI
844e474e71dSkettenis 	};
845e474e71dSkettenis 	int maj;
846e474e71dSkettenis 
847e474e71dSkettenis 	if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
848e474e71dSkettenis 		return ENOMEM;
849e474e71dSkettenis 
850e474e71dSkettenis 	/* Disable FIFO. */
851e474e71dSkettenis 	bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
852e474e71dSkettenis 	    bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
853e474e71dSkettenis 
854e474e71dSkettenis 	/* Look for major of com(4) to replace. */
855e474e71dSkettenis 	for (maj = 0; maj < nchrdev; maj++)
856e474e71dSkettenis 		if (cdevsw[maj].d_open == comopen)
857e474e71dSkettenis 			break;
858e474e71dSkettenis 	if (maj == nchrdev)
859e474e71dSkettenis 		return ENXIO;
860e474e71dSkettenis 
861e474e71dSkettenis 	cn_tab = &pluartcons;
862e474e71dSkettenis 	cn_tab->cn_dev = makedev(maj, 0);
863eee2dd38Skettenis 	cdevsw[maj] = pluartdev;	/* KLUDGE */
864e474e71dSkettenis 
865e474e71dSkettenis 	pluartconsiot = iot;
866e474e71dSkettenis 	pluartconsaddr = iobase;
867e474e71dSkettenis 	pluartconscflag = cflag;
868fbe20e63Santon 	pluartconsrate = rate;
869e474e71dSkettenis 
870e474e71dSkettenis 	return 0;
871e474e71dSkettenis }
872e474e71dSkettenis 
873e474e71dSkettenis int
pluartcngetc(dev_t dev)874e474e71dSkettenis pluartcngetc(dev_t dev)
875e474e71dSkettenis {
876e474e71dSkettenis 	int c;
877e474e71dSkettenis 	int s;
878e474e71dSkettenis 	s = splhigh();
879e474e71dSkettenis 	while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
8806a0d4444Santon 	    UART_FR_RXFE))
881e474e71dSkettenis 		;
882e474e71dSkettenis 	c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
883e474e71dSkettenis 	splx(s);
884e474e71dSkettenis 	return c;
885e474e71dSkettenis }
886e474e71dSkettenis 
887e474e71dSkettenis void
pluartcnputc(dev_t dev,int c)888e474e71dSkettenis pluartcnputc(dev_t dev, int c)
889e474e71dSkettenis {
890e474e71dSkettenis 	int s;
891e474e71dSkettenis 	s = splhigh();
892e474e71dSkettenis 	while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
8936a0d4444Santon 	    UART_FR_TXFF))
894e474e71dSkettenis 		;
895e474e71dSkettenis 	bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
896e474e71dSkettenis 	splx(s);
897e474e71dSkettenis }
898e474e71dSkettenis 
899e474e71dSkettenis void
pluartcnpollc(dev_t dev,int on)900e474e71dSkettenis pluartcnpollc(dev_t dev, int on)
901e474e71dSkettenis {
902e474e71dSkettenis }
903