xref: /openbsd-src/sys/dev/sbus/cs4231.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: cs4231.c,v 1.33 2014/07/12 18:48:52 tedu Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Effort sponsored in part by the Defense Advanced Research Projects
29  * Agency (DARPA) and Air Force Research Laboratory, Air Force
30  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31  *
32  */
33 
34 /*
35  * Driver for CS4231 based audio found in some sun4m systems (cs4231)
36  * based on ideas from the S/Linux project and the NetBSD project.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/device.h>
44 #include <sys/proc.h>
45 #include <sys/malloc.h>
46 
47 #include <machine/bus.h>
48 #include <machine/intr.h>
49 #include <machine/autoconf.h>
50 
51 #include <sys/audioio.h>
52 #include <dev/audio_if.h>
53 #include <dev/auconv.h>
54 
55 #include <dev/ic/ad1848reg.h>
56 #include <dev/ic/cs4231reg.h>
57 #include <dev/ic/apcdmareg.h>
58 #include <dev/sbus/sbusvar.h>
59 #include <dev/sbus/cs4231var.h>
60 
61 #define	CSAUDIO_DAC_LVL		0
62 #define	CSAUDIO_LINE_IN_LVL	1
63 #define	CSAUDIO_MIC_LVL		2
64 #define	CSAUDIO_CD_LVL		3
65 #define	CSAUDIO_MONITOR_LVL	4
66 #define	CSAUDIO_OUTPUT_LVL	5
67 #define	CSAUDIO_LINE_IN_MUTE	6
68 #define	CSAUDIO_DAC_MUTE	7
69 #define	CSAUDIO_CD_MUTE		8
70 #define	CSAUDIO_MIC_MUTE	9
71 #define	CSAUDIO_MONITOR_MUTE	10
72 #define	CSAUDIO_OUTPUT_MUTE	11
73 #define	CSAUDIO_REC_LVL		12
74 #define	CSAUDIO_RECORD_SOURCE	13
75 #define	CSAUDIO_OUTPUT		14
76 #define	CSAUDIO_INPUT_CLASS	15
77 #define	CSAUDIO_OUTPUT_CLASS	16
78 #define	CSAUDIO_RECORD_CLASS	17
79 #define	CSAUDIO_MONITOR_CLASS	18
80 
81 #define	CSPORT_AUX2		0
82 #define	CSPORT_AUX1		1
83 #define	CSPORT_DAC		2
84 #define	CSPORT_LINEIN		3
85 #define	CSPORT_MONO		4
86 #define	CSPORT_MONITOR		5
87 #define	CSPORT_SPEAKER		6
88 #define	CSPORT_LINEOUT		7
89 #define	CSPORT_HEADPHONE	8
90 #define	CSPORT_MICROPHONE	9
91 
92 #define MIC_IN_PORT	0
93 #define LINE_IN_PORT	1
94 #define AUX1_IN_PORT	2
95 #define DAC_IN_PORT	3
96 
97 #ifdef AUDIO_DEBUG
98 #define	DPRINTF(x)	printf x
99 #else
100 #define	DPRINTF(x)
101 #endif
102 
103 #define	CS_TIMEOUT	90000
104 
105 #define	CS_PC_LINEMUTE	XCTL0_ENABLE
106 #define	CS_PC_HDPHMUTE	XCTL1_ENABLE
107 #define	CS_AFS_TI	0x40		/* timer interrupt */
108 #define	CS_AFS_CI	0x20		/* capture interrupt */
109 #define	CS_AFS_PI	0x10		/* playback interrupt */
110 #define	CS_AFS_CU	0x08		/* capture underrun */
111 #define	CS_AFS_CO	0x04		/* capture overrun */
112 #define	CS_AFS_PO	0x02		/* playback overrun */
113 #define	CS_AFS_PU	0x01		/* playback underrun */
114 
115 #define CS_WRITE(sc,r,v)	\
116     bus_space_write_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2, (v))
117 #define	CS_READ(sc,r)		\
118     bus_space_read_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2)
119 
120 #define	APC_WRITE(sc,r,v)	\
121     bus_space_write_4(sc->sc_bustag, sc->sc_regs, r, v)
122 #define	APC_READ(sc,r)		\
123     bus_space_read_4(sc->sc_bustag, sc->sc_regs, r)
124 
125 int	cs4231_match(struct device *, void *, void *);
126 void	cs4231_attach(struct device *, struct device *, void *);
127 int	cs4231_intr(void *);
128 
129 int	cs4231_set_speed(struct cs4231_softc *, u_long *);
130 void	cs4231_setup_output(struct cs4231_softc *sc);
131 
132 void		cs4231_write(struct cs4231_softc *, u_int8_t, u_int8_t);
133 u_int8_t	cs4231_read(struct cs4231_softc *, u_int8_t);
134 
135 /* Audio interface */
136 int	cs4231_open(void *, int);
137 void	cs4231_close(void *);
138 int	cs4231_query_encoding(void *, struct audio_encoding *);
139 int	cs4231_set_params(void *, int, int, struct audio_params *,
140     struct audio_params *);
141 int	cs4231_round_blocksize(void *, int);
142 int	cs4231_commit_settings(void *);
143 int	cs4231_halt_output(void *);
144 int	cs4231_halt_input(void *);
145 int	cs4231_getdev(void *, struct audio_device *);
146 int	cs4231_set_port(void *, mixer_ctrl_t *);
147 int	cs4231_get_port(void *, mixer_ctrl_t *);
148 int	cs4231_query_devinfo(void *, mixer_devinfo_t *);
149 void *	cs4231_alloc(void *, int, size_t, int, int);
150 void	cs4231_free(void *, void *, int);
151 int	cs4231_get_props(void *);
152 int	cs4231_trigger_output(void *, void *, void *, int,
153     void (*)(void *), void *, struct audio_params *);
154 int	cs4231_trigger_input(void *, void *, void *, int,
155     void (*)(void *), void *, struct audio_params *);
156 
157 struct audio_hw_if cs4231_sa_hw_if = {
158 	cs4231_open,
159 	cs4231_close,
160 	0,
161 	cs4231_query_encoding,
162 	cs4231_set_params,
163 	cs4231_round_blocksize,
164 	cs4231_commit_settings,
165 	0,
166 	0,
167 	0,
168 	0,
169 	cs4231_halt_output,
170 	cs4231_halt_input,
171 	0,
172 	cs4231_getdev,
173 	0,
174 	cs4231_set_port,
175 	cs4231_get_port,
176 	cs4231_query_devinfo,
177 	cs4231_alloc,
178 	cs4231_free,
179 	0,
180 	0,
181 	cs4231_get_props,
182 	cs4231_trigger_output,
183 	cs4231_trigger_input,
184 	0
185 };
186 
187 struct cfattach audiocs_ca = {
188 	sizeof (struct cs4231_softc), cs4231_match, cs4231_attach
189 };
190 
191 struct cfdriver audiocs_cd = {
192 	NULL, "audiocs", DV_DULL
193 };
194 
195 struct audio_device cs4231_device = {
196 	"SUNW,CS4231",
197 	"b",
198 	"onboard1",
199 };
200 
201 int
202 cs4231_match(struct device *parent, void *vcf, void *aux)
203 {
204 	struct sbus_attach_args *sa = aux;
205 
206 	return (strcmp("SUNW,CS4231", sa->sa_name) == 0);
207 }
208 
209 void
210 cs4231_attach(struct device *parent, struct device *self, void *aux)
211 {
212 	struct sbus_attach_args *sa = aux;
213 	struct cs4231_softc *sc = (struct cs4231_softc *)self;
214 	int node;
215 	u_int32_t sbusburst, burst;
216 
217 	node = sa->sa_node;
218 
219 	/* Pass on the bus tags */
220 	sc->sc_bustag = sa->sa_bustag;
221 	sc->sc_dmatag = sa->sa_dmatag;
222 
223 	/* Make sure things are sane. */
224 	if (sa->sa_nintr != 1) {
225 		printf(": expected 1 interrupt, got %d\n", sa->sa_nintr);
226 		return;
227 	}
228 	if (sa->sa_nreg != 1) {
229 		printf(": expected 1 register set, got %d\n",
230 		    sa->sa_nreg);
231 		return;
232 	}
233 
234 	if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_AUDIO, 0,
235 	    cs4231_intr, sc, self->dv_xname) == NULL) {
236 		printf(": couldn't establish interrupt, pri %d\n",
237 		    INTLEV(sa->sa_pri));
238 		return;
239 	}
240 
241 	if (sbus_bus_map(sa->sa_bustag,
242 	    sa->sa_reg[0].sbr_slot,
243 	    (bus_addr_t)sa->sa_reg[0].sbr_offset,
244 	    (bus_size_t)sa->sa_reg[0].sbr_size,
245 	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regs) != 0) {
246 		printf(": couldn't map registers\n");
247 		return;
248 	}
249 
250 	sbusburst = ((struct sbus_softc *)parent)->sc_burst;
251 	if (sbusburst == 0)
252 		sbusburst = SBUS_BURST_32 - 1;	/* 1->16 */
253 	burst = getpropint(node, "burst-sizes", -1);
254 	if (burst == -1)
255 		burst = sbusburst;
256 	sc->sc_burst = burst & sbusburst;
257 
258 	printf("\n");
259 
260 	audio_attach_mi(&cs4231_sa_hw_if, sc, &sc->sc_dev);
261 
262 	/* Default to speaker, unmuted, reasonable volume */
263 	sc->sc_out_port = CSPORT_SPEAKER;
264 	sc->sc_in_port = CSPORT_MICROPHONE;
265 	sc->sc_mute[CSPORT_SPEAKER] = 1;
266 	sc->sc_mute[CSPORT_MONITOR] = 1;
267 	sc->sc_volume[CSPORT_SPEAKER].left = 192;
268 	sc->sc_volume[CSPORT_SPEAKER].right = 192;
269 }
270 
271 /*
272  * Write to one of the indexed registers of cs4231.
273  */
274 void
275 cs4231_write(struct cs4231_softc *sc, u_int8_t r, u_int8_t v)
276 {
277 	CS_WRITE(sc, AD1848_IADDR, r);
278 	CS_WRITE(sc, AD1848_IDATA, v);
279 }
280 
281 /*
282  * Read from one of the indexed registers of cs4231.
283  */
284 u_int8_t
285 cs4231_read(struct cs4231_softc *sc, u_int8_t r)
286 {
287 	CS_WRITE(sc, AD1848_IADDR, r);
288 	return (CS_READ(sc, AD1848_IDATA));
289 }
290 
291 int
292 cs4231_set_speed(struct cs4231_softc *sc, u_long *argp)
293 {
294 	/*
295 	 * The available speeds are in the following table. Keep the speeds in
296 	 * the increasing order.
297 	 */
298 	typedef struct {
299 		int speed;
300 		u_char bits;
301 	} speed_struct;
302 	u_long arg = *argp;
303 
304 	const static speed_struct speed_table[] = {
305 		{5510,	(0 << 1) | CLOCK_XTAL2},
306 		{5510,	(0 << 1) | CLOCK_XTAL2},
307 		{6620,	(7 << 1) | CLOCK_XTAL2},
308 		{8000,	(0 << 1) | CLOCK_XTAL1},
309 		{9600,	(7 << 1) | CLOCK_XTAL1},
310 		{11025,	(1 << 1) | CLOCK_XTAL2},
311 		{16000,	(1 << 1) | CLOCK_XTAL1},
312 		{18900,	(2 << 1) | CLOCK_XTAL2},
313 		{22050,	(3 << 1) | CLOCK_XTAL2},
314 		{27420,	(2 << 1) | CLOCK_XTAL1},
315 		{32000,	(3 << 1) | CLOCK_XTAL1},
316 		{33075,	(6 << 1) | CLOCK_XTAL2},
317 		{33075,	(4 << 1) | CLOCK_XTAL2},
318 		{44100,	(5 << 1) | CLOCK_XTAL2},
319 		{48000,	(6 << 1) | CLOCK_XTAL1},
320 	};
321 
322 	int i, n, selected = -1;
323 
324 	n = sizeof(speed_table) / sizeof(speed_struct);
325 
326 	if (arg < speed_table[0].speed)
327 		selected = 0;
328 	if (arg > speed_table[n - 1].speed)
329 		selected = n - 1;
330 
331 	for (i = 1; selected == -1 && i < n; i++) {
332 		if (speed_table[i].speed == arg)
333 			selected = i;
334 		else if (speed_table[i].speed > arg) {
335 			int diff1, diff2;
336 
337 			diff1 = arg - speed_table[i - 1].speed;
338 			diff2 = speed_table[i].speed - arg;
339 			if (diff1 < diff2)
340 				selected = i - 1;
341 			else
342 				selected = i;
343 		}
344 	}
345 
346 	if (selected == -1)
347 		selected = 3;
348 
349 	sc->sc_speed_bits = speed_table[selected].bits;
350 	sc->sc_need_commit = 1;
351 	*argp = speed_table[selected].speed;
352 
353 	return (0);
354 }
355 
356 /*
357  * Audio interface functions
358  */
359 int
360 cs4231_open(void *vsc, int flags)
361 {
362 	struct cs4231_softc *sc = vsc;
363 	int tries;
364 
365 	if (sc->sc_open)
366 		return (EBUSY);
367 	sc->sc_open = 1;
368 
369 	sc->sc_capture.cs_intr = NULL;
370 	sc->sc_capture.cs_arg = NULL;
371 	sc->sc_capture.cs_locked = 0;
372 
373 	sc->sc_playback.cs_intr = NULL;
374 	sc->sc_playback.cs_arg = NULL;
375 	sc->sc_playback.cs_locked = 0;
376 
377 	APC_WRITE(sc, APC_CSR, APC_CSR_RESET);
378 	DELAY(10);
379 	APC_WRITE(sc, APC_CSR, 0);
380 	DELAY(10);
381 	APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) | APC_CSR_CODEC_RESET);
382 
383 	DELAY(20);
384 
385 	APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & (~APC_CSR_CODEC_RESET));
386 
387 	for (tries = CS_TIMEOUT;
388 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
389 		DELAY(10);
390 	if (tries == 0)
391 		printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
392 
393 	/* Turn on cs4231 mode */
394 	cs4231_write(sc, SP_MISC_INFO,
395 	    cs4231_read(sc, SP_MISC_INFO) | MODE2);
396 
397 	cs4231_setup_output(sc);
398 
399 	cs4231_write(sc, SP_PIN_CONTROL,
400 	    cs4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
401 
402 	return (0);
403 }
404 
405 void
406 cs4231_setup_output(struct cs4231_softc *sc)
407 {
408 	u_int8_t pc, mi, rm, lm;
409 
410 	pc = cs4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
411 
412 	mi = cs4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
413 
414 	lm = cs4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
415 	lm &= ~OUTPUT_ATTEN_BITS;
416 	lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
417 	    OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
418 
419 	rm = cs4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
420 	rm &= ~OUTPUT_ATTEN_BITS;
421 	rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
422 	    OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
423 
424 	if (sc->sc_mute[CSPORT_MONITOR]) {
425 		lm &= ~OUTPUT_MUTE;
426 		rm &= ~OUTPUT_MUTE;
427 	}
428 
429 	switch (sc->sc_out_port) {
430 	case CSPORT_HEADPHONE:
431 		if (sc->sc_mute[CSPORT_SPEAKER])
432 			pc &= ~CS_PC_HDPHMUTE;
433 		break;
434 	case CSPORT_SPEAKER:
435 		if (sc->sc_mute[CSPORT_SPEAKER])
436 			mi &= ~MONO_OUTPUT_MUTE;
437 		break;
438 	case CSPORT_LINEOUT:
439 		if (sc->sc_mute[CSPORT_SPEAKER])
440 			pc &= ~CS_PC_LINEMUTE;
441 		break;
442 	}
443 
444 	cs4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
445 	cs4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
446 	cs4231_write(sc, SP_PIN_CONTROL, pc);
447 	cs4231_write(sc, CS_MONO_IO_CONTROL, mi);
448 
449 	/* XXX doesn't really belong here... */
450 	switch (sc->sc_in_port) {
451 	case CSPORT_LINEIN:
452 		pc = LINE_INPUT;
453 		break;
454 	case CSPORT_AUX1:
455 		pc = AUX_INPUT;
456 		break;
457 	case CSPORT_DAC:
458 		pc = MIXED_DAC_INPUT;
459 		break;
460 	case CSPORT_MICROPHONE:
461 	default:
462 		pc = MIC_INPUT;
463 		break;
464 	}
465 	lm = cs4231_read(sc, SP_LEFT_INPUT_CONTROL);
466 	rm = cs4231_read(sc, SP_RIGHT_INPUT_CONTROL);
467 	lm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
468 	rm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
469 	lm |= pc | (sc->sc_adc.left >> 4);
470 	rm |= pc | (sc->sc_adc.right >> 4);
471 	cs4231_write(sc, SP_LEFT_INPUT_CONTROL, lm);
472 	cs4231_write(sc, SP_RIGHT_INPUT_CONTROL, rm);
473 }
474 
475 void
476 cs4231_close(void *vsc)
477 {
478 	struct cs4231_softc *sc = vsc;
479 
480 	cs4231_halt_input(sc);
481 	cs4231_halt_output(sc);
482 	cs4231_write(sc, SP_PIN_CONTROL,
483 	    cs4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
484 	sc->sc_open = 0;
485 }
486 
487 int
488 cs4231_query_encoding(void *vsc, struct audio_encoding *fp)
489 {
490 	int err = 0;
491 
492 	switch (fp->index) {
493 	case 0:
494 		strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
495 		fp->encoding = AUDIO_ENCODING_ULAW;
496 		fp->precision = 8;
497 		fp->flags = 0;
498 		break;
499 	case 1:
500 		strlcpy(fp->name, AudioEalaw, sizeof fp->name);
501 		fp->encoding = AUDIO_ENCODING_ALAW;
502 		fp->precision = 8;
503 		fp->flags = 0;
504 		break;
505 	case 2:
506 		strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
507 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
508 		fp->precision = 16;
509 		fp->flags = 0;
510 		break;
511 	case 3:
512 		strlcpy(fp->name, AudioEulinear, sizeof fp->name);
513 		fp->encoding = AUDIO_ENCODING_ULINEAR;
514 		fp->precision = 8;
515 		fp->flags = 0;
516 		break;
517 	case 4:
518 		strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
519 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
520 		fp->precision = 16;
521 		fp->flags = 0;
522 		break;
523 	case 5:
524 		strlcpy(fp->name, AudioEslinear, sizeof fp->name);
525 		fp->encoding = AUDIO_ENCODING_SLINEAR;
526 		fp->precision = 8;
527 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
528 		break;
529 	case 6:
530 		strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
531 		fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
532 		fp->precision = 16;
533 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
534 		break;
535 	case 7:
536 		strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
537 		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
538 		fp->precision = 16;
539 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
540 		break;
541 	case 8:
542 		strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
543 		fp->encoding = AUDIO_ENCODING_ADPCM;
544 		fp->precision = 8;
545 		fp->flags = 0;
546 		break;
547 	default:
548 		err = EINVAL;
549 	}
550 	fp->bps = AUDIO_BPS(fp->precision);
551 	fp->msb = 1;
552 
553 	return (err);
554 }
555 
556 int
557 cs4231_set_params(void *vsc, int setmode, int usemode,
558     struct audio_params *p, struct audio_params *r)
559 {
560 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
561 	int err, bits, enc = p->encoding;
562 	void (*pswcode)(void *, u_char *, int cnt) = NULL;
563 	void (*rswcode)(void *, u_char *, int cnt) = NULL;
564 
565 	switch (enc) {
566 	case AUDIO_ENCODING_ULAW:
567 		if (p->precision != 8)
568 			return (EINVAL);
569 		bits = FMT_ULAW >> 5;
570 		break;
571 	case AUDIO_ENCODING_ALAW:
572 		if (p->precision != 8)
573 			return (EINVAL);
574 		bits = FMT_ALAW >> 5;
575 		break;
576 	case AUDIO_ENCODING_SLINEAR_LE:
577 		if (p->precision == 8) {
578 			bits = FMT_PCM8 >> 5;
579 			pswcode = rswcode = change_sign8;
580 		} else if (p->precision == 16)
581 			bits = FMT_TWOS_COMP >> 5;
582 		else
583 			return (EINVAL);
584 		break;
585 	case AUDIO_ENCODING_ULINEAR:
586 		if (p->precision != 8)
587 			return (EINVAL);
588 		bits = FMT_PCM8 >> 5;
589 		break;
590 	case AUDIO_ENCODING_SLINEAR_BE:
591 		if (p->precision == 8) {
592 			bits = FMT_PCM8 >> 5;
593 			pswcode = rswcode = change_sign8;
594 		} else if (p->precision == 16)
595 			bits = FMT_TWOS_COMP_BE >> 5;
596 		else
597 			return (EINVAL);
598 		break;
599 	case AUDIO_ENCODING_SLINEAR:
600 		if (p->precision != 8)
601 			return (EINVAL);
602 		bits = FMT_PCM8 >> 5;
603 		pswcode = rswcode = change_sign8;
604 		break;
605 	case AUDIO_ENCODING_ULINEAR_LE:
606 		if (p->precision == 8)
607 			bits = FMT_PCM8 >> 5;
608 		else if (p->precision == 16) {
609 			bits = FMT_TWOS_COMP >> 5;
610 			pswcode = rswcode = change_sign16_le;
611 		} else
612 			return (EINVAL);
613 		break;
614 	case AUDIO_ENCODING_ULINEAR_BE:
615 		if (p->precision == 8)
616 			bits = FMT_PCM8 >> 5;
617 		else if (p->precision == 16) {
618 			bits = FMT_TWOS_COMP_BE >> 5;
619 			pswcode = rswcode = change_sign16_be;
620 		} else
621 			return (EINVAL);
622 		break;
623 	case AUDIO_ENCODING_ADPCM:
624 		if (p->precision != 8)
625 			return (EINVAL);
626 		bits = FMT_ADPCM >> 5;
627 		break;
628 	default:
629 		return (EINVAL);
630 	}
631 
632 	if (p->channels != 1 && p->channels != 2)
633 		return (EINVAL);
634 
635 	err = cs4231_set_speed(sc, &p->sample_rate);
636 	if (err)
637 		return (err);
638 
639 	p->sw_code = pswcode;
640 	r->sw_code = rswcode;
641 	p->bps = AUDIO_BPS(p->precision);
642 	r->bps = AUDIO_BPS(r->precision);
643 	p->msb = r->msb = 1;
644 
645 	sc->sc_format_bits = bits;
646 	sc->sc_channels = p->channels;
647 	sc->sc_precision = p->precision;
648 	sc->sc_need_commit = 1;
649 	return (0);
650 }
651 
652 int
653 cs4231_round_blocksize(void *vsc, int blk)
654 {
655 	return ((blk + 3) & (-4));
656 }
657 
658 int
659 cs4231_commit_settings(void *vsc)
660 {
661 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
662 	int tries;
663 	u_int8_t r, fs;
664 
665 	if (sc->sc_need_commit == 0)
666 		return (0);
667 
668 	fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
669 	if (sc->sc_channels == 2)
670 		fs |= FMT_STEREO;
671 
672 	/* XXX: this is called before DMA is setup, useful ? */
673 	mtx_enter(&audio_lock);
674 
675 	r = cs4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
676 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
677 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
678 	CS_WRITE(sc, AD1848_IDATA, r);
679 
680 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
681 	CS_WRITE(sc, AD1848_IDATA, fs);
682 	CS_READ(sc, AD1848_IDATA);
683 	CS_READ(sc, AD1848_IDATA);
684 	tries = CS_TIMEOUT;
685 	for (tries = CS_TIMEOUT;
686 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
687 		DELAY(10);
688 	if (tries == 0)
689 		printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
690 
691 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
692 	CS_WRITE(sc, AD1848_IDATA, fs);
693 	CS_READ(sc, AD1848_IDATA);
694 	CS_READ(sc, AD1848_IDATA);
695 	for (tries = CS_TIMEOUT;
696 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
697 		DELAY(10);
698 	if (tries == 0)
699 		printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
700 
701 	CS_WRITE(sc, AD1848_IADDR, 0);
702 	for (tries = CS_TIMEOUT;
703 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
704 		DELAY(10);
705 	if (tries == 0)
706 		printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
707 
708 	CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
709 	for (tries = CS_TIMEOUT;
710 	     tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
711 		DELAY(10);
712 	if (tries == 0)
713 		printf("%s: timeout waiting for autocalibration\n",
714 		    sc->sc_dev.dv_xname);
715 
716 	mtx_leave(&audio_lock);
717 
718 	sc->sc_need_commit = 0;
719 	return (0);
720 }
721 
722 int
723 cs4231_halt_output(void *vsc)
724 {
725 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
726 
727 	/* XXX Kills some capture bits */
728 	mtx_enter(&audio_lock);
729 	APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) &
730 	    ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE |
731 	      APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE));
732 	cs4231_write(sc, SP_INTERFACE_CONFIG,
733 	    cs4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
734 	sc->sc_playback.cs_locked = 0;
735 	mtx_leave(&audio_lock);
736 	return (0);
737 }
738 
739 int
740 cs4231_halt_input(void *vsc)
741 {
742 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
743 
744 	/* XXX Kills some playback bits */
745 	mtx_enter(&audio_lock);
746 	APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE);
747 	cs4231_write(sc, SP_INTERFACE_CONFIG,
748 	    cs4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
749 	sc->sc_capture.cs_locked = 0;
750 	mtx_leave(&audio_lock);
751 	return (0);
752 }
753 
754 int
755 cs4231_getdev(void *vsc, struct audio_device *retp)
756 {
757 	*retp = cs4231_device;
758 	return (0);
759 }
760 
761 int
762 cs4231_set_port(void *vsc, mixer_ctrl_t *cp)
763 {
764 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
765 	int error = EINVAL;
766 
767 	DPRINTF(("cs4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
768 
769 	switch (cp->dev) {
770 	case CSAUDIO_DAC_LVL:
771 		if (cp->type != AUDIO_MIXER_VALUE)
772 			break;
773 		if (cp->un.value.num_channels == 1)
774 			cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
775 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
776 			    LINE_INPUT_ATTEN_BITS);
777 		else if (cp->un.value.num_channels == 2) {
778 			cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
779 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
780 			    LINE_INPUT_ATTEN_BITS);
781 			cs4231_write(sc, SP_RIGHT_AUX1_CONTROL,
782 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
783 			    LINE_INPUT_ATTEN_BITS);
784 		} else
785 			break;
786 		error = 0;
787 		break;
788 	case CSAUDIO_LINE_IN_LVL:
789 		if (cp->type != AUDIO_MIXER_VALUE)
790 			break;
791 		if (cp->un.value.num_channels == 1)
792 			cs4231_write(sc, CS_LEFT_LINE_CONTROL,
793 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
794 			    AUX_INPUT_ATTEN_BITS);
795 		else if (cp->un.value.num_channels == 2) {
796 			cs4231_write(sc, CS_LEFT_LINE_CONTROL,
797 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
798 			    AUX_INPUT_ATTEN_BITS);
799 			cs4231_write(sc, CS_RIGHT_LINE_CONTROL,
800 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
801 			    AUX_INPUT_ATTEN_BITS);
802 		} else
803 			break;
804 		error = 0;
805 		break;
806 	case CSAUDIO_MIC_LVL:
807 		if (cp->type != AUDIO_MIXER_VALUE)
808 			break;
809 		if (cp->un.value.num_channels == 1) {
810 #if 0
811 			cs4231_write(sc, CS_MONO_IO_CONTROL,
812 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
813 			    MONO_INPUT_ATTEN_BITS);
814 #endif
815 		} else
816 			break;
817 		error = 0;
818 		break;
819 	case CSAUDIO_CD_LVL:
820 		if (cp->type != AUDIO_MIXER_VALUE)
821 			break;
822 		if (cp->un.value.num_channels == 1) {
823 			cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
824 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
825 			    LINE_INPUT_ATTEN_BITS);
826 		} else if (cp->un.value.num_channels == 2) {
827 			cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
828 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
829 			    LINE_INPUT_ATTEN_BITS);
830 			cs4231_write(sc, SP_RIGHT_AUX2_CONTROL,
831 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
832 			    LINE_INPUT_ATTEN_BITS);
833 		} else
834 			break;
835 		error = 0;
836 		break;
837 	case CSAUDIO_MONITOR_LVL:
838 		if (cp->type != AUDIO_MIXER_VALUE)
839 			break;
840 		if (cp->un.value.num_channels == 1)
841 			cs4231_write(sc, SP_DIGITAL_MIX,
842 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
843 		else
844 			break;
845 		error = 0;
846 		break;
847 	case CSAUDIO_OUTPUT_LVL:
848 		if (cp->type != AUDIO_MIXER_VALUE)
849 			break;
850 		if (cp->un.value.num_channels == 1) {
851 			sc->sc_volume[CSPORT_SPEAKER].left =
852 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
853 			sc->sc_volume[CSPORT_SPEAKER].right =
854 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
855 		}
856 		else if (cp->un.value.num_channels == 2) {
857 			sc->sc_volume[CSPORT_SPEAKER].left =
858 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
859 			sc->sc_volume[CSPORT_SPEAKER].right =
860 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
861 		}
862 		else
863 			break;
864 
865 		cs4231_setup_output(sc);
866 		error = 0;
867 		break;
868 	case CSAUDIO_OUTPUT:
869 		if (cp->type != AUDIO_MIXER_ENUM)
870 			break;
871 		if (cp->un.ord != CSPORT_LINEOUT &&
872 		    cp->un.ord != CSPORT_SPEAKER &&
873 		    cp->un.ord != CSPORT_HEADPHONE)
874 			return (EINVAL);
875 		sc->sc_out_port = cp->un.ord;
876 		cs4231_setup_output(sc);
877 		error = 0;
878 		break;
879 	case CSAUDIO_LINE_IN_MUTE:
880 		if (cp->type != AUDIO_MIXER_ENUM)
881 			break;
882 		sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
883 		error = 0;
884 		break;
885 	case CSAUDIO_DAC_MUTE:
886 		if (cp->type != AUDIO_MIXER_ENUM)
887 			break;
888 		sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
889 		error = 0;
890 		break;
891 	case CSAUDIO_CD_MUTE:
892 		if (cp->type != AUDIO_MIXER_ENUM)
893 			break;
894 		sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
895 		error = 0;
896 		break;
897 	case CSAUDIO_MIC_MUTE:
898 		if (cp->type != AUDIO_MIXER_ENUM)
899 			break;
900 		sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
901 		error = 0;
902 		break;
903 	case CSAUDIO_MONITOR_MUTE:
904 		if (cp->type != AUDIO_MIXER_ENUM)
905 			break;
906 		sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
907 		error = 0;
908 		break;
909 	case CSAUDIO_OUTPUT_MUTE:
910 		if (cp->type != AUDIO_MIXER_ENUM)
911 			break;
912 		sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
913 		cs4231_setup_output(sc);
914 		error = 0;
915 		break;
916 	case CSAUDIO_REC_LVL:
917 		if (cp->type != AUDIO_MIXER_VALUE)
918 			break;
919 		if (cp->un.value.num_channels == 1) {
920 			sc->sc_adc.left =
921 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
922 			sc->sc_adc.right =
923 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
924 		} else if (cp->un.value.num_channels == 2) {
925 			sc->sc_adc.left =
926 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
927 			sc->sc_adc.right =
928 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
929 		} else
930 			break;
931 		cs4231_setup_output(sc);
932 		error = 0;
933 		break;
934 	case CSAUDIO_RECORD_SOURCE:
935 		if (cp->type != AUDIO_MIXER_ENUM)
936 			break;
937 		if (cp->un.ord == CSPORT_MICROPHONE ||
938 		    cp->un.ord == CSPORT_LINEIN ||
939 		    cp->un.ord == CSPORT_AUX1 ||
940 		    cp->un.ord == CSPORT_DAC) {
941 			sc->sc_in_port  = cp->un.ord;
942 			error = 0;
943 			cs4231_setup_output(sc);
944 		}
945 		break;
946 	}
947 
948 	return (error);
949 }
950 
951 int
952 cs4231_get_port(void *vsc, mixer_ctrl_t *cp)
953 {
954 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
955 	int error = EINVAL;
956 
957 	DPRINTF(("cs4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
958 
959 	switch (cp->dev) {
960 	case CSAUDIO_DAC_LVL:
961 		if (cp->type != AUDIO_MIXER_VALUE)
962 			break;
963 		if (cp->un.value.num_channels == 1)
964 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
965 			    cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
966 			    LINE_INPUT_ATTEN_BITS;
967 		else if (cp->un.value.num_channels == 2) {
968 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
969 			    cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
970 			    LINE_INPUT_ATTEN_BITS;
971 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
972 			    cs4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
973 			    LINE_INPUT_ATTEN_BITS;
974 		} else
975 			break;
976 		error = 0;
977 		break;
978 	case CSAUDIO_LINE_IN_LVL:
979 		if (cp->type != AUDIO_MIXER_VALUE)
980 			break;
981 		if (cp->un.value.num_channels == 1)
982 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
983 			    cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
984 		else if (cp->un.value.num_channels == 2) {
985 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
986 			    cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
987 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
988 			    cs4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
989 		} else
990 			break;
991 		error = 0;
992 		break;
993 	case CSAUDIO_MIC_LVL:
994 		if (cp->type != AUDIO_MIXER_VALUE)
995 			break;
996 		if (cp->un.value.num_channels == 1) {
997 #if 0
998 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
999 			    cs4231_read(sc, CS_MONO_IO_CONTROL) &
1000 			    MONO_INPUT_ATTEN_BITS;
1001 #endif
1002 		} else
1003 			break;
1004 		error = 0;
1005 		break;
1006 	case CSAUDIO_CD_LVL:
1007 		if (cp->type != AUDIO_MIXER_VALUE)
1008 			break;
1009 		if (cp->un.value.num_channels == 1)
1010 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1011 			    cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
1012 			    LINE_INPUT_ATTEN_BITS;
1013 		else if (cp->un.value.num_channels == 2) {
1014 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1015 			    cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
1016 			    LINE_INPUT_ATTEN_BITS;
1017 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1018 			    cs4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
1019 			    LINE_INPUT_ATTEN_BITS;
1020 		}
1021 		else
1022 			break;
1023 		error = 0;
1024 		break;
1025 	case CSAUDIO_MONITOR_LVL:
1026 		if (cp->type != AUDIO_MIXER_VALUE)
1027 			break;
1028 		if (cp->un.value.num_channels != 1)
1029 			break;
1030 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1031 		    cs4231_read(sc, SP_DIGITAL_MIX) >> 2;
1032 		error = 0;
1033 		break;
1034 	case CSAUDIO_OUTPUT_LVL:
1035 		if (cp->type != AUDIO_MIXER_VALUE)
1036 			break;
1037 		if (cp->un.value.num_channels == 1)
1038 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1039 			    sc->sc_volume[CSPORT_SPEAKER].left;
1040 		else if (cp->un.value.num_channels == 2) {
1041 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1042 			    sc->sc_volume[CSPORT_SPEAKER].left;
1043 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1044 			    sc->sc_volume[CSPORT_SPEAKER].right;
1045 		}
1046 		else
1047 			break;
1048 		error = 0;
1049 		break;
1050 	case CSAUDIO_LINE_IN_MUTE:
1051 		if (cp->type != AUDIO_MIXER_ENUM)
1052 			break;
1053 		cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
1054 		error = 0;
1055 		break;
1056 	case CSAUDIO_DAC_MUTE:
1057 		if (cp->type != AUDIO_MIXER_ENUM)
1058 			break;
1059 		cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
1060 		error = 0;
1061 		break;
1062 	case CSAUDIO_CD_MUTE:
1063 		if (cp->type != AUDIO_MIXER_ENUM)
1064 			break;
1065 		cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
1066 		error = 0;
1067 		break;
1068 	case CSAUDIO_MIC_MUTE:
1069 		if (cp->type != AUDIO_MIXER_ENUM)
1070 			break;
1071 		cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
1072 		error = 0;
1073 		break;
1074 	case CSAUDIO_MONITOR_MUTE:
1075 		if (cp->type != AUDIO_MIXER_ENUM)
1076 			break;
1077 		cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
1078 		error = 0;
1079 		break;
1080 	case CSAUDIO_OUTPUT_MUTE:
1081 		if (cp->type != AUDIO_MIXER_ENUM)
1082 			break;
1083 		cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
1084 		error = 0;
1085 		break;
1086 	case CSAUDIO_REC_LVL:
1087 		if (cp->type != AUDIO_MIXER_VALUE)
1088 			break;
1089 		if (cp->un.value.num_channels == 1) {
1090 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1091 			    sc->sc_adc.left;
1092 		} else if (cp->un.value.num_channels == 2) {
1093 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1094 			    sc->sc_adc.left;
1095 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1096 			    sc->sc_adc.right;
1097 		} else
1098 			break;
1099 		error = 0;
1100 		break;
1101 	case CSAUDIO_RECORD_SOURCE:
1102 		if (cp->type != AUDIO_MIXER_ENUM)
1103 			break;
1104 		cp->un.ord = sc->sc_in_port;
1105 		error = 0;
1106 		break;
1107 	case CSAUDIO_OUTPUT:
1108 		if (cp->type != AUDIO_MIXER_ENUM)
1109 			break;
1110 		cp->un.ord = sc->sc_out_port;
1111 		error = 0;
1112 		break;
1113 	}
1114 	return (error);
1115 }
1116 
1117 int
1118 cs4231_query_devinfo(void *vsc, mixer_devinfo_t *dip)
1119 {
1120 	int err = 0;
1121 
1122 	switch (dip->index) {
1123 	case CSAUDIO_MIC_LVL:		/* mono/microphone mixer */
1124 		dip->type = AUDIO_MIXER_VALUE;
1125 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1126 		dip->prev = AUDIO_MIXER_LAST;
1127 		dip->next = CSAUDIO_MIC_MUTE;
1128 		strlcpy(dip->label.name, AudioNmicrophone,
1129 		    sizeof dip->label.name);
1130 		dip->un.v.num_channels = 1;
1131 		strlcpy(dip->un.v.units.name, AudioNvolume,
1132 		    sizeof dip->un.v.units.name);
1133 		break;
1134 	case CSAUDIO_DAC_LVL:		/* dacout */
1135 		dip->type = AUDIO_MIXER_VALUE;
1136 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1137 		dip->prev = AUDIO_MIXER_LAST;
1138 		dip->next = CSAUDIO_DAC_MUTE;
1139 		strlcpy(dip->label.name, AudioNdac,
1140 		    sizeof dip->label.name);
1141 		dip->un.v.num_channels = 2;
1142 		strlcpy(dip->un.v.units.name, AudioNvolume,
1143 		    sizeof dip->un.v.units.name);
1144 		break;
1145 	case CSAUDIO_LINE_IN_LVL:	/* line */
1146 		dip->type = AUDIO_MIXER_VALUE;
1147 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1148 		dip->prev = AUDIO_MIXER_LAST;
1149 		dip->next = CSAUDIO_LINE_IN_MUTE;
1150 		strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
1151 		dip->un.v.num_channels = 2;
1152 		strlcpy(dip->un.v.units.name, AudioNvolume,
1153 		    sizeof dip->un.v.units.name);
1154 		break;
1155 	case CSAUDIO_CD_LVL:		/* cd */
1156 		dip->type = AUDIO_MIXER_VALUE;
1157 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1158 		dip->prev = AUDIO_MIXER_LAST;
1159 		dip->next = CSAUDIO_CD_MUTE;
1160 		strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
1161 		dip->un.v.num_channels = 2;
1162 		strlcpy(dip->un.v.units.name, AudioNvolume,
1163 		    sizeof dip->un.v.units.name);
1164 		break;
1165 	case CSAUDIO_MONITOR_LVL:	/* monitor level */
1166 		dip->type = AUDIO_MIXER_VALUE;
1167 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1168 		dip->prev = AUDIO_MIXER_LAST;
1169 		dip->next = CSAUDIO_MONITOR_MUTE;
1170 		strlcpy(dip->label.name, AudioNmonitor,
1171 		    sizeof dip->label.name);
1172 		dip->un.v.num_channels = 1;
1173 		strlcpy(dip->un.v.units.name, AudioNvolume,
1174 		    sizeof dip->un.v.units.name);
1175 		break;
1176 	case CSAUDIO_OUTPUT_LVL:
1177 		dip->type = AUDIO_MIXER_VALUE;
1178 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1179 		dip->prev = AUDIO_MIXER_LAST;
1180 		dip->next = CSAUDIO_OUTPUT_MUTE;
1181 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1182 		dip->un.v.num_channels = 2;
1183 		strlcpy(dip->un.v.units.name, AudioNvolume,
1184 		    sizeof dip->un.v.units.name);
1185 		break;
1186 	case CSAUDIO_LINE_IN_MUTE:
1187 		dip->type = AUDIO_MIXER_ENUM;
1188 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1189 		dip->prev = CSAUDIO_LINE_IN_LVL;
1190 		dip->next = AUDIO_MIXER_LAST;
1191 		goto mute;
1192 	case CSAUDIO_DAC_MUTE:
1193 		dip->type = AUDIO_MIXER_ENUM;
1194 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1195 		dip->prev = CSAUDIO_DAC_LVL;
1196 		dip->next = AUDIO_MIXER_LAST;
1197 		goto mute;
1198 	case CSAUDIO_CD_MUTE:
1199 		dip->type = AUDIO_MIXER_ENUM;
1200 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1201 		dip->prev = CSAUDIO_CD_LVL;
1202 		dip->next = AUDIO_MIXER_LAST;
1203 		goto mute;
1204 	case CSAUDIO_MIC_MUTE:
1205 		dip->type = AUDIO_MIXER_ENUM;
1206 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1207 		dip->prev = CSAUDIO_MIC_LVL;
1208 		dip->next = AUDIO_MIXER_LAST;
1209 		goto mute;
1210 	case CSAUDIO_MONITOR_MUTE:
1211 		dip->type = AUDIO_MIXER_ENUM;
1212 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1213 		dip->prev = CSAUDIO_MONITOR_LVL;
1214 		dip->next = AUDIO_MIXER_LAST;
1215 		goto mute;
1216 	case CSAUDIO_OUTPUT_MUTE:
1217 		dip->type = AUDIO_MIXER_ENUM;
1218 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1219 		dip->prev = CSAUDIO_OUTPUT_LVL;
1220 		dip->next = AUDIO_MIXER_LAST;
1221 		goto mute;
1222 
1223 	mute:
1224 		strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
1225 		dip->un.e.num_mem = 2;
1226 		strlcpy(dip->un.e.member[0].label.name, AudioNon,
1227 		    sizeof dip->un.e.member[0].label.name);
1228 		dip->un.e.member[0].ord = 0;
1229 		strlcpy(dip->un.e.member[1].label.name, AudioNoff,
1230 		    sizeof dip->un.e.member[1].label.name);
1231 		dip->un.e.member[1].ord = 1;
1232 		break;
1233 	case CSAUDIO_REC_LVL:		/* record level */
1234 		dip->type = AUDIO_MIXER_VALUE;
1235 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1236 		dip->prev = AUDIO_MIXER_LAST;
1237 		dip->next = CSAUDIO_RECORD_SOURCE;
1238 		strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
1239 		dip->un.v.num_channels = 2;
1240 		strlcpy(dip->un.v.units.name, AudioNvolume,
1241 		    sizeof dip->un.v.units.name);
1242 		break;
1243 	case CSAUDIO_RECORD_SOURCE:
1244 		dip->type = AUDIO_MIXER_ENUM;
1245 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1246 		dip->prev = CSAUDIO_REC_LVL;
1247 		dip->next = AUDIO_MIXER_LAST;
1248 		strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1249 		dip->un.e.num_mem = 4;
1250 		strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
1251 		    sizeof dip->un.e.member[0].label.name);
1252 		dip->un.e.member[0].ord = CSPORT_MICROPHONE;
1253 		strlcpy(dip->un.e.member[1].label.name, AudioNline,
1254 		    sizeof dip->un.e.member[1].label.name);
1255 		dip->un.e.member[1].ord = CSPORT_LINEIN;
1256 		strlcpy(dip->un.e.member[2].label.name, AudioNcd,
1257 		    sizeof dip->un.e.member[2].label.name);
1258 		dip->un.e.member[2].ord = CSPORT_AUX1;
1259 		strlcpy(dip->un.e.member[3].label.name, AudioNdac,
1260 		    sizeof dip->un.e.member[3].label.name);
1261 		dip->un.e.member[3].ord = CSPORT_DAC;
1262 		break;
1263 	case CSAUDIO_OUTPUT:
1264 		dip->type = AUDIO_MIXER_ENUM;
1265 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1266 		dip->prev = dip->next = AUDIO_MIXER_LAST;
1267 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1268 		dip->un.e.num_mem = 3;
1269 		strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
1270 		    sizeof dip->un.e.member[0].label.name);
1271 		dip->un.e.member[0].ord = CSPORT_SPEAKER;
1272 		strlcpy(dip->un.e.member[1].label.name, AudioNline,
1273 		    sizeof dip->un.e.member[1].label.name);
1274 		dip->un.e.member[1].ord = CSPORT_LINEOUT;
1275 		strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
1276 		    sizeof dip->un.e.member[2].label.name);
1277 		dip->un.e.member[2].ord = CSPORT_HEADPHONE;
1278 		break;
1279 	case CSAUDIO_INPUT_CLASS:	/* input class descriptor */
1280 		dip->type = AUDIO_MIXER_CLASS;
1281 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1282 		dip->prev = AUDIO_MIXER_LAST;
1283 		dip->next = AUDIO_MIXER_LAST;
1284 		strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1285 		break;
1286 	case CSAUDIO_OUTPUT_CLASS:	/* output class descriptor */
1287 		dip->type = AUDIO_MIXER_CLASS;
1288 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1289 		dip->prev = AUDIO_MIXER_LAST;
1290 		dip->next = AUDIO_MIXER_LAST;
1291 		strlcpy(dip->label.name, AudioCoutputs,
1292 		    sizeof dip->label.name);
1293 		break;
1294 	case CSAUDIO_MONITOR_CLASS:	/* monitor class descriptor */
1295 		dip->type = AUDIO_MIXER_CLASS;
1296 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1297 		dip->prev = AUDIO_MIXER_LAST;
1298 		dip->next = AUDIO_MIXER_LAST;
1299 		strlcpy(dip->label.name, AudioCmonitor,
1300 		    sizeof dip->label.name);
1301 		break;
1302 	case CSAUDIO_RECORD_CLASS:	/* record class descriptor */
1303 		dip->type = AUDIO_MIXER_CLASS;
1304 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1305 		dip->prev = AUDIO_MIXER_LAST;
1306 		dip->next = AUDIO_MIXER_LAST;
1307 		strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1308 		break;
1309 	default:
1310 		err = ENXIO;
1311 	}
1312 
1313 	return (err);
1314 }
1315 
1316 int
1317 cs4231_get_props(void *vsc)
1318 {
1319 	return (AUDIO_PROP_FULLDUPLEX);
1320 }
1321 
1322 /*
1323  * Hardware interrupt handler
1324  */
1325 int
1326 cs4231_intr(void *vsc)
1327 {
1328 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1329 	u_int32_t csr;
1330 	u_int8_t reg, status;
1331 	struct cs_dma *p;
1332 	int r = 0;
1333 
1334 	mtx_enter(&audio_lock);
1335 	csr = APC_READ(sc, APC_CSR);
1336 	APC_WRITE(sc, APC_CSR, csr);
1337 
1338 	if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
1339 		printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
1340 		r = 1;
1341 	}
1342 
1343 	if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
1344 		/* playback interrupt */
1345 		r = 1;
1346 	}
1347 
1348 	if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
1349 		/* general interrupt */
1350 		status = CS_READ(sc, AD1848_STATUS);
1351 		if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
1352 			reg = cs4231_read(sc, CS_IRQ_STATUS);
1353 			if (reg & CS_AFS_PI) {
1354 				cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1355 				cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1356 			}
1357 			if (reg & CS_AFS_CI) {
1358 				cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1359 				cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1360 			}
1361 			CS_WRITE(sc, AD1848_STATUS, 0);
1362 		}
1363 		r = 1;
1364 	}
1365 
1366 
1367 	if (csr & (APC_CSR_PI|APC_CSR_PMI|APC_CSR_PIE|APC_CSR_PD))
1368 		r = 1;
1369 
1370 	if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
1371 		struct cs_channel *chan = &sc->sc_playback;
1372 		u_long nextaddr, togo;
1373 
1374 		p = chan->cs_curdma;
1375 		togo = chan->cs_segsz - chan->cs_cnt;
1376 		if (togo == 0) {
1377 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1378 			chan->cs_cnt = togo = chan->cs_blksz;
1379 		} else {
1380 			nextaddr = APC_READ(sc, APC_PNVA) + chan->cs_blksz;
1381 			if (togo > chan->cs_blksz)
1382 				togo = chan->cs_blksz;
1383 			chan->cs_cnt += togo;
1384 		}
1385 
1386 		APC_WRITE(sc, APC_PNVA, nextaddr);
1387 		APC_WRITE(sc, APC_PNC, togo);
1388 
1389 		if (chan->cs_intr != NULL)
1390 			(*chan->cs_intr)(chan->cs_arg);
1391 		r = 1;
1392 	}
1393 
1394 	if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
1395 		if (csr & APC_CSR_CD) {
1396 			struct cs_channel *chan = &sc->sc_capture;
1397 			u_long nextaddr, togo;
1398 
1399 			p = chan->cs_curdma;
1400 			togo = chan->cs_segsz - chan->cs_cnt;
1401 			if (togo == 0) {
1402 				nextaddr =
1403 				    (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1404 				chan->cs_cnt = togo = chan->cs_blksz;
1405 			} else {
1406 				nextaddr = APC_READ(sc, APC_CNVA) +
1407 				    chan->cs_blksz;
1408 				if (togo > chan->cs_blksz)
1409 					togo = chan->cs_blksz;
1410 				chan->cs_cnt += togo;
1411 			}
1412 
1413 			APC_WRITE(sc, APC_CNVA, nextaddr);
1414 			APC_WRITE(sc, APC_CNC, togo);
1415 
1416 			if (chan->cs_intr != NULL)
1417 				(*chan->cs_intr)(chan->cs_arg);
1418 		}
1419 		r = 1;
1420 	}
1421 
1422 	if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
1423 		/* capture empty */
1424 		r = 1;
1425 	}
1426 
1427 	mtx_leave(&audio_lock);
1428 	return (r);
1429 }
1430 
1431 void *
1432 cs4231_alloc(void *vsc, int direction, size_t size, int pool, int flags)
1433 {
1434 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1435 	bus_dma_tag_t dmat = sc->sc_dmatag;
1436 	struct cs_dma *p;
1437 
1438 	p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1439 	if (p == NULL)
1440 		return (NULL);
1441 
1442 	if (bus_dmamap_create(dmat, size, 1, size, 0,
1443 	    BUS_DMA_NOWAIT, &p->dmamap) != 0)
1444 		goto fail;
1445 
1446 	p->size = size;
1447 
1448 	if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
1449 	    nitems(p->segs), &p->nsegs,
1450 	    BUS_DMA_NOWAIT) != 0)
1451 		goto fail1;
1452 
1453 	if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
1454 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
1455 		goto fail2;
1456 
1457 	if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
1458 	    BUS_DMA_NOWAIT) != 0)
1459 		goto fail3;
1460 
1461 	p->next = sc->sc_dmas;
1462 	sc->sc_dmas = p;
1463 	return (p->addr);
1464 
1465 fail3:
1466 	bus_dmamem_unmap(dmat, p->addr, p->size);
1467 fail2:
1468 	bus_dmamem_free(dmat, p->segs, p->nsegs);
1469 fail1:
1470 	bus_dmamap_destroy(dmat, p->dmamap);
1471 fail:
1472 	free(p, pool, 0);
1473 	return (NULL);
1474 }
1475 
1476 void
1477 cs4231_free(void *vsc, void *ptr, int pool)
1478 {
1479 	struct cs4231_softc *sc = vsc;
1480 	bus_dma_tag_t dmat = sc->sc_dmatag;
1481 	struct cs_dma *p, **pp;
1482 
1483 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1484 		if (p->addr != ptr)
1485 			continue;
1486 		bus_dmamap_unload(dmat, p->dmamap);
1487 		bus_dmamem_unmap(dmat, p->addr, p->size);
1488 		bus_dmamem_free(dmat, p->segs, p->nsegs);
1489 		bus_dmamap_destroy(dmat, p->dmamap);
1490 		*pp = p->next;
1491 		free(p, pool, 0);
1492 		return;
1493 	}
1494 	printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1495 }
1496 
1497 int
1498 cs4231_trigger_output(void *vsc, void *start, void *end, int blksize,
1499     void (*intr)(void *), void *arg, struct audio_params *param)
1500 {
1501 	struct cs4231_softc *sc = vsc;
1502 	struct cs_channel *chan = &sc->sc_playback;
1503 	struct cs_dma *p;
1504 	u_int32_t csr;
1505 	u_long n;
1506 
1507 	if (chan->cs_locked != 0) {
1508 		printf("%s: trigger_output: already running\n",
1509 		    sc->sc_dev.dv_xname);
1510 		return (EINVAL);
1511 	}
1512 
1513 	chan->cs_locked = 1;
1514 	chan->cs_intr = intr;
1515 	chan->cs_arg = arg;
1516 
1517 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1518 		/*EMPTY*/;
1519 	if (p == NULL) {
1520 		printf("%s: trigger_output: bad addr: %p\n",
1521 		    sc->sc_dev.dv_xname, start);
1522 		return (EINVAL);
1523 	}
1524 
1525 	n = (char *)end - (char *)start;
1526 
1527 	/*
1528 	 * Do only `blksize' at a time, so audio_pint() is kept
1529 	 * synchronous with us...
1530 	 */
1531 	chan->cs_blksz = blksize;
1532 	chan->cs_curdma = p;
1533 	chan->cs_segsz = n;
1534 
1535 	if (n > chan->cs_blksz)
1536 		n = chan->cs_blksz;
1537 
1538 	chan->cs_cnt = n;
1539 
1540 	mtx_enter(&audio_lock);
1541 	csr = APC_READ(sc, APC_CSR);
1542 
1543 	APC_WRITE(sc, APC_PNVA, (u_long)p->dmamap->dm_segs[0].ds_addr);
1544 	APC_WRITE(sc, APC_PNC, (u_long)n);
1545 
1546 	if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
1547 		APC_WRITE(sc, APC_CSR,
1548 		    APC_READ(sc, APC_CSR) & ~(APC_CSR_PIE | APC_CSR_PPAUSE));
1549 		APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) |
1550 		    APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE |
1551 		    APC_CSR_PMIE | APC_CSR_PDMA_GO);
1552 		cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1553 		cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1554 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1555 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
1556 	}
1557 	mtx_leave(&audio_lock);
1558 	return (0);
1559 }
1560 
1561 int
1562 cs4231_trigger_input(void *vsc, void *start, void *end, int blksize,
1563     void (*intr)(void *), void *arg, struct audio_params *param)
1564 {
1565 	struct cs4231_softc *sc = vsc;
1566 	struct cs_channel *chan = &sc->sc_capture;
1567 	struct cs_dma *p;
1568 	u_int32_t csr;
1569 	u_long n;
1570 
1571 	if (chan->cs_locked != 0) {
1572 		printf("%s: trigger_input: already running\n",
1573 		    sc->sc_dev.dv_xname);
1574 		return (EINVAL);
1575 	}
1576 	chan->cs_locked = 1;
1577 	chan->cs_intr = intr;
1578 	chan->cs_arg = arg;
1579 
1580 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1581 		/*EMPTY*/;
1582 	if (p == NULL) {
1583 		printf("%s: trigger_input: bad addr: %p\n",
1584 		    sc->sc_dev.dv_xname, start);
1585 		return (EINVAL);
1586 	}
1587 
1588 	n = (char *)end - (char *)start;
1589 
1590 	/*
1591 	 * Do only `blksize' at a time, so audio_cint() is kept
1592 	 * synchronous with us...
1593 	 */
1594 	chan->cs_blksz = blksize;
1595 	chan->cs_curdma = p;
1596 	chan->cs_segsz = n;
1597 
1598 	if (n > chan->cs_blksz)
1599 		n = chan->cs_blksz;
1600 	chan->cs_cnt = n;
1601 
1602 	mtx_enter(&audio_lock);
1603 	APC_WRITE(sc, APC_CNVA, p->dmamap->dm_segs[0].ds_addr);
1604 	APC_WRITE(sc, APC_CNC, (u_long)n);
1605 
1606 	csr = APC_READ(sc, APC_CSR);
1607 	if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
1608 		csr &= APC_CSR_CPAUSE;
1609 		csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
1610 		    APC_CSR_CDMA_GO;
1611 		APC_WRITE(sc, APC_CSR, csr);
1612 		cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1613 		cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1614 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1615 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1616 	}
1617 
1618 	if (APC_READ(sc, APC_CSR) & APC_CSR_CD) {
1619 		u_long nextaddr, togo;
1620 
1621 		p = chan->cs_curdma;
1622 		togo = chan->cs_segsz - chan->cs_cnt;
1623 		if (togo == 0) {
1624 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1625 			chan->cs_cnt = togo = chan->cs_blksz;
1626 		} else {
1627 			nextaddr = APC_READ(sc, APC_CNVA) + chan->cs_blksz;
1628 			if (togo > chan->cs_blksz)
1629 				togo = chan->cs_blksz;
1630 			chan->cs_cnt += togo;
1631 		}
1632 
1633 		APC_WRITE(sc, APC_CNVA, nextaddr);
1634 		APC_WRITE(sc, APC_CNC, togo);
1635 	}
1636 
1637 	mtx_leave(&audio_lock);
1638 	return (0);
1639 }
1640