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