xref: /openbsd-src/sys/dev/fdt/cduart.c (revision 282e735ec5f887e380e4ca31e411c5365c102af1)
1*282e735eSvisa /*	$OpenBSD: cduart.c,v 1.1 2021/04/24 07:49:11 visa Exp $	*/
2*282e735eSvisa 
3*282e735eSvisa /*
4*282e735eSvisa  * Copyright (c) 2021 Visa Hankala
5*282e735eSvisa  *
6*282e735eSvisa  * Permission to use, copy, modify, and/or distribute this software for any
7*282e735eSvisa  * purpose with or without fee is hereby granted, provided that the above
8*282e735eSvisa  * copyright notice and this permission notice appear in all copies.
9*282e735eSvisa  *
10*282e735eSvisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*282e735eSvisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*282e735eSvisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*282e735eSvisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*282e735eSvisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*282e735eSvisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*282e735eSvisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*282e735eSvisa  */
18*282e735eSvisa 
19*282e735eSvisa /*
20*282e735eSvisa  * Driver for Cadence UART.
21*282e735eSvisa  */
22*282e735eSvisa 
23*282e735eSvisa #include <sys/param.h>
24*282e735eSvisa #include <sys/systm.h>
25*282e735eSvisa #include <sys/conf.h>
26*282e735eSvisa #include <sys/device.h>
27*282e735eSvisa #include <sys/fcntl.h>
28*282e735eSvisa #include <sys/tty.h>
29*282e735eSvisa #include <sys/syslog.h>
30*282e735eSvisa 
31*282e735eSvisa #include <machine/bus.h>
32*282e735eSvisa #include <machine/fdt.h>
33*282e735eSvisa 
34*282e735eSvisa #include <dev/cons.h>
35*282e735eSvisa 
36*282e735eSvisa #include <dev/ofw/fdt.h>
37*282e735eSvisa #include <dev/ofw/openfirm.h>
38*282e735eSvisa 
39*282e735eSvisa #define CDUART_CR			0x0000
40*282e735eSvisa #define  CDUART_CR_STOPBRK			(1 << 8)
41*282e735eSvisa #define  CDUART_CR_STARTBRK			(1 << 7)
42*282e735eSvisa #define  CDUART_CR_TORST			(1 << 6)
43*282e735eSvisa #define  CDUART_CR_TXDIS			(1 << 5)
44*282e735eSvisa #define  CDUART_CR_TXEN				(1 << 4)
45*282e735eSvisa #define  CDUART_CR_RXDIS			(1 << 3)
46*282e735eSvisa #define  CDUART_CR_RXEN				(1 << 2)
47*282e735eSvisa #define  CDUART_CR_TXRST			(1 << 1)
48*282e735eSvisa #define  CDUART_CR_RXRST			(1 << 0)
49*282e735eSvisa #define CDUART_MR			0x0004
50*282e735eSvisa #define  CDUART_MR_CHMODE_MASK			(0x3 << 8)
51*282e735eSvisa #define  CDUART_MR_NBSTOP_MASK			(0x3 << 6)
52*282e735eSvisa #define  CDUART_MR_PAR_MASK			(0x7 << 3)
53*282e735eSvisa #define  CDUART_MR_PAR_NO			(0x4 << 3)
54*282e735eSvisa #define  CDUART_MR_PAR_FORCED1			(0x3 << 3)
55*282e735eSvisa #define  CDUART_MR_PAR_FORCED0			(0x2 << 3)
56*282e735eSvisa #define  CDUART_MR_PAR_ODD			(0x1 << 3)
57*282e735eSvisa #define  CDUART_MR_PAR_EVEN			(0x0 << 3)
58*282e735eSvisa #define  CDUART_MR_CHRL_MASK			(0x3 << 1)
59*282e735eSvisa #define  CDUART_MR_CHRL_C6			(0x3 << 1)
60*282e735eSvisa #define  CDUART_MR_CHRL_C7			(0x2 << 1)
61*282e735eSvisa #define  CDUART_MR_CHRL_C8			(0x0 << 1)
62*282e735eSvisa #define  CDUART_MR_CLKSEL			(1 << 0)
63*282e735eSvisa #define CDUART_IER			0x0008
64*282e735eSvisa #define CDUART_IDR			0x000c
65*282e735eSvisa #define CDUART_IMR			0x0010
66*282e735eSvisa #define CDUART_ISR			0x0014
67*282e735eSvisa #define  CDUART_ISR_TXOVR			(1 << 12)
68*282e735eSvisa #define  CDUART_ISR_TNFUL			(1 << 11)
69*282e735eSvisa #define  CDUART_ISR_TTRIG			(1 << 10)
70*282e735eSvisa #define  CDUART_IXR_DMS				(1 << 9)
71*282e735eSvisa #define  CDUART_IXR_TOUT			(1 << 8)
72*282e735eSvisa #define  CDUART_IXR_PARITY			(1 << 7)
73*282e735eSvisa #define  CDUART_IXR_FRAMING			(1 << 6)
74*282e735eSvisa #define  CDUART_IXR_RXOVR			(1 << 5)
75*282e735eSvisa #define  CDUART_IXR_TXFULL			(1 << 4)
76*282e735eSvisa #define  CDUART_IXR_TXEMPTY			(1 << 3)
77*282e735eSvisa #define  CDUART_IXR_RXFULL			(1 << 2)
78*282e735eSvisa #define  CDUART_IXR_RXEMPTY			(1 << 1)
79*282e735eSvisa #define  CDUART_IXR_RTRIG			(1 << 0)
80*282e735eSvisa #define CDUART_RXTOUT			0x001c
81*282e735eSvisa #define CDUART_RXWM			0x0020
82*282e735eSvisa #define CDUART_SR			0x002c
83*282e735eSvisa #define  CDUART_SR_TNFUL			(1 << 14)
84*282e735eSvisa #define  CDUART_SR_TTRIG			(1 << 13)
85*282e735eSvisa #define  CDUART_SR_FLOWDEL			(1 << 12)
86*282e735eSvisa #define  CDUART_SR_TACTIVE			(1 << 11)
87*282e735eSvisa #define  CDUART_SR_RACTIVE			(1 << 10)
88*282e735eSvisa #define  CDUART_SR_TXFULL			(1 << 4)
89*282e735eSvisa #define  CDUART_SR_TXEMPTY			(1 << 3)
90*282e735eSvisa #define  CDUART_SR_RXFULL			(1 << 2)
91*282e735eSvisa #define  CDUART_SR_RXEMPTY			(1 << 1)
92*282e735eSvisa #define  CDUART_SR_RXOVR			(1 << 0)
93*282e735eSvisa #define CDUART_FIFO			0x0030
94*282e735eSvisa 
95*282e735eSvisa #define CDUART_SPACE_SIZE		0x0048
96*282e735eSvisa 
97*282e735eSvisa #define CDUART_FIFOSIZE		64
98*282e735eSvisa #define CDUART_IBUFSIZE		128
99*282e735eSvisa 
100*282e735eSvisa struct cduart_softc {
101*282e735eSvisa 	struct device		sc_dev;
102*282e735eSvisa 	bus_space_tag_t		sc_iot;
103*282e735eSvisa 	bus_space_handle_t	sc_ioh;
104*282e735eSvisa 	void			*sc_ih;
105*282e735eSvisa 	void			*sc_si;
106*282e735eSvisa 
107*282e735eSvisa 	struct tty		*sc_tty;
108*282e735eSvisa 	uint8_t			sc_cua;
109*282e735eSvisa 
110*282e735eSvisa 	struct timeout		sc_diag_tmo;
111*282e735eSvisa 	int			sc_overflows;
112*282e735eSvisa 	int			sc_floods;
113*282e735eSvisa 	int			sc_errors;
114*282e735eSvisa 
115*282e735eSvisa 	int			sc_ibufs[2][CDUART_IBUFSIZE];
116*282e735eSvisa 	int			*sc_ibuf;
117*282e735eSvisa 	int			*sc_ibufend;
118*282e735eSvisa 	int			*sc_ibufp;
119*282e735eSvisa };
120*282e735eSvisa 
121*282e735eSvisa int	cduart_match(struct device *, void *, void *);
122*282e735eSvisa void	cduart_attach(struct device *, struct device *, void *);
123*282e735eSvisa void	cduart_diag(void *);
124*282e735eSvisa int	cduart_intr(void *);
125*282e735eSvisa void	cduart_softintr(void *);
126*282e735eSvisa 
127*282e735eSvisa struct tty *cduarttty(dev_t);
128*282e735eSvisa struct cduart_softc *cduart_sc(dev_t);
129*282e735eSvisa 
130*282e735eSvisa int	cduartparam(struct tty *, struct termios *);
131*282e735eSvisa void	cduartstart(struct tty *);
132*282e735eSvisa 
133*282e735eSvisa int	cduartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
134*282e735eSvisa void	cduartcnprobe(struct consdev *);
135*282e735eSvisa void	cduartcninit(struct consdev *);
136*282e735eSvisa int	cduartcngetc(dev_t);
137*282e735eSvisa void	cduartcnputc(dev_t, int);
138*282e735eSvisa void	cduartcnpollc(dev_t, int);
139*282e735eSvisa 
140*282e735eSvisa cdev_decl(com);
141*282e735eSvisa cdev_decl(cduart);
142*282e735eSvisa 
143*282e735eSvisa const struct cfattach cduart_ca = {
144*282e735eSvisa 	sizeof(struct cduart_softc), cduart_match, cduart_attach
145*282e735eSvisa };
146*282e735eSvisa 
147*282e735eSvisa struct cfdriver cduart_cd = {
148*282e735eSvisa 	NULL, "cduart", DV_DULL
149*282e735eSvisa };
150*282e735eSvisa 
151*282e735eSvisa bus_space_tag_t	cduartconsiot;
152*282e735eSvisa bus_space_handle_t cduartconsioh;
153*282e735eSvisa int		cduartconsrate;
154*282e735eSvisa tcflag_t	cduartconscflag;
155*282e735eSvisa struct cdevsw	cduartdev = cdev_tty_init(3, cduart);
156*282e735eSvisa 
157*282e735eSvisa #define DEVUNIT(x)	(minor(x) & 0x7f)
158*282e735eSvisa #define DEVCUA(x)	(minor(x) & 0x80)
159*282e735eSvisa 
160*282e735eSvisa static inline uint32_t
cduart_read(struct cduart_softc * sc,uint32_t reg)161*282e735eSvisa cduart_read(struct cduart_softc *sc, uint32_t reg)
162*282e735eSvisa {
163*282e735eSvisa 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
164*282e735eSvisa }
165*282e735eSvisa 
166*282e735eSvisa static inline void
cduart_write(struct cduart_softc * sc,uint32_t reg,uint32_t val)167*282e735eSvisa cduart_write(struct cduart_softc *sc, uint32_t reg, uint32_t val)
168*282e735eSvisa {
169*282e735eSvisa 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
170*282e735eSvisa }
171*282e735eSvisa 
172*282e735eSvisa void
cduart_init_cons(void)173*282e735eSvisa cduart_init_cons(void)
174*282e735eSvisa {
175*282e735eSvisa 	struct fdt_reg reg;
176*282e735eSvisa 	void *node;
177*282e735eSvisa 
178*282e735eSvisa 	if ((node = fdt_find_cons("cdns,uart-r1p8")) == NULL &&
179*282e735eSvisa 	    (node = fdt_find_cons("cdns,uart-r1p12")) == NULL)
180*282e735eSvisa 		return;
181*282e735eSvisa 	if (fdt_get_reg(node, 0, &reg) != 0)
182*282e735eSvisa 		return;
183*282e735eSvisa 
184*282e735eSvisa 	cduartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
185*282e735eSvisa }
186*282e735eSvisa 
187*282e735eSvisa int
cduart_match(struct device * parent,void * match,void * aux)188*282e735eSvisa cduart_match(struct device *parent, void *match, void *aux)
189*282e735eSvisa {
190*282e735eSvisa 	struct fdt_attach_args *faa = aux;
191*282e735eSvisa 
192*282e735eSvisa 	return OF_is_compatible(faa->fa_node, "cdns,uart-r1p8") ||
193*282e735eSvisa 	    OF_is_compatible(faa->fa_node, "cdns,uart-r1p12");
194*282e735eSvisa }
195*282e735eSvisa 
196*282e735eSvisa void
cduart_attach(struct device * parent,struct device * self,void * aux)197*282e735eSvisa cduart_attach(struct device *parent, struct device *self, void *aux)
198*282e735eSvisa {
199*282e735eSvisa 	struct fdt_attach_args *faa = aux;
200*282e735eSvisa 	struct cduart_softc *sc = (struct cduart_softc *)self;
201*282e735eSvisa 	uint32_t cr, isr;
202*282e735eSvisa 	int maj;
203*282e735eSvisa 
204*282e735eSvisa 	if (faa->fa_nreg < 1) {
205*282e735eSvisa 		printf(": no registers\n");
206*282e735eSvisa 		return;
207*282e735eSvisa 	}
208*282e735eSvisa 
209*282e735eSvisa 	sc->sc_iot = faa->fa_iot;
210*282e735eSvisa 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
211*282e735eSvisa 	    faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) {
212*282e735eSvisa 		printf(": can't map registers\n");
213*282e735eSvisa 		return;
214*282e735eSvisa 	}
215*282e735eSvisa 
216*282e735eSvisa 	/* Disable all interrupts. */
217*282e735eSvisa 	cduart_write(sc, CDUART_IDR, ~0U);
218*282e735eSvisa 
219*282e735eSvisa 	/* Clear any pending interrupts. */
220*282e735eSvisa 	isr = cduart_read(sc, CDUART_ISR);
221*282e735eSvisa 	cduart_write(sc, CDUART_ISR, isr);
222*282e735eSvisa 
223*282e735eSvisa 	sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
224*282e735eSvisa 	    cduart_intr, sc, sc->sc_dev.dv_xname);
225*282e735eSvisa 	if (sc->sc_ih == NULL) {
226*282e735eSvisa 		printf(": can't establish interrupt\n");
227*282e735eSvisa 		goto fail;
228*282e735eSvisa 	}
229*282e735eSvisa 
230*282e735eSvisa 	timeout_set(&sc->sc_diag_tmo, cduart_diag, sc);
231*282e735eSvisa 	sc->sc_si = softintr_establish(IPL_TTY, cduart_softintr, sc);
232*282e735eSvisa 	if (sc->sc_si == NULL) {
233*282e735eSvisa 		printf(": can't establish soft interrupt\n");
234*282e735eSvisa 		goto fail;
235*282e735eSvisa 	}
236*282e735eSvisa 
237*282e735eSvisa 	if (faa->fa_node == stdout_node) {
238*282e735eSvisa 		/* Locate the major number. */
239*282e735eSvisa 		for (maj = 0; maj < nchrdev; maj++) {
240*282e735eSvisa 			if (cdevsw[maj].d_open == cduartopen)
241*282e735eSvisa 				break;
242*282e735eSvisa 		}
243*282e735eSvisa 		KASSERT(maj < nchrdev);
244*282e735eSvisa 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
245*282e735eSvisa 		printf(": console");
246*282e735eSvisa 	}
247*282e735eSvisa 
248*282e735eSvisa 	/* Enable transmitter and receiver. */
249*282e735eSvisa 	cr = cduart_read(sc, CDUART_CR);
250*282e735eSvisa 	cr &= ~(CDUART_CR_TXDIS | CDUART_CR_RXDIS);
251*282e735eSvisa 	cr |= CDUART_CR_TXEN | CDUART_CR_RXEN;
252*282e735eSvisa 	cduart_write(sc, CDUART_CR, cr);
253*282e735eSvisa 
254*282e735eSvisa 	printf("\n");
255*282e735eSvisa 
256*282e735eSvisa 	return;
257*282e735eSvisa 
258*282e735eSvisa fail:
259*282e735eSvisa 	if (sc->sc_si != NULL)
260*282e735eSvisa 		softintr_disestablish(sc->sc_si);
261*282e735eSvisa 	if (sc->sc_ih != NULL)
262*282e735eSvisa 		fdt_intr_disestablish(sc->sc_ih);
263*282e735eSvisa 	if (sc->sc_ioh != 0)
264*282e735eSvisa 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, CDUART_SPACE_SIZE);
265*282e735eSvisa }
266*282e735eSvisa 
267*282e735eSvisa int
cduart_intr(void * arg)268*282e735eSvisa cduart_intr(void *arg)
269*282e735eSvisa {
270*282e735eSvisa 	struct cduart_softc *sc = arg;
271*282e735eSvisa 	struct tty *tp = sc->sc_tty;
272*282e735eSvisa 	int *ibufp;
273*282e735eSvisa 	uint32_t isr, sr;
274*282e735eSvisa 	int c, handled = 0;
275*282e735eSvisa 
276*282e735eSvisa 	if (tp == NULL)
277*282e735eSvisa 		return 0;
278*282e735eSvisa 
279*282e735eSvisa 	isr = cduart_read(sc, CDUART_ISR);
280*282e735eSvisa 	cduart_write(sc, CDUART_ISR, isr);
281*282e735eSvisa 
282*282e735eSvisa 	if ((isr & CDUART_IXR_TXEMPTY) && (tp->t_state & TS_BUSY)) {
283*282e735eSvisa 		tp->t_state &= ~TS_BUSY;
284*282e735eSvisa 		(*linesw[tp->t_line].l_start)(tp);
285*282e735eSvisa 		handled = 1;
286*282e735eSvisa 	}
287*282e735eSvisa 
288*282e735eSvisa 	if (isr & (CDUART_IXR_TOUT | CDUART_IXR_RTRIG)) {
289*282e735eSvisa 		ibufp = sc->sc_ibufp;
290*282e735eSvisa 		for (;;) {
291*282e735eSvisa 			sr = cduart_read(sc, CDUART_SR);
292*282e735eSvisa 			if (sr & CDUART_SR_RXEMPTY)
293*282e735eSvisa 				break;
294*282e735eSvisa 			c = cduart_read(sc, CDUART_FIFO) & 0xff;
295*282e735eSvisa 
296*282e735eSvisa 			if (ibufp < sc->sc_ibufend) {
297*282e735eSvisa 				*ibufp++ = c;
298*282e735eSvisa 			} else {
299*282e735eSvisa 				sc->sc_floods++;
300*282e735eSvisa 				if (sc->sc_errors++ == 0)
301*282e735eSvisa 					timeout_add_sec(&sc->sc_diag_tmo, 60);
302*282e735eSvisa 			}
303*282e735eSvisa 		}
304*282e735eSvisa 		if (sc->sc_ibufp != ibufp) {
305*282e735eSvisa 			sc->sc_ibufp = ibufp;
306*282e735eSvisa 			softintr_schedule(sc->sc_si);
307*282e735eSvisa 		}
308*282e735eSvisa 		handled = 1;
309*282e735eSvisa 	}
310*282e735eSvisa 
311*282e735eSvisa 	if (isr & CDUART_IXR_RXOVR) {
312*282e735eSvisa 		sc->sc_overflows++;
313*282e735eSvisa 		if (sc->sc_errors++ == 0)
314*282e735eSvisa 			timeout_add_sec(&sc->sc_diag_tmo, 60);
315*282e735eSvisa 		handled = 1;
316*282e735eSvisa 	}
317*282e735eSvisa 
318*282e735eSvisa 	return handled;
319*282e735eSvisa }
320*282e735eSvisa 
321*282e735eSvisa void
cduart_softintr(void * arg)322*282e735eSvisa cduart_softintr(void *arg)
323*282e735eSvisa {
324*282e735eSvisa 	struct cduart_softc *sc = arg;
325*282e735eSvisa 	struct tty *tp = sc->sc_tty;
326*282e735eSvisa 	int *ibufend, *ibufp;
327*282e735eSvisa 	int s;
328*282e735eSvisa 
329*282e735eSvisa 	s = spltty();
330*282e735eSvisa 
331*282e735eSvisa 	ibufp = sc->sc_ibuf;
332*282e735eSvisa 	ibufend = sc->sc_ibufp;
333*282e735eSvisa 
334*282e735eSvisa 	if (ibufp == ibufend) {
335*282e735eSvisa 		splx(s);
336*282e735eSvisa 		return;
337*282e735eSvisa 	}
338*282e735eSvisa 
339*282e735eSvisa 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
340*282e735eSvisa 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
341*282e735eSvisa 	sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
342*282e735eSvisa 
343*282e735eSvisa 	if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
344*282e735eSvisa 		splx(s);
345*282e735eSvisa 		return;
346*282e735eSvisa 	}
347*282e735eSvisa 
348*282e735eSvisa 	splx(s);
349*282e735eSvisa 
350*282e735eSvisa 	while (ibufp < ibufend)
351*282e735eSvisa 		(*linesw[tp->t_line].l_rint)(*ibufp++, tp);
352*282e735eSvisa }
353*282e735eSvisa 
354*282e735eSvisa void
cduart_diag(void * arg)355*282e735eSvisa cduart_diag(void *arg)
356*282e735eSvisa {
357*282e735eSvisa 	struct cduart_softc *sc = arg;
358*282e735eSvisa 	int overflows, floods;
359*282e735eSvisa 	int s;
360*282e735eSvisa 
361*282e735eSvisa 	s = spltty();
362*282e735eSvisa 	sc->sc_errors = 0;
363*282e735eSvisa 	overflows = sc->sc_overflows;
364*282e735eSvisa 	sc->sc_overflows = 0;
365*282e735eSvisa 	floods = sc->sc_floods;
366*282e735eSvisa 	sc->sc_floods = 0;
367*282e735eSvisa 	splx(s);
368*282e735eSvisa 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
369*282e735eSvisa 	    sc->sc_dev.dv_xname,
370*282e735eSvisa 	    overflows, overflows == 1 ? "" : "s",
371*282e735eSvisa 	    floods, floods == 1 ? "" : "s");
372*282e735eSvisa }
373*282e735eSvisa 
374*282e735eSvisa int
cduartopen(dev_t dev,int flag,int mode,struct proc * p)375*282e735eSvisa cduartopen(dev_t dev, int flag, int mode, struct proc *p)
376*282e735eSvisa {
377*282e735eSvisa 	struct cduart_softc *sc;
378*282e735eSvisa 	struct tty *tp;
379*282e735eSvisa 	uint32_t sr;
380*282e735eSvisa 	int error, s;
381*282e735eSvisa 
382*282e735eSvisa 	sc = cduart_sc(dev);
383*282e735eSvisa 	if (sc == NULL)
384*282e735eSvisa 		return ENXIO;
385*282e735eSvisa 
386*282e735eSvisa 	s = spltty();
387*282e735eSvisa 
388*282e735eSvisa 	if (sc->sc_tty == NULL)
389*282e735eSvisa 		sc->sc_tty = ttymalloc(0);
390*282e735eSvisa 
391*282e735eSvisa 	tp = sc->sc_tty;
392*282e735eSvisa 	tp->t_oproc = cduartstart;
393*282e735eSvisa 	tp->t_param = cduartparam;
394*282e735eSvisa 	tp->t_dev = dev;
395*282e735eSvisa 	if ((tp->t_state & TS_ISOPEN) == 0) {
396*282e735eSvisa 		tp->t_state |= TS_WOPEN | TS_CARR_ON;
397*282e735eSvisa 		ttychars(tp);
398*282e735eSvisa 		tp->t_iflag = TTYDEF_IFLAG;
399*282e735eSvisa 		tp->t_oflag = TTYDEF_OFLAG;
400*282e735eSvisa 		tp->t_cflag = TTYDEF_CFLAG;
401*282e735eSvisa 		tp->t_lflag = TTYDEF_LFLAG;
402*282e735eSvisa 		tp->t_ispeed = B115200; /* XXX */
403*282e735eSvisa 		tp->t_ospeed = tp->t_ispeed;
404*282e735eSvisa 		ttsetwater(tp);
405*282e735eSvisa 
406*282e735eSvisa 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
407*282e735eSvisa 		sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
408*282e735eSvisa 
409*282e735eSvisa 		cduart_write(sc, CDUART_RXTOUT, 10);
410*282e735eSvisa 		cduart_write(sc, CDUART_RXWM, CDUART_FIFOSIZE / 2);
411*282e735eSvisa 
412*282e735eSvisa 		/* Clear any pending I/O. */
413*282e735eSvisa 		for (;;) {
414*282e735eSvisa 			sr = cduart_read(sc, CDUART_SR);
415*282e735eSvisa 			if (sr & CDUART_SR_RXEMPTY)
416*282e735eSvisa 				break;
417*282e735eSvisa 			(void)cduart_read(sc, CDUART_FIFO);
418*282e735eSvisa 		}
419*282e735eSvisa 
420*282e735eSvisa 		cduart_write(sc, CDUART_IER,
421*282e735eSvisa 		    CDUART_IXR_TOUT | CDUART_IXR_RXOVR | CDUART_IXR_RTRIG);
422*282e735eSvisa 	} else if ((tp->t_state & TS_XCLUDE) && suser(p) != 0) {
423*282e735eSvisa 		splx(s);
424*282e735eSvisa 		return EBUSY;
425*282e735eSvisa 	}
426*282e735eSvisa 
427*282e735eSvisa 	if (DEVCUA(dev)) {
428*282e735eSvisa 		if (tp->t_state & TS_ISOPEN) {
429*282e735eSvisa 			splx(s);
430*282e735eSvisa 			return EBUSY;
431*282e735eSvisa 		}
432*282e735eSvisa 		sc->sc_cua = 1;
433*282e735eSvisa 	} else {
434*282e735eSvisa 		if ((flag & O_NONBLOCK) && sc->sc_cua) {
435*282e735eSvisa 			splx(s);
436*282e735eSvisa 			return EBUSY;
437*282e735eSvisa 		} else {
438*282e735eSvisa 			while (sc->sc_cua) {
439*282e735eSvisa 				tp->t_state |= TS_WOPEN;
440*282e735eSvisa 				error = ttysleep(tp, &tp->t_rawq,
441*282e735eSvisa 				    TTIPRI | PCATCH, ttopen);
442*282e735eSvisa 				if (error != 0 && (tp->t_state & TS_WOPEN)) {
443*282e735eSvisa 					tp->t_state &= ~TS_WOPEN;
444*282e735eSvisa 					splx(s);
445*282e735eSvisa 					return error;
446*282e735eSvisa 				}
447*282e735eSvisa 			}
448*282e735eSvisa 		}
449*282e735eSvisa 	}
450*282e735eSvisa 
451*282e735eSvisa 	splx(s);
452*282e735eSvisa 
453*282e735eSvisa 	return (*linesw[tp->t_line].l_open)(dev, tp, p);
454*282e735eSvisa }
455*282e735eSvisa 
456*282e735eSvisa int
cduartclose(dev_t dev,int flag,int mode,struct proc * p)457*282e735eSvisa cduartclose(dev_t dev, int flag, int mode, struct proc *p)
458*282e735eSvisa {
459*282e735eSvisa 	struct cduart_softc *sc;
460*282e735eSvisa 	struct tty *tp;
461*282e735eSvisa 	int s;
462*282e735eSvisa 
463*282e735eSvisa 	sc = cduart_sc(dev);
464*282e735eSvisa 	tp = sc->sc_tty;
465*282e735eSvisa 
466*282e735eSvisa 	if ((tp->t_state & TS_ISOPEN) == 0)
467*282e735eSvisa 		return 0;
468*282e735eSvisa 
469*282e735eSvisa 	(*linesw[tp->t_line].l_close)(tp, flag, p);
470*282e735eSvisa 	s = spltty();
471*282e735eSvisa 	/* Disable interrupts. */
472*282e735eSvisa 	cduart_write(sc, CDUART_IDR, ~0U);
473*282e735eSvisa 	sc->sc_cua = 0;
474*282e735eSvisa 	splx(s);
475*282e735eSvisa 	ttyclose(tp);
476*282e735eSvisa 
477*282e735eSvisa 	return 0;
478*282e735eSvisa }
479*282e735eSvisa 
480*282e735eSvisa int
cduartread(dev_t dev,struct uio * uio,int flag)481*282e735eSvisa cduartread(dev_t dev, struct uio *uio, int flag)
482*282e735eSvisa {
483*282e735eSvisa 	struct tty *tp;
484*282e735eSvisa 
485*282e735eSvisa 	tp = cduarttty(dev);
486*282e735eSvisa 	if (tp == NULL)
487*282e735eSvisa 		return ENODEV;
488*282e735eSvisa 
489*282e735eSvisa 	return (*linesw[tp->t_line].l_read)(tp, uio, flag);
490*282e735eSvisa }
491*282e735eSvisa 
492*282e735eSvisa int
cduartwrite(dev_t dev,struct uio * uio,int flag)493*282e735eSvisa cduartwrite(dev_t dev, struct uio *uio, int flag)
494*282e735eSvisa {
495*282e735eSvisa 	struct tty *tp;
496*282e735eSvisa 
497*282e735eSvisa 	tp = cduarttty(dev);
498*282e735eSvisa 	if (tp == NULL)
499*282e735eSvisa 		return ENODEV;
500*282e735eSvisa 
501*282e735eSvisa 	return (*linesw[tp->t_line].l_write)(tp, uio, flag);
502*282e735eSvisa }
503*282e735eSvisa 
504*282e735eSvisa int
cduartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)505*282e735eSvisa cduartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
506*282e735eSvisa {
507*282e735eSvisa 	struct cduart_softc *sc;
508*282e735eSvisa 	struct tty *tp;
509*282e735eSvisa 	int error;
510*282e735eSvisa 
511*282e735eSvisa 	sc = cduart_sc(dev);
512*282e735eSvisa 	if (sc == NULL)
513*282e735eSvisa 		return ENODEV;
514*282e735eSvisa 
515*282e735eSvisa 	tp = sc->sc_tty;
516*282e735eSvisa 	if (tp == NULL)
517*282e735eSvisa 		return ENXIO;
518*282e735eSvisa 
519*282e735eSvisa 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
520*282e735eSvisa 	if (error >= 0)
521*282e735eSvisa 		return error;
522*282e735eSvisa 
523*282e735eSvisa 	error = ttioctl(tp, cmd, data, flag, p);
524*282e735eSvisa 	if (error >= 0)
525*282e735eSvisa 		return error;
526*282e735eSvisa 
527*282e735eSvisa 	/* XXX */
528*282e735eSvisa 	switch (cmd) {
529*282e735eSvisa 	case TIOCSBRK:
530*282e735eSvisa 	case TIOCCBRK:
531*282e735eSvisa 	case TIOCSDTR:
532*282e735eSvisa 	case TIOCCDTR:
533*282e735eSvisa 	case TIOCMSET:
534*282e735eSvisa 	case TIOCMBIC:
535*282e735eSvisa 	case TIOCMGET:
536*282e735eSvisa 	case TIOCGFLAGS:
537*282e735eSvisa 		break;
538*282e735eSvisa 	case TIOCSFLAGS:
539*282e735eSvisa 		error = suser(p);
540*282e735eSvisa 		if (error != 0)
541*282e735eSvisa 			return EPERM;
542*282e735eSvisa 		break;
543*282e735eSvisa 	default:
544*282e735eSvisa 		return ENOTTY;
545*282e735eSvisa 	}
546*282e735eSvisa 
547*282e735eSvisa 	return 0;
548*282e735eSvisa }
549*282e735eSvisa 
550*282e735eSvisa int
cduartparam(struct tty * tp,struct termios * t)551*282e735eSvisa cduartparam(struct tty *tp, struct termios *t)
552*282e735eSvisa {
553*282e735eSvisa 	return 0;
554*282e735eSvisa }
555*282e735eSvisa 
556*282e735eSvisa void
cduartstart(struct tty * tp)557*282e735eSvisa cduartstart(struct tty *tp)
558*282e735eSvisa {
559*282e735eSvisa 	struct cduart_softc *sc;
560*282e735eSvisa 	uint32_t sr;
561*282e735eSvisa 	int s;
562*282e735eSvisa 
563*282e735eSvisa 	sc = cduart_sc(tp->t_dev);
564*282e735eSvisa 
565*282e735eSvisa 	s = spltty();
566*282e735eSvisa 	if (tp->t_state & TS_BUSY)
567*282e735eSvisa 		goto out;
568*282e735eSvisa 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
569*282e735eSvisa 		goto stopped;
570*282e735eSvisa 	ttwakeupwr(tp);
571*282e735eSvisa 	if (tp->t_outq.c_cc == 0)
572*282e735eSvisa 		goto stopped;
573*282e735eSvisa 	tp->t_state |= TS_BUSY;
574*282e735eSvisa 
575*282e735eSvisa 	cduart_write(sc, CDUART_ISR, CDUART_IXR_TXEMPTY);
576*282e735eSvisa 
577*282e735eSvisa 	sr = cduart_read(sc, CDUART_SR);
578*282e735eSvisa 	while ((sr & CDUART_SR_TXFULL) == 0 && tp->t_outq.c_cc != 0) {
579*282e735eSvisa 		cduart_write(sc, CDUART_FIFO, getc(&tp->t_outq));
580*282e735eSvisa 		sr = cduart_read(sc, CDUART_SR);
581*282e735eSvisa 	}
582*282e735eSvisa 
583*282e735eSvisa 	cduart_write(sc, CDUART_IER, CDUART_IXR_TXEMPTY);
584*282e735eSvisa out:
585*282e735eSvisa 	splx(s);
586*282e735eSvisa 	return;
587*282e735eSvisa stopped:
588*282e735eSvisa 	cduart_write(sc, CDUART_IDR, CDUART_IXR_TXEMPTY);
589*282e735eSvisa 	splx(s);
590*282e735eSvisa }
591*282e735eSvisa 
592*282e735eSvisa int
cduartstop(struct tty * tp,int flag)593*282e735eSvisa cduartstop(struct tty *tp, int flag)
594*282e735eSvisa {
595*282e735eSvisa 	return 0;
596*282e735eSvisa }
597*282e735eSvisa 
598*282e735eSvisa struct tty *
cduarttty(dev_t dev)599*282e735eSvisa cduarttty(dev_t dev)
600*282e735eSvisa {
601*282e735eSvisa 	struct cduart_softc *sc;
602*282e735eSvisa 
603*282e735eSvisa 	sc = cduart_sc(dev);
604*282e735eSvisa 	if (sc == NULL)
605*282e735eSvisa 		return NULL;
606*282e735eSvisa 
607*282e735eSvisa 	return sc->sc_tty;
608*282e735eSvisa }
609*282e735eSvisa 
610*282e735eSvisa struct cduart_softc *
cduart_sc(dev_t dev)611*282e735eSvisa cduart_sc(dev_t dev)
612*282e735eSvisa {
613*282e735eSvisa 	int unit = DEVUNIT(dev);
614*282e735eSvisa 
615*282e735eSvisa 	if (unit >= cduart_cd.cd_ndevs)
616*282e735eSvisa 		return NULL;
617*282e735eSvisa 	return (struct cduart_softc *)cduart_cd.cd_devs[unit];
618*282e735eSvisa }
619*282e735eSvisa 
620*282e735eSvisa struct consdev cduartcons = {
621*282e735eSvisa 	.cn_probe	= NULL,
622*282e735eSvisa 	.cn_init	= NULL,
623*282e735eSvisa 	.cn_getc	= cduartcngetc,
624*282e735eSvisa 	.cn_putc	= cduartcnputc,
625*282e735eSvisa 	.cn_pollc	= cduartcnpollc,
626*282e735eSvisa 	.cn_bell	= NULL,
627*282e735eSvisa 	.cn_dev		= NODEV,
628*282e735eSvisa 	.cn_pri		= CN_MIDPRI,
629*282e735eSvisa };
630*282e735eSvisa 
631*282e735eSvisa int
cduartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)632*282e735eSvisa cduartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
633*282e735eSvisa     tcflag_t cflag)
634*282e735eSvisa {
635*282e735eSvisa 	bus_space_handle_t ioh;
636*282e735eSvisa 	int maj;
637*282e735eSvisa 
638*282e735eSvisa 	/* Look for major of com(4) to replace. */
639*282e735eSvisa 	for (maj = 0; maj < nchrdev; maj++) {
640*282e735eSvisa 		if (cdevsw[maj].d_open == comopen)
641*282e735eSvisa 			break;
642*282e735eSvisa 	}
643*282e735eSvisa 	if (maj == nchrdev)
644*282e735eSvisa 		return ENXIO;
645*282e735eSvisa 
646*282e735eSvisa 	if (bus_space_map(iot, iobase, CDUART_SPACE_SIZE, 0, &ioh) != 0)
647*282e735eSvisa 		return ENOMEM;
648*282e735eSvisa 
649*282e735eSvisa 	cn_tab = &cduartcons;
650*282e735eSvisa 	cn_tab->cn_dev = makedev(maj, 0);
651*282e735eSvisa 	cdevsw[maj] = cduartdev;
652*282e735eSvisa 
653*282e735eSvisa 	cduartconsiot = iot;
654*282e735eSvisa 	cduartconsioh = ioh;
655*282e735eSvisa 	cduartconsrate = rate;
656*282e735eSvisa 	cduartconscflag = cflag;
657*282e735eSvisa 
658*282e735eSvisa 	return 0;
659*282e735eSvisa }
660*282e735eSvisa 
661*282e735eSvisa void
cduartcnprobe(struct consdev * cp)662*282e735eSvisa cduartcnprobe(struct consdev *cp)
663*282e735eSvisa {
664*282e735eSvisa }
665*282e735eSvisa 
666*282e735eSvisa void
cduartcninit(struct consdev * cp)667*282e735eSvisa cduartcninit(struct consdev *cp)
668*282e735eSvisa {
669*282e735eSvisa }
670*282e735eSvisa 
671*282e735eSvisa int
cduartcngetc(dev_t dev)672*282e735eSvisa cduartcngetc(dev_t dev)
673*282e735eSvisa {
674*282e735eSvisa 	int s;
675*282e735eSvisa 	uint8_t c;
676*282e735eSvisa 
677*282e735eSvisa 	s = splhigh();
678*282e735eSvisa 	while (bus_space_read_4(cduartconsiot, cduartconsioh,
679*282e735eSvisa 	    CDUART_SR) & CDUART_SR_RXEMPTY)
680*282e735eSvisa 		CPU_BUSY_CYCLE();
681*282e735eSvisa 	c = bus_space_read_4(cduartconsiot, cduartconsioh, CDUART_FIFO);
682*282e735eSvisa 	splx(s);
683*282e735eSvisa 
684*282e735eSvisa 	return c;
685*282e735eSvisa }
686*282e735eSvisa 
687*282e735eSvisa void
cduartcnputc(dev_t dev,int c)688*282e735eSvisa cduartcnputc(dev_t dev, int c)
689*282e735eSvisa {
690*282e735eSvisa 	int s;
691*282e735eSvisa 
692*282e735eSvisa 	s = splhigh();
693*282e735eSvisa 	while (bus_space_read_4(cduartconsiot, cduartconsioh,
694*282e735eSvisa 	    CDUART_SR) & CDUART_SR_TXFULL)
695*282e735eSvisa 		CPU_BUSY_CYCLE();
696*282e735eSvisa 	bus_space_write_4(cduartconsiot, cduartconsioh, CDUART_FIFO, c);
697*282e735eSvisa 	splx(s);
698*282e735eSvisa }
699*282e735eSvisa 
700*282e735eSvisa void
cduartcnpollc(dev_t dev,int on)701*282e735eSvisa cduartcnpollc(dev_t dev, int on)
702*282e735eSvisa {
703*282e735eSvisa }
704