xref: /openbsd-src/sys/dev/sbus/cs4231.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: cs4231.c,v 1.37 2016/09/19 06:46:44 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_ULINEAR:
498 		if (p->precision != 8)
499 			return (EINVAL);
500 		bits = FMT_PCM8 >> 5;
501 		break;
502 	case AUDIO_ENCODING_SLINEAR_BE:
503 		if (p->precision == 16)
504 			bits = FMT_TWOS_COMP_BE >> 5;
505 		else
506 			return (EINVAL);
507 		break;
508 	case AUDIO_ENCODING_ULINEAR_LE:
509 		if (p->precision == 8)
510 			bits = FMT_PCM8 >> 5;
511 		else
512 			return (EINVAL);
513 		break;
514 	case AUDIO_ENCODING_ULINEAR_BE:
515 		if (p->precision == 8)
516 			bits = FMT_PCM8 >> 5;
517 		else
518 			return (EINVAL);
519 		break;
520 	default:
521 		return (EINVAL);
522 	}
523 
524 	if (p->channels != 1 && p->channels != 2)
525 		return (EINVAL);
526 
527 	err = cs4231_set_speed(sc, &p->sample_rate);
528 	if (err)
529 		return (err);
530 
531 	p->bps = AUDIO_BPS(p->precision);
532 	r->bps = AUDIO_BPS(r->precision);
533 	p->msb = r->msb = 1;
534 
535 	sc->sc_format_bits = bits;
536 	sc->sc_channels = p->channels;
537 	sc->sc_precision = p->precision;
538 	sc->sc_need_commit = 1;
539 	return (0);
540 }
541 
542 int
543 cs4231_round_blocksize(void *vsc, int blk)
544 {
545 	return ((blk + 3) & (-4));
546 }
547 
548 int
549 cs4231_commit_settings(void *vsc)
550 {
551 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
552 	int tries;
553 	u_int8_t r, fs;
554 
555 	if (sc->sc_need_commit == 0)
556 		return (0);
557 
558 	fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
559 	if (sc->sc_channels == 2)
560 		fs |= FMT_STEREO;
561 
562 	/* XXX: this is called before DMA is setup, useful ? */
563 	mtx_enter(&audio_lock);
564 
565 	r = cs4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
566 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
567 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
568 	CS_WRITE(sc, AD1848_IDATA, r);
569 
570 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
571 	CS_WRITE(sc, AD1848_IDATA, fs);
572 	CS_READ(sc, AD1848_IDATA);
573 	CS_READ(sc, AD1848_IDATA);
574 	tries = CS_TIMEOUT;
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 fspb\n", sc->sc_dev.dv_xname);
580 
581 	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
582 	CS_WRITE(sc, AD1848_IDATA, fs);
583 	CS_READ(sc, AD1848_IDATA);
584 	CS_READ(sc, AD1848_IDATA);
585 	for (tries = CS_TIMEOUT;
586 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
587 		DELAY(10);
588 	if (tries == 0)
589 		printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
590 
591 	CS_WRITE(sc, AD1848_IADDR, 0);
592 	for (tries = CS_TIMEOUT;
593 	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
594 		DELAY(10);
595 	if (tries == 0)
596 		printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
597 
598 	CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
599 	for (tries = CS_TIMEOUT;
600 	     tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
601 		DELAY(10);
602 	if (tries == 0)
603 		printf("%s: timeout waiting for autocalibration\n",
604 		    sc->sc_dev.dv_xname);
605 
606 	mtx_leave(&audio_lock);
607 
608 	sc->sc_need_commit = 0;
609 	return (0);
610 }
611 
612 int
613 cs4231_halt_output(void *vsc)
614 {
615 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
616 
617 	/* XXX Kills some capture bits */
618 	mtx_enter(&audio_lock);
619 	APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) &
620 	    ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE |
621 	      APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE));
622 	cs4231_write(sc, SP_INTERFACE_CONFIG,
623 	    cs4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
624 	sc->sc_playback.cs_locked = 0;
625 	mtx_leave(&audio_lock);
626 	return (0);
627 }
628 
629 int
630 cs4231_halt_input(void *vsc)
631 {
632 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
633 
634 	/* XXX Kills some playback bits */
635 	mtx_enter(&audio_lock);
636 	APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE);
637 	cs4231_write(sc, SP_INTERFACE_CONFIG,
638 	    cs4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
639 	sc->sc_capture.cs_locked = 0;
640 	mtx_leave(&audio_lock);
641 	return (0);
642 }
643 
644 int
645 cs4231_set_port(void *vsc, mixer_ctrl_t *cp)
646 {
647 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
648 	int error = EINVAL;
649 
650 	DPRINTF(("cs4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
651 
652 	switch (cp->dev) {
653 	case CSAUDIO_DAC_LVL:
654 		if (cp->type != AUDIO_MIXER_VALUE)
655 			break;
656 		if (cp->un.value.num_channels == 1)
657 			cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
658 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
659 			    LINE_INPUT_ATTEN_BITS);
660 		else if (cp->un.value.num_channels == 2) {
661 			cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
662 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
663 			    LINE_INPUT_ATTEN_BITS);
664 			cs4231_write(sc, SP_RIGHT_AUX1_CONTROL,
665 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
666 			    LINE_INPUT_ATTEN_BITS);
667 		} else
668 			break;
669 		error = 0;
670 		break;
671 	case CSAUDIO_LINE_IN_LVL:
672 		if (cp->type != AUDIO_MIXER_VALUE)
673 			break;
674 		if (cp->un.value.num_channels == 1)
675 			cs4231_write(sc, CS_LEFT_LINE_CONTROL,
676 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
677 			    AUX_INPUT_ATTEN_BITS);
678 		else if (cp->un.value.num_channels == 2) {
679 			cs4231_write(sc, CS_LEFT_LINE_CONTROL,
680 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
681 			    AUX_INPUT_ATTEN_BITS);
682 			cs4231_write(sc, CS_RIGHT_LINE_CONTROL,
683 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
684 			    AUX_INPUT_ATTEN_BITS);
685 		} else
686 			break;
687 		error = 0;
688 		break;
689 	case CSAUDIO_MIC_LVL:
690 		if (cp->type != AUDIO_MIXER_VALUE)
691 			break;
692 		if (cp->un.value.num_channels == 1) {
693 #if 0
694 			cs4231_write(sc, CS_MONO_IO_CONTROL,
695 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
696 			    MONO_INPUT_ATTEN_BITS);
697 #endif
698 		} else
699 			break;
700 		error = 0;
701 		break;
702 	case CSAUDIO_CD_LVL:
703 		if (cp->type != AUDIO_MIXER_VALUE)
704 			break;
705 		if (cp->un.value.num_channels == 1) {
706 			cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
707 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
708 			    LINE_INPUT_ATTEN_BITS);
709 		} else if (cp->un.value.num_channels == 2) {
710 			cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
711 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
712 			    LINE_INPUT_ATTEN_BITS);
713 			cs4231_write(sc, SP_RIGHT_AUX2_CONTROL,
714 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
715 			    LINE_INPUT_ATTEN_BITS);
716 		} else
717 			break;
718 		error = 0;
719 		break;
720 	case CSAUDIO_MONITOR_LVL:
721 		if (cp->type != AUDIO_MIXER_VALUE)
722 			break;
723 		if (cp->un.value.num_channels == 1)
724 			cs4231_write(sc, SP_DIGITAL_MIX,
725 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
726 		else
727 			break;
728 		error = 0;
729 		break;
730 	case CSAUDIO_OUTPUT_LVL:
731 		if (cp->type != AUDIO_MIXER_VALUE)
732 			break;
733 		if (cp->un.value.num_channels == 1) {
734 			sc->sc_volume[CSPORT_SPEAKER].left =
735 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
736 			sc->sc_volume[CSPORT_SPEAKER].right =
737 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
738 		}
739 		else if (cp->un.value.num_channels == 2) {
740 			sc->sc_volume[CSPORT_SPEAKER].left =
741 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
742 			sc->sc_volume[CSPORT_SPEAKER].right =
743 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
744 		}
745 		else
746 			break;
747 
748 		cs4231_setup_output(sc);
749 		error = 0;
750 		break;
751 	case CSAUDIO_OUTPUT:
752 		if (cp->type != AUDIO_MIXER_ENUM)
753 			break;
754 		if (cp->un.ord != CSPORT_LINEOUT &&
755 		    cp->un.ord != CSPORT_SPEAKER &&
756 		    cp->un.ord != CSPORT_HEADPHONE)
757 			return (EINVAL);
758 		sc->sc_out_port = cp->un.ord;
759 		cs4231_setup_output(sc);
760 		error = 0;
761 		break;
762 	case CSAUDIO_LINE_IN_MUTE:
763 		if (cp->type != AUDIO_MIXER_ENUM)
764 			break;
765 		sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
766 		error = 0;
767 		break;
768 	case CSAUDIO_DAC_MUTE:
769 		if (cp->type != AUDIO_MIXER_ENUM)
770 			break;
771 		sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
772 		error = 0;
773 		break;
774 	case CSAUDIO_CD_MUTE:
775 		if (cp->type != AUDIO_MIXER_ENUM)
776 			break;
777 		sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
778 		error = 0;
779 		break;
780 	case CSAUDIO_MIC_MUTE:
781 		if (cp->type != AUDIO_MIXER_ENUM)
782 			break;
783 		sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
784 		error = 0;
785 		break;
786 	case CSAUDIO_MONITOR_MUTE:
787 		if (cp->type != AUDIO_MIXER_ENUM)
788 			break;
789 		sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
790 		error = 0;
791 		break;
792 	case CSAUDIO_OUTPUT_MUTE:
793 		if (cp->type != AUDIO_MIXER_ENUM)
794 			break;
795 		sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
796 		cs4231_setup_output(sc);
797 		error = 0;
798 		break;
799 	case CSAUDIO_REC_LVL:
800 		if (cp->type != AUDIO_MIXER_VALUE)
801 			break;
802 		if (cp->un.value.num_channels == 1) {
803 			sc->sc_adc.left =
804 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
805 			sc->sc_adc.right =
806 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
807 		} else if (cp->un.value.num_channels == 2) {
808 			sc->sc_adc.left =
809 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
810 			sc->sc_adc.right =
811 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
812 		} else
813 			break;
814 		cs4231_setup_output(sc);
815 		error = 0;
816 		break;
817 	case CSAUDIO_RECORD_SOURCE:
818 		if (cp->type != AUDIO_MIXER_ENUM)
819 			break;
820 		if (cp->un.ord == CSPORT_MICROPHONE ||
821 		    cp->un.ord == CSPORT_LINEIN ||
822 		    cp->un.ord == CSPORT_AUX1 ||
823 		    cp->un.ord == CSPORT_DAC) {
824 			sc->sc_in_port  = cp->un.ord;
825 			error = 0;
826 			cs4231_setup_output(sc);
827 		}
828 		break;
829 	}
830 
831 	return (error);
832 }
833 
834 int
835 cs4231_get_port(void *vsc, mixer_ctrl_t *cp)
836 {
837 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
838 	int error = EINVAL;
839 
840 	DPRINTF(("cs4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
841 
842 	switch (cp->dev) {
843 	case CSAUDIO_DAC_LVL:
844 		if (cp->type != AUDIO_MIXER_VALUE)
845 			break;
846 		if (cp->un.value.num_channels == 1)
847 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
848 			    cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
849 			    LINE_INPUT_ATTEN_BITS;
850 		else if (cp->un.value.num_channels == 2) {
851 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
852 			    cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
853 			    LINE_INPUT_ATTEN_BITS;
854 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
855 			    cs4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
856 			    LINE_INPUT_ATTEN_BITS;
857 		} else
858 			break;
859 		error = 0;
860 		break;
861 	case CSAUDIO_LINE_IN_LVL:
862 		if (cp->type != AUDIO_MIXER_VALUE)
863 			break;
864 		if (cp->un.value.num_channels == 1)
865 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
866 			    cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
867 		else if (cp->un.value.num_channels == 2) {
868 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
869 			    cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
870 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
871 			    cs4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
872 		} else
873 			break;
874 		error = 0;
875 		break;
876 	case CSAUDIO_MIC_LVL:
877 		if (cp->type != AUDIO_MIXER_VALUE)
878 			break;
879 		if (cp->un.value.num_channels == 1) {
880 #if 0
881 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
882 			    cs4231_read(sc, CS_MONO_IO_CONTROL) &
883 			    MONO_INPUT_ATTEN_BITS;
884 #endif
885 		} else
886 			break;
887 		error = 0;
888 		break;
889 	case CSAUDIO_CD_LVL:
890 		if (cp->type != AUDIO_MIXER_VALUE)
891 			break;
892 		if (cp->un.value.num_channels == 1)
893 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
894 			    cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
895 			    LINE_INPUT_ATTEN_BITS;
896 		else if (cp->un.value.num_channels == 2) {
897 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
898 			    cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
899 			    LINE_INPUT_ATTEN_BITS;
900 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
901 			    cs4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
902 			    LINE_INPUT_ATTEN_BITS;
903 		}
904 		else
905 			break;
906 		error = 0;
907 		break;
908 	case CSAUDIO_MONITOR_LVL:
909 		if (cp->type != AUDIO_MIXER_VALUE)
910 			break;
911 		if (cp->un.value.num_channels != 1)
912 			break;
913 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
914 		    cs4231_read(sc, SP_DIGITAL_MIX) >> 2;
915 		error = 0;
916 		break;
917 	case CSAUDIO_OUTPUT_LVL:
918 		if (cp->type != AUDIO_MIXER_VALUE)
919 			break;
920 		if (cp->un.value.num_channels == 1)
921 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
922 			    sc->sc_volume[CSPORT_SPEAKER].left;
923 		else if (cp->un.value.num_channels == 2) {
924 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
925 			    sc->sc_volume[CSPORT_SPEAKER].left;
926 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
927 			    sc->sc_volume[CSPORT_SPEAKER].right;
928 		}
929 		else
930 			break;
931 		error = 0;
932 		break;
933 	case CSAUDIO_LINE_IN_MUTE:
934 		if (cp->type != AUDIO_MIXER_ENUM)
935 			break;
936 		cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
937 		error = 0;
938 		break;
939 	case CSAUDIO_DAC_MUTE:
940 		if (cp->type != AUDIO_MIXER_ENUM)
941 			break;
942 		cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
943 		error = 0;
944 		break;
945 	case CSAUDIO_CD_MUTE:
946 		if (cp->type != AUDIO_MIXER_ENUM)
947 			break;
948 		cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
949 		error = 0;
950 		break;
951 	case CSAUDIO_MIC_MUTE:
952 		if (cp->type != AUDIO_MIXER_ENUM)
953 			break;
954 		cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
955 		error = 0;
956 		break;
957 	case CSAUDIO_MONITOR_MUTE:
958 		if (cp->type != AUDIO_MIXER_ENUM)
959 			break;
960 		cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
961 		error = 0;
962 		break;
963 	case CSAUDIO_OUTPUT_MUTE:
964 		if (cp->type != AUDIO_MIXER_ENUM)
965 			break;
966 		cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
967 		error = 0;
968 		break;
969 	case CSAUDIO_REC_LVL:
970 		if (cp->type != AUDIO_MIXER_VALUE)
971 			break;
972 		if (cp->un.value.num_channels == 1) {
973 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
974 			    sc->sc_adc.left;
975 		} else if (cp->un.value.num_channels == 2) {
976 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
977 			    sc->sc_adc.left;
978 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
979 			    sc->sc_adc.right;
980 		} else
981 			break;
982 		error = 0;
983 		break;
984 	case CSAUDIO_RECORD_SOURCE:
985 		if (cp->type != AUDIO_MIXER_ENUM)
986 			break;
987 		cp->un.ord = sc->sc_in_port;
988 		error = 0;
989 		break;
990 	case CSAUDIO_OUTPUT:
991 		if (cp->type != AUDIO_MIXER_ENUM)
992 			break;
993 		cp->un.ord = sc->sc_out_port;
994 		error = 0;
995 		break;
996 	}
997 	return (error);
998 }
999 
1000 int
1001 cs4231_query_devinfo(void *vsc, mixer_devinfo_t *dip)
1002 {
1003 	int err = 0;
1004 
1005 	switch (dip->index) {
1006 	case CSAUDIO_MIC_LVL:		/* mono/microphone mixer */
1007 		dip->type = AUDIO_MIXER_VALUE;
1008 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1009 		dip->prev = AUDIO_MIXER_LAST;
1010 		dip->next = CSAUDIO_MIC_MUTE;
1011 		strlcpy(dip->label.name, AudioNmicrophone,
1012 		    sizeof dip->label.name);
1013 		dip->un.v.num_channels = 1;
1014 		strlcpy(dip->un.v.units.name, AudioNvolume,
1015 		    sizeof dip->un.v.units.name);
1016 		break;
1017 	case CSAUDIO_DAC_LVL:		/* dacout */
1018 		dip->type = AUDIO_MIXER_VALUE;
1019 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1020 		dip->prev = AUDIO_MIXER_LAST;
1021 		dip->next = CSAUDIO_DAC_MUTE;
1022 		strlcpy(dip->label.name, AudioNdac,
1023 		    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_LINE_IN_LVL:	/* line */
1029 		dip->type = AUDIO_MIXER_VALUE;
1030 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1031 		dip->prev = AUDIO_MIXER_LAST;
1032 		dip->next = CSAUDIO_LINE_IN_MUTE;
1033 		strlcpy(dip->label.name, AudioNline, 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_CD_LVL:		/* cd */
1039 		dip->type = AUDIO_MIXER_VALUE;
1040 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1041 		dip->prev = AUDIO_MIXER_LAST;
1042 		dip->next = CSAUDIO_CD_MUTE;
1043 		strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
1044 		dip->un.v.num_channels = 2;
1045 		strlcpy(dip->un.v.units.name, AudioNvolume,
1046 		    sizeof dip->un.v.units.name);
1047 		break;
1048 	case CSAUDIO_MONITOR_LVL:	/* monitor level */
1049 		dip->type = AUDIO_MIXER_VALUE;
1050 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1051 		dip->prev = AUDIO_MIXER_LAST;
1052 		dip->next = CSAUDIO_MONITOR_MUTE;
1053 		strlcpy(dip->label.name, AudioNmonitor,
1054 		    sizeof dip->label.name);
1055 		dip->un.v.num_channels = 1;
1056 		strlcpy(dip->un.v.units.name, AudioNvolume,
1057 		    sizeof dip->un.v.units.name);
1058 		break;
1059 	case CSAUDIO_OUTPUT_LVL:
1060 		dip->type = AUDIO_MIXER_VALUE;
1061 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1062 		dip->prev = AUDIO_MIXER_LAST;
1063 		dip->next = CSAUDIO_OUTPUT_MUTE;
1064 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1065 		dip->un.v.num_channels = 2;
1066 		strlcpy(dip->un.v.units.name, AudioNvolume,
1067 		    sizeof dip->un.v.units.name);
1068 		break;
1069 	case CSAUDIO_LINE_IN_MUTE:
1070 		dip->type = AUDIO_MIXER_ENUM;
1071 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1072 		dip->prev = CSAUDIO_LINE_IN_LVL;
1073 		dip->next = AUDIO_MIXER_LAST;
1074 		goto mute;
1075 	case CSAUDIO_DAC_MUTE:
1076 		dip->type = AUDIO_MIXER_ENUM;
1077 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1078 		dip->prev = CSAUDIO_DAC_LVL;
1079 		dip->next = AUDIO_MIXER_LAST;
1080 		goto mute;
1081 	case CSAUDIO_CD_MUTE:
1082 		dip->type = AUDIO_MIXER_ENUM;
1083 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1084 		dip->prev = CSAUDIO_CD_LVL;
1085 		dip->next = AUDIO_MIXER_LAST;
1086 		goto mute;
1087 	case CSAUDIO_MIC_MUTE:
1088 		dip->type = AUDIO_MIXER_ENUM;
1089 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1090 		dip->prev = CSAUDIO_MIC_LVL;
1091 		dip->next = AUDIO_MIXER_LAST;
1092 		goto mute;
1093 	case CSAUDIO_MONITOR_MUTE:
1094 		dip->type = AUDIO_MIXER_ENUM;
1095 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1096 		dip->prev = CSAUDIO_MONITOR_LVL;
1097 		dip->next = AUDIO_MIXER_LAST;
1098 		goto mute;
1099 	case CSAUDIO_OUTPUT_MUTE:
1100 		dip->type = AUDIO_MIXER_ENUM;
1101 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1102 		dip->prev = CSAUDIO_OUTPUT_LVL;
1103 		dip->next = AUDIO_MIXER_LAST;
1104 		goto mute;
1105 
1106 	mute:
1107 		strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
1108 		dip->un.e.num_mem = 2;
1109 		strlcpy(dip->un.e.member[0].label.name, AudioNon,
1110 		    sizeof dip->un.e.member[0].label.name);
1111 		dip->un.e.member[0].ord = 0;
1112 		strlcpy(dip->un.e.member[1].label.name, AudioNoff,
1113 		    sizeof dip->un.e.member[1].label.name);
1114 		dip->un.e.member[1].ord = 1;
1115 		break;
1116 	case CSAUDIO_REC_LVL:		/* record level */
1117 		dip->type = AUDIO_MIXER_VALUE;
1118 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1119 		dip->prev = AUDIO_MIXER_LAST;
1120 		dip->next = CSAUDIO_RECORD_SOURCE;
1121 		strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
1122 		dip->un.v.num_channels = 2;
1123 		strlcpy(dip->un.v.units.name, AudioNvolume,
1124 		    sizeof dip->un.v.units.name);
1125 		break;
1126 	case CSAUDIO_RECORD_SOURCE:
1127 		dip->type = AUDIO_MIXER_ENUM;
1128 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1129 		dip->prev = CSAUDIO_REC_LVL;
1130 		dip->next = AUDIO_MIXER_LAST;
1131 		strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1132 		dip->un.e.num_mem = 4;
1133 		strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
1134 		    sizeof dip->un.e.member[0].label.name);
1135 		dip->un.e.member[0].ord = CSPORT_MICROPHONE;
1136 		strlcpy(dip->un.e.member[1].label.name, AudioNline,
1137 		    sizeof dip->un.e.member[1].label.name);
1138 		dip->un.e.member[1].ord = CSPORT_LINEIN;
1139 		strlcpy(dip->un.e.member[2].label.name, AudioNcd,
1140 		    sizeof dip->un.e.member[2].label.name);
1141 		dip->un.e.member[2].ord = CSPORT_AUX1;
1142 		strlcpy(dip->un.e.member[3].label.name, AudioNdac,
1143 		    sizeof dip->un.e.member[3].label.name);
1144 		dip->un.e.member[3].ord = CSPORT_DAC;
1145 		break;
1146 	case CSAUDIO_OUTPUT:
1147 		dip->type = AUDIO_MIXER_ENUM;
1148 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1149 		dip->prev = dip->next = AUDIO_MIXER_LAST;
1150 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1151 		dip->un.e.num_mem = 3;
1152 		strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
1153 		    sizeof dip->un.e.member[0].label.name);
1154 		dip->un.e.member[0].ord = CSPORT_SPEAKER;
1155 		strlcpy(dip->un.e.member[1].label.name, AudioNline,
1156 		    sizeof dip->un.e.member[1].label.name);
1157 		dip->un.e.member[1].ord = CSPORT_LINEOUT;
1158 		strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
1159 		    sizeof dip->un.e.member[2].label.name);
1160 		dip->un.e.member[2].ord = CSPORT_HEADPHONE;
1161 		break;
1162 	case CSAUDIO_INPUT_CLASS:	/* input class descriptor */
1163 		dip->type = AUDIO_MIXER_CLASS;
1164 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1165 		dip->prev = AUDIO_MIXER_LAST;
1166 		dip->next = AUDIO_MIXER_LAST;
1167 		strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1168 		break;
1169 	case CSAUDIO_OUTPUT_CLASS:	/* output class descriptor */
1170 		dip->type = AUDIO_MIXER_CLASS;
1171 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1172 		dip->prev = AUDIO_MIXER_LAST;
1173 		dip->next = AUDIO_MIXER_LAST;
1174 		strlcpy(dip->label.name, AudioCoutputs,
1175 		    sizeof dip->label.name);
1176 		break;
1177 	case CSAUDIO_MONITOR_CLASS:	/* monitor class descriptor */
1178 		dip->type = AUDIO_MIXER_CLASS;
1179 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1180 		dip->prev = AUDIO_MIXER_LAST;
1181 		dip->next = AUDIO_MIXER_LAST;
1182 		strlcpy(dip->label.name, AudioCmonitor,
1183 		    sizeof dip->label.name);
1184 		break;
1185 	case CSAUDIO_RECORD_CLASS:	/* record class descriptor */
1186 		dip->type = AUDIO_MIXER_CLASS;
1187 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1188 		dip->prev = AUDIO_MIXER_LAST;
1189 		dip->next = AUDIO_MIXER_LAST;
1190 		strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1191 		break;
1192 	default:
1193 		err = ENXIO;
1194 	}
1195 
1196 	return (err);
1197 }
1198 
1199 int
1200 cs4231_get_props(void *vsc)
1201 {
1202 	return (AUDIO_PROP_FULLDUPLEX);
1203 }
1204 
1205 /*
1206  * Hardware interrupt handler
1207  */
1208 int
1209 cs4231_intr(void *vsc)
1210 {
1211 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1212 	u_int32_t csr;
1213 	u_int8_t reg, status;
1214 	struct cs_dma *p;
1215 	int r = 0;
1216 
1217 	mtx_enter(&audio_lock);
1218 	csr = APC_READ(sc, APC_CSR);
1219 	APC_WRITE(sc, APC_CSR, csr);
1220 
1221 	if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
1222 		printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
1223 		r = 1;
1224 	}
1225 
1226 	if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
1227 		/* playback interrupt */
1228 		r = 1;
1229 	}
1230 
1231 	if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
1232 		/* general interrupt */
1233 		status = CS_READ(sc, AD1848_STATUS);
1234 		if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
1235 			reg = cs4231_read(sc, CS_IRQ_STATUS);
1236 			if (reg & CS_AFS_PI) {
1237 				cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1238 				cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1239 			}
1240 			if (reg & CS_AFS_CI) {
1241 				cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1242 				cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1243 			}
1244 			CS_WRITE(sc, AD1848_STATUS, 0);
1245 		}
1246 		r = 1;
1247 	}
1248 
1249 
1250 	if (csr & (APC_CSR_PI|APC_CSR_PMI|APC_CSR_PIE|APC_CSR_PD))
1251 		r = 1;
1252 
1253 	if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
1254 		struct cs_channel *chan = &sc->sc_playback;
1255 		u_long nextaddr, togo;
1256 
1257 		p = chan->cs_curdma;
1258 		togo = chan->cs_segsz - chan->cs_cnt;
1259 		if (togo == 0) {
1260 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1261 			chan->cs_cnt = togo = chan->cs_blksz;
1262 		} else {
1263 			nextaddr = APC_READ(sc, APC_PNVA) + chan->cs_blksz;
1264 			if (togo > chan->cs_blksz)
1265 				togo = chan->cs_blksz;
1266 			chan->cs_cnt += togo;
1267 		}
1268 
1269 		APC_WRITE(sc, APC_PNVA, nextaddr);
1270 		APC_WRITE(sc, APC_PNC, togo);
1271 
1272 		if (chan->cs_intr != NULL)
1273 			(*chan->cs_intr)(chan->cs_arg);
1274 		r = 1;
1275 	}
1276 
1277 	if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
1278 		if (csr & APC_CSR_CD) {
1279 			struct cs_channel *chan = &sc->sc_capture;
1280 			u_long nextaddr, togo;
1281 
1282 			p = chan->cs_curdma;
1283 			togo = chan->cs_segsz - chan->cs_cnt;
1284 			if (togo == 0) {
1285 				nextaddr =
1286 				    (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1287 				chan->cs_cnt = togo = chan->cs_blksz;
1288 			} else {
1289 				nextaddr = APC_READ(sc, APC_CNVA) +
1290 				    chan->cs_blksz;
1291 				if (togo > chan->cs_blksz)
1292 					togo = chan->cs_blksz;
1293 				chan->cs_cnt += togo;
1294 			}
1295 
1296 			APC_WRITE(sc, APC_CNVA, nextaddr);
1297 			APC_WRITE(sc, APC_CNC, togo);
1298 
1299 			if (chan->cs_intr != NULL)
1300 				(*chan->cs_intr)(chan->cs_arg);
1301 		}
1302 		r = 1;
1303 	}
1304 
1305 	if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
1306 		/* capture empty */
1307 		r = 1;
1308 	}
1309 
1310 	mtx_leave(&audio_lock);
1311 	return (r);
1312 }
1313 
1314 void *
1315 cs4231_alloc(void *vsc, int direction, size_t size, int pool, int flags)
1316 {
1317 	struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1318 	bus_dma_tag_t dmat = sc->sc_dmatag;
1319 	struct cs_dma *p;
1320 
1321 	p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1322 	if (p == NULL)
1323 		return (NULL);
1324 
1325 	if (bus_dmamap_create(dmat, size, 1, size, 0,
1326 	    BUS_DMA_NOWAIT, &p->dmamap) != 0)
1327 		goto fail;
1328 
1329 	p->size = size;
1330 
1331 	if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
1332 	    nitems(p->segs), &p->nsegs,
1333 	    BUS_DMA_NOWAIT) != 0)
1334 		goto fail1;
1335 
1336 	if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
1337 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
1338 		goto fail2;
1339 
1340 	if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
1341 	    BUS_DMA_NOWAIT) != 0)
1342 		goto fail3;
1343 
1344 	p->next = sc->sc_dmas;
1345 	sc->sc_dmas = p;
1346 	return (p->addr);
1347 
1348 fail3:
1349 	bus_dmamem_unmap(dmat, p->addr, p->size);
1350 fail2:
1351 	bus_dmamem_free(dmat, p->segs, p->nsegs);
1352 fail1:
1353 	bus_dmamap_destroy(dmat, p->dmamap);
1354 fail:
1355 	free(p, pool, 0);
1356 	return (NULL);
1357 }
1358 
1359 void
1360 cs4231_free(void *vsc, void *ptr, int pool)
1361 {
1362 	struct cs4231_softc *sc = vsc;
1363 	bus_dma_tag_t dmat = sc->sc_dmatag;
1364 	struct cs_dma *p, **pp;
1365 
1366 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1367 		if (p->addr != ptr)
1368 			continue;
1369 		bus_dmamap_unload(dmat, p->dmamap);
1370 		bus_dmamem_unmap(dmat, p->addr, p->size);
1371 		bus_dmamem_free(dmat, p->segs, p->nsegs);
1372 		bus_dmamap_destroy(dmat, p->dmamap);
1373 		*pp = p->next;
1374 		free(p, pool, 0);
1375 		return;
1376 	}
1377 	printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1378 }
1379 
1380 int
1381 cs4231_trigger_output(void *vsc, void *start, void *end, int blksize,
1382     void (*intr)(void *), void *arg, struct audio_params *param)
1383 {
1384 	struct cs4231_softc *sc = vsc;
1385 	struct cs_channel *chan = &sc->sc_playback;
1386 	struct cs_dma *p;
1387 	u_int32_t csr;
1388 	u_long n;
1389 
1390 	if (chan->cs_locked != 0) {
1391 		printf("%s: trigger_output: already running\n",
1392 		    sc->sc_dev.dv_xname);
1393 		return (EINVAL);
1394 	}
1395 
1396 	chan->cs_locked = 1;
1397 	chan->cs_intr = intr;
1398 	chan->cs_arg = arg;
1399 
1400 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1401 		/*EMPTY*/;
1402 	if (p == NULL) {
1403 		printf("%s: trigger_output: bad addr: %p\n",
1404 		    sc->sc_dev.dv_xname, start);
1405 		return (EINVAL);
1406 	}
1407 
1408 	n = (char *)end - (char *)start;
1409 
1410 	/*
1411 	 * Do only `blksize' at a time, so audio_pint() is kept
1412 	 * synchronous with us...
1413 	 */
1414 	chan->cs_blksz = blksize;
1415 	chan->cs_curdma = p;
1416 	chan->cs_segsz = n;
1417 
1418 	if (n > chan->cs_blksz)
1419 		n = chan->cs_blksz;
1420 
1421 	chan->cs_cnt = n;
1422 
1423 	mtx_enter(&audio_lock);
1424 	csr = APC_READ(sc, APC_CSR);
1425 
1426 	APC_WRITE(sc, APC_PNVA, (u_long)p->dmamap->dm_segs[0].ds_addr);
1427 	APC_WRITE(sc, APC_PNC, (u_long)n);
1428 
1429 	if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
1430 		APC_WRITE(sc, APC_CSR,
1431 		    APC_READ(sc, APC_CSR) & ~(APC_CSR_PIE | APC_CSR_PPAUSE));
1432 		APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) |
1433 		    APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE |
1434 		    APC_CSR_PMIE | APC_CSR_PDMA_GO);
1435 		cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1436 		cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1437 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1438 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
1439 	}
1440 	mtx_leave(&audio_lock);
1441 	return (0);
1442 }
1443 
1444 int
1445 cs4231_trigger_input(void *vsc, void *start, void *end, int blksize,
1446     void (*intr)(void *), void *arg, struct audio_params *param)
1447 {
1448 	struct cs4231_softc *sc = vsc;
1449 	struct cs_channel *chan = &sc->sc_capture;
1450 	struct cs_dma *p;
1451 	u_int32_t csr;
1452 	u_long n;
1453 
1454 	if (chan->cs_locked != 0) {
1455 		printf("%s: trigger_input: already running\n",
1456 		    sc->sc_dev.dv_xname);
1457 		return (EINVAL);
1458 	}
1459 	chan->cs_locked = 1;
1460 	chan->cs_intr = intr;
1461 	chan->cs_arg = arg;
1462 
1463 	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1464 		/*EMPTY*/;
1465 	if (p == NULL) {
1466 		printf("%s: trigger_input: bad addr: %p\n",
1467 		    sc->sc_dev.dv_xname, start);
1468 		return (EINVAL);
1469 	}
1470 
1471 	n = (char *)end - (char *)start;
1472 
1473 	/*
1474 	 * Do only `blksize' at a time, so audio_cint() is kept
1475 	 * synchronous with us...
1476 	 */
1477 	chan->cs_blksz = blksize;
1478 	chan->cs_curdma = p;
1479 	chan->cs_segsz = n;
1480 
1481 	if (n > chan->cs_blksz)
1482 		n = chan->cs_blksz;
1483 	chan->cs_cnt = n;
1484 
1485 	mtx_enter(&audio_lock);
1486 	APC_WRITE(sc, APC_CNVA, p->dmamap->dm_segs[0].ds_addr);
1487 	APC_WRITE(sc, APC_CNC, (u_long)n);
1488 
1489 	csr = APC_READ(sc, APC_CSR);
1490 	if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
1491 		csr &= APC_CSR_CPAUSE;
1492 		csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
1493 		    APC_CSR_CDMA_GO;
1494 		APC_WRITE(sc, APC_CSR, csr);
1495 		cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1496 		cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1497 		cs4231_write(sc, SP_INTERFACE_CONFIG,
1498 		    cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1499 	}
1500 
1501 	if (APC_READ(sc, APC_CSR) & APC_CSR_CD) {
1502 		u_long nextaddr, togo;
1503 
1504 		p = chan->cs_curdma;
1505 		togo = chan->cs_segsz - chan->cs_cnt;
1506 		if (togo == 0) {
1507 			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1508 			chan->cs_cnt = togo = chan->cs_blksz;
1509 		} else {
1510 			nextaddr = APC_READ(sc, APC_CNVA) + chan->cs_blksz;
1511 			if (togo > chan->cs_blksz)
1512 				togo = chan->cs_blksz;
1513 			chan->cs_cnt += togo;
1514 		}
1515 
1516 		APC_WRITE(sc, APC_CNVA, nextaddr);
1517 		APC_WRITE(sc, APC_CNC, togo);
1518 	}
1519 
1520 	mtx_leave(&audio_lock);
1521 	return (0);
1522 }
1523