cs4231.c revision 1.6 1 /* $NetBSD: cs4231.c,v 1.6 2001/11/13 13:14:36 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: cs4231.c,v 1.6 2001/11/13 13:14:36 lukem Exp $");
41
42 #include "audio.h"
43 #if NAUDIO > 0
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/errno.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50
51 #include <machine/autoconf.h>
52 #include <machine/cpu.h>
53
54 #include <sys/audioio.h>
55 #include <dev/audio_if.h>
56
57 #include <dev/ic/ad1848reg.h>
58 #include <dev/ic/cs4231reg.h>
59 #include <dev/ic/ad1848var.h>
60 #include <dev/ic/cs4231var.h>
61 #include <dev/ic/apcdmareg.h>
62
63 /*---*/
64 #define CSAUDIO_DAC_LVL 0
65 #define CSAUDIO_LINE_IN_LVL 1
66 #define CSAUDIO_MONO_LVL 2
67 #define CSAUDIO_CD_LVL 3
68 #define CSAUDIO_MONITOR_LVL 4
69 #define CSAUDIO_OUT_LVL 5
70 #define CSAUDIO_LINE_IN_MUTE 6
71 #define CSAUDIO_DAC_MUTE 7
72 #define CSAUDIO_CD_MUTE 8
73 #define CSAUDIO_MONO_MUTE 9
74 #define CSAUDIO_MONITOR_MUTE 10
75 #define CSAUDIO_REC_LVL 11
76 #define CSAUDIO_RECORD_SOURCE 12
77
78 #define CSAUDIO_INPUT_CLASS 13
79 #define CSAUDIO_OUTPUT_CLASS 14
80 #define CSAUDIO_RECORD_CLASS 15
81 #define CSAUDIO_MONITOR_CLASS 16
82
83 #ifdef AUDIO_DEBUG
84 int cs4231debug = 0;
85 #define DPRINTF(x) if (cs4231debug) printf x
86 #else
87 #define DPRINTF(x)
88 #endif
89
90 struct audio_device cs4231_device = {
91 "cs4231",
92 "x",
93 "audio"
94 };
95
96
97 /*
98 * Define our interface to the higher level audio driver.
99 */
100 int cs4231_open __P((void *, int));
101 void cs4231_close __P((void *));
102 size_t cs4231_round_buffersize __P((void *, int, size_t));
103 int cs4231_round_blocksize __P((void *, int));
104 int cs4231_halt_output __P((void *));
105 int cs4231_halt_input __P((void *));
106 int cs4231_getdev __P((void *, struct audio_device *));
107 int cs4231_set_port __P((void *, mixer_ctrl_t *));
108 int cs4231_get_port __P((void *, mixer_ctrl_t *));
109 int cs4231_query_devinfo __P((void *, mixer_devinfo_t *));
110 int cs4231_get_props __P((void *));
111
112 void *cs4231_malloc __P((void *, int, size_t, int, int));
113 void cs4231_free __P((void *, void *, int));
114 int cs4231_trigger_output __P((void *, void *, void *, int,
115 void (*)(void *), void *,
116 struct audio_params *));
117 int cs4231_trigger_input __P((void *, void *, void *, int,
118 void (*)(void *), void *,
119 struct audio_params *));
120
121 #ifdef AUDIO_DEBUG
122 static void cs4231_regdump __P((char *, struct cs4231_softc *));
123 #endif
124
125 int
126 cs4231_read(sc, index)
127 struct ad1848_softc *sc;
128 int index;
129 {
130 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, (index << 2));
131 }
132
133 void
134 cs4231_write(sc, index, value)
135 struct ad1848_softc *sc;
136 int index, value;
137 {
138 bus_space_write_1(sc->sc_iot, sc->sc_ioh, (index << 2), value);
139 }
140
141 struct audio_hw_if audiocs_hw_if = {
142 cs4231_open,
143 cs4231_close,
144 0,
145 ad1848_query_encoding,
146 ad1848_set_params,
147 cs4231_round_blocksize,
148 ad1848_commit_settings,
149 0,
150 0,
151 NULL,
152 NULL,
153 cs4231_halt_output,
154 cs4231_halt_input,
155 0,
156 cs4231_getdev,
157 0,
158 cs4231_set_port,
159 cs4231_get_port,
160 cs4231_query_devinfo,
161 cs4231_malloc,
162 cs4231_free,
163 cs4231_round_buffersize,
164 0,
165 cs4231_get_props,
166 cs4231_trigger_output,
167 cs4231_trigger_input,
168 NULL,
169 };
170
171
172 #ifdef AUDIO_DEBUG
173 static void
174 cs4231_regdump(label, sc)
175 char *label;
176 struct cs4231_softc *sc;
177 {
178 char bits[128];
179 volatile struct apc_dma *dma = sc->sc_dmareg;
180
181 printf("cs4231regdump(%s): regs:", label);
182 printf("dmapva: 0x%x; ", dma->dmapva);
183 printf("dmapc: 0x%x; ", dma->dmapc);
184 printf("dmapnva: 0x%x; ", dma->dmapnva);
185 printf("dmapnc: 0x%x\n", dma->dmapnc);
186 printf("dmacva: 0x%x; ", dma->dmacva);
187 printf("dmacc: 0x%x; ", dma->dmacc);
188 printf("dmacnva: 0x%x; ", dma->dmacnva);
189 printf("dmacnc: 0x%x\n", dma->dmacnc);
190
191 printf("apc_dmacsr=%s\n",
192 bitmask_snprintf(dma->dmacsr, APC_BITS, bits, sizeof(bits)) );
193
194 ad1848_dump_regs(&sc->sc_ad1848);
195 }
196 #endif
197
198 void
199 cs4231_init(sc)
200 struct cs4231_softc *sc;
201 {
202 char *buf;
203 #if 0
204 volatile struct apc_dma *dma = sc->sc_dmareg;
205 #endif
206 int reg;
207
208 #if 0
209 dma->dmacsr = APC_CODEC_PDN;
210 delay(20);
211 dma->dmacsr &= ~APC_CODEC_PDN;
212 #endif
213 /* First, put chip in native mode */
214 reg = ad_read(&sc->sc_ad1848, SP_MISC_INFO);
215 ad_write(&sc->sc_ad1848, SP_MISC_INFO, reg | MODE2);
216
217 /* Read version numbers from I25 */
218 reg = ad_read(&sc->sc_ad1848, CS_VERSION_ID);
219 switch (reg & (CS_VERSION_NUMBER | CS_VERSION_CHIPID)) {
220 case 0xa0:
221 sc->sc_ad1848.chip_name = "CS4231A";
222 break;
223 case 0x80:
224 sc->sc_ad1848.chip_name = "CS4231";
225 break;
226 case 0x82:
227 sc->sc_ad1848.chip_name = "CS4232";
228 break;
229 default:
230 if ((buf = malloc(32, M_TEMP, M_NOWAIT)) != NULL) {
231 sprintf(buf, "unknown rev: %x/%x", reg&0xe, reg&7);
232 sc->sc_ad1848.chip_name = buf;
233 }
234 }
235 }
236
237 void *
238 cs4231_malloc(addr, direction, size, pool, flags)
239 void *addr;
240 int direction;
241 size_t size;
242 int pool, flags;
243 {
244 struct cs4231_softc *sc = addr;
245 bus_dma_tag_t dmatag = sc->sc_dmatag;
246 struct cs_dma *p;
247
248 p = malloc(sizeof(*p), pool, flags);
249 if (p == NULL)
250 return (NULL);
251
252 /* Allocate a DMA map */
253 if (bus_dmamap_create(dmatag, size, 1, size, 0,
254 BUS_DMA_NOWAIT, &p->dmamap) != 0)
255 goto fail1;
256
257 /* Allocate DMA memory */
258 p->size = size;
259 if (bus_dmamem_alloc(dmatag, size, 64*1024, 0,
260 p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
261 &p->nsegs, BUS_DMA_NOWAIT) != 0)
262 goto fail2;
263
264 /* Map DMA memory into kernel space */
265 if (bus_dmamem_map(dmatag, p->segs, p->nsegs, p->size,
266 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0)
267 goto fail3;
268
269 /* Load the buffer */
270 if (bus_dmamap_load(dmatag, p->dmamap,
271 p->addr, size, NULL, BUS_DMA_NOWAIT) != 0)
272 goto fail4;
273
274 p->next = sc->sc_dmas;
275 sc->sc_dmas = p;
276 return (p->addr);
277
278 fail4:
279 bus_dmamem_unmap(dmatag, p->addr, p->size);
280 fail3:
281 bus_dmamem_free(dmatag, p->segs, p->nsegs);
282 fail2:
283 bus_dmamap_destroy(dmatag, p->dmamap);
284 fail1:
285 free(p, pool);
286 return (NULL);
287 }
288
289 void
290 cs4231_free(addr, ptr, pool)
291 void *addr;
292 void *ptr;
293 int pool;
294 {
295 struct cs4231_softc *sc = addr;
296 bus_dma_tag_t dmatag = sc->sc_dmatag;
297 struct cs_dma *p, **pp;
298
299 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
300 if (p->addr != ptr)
301 continue;
302 bus_dmamap_unload(dmatag, p->dmamap);
303 bus_dmamem_unmap(dmatag, p->addr, p->size);
304 bus_dmamem_free(dmatag, p->segs, p->nsegs);
305 bus_dmamap_destroy(dmatag, p->dmamap);
306 *pp = p->next;
307 free(p, pool);
308 return;
309 }
310 printf("cs4231_free: rogue pointer\n");
311 }
312
313 int
314 cs4231_open(addr, flags)
315 void *addr;
316 int flags;
317 {
318 struct cs4231_softc *sc = addr;
319 #if 0
320 struct apc_dma *dma = sc->sc_dmareg;
321 #endif
322
323 DPRINTF(("sa_open: unit %p\n", sc));
324
325 if (sc->sc_open)
326 return (EBUSY);
327 sc->sc_open = 1;
328 sc->sc_locked = 0;
329 sc->sc_rintr = 0;
330 sc->sc_rarg = 0;
331 sc->sc_pintr = 0;
332 sc->sc_parg = 0;
333 #if 1
334 /*No interrupts from ad1848 */
335 ad_write(&sc->sc_ad1848, SP_PIN_CONTROL, 0);
336 #endif
337 #if 0
338 dma->dmacsr = APC_RESET;
339 delay(10);
340 dma->dmacsr = 0;
341 delay(10);
342 #endif
343 ad1848_reset(&sc->sc_ad1848);
344
345 DPRINTF(("saopen: ok -> sc=%p\n", sc));
346 return (0);
347 }
348
349 void
350 cs4231_close(addr)
351 void *addr;
352 {
353 struct cs4231_softc *sc = addr;
354
355 DPRINTF(("sa_close: sc=%p\n", sc));
356 /*
357 * halt i/o, clear open flag, and done.
358 */
359 cs4231_halt_input(sc);
360 cs4231_halt_output(sc);
361 sc->sc_open = 0;
362
363 DPRINTF(("sa_close: closed.\n"));
364 }
365
366 size_t
367 cs4231_round_buffersize(addr, direction, size)
368 void *addr;
369 int direction;
370 size_t size;
371 {
372 #if 0
373 if (size > APC_MAX)
374 size = APC_MAX;
375 #endif
376 return (size);
377 }
378
379 int
380 cs4231_round_blocksize(addr, blk)
381 void *addr;
382 int blk;
383 {
384 return (blk & -4);
385 }
386
387 int
388 cs4231_getdev(addr, retp)
389 void *addr;
390 struct audio_device *retp;
391 {
392 *retp = cs4231_device;
393 return (0);
394 }
395
396 static ad1848_devmap_t csmapping[] = {
397 { CSAUDIO_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
398 { CSAUDIO_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
399 { CSAUDIO_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
400 { CSAUDIO_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
401 { CSAUDIO_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
402 { CSAUDIO_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
403 { CSAUDIO_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
404 { CSAUDIO_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
405 { CSAUDIO_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
406 { CSAUDIO_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
407 { CSAUDIO_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
408 { CSAUDIO_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
409 { CSAUDIO_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 }
410 };
411
412 static int nummap = sizeof(csmapping) / sizeof(csmapping[0]);
413
414
415 int
416 cs4231_set_port(addr, cp)
417 void *addr;
418 mixer_ctrl_t *cp;
419 {
420 struct ad1848_softc *ac = addr;
421
422 DPRINTF(("cs4231_set_port: port=%d", cp->dev));
423 return (ad1848_mixer_set_port(ac, csmapping, nummap, cp));
424 }
425
426 int
427 cs4231_get_port(addr, cp)
428 void *addr;
429 mixer_ctrl_t *cp;
430 {
431 struct ad1848_softc *ac = addr;
432
433 DPRINTF(("cs4231_get_port: port=%d", cp->dev));
434 return (ad1848_mixer_get_port(ac, csmapping, nummap, cp));
435 }
436
437 int
438 cs4231_get_props(addr)
439 void *addr;
440 {
441 return (AUDIO_PROP_FULLDUPLEX);
442 }
443
444 int
445 cs4231_query_devinfo(addr, dip)
446 void *addr;
447 mixer_devinfo_t *dip;
448 {
449
450 switch(dip->index) {
451 #if 0
452 case CSAUDIO_MIC_IN_LVL: /* Microphone */
453 dip->type = AUDIO_MIXER_VALUE;
454 dip->mixer_class = CSAUDIO_INPUT_CLASS;
455 dip->prev = AUDIO_MIXER_LAST;
456 dip->next = CSAUDIO_MIC_IN_MUTE;
457 strcpy(dip->label.name, AudioNmicrophone);
458 dip->un.v.num_channels = 2;
459 strcpy(dip->un.v.units.name, AudioNvolume);
460 break;
461 #endif
462
463 case CSAUDIO_MONO_LVL: /* mono/microphone mixer */
464 dip->type = AUDIO_MIXER_VALUE;
465 dip->mixer_class = CSAUDIO_INPUT_CLASS;
466 dip->prev = AUDIO_MIXER_LAST;
467 dip->next = CSAUDIO_MONO_MUTE;
468 strcpy(dip->label.name, AudioNmicrophone);
469 dip->un.v.num_channels = 1;
470 strcpy(dip->un.v.units.name, AudioNvolume);
471 break;
472
473 case CSAUDIO_DAC_LVL: /* dacout */
474 dip->type = AUDIO_MIXER_VALUE;
475 dip->mixer_class = CSAUDIO_INPUT_CLASS;
476 dip->prev = AUDIO_MIXER_LAST;
477 dip->next = CSAUDIO_DAC_MUTE;
478 strcpy(dip->label.name, AudioNdac);
479 dip->un.v.num_channels = 2;
480 strcpy(dip->un.v.units.name, AudioNvolume);
481 break;
482
483 case CSAUDIO_LINE_IN_LVL: /* line */
484 dip->type = AUDIO_MIXER_VALUE;
485 dip->mixer_class = CSAUDIO_INPUT_CLASS;
486 dip->prev = AUDIO_MIXER_LAST;
487 dip->next = CSAUDIO_LINE_IN_MUTE;
488 strcpy(dip->label.name, AudioNline);
489 dip->un.v.num_channels = 2;
490 strcpy(dip->un.v.units.name, AudioNvolume);
491 break;
492
493 case CSAUDIO_CD_LVL: /* cd */
494 dip->type = AUDIO_MIXER_VALUE;
495 dip->mixer_class = CSAUDIO_INPUT_CLASS;
496 dip->prev = AUDIO_MIXER_LAST;
497 dip->next = CSAUDIO_CD_MUTE;
498 strcpy(dip->label.name, AudioNcd);
499 dip->un.v.num_channels = 2;
500 strcpy(dip->un.v.units.name, AudioNvolume);
501 break;
502
503
504 case CSAUDIO_MONITOR_LVL: /* monitor level */
505 dip->type = AUDIO_MIXER_VALUE;
506 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
507 dip->next = CSAUDIO_MONITOR_MUTE;
508 dip->prev = AUDIO_MIXER_LAST;
509 strcpy(dip->label.name, AudioNmonitor);
510 dip->un.v.num_channels = 1;
511 strcpy(dip->un.v.units.name, AudioNvolume);
512 break;
513
514 case CSAUDIO_OUT_LVL: /* cs4231 output volume: not useful? */
515 dip->type = AUDIO_MIXER_VALUE;
516 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
517 dip->prev = dip->next = AUDIO_MIXER_LAST;
518 strcpy(dip->label.name, AudioNoutput);
519 dip->un.v.num_channels = 2;
520 strcpy(dip->un.v.units.name, AudioNvolume);
521 break;
522
523 case CSAUDIO_LINE_IN_MUTE:
524 dip->mixer_class = CSAUDIO_INPUT_CLASS;
525 dip->type = AUDIO_MIXER_ENUM;
526 dip->prev = CSAUDIO_LINE_IN_LVL;
527 dip->next = AUDIO_MIXER_LAST;
528 goto mute;
529
530 case CSAUDIO_DAC_MUTE:
531 dip->mixer_class = CSAUDIO_INPUT_CLASS;
532 dip->type = AUDIO_MIXER_ENUM;
533 dip->prev = CSAUDIO_DAC_LVL;
534 dip->next = AUDIO_MIXER_LAST;
535 goto mute;
536
537 case CSAUDIO_CD_MUTE:
538 dip->mixer_class = CSAUDIO_INPUT_CLASS;
539 dip->type = AUDIO_MIXER_ENUM;
540 dip->prev = CSAUDIO_CD_LVL;
541 dip->next = AUDIO_MIXER_LAST;
542 goto mute;
543
544 case CSAUDIO_MONO_MUTE:
545 dip->mixer_class = CSAUDIO_INPUT_CLASS;
546 dip->type = AUDIO_MIXER_ENUM;
547 dip->prev = CSAUDIO_MONO_LVL;
548 dip->next = AUDIO_MIXER_LAST;
549 goto mute;
550
551 case CSAUDIO_MONITOR_MUTE:
552 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
553 dip->type = AUDIO_MIXER_ENUM;
554 dip->prev = CSAUDIO_MONITOR_LVL;
555 dip->next = AUDIO_MIXER_LAST;
556 mute:
557 strcpy(dip->label.name, AudioNmute);
558 dip->un.e.num_mem = 2;
559 strcpy(dip->un.e.member[0].label.name, AudioNoff);
560 dip->un.e.member[0].ord = 0;
561 strcpy(dip->un.e.member[1].label.name, AudioNon);
562 dip->un.e.member[1].ord = 1;
563 break;
564
565 case CSAUDIO_REC_LVL: /* record level */
566 dip->type = AUDIO_MIXER_VALUE;
567 dip->mixer_class = CSAUDIO_RECORD_CLASS;
568 dip->prev = AUDIO_MIXER_LAST;
569 dip->next = CSAUDIO_RECORD_SOURCE;
570 strcpy(dip->label.name, AudioNrecord);
571 dip->un.v.num_channels = 2;
572 strcpy(dip->un.v.units.name, AudioNvolume);
573 break;
574
575 case CSAUDIO_RECORD_SOURCE:
576 dip->mixer_class = CSAUDIO_RECORD_CLASS;
577 dip->type = AUDIO_MIXER_ENUM;
578 dip->prev = CSAUDIO_REC_LVL;
579 dip->next = AUDIO_MIXER_LAST;
580 strcpy(dip->label.name, AudioNsource);
581 dip->un.e.num_mem = 4;
582 strcpy(dip->un.e.member[0].label.name, AudioNoutput);
583 dip->un.e.member[0].ord = DAC_IN_PORT;
584 strcpy(dip->un.e.member[1].label.name, AudioNmicrophone);
585 dip->un.e.member[1].ord = MIC_IN_PORT;
586 strcpy(dip->un.e.member[2].label.name, AudioNdac);
587 dip->un.e.member[2].ord = AUX1_IN_PORT;
588 strcpy(dip->un.e.member[3].label.name, AudioNline);
589 dip->un.e.member[3].ord = LINE_IN_PORT;
590 break;
591
592 case CSAUDIO_INPUT_CLASS: /* input class descriptor */
593 dip->type = AUDIO_MIXER_CLASS;
594 dip->mixer_class = CSAUDIO_INPUT_CLASS;
595 dip->next = dip->prev = AUDIO_MIXER_LAST;
596 strcpy(dip->label.name, AudioCinputs);
597 break;
598
599 case CSAUDIO_OUTPUT_CLASS: /* output class descriptor */
600 dip->type = AUDIO_MIXER_CLASS;
601 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
602 dip->next = dip->prev = AUDIO_MIXER_LAST;
603 strcpy(dip->label.name, AudioCoutputs);
604 break;
605
606 case CSAUDIO_MONITOR_CLASS: /* monitor class descriptor */
607 dip->type = AUDIO_MIXER_CLASS;
608 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
609 dip->next = dip->prev = AUDIO_MIXER_LAST;
610 strcpy(dip->label.name, AudioCmonitor);
611 break;
612
613 case CSAUDIO_RECORD_CLASS: /* record source class */
614 dip->type = AUDIO_MIXER_CLASS;
615 dip->mixer_class = CSAUDIO_RECORD_CLASS;
616 dip->next = dip->prev = AUDIO_MIXER_LAST;
617 strcpy(dip->label.name, AudioCrecord);
618 break;
619
620 default:
621 return ENXIO;
622 /*NOTREACHED*/
623 }
624 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
625
626 return (0);
627 }
628
629 int
630 cs4231_trigger_output(addr, start, end, blksize, intr, arg, param)
631 void *addr;
632 void *start, *end;
633 int blksize;
634 void (*intr) __P((void *));
635 void *arg;
636 struct audio_params *param;
637 {
638 struct cs4231_softc *sc = addr;
639 struct cs_dma *p;
640 volatile struct apc_dma *dma = sc->sc_dmareg;
641 int csr;
642 vsize_t n;
643
644 if (sc->sc_locked != 0) {
645 printf("cs4231_trigger_output: already running\n");
646 return (EINVAL);
647 }
648
649 sc->sc_locked = 1;
650 sc->sc_pintr = intr;
651 sc->sc_parg = arg;
652
653 for (p = sc->sc_dmas; p != NULL && p->addr != start; p = p->next)
654 /*void*/;
655 if (p == NULL) {
656 printf("cs4231_trigger_output: bad addr %p\n", start);
657 return (EINVAL);
658 }
659
660 n = (char *)end - (char *)start;
661
662 /* XXX
663 * Do only `blksize' at a time, so audio_pint() is kept
664 * synchronous with us...
665 */
666 /*XXX*/sc->sc_blksz = blksize;
667 /*XXX*/sc->sc_nowplaying = p;
668 /*XXX*/sc->sc_playsegsz = n;
669
670 if (n > APC_MAX)
671 n = APC_MAX;
672
673 sc->sc_playcnt = n;
674
675 DPRINTF(("trigger_out: start %p, end %p, size %lu; "
676 "dmaaddr 0x%lx, dmacnt %lu, segsize %lu\n",
677 start, end, (u_long)sc->sc_playsegsz,
678 (u_long)p->dmamap->dm_segs[0].ds_addr,
679 (u_long)n, (u_long)p->size));
680
681 csr = dma->dmacsr;
682 dma->dmapnva = (u_long)p->dmamap->dm_segs[0].ds_addr;
683 dma->dmapnc = (u_long)n;
684 if ((csr & PDMA_GO) == 0 || (csr & APC_PPAUSE) != 0) {
685 int reg;
686
687 dma->dmacsr &= ~(APC_PIE|APC_PPAUSE);
688 dma->dmacsr |= APC_EI|APC_IE|APC_PIE|APC_EIE|APC_PMIE|PDMA_GO;
689
690 /* Start chip */
691
692 /* Probably should just ignore this.. */
693 ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
694 ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
695
696 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
697 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
698 (PLAYBACK_ENABLE|reg));
699 }
700
701 return (0);
702 }
703
704 int
705 cs4231_trigger_input(addr, start, end, blksize, intr, arg, param)
706 void *addr;
707 void *start, *end;
708 int blksize;
709 void (*intr) __P((void *));
710 void *arg;
711 struct audio_params *param;
712 {
713 return (ENXIO);
714 }
715
716 int
717 cs4231_halt_output(addr)
718 void *addr;
719 {
720 struct cs4231_softc *sc = addr;
721 volatile struct apc_dma *dma = sc->sc_dmareg;
722 int reg;
723
724 dma->dmacsr &= ~(APC_EI | APC_IE | APC_PIE | APC_EIE | PDMA_GO | APC_PMIE);
725 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
726 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~PLAYBACK_ENABLE));
727 sc->sc_locked = 0;
728
729 return (0);
730 }
731
732 int
733 cs4231_halt_input(addr)
734 void *addr;
735 {
736 struct cs4231_softc *sc = addr;
737 int reg;
738
739 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
740 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~CAPTURE_ENABLE));
741 sc->sc_locked = 0;
742
743 return (0);
744 }
745
746
747 int
748 cs4231_intr(arg)
749 void *arg;
750 {
751 struct cs4231_softc *sc = arg;
752 volatile struct apc_dma *dma = sc->sc_dmareg;
753 struct cs_dma *p;
754 int ret = 0;
755 int csr;
756 int reg, status;
757 #if defined(DEBUG) || defined(AUDIO_DEBUG)
758 char bits[128];
759 #endif
760
761 #ifdef AUDIO_DEBUG
762 if (cs4231debug > 1)
763 cs4231_regdump("audiointr", sc);
764 #endif
765
766 /* Read DMA status */
767 csr = dma->dmacsr;
768 DPRINTF((
769 "intr: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n",
770 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)),
771 (u_long)dma->dmapva, (u_long)dma->dmapc,
772 (u_long)dma->dmapnva, (u_long)dma->dmapnc));
773
774 status = ADREAD(&sc->sc_ad1848, AD1848_STATUS);
775 DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
776 bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits))));
777 if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
778 reg = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS);
779 DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
780 bitmask_snprintf(reg, CS_I24_BITS, bits, sizeof(bits))));
781
782 if (reg & CS_IRQ_PI) {
783 ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
784 ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
785 }
786 /* Clear interrupt bit */
787 ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0);
788 }
789
790 /* Write back DMA status (clears interrupt) */
791 dma->dmacsr = csr;
792
793 /*
794 * Simplistic.. if "play emtpy" is set advance to next chunk.
795 */
796 #if 1
797 /* Ack all play interrupts*/
798 if ((csr & (APC_PI|APC_PD|APC_PIE|APC_PMI)) != 0)
799 ret = 1;
800 #endif
801 if (csr & APC_PM) {
802 u_long nextaddr, togo;
803
804 p = sc->sc_nowplaying;
805
806 togo = sc->sc_playsegsz - sc->sc_playcnt;
807 if (togo == 0) {
808 /* Roll over */
809 nextaddr = (u_long)p->dmamap->dm_segs[0].ds_addr;
810 sc->sc_playcnt = togo = APC_MAX;
811 } else {
812 nextaddr = dma->dmapnva + APC_MAX;
813 if (togo > APC_MAX)
814 togo = APC_MAX;
815 sc->sc_playcnt += togo;
816 }
817
818 dma->dmapnva = nextaddr;
819 dma->dmapnc = togo;
820
821 if (sc->sc_pintr != NULL)
822 (*sc->sc_pintr)(sc->sc_parg);
823
824 ret = 1;
825 }
826
827 if (csr & APC_CI) {
828 if (sc->sc_rintr != NULL) {
829 ret = 1;
830 (*sc->sc_rintr)(sc->sc_rarg);
831 }
832 }
833
834 #ifdef DEBUG
835 if (ret == 0) {
836 printf(
837 "oops: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n",
838 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)),
839 (u_long)dma->dmapva, (u_long)dma->dmapc,
840 (u_long)dma->dmapnva, (u_long)dma->dmapnc);
841 ret = 1;
842 }
843 #endif
844
845 return (ret);
846 }
847 #endif /* NAUDIO > 0 */
848