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