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