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, ®) != 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