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