1/*      $NetBSD: sv.c,v 1.63 2024/02/09 22:08:36 andvar Exp $ */
2/*      $OpenBSD: sv.c,v 1.2 1998/07/13 01:50:15 csapuntz Exp $ */
3
4/*
5 * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Charles M. Hannum.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1998 Constantine Paul Sapuntzakis
35 * All rights reserved
36 *
37 * Author: Constantine Paul Sapuntzakis (csapuntz@cvs.openbsd.org)
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 * 3. The author's name or those of the contributors may be used to
48 *    endorse or promote products derived from this software without
49 *    specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS
52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
62 */
63
64/*
65 * S3 SonicVibes driver
66 *   Heavily based on the eap driver by Lennart Augustsson
67 */
68
69#include <sys/cdefs.h>
70__KERNEL_RCSID(0, "$NetBSD: sv.c,v 1.63 2024/02/09 22:08:36 andvar Exp $");
71
72#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/kernel.h>
75#include <sys/kmem.h>
76#include <sys/device.h>
77
78#include <dev/pci/pcireg.h>
79#include <dev/pci/pcivar.h>
80#include <dev/pci/pcidevs.h>
81
82#include <sys/audioio.h>
83#include <dev/audio/audio_if.h>
84
85#include <dev/ic/i8237reg.h>
86#include <dev/pci/svreg.h>
87#include <dev/pci/svvar.h>
88
89#include <sys/bus.h>
90
91/* XXX
92 * The SonicVibes DMA is broken and only works on 24-bit addresses.
93 * As long as bus_dmamem_alloc_range() is missing we use the ISA
94 * DMA tag on i386.
95 */
96#if defined(amd64) || defined(i386)
97#include <dev/isa/isavar.h>
98#endif
99
100#ifdef AUDIO_DEBUG
101#define DPRINTF(x)	if (svdebug) printf x
102#define DPRINTFN(n,x)	if (svdebug>(n)) printf x
103int	svdebug = 0;
104#else
105#define DPRINTF(x)
106#define DPRINTFN(n,x)
107#endif
108
109static int	sv_match(device_t, cfdata_t, void *);
110static void	sv_attach(device_t, device_t, void *);
111static int	sv_intr(void *);
112
113struct sv_dma {
114	bus_dmamap_t map;
115	void *addr;
116	bus_dma_segment_t segs[1];
117	int nsegs;
118	size_t size;
119	struct sv_dma *next;
120};
121#define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
122#define KERNADDR(p) ((void *)((p)->addr))
123
124CFATTACH_DECL_NEW(sv, sizeof(struct sv_softc),
125    sv_match, sv_attach, NULL, NULL);
126
127static struct audio_device sv_device = {
128	"S3 SonicVibes",
129	"",
130	"sv"
131};
132
133#define ARRAY_SIZE(foo)  ((sizeof(foo)) / sizeof(foo[0]))
134
135static int	sv_allocmem(struct sv_softc *, size_t, size_t, int,
136			    struct sv_dma *);
137static int	sv_freemem(struct sv_softc *, struct sv_dma *);
138
139static void	sv_init_mixer(struct sv_softc *);
140
141static int	sv_open(void *, int);
142static int	sv_query_format(void *, audio_format_query_t *);
143static int	sv_set_format(void *, int,
144			      const audio_params_t *, const audio_params_t *,
145			      audio_filter_reg_t *, audio_filter_reg_t *);
146static int	sv_round_blocksize(void *, int, int, const audio_params_t *);
147static int	sv_trigger_output(void *, void *, void *, int, void (*)(void *),
148				  void *, const audio_params_t *);
149static int	sv_trigger_input(void *, void *, void *, int, void (*)(void *),
150				 void *, const audio_params_t *);
151static int	sv_halt_output(void *);
152static int	sv_halt_input(void *);
153static int	sv_getdev(void *, struct audio_device *);
154static int	sv_mixer_set_port(void *, mixer_ctrl_t *);
155static int	sv_mixer_get_port(void *, mixer_ctrl_t *);
156static int	sv_query_devinfo(void *, mixer_devinfo_t *);
157static void *	sv_malloc(void *, int, size_t);
158static void	sv_free(void *, void *, size_t);
159static int	sv_get_props(void *);
160static void	sv_get_locks(void *, kmutex_t **, kmutex_t **);
161
162#ifdef AUDIO_DEBUG
163void    sv_dumpregs(struct sv_softc *sc);
164#endif
165
166static const struct audio_hw_if sv_hw_if = {
167	.open			= sv_open,
168	.query_format		= sv_query_format,
169	.set_format		= sv_set_format,
170	.round_blocksize	= sv_round_blocksize,
171	.halt_output		= sv_halt_output,
172	.halt_input		= sv_halt_input,
173	.getdev			= sv_getdev,
174	.set_port		= sv_mixer_set_port,
175	.get_port		= sv_mixer_get_port,
176	.query_devinfo		= sv_query_devinfo,
177	.allocm			= sv_malloc,
178	.freem			= sv_free,
179	.get_props		= sv_get_props,
180	.trigger_output		= sv_trigger_output,
181	.trigger_input		= sv_trigger_input,
182	.get_locks		= sv_get_locks,
183};
184
185static const struct audio_format sv_formats[] = {
186	{
187		.mode		= AUMODE_PLAY | AUMODE_RECORD,
188		.encoding	= AUDIO_ENCODING_SLINEAR_LE,
189		.validbits	= 16,
190		.precision	= 16,
191		.channels	= 2,
192		.channel_mask	= AUFMT_STEREO,
193		.frequency_type	= 0,
194		.frequency	= { 2000, 48000 },
195	},
196};
197#define SV_NFORMATS	__arraycount(sv_formats)
198
199
200static void
201sv_write(struct sv_softc *sc, uint8_t reg, uint8_t val)
202{
203
204	DPRINTFN(8,("sv_write(0x%x, 0x%x)\n", reg, val));
205	bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
206}
207
208static uint8_t
209sv_read(struct sv_softc *sc, uint8_t reg)
210{
211	uint8_t val;
212
213	val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg);
214	DPRINTFN(8,("sv_read(0x%x) = 0x%x\n", reg, val));
215	return val;
216}
217
218static uint8_t
219sv_read_indirect(struct sv_softc *sc, uint8_t reg)
220{
221	uint8_t val;
222
223	sv_write(sc, SV_CODEC_IADDR, reg & SV_IADDR_MASK);
224	val = sv_read(sc, SV_CODEC_IDATA);
225	return val;
226}
227
228static void
229sv_write_indirect(struct sv_softc *sc, uint8_t reg, uint8_t val)
230{
231	uint8_t iaddr;
232
233	iaddr = reg & SV_IADDR_MASK;
234	if (reg == SV_DMA_DATA_FORMAT)
235		iaddr |= SV_IADDR_MCE;
236
237	sv_write(sc, SV_CODEC_IADDR, iaddr);
238	sv_write(sc, SV_CODEC_IDATA, val);
239}
240
241static int
242sv_match(device_t parent, cfdata_t match, void *aux)
243{
244	struct pci_attach_args *pa;
245
246	pa = aux;
247	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_S3 &&
248	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_S3_SONICVIBES)
249		return 1;
250
251	return 0;
252}
253
254static pcireg_t pci_io_alloc_low, pci_io_alloc_high;
255
256static int
257pci_alloc_io(pci_chipset_tag_t pc, pcitag_t pt, int pcioffs,
258    bus_space_tag_t iot, bus_size_t size, bus_size_t align,
259    bus_size_t bound, int flags, bus_space_handle_t *ioh)
260{
261	bus_addr_t addr;
262	int error;
263
264	error = bus_space_alloc(iot, pci_io_alloc_low, pci_io_alloc_high,
265				size, align, bound, flags, &addr, ioh);
266	if (error)
267		return error;
268
269	pci_conf_write(pc, pt, pcioffs, addr);
270	return 0;
271}
272
273/*
274 * Allocate IO addresses when all other configuration is done.
275 */
276static void
277sv_defer(device_t self)
278{
279	struct sv_softc *sc;
280	pci_chipset_tag_t pc;
281	pcitag_t pt;
282	pcireg_t dmaio;
283
284	sc = device_private(self);
285	pc = sc->sc_pa.pa_pc;
286	pt = sc->sc_pa.pa_tag;
287	DPRINTF(("sv_defer: %p\n", sc));
288
289	/* XXX
290	 * Get a reasonable default for the I/O range.
291	 * Assume the range around SB_PORTBASE is valid on this PCI bus.
292	 */
293	pci_io_alloc_low = pci_conf_read(pc, pt, SV_SB_PORTBASE_SLOT);
294	pci_io_alloc_high = pci_io_alloc_low + 0x1000;
295
296	if (pci_alloc_io(pc, pt, SV_DMAA_CONFIG_OFF,
297			  sc->sc_iot, SV_DMAA_SIZE, SV_DMAA_ALIGN, 0,
298			  0, &sc->sc_dmaa_ioh)) {
299		printf("sv_attach: cannot allocate DMA A range\n");
300		return;
301	}
302	dmaio = pci_conf_read(pc, pt, SV_DMAA_CONFIG_OFF);
303	DPRINTF(("sv_attach: addr a dmaio=0x%lx\n", (u_long)dmaio));
304	pci_conf_write(pc, pt, SV_DMAA_CONFIG_OFF,
305		       dmaio | SV_DMA_CHANNEL_ENABLE | SV_DMAA_EXTENDED_ADDR);
306
307	if (pci_alloc_io(pc, pt, SV_DMAC_CONFIG_OFF,
308			  sc->sc_iot, SV_DMAC_SIZE, SV_DMAC_ALIGN, 0,
309			  0, &sc->sc_dmac_ioh)) {
310		printf("sv_attach: cannot allocate DMA C range\n");
311		return;
312	}
313	dmaio = pci_conf_read(pc, pt, SV_DMAC_CONFIG_OFF);
314	DPRINTF(("sv_attach: addr c dmaio=0x%lx\n", (u_long)dmaio));
315	pci_conf_write(pc, pt, SV_DMAC_CONFIG_OFF,
316		       dmaio | SV_DMA_CHANNEL_ENABLE);
317
318	sc->sc_dmaset = 1;
319}
320
321static void
322sv_attach(device_t parent, device_t self, void *aux)
323{
324	struct sv_softc *sc;
325	struct pci_attach_args *pa;
326	pci_chipset_tag_t pc;
327	pcitag_t pt;
328	pci_intr_handle_t ih;
329	pcireg_t csr;
330	char const *intrstr;
331	uint8_t reg;
332	struct audio_attach_args arg;
333	char intrbuf[PCI_INTRSTR_LEN];
334
335	sc = device_private(self);
336	pa = aux;
337	pc = pa->pa_pc;
338	pt = pa->pa_tag;
339	aprint_naive("\n");
340	aprint_normal("\n");
341
342	/* Map I/O registers */
343	if (pci_mapreg_map(pa, SV_ENHANCED_PORTBASE_SLOT,
344			   PCI_MAPREG_TYPE_IO, 0,
345			   &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
346		aprint_error_dev(self, "can't map enhanced i/o space\n");
347		return;
348	}
349	if (pci_mapreg_map(pa, SV_FM_PORTBASE_SLOT,
350			   PCI_MAPREG_TYPE_IO, 0,
351			   &sc->sc_opliot, &sc->sc_oplioh, NULL, NULL)) {
352		aprint_error_dev(self, "can't map FM i/o space\n");
353		return;
354	}
355	if (pci_mapreg_map(pa, SV_MIDI_PORTBASE_SLOT,
356			   PCI_MAPREG_TYPE_IO, 0,
357			   &sc->sc_midiiot, &sc->sc_midiioh, NULL, NULL)) {
358		aprint_error_dev(self, "can't map MIDI i/o space\n");
359		return;
360	}
361	DPRINTF(("sv: IO ports: enhanced=0x%x, OPL=0x%x, MIDI=0x%x\n",
362		 (int)sc->sc_ioh, (int)sc->sc_oplioh, (int)sc->sc_midiioh));
363
364#if defined(alpha)
365	/* XXX Force allocation through the SGMAP. */
366	sc->sc_dmatag = alphabus_dma_get_tag(pa->pa_dmat, ALPHA_BUS_ISA);
367#elif defined(amd64) || defined(i386)
368/* XXX
369 * The SonicVibes DMA is broken and only works on 24-bit addresses.
370 * As long as bus_dmamem_alloc_range() is missing we use the ISA
371 * DMA tag on i386.
372 */
373	sc->sc_dmatag = &isa_bus_dma_tag;
374#else
375	sc->sc_dmatag = pa->pa_dmat;
376#endif
377
378	pci_conf_write(pc, pt, SV_DMAA_CONFIG_OFF, SV_DMAA_EXTENDED_ADDR);
379	pci_conf_write(pc, pt, SV_DMAC_CONFIG_OFF, 0);
380
381	/* Enable the device. */
382	csr = pci_conf_read(pc, pt, PCI_COMMAND_STATUS_REG);
383	pci_conf_write(pc, pt, PCI_COMMAND_STATUS_REG,
384		       csr | PCI_COMMAND_MASTER_ENABLE);
385
386	sv_write_indirect(sc, SV_ANALOG_POWER_DOWN_CONTROL, 0);
387	sv_write_indirect(sc, SV_DIGITAL_POWER_DOWN_CONTROL, 0);
388
389	/* initialize codec registers */
390	reg = sv_read(sc, SV_CODEC_CONTROL);
391	reg |= SV_CTL_RESET;
392	sv_write(sc, SV_CODEC_CONTROL, reg);
393	delay(50);
394
395	reg = sv_read(sc, SV_CODEC_CONTROL);
396	reg &= ~SV_CTL_RESET;
397	reg |= SV_CTL_INTA | SV_CTL_ENHANCED;
398
399	/* This write clears the reset */
400	sv_write(sc, SV_CODEC_CONTROL, reg);
401	delay(50);
402
403	/* This write actually shoves the new values in */
404	sv_write(sc, SV_CODEC_CONTROL, reg);
405
406	DPRINTF(("sv_attach: control=0x%x\n", sv_read(sc, SV_CODEC_CONTROL)));
407
408	/* Map and establish the interrupt. */
409	if (pci_intr_map(pa, &ih)) {
410		aprint_error_dev(self, "couldn't map interrupt\n");
411		return;
412	}
413
414	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
415	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
416
417	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
418	sc->sc_ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, sv_intr, sc,
419	    device_xname(self));
420	if (sc->sc_ih == NULL) {
421		aprint_error_dev(self, "couldn't establish interrupt");
422		if (intrstr != NULL)
423			aprint_error(" at %s", intrstr);
424		aprint_error("\n");
425		mutex_destroy(&sc->sc_lock);
426		mutex_destroy(&sc->sc_intr_lock);
427		return;
428	}
429	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
430	aprint_normal_dev(self, "rev %d",
431	    sv_read_indirect(sc, SV_REVISION_LEVEL));
432	if (sv_read(sc, SV_CODEC_CONTROL) & SV_CTL_MD1)
433		aprint_normal(", reverb SRAM present");
434	if (!(sv_read_indirect(sc, SV_WAVETABLE_SOURCE_SELECT) & SV_WSS_WT0))
435		aprint_normal(", wavetable ROM present");
436	aprint_normal("\n");
437
438	/* Enable DMA interrupts */
439	reg = sv_read(sc, SV_CODEC_INTMASK);
440	reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
441	reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
442	sv_write(sc, SV_CODEC_INTMASK, reg);
443	sv_read(sc, SV_CODEC_STATUS);
444
445	sv_init_mixer(sc);
446
447	audio_attach_mi(&sv_hw_if, sc, self);
448
449	arg.type = AUDIODEV_TYPE_OPL;
450	arg.hwif = 0;
451	arg.hdl = 0;
452	(void)config_found(self, &arg, audioprint, CFARGS(.iattr = "sv"));
453
454	sc->sc_pa = *pa;	/* for deferred setup */
455	config_defer(self, sv_defer);
456}
457
458#ifdef AUDIO_DEBUG
459void
460sv_dumpregs(struct sv_softc *sc)
461{
462	int idx;
463
464#if 0
465	for (idx = 0; idx < 0x50; idx += 4)
466		printf ("%02x = %x\n", idx,
467			pci_conf_read(pa->pa_pc, pa->pa_tag, idx));
468#endif
469
470	for (idx = 0; idx < 6; idx++)
471		printf ("REG %02x = %02x\n", idx, sv_read(sc, idx));
472
473	for (idx = 0; idx < 0x32; idx++)
474		printf ("IREG %02x = %02x\n", idx, sv_read_indirect(sc, idx));
475
476	for (idx = 0; idx < 0x10; idx++)
477		printf ("DMA %02x = %02x\n", idx,
478			bus_space_read_1(sc->sc_iot, sc->sc_dmaa_ioh, idx));
479}
480#endif
481
482static int
483sv_intr(void *p)
484{
485	struct sv_softc *sc;
486	uint8_t intr;
487
488	sc = p;
489
490	mutex_spin_enter(&sc->sc_intr_lock);
491
492	intr = sv_read(sc, SV_CODEC_STATUS);
493	DPRINTFN(5,("sv_intr: intr=0x%x\n", intr));
494
495	if (intr & SV_INTSTATUS_DMAA) {
496		if (sc->sc_pintr)
497			sc->sc_pintr(sc->sc_parg);
498	}
499
500	if (intr & SV_INTSTATUS_DMAC) {
501		if (sc->sc_rintr)
502			sc->sc_rintr(sc->sc_rarg);
503	}
504
505	mutex_spin_exit(&sc->sc_intr_lock);
506
507	return (intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC)) != 0;
508}
509
510static int
511sv_allocmem(struct sv_softc *sc, size_t size, size_t align,
512    int direction, struct sv_dma *p)
513{
514	int error;
515
516	p->size = size;
517	error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
518	    p->segs, ARRAY_SIZE(p->segs), &p->nsegs, BUS_DMA_WAITOK);
519	if (error)
520		return error;
521
522	error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
523	    &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
524	if (error)
525		goto free;
526
527	error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
528	    0, BUS_DMA_WAITOK, &p->map);
529	if (error)
530		goto unmap;
531
532	error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
533	    BUS_DMA_WAITOK | ((direction == AUMODE_RECORD) ? BUS_DMA_READ : BUS_DMA_WRITE));
534	if (error)
535		goto destroy;
536	DPRINTF(("sv_allocmem: pa=%lx va=%lx pba=%lx\n",
537	    (long)p->segs[0].ds_addr, (long)KERNADDR(p), (long)DMAADDR(p)));
538	return 0;
539
540destroy:
541	bus_dmamap_destroy(sc->sc_dmatag, p->map);
542unmap:
543	bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
544free:
545	bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
546	return error;
547}
548
549static int
550sv_freemem(struct sv_softc *sc, struct sv_dma *p)
551{
552
553	bus_dmamap_unload(sc->sc_dmatag, p->map);
554	bus_dmamap_destroy(sc->sc_dmatag, p->map);
555	bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
556	bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
557	return 0;
558}
559
560static int
561sv_open(void *addr, int flags)
562{
563	struct sv_softc *sc;
564
565	sc = addr;
566	DPRINTF(("sv_open\n"));
567	if (!sc->sc_dmaset)
568		return ENXIO;
569
570	return 0;
571}
572
573static int
574sv_query_format(void *addr, audio_format_query_t *afp)
575{
576
577	return audio_query_format(sv_formats, SV_NFORMATS, afp);
578}
579
580static int
581sv_set_format(void *addr, int setmode,
582    const audio_params_t *play, const audio_params_t *rec,
583    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
584{
585	struct sv_softc *sc;
586	uint32_t val;
587
588	sc = addr;
589
590	/* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
591
592	val = play->sample_rate * 65536 / 48000;
593	/*
594	 * If the sample rate is exactly 48 kHz, the fraction would overflow the
595	 * register, so we have to bias it.  This causes a little clock drift.
596	 * The drift is below normal crystal tolerance (.0001%), so although
597	 * this seems a little silly, we can pretty much ignore it.
598	 * (I tested the output speed with values of 1-20, just to be sure this
599	 * register isn't *supposed* to have a bias.  It isn't.)
600	 * - mycroft
601	 */
602	if (val > 65535)
603		val = 65535;
604
605	mutex_spin_enter(&sc->sc_intr_lock);
606	sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_0, val & 0xff);
607	sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_1, val >> 8);
608	mutex_spin_exit(&sc->sc_intr_lock);
609
610#define F_REF 24576000
611
612#define ABS(x) (((x) < 0) ? (-x) : (x))
613
614	if (setmode & AUMODE_RECORD) {
615		/* The ADC reference frequency (f_out) is 512 * sample rate */
616
617		/* f_out is derived from the 24.576MHz crystal by three values:
618		   M & N & R. The equation is as follows:
619
620		   f_out = (m + 2) * f_ref / ((n + 2) * (2 ^ a))
621
622		   with the constraint that:
623
624		   80 MHz < (m + 2) / (n + 2) * f_ref <= 150MHz
625		   and n, m >= 1
626		*/
627
628		int  goal_f_out;
629		int  a, n, m, best_n, best_m, best_error;
630		int  pll_sample;
631		int  error;
632
633		goal_f_out = 512 * rec->sample_rate;
634		best_n = 0;
635		best_m = 0;
636		best_error = 10000000;
637		for (a = 0; a < 8; a++) {
638			if ((goal_f_out * (1 << a)) >= 80000000)
639				break;
640		}
641
642		/* a != 8 because sample_rate >= 2000 */
643
644		for (n = 33; n > 2; n--) {
645			m = (goal_f_out * n * (1 << a)) / F_REF;
646			if ((m > 257) || (m < 3))
647				continue;
648
649			pll_sample = (m * F_REF) / (n * (1 << a));
650			pll_sample /= 512;
651
652			/* Threshold might be good here */
653			error = pll_sample - rec->sample_rate;
654			error = ABS(error);
655
656			if (error < best_error) {
657				best_error = error;
658				best_n = n;
659				best_m = m;
660				if (error == 0) break;
661			}
662		}
663
664		best_n -= 2;
665		best_m -= 2;
666
667		mutex_spin_enter(&sc->sc_intr_lock);
668		sv_write_indirect(sc, SV_ADC_PLL_M, best_m);
669		sv_write_indirect(sc, SV_ADC_PLL_N,
670				  best_n | (a << SV_PLL_R_SHIFT));
671		mutex_spin_exit(&sc->sc_intr_lock);
672	}
673
674	return 0;
675}
676
677static int
678sv_round_blocksize(void *addr, int blk, int mode,
679    const audio_params_t *param)
680{
681
682	blk = blk & -32;	/* keep good alignment */
683	if (blk < 32)
684		blk = 32;
685	return blk;
686}
687
688static int
689sv_trigger_output(void *addr, void *start, void *end, int blksize,
690    void (*intr)(void *), void *arg, const audio_params_t *param)
691{
692	struct sv_softc *sc;
693	struct sv_dma *p;
694	uint8_t mode;
695	int dma_count;
696
697	DPRINTFN(1, ("sv_trigger_output: sc=%p start=%p end=%p blksize=%d "
698	    "intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
699	sc = addr;
700	sc->sc_pintr = intr;
701	sc->sc_parg = arg;
702
703	mode = sv_read_indirect(sc, SV_DMA_DATA_FORMAT);
704	mode &= ~(SV_DMAA_FORMAT16 | SV_DMAA_STEREO);
705	if (param->precision == 16)
706		mode |= SV_DMAA_FORMAT16;
707	if (param->channels == 2)
708		mode |= SV_DMAA_STEREO;
709	sv_write_indirect(sc, SV_DMA_DATA_FORMAT, mode);
710
711	for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
712		continue;
713	if (p == NULL) {
714		printf("sv_trigger_output: bad addr %p\n", start);
715		return EINVAL;
716	}
717
718	dma_count = ((char *)end - (char *)start) - 1;
719	DPRINTF(("sv_trigger_output: DMA start loop input addr=%x cc=%d\n",
720	    (int)DMAADDR(p), dma_count));
721
722	bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0,
723			  DMAADDR(p));
724	bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_COUNT0,
725			  dma_count);
726	bus_space_write_1(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_MODE,
727			  DMA37MD_READ | DMA37MD_LOOP);
728
729	DPRINTF(("sv_trigger_output: current addr=%x\n",
730	    bus_space_read_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0)));
731
732	dma_count = blksize - 1;
733
734	sv_write_indirect(sc, SV_DMAA_COUNT1, dma_count >> 8);
735	sv_write_indirect(sc, SV_DMAA_COUNT0, dma_count & 0xFF);
736
737	mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
738	sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode | SV_PLAY_ENABLE);
739
740	return 0;
741}
742
743static int
744sv_trigger_input(void *addr, void *start, void *end, int blksize,
745    void (*intr)(void *), void *arg, const audio_params_t *param)
746{
747	struct sv_softc *sc;
748	struct sv_dma *p;
749	uint8_t mode;
750	int dma_count;
751
752	DPRINTFN(1, ("sv_trigger_input: sc=%p start=%p end=%p blksize=%d "
753	    "intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
754	sc = addr;
755	sc->sc_rintr = intr;
756	sc->sc_rarg = arg;
757
758	mode = sv_read_indirect(sc, SV_DMA_DATA_FORMAT);
759	mode &= ~(SV_DMAC_FORMAT16 | SV_DMAC_STEREO);
760	if (param->precision == 16)
761		mode |= SV_DMAC_FORMAT16;
762	if (param->channels == 2)
763		mode |= SV_DMAC_STEREO;
764	sv_write_indirect(sc, SV_DMA_DATA_FORMAT, mode);
765
766	for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
767		continue;
768	if (!p) {
769		printf("sv_trigger_input: bad addr %p\n", start);
770		return EINVAL;
771	}
772
773	dma_count = (((char *)end - (char *)start) >> 1) - 1;
774	DPRINTF(("sv_trigger_input: DMA start loop input addr=%x cc=%d\n",
775	    (int)DMAADDR(p), dma_count));
776
777	bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0,
778			  DMAADDR(p));
779	bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_COUNT0,
780			  dma_count);
781	bus_space_write_1(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_MODE,
782			  DMA37MD_WRITE | DMA37MD_LOOP);
783
784	DPRINTF(("sv_trigger_input: current addr=%x\n",
785	    bus_space_read_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0)));
786
787	dma_count = (blksize >> 1) - 1;
788
789	sv_write_indirect(sc, SV_DMAC_COUNT1, dma_count >> 8);
790	sv_write_indirect(sc, SV_DMAC_COUNT0, dma_count & 0xFF);
791
792	mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
793	sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode | SV_RECORD_ENABLE);
794
795	return 0;
796}
797
798static int
799sv_halt_output(void *addr)
800{
801	struct sv_softc *sc;
802	uint8_t mode;
803
804	DPRINTF(("sv: sv_halt_output\n"));
805	sc = addr;
806	mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
807	sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode & ~SV_PLAY_ENABLE);
808	sc->sc_pintr = 0;
809
810	return 0;
811}
812
813static int
814sv_halt_input(void *addr)
815{
816	struct sv_softc *sc;
817	uint8_t mode;
818
819	DPRINTF(("sv: sv_halt_input\n"));
820	sc = addr;
821	mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
822	sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode & ~SV_RECORD_ENABLE);
823	sc->sc_rintr = 0;
824
825	return 0;
826}
827
828static int
829sv_getdev(void *addr, struct audio_device *retp)
830{
831
832	*retp = sv_device;
833	return 0;
834}
835
836
837/*
838 * Mixer related code is here
839 *
840 */
841
842#define SV_INPUT_CLASS 0
843#define SV_OUTPUT_CLASS 1
844#define SV_RECORD_CLASS 2
845
846#define SV_LAST_CLASS 2
847
848static const char *mixer_classes[] =
849	{ AudioCinputs, AudioCoutputs, AudioCrecord };
850
851static const struct {
852	uint8_t   l_port;
853	uint8_t   r_port;
854	uint8_t   mask;
855	uint8_t   class;
856	const char *audio;
857} ports[] = {
858  { SV_LEFT_AUX1_INPUT_CONTROL, SV_RIGHT_AUX1_INPUT_CONTROL, SV_AUX1_MASK,
859    SV_INPUT_CLASS, "aux1" },
860  { SV_LEFT_CD_INPUT_CONTROL, SV_RIGHT_CD_INPUT_CONTROL, SV_CD_MASK,
861    SV_INPUT_CLASS, AudioNcd },
862  { SV_LEFT_LINE_IN_INPUT_CONTROL, SV_RIGHT_LINE_IN_INPUT_CONTROL, SV_LINE_IN_MASK,
863    SV_INPUT_CLASS, AudioNline },
864  { SV_MIC_INPUT_CONTROL, 0, SV_MIC_MASK, SV_INPUT_CLASS, AudioNmicrophone },
865  { SV_LEFT_SYNTH_INPUT_CONTROL, SV_RIGHT_SYNTH_INPUT_CONTROL,
866    SV_SYNTH_MASK, SV_INPUT_CLASS, AudioNfmsynth },
867  { SV_LEFT_AUX2_INPUT_CONTROL, SV_RIGHT_AUX2_INPUT_CONTROL, SV_AUX2_MASK,
868    SV_INPUT_CLASS, "aux2" },
869  { SV_LEFT_PCM_INPUT_CONTROL, SV_RIGHT_PCM_INPUT_CONTROL, SV_PCM_MASK,
870    SV_INPUT_CLASS, AudioNdac },
871  { SV_LEFT_MIXER_OUTPUT_CONTROL, SV_RIGHT_MIXER_OUTPUT_CONTROL,
872    SV_MIXER_OUT_MASK, SV_OUTPUT_CLASS, AudioNmaster }
873};
874
875
876static const struct {
877	int idx;
878	const char *name;
879} record_sources[] = {
880	{ SV_REC_CD, AudioNcd },
881	{ SV_REC_DAC, AudioNdac },
882	{ SV_REC_AUX2, "aux2" },
883	{ SV_REC_LINE, AudioNline },
884	{ SV_REC_AUX1, "aux1" },
885	{ SV_REC_MIC, AudioNmicrophone },
886	{ SV_REC_MIXER, AudioNmixerout }
887};
888
889
890#define SV_DEVICES_PER_PORT 2
891#define SV_FIRST_MIXER (SV_LAST_CLASS + 1)
892#define SV_LAST_MIXER (SV_DEVICES_PER_PORT * (ARRAY_SIZE(ports)) + SV_LAST_CLASS)
893#define SV_RECORD_SOURCE (SV_LAST_MIXER + 1)
894#define SV_MIC_BOOST (SV_LAST_MIXER + 2)
895#define SV_RECORD_GAIN (SV_LAST_MIXER + 3)
896#define SV_SRS_MODE (SV_LAST_MIXER + 4)
897
898static int
899sv_query_devinfo(void *addr, mixer_devinfo_t *dip)
900{
901	int i;
902
903	/* It's a class */
904	if (dip->index <= SV_LAST_CLASS) {
905		dip->type = AUDIO_MIXER_CLASS;
906		dip->mixer_class = dip->index;
907		dip->next = dip->prev = AUDIO_MIXER_LAST;
908		strcpy(dip->label.name, mixer_classes[dip->index]);
909		return 0;
910	}
911
912	if (dip->index >= SV_FIRST_MIXER &&
913	    dip->index <= SV_LAST_MIXER) {
914		int off, mute ,idx;
915
916		off = dip->index - SV_FIRST_MIXER;
917		mute = (off % SV_DEVICES_PER_PORT);
918		idx = off / SV_DEVICES_PER_PORT;
919		dip->mixer_class = ports[idx].class;
920		strcpy(dip->label.name, ports[idx].audio);
921
922		if (!mute) {
923			dip->type = AUDIO_MIXER_VALUE;
924			dip->prev = AUDIO_MIXER_LAST;
925			dip->next = dip->index + 1;
926
927			if (ports[idx].r_port != 0)
928				dip->un.v.num_channels = 2;
929			else
930				dip->un.v.num_channels = 1;
931
932			strcpy(dip->un.v.units.name, AudioNvolume);
933		} else {
934			dip->type = AUDIO_MIXER_ENUM;
935			dip->prev = dip->index - 1;
936			dip->next = AUDIO_MIXER_LAST;
937
938			strcpy(dip->label.name, AudioNmute);
939			dip->un.e.num_mem = 2;
940			strcpy(dip->un.e.member[0].label.name, AudioNoff);
941			dip->un.e.member[0].ord = 0;
942			strcpy(dip->un.e.member[1].label.name, AudioNon);
943			dip->un.e.member[1].ord = 1;
944		}
945
946		return 0;
947	}
948
949	switch (dip->index) {
950	case SV_RECORD_SOURCE:
951		dip->mixer_class = SV_RECORD_CLASS;
952		dip->prev = AUDIO_MIXER_LAST;
953		dip->next = SV_RECORD_GAIN;
954		strcpy(dip->label.name, AudioNsource);
955		dip->type = AUDIO_MIXER_ENUM;
956
957		dip->un.e.num_mem = ARRAY_SIZE(record_sources);
958		for (i = 0; i < ARRAY_SIZE(record_sources); i++) {
959			strcpy(dip->un.e.member[i].label.name,
960			       record_sources[i].name);
961			dip->un.e.member[i].ord = record_sources[i].idx;
962		}
963		return 0;
964
965	case SV_RECORD_GAIN:
966		dip->mixer_class = SV_RECORD_CLASS;
967		dip->prev = SV_RECORD_SOURCE;
968		dip->next = AUDIO_MIXER_LAST;
969		strcpy(dip->label.name, "gain");
970		dip->type = AUDIO_MIXER_VALUE;
971		dip->un.v.num_channels = 1;
972		strcpy(dip->un.v.units.name, AudioNvolume);
973		return 0;
974
975	case SV_MIC_BOOST:
976		dip->mixer_class = SV_RECORD_CLASS;
977		dip->prev = AUDIO_MIXER_LAST;
978		dip->next = AUDIO_MIXER_LAST;
979		strcpy(dip->label.name, "micboost");
980		goto on_off;
981
982	case SV_SRS_MODE:
983		dip->mixer_class = SV_OUTPUT_CLASS;
984		dip->prev = dip->next = AUDIO_MIXER_LAST;
985		strcpy(dip->label.name, AudioNspatial);
986
987	on_off:
988		dip->type = AUDIO_MIXER_ENUM;
989		dip->un.e.num_mem = 2;
990		strcpy(dip->un.e.member[0].label.name, AudioNoff);
991		dip->un.e.member[0].ord = 0;
992		strcpy(dip->un.e.member[1].label.name, AudioNon);
993		dip->un.e.member[1].ord = 1;
994		return 0;
995	}
996
997	return ENXIO;
998}
999
1000static int
1001sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1002{
1003	struct sv_softc *sc;
1004	uint8_t reg;
1005	int idx;
1006
1007	sc = addr;
1008	if (cp->dev >= SV_FIRST_MIXER &&
1009	    cp->dev <= SV_LAST_MIXER) {
1010		int off, mute;
1011
1012		off = cp->dev - SV_FIRST_MIXER;
1013		mute = (off % SV_DEVICES_PER_PORT);
1014		idx = off / SV_DEVICES_PER_PORT;
1015
1016		if (mute) {
1017			if (cp->type != AUDIO_MIXER_ENUM)
1018				return EINVAL;
1019
1020			mutex_spin_enter(&sc->sc_intr_lock);
1021			reg = sv_read_indirect(sc, ports[idx].l_port);
1022			if (cp->un.ord)
1023				reg |= SV_MUTE_BIT;
1024			else
1025				reg &= ~SV_MUTE_BIT;
1026			sv_write_indirect(sc, ports[idx].l_port, reg);
1027
1028			if (ports[idx].r_port) {
1029				reg = sv_read_indirect(sc, ports[idx].r_port);
1030				if (cp->un.ord)
1031					reg |= SV_MUTE_BIT;
1032				else
1033					reg &= ~SV_MUTE_BIT;
1034				sv_write_indirect(sc, ports[idx].r_port, reg);
1035			}
1036			mutex_spin_exit(&sc->sc_intr_lock);
1037		} else {
1038			int  lval, rval;
1039
1040			if (cp->type != AUDIO_MIXER_VALUE)
1041				return EINVAL;
1042
1043			if (cp->un.value.num_channels != 1 &&
1044			    cp->un.value.num_channels != 2)
1045				return (EINVAL);
1046
1047			if (ports[idx].r_port == 0) {
1048				if (cp->un.value.num_channels != 1)
1049					return (EINVAL);
1050				lval = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1051				rval = 0; /* shut up GCC */
1052			} else {
1053				if (cp->un.value.num_channels != 2)
1054					return (EINVAL);
1055
1056				lval = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1057				rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1058			}
1059
1060			mutex_spin_enter(&sc->sc_intr_lock);
1061			reg = sv_read_indirect(sc, ports[idx].l_port);
1062			reg &= ~(ports[idx].mask);
1063			lval = (AUDIO_MAX_GAIN - lval) * ports[idx].mask /
1064				AUDIO_MAX_GAIN;
1065			reg |= lval;
1066			sv_write_indirect(sc, ports[idx].l_port, reg);
1067
1068			if (ports[idx].r_port != 0) {
1069				reg = sv_read_indirect(sc, ports[idx].r_port);
1070				reg &= ~(ports[idx].mask);
1071
1072				rval = (AUDIO_MAX_GAIN - rval) * ports[idx].mask /
1073					AUDIO_MAX_GAIN;
1074				reg |= rval;
1075
1076				sv_write_indirect(sc, ports[idx].r_port, reg);
1077			}
1078
1079			sv_read_indirect(sc, ports[idx].l_port);
1080			mutex_spin_exit(&sc->sc_intr_lock);
1081		}
1082
1083		return 0;
1084	}
1085
1086
1087	switch (cp->dev) {
1088	case SV_RECORD_SOURCE:
1089		if (cp->type != AUDIO_MIXER_ENUM)
1090			return EINVAL;
1091
1092		for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) {
1093			if (record_sources[idx].idx == cp->un.ord)
1094				goto found;
1095		}
1096
1097		return EINVAL;
1098
1099	found:
1100		mutex_spin_enter(&sc->sc_intr_lock);
1101		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1102		reg &= ~SV_REC_SOURCE_MASK;
1103		reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
1104		sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1105
1106		reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
1107		reg &= ~SV_REC_SOURCE_MASK;
1108		reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
1109		sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
1110		mutex_spin_exit(&sc->sc_intr_lock);
1111		return 0;
1112
1113	case SV_RECORD_GAIN:
1114	{
1115		int val;
1116
1117		if (cp->type != AUDIO_MIXER_VALUE)
1118			return EINVAL;
1119
1120		if (cp->un.value.num_channels != 1)
1121			return EINVAL;
1122
1123		val = (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]
1124		    * SV_REC_GAIN_MASK) / AUDIO_MAX_GAIN;
1125
1126		mutex_spin_enter(&sc->sc_intr_lock);
1127		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1128		reg &= ~SV_REC_GAIN_MASK;
1129		reg |= val;
1130		sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1131
1132		reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
1133		reg &= ~SV_REC_GAIN_MASK;
1134		reg |= val;
1135		sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
1136		mutex_spin_exit(&sc->sc_intr_lock);
1137	}
1138	return (0);
1139
1140	case SV_MIC_BOOST:
1141		if (cp->type != AUDIO_MIXER_ENUM)
1142			return EINVAL;
1143
1144		mutex_spin_enter(&sc->sc_intr_lock);
1145		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1146		if (cp->un.ord) {
1147			reg |= SV_MIC_BOOST_BIT;
1148		} else {
1149			reg &= ~SV_MIC_BOOST_BIT;
1150		}
1151
1152		sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1153		mutex_spin_exit(&sc->sc_intr_lock);
1154		return 0;
1155
1156	case SV_SRS_MODE:
1157		if (cp->type != AUDIO_MIXER_ENUM)
1158			return EINVAL;
1159
1160		mutex_spin_enter(&sc->sc_intr_lock);
1161		reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
1162		if (cp->un.ord) {
1163			reg &= ~SV_SRS_SPACE_ONOFF;
1164		} else {
1165			reg |= SV_SRS_SPACE_ONOFF;
1166		}
1167
1168		sv_write_indirect(sc, SV_SRS_SPACE_CONTROL, reg);
1169		mutex_spin_exit(&sc->sc_intr_lock);
1170		return 0;
1171	}
1172
1173	return EINVAL;
1174}
1175
1176static int
1177sv_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1178{
1179	struct sv_softc *sc;
1180	int val, error;
1181	uint8_t reg;
1182
1183	sc = addr;
1184	error = 0;
1185
1186	mutex_spin_enter(&sc->sc_intr_lock);
1187
1188	if (cp->dev >= SV_FIRST_MIXER &&
1189	    cp->dev <= SV_LAST_MIXER) {
1190		int off = cp->dev - SV_FIRST_MIXER;
1191		int mute = (off % 2);
1192		int idx = off / 2;
1193
1194		off = cp->dev - SV_FIRST_MIXER;
1195		mute = (off % 2);
1196		idx = off / 2;
1197		if (mute) {
1198			if (cp->type != AUDIO_MIXER_ENUM)
1199				error = EINVAL;
1200			else {
1201				reg = sv_read_indirect(sc, ports[idx].l_port);
1202				cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0);
1203			}
1204		} else {
1205			if (cp->type != AUDIO_MIXER_VALUE ||
1206			    (cp->un.value.num_channels != 1 &&
1207			    cp->un.value.num_channels != 2) ||
1208			   ((ports[idx].r_port == 0 &&
1209			     cp->un.value.num_channels != 1) ||
1210			    (ports[idx].r_port != 0 &&
1211			     cp->un.value.num_channels != 2)))
1212				error = EINVAL;
1213			else {
1214				reg = sv_read_indirect(sc, ports[idx].l_port);
1215				reg &= ports[idx].mask;
1216
1217				val = AUDIO_MAX_GAIN -
1218				    ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
1219
1220				if (ports[idx].r_port != 0) {
1221					cp->un.value.level
1222					    [AUDIO_MIXER_LEVEL_LEFT] = val;
1223
1224					reg = sv_read_indirect(sc,
1225					    ports[idx].r_port);
1226					reg &= ports[idx].mask;
1227
1228					val = AUDIO_MAX_GAIN -
1229					    ((reg * AUDIO_MAX_GAIN)
1230					    / ports[idx].mask);
1231					cp->un.value.level
1232					    [AUDIO_MIXER_LEVEL_RIGHT] = val;
1233				} else
1234					cp->un.value.level
1235					    [AUDIO_MIXER_LEVEL_MONO] = val;
1236			}
1237		}
1238
1239		mutex_spin_exit(&sc->sc_intr_lock);
1240		return error;
1241	}
1242
1243	switch (cp->dev) {
1244	case SV_RECORD_SOURCE:
1245		if (cp->type != AUDIO_MIXER_ENUM) {
1246			error = EINVAL;
1247			break;
1248		}
1249
1250		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1251		cp->un.ord = ((reg & SV_REC_SOURCE_MASK) >> SV_REC_SOURCE_SHIFT);
1252
1253		break;
1254
1255	case SV_RECORD_GAIN:
1256		if (cp->type != AUDIO_MIXER_VALUE) {
1257			error = EINVAL;
1258			break;
1259		}
1260		if (cp->un.value.num_channels != 1) {
1261			error = EINVAL;
1262			break;
1263		}
1264
1265		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL) & SV_REC_GAIN_MASK;
1266		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1267			(((unsigned int)reg) * AUDIO_MAX_GAIN) / SV_REC_GAIN_MASK;
1268
1269		break;
1270
1271	case SV_MIC_BOOST:
1272		if (cp->type != AUDIO_MIXER_ENUM) {
1273			error = EINVAL;
1274			break;
1275		}
1276		reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1277		cp->un.ord = ((reg & SV_MIC_BOOST_BIT) ? 1 : 0);
1278		break;
1279
1280	case SV_SRS_MODE:
1281		if (cp->type != AUDIO_MIXER_ENUM) {
1282			error = EINVAL;
1283			break;
1284		}
1285		reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
1286		cp->un.ord = ((reg & SV_SRS_SPACE_ONOFF) ? 0 : 1);
1287		break;
1288	default:
1289		error = EINVAL;
1290		break;
1291	}
1292
1293	mutex_spin_exit(&sc->sc_intr_lock);
1294	return error;
1295}
1296
1297static void
1298sv_init_mixer(struct sv_softc *sc)
1299{
1300	mixer_ctrl_t cp;
1301	int i;
1302
1303	cp.type = AUDIO_MIXER_ENUM;
1304	cp.dev = SV_SRS_MODE;
1305	cp.un.ord = 0;
1306
1307	sv_mixer_set_port(sc, &cp);
1308
1309	for (i = 0; i < ARRAY_SIZE(ports); i++) {
1310		if (!strcmp(ports[i].audio, AudioNdac)) {
1311			cp.type = AUDIO_MIXER_ENUM;
1312			cp.dev = SV_FIRST_MIXER + i * SV_DEVICES_PER_PORT + 1;
1313			cp.un.ord = 0;
1314			sv_mixer_set_port(sc, &cp);
1315			break;
1316		}
1317	}
1318}
1319
1320static void *
1321sv_malloc(void *addr, int direction, size_t size)
1322{
1323	struct sv_softc *sc;
1324	struct sv_dma *p;
1325	int error;
1326
1327	sc = addr;
1328	p = kmem_alloc(sizeof(*p), KM_SLEEP);
1329	error = sv_allocmem(sc, size, 16, direction, p);
1330	if (error) {
1331		kmem_free(p, sizeof(*p));
1332		return 0;
1333	}
1334	p->next = sc->sc_dmas;
1335	sc->sc_dmas = p;
1336	return KERNADDR(p);
1337}
1338
1339static void
1340sv_free(void *addr, void *ptr, size_t size)
1341{
1342	struct sv_softc *sc;
1343	struct sv_dma **pp, *p;
1344
1345	sc = addr;
1346	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
1347		if (KERNADDR(p) == ptr) {
1348			sv_freemem(sc, p);
1349			*pp = p->next;
1350			kmem_free(p, sizeof(*p));
1351			return;
1352		}
1353	}
1354}
1355
1356static int
1357sv_get_props(void *addr)
1358{
1359
1360	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
1361	    AUDIO_PROP_FULLDUPLEX;
1362}
1363
1364static void
1365sv_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
1366{
1367	struct sv_softc *sc;
1368
1369	sc = addr;
1370	*intr = &sc->sc_intr_lock;
1371	*thread = &sc->sc_lock;
1372}
1373