ce4231.c revision 1.33
1/*	$OpenBSD: ce4231.c,v 1.33 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
29/*
30 * Driver for CS4231 based audio found in some sun4u systems (cs4231)
31 * based on ideas from the S/Linux project and the NetBSD project.
32 *
33 * Effort sponsored in part by the Defense Advanced Research Projects
34 * Agency (DARPA) and Air Force Research Laboratory, Air Force
35 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
36 *
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/cpu.h>
48#include <machine/bus.h>
49#include <machine/intr.h>
50#include <machine/autoconf.h>
51
52#include <sys/audioio.h>
53#include <dev/audio_if.h>
54
55#include <sparc64/dev/ebusreg.h>
56#include <sparc64/dev/ebusvar.h>
57#include <sparc64/dev/ce4231var.h>
58
59/* AD1418 provides basic registers, CS4231 extends with more */
60#include <dev/ic/ad1848reg.h>
61#include <dev/ic/cs4231reg.h>
62
63/* Mixer classes and mixer knobs */
64#define CSAUDIO_INPUT_CLASS	0
65#define CSAUDIO_OUTPUT_CLASS	1
66#define CSAUDIO_RECORD_CLASS	2
67#define CSAUDIO_DAC_LVL		3
68#define CSAUDIO_DAC_MUTE	4
69#define CSAUDIO_OUTPUTS		5
70#define CSAUDIO_CD_LVL		6
71#define CSAUDIO_CD_MUTE		7
72#define CSAUDIO_LINE_IN_LVL	8
73#define CSAUDIO_LINE_IN_MUTE	9
74#define CSAUDIO_MONITOR_LVL	10
75#define CSAUDIO_MONITOR_MUTE	11
76#define CSAUDIO_REC_LVL		12
77#define CSAUDIO_RECORD_SOURCE	13
78#define CSAUDIO_MIC_PREAMP	14
79
80/* Recording sources */
81#define REC_PORT_LINE	0
82#define REC_PORT_CD	1
83#define REC_PORT_MIC	2
84#define REC_PORT_MIX	3
85
86/* Output ports. */
87#define OUT_PORT_LINE	0x1
88#define OUT_PORT_HP	0x2
89#define OUT_PORT_SPKR	0x4
90
91/* Bits on the ADC reg that determine recording source */
92#define CS_REC_SRC_BITS 0xc0
93
94#ifdef AUDIO_DEBUG
95#define	DPRINTF(x)	printf x
96#else
97#define	DPRINTF(x)
98#endif
99
100#define	CS_TIMEOUT	90000
101
102/* Read/write CS4231 direct registers */
103#define CS_WRITE(sc,r,v)	\
104    bus_space_write_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2, (v))
105#define	CS_READ(sc,r)		\
106    bus_space_read_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2)
107
108/* Read/write EBDMA playback registers */
109#define	P_WRITE(sc,r,v)		\
110    bus_space_write_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r), (v))
111#define	P_READ(sc,r)		\
112    bus_space_read_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r))
113
114/* Read/write EBDMA capture registers */
115#define	C_WRITE(sc,r,v)		\
116    bus_space_write_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r), (v))
117#define	C_READ(sc,r)		\
118    bus_space_read_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r))
119
120int	ce4231_match(struct device *, void *, void *);
121void	ce4231_attach(struct device *, struct device *, void *);
122int	ce4231_cintr(void *);
123int	ce4231_pintr(void *);
124
125int	ce4231_set_speed(struct ce4231_softc *, u_long *);
126
127void	ce4231_set_outputs(struct ce4231_softc *, int);
128int	ce4231_get_outputs(struct ce4231_softc *);
129
130void		ce4231_write(struct ce4231_softc *, u_int8_t, u_int8_t);
131u_int8_t	ce4231_read(struct ce4231_softc *, u_int8_t);
132
133/* Audio interface */
134int	ce4231_open(void *, int);
135void	ce4231_close(void *);
136int	ce4231_query_encoding(void *, struct audio_encoding *);
137int	ce4231_set_params(void *, int, int, struct audio_params *,
138    struct audio_params *);
139int	ce4231_round_blocksize(void *, int);
140int	ce4231_commit_settings(void *);
141int	ce4231_halt_output(void *);
142int	ce4231_halt_input(void *);
143int	ce4231_getdev(void *, struct audio_device *);
144int	ce4231_set_port(void *, mixer_ctrl_t *);
145int	ce4231_get_port(void *, mixer_ctrl_t *);
146int	ce4231_query_devinfo(void *addr, mixer_devinfo_t *);
147void *	ce4231_alloc(void *, int, size_t, int, int);
148void	ce4231_free(void *, void *, int);
149int	ce4231_get_props(void *);
150int	ce4231_trigger_output(void *, void *, void *, int,
151    void (*intr)(void *), void *arg, struct audio_params *);
152int	ce4231_trigger_input(void *, void *, void *, int,
153    void (*intr)(void *), void *arg, struct audio_params *);
154
155struct audio_hw_if ce4231_sa_hw_if = {
156	ce4231_open,
157	ce4231_close,
158	0,
159	ce4231_query_encoding,
160	ce4231_set_params,
161	ce4231_round_blocksize,
162	ce4231_commit_settings,
163	0,
164	0,
165	0,
166	0,
167	ce4231_halt_output,
168	ce4231_halt_input,
169	0,
170	ce4231_getdev,
171	0,
172	ce4231_set_port,
173	ce4231_get_port,
174	ce4231_query_devinfo,
175	ce4231_alloc,
176	ce4231_free,
177	0,
178	0,
179	ce4231_get_props,
180	ce4231_trigger_output,
181	ce4231_trigger_input,
182	0
183};
184
185struct cfattach audioce_ca = {
186	sizeof (struct ce4231_softc), ce4231_match, ce4231_attach
187};
188
189struct cfdriver audioce_cd = {
190	NULL, "audioce", DV_DULL
191};
192
193struct audio_device ce4231_device = {
194	"SUNW,CS4231",
195	"b",
196	"onboard1",
197};
198
199int
200ce4231_match(parent, vcf, aux)
201	struct device *parent;
202	void *vcf, *aux;
203{
204	struct ebus_attach_args *ea = aux;
205
206	if (!strcmp("SUNW,CS4231", ea->ea_name) ||
207	    !strcmp("audio", ea->ea_name))
208		return (1);
209	return (0);
210}
211
212void
213ce4231_attach(parent, self, aux)
214	struct device *parent, *self;
215	void *aux;
216{
217	struct ebus_attach_args *ea = aux;
218	struct ce4231_softc *sc = (struct ce4231_softc *)self;
219	mixer_ctrl_t cp;
220	int node;
221
222	node = ea->ea_node;
223
224	sc->sc_last_format = 0xffffffff;
225
226	/* Pass on the bus tags */
227	sc->sc_bustag = ea->ea_memtag;
228	sc->sc_dmatag = ea->ea_dmatag;
229
230	/* Make sure things are sane. */
231	if (ea->ea_nintrs != 2) {
232		printf(": expected 2 interrupts, got %d\n", ea->ea_nintrs);
233		return;
234	}
235	if (ea->ea_nregs != 4) {
236		printf(": expected 4 register set, got %d\n",
237		    ea->ea_nregs);
238		return;
239	}
240
241	sc->sc_cih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[0],
242	    IPL_AUDIO, BUS_INTR_ESTABLISH_MPSAFE, ce4231_cintr,
243	    sc, self->dv_xname);
244	if (sc->sc_cih == NULL) {
245		printf(": couldn't establish capture interrupt\n");
246		return;
247	}
248	sc->sc_pih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[1],
249	    IPL_AUDIO, BUS_INTR_ESTABLISH_MPSAFE, ce4231_pintr,
250	    sc, self->dv_xname);
251	if (sc->sc_pih == NULL) {
252		printf(": couldn't establish play interrupt1\n");
253		return;
254	}
255
256	/* XXX what if prom has already mapped?! */
257
258	if (ebus_bus_map(sc->sc_bustag, 0,
259	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size,
260	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cshandle) != 0) {
261		printf(": couldn't map cs4231 registers\n");
262		return;
263	}
264
265	if (ebus_bus_map(sc->sc_bustag, 0,
266	    EBUS_PADDR_FROM_REG(&ea->ea_regs[1]), ea->ea_regs[1].size,
267	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_pdmahandle) != 0) {
268		printf(": couldn't map dma1 registers\n");
269		return;
270	}
271
272	if (ebus_bus_map(sc->sc_bustag, 0,
273	    EBUS_PADDR_FROM_REG(&ea->ea_regs[2]), ea->ea_regs[2].size,
274	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cdmahandle) != 0) {
275		printf(": couldn't map dma2 registers\n");
276		return;
277	}
278
279	if (ebus_bus_map(sc->sc_bustag, 0,
280	    EBUS_PADDR_FROM_REG(&ea->ea_regs[3]), ea->ea_regs[3].size,
281	    BUS_SPACE_MAP_LINEAR, 0, &sc->sc_auxhandle) != 0) {
282		printf(": couldn't map aux registers\n");
283		return;
284	}
285
286	printf(": nvaddrs %d\n", ea->ea_nvaddrs);
287
288	audio_attach_mi(&ce4231_sa_hw_if, sc, &sc->sc_dev);
289
290	/* Enable mode 2. */
291	ce4231_write(sc, SP_MISC_INFO, ce4231_read(sc, SP_MISC_INFO) | MODE2);
292
293	/* Attenuate DAC, CD and line-in.  -22.5 dB for all. */
294	cp.dev = CSAUDIO_DAC_LVL;
295	cp.type = AUDIO_MIXER_VALUE;
296	cp.un.value.num_channels = 2;
297	cp.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 195;
298	cp.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 195;
299	ce4231_set_port(sc, &cp);
300
301	cp.dev = CSAUDIO_CD_LVL;
302	cp.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 135;
303	cp.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 135;
304	ce4231_set_port(sc, &cp);
305
306	cp.dev = CSAUDIO_LINE_IN_LVL;
307	ce4231_set_port(sc, &cp);
308
309	/* Unmute DAC, CD and line-in */
310	cp.dev = CSAUDIO_DAC_MUTE;
311	cp.type = AUDIO_MIXER_ENUM;
312	cp.un.ord = 0;
313	ce4231_set_port(sc, &cp);
314
315	cp.dev = CSAUDIO_CD_MUTE;
316	ce4231_set_port(sc, &cp);
317
318	cp.dev = CSAUDIO_LINE_IN_MUTE;
319	ce4231_set_port(sc, &cp);
320
321	/* XXX get real burst... */
322	sc->sc_burst = EBDCSR_BURST_8;
323}
324
325/*
326 * Write to one of the indexed registers of cs4231.
327 */
328void
329ce4231_write(sc, r, v)
330	struct ce4231_softc *sc;
331	u_int8_t r, v;
332{
333	CS_WRITE(sc, AD1848_IADDR, r);
334	CS_WRITE(sc, AD1848_IDATA, v);
335}
336
337/*
338 * Read from one of the indexed registers of cs4231.
339 */
340u_int8_t
341ce4231_read(sc, r)
342	struct ce4231_softc *sc;
343	u_int8_t r;
344{
345	CS_WRITE(sc, AD1848_IADDR, r);
346	return (CS_READ(sc, AD1848_IDATA));
347}
348
349int
350ce4231_set_speed(sc, argp)
351	struct ce4231_softc *sc;
352	u_long *argp;
353
354{
355	/*
356	 * The available speeds are in the following table. Keep the speeds in
357	 * the increasing order.
358	 */
359	typedef struct {
360		int speed;
361		u_char bits;
362	} speed_struct;
363	u_long arg = *argp;
364
365	static speed_struct speed_table[] = {
366		{5510,	(0 << 1) | CLOCK_XTAL2},
367		{5510,	(0 << 1) | CLOCK_XTAL2},
368		{6620,	(7 << 1) | CLOCK_XTAL2},
369		{8000,	(0 << 1) | CLOCK_XTAL1},
370		{9600,	(7 << 1) | CLOCK_XTAL1},
371		{11025,	(1 << 1) | CLOCK_XTAL2},
372		{16000,	(1 << 1) | CLOCK_XTAL1},
373		{18900,	(2 << 1) | CLOCK_XTAL2},
374		{22050,	(3 << 1) | CLOCK_XTAL2},
375		{27420,	(2 << 1) | CLOCK_XTAL1},
376		{32000,	(3 << 1) | CLOCK_XTAL1},
377		{33075,	(6 << 1) | CLOCK_XTAL2},
378		{33075,	(4 << 1) | CLOCK_XTAL2},
379		{44100,	(5 << 1) | CLOCK_XTAL2},
380		{48000,	(6 << 1) | CLOCK_XTAL1},
381	};
382
383	int i, n, selected = -1;
384
385	n = sizeof(speed_table) / sizeof(speed_struct);
386
387	if (arg < speed_table[0].speed)
388		selected = 0;
389	if (arg > speed_table[n - 1].speed)
390		selected = n - 1;
391
392	for (i = 1; selected == -1 && i < n; i++) {
393		if (speed_table[i].speed == arg)
394			selected = i;
395		else if (speed_table[i].speed > arg) {
396			int diff1, diff2;
397
398			diff1 = arg - speed_table[i - 1].speed;
399			diff2 = speed_table[i].speed - arg;
400			if (diff1 < diff2)
401				selected = i - 1;
402			else
403				selected = i;
404		}
405	}
406
407	if (selected == -1)
408		selected = 3;
409
410	sc->sc_speed_bits = speed_table[selected].bits;
411	sc->sc_need_commit = 1;
412	*argp = speed_table[selected].speed;
413
414	return (0);
415}
416
417/*
418 * Audio interface functions
419 */
420int
421ce4231_open(addr, flags)
422	void *addr;
423	int flags;
424{
425	struct ce4231_softc *sc = addr;
426	int tries;
427
428	DPRINTF(("ce4231_open\n"));
429
430	if (sc->sc_open)
431		return (EBUSY);
432
433	sc->sc_open = 1;
434	sc->sc_rintr = 0;
435	sc->sc_rarg = 0;
436	sc->sc_pintr = 0;
437	sc->sc_parg = 0;
438
439	P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
440	C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
441	P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
442	C_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
443
444	DELAY(20);
445
446	for (tries = CS_TIMEOUT;
447	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
448		DELAY(10);
449	if (tries == 0)
450		printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
451
452	ce4231_write(sc, SP_PIN_CONTROL,
453	    ce4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
454
455	return (0);
456}
457
458void
459ce4231_close(addr)
460	void *addr;
461{
462	struct ce4231_softc *sc = addr;
463
464	ce4231_halt_input(sc);
465	ce4231_halt_output(sc);
466	ce4231_write(sc, SP_PIN_CONTROL,
467	    ce4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
468	sc->sc_open = 0;
469}
470
471int
472ce4231_query_encoding(addr, fp)
473	void *addr;
474	struct audio_encoding *fp;
475{
476	int err = 0;
477
478	switch (fp->index) {
479	case 0:
480		strlcpy(fp->name, AudioEmulaw, sizeof(fp->name));
481		fp->encoding = AUDIO_ENCODING_ULAW;
482		fp->precision = 8;
483		fp->flags = 0;
484		break;
485	case 1:
486		strlcpy(fp->name, AudioEalaw, sizeof(fp->name));
487		fp->encoding = AUDIO_ENCODING_ALAW;
488		fp->precision = 8;
489		fp->flags = 0;
490		break;
491	case 2:
492		strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name));
493		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
494		fp->precision = 16;
495		fp->flags = 0;
496		break;
497	case 3:
498		strlcpy(fp->name, AudioEulinear, sizeof(fp->name));
499		fp->encoding = AUDIO_ENCODING_ULINEAR;
500		fp->precision = 8;
501		fp->flags = 0;
502		break;
503	case 4:
504		strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name));
505		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
506		fp->precision = 16;
507		fp->flags = 0;
508		break;
509	default:
510		err = EINVAL;
511	}
512	fp->bps = AUDIO_BPS(fp->precision);
513	fp->msb = 1;
514	return (err);
515}
516
517int
518ce4231_set_params(addr, setmode, usemode, p, r)
519	void *addr;
520	int setmode, usemode;
521	struct audio_params *p, *r;
522{
523	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
524	int err, bits, enc = p->encoding;
525
526	if (p->precision > 16)
527		p->precision = 16;
528	switch (enc) {
529	case AUDIO_ENCODING_ULAW:
530		p->precision = 8;
531		bits = FMT_ULAW >> 5;
532		break;
533	case AUDIO_ENCODING_ALAW:
534		p->precision = 8;
535		bits = FMT_ALAW >> 5;
536		break;
537	case AUDIO_ENCODING_SLINEAR_LE:
538		p->precision = 16;
539		bits = FMT_TWOS_COMP >> 5;
540		break;
541	case AUDIO_ENCODING_SLINEAR_BE:
542		p->precision = 16;
543		bits = FMT_TWOS_COMP_BE >> 5;
544		break;
545	case AUDIO_ENCODING_ULINEAR_LE:
546	case AUDIO_ENCODING_ULINEAR_BE:
547		p->precision = 8;
548		break;
549	default:
550		return (EINVAL);
551	}
552
553	if (p->channels > 2)
554		p->channels = 2;
555
556	err = ce4231_set_speed(sc, &p->sample_rate);
557	if (err)
558		return (err);
559
560	p->bps = AUDIO_BPS(p->precision);
561	r->bps = AUDIO_BPS(r->precision);
562	p->msb = r->msb = 1;
563
564	sc->sc_format_bits = bits;
565	sc->sc_channels = p->channels;
566	sc->sc_precision = p->precision;
567	sc->sc_need_commit = 1;
568	return (0);
569}
570
571int
572ce4231_round_blocksize(addr, blk)
573	void *addr;
574	int blk;
575{
576	return ((blk + 3) & (-4));
577}
578
579int
580ce4231_commit_settings(addr)
581	void *addr;
582{
583	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
584	int tries;
585	u_int8_t r, fs;
586
587	if (sc->sc_need_commit == 0)
588		return (0);
589
590	fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
591	if (sc->sc_channels == 2)
592		fs |= FMT_STEREO;
593
594	if (sc->sc_last_format == fs) {
595		sc->sc_need_commit = 0;
596		return (0);
597	}
598
599	/* XXX: this code is called before DMA (this intrs) is stopped */
600	mtx_enter(&audio_lock);
601
602	r = ce4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
603	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
604	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
605	CS_WRITE(sc, AD1848_IDATA, r);
606
607	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
608	CS_WRITE(sc, AD1848_IDATA, fs);
609	CS_READ(sc, AD1848_IDATA);
610	CS_READ(sc, AD1848_IDATA);
611	tries = CS_TIMEOUT;
612	for (tries = CS_TIMEOUT;
613	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
614		DELAY(10);
615	if (tries == 0)
616		printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
617
618	CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
619	CS_WRITE(sc, AD1848_IDATA, fs);
620	CS_READ(sc, AD1848_IDATA);
621	CS_READ(sc, AD1848_IDATA);
622	for (tries = CS_TIMEOUT;
623	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
624		DELAY(10);
625	if (tries == 0)
626		printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
627
628	CS_WRITE(sc, AD1848_IADDR, 0);
629	for (tries = CS_TIMEOUT;
630	     tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
631		DELAY(10);
632	if (tries == 0)
633		printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
634
635	CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
636	for (tries = CS_TIMEOUT;
637	     tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
638		DELAY(10);
639	if (tries == 0)
640		printf("%s: timeout waiting for autocalibration\n",
641		    sc->sc_dev.dv_xname);
642
643	mtx_leave(&audio_lock);
644
645	sc->sc_need_commit = 0;
646	return (0);
647}
648
649int
650ce4231_halt_output(addr)
651	void *addr;
652{
653	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
654
655	P_WRITE(sc, EBDMA_DCSR,
656	    P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
657	ce4231_write(sc, SP_INTERFACE_CONFIG,
658	    ce4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
659	return (0);
660}
661
662int
663ce4231_halt_input(addr)
664	void *addr;
665{
666	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
667
668	C_WRITE(sc, EBDMA_DCSR,
669	    C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
670	ce4231_write(sc, SP_INTERFACE_CONFIG,
671	    ce4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
672	return (0);
673}
674
675int
676ce4231_getdev(addr, retp)
677	void *addr;
678	struct audio_device *retp;
679{
680	*retp = ce4231_device;
681	return (0);
682}
683
684void
685ce4231_set_outputs(struct ce4231_softc *sc, int mask)
686{
687	u_int8_t val;
688
689	val = ce4231_read(sc, CS_MONO_IO_CONTROL) & ~MONO_OUTPUT_MUTE;
690	if (!(mask & OUT_PORT_SPKR))
691		val |= MONO_OUTPUT_MUTE;
692	ce4231_write(sc, CS_MONO_IO_CONTROL, val);
693
694	val = ce4231_read(sc, SP_PIN_CONTROL) & ~(XCTL0_ENABLE | XCTL1_ENABLE);
695	if (!(mask & OUT_PORT_LINE))
696		val |= XCTL0_ENABLE;
697	if (!(mask & OUT_PORT_HP))
698		val |= XCTL1_ENABLE;
699	ce4231_write(sc, SP_PIN_CONTROL, val);
700}
701
702int
703ce4231_get_outputs(struct ce4231_softc *sc)
704{
705	int mask = 0;
706	u_int8_t val;
707
708	if (!(ce4231_read(sc, CS_MONO_IO_CONTROL) & MONO_OUTPUT_MUTE))
709		mask |= OUT_PORT_SPKR;
710
711	val = ce4231_read(sc, SP_PIN_CONTROL);
712	if (!(val & XCTL0_ENABLE))
713		mask |= OUT_PORT_LINE;
714	if (!(val & XCTL1_ENABLE))
715		mask |= OUT_PORT_HP;
716
717	return (mask);
718}
719
720int
721ce4231_set_port(void *addr, mixer_ctrl_t *cp)
722{
723	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
724	u_int8_t l, r;
725
726	DPRINTF(("ce4231_set_port: dev=%d type=%d\n", cp->dev, cp->type));
727
728	switch (cp->dev) {
729
730	case CSAUDIO_DAC_LVL:
731		if (cp->type != AUDIO_MIXER_VALUE)
732			return (EINVAL);
733		l = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) &
734		    OUTPUT_ATTEN_MASK;
735		r = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) &
736		    OUTPUT_ATTEN_MASK;
737		l |= (AUDIO_MAX_GAIN -
738		    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 2;
739		r |= (AUDIO_MAX_GAIN -
740		    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 2;
741		ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, l);
742		ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, r);
743		break;
744	case CSAUDIO_DAC_MUTE:
745		if (cp->type != AUDIO_MIXER_ENUM)
746			return (EINVAL);
747		l = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) & ~OUTPUT_MUTE;
748		r = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) & ~OUTPUT_MUTE;
749		if (cp->un.ord) {
750			l |= OUTPUT_MUTE;
751			r |= OUTPUT_MUTE;
752		}
753		ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, l);
754		ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, r);
755		break;
756
757	case CSAUDIO_OUTPUTS:
758		if (cp->type != AUDIO_MIXER_SET)
759			return (EINVAL);
760		ce4231_set_outputs(sc, cp->un.mask);
761		break;
762
763	case CSAUDIO_CD_LVL:
764		if (cp->type != AUDIO_MIXER_VALUE)
765			return (EINVAL);
766		l = ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
767		    AUX_INPUT_ATTEN_MASK;
768		r = ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
769		    AUX_INPUT_ATTEN_MASK;
770		l |= (AUDIO_MAX_GAIN -
771		    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 3;
772		r |= (AUDIO_MAX_GAIN -
773		    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 3;
774		ce4231_write(sc, SP_LEFT_AUX1_CONTROL, l);
775		ce4231_write(sc, SP_RIGHT_AUX1_CONTROL, r);
776		break;
777	case CSAUDIO_CD_MUTE:
778		if (cp->type != AUDIO_MIXER_ENUM)
779			return (EINVAL);
780		l = ce4231_read(sc, SP_LEFT_AUX1_CONTROL) & ~AUX_INPUT_MUTE;
781		r = ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) & ~AUX_INPUT_MUTE;
782		if (cp->un.ord) {
783			l |= AUX_INPUT_MUTE;
784			r |= AUX_INPUT_MUTE;
785		}
786		ce4231_write(sc, SP_LEFT_AUX1_CONTROL, l);
787		ce4231_write(sc, SP_RIGHT_AUX1_CONTROL, r);
788		break;
789
790	case CSAUDIO_LINE_IN_LVL:
791		if (cp->type != AUDIO_MIXER_VALUE)
792			return (EINVAL);
793		l = ce4231_read(sc, CS_LEFT_LINE_CONTROL) &
794		    LINE_INPUT_ATTEN_MASK;
795		r = ce4231_read(sc, CS_RIGHT_LINE_CONTROL) &
796		    LINE_INPUT_ATTEN_MASK;
797		l |= (AUDIO_MAX_GAIN -
798		    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]) >> 3;
799		r |= (AUDIO_MAX_GAIN -
800		    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]) >> 3;
801		ce4231_write(sc, CS_LEFT_LINE_CONTROL, l);
802		ce4231_write(sc, CS_RIGHT_LINE_CONTROL, r);
803		break;
804	case CSAUDIO_LINE_IN_MUTE:
805		l = ce4231_read(sc, CS_LEFT_LINE_CONTROL) & ~LINE_INPUT_MUTE;
806		r = ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & ~LINE_INPUT_MUTE;
807		if (cp->un.ord) {
808			l |= LINE_INPUT_MUTE;
809			r |= LINE_INPUT_MUTE;
810		}
811		ce4231_write(sc, CS_LEFT_LINE_CONTROL, l);
812		ce4231_write(sc, CS_RIGHT_LINE_CONTROL, r);
813		break;
814
815	case CSAUDIO_MONITOR_LVL:
816		if (cp->type != AUDIO_MIXER_VALUE)
817			return (EINVAL);
818		if (cp->un.value.num_channels != 1)
819			return (EINVAL);
820		l = ce4231_read(sc, SP_DIGITAL_MIX) & ~MIX_ATTEN_MASK;
821		l |= (AUDIO_MAX_GAIN -
822		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]) &
823		    MIX_ATTEN_MASK;
824		ce4231_write(sc, SP_DIGITAL_MIX, l);
825		break;
826	case CSAUDIO_MONITOR_MUTE:
827		if (cp->type != AUDIO_MIXER_ENUM)
828			return (EINVAL);
829		l = ce4231_read(sc, SP_DIGITAL_MIX) & ~DIGITAL_MIX1_ENABLE;
830		if (!cp->un.ord)
831			l |= DIGITAL_MIX1_ENABLE;
832		ce4231_write(sc, SP_DIGITAL_MIX, l);
833		break;
834
835	case CSAUDIO_REC_LVL:
836		if (cp->type != AUDIO_MIXER_VALUE)
837			return (EINVAL);
838		l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & INPUT_GAIN_MASK;
839		r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & INPUT_GAIN_MASK;
840		l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] >> 4;
841		r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] >> 4;
842		ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l);
843		ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r);
844		break;
845	case CSAUDIO_RECORD_SOURCE:
846		if (cp->type != AUDIO_MIXER_ENUM)
847			return (EINVAL);
848		l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) & INPUT_SOURCE_MASK;
849		r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) & INPUT_SOURCE_MASK;
850		l |= cp->un.ord << 6;
851		r |= cp->un.ord << 6;
852		ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l);
853		ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r);
854		break;
855
856	case CSAUDIO_MIC_PREAMP:
857		if (cp->type != AUDIO_MIXER_ENUM)
858			return (EINVAL);
859		l = ce4231_read(sc, SP_LEFT_INPUT_CONTROL) &
860		    ~INPUT_MIC_GAIN_ENABLE;
861		r = ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) &
862		    ~INPUT_MIC_GAIN_ENABLE;
863		if (cp->un.ord) {
864			l |= INPUT_MIC_GAIN_ENABLE;
865			r |= INPUT_MIC_GAIN_ENABLE;
866		}
867		ce4231_write(sc, SP_LEFT_INPUT_CONTROL, l);
868		ce4231_write(sc, SP_RIGHT_INPUT_CONTROL, r);
869		break;
870
871	default:
872		return (EINVAL);
873	}
874
875	return (0);
876}
877
878int
879ce4231_get_port(void *addr, mixer_ctrl_t *cp)
880{
881	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
882
883	DPRINTF(("ce4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
884
885	switch (cp->dev) {
886
887	case CSAUDIO_DAC_LVL:
888		if (cp->type != AUDIO_MIXER_VALUE)
889			return (EINVAL);
890		cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
891		    AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) &
892		    OUTPUT_ATTEN_BITS) << 2);
893		cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
894		    AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL) &
895		    OUTPUT_ATTEN_BITS) << 2);
896		break;
897	case CSAUDIO_DAC_MUTE:
898		if (cp->type != AUDIO_MIXER_ENUM)
899			return (EINVAL);
900		cp->un.ord = (ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL) &
901		    OUTPUT_MUTE) ? 1 : 0;
902		break;
903
904	case CSAUDIO_OUTPUTS:
905		if (cp->type != AUDIO_MIXER_SET)
906			return (EINVAL);
907		cp->un.mask = ce4231_get_outputs(sc);
908		break;
909
910	case CSAUDIO_CD_LVL:
911		if (cp->type != AUDIO_MIXER_VALUE)
912			return (EINVAL);
913		cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
914		    AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
915		    AUX_INPUT_ATTEN_BITS) << 3);
916		cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
917		    AUDIO_MAX_GAIN - ((ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
918		    AUX_INPUT_ATTEN_BITS) << 3);
919		break;
920	case CSAUDIO_CD_MUTE:
921		if (cp->type != AUDIO_MIXER_ENUM)
922			return (EINVAL);
923		cp->un.ord = (ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
924		    AUX_INPUT_MUTE) ? 1 : 0;
925		break;
926
927	case CSAUDIO_LINE_IN_LVL:
928		if (cp->type != AUDIO_MIXER_VALUE)
929			return (EINVAL);
930		cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
931		    AUDIO_MAX_GAIN - ((ce4231_read(sc, CS_LEFT_LINE_CONTROL) &
932		    LINE_INPUT_ATTEN_BITS) << 3);
933		cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
934		    AUDIO_MAX_GAIN - ((ce4231_read(sc, CS_RIGHT_LINE_CONTROL) &
935		    LINE_INPUT_ATTEN_BITS) << 3);
936		break;
937	case CSAUDIO_LINE_IN_MUTE:
938		if (cp->type != AUDIO_MIXER_ENUM)
939			return (EINVAL);
940		cp->un.ord = (ce4231_read(sc, CS_LEFT_LINE_CONTROL) &
941		    LINE_INPUT_MUTE) ? 1 : 0;
942		break;
943
944	case CSAUDIO_MONITOR_LVL:
945		if (cp->type != AUDIO_MIXER_VALUE)
946			return (EINVAL);
947		if (cp->un.value.num_channels != 1)
948			return (EINVAL);
949		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
950		    AUDIO_MAX_GAIN - (ce4231_read(sc, SP_DIGITAL_MIX) &
951		    MIX_ATTEN_MASK);
952		break;
953	case CSAUDIO_MONITOR_MUTE:
954		if (cp->type != AUDIO_MIXER_ENUM)
955			return (EINVAL);
956		cp->un.ord = (ce4231_read(sc, SP_DIGITAL_MIX) &
957		    DIGITAL_MIX1_ENABLE) ? 0 : 1;
958		break;
959
960	case CSAUDIO_REC_LVL:
961		if (cp->type != AUDIO_MIXER_VALUE)
962			return (EINVAL);
963		cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
964		    (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) &
965		    ~INPUT_GAIN_MASK) << 4;
966		cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
967		    (ce4231_read(sc, SP_RIGHT_INPUT_CONTROL) &
968		    ~INPUT_GAIN_MASK) << 4;
969		break;
970	case CSAUDIO_RECORD_SOURCE:
971		if (cp->type != AUDIO_MIXER_ENUM)
972			return (EINVAL);
973		cp->un.ord = (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) &
974		    CS_REC_SRC_BITS) >> 6;
975		break;
976
977	case CSAUDIO_MIC_PREAMP:
978		if (cp->type != AUDIO_MIXER_ENUM)
979			return (EINVAL);
980		cp->un.ord = (ce4231_read(sc, SP_LEFT_INPUT_CONTROL) &
981		    INPUT_MIC_GAIN_ENABLE) ? 1 : 0;
982		break;
983
984	default:
985		return (EINVAL);
986	}
987	return (0);
988}
989
990int
991ce4231_query_devinfo(void *addr, mixer_devinfo_t *dip)
992{
993	size_t nsize = MAX_AUDIO_DEV_LEN;
994	int err = 0;
995
996	switch (dip->index) {
997	case CSAUDIO_INPUT_CLASS:
998		dip->type = AUDIO_MIXER_CLASS;
999		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1000		dip->prev = dip->next = AUDIO_MIXER_LAST;
1001		strlcpy(dip->label.name, AudioCinputs, nsize);
1002		break;
1003	case CSAUDIO_OUTPUT_CLASS:
1004		dip->type = AUDIO_MIXER_CLASS;
1005		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1006		dip->prev = dip->next = AUDIO_MIXER_LAST;
1007		strlcpy(dip->label.name, AudioCoutputs, nsize);
1008		break;
1009	case CSAUDIO_RECORD_CLASS:
1010		dip->type = AUDIO_MIXER_CLASS;
1011		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1012		dip->prev = dip->next = AUDIO_MIXER_LAST;
1013		strlcpy(dip->label.name, AudioCrecord, nsize);
1014		break;
1015
1016	case CSAUDIO_DAC_LVL:
1017		dip->type = AUDIO_MIXER_VALUE;
1018		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1019		dip->prev = AUDIO_MIXER_LAST;
1020		dip->next = CSAUDIO_DAC_MUTE;
1021		strlcpy(dip->label.name, AudioNdac, nsize);
1022		dip->un.v.num_channels = 2;
1023		dip->un.v.delta = 4;
1024		strlcpy(dip->un.v.units.name, AudioNvolume, nsize);
1025		break;
1026	case CSAUDIO_DAC_MUTE:
1027		dip->type = AUDIO_MIXER_ENUM;
1028		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1029		dip->prev = CSAUDIO_DAC_LVL;
1030		dip->next = AUDIO_MIXER_LAST;
1031		strlcpy(dip->label.name, AudioNmute, nsize);
1032		goto onoff;
1033
1034	case CSAUDIO_OUTPUTS:
1035		dip->type = AUDIO_MIXER_SET;
1036		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1037		dip->prev = dip->next = AUDIO_MIXER_LAST;
1038		strlcpy(dip->label.name, AudioNoutput, nsize);
1039		dip->un.s.num_mem = 3;
1040		strlcpy(dip->un.s.member[0].label.name, AudioNline, nsize);
1041		dip->un.s.member[0].mask = OUT_PORT_LINE;
1042		strlcpy(dip->un.s.member[1].label.name, AudioNheadphone, nsize);
1043		dip->un.s.member[1].mask = OUT_PORT_HP;
1044		strlcpy(dip->un.s.member[2].label.name, AudioNspeaker, nsize);
1045		dip->un.s.member[2].mask = OUT_PORT_SPKR;
1046		break;
1047
1048	case CSAUDIO_CD_LVL:
1049		dip->type = AUDIO_MIXER_VALUE;
1050		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1051		dip->prev = AUDIO_MIXER_LAST;
1052		dip->next = CSAUDIO_CD_MUTE;
1053		strlcpy(dip->label.name, AudioNcd, nsize);
1054		dip->un.v.num_channels = 2;
1055		dip->un.v.delta = 8;
1056		strlcpy(dip->un.v.units.name, AudioNvolume, nsize);
1057		break;
1058	case CSAUDIO_CD_MUTE:
1059		dip->type = AUDIO_MIXER_ENUM;
1060		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1061		dip->prev = CSAUDIO_CD_LVL;
1062		dip->next = AUDIO_MIXER_LAST;
1063		strlcpy(dip->label.name, AudioNmute, nsize);
1064		goto onoff;
1065
1066	case CSAUDIO_LINE_IN_LVL:
1067		dip->type = AUDIO_MIXER_VALUE;
1068		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1069		dip->prev = AUDIO_MIXER_LAST;
1070		dip->next = CSAUDIO_LINE_IN_MUTE;
1071		strlcpy(dip->label.name, AudioNline, nsize);
1072		dip->un.v.num_channels = 2;
1073		dip->un.v.delta = 8;
1074		strlcpy(dip->un.v.units.name, AudioNvolume, nsize);
1075		break;
1076	case CSAUDIO_LINE_IN_MUTE:
1077		dip->type = AUDIO_MIXER_ENUM;
1078		dip->mixer_class = CSAUDIO_INPUT_CLASS;
1079		dip->prev = CSAUDIO_LINE_IN_LVL;
1080		dip->next = AUDIO_MIXER_LAST;
1081		strlcpy(dip->label.name, AudioNmute, nsize);
1082		goto onoff;
1083
1084	case CSAUDIO_MONITOR_LVL:
1085		dip->type = AUDIO_MIXER_VALUE;
1086		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1087		dip->prev = AUDIO_MIXER_LAST;
1088		dip->next = CSAUDIO_MONITOR_MUTE;
1089		strlcpy(dip->label.name, AudioNmonitor, nsize);
1090		dip->un.v.num_channels = 1;
1091		dip->un.v.delta = 4;
1092		strlcpy(dip->un.v.units.name, AudioNvolume, nsize);
1093		break;
1094	case CSAUDIO_MONITOR_MUTE:
1095		dip->type = AUDIO_MIXER_ENUM;
1096		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1097		dip->prev = CSAUDIO_MONITOR_LVL;
1098		dip->next = AUDIO_MIXER_LAST;
1099		strlcpy(dip->label.name, AudioNmute, nsize);
1100		goto onoff;
1101
1102	case CSAUDIO_REC_LVL:
1103		dip->type = AUDIO_MIXER_VALUE;
1104		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1105		dip->prev = dip->next = AUDIO_MIXER_LAST;
1106		strlcpy(dip->label.name, AudioNvolume, nsize);
1107		dip->un.v.num_channels = 2;
1108		dip->un.v.delta = 16;
1109		strlcpy(dip->un.v.units.name, AudioNvolume, nsize);
1110		break;
1111	case CSAUDIO_RECORD_SOURCE:
1112		dip->type = AUDIO_MIXER_ENUM;
1113		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1114		dip->prev = dip->next = AUDIO_MIXER_LAST;
1115		strlcpy(dip->label.name, AudioNsource, nsize);
1116		dip->un.e.num_mem = 4;
1117		strlcpy(dip->un.e.member[0].label.name, AudioNline, nsize);
1118		dip->un.e.member[0].ord = REC_PORT_LINE;
1119		strlcpy(dip->un.e.member[1].label.name, AudioNcd, nsize);
1120		dip->un.e.member[1].ord = REC_PORT_CD;
1121		strlcpy(dip->un.e.member[2].label.name, AudioNmicrophone, nsize);
1122		dip->un.e.member[2].ord = REC_PORT_MIC;
1123		strlcpy(dip->un.e.member[3].label.name, AudioNmixerout, nsize);
1124		dip->un.e.member[3].ord = REC_PORT_MIX;
1125		break;
1126
1127	case CSAUDIO_MIC_PREAMP:
1128		dip->type = AUDIO_MIXER_ENUM;
1129		dip->mixer_class = CSAUDIO_RECORD_CLASS;
1130		dip->prev = dip->next = AUDIO_MIXER_LAST;
1131		snprintf(dip->label.name, nsize, "%s_%s", AudioNmicrophone,
1132		   AudioNpreamp);
1133		goto onoff;
1134
1135onoff:
1136		dip->un.e.num_mem = 2;
1137		strlcpy(dip->un.e.member[0].label.name, AudioNon, nsize);
1138		dip->un.e.member[0].ord = 1;
1139		strlcpy(dip->un.e.member[1].label.name, AudioNoff, nsize);
1140		dip->un.e.member[1].ord = 0;
1141		break;
1142
1143	default:
1144		err = ENXIO;
1145	}
1146
1147	return (err);
1148}
1149
1150int
1151ce4231_get_props(addr)
1152	void *addr;
1153{
1154	return (AUDIO_PROP_FULLDUPLEX);
1155}
1156
1157/*
1158 * Hardware interrupt handler
1159 */
1160/*
1161 * Don't bother with the AD1848_STATUS register.  It's interrupt bit gets
1162 * set for both recording and playback interrupts.  But we have separate
1163 * handlers for playback and recording, and if we clear the status in
1164 * one handler while there is an interrupt pending for the other direction
1165 * as well, we'll never notice the interrupt for the other direction.
1166 *
1167 * Instead rely solely on CS_IRQ_STATUS, which has separate bits for
1168 * playback and recording interrupts.  Also note that resetting
1169 * AD1848_STATUS clears the interrupt bits in CS_IRQ_STATUS.
1170 */
1171
1172int
1173ce4231_pintr(v)
1174	void *v;
1175{
1176	struct ce4231_softc *sc = (struct ce4231_softc *)v;
1177	u_int32_t csr;
1178	u_int8_t reg;
1179	struct cs_dma *p;
1180	struct cs_chdma *chdma = &sc->sc_pchdma;
1181	int r = 0;
1182
1183	mtx_enter(&audio_lock);
1184	csr = P_READ(sc, EBDMA_DCSR);
1185
1186	reg = ce4231_read(sc, CS_IRQ_STATUS);
1187	if (reg & CS_IRQ_PI) {
1188		ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1189		ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1190		ce4231_write(sc, CS_IRQ_STATUS, reg & ~CS_IRQ_PI);
1191	}
1192
1193	P_WRITE(sc, EBDMA_DCSR, csr);
1194
1195	if (csr & EBDCSR_INT)
1196		r = 1;
1197
1198	if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) {
1199		u_long nextaddr, togo;
1200
1201		p = chdma->cur_dma;
1202		togo = chdma->segsz - chdma->count;
1203		if (togo == 0) {
1204			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1205			chdma->count = togo = chdma->blksz;
1206		} else {
1207			nextaddr = chdma->lastaddr;
1208			if (togo > chdma->blksz)
1209				togo = chdma->blksz;
1210			chdma->count += togo;
1211		}
1212
1213		P_WRITE(sc, EBDMA_DCNT, togo);
1214		P_WRITE(sc, EBDMA_DADDR, nextaddr);
1215		chdma->lastaddr = nextaddr + togo;
1216
1217		if (sc->sc_pintr != NULL)
1218			(*sc->sc_pintr)(sc->sc_parg);
1219		r = 1;
1220	}
1221	mtx_leave(&audio_lock);
1222	return (r);
1223}
1224
1225int
1226ce4231_cintr(v)
1227	void *v;
1228{
1229	struct ce4231_softc *sc = (struct ce4231_softc *)v;
1230	u_int32_t csr;
1231	u_int8_t reg;
1232	struct cs_dma *p;
1233	struct cs_chdma *chdma = &sc->sc_rchdma;
1234	int r = 0;
1235
1236	mtx_enter(&audio_lock);
1237	csr = C_READ(sc, EBDMA_DCSR);
1238
1239	reg = ce4231_read(sc, CS_IRQ_STATUS);
1240	if (reg & CS_IRQ_CI) {
1241		ce4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1242		ce4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1243		ce4231_write(sc, CS_IRQ_STATUS, reg & ~CS_IRQ_CI);
1244	}
1245
1246	C_WRITE(sc, EBDMA_DCSR, csr);
1247
1248	if (csr & EBDCSR_INT)
1249		r = 1;
1250
1251	if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) {
1252		u_long nextaddr, togo;
1253
1254		p = chdma->cur_dma;
1255		togo = chdma->segsz - chdma->count;
1256		if (togo == 0) {
1257			nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1258			chdma->count = togo = chdma->blksz;
1259		} else {
1260			nextaddr = chdma->lastaddr;
1261			if (togo > chdma->blksz)
1262				togo = chdma->blksz;
1263			chdma->count += togo;
1264		}
1265
1266		C_WRITE(sc, EBDMA_DCNT, togo);
1267		C_WRITE(sc, EBDMA_DADDR, nextaddr);
1268		chdma->lastaddr = nextaddr + togo;
1269
1270		if (sc->sc_rintr != NULL)
1271			(*sc->sc_rintr)(sc->sc_rarg);
1272		r = 1;
1273	}
1274	mtx_leave(&audio_lock);
1275	return (r);
1276}
1277
1278void *
1279ce4231_alloc(addr, direction, size, pool, flags)
1280	void *addr;
1281	int direction;
1282	size_t size;
1283	int pool;
1284	int flags;
1285{
1286	struct ce4231_softc *sc = (struct ce4231_softc *)addr;
1287	bus_dma_tag_t dmat = sc->sc_dmatag;
1288	struct cs_dma *p;
1289
1290	p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1291	if (p == NULL)
1292		return (NULL);
1293
1294	if (bus_dmamap_create(dmat, size, 1, size, 0,
1295	    BUS_DMA_NOWAIT, &p->dmamap) != 0)
1296		goto fail;
1297
1298	p->size = size;
1299
1300	if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
1301	    sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs,
1302	    BUS_DMA_NOWAIT) != 0)
1303		goto fail1;
1304
1305	if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
1306	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
1307		goto fail2;
1308
1309	if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
1310	    BUS_DMA_NOWAIT) != 0)
1311		goto fail3;
1312
1313	p->next = sc->sc_dmas;
1314	sc->sc_dmas = p;
1315	return (p->addr);
1316
1317fail3:
1318	bus_dmamem_unmap(dmat, p->addr, p->size);
1319fail2:
1320	bus_dmamem_free(dmat, p->segs, p->nsegs);
1321fail1:
1322	bus_dmamap_destroy(dmat, p->dmamap);
1323fail:
1324	free(p, pool, 0);
1325	return (NULL);
1326}
1327
1328void
1329ce4231_free(addr, ptr, pool)
1330	void *addr;
1331	void *ptr;
1332	int pool;
1333{
1334	struct ce4231_softc *sc = addr;
1335	bus_dma_tag_t dmat = sc->sc_dmatag;
1336	struct cs_dma *p, **pp;
1337
1338	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1339		if (p->addr != ptr)
1340			continue;
1341		bus_dmamap_unload(dmat, p->dmamap);
1342		bus_dmamem_unmap(dmat, p->addr, p->size);
1343		bus_dmamem_free(dmat, p->segs, p->nsegs);
1344		bus_dmamap_destroy(dmat, p->dmamap);
1345		*pp = p->next;
1346		free(p, pool, 0);
1347		return;
1348	}
1349	printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1350}
1351
1352int
1353ce4231_trigger_output(addr, start, end, blksize, intr, arg, param)
1354	void *addr, *start, *end;
1355	int blksize;
1356	void (*intr)(void *);
1357	void *arg;
1358	struct audio_params *param;
1359{
1360	struct ce4231_softc *sc = addr;
1361	struct cs_dma *p;
1362	struct cs_chdma *chdma = &sc->sc_pchdma;
1363	u_int32_t csr;
1364	vaddr_t n;
1365
1366	sc->sc_pintr = intr;
1367	sc->sc_parg = arg;
1368
1369	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1370		/*EMPTY*/;
1371	if (p == NULL) {
1372		printf("%s: trigger_output: bad addr: %p\n",
1373		    sc->sc_dev.dv_xname, start);
1374		return (EINVAL);
1375	}
1376
1377	n = (char *)end - (char *)start;
1378
1379	/*
1380	 * Do only `blksize' at a time, so audio_pint() is kept
1381	 * synchronous with us...
1382	 */
1383	chdma->cur_dma = p;
1384	chdma->blksz = blksize;
1385	chdma->segsz = n;
1386
1387	if (n > chdma->blksz)
1388		n = chdma->blksz;
1389
1390	chdma->count = n;
1391
1392	csr = P_READ(sc, EBDMA_DCSR);
1393	if (csr & EBDCSR_DMAEN) {
1394		P_WRITE(sc, EBDMA_DCNT, (u_long)n);
1395		P_WRITE(sc, EBDMA_DADDR,
1396		    (u_long)p->dmamap->dm_segs[0].ds_addr);
1397	} else {
1398		P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
1399		P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
1400
1401		P_WRITE(sc, EBDMA_DCNT, (u_long)n);
1402		P_WRITE(sc, EBDMA_DADDR,
1403		    (u_long)p->dmamap->dm_segs[0].ds_addr);
1404
1405		P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_DMAEN |
1406		    EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN);
1407
1408		ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1409		ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1410		ce4231_write(sc, SP_INTERFACE_CONFIG,
1411		    ce4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
1412	}
1413	chdma->lastaddr = p->dmamap->dm_segs[0].ds_addr + n;
1414
1415	return (0);
1416}
1417
1418int
1419ce4231_trigger_input(addr, start, end, blksize, intr, arg, param)
1420	void *addr, *start, *end;
1421	int blksize;
1422	void (*intr)(void *);
1423	void *arg;
1424	struct audio_params *param;
1425{
1426	struct ce4231_softc *sc = addr;
1427	struct cs_dma *p;
1428	struct cs_chdma *chdma = &sc->sc_rchdma;
1429	u_int32_t csr;
1430	vaddr_t n;
1431
1432	sc->sc_rintr = intr;
1433	sc->sc_rarg = arg;
1434
1435	for (p = sc->sc_dmas; p->addr != start; p = p->next)
1436		/*EMPTY*/;
1437	if (p == NULL) {
1438		printf("%s: trigger_input: bad addr: %p\n",
1439		    sc->sc_dev.dv_xname, start);
1440		return (EINVAL);
1441	}
1442
1443	n = (char *)end - (char *)start;
1444
1445	/*
1446	 * Do only `blksize' at a time, so audio_rint() is kept
1447	 * synchronous with us...
1448	 */
1449	chdma->cur_dma = p;
1450	chdma->blksz = blksize;
1451	chdma->segsz = n;
1452
1453	if (n > chdma->blksz)
1454		n = chdma->blksz;
1455
1456	chdma->count = n;
1457
1458	csr = C_READ(sc, EBDMA_DCSR);
1459	if (csr & EBDCSR_DMAEN) {
1460		C_WRITE(sc, EBDMA_DCNT, (u_long)n);
1461		C_WRITE(sc, EBDMA_DADDR,
1462		    (u_long)p->dmamap->dm_segs[0].ds_addr);
1463	} else {
1464		C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
1465		C_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
1466
1467		C_WRITE(sc, EBDMA_DCNT, (u_long)n);
1468		C_WRITE(sc, EBDMA_DADDR,
1469		    (u_long)p->dmamap->dm_segs[0].ds_addr);
1470
1471		C_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_WRITE |
1472		    EBDCSR_DMAEN | EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN);
1473
1474		ce4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1475		ce4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1476		ce4231_write(sc, SP_INTERFACE_CONFIG,
1477		    ce4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1478	}
1479	chdma->lastaddr = p->dmamap->dm_segs[0].ds_addr + n;
1480
1481	return (0);
1482}
1483