xref: /openbsd/sys/dev/sbus/cs4231.c (revision 891d7ab6)
1 /*	$OpenBSD: cs4231.c,v 1.31 2011/04/05 19:54:35 jasper 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 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 int
1312 cs4231_get_props(void *vsc)
1313 {
1314 	return (AUDIO_PROP_FULLDUPLEX);
1315 }
1316 
1317 /*
1318  * Hardware interrupt handler
1319  */
1320 int
1321 cs4231_intr(void *vsc)
1322 {
1323 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1324 	u_int32_t csr;
1325 	u_int8_t reg, status;
1326 	struct cs_dma *p;
1327 	int r = 0;
1328 
1329 	csr = APC_READ(sc, APC_CSR);
1330 	APC_WRITE(sc, APC_CSR, csr);
1331 
1332 	if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
1333 		printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
1334 		r = 1;
1335 	}
1336 
1337 	if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
1338 		/* playback interrupt */
1339 		r = 1;
1340 	}
1341 
1342 	if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
1343 		/* general interrupt */
1344 		status = CS_READ(sc, AD1848_STATUS);
1345 		if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
1346 			reg = cs4231_read(sc, CS_IRQ_STATUS);
1347 			if (reg & CS_AFS_PI) {
1348 				cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1349 				cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1350 			}
1351 			if (reg & CS_AFS_CI) {
1352 				cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1353 				cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1354 			}
1355 			CS_WRITE(sc, AD1848_STATUS, 0);
1356 		}
1357 		r = 1;
1358 	}
1359 
1360 
1361 	if (csr & (APC_CSR_PI|APC_CSR_PMI|APC_CSR_PIE|APC_CSR_PD))
1362 		r = 1;
1363 
1364 	if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
1365 		struct cs_channel *chan = &sc->sc_playback;
1366 		u_long nextaddr, togo;
1367 
1368 		p = chan->cs_curdma;
1369 		togo = chan->cs_segsz - chan->cs_cnt;
1370 		if (togo == 0) {
1371 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1372 			chan->cs_cnt = togo = chan->cs_blksz;
1373 		} else {
1374 			nextaddr = APC_READ(sc, APC_PNVA) + chan->cs_blksz;
1375 			if (togo > chan->cs_blksz)
1376 				togo = chan->cs_blksz;
1377 			chan->cs_cnt += togo;
1378 		}
1379 
1380 		APC_WRITE(sc, APC_PNVA, nextaddr);
1381 		APC_WRITE(sc, APC_PNC, togo);
1382 
1383 		if (chan->cs_intr != NULL)
1384 			(*chan->cs_intr)(chan->cs_arg);
1385 		r = 1;
1386 	}
1387 
1388 	if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
1389 		if (csr & APC_CSR_CD) {
1390 			struct cs_channel *chan = &sc->sc_capture;
1391 			u_long nextaddr, togo;
1392 
1393 			p = chan->cs_curdma;
1394 			togo = chan->cs_segsz - chan->cs_cnt;
1395 			if (togo == 0) {
1396 				nextaddr =
1397 				    (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1398 				chan->cs_cnt = togo = chan->cs_blksz;
1399 			} else {
1400 				nextaddr = APC_READ(sc, APC_CNVA) +
1401 				    chan->cs_blksz;
1402 				if (togo > chan->cs_blksz)
1403 					togo = chan->cs_blksz;
1404 				chan->cs_cnt += togo;
1405 			}
1406 
1407 			APC_WRITE(sc, APC_CNVA, nextaddr);
1408 			APC_WRITE(sc, APC_CNC, togo);
1409 
1410 			if (chan->cs_intr != NULL)
1411 				(*chan->cs_intr)(chan->cs_arg);
1412 		}
1413 		r = 1;
1414 	}
1415 
1416 	if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
1417 		/* capture empty */
1418 		r = 1;
1419 	}
1420 
1421 	return (r);
1422 }
1423 
1424 void *
1425 cs4231_alloc(void *vsc, int direction, size_t size, int pool, int flags)
1426 {
1427 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1428 	bus_dma_tag_t dmat = sc->sc_dmatag;
1429 	struct cs_dma *p;
1430 
1431 	p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1432 	if (p == NULL)
1433 		return (NULL);
1434 
1435 	if (bus_dmamap_create(dmat, size, 1, size, 0,
1436 	    BUS_DMA_NOWAIT, &p->dmamap) != 0)
1437 		goto fail;
1438 
1439 	p->size = size;
1440 
1441 	if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
1442 	    nitems(p->segs), &p->nsegs,
1443 	    BUS_DMA_NOWAIT) != 0)
1444 		goto fail1;
1445 
1446 	if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
1447 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
1448 		goto fail2;
1449 
1450 	if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
1451 	    BUS_DMA_NOWAIT) != 0)
1452 		goto fail3;
1453 
1454 	p->next = sc->sc_dmas;
1455 	sc->sc_dmas = p;
1456 	return (p->addr);
1457 
1458 fail3:
1459 	bus_dmamem_unmap(dmat, p->addr, p->size);
1460 fail2:
1461 	bus_dmamem_free(dmat, p->segs, p->nsegs);
1462 fail1:
1463 	bus_dmamap_destroy(dmat, p->dmamap);
1464 fail:
1465 	free(p, pool);
1466 	return (NULL);
1467 }
1468 
1469 void
1470 cs4231_free(void *vsc, void *ptr, int pool)
1471 {
1472 	struct cs4231_softc *sc = vsc;
1473 	bus_dma_tag_t dmat = sc->sc_dmatag;
1474 	struct cs_dma *p, **pp;
1475 
1476 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1477 		if (p->addr != ptr)
1478 			continue;
1479 		bus_dmamap_unload(dmat, p->dmamap);
1480 		bus_dmamem_unmap(dmat, p->addr, p->size);
1481 		bus_dmamem_free(dmat, p->segs, p->nsegs);
1482 		bus_dmamap_destroy(dmat, p->dmamap);
1483 		*pp = p->next;
1484 		free(p, pool);
1485 		return;
1486 	}
1487 	printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1488 }
1489 
1490 int
1491 cs4231_trigger_output(void *vsc, void *start, void *end, int blksize,
1492     void (*intr)(void *), void *arg, struct audio_params *param)
1493 {
1494 	struct cs4231_softc *sc = vsc;
1495 	struct cs_channel *chan = &sc->sc_playback;
1496 	struct cs_dma *p;
1497 	u_int32_t csr;
1498 	u_long n;
1499 
1500 	if (chan->cs_locked != 0) {
1501 		printf("%s: trigger_output: already running\n",
1502 		    sc->sc_dev.dv_xname);
1503 		return (EINVAL);
1504 	}
1505 
1506 	chan->cs_locked = 1;
1507 	chan->cs_intr = intr;
1508 	chan->cs_arg = arg;
1509 
1510 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1511 		/*EMPTY*/;
1512 	if (p == NULL) {
1513 		printf("%s: trigger_output: bad addr: %p\n",
1514 		    sc->sc_dev.dv_xname, start);
1515 		return (EINVAL);
1516 	}
1517 
1518 	n = (char *)end - (char *)start;
1519 
1520 	/*
1521 	 * Do only `blksize' at a time, so audio_pint() is kept
1522 	 * synchronous with us...
1523 	 */
1524 	chan->cs_blksz = blksize;
1525 	chan->cs_curdma = p;
1526 	chan->cs_segsz = n;
1527 
1528 	if (n > chan->cs_blksz)
1529 		n = chan->cs_blksz;
1530 
1531 	chan->cs_cnt = n;
1532 
1533 	csr = APC_READ(sc, APC_CSR);
1534 
1535 	APC_WRITE(sc, APC_PNVA, (u_long)p->dmamap->dm_segs[0].ds_addr);
1536 	APC_WRITE(sc, APC_PNC, (u_long)n);
1537 
1538 	if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
1539 		APC_WRITE(sc, APC_CSR,
1540 		    APC_READ(sc, APC_CSR) & ~(APC_CSR_PIE | APC_CSR_PPAUSE));
1541 		APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) |
1542 		    APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE |
1543 		    APC_CSR_PMIE | APC_CSR_PDMA_GO);
1544 		cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1545 		cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1546 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1547 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
1548 	}
1549 	return (0);
1550 }
1551 
1552 int
1553 cs4231_trigger_input(void *vsc, void *start, void *end, int blksize,
1554     void (*intr)(void *), void *arg, struct audio_params *param)
1555 {
1556 	struct cs4231_softc *sc = vsc;
1557 	struct cs_channel *chan = &sc->sc_capture;
1558 	struct cs_dma *p;
1559 	u_int32_t csr;
1560 	u_long n;
1561 
1562 	if (chan->cs_locked != 0) {
1563 		printf("%s: trigger_input: already running\n",
1564 		    sc->sc_dev.dv_xname);
1565 		return (EINVAL);
1566 	}
1567 	chan->cs_locked = 1;
1568 	chan->cs_intr = intr;
1569 	chan->cs_arg = arg;
1570 
1571 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1572 		/*EMPTY*/;
1573 	if (p == NULL) {
1574 		printf("%s: trigger_input: bad addr: %p\n",
1575 		    sc->sc_dev.dv_xname, start);
1576 		return (EINVAL);
1577 	}
1578 
1579 	n = (char *)end - (char *)start;
1580 
1581 	/*
1582 	 * Do only `blksize' at a time, so audio_cint() is kept
1583 	 * synchronous with us...
1584 	 */
1585 	chan->cs_blksz = blksize;
1586 	chan->cs_curdma = p;
1587 	chan->cs_segsz = n;
1588 
1589 	if (n > chan->cs_blksz)
1590 		n = chan->cs_blksz;
1591 	chan->cs_cnt = n;
1592 
1593 	APC_WRITE(sc, APC_CNVA, p->dmamap->dm_segs[0].ds_addr);
1594 	APC_WRITE(sc, APC_CNC, (u_long)n);
1595 
1596 	csr = APC_READ(sc, APC_CSR);
1597 	if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
1598 		csr &= APC_CSR_CPAUSE;
1599 		csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
1600 		    APC_CSR_CDMA_GO;
1601 		APC_WRITE(sc, APC_CSR, csr);
1602 		cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1603 		cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1604 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1605 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1606 	}
1607 
1608 	if (APC_READ(sc, APC_CSR) & APC_CSR_CD) {
1609 		u_long nextaddr, togo;
1610 
1611 		p = chan->cs_curdma;
1612 		togo = chan->cs_segsz - chan->cs_cnt;
1613 		if (togo == 0) {
1614 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1615 			chan->cs_cnt = togo = chan->cs_blksz;
1616 		} else {
1617 			nextaddr = APC_READ(sc, APC_CNVA) + chan->cs_blksz;
1618 			if (togo > chan->cs_blksz)
1619 				togo = chan->cs_blksz;
1620 			chan->cs_cnt += togo;
1621 		}
1622 
1623 		APC_WRITE(sc, APC_CNVA, nextaddr);
1624 		APC_WRITE(sc, APC_CNC, togo);
1625 	}
1626 
1627 	return (0);
1628 }
1629