audioamd.c revision 1.1 1 /* $NetBSD: audioamd.c,v 1.1 2000/05/02 06:35:14 augustss Exp $ */
2 /* NetBSD: am7930_sparc.c,v 1.44 1999/03/14 22:29:00 jonathan Exp */
3
4 /*
5 * Copyright (c) 1995 Rolf Grossmann
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Rolf Grossmann.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "audio.h"
35 #if NAUDIO > 0
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/errno.h>
40 #include <sys/device.h>
41
42 #include <machine/bus.h>
43 #include <machine/autoconf.h>
44 #include <machine/cpu.h>
45
46 #include <sys/audioio.h>
47 #include <dev/audio_if.h>
48
49 #include <dev/ic/am7930reg.h>
50 #include <dev/ic/am7930var.h>
51
52 #define AUDIO_ROM_NAME "audio"
53
54 #ifdef AUDIO_DEBUG
55 #define DPRINTF(x) if (am7930debug) printf x
56 #define DPRINTFN(n,x) if (am7930debug>(n)) printf x
57 #else
58 #define DPRINTF(x)
59 #define DPRINTFN(n,x)
60 #endif /* AUDIO_DEBUG */
61
62
63 /* interrupt interfaces */
64 #ifdef AUDIO_C_HANDLER
65 int am7930hwintr __P((void *));
66 #if defined(SUN4M)
67 #define AUDIO_SET_SWINTR do { \
68 if (CPU_ISSUN4M) \
69 raise(0, 4); \
70 else \
71 ienab_bis(IE_L4); \
72 } while(0);
73 #else
74 #define AUDIO_SET_SWINTR ienab_bis(IE_L4)
75 #endif /* defined(SUN4M) */
76 #else
77 struct auio *auiop;
78 #endif /* AUDIO_C_HANDLER */
79 int am7930swintr __P((void *));
80
81 /*
82 * pdma state
83 */
84 struct auio {
85 bus_space_tag_t au_bt; /* bus tag */
86 bus_space_handle_t au_bh; /* handle to chip registers */
87
88 u_int8_t *au_rdata; /* record data */
89 u_int8_t *au_rend; /* end of record data */
90 u_int8_t *au_pdata; /* play data */
91 u_int8_t *au_pend; /* end of play data */
92 struct evcnt au_intrcnt; /* statistics */
93 };
94
95 /*
96 * interrupt-handler status
97 */
98 struct am7930_intrhand {
99 int (*ih_fun) __P((void *));
100 void *ih_arg;
101 };
102
103 struct audioamd_softc {
104 struct am7930_softc sc_am7930; /* glue to MI code */
105
106 bus_space_tag_t sc_bt; /* bus cookie */
107 bus_space_handle_t sc_bh; /* device registers */
108
109 struct am7930_intrhand sc_ih; /* interrupt vector (hw or sw) */
110 void (*sc_rintr)(void*); /* input completion intr handler */
111 void *sc_rarg; /* arg for sc_rintr() */
112 void (*sc_pintr)(void*); /* output completion intr handler */
113 void *sc_parg; /* arg for sc_pintr() */
114
115 /* sc_au is special in that the hardware interrupt handler uses it */
116 struct auio sc_au; /* recv and xmit buffers, etc */
117 #define sc_intrcnt sc_au.au_intrcnt /* statistics */
118 };
119
120 void audioamd_mainbus_attach __P((struct device *,
121 struct device *, void *));
122 int audioamd_mainbus_match __P((struct device *, struct cfdata *, void *));
123 void audioamd_sbus_attach __P((struct device *, struct device *, void *));
124 int audioamd_sbus_match __P((struct device *, struct cfdata *, void *));
125 void audioamd_attach(struct audioamd_softc *sc, int);
126
127 struct cfattach audioamd_mainbus_ca = {
128 sizeof(struct audioamd_softc),
129 audioamd_mainbus_match,
130 audioamd_mainbus_attach
131 };
132
133 struct cfattach audioamd_sbus_ca = {
134 sizeof(struct audioamd_softc),
135 audioamd_sbus_match,
136 audioamd_sbus_attach
137 };
138
139 /*
140 * Define our interface into the am7930 MI driver.
141 */
142
143 u_int8_t audioamd_codec_iread __P((struct am7930_softc *, int));
144 u_int16_t audioamd_codec_iread16 __P((struct am7930_softc *, int));
145 void audioamd_codec_iwrite __P((struct am7930_softc *, int, u_int8_t));
146 void audioamd_codec_iwrite16 __P((struct am7930_softc *, int, u_int16_t));
147 void audioamd_onopen __P((struct am7930_softc *sc));
148 void audioamd_onclose __P((struct am7930_softc *sc));
149
150 struct am7930_glue audioamd_glue = {
151 audioamd_codec_iread,
152 audioamd_codec_iwrite,
153 audioamd_codec_iread16,
154 audioamd_codec_iwrite16,
155 audioamd_onopen,
156 audioamd_onclose,
157 0,
158 0,
159 0,
160 };
161
162 /*
163 * Define our interface to the higher level audio driver.
164 */
165 int audioamd_start_output __P((void *, void *, int, void (*)(void *),
166 void *));
167 int audioamd_start_input __P((void *, void *, int, void (*)(void *),
168 void *));
169
170 struct audio_hw_if sa_hw_if = {
171 am7930_open,
172 am7930_close,
173 0,
174 am7930_query_encoding,
175 am7930_set_params,
176 am7930_round_blocksize,
177 am7930_commit_settings,
178 0,
179 0,
180 audioamd_start_output, /* md */
181 audioamd_start_input, /* md */
182 am7930_halt_output,
183 am7930_halt_input,
184 0,
185 audioamd_getdev,
186 0,
187 am7930_set_port,
188 am7930_get_port,
189 am7930_query_devinfo,
190 0,
191 0,
192 0,
193 0,
194 am7930_get_props,
195 };
196
197 struct audio_device audioamd_device = {
198 "am7930",
199 "x",
200 "audioamd"
201 };
202
203
204 int
205 audioamd_mainbus_match(parent, cf, aux)
206 struct device *parent;
207 struct cfdata *cf;
208 void *aux;
209 {
210 struct mainbus_attach_args *ma = aux;
211
212 if (CPU_ISSUN4)
213 return (0);
214 return (strcmp(AUDIO_ROM_NAME, ma->ma_name) == 0);
215 }
216
217 int
218 audioamd_sbus_match(parent, cf, aux)
219 struct device *parent;
220 struct cfdata *cf;
221 void *aux;
222 {
223 struct sbus_attach_args *sa = aux;
224
225 return (strcmp(AUDIO_ROM_NAME, sa->sa_name) == 0);
226 }
227
228 void
229 audioamd_mainbus_attach(parent, self, aux)
230 struct device *parent, *self;
231 void *aux;
232 {
233 struct mainbus_attach_args *ma = aux;
234 struct audioamd_softc *sc = (struct audioamd_softc *)self;
235 bus_space_handle_t bh;
236
237 sc->sc_bt = ma->ma_bustag;
238
239 if (bus_space_map2(
240 ma->ma_bustag,
241 ma->ma_iospace,
242 ma->ma_paddr,
243 sizeof(struct am7930),
244 BUS_SPACE_MAP_LINEAR,
245 0,
246 &bh) != 0) {
247 printf("%s: cannot map registers\n", self->dv_xname);
248 return;
249 }
250 sc->sc_bh = bh;
251 audioamd_attach(sc, ma->ma_pri);
252 }
253
254
255 void
256 audioamd_sbus_attach(parent, self, aux)
257 struct device *parent, *self;
258 void *aux;
259 {
260 struct sbus_attach_args *sa = aux;
261 struct audioamd_softc *sc = (struct audioamd_softc *)self;
262 bus_space_handle_t bh;
263
264 sc->sc_bt = sa->sa_bustag;
265
266 if (sbus_bus_map(
267 sa->sa_bustag,
268 sa->sa_slot,
269 sa->sa_offset,
270 sizeof(struct am7930),
271 0, 0,
272 &bh) != 0) {
273 printf("%s: cannot map registers\n", self->dv_xname);
274 return;
275 }
276 sc->sc_bh = bh;
277 audioamd_attach(sc, sa->sa_pri);
278 }
279
280 void
281 audioamd_attach(sc, pri)
282 struct audioamd_softc *sc;
283 int pri;
284 {
285
286 printf(" softpri %d\n", PIL_AUSOFT);
287
288 /*
289 * Set up glue for MI code early; we use some of it here.
290 */
291 sc->sc_glue = &audioamd_glue;
292
293 am7930_init(sc, AUDIOAMD_POLL_MODE);
294
295 #ifndef AUDIO_C_HANDLER
296 auiop = &sc->sc_au;
297 (void)bus_intr_establish(sc->sc_bt, pri,
298 BUS_INTR_ESTABLISH_FASTTRAP,
299 (int (*) __P((void *)))amd7930_trap, NULL);
300 #else
301 (void)bus_intr_establish(sc->sc_bt, pri, 0,
302 am7930hwintr, &sc->sc_au);
303 #endif
304 (void)bus_intr_establish(sc->sc_bt, PIL_AUSOFT,
305 BUS_INTR_ESTABLISH_SOFTINTR,
306 am7930swintr, sc);
307
308 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
309
310 audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev);
311 }
312
313
314 void
315 audioamd_onopen(sc)
316 struct am7930_softc *sc;
317 {
318 struct audioamd_softc *mdsc = (struct audioamd *)sc;
319
320 /* reset pdma state */
321 mdsc->sc_rintr = 0;
322 mdsc->sc_rarg = 0;
323 mdsc->sc_pintr = 0;
324 mdsc->sc_parg = 0;
325
326 mdsc->sc_au.au_rdata = 0;
327 mdsc->sc_au.au_pdata = 0;
328 }
329
330
331 void
332 audioamd_onclose(sc)
333 struct am7930_softc *sc;
334 {
335 /* On sparc, just do the chipset-level halt. */
336 am7930_halt_input(sc);
337 am7930_halt_output(sc);
338 }
339
340 int
341 audioamd_output(addr, p, cc, intr, arg)
342 void *addr;
343 void *p;
344 int cc;
345 void (*intr) __P((void *));
346 void *arg;
347 {
348 struct audioamd_softc *sc = addr;
349
350 DPRINTFN(1, ("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
351
352 if (!sc->sc_locked) {
353 audioamd_codec_iwrite(sc,
354 AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE);
355 sc->sc_locked = 1;
356 DPRINTF(("sa_start_output: started intrs.\n"));
357 }
358 sc->sc_pintr = intr;
359 sc->sc_parg = arg;
360 sc->sc_au.au_pdata = p;
361 sc->sc_au.au_pend = (char *)p + cc - 1;
362 return(0);
363 }
364
365 int
366 am7930_start_input(addr, p, cc, intr, arg)
367 void *addr;
368 void *p;
369 int cc;
370 void (*intr) __P((void *));
371 void *arg;
372 {
373 struct audioamd_softc *sc = addr;
374
375 DPRINTFN(1, ("sa_start_input: cc=%d %p (%p)\n", cc, intr, arg));
376
377 if (!sc->sc_locked) {
378 audioamd_codec_iwrite(sc,
379 AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE);
380 sc->sc_locked = 1;
381 DPRINTF(("sa_start_input: started intrs.\n"));
382 }
383 sc->sc_rintr = intr;
384 sc->sc_rarg = arg;
385 sc->sc_au.au_rdata = p;
386 sc->sc_au.au_rend = (char *)p + cc -1;
387 return(0);
388 }
389
390
391 /*
392 * Pseudo-DMA support: either C or locore assember.
393 */
394
395 #ifdef AUDIO_C_HANDLER
396 int
397 am7930hwintr(au0)
398 void *au0;
399 {
400 struct auio *au = au0;
401 u_int8_t *d, *e;
402 int k;
403
404 /* XXX where is sc? */
405
406 /* clear interrupt */
407 k = audioamd_codec_dread(sc, AM7930_DREG_IR);
408
409 /* receive incoming data */
410 d = au->au_rdata;
411 e = au->au_rend;
412 if (d && d <= e) {
413 *d = audioamd_codec_dread(sc, AM7930_DREG_BBRB);
414 au->au_rdata++;
415 if (d == e) {
416 DPRINTFN(1, ("am7930hwintr: swintr(r) requested"));
417 AUDIO_SET_SWINTR;
418 }
419 }
420
421 /* send outgoing data */
422 d = au->au_pdata;
423 e = au->au_pend;
424 if (d && d <= e) {
425 audioamd_codec_dwrite(sc, AM7930_DREG_BBTB, *d);
426 au->au_pdata++;
427 if (d == e) {
428 DPRINTFN(1, ("am7930hwintr: swintr(p) requested"));
429 AUDIO_SET_SWINTR;
430 }
431 }
432
433 *(au->au_intrcnt)++;
434 return (1);
435 }
436 #endif /* AUDIO_C_HANDLER */
437
438 int
439 am7930swintr(sc0)
440 void *sc0;
441 {
442 struct audioamd_softc *sc = sc0;
443 struct auio *au;
444 int s, ret = 0;
445
446 DPRINTFN(1, ("audiointr: sc=%p\n", sc););
447
448 au = &sc->sc_au;
449 s = splaudio();
450 if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) {
451 splx(s);
452 ret = 1;
453 (*sc->sc_rintr)(sc->sc_rarg);
454 s = splaudio();
455 }
456 if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) {
457 splx(s);
458 ret = 1;
459 (*sc->sc_pintr)(sc->sc_parg);
460 } else
461 splx(s);
462 return (ret);
463 }
464
465
466 /* indirect write */
467 void
468 audioamd_codec_iwrite(sc, reg, val)
469 struct am7930_softc *sc;
470 int reg;
471 u_int8_t val;
472 {
473 audioamd_codec_dwrite(sc, AM7930_DREG_CR, reg);
474 audioamd_codec_dwrite(sc, AM7930_DREG_DR, val);
475 }
476
477
478 void
479 audioamd_codec_iwrite16(sc, reg, val)
480 struct am7930_softc *sc;
481 int reg;
482 u_int16_t val;
483 {
484 audioamd_codec_dwrite(sc, AM7930_DREG_CR, reg);
485 audioamd_codec_dwrite(sc, AM7930_DREG_DR, val);
486 audioamd_codec_dwrite(sc, AM7930_DREG_DR, val>>8);
487 }
488
489
490 /* indirect read */
491 u_int8_t
492 audioamd_codec_iread(sc, reg)
493 struct am7930_softc *sc;
494 int reg;
495 {
496 audioamd_codec_dwrite(sc, AM7930_DREG_CR, reg);
497 return audioamd_codec_dread(sc, AM7930_DREG_DR);
498 }
499
500 /* direct write */
501 void
502 audioamd_codec_dwrite(sc, reg, val)
503 struct am7930_softc *sc;
504 int reg;
505 u_int8_t val;
506 {
507 struct audioamd_softc *mdsc = (struct audioamd_softc *)sc;
508 bus_space_write_1(mdsc->sc_bt, mdsc->sc_bh, reg, val);
509 }
510
511 /* direct read */
512 u_int8_t
513 bba_codec_dread(sc, reg)
514 struct am7930_softc *sc;
515 int reg;
516 {
517 struct audioamd_softc *mdsc = (struct audioamd_softc *)sc;
518 return bus_space_read_1(mdsc->sc_bt, mdsc->sc_bh, reg);
519 }
520
521 #endif /* NAUDIO > 0 */
522