xref: /netbsd-src/sys/dev/ic/cs4231.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
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