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