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