1 /*	$OpenBSD: daadio.c,v 1.5 2003/06/02 18:40:59 jason Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * This software was developed by Jason L. Wright under contract with
8  * RTMX Incorporated (http://www.rtmx.com).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Driver for the MATRIX Corporation MD-DAADIO digital->analog,
34  * analog->digial, parallel i/o VME board.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/syslog.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 #include <sys/conf.h>
46 #include <sys/fcntl.h>
47 #include <sys/proc.h>
48 
49 #include <machine/autoconf.h>
50 #include <sparc/cpu.h>
51 #include <sparc/sparc/cpuvar.h>
52 #include <sparc/dev/sbusvar.h>
53 #include <sparc/dev/dmareg.h>	/* for SBUS_BURST_* */
54 #include <machine/daadioio.h>
55 
56 #include <sparc/dev/fgareg.h>
57 #include <sparc/dev/fgavar.h>
58 #include <sparc/dev/daadioreg.h>
59 
60 int	daadiomatch(struct device *, void *, void *);
61 void	daadioattach(struct device *, struct device *, void *);
62 int	daadiointr(void *);
63 
64 struct daadio_softc {
65 	struct		device sc_dv;		/* base device */
66 	struct		daadioregs *sc_regs;	/* registers */
67 	struct		intrhand sc_ih;		/* interrupt vectoring */
68 	struct		daadio_adc *sc_adc_p;
69 	int		sc_adc_done;
70 	int		sc_flags;		/* flags */
71 #define	DAF_LOCKED	0x1
72 #define	DAF_WANTED	0x2
73 	u_int16_t	sc_adc_val;
74 	u_int8_t	sc_ier;			/* software copy of ier */
75 };
76 
77 struct cfattach daadio_ca = {
78 	sizeof (struct daadio_softc), daadiomatch, daadioattach
79 };
80 
81 struct cfdriver daadio_cd = {
82 	NULL, "daadio", DV_DULL
83 };
84 
85 void	daadio_ier_setbit(struct daadio_softc *, u_int8_t);
86 void	daadio_ier_clearbit(struct daadio_softc *, u_int8_t);
87 int	daadio_adc(struct daadio_softc *, struct daadio_adc *);
88 
89 int	daadioopen(dev_t, int, int, struct proc *);
90 int	daadioclose(dev_t, int, int, struct proc *);
91 int	daadioioctl(dev_t, u_long, caddr_t, int, struct proc *);
92 
93 int
daadiomatch(parent,vcf,aux)94 daadiomatch(parent, vcf, aux)
95 	struct device *parent;
96 	void *vcf, *aux;
97 {
98 	struct cfdata *cf = vcf;
99 	struct confargs *ca = aux;
100 	struct daadioregs *regs;
101 
102 	if (ca->ca_bustype != BUS_FGA_A16D16)
103 		return (0);
104 
105 	if (strcmp(ca->ca_ra.ra_name, cf->cf_driver->cd_name))
106 		return (0);
107 
108 	if (ca->ca_ra.ra_reg[0].rr_len < sizeof(struct daadioboard))
109 		return (0);
110 
111 	regs = ca->ca_ra.ra_reg[0].rr_paddr;
112 	if (probeget((caddr_t)&regs->sid, 1) != -1)
113 		return (1);
114 
115 	return (0);
116 }
117 
118 void
daadioattach(parent,self,aux)119 daadioattach(parent, self, aux)
120 	struct device *parent, *self;
121 	void *aux;
122 {
123 	struct confargs *ca = aux;
124 	struct daadio_softc *sc = (struct daadio_softc *)self;
125 
126 	sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
127 	    sizeof(struct daadioboard));
128 
129 	sc->sc_regs->pio_pattern = sc->sc_regs->pio_porta;
130 	sc->sc_regs->sid = ca->ca_ra.ra_intr[0].int_vec;
131 	sc->sc_regs->gvrilr &= ~ILR_IRQ_MASK;
132 	sc->sc_regs->gvrilr |= (ca->ca_ra.ra_intr[0].int_pri << ILR_IRQ_SHIFT)
133 	    & ILR_IRQ_MASK;
134 	sc->sc_ih.ih_fun = daadiointr;
135 	sc->sc_ih.ih_arg = sc;
136 	fvmeintrestablish(parent, ca->ca_ra.ra_intr[0].int_vec,
137 	    ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih);
138 	daadio_ier_setbit(sc, IER_PIOEVENT);
139 	daadio_ier_setbit(sc, IER_CONVERSION);
140 
141 	printf(": level %d vec 0x%x\n",
142 	    ca->ca_ra.ra_intr[0].int_pri, ca->ca_ra.ra_intr[0].int_vec);
143 }
144 
145 int
daadiointr(vsc)146 daadiointr(vsc)
147 	void *vsc;
148 {
149 	struct daadio_softc *sc = vsc;
150 	struct daadioregs *regs = sc->sc_regs;
151 	u_int8_t val, isr;
152 	int r = 0;
153 
154 	isr = regs->isr;
155 
156 	if (isr & ISR_PIOEVENT) {
157 		val = regs->pio_porta;
158 		printf("pio value: %x\n", val);
159 		r = 1;
160 		regs->pio_pattern = val;
161 	}
162 
163 	if (isr & ISR_CONVERSION) {
164 		r = 1;
165 		sc->sc_adc_val = sc->sc_regs->adc12bit[0];
166 		sc->sc_adc_done = 1;
167 		if (sc->sc_adc_p != NULL)
168 			wakeup(sc->sc_adc_p);
169 	}
170 
171 	return (r);
172 }
173 
174 void
daadio_ier_setbit(sc,v)175 daadio_ier_setbit(sc, v)
176 	struct daadio_softc *sc;
177 	u_int8_t v;
178 {
179 	sc->sc_ier |= v;
180 	sc->sc_regs->ier = sc->sc_ier;
181 }
182 
183 void
daadio_ier_clearbit(sc,v)184 daadio_ier_clearbit(sc, v)
185 	struct daadio_softc *sc;
186 	u_int8_t v;
187 {
188 	sc->sc_ier &= ~v;
189 	sc->sc_regs->ier = sc->sc_ier;
190 }
191 
192 #define	DAADIO_CARD(d)	((minor(d) >> 6) & 3)
193 
194 int
daadioopen(dev,flags,mode,p)195 daadioopen(dev, flags, mode, p)
196 	dev_t dev;
197 	int flags, mode;
198 	struct proc *p;
199 {
200 	struct daadio_softc *sc;
201 	int card = DAADIO_CARD(dev);
202 
203 	if (card >= daadio_cd.cd_ndevs)
204 		return (ENXIO);
205 	sc = daadio_cd.cd_devs[card];
206 	if (sc == NULL)
207 		return (ENXIO);
208 	return (0);
209 }
210 
211 int
daadioclose(dev,flags,mode,p)212 daadioclose(dev, flags, mode, p)
213 	dev_t dev;
214 	int flags, mode;
215 	struct proc *p;
216 {
217 	return (0);
218 }
219 
220 int
daadioioctl(dev,cmd,data,flags,p)221 daadioioctl(dev, cmd, data, flags, p)
222 	dev_t dev;
223 	u_long cmd;
224 	caddr_t data;
225 	int flags;
226 	struct proc *p;
227 {
228 	struct daadio_softc *sc = daadio_cd.cd_devs[DAADIO_CARD(dev)];
229 	struct daadio_adc *adc = (struct daadio_adc *)data;
230 	struct daadio_dac *dac = (struct daadio_dac *)data;
231 	struct daadio_pio *pio = (struct daadio_pio *)data;
232 	int error = 0;
233 	u_int8_t reg, val;
234 
235 	switch (cmd) {
236 	case DIOGADC:
237 		error = daadio_adc(sc, adc);
238 		break;
239 	case DIOGPIO:
240 		switch (pio->dap_reg) {
241 		case 0:
242 			pio->dap_val = sc->sc_regs->pio_porta;
243 			break;
244 		case 1:
245 			pio->dap_val = sc->sc_regs->pio_portb;
246 			break;
247 		case 2:
248 			pio->dap_val = sc->sc_regs->pio_portc;
249 			break;
250 		case 3:
251 			pio->dap_val = sc->sc_regs->pio_portd;
252 			break;
253 		case 4:
254 			pio->dap_val = sc->sc_regs->pio_porte;
255 			break;
256 		case 5:
257 			pio->dap_val = sc->sc_regs->pio_portf;
258 			break;
259 		default:
260 			error = EINVAL;
261 			break;
262 		}
263 		break;
264 	case DIOSPIO:
265 		if ((flags & FWRITE) == 0) {
266 			error = EPERM;
267 			break;
268 		}
269 		switch (pio->dap_reg) {
270 		case 0:
271 			sc->sc_regs->pio_porta = pio->dap_val;
272 			break;
273 		case 1:
274 			sc->sc_regs->pio_portb = pio->dap_val;
275 			break;
276 		case 2:
277 			sc->sc_regs->pio_portc = pio->dap_val;
278 			break;
279 		case 3:
280 			sc->sc_regs->pio_portd = pio->dap_val;
281 			break;
282 		case 4:
283 			sc->sc_regs->pio_porte = pio->dap_val;
284 			break;
285 		case 5:
286 			sc->sc_regs->pio_portf = pio->dap_val;
287 			break;
288 		default:
289 			error = EINVAL;
290 			break;
291 		}
292 		break;
293 	case DIOSOPIO:
294 		if ((flags & FWRITE) == 0) {
295 			error = EPERM;
296 			break;
297 		}
298 		if (pio->dap_reg >= 6) {
299 			error = EINVAL;
300 			break;
301 		}
302 
303 		reg = sc->sc_regs->pio_oc;
304 		val = (1 << pio->dap_reg);
305 
306 		if (pio->dap_val)
307 			reg |= val;
308 		else
309 			reg &= ~val;
310 
311 		sc->sc_regs->pio_oc = reg;
312 		break;
313 	case DIOGOPIO:
314 		if (pio->dap_reg >= 6) {
315 			error = EINVAL;
316 			break;
317 		}
318 
319 		reg = sc->sc_regs->pio_oc;
320 		val = (1 << pio->dap_reg);
321 
322 		if ((reg & val) != 0)
323 			pio->dap_val = 1;
324 		else
325 			pio->dap_val = 0;
326 		break;
327 	case DIOSDAC:
328 		if ((flags & FWRITE) == 0) {
329 			error = EPERM;
330 			break;
331 		}
332 		if (dac->dac_reg >= 8) {
333 			error = EINVAL;
334 			break;
335 		}
336 		sc->sc_regs->dac_channel[dac->dac_reg] = dac->dac_val;
337 		break;
338 	default:
339 		error = ENOTTY;
340 	}
341 
342 	return (error);
343 }
344 
345 int
daadio_adc(sc,adc)346 daadio_adc(sc, adc)
347 	struct daadio_softc *sc;
348 	struct daadio_adc *adc;
349 {
350 	int s, err = 0;
351 
352 	if (adc->dad_reg >= 32)
353 		return (EINVAL);
354 
355 	s = splhigh();
356 
357 	/* Lock device. */
358 	while ((sc->sc_flags & DAF_LOCKED) != 0) {
359 		sc->sc_flags |= DAF_WANTED;
360 		if ((err = tsleep(sc, PWAIT, "daadio", 0)) != 0)
361 			goto out;
362 	}
363 	sc->sc_flags |= DAF_LOCKED;
364 
365 	/* Start conversion. */
366 	sc->sc_adc_done = 0;
367 	sc->sc_adc_p = adc;
368 	sc->sc_regs->adc12bit[adc->dad_reg] = 0;
369 
370 	/* Wait for conversion. */
371 	while (sc->sc_adc_done == 0)
372 		if ((err = tsleep(sc->sc_adc_p, PWAIT, "daadio", 0)) != 0)
373 			goto out;
374 	sc->sc_adc_p = NULL;
375 	adc->dad_val = sc->sc_adc_val;
376 
377 	/* Unlock device. */
378 	sc->sc_flags &= ~DAF_LOCKED;
379 	if (sc->sc_flags & DAF_WANTED) {
380 		sc->sc_flags &= ~DAF_WANTED;
381 		wakeup(sc);
382 	}
383 
384 out:
385 	splx(s);
386 	return (err);
387 }
388