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