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