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)®s->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