xref: /openbsd-src/sys/dev/ic/am7930.c (revision cc5bdd413dc6810be27950ffc92a3e2dad4ebdcb)
1*cc5bdd41Skn /*	$OpenBSD: am7930.c,v 1.8 2022/10/26 20:19:07 kn Exp $	*/
2d98f46d7Smiod /*	$NetBSD: am7930.c,v 1.44 2001/11/13 13:14:34 lukem Exp $	*/
3d98f46d7Smiod 
4d98f46d7Smiod /*
5d98f46d7Smiod  * Copyright (c) 1995 Rolf Grossmann
6d98f46d7Smiod  * All rights reserved.
7d98f46d7Smiod  *
8d98f46d7Smiod  * Redistribution and use in source and binary forms, with or without
9d98f46d7Smiod  * modification, are permitted provided that the following conditions
10d98f46d7Smiod  * are met:
11d98f46d7Smiod  * 1. Redistributions of source code must retain the above copyright
12d98f46d7Smiod  *    notice, this list of conditions and the following disclaimer.
13d98f46d7Smiod  * 2. Redistributions in binary form must reproduce the above copyright
14d98f46d7Smiod  *    notice, this list of conditions and the following disclaimer in the
15d98f46d7Smiod  *    documentation and/or other materials provided with the distribution.
16d98f46d7Smiod  * 3. All advertising materials mentioning features or use of this software
17d98f46d7Smiod  *    must display the following acknowledgement:
18d98f46d7Smiod  *      This product includes software developed by Rolf Grossmann.
19d98f46d7Smiod  * 4. The name of the author may not be used to endorse or promote products
20d98f46d7Smiod  *    derived from this software without specific prior written permission
21d98f46d7Smiod  *
22d98f46d7Smiod  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23d98f46d7Smiod  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24d98f46d7Smiod  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25d98f46d7Smiod  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26d98f46d7Smiod  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27d98f46d7Smiod  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28d98f46d7Smiod  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29d98f46d7Smiod  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30d98f46d7Smiod  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31d98f46d7Smiod  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32d98f46d7Smiod  */
33d98f46d7Smiod 
34d98f46d7Smiod /*
35d98f46d7Smiod  * Front-end attachment independent layer for AMD 79c30
36d98f46d7Smiod  * audio driver.  No ISDN support.
37d98f46d7Smiod  */
38d98f46d7Smiod 
39d98f46d7Smiod #include <sys/param.h>
40d98f46d7Smiod #include <sys/systm.h>
41d98f46d7Smiod #include <sys/errno.h>
42d98f46d7Smiod #include <sys/ioctl.h>
43d98f46d7Smiod #include <sys/device.h>
44d98f46d7Smiod #include <sys/proc.h>
45d98f46d7Smiod 
46d98f46d7Smiod #include <sys/audioio.h>
47d98f46d7Smiod #include <dev/audio_if.h>
48d98f46d7Smiod 
49d98f46d7Smiod #include <dev/ic/am7930reg.h>
50d98f46d7Smiod #include <dev/ic/am7930var.h>
51d98f46d7Smiod 
52d98f46d7Smiod #ifdef AUDIO_DEBUG
53d98f46d7Smiod int	am7930debug = 0;
54d98f46d7Smiod #define	DPRINTF(x)	if (am7930debug) printf x
55d98f46d7Smiod #else
56d98f46d7Smiod #define	DPRINTF(x)
57d98f46d7Smiod #endif
58d98f46d7Smiod 
59d98f46d7Smiod 
60d98f46d7Smiod /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
61d98f46d7Smiod 
62d98f46d7Smiod /*
63d98f46d7Smiod  * gx, gr & stg gains.  this table must contain 256 elements with
64d98f46d7Smiod  * the 0th being "infinity" (the magic value 9008).  The remaining
65d98f46d7Smiod  * elements match sun's gain curve (but with higher resolution):
66d98f46d7Smiod  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
67d98f46d7Smiod  */
68d98f46d7Smiod static const uint16_t gx_coeff[256] = {
69d98f46d7Smiod 	0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
70d98f46d7Smiod 	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
71d98f46d7Smiod 	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
72d98f46d7Smiod 	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
73d98f46d7Smiod 	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
74d98f46d7Smiod 	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
75d98f46d7Smiod 	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
76d98f46d7Smiod 	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
77d98f46d7Smiod 	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
78d98f46d7Smiod 	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
79d98f46d7Smiod 	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
80d98f46d7Smiod 	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
81d98f46d7Smiod 	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
82d98f46d7Smiod 	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
83d98f46d7Smiod 	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
84d98f46d7Smiod 	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
85d98f46d7Smiod 	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
86d98f46d7Smiod 	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
87d98f46d7Smiod 	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
88d98f46d7Smiod 	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
89d98f46d7Smiod 	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
90d98f46d7Smiod 	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
91d98f46d7Smiod 	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
92d98f46d7Smiod 	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
93d98f46d7Smiod 	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
94d98f46d7Smiod 	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
95d98f46d7Smiod 	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
96d98f46d7Smiod 	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
97d98f46d7Smiod 	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
98d98f46d7Smiod 	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
99d98f46d7Smiod 	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
100d98f46d7Smiod 	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
101d98f46d7Smiod };
102d98f46d7Smiod 
103d98f46d7Smiod /*
104d98f46d7Smiod  * second stage play gain.
105d98f46d7Smiod  */
106d98f46d7Smiod static const uint16_t ger_coeff[] = {
107d98f46d7Smiod 	0x431f, /* 5. dB */
108d98f46d7Smiod 	0x331f, /* 5.5 dB */
109d98f46d7Smiod 	0x40dd, /* 6. dB */
110d98f46d7Smiod 	0x11dd, /* 6.5 dB */
111d98f46d7Smiod 	0x440f, /* 7. dB */
112d98f46d7Smiod 	0x411f, /* 7.5 dB */
113d98f46d7Smiod 	0x311f, /* 8. dB */
114d98f46d7Smiod 	0x5520, /* 8.5 dB */
115d98f46d7Smiod 	0x10dd, /* 9. dB */
116d98f46d7Smiod 	0x4211, /* 9.5 dB */
117d98f46d7Smiod 	0x410f, /* 10. dB */
118d98f46d7Smiod 	0x111f, /* 10.5 dB */
119d98f46d7Smiod 	0x600b, /* 11. dB */
120d98f46d7Smiod 	0x00dd, /* 11.5 dB */
121d98f46d7Smiod 	0x4210, /* 12. dB */
122d98f46d7Smiod 	0x110f, /* 13. dB */
123d98f46d7Smiod 	0x7200, /* 14. dB */
124d98f46d7Smiod 	0x2110, /* 15. dB */
125d98f46d7Smiod 	0x2200, /* 15.9 dB */
126d98f46d7Smiod 	0x000b, /* 16.9 dB */
127d98f46d7Smiod 	0x000f  /* 18. dB */
128d98f46d7Smiod #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
129d98f46d7Smiod };
130d98f46d7Smiod 
131d98f46d7Smiod 
132d98f46d7Smiod /*
133d98f46d7Smiod  * Reset chip and set boot-time softc defaults.
134d98f46d7Smiod  */
135d98f46d7Smiod void
am7930_init(struct am7930_softc * sc,int flag)136d98f46d7Smiod am7930_init(struct am7930_softc *sc, int flag)
137d98f46d7Smiod {
138d98f46d7Smiod 	DPRINTF(("am7930_init()\n"));
139d98f46d7Smiod 
140d98f46d7Smiod 	/* set boot defaults */
141d98f46d7Smiod 	sc->sc_rlevel = 128;
142d98f46d7Smiod 	sc->sc_plevel = 128;
143d98f46d7Smiod 	sc->sc_mlevel = 0;
144d98f46d7Smiod 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
145d98f46d7Smiod 	sc->sc_mic_mute = 0;
146d98f46d7Smiod 
147d98f46d7Smiod 	/* disable sample interrupts */
148d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
149d98f46d7Smiod 
150d98f46d7Smiod 	/* initialise voice and data, and disable interrupts */
151d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
152d98f46d7Smiod 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
153d98f46d7Smiod 
154d98f46d7Smiod 	if (flag == AUDIOAMD_DMA_MODE) {
155d98f46d7Smiod 		/* configure PP for serial (SBP) mode */
156d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
157d98f46d7Smiod 
158d98f46d7Smiod 		/*
159d98f46d7Smiod 		 * Initialise the MUX unit - route the MAP to the PP
160d98f46d7Smiod 		 */
161d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
162d98f46d7Smiod 		    (AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
163d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
164d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
165d98f46d7Smiod 	} else {
166d98f46d7Smiod 		/*
167d98f46d7Smiod 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
168d98f46d7Smiod 		 * through channel Bb.  MCR1 and MCR2 are unused.
169d98f46d7Smiod 		 * Setting the INT enable bit in MCR4 will generate an
170d98f46d7Smiod 		 * interrupt on each converted audio sample.
171d98f46d7Smiod 		 */
172d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
173d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
174d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
175d98f46d7Smiod 		    (AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
176d98f46d7Smiod 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
177d98f46d7Smiod 		    AM7930_MCR4_INT_ENABLE);
178d98f46d7Smiod 	}
179d98f46d7Smiod }
180d98f46d7Smiod 
181*cc5bdd41Skn /*
182*cc5bdd41Skn  * XXX chip is full-duplex, but really attach-dependent.
183*cc5bdd41Skn  * For now we know of no half-duplex attachments.
184*cc5bdd41Skn  */
185d98f46d7Smiod int
am7930_open(void * addr,int flags)186d98f46d7Smiod am7930_open(void *addr, int flags)
187d98f46d7Smiod {
188d98f46d7Smiod 	struct am7930_softc *sc = addr;
189d98f46d7Smiod 
190d98f46d7Smiod 	DPRINTF(("sa_open: unit %p\n", sc));
191d98f46d7Smiod 	if (sc->sc_open)
192d98f46d7Smiod 		return EBUSY;
193d98f46d7Smiod 	sc->sc_open = 1;
194d98f46d7Smiod 	sc->sc_locked = 0;
195d98f46d7Smiod 
196d98f46d7Smiod 	sc->sc_glue->onopen(sc);
197d98f46d7Smiod 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
198d98f46d7Smiod 	return 0;
199d98f46d7Smiod }
200d98f46d7Smiod 
201d98f46d7Smiod void
am7930_close(void * addr)202d98f46d7Smiod am7930_close(void *addr)
203d98f46d7Smiod {
204d98f46d7Smiod 	struct am7930_softc *sc = addr;
205d98f46d7Smiod 
206d98f46d7Smiod 	DPRINTF(("sa_close: sc=%p\n", sc));
207d98f46d7Smiod 	sc->sc_glue->onclose(sc);
208d98f46d7Smiod 	sc->sc_open = 0;
209d98f46d7Smiod 	DPRINTF(("sa_close: closed.\n"));
210d98f46d7Smiod }
211d98f46d7Smiod 
212d98f46d7Smiod int
am7930_set_params(void * addr,int setmode,int usemode,struct audio_params * play,struct audio_params * rec)2131290f517Smiod am7930_set_params(void *addr, int setmode, int usemode,
2141290f517Smiod     struct audio_params *play, struct audio_params *rec)
215d98f46d7Smiod {
216bca289f0Smiod 	struct am7930_softc *sc = addr;
2171290f517Smiod 	struct audio_params *p;
2181290f517Smiod 	int mode;
219d98f46d7Smiod 
2201290f517Smiod 	for (mode = AUMODE_RECORD; mode != -1;
2211290f517Smiod 	    mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
2221290f517Smiod 		if ((setmode & mode) == 0)
2231290f517Smiod 			continue;
2241290f517Smiod 
2251290f517Smiod 		p = mode == AUMODE_PLAY ? play : rec;
2261290f517Smiod 		if (p == NULL)
2271290f517Smiod 			continue;
2281290f517Smiod 
229ac2bb4f3Sratchov 		p->encoding = AUDIO_ENCODING_ULAW;
230ac2bb4f3Sratchov 		p->precision = sc->sc_glue->precision;
231ac2bb4f3Sratchov 		p->bps = AUDIO_BPS(p->precision);
232ac2bb4f3Sratchov 		p->msb = 0;
233d98f46d7Smiod 		p->channels = 1;
234d98f46d7Smiod 		/* no other rates supported by amd chip */
235d98f46d7Smiod 		p->sample_rate = 8000;
236d98f46d7Smiod 	}
237d98f46d7Smiod 
238d98f46d7Smiod 	return 0;
239d98f46d7Smiod }
240d98f46d7Smiod 
241d98f46d7Smiod int
am7930_round_blocksize(void * addr,int blk)242d98f46d7Smiod am7930_round_blocksize(void *addr, int blk)
243d98f46d7Smiod {
244d98f46d7Smiod 	return blk;
245d98f46d7Smiod }
246d98f46d7Smiod 
247d98f46d7Smiod int
am7930_commit_settings(void * addr)248d98f46d7Smiod am7930_commit_settings(void *addr)
249d98f46d7Smiod {
250d98f46d7Smiod 	struct am7930_softc *sc = addr;
251d98f46d7Smiod 	uint16_t ger, gr, gx, stgr;
252d98f46d7Smiod 	uint8_t mmr2, mmr3;
2535bd8c879Sratchov 	int level;
254d98f46d7Smiod 
255d98f46d7Smiod 	DPRINTF(("sa_commit.\n"));
256d98f46d7Smiod 	gx = gx_coeff[sc->sc_rlevel];
257d98f46d7Smiod 	stgr = gx_coeff[sc->sc_mlevel];
258d98f46d7Smiod 
259d98f46d7Smiod 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
260d98f46d7Smiod 	if (level >= 256) {
261d98f46d7Smiod 		ger = ger_coeff[level - 256];
262d98f46d7Smiod 		gr = gx_coeff[255];
263d98f46d7Smiod 	} else {
264d98f46d7Smiod 		ger = ger_coeff[0];
265d98f46d7Smiod 		gr = gx_coeff[level];
266d98f46d7Smiod 	}
267d98f46d7Smiod 
268886882aaSratchov 	/* XXX: this is called before DMA is setup, useful ? */
269886882aaSratchov 	mtx_enter(&audio_lock);
270d98f46d7Smiod 
271d98f46d7Smiod 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
272d98f46d7Smiod 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
273d98f46d7Smiod 		mmr2 |= AM7930_MMR2_LS;
274d98f46d7Smiod 	else
275d98f46d7Smiod 		mmr2 &= ~AM7930_MMR2_LS;
276d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
277d98f46d7Smiod 
278d98f46d7Smiod 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
279d98f46d7Smiod 	if (sc->sc_mic_mute)
280d98f46d7Smiod 		mmr3 |= AM7930_MMR3_MUTE;
281d98f46d7Smiod 	else
282d98f46d7Smiod 		mmr3 &= ~AM7930_MMR3_MUTE;
283d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
284d98f46d7Smiod 
285d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
286d98f46d7Smiod 	    AM7930_MMR1_GX | AM7930_MMR1_GER |
287d98f46d7Smiod 	    AM7930_MMR1_GR | AM7930_MMR1_STG);
288d98f46d7Smiod 
289d98f46d7Smiod 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
290d98f46d7Smiod 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
291d98f46d7Smiod 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
292d98f46d7Smiod 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
293d98f46d7Smiod 
294886882aaSratchov 	mtx_leave(&audio_lock);
295d98f46d7Smiod 
296d98f46d7Smiod 	return 0;
297d98f46d7Smiod }
298d98f46d7Smiod 
299d98f46d7Smiod int
am7930_halt_output(void * addr)300d98f46d7Smiod am7930_halt_output(void *addr)
301d98f46d7Smiod {
302d98f46d7Smiod 	struct am7930_softc *sc = addr;
303d98f46d7Smiod 
304d98f46d7Smiod 	/* XXX only halt, if input is also halted ?? */
305d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
306d98f46d7Smiod 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
307d98f46d7Smiod 	sc->sc_locked = 0;
308d98f46d7Smiod 	return 0;
309d98f46d7Smiod }
310d98f46d7Smiod 
311d98f46d7Smiod int
am7930_halt_input(void * addr)312d98f46d7Smiod am7930_halt_input(void *addr)
313d98f46d7Smiod {
314d98f46d7Smiod 	struct am7930_softc *sc = addr;
315d98f46d7Smiod 
316d98f46d7Smiod 	/* XXX only halt, if output is also halted ?? */
317d98f46d7Smiod 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
318d98f46d7Smiod 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
319d98f46d7Smiod 	sc->sc_locked = 0;
320d98f46d7Smiod 	return 0;
321d98f46d7Smiod }
322d98f46d7Smiod 
323d98f46d7Smiod /*
324d98f46d7Smiod  * Attach-dependent channel set/query
325d98f46d7Smiod  */
326d98f46d7Smiod int
am7930_set_port(void * addr,mixer_ctrl_t * cp)327d98f46d7Smiod am7930_set_port(void *addr, mixer_ctrl_t *cp)
328d98f46d7Smiod {
329d98f46d7Smiod 	struct am7930_softc *sc = addr;
330d98f46d7Smiod 
331d98f46d7Smiod 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
332d98f46d7Smiod 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
333d98f46d7Smiod 	    cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
334d98f46d7Smiod 	    cp->dev == AUDIOAMD_MIC_MUTE) {
335d98f46d7Smiod 		if (cp->type != AUDIO_MIXER_ENUM)
336d98f46d7Smiod 			return EINVAL;
337d98f46d7Smiod 	} else if (cp->type != AUDIO_MIXER_VALUE ||
338d98f46d7Smiod 	    cp->un.value.num_channels != 1) {
339d98f46d7Smiod 		return EINVAL;
340d98f46d7Smiod 	}
341d98f46d7Smiod 
342d98f46d7Smiod 	switch(cp->dev) {
343d98f46d7Smiod 	case AUDIOAMD_MIC_VOL:
344d98f46d7Smiod 		sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
345d98f46d7Smiod 		break;
346d98f46d7Smiod 	case AUDIOAMD_SPEAKER_VOL:
347d98f46d7Smiod 	case AUDIOAMD_HEADPHONES_VOL:
348d98f46d7Smiod 		sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
349d98f46d7Smiod 		break;
350d98f46d7Smiod 	case AUDIOAMD_MONITOR_VOL:
351d98f46d7Smiod 		sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
352d98f46d7Smiod 		break;
353d98f46d7Smiod 	case AUDIOAMD_RECORD_SOURCE:
354d98f46d7Smiod 		if (cp->un.ord != AUDIOAMD_MIC_VOL)
355d98f46d7Smiod 			return EINVAL;
356d98f46d7Smiod 		break;
357d98f46d7Smiod 	case AUDIOAMD_MIC_MUTE:
358d98f46d7Smiod 		sc->sc_mic_mute = cp->un.ord;
359d98f46d7Smiod 		break;
360d98f46d7Smiod 	case AUDIOAMD_MONITOR_OUTPUT:
361d98f46d7Smiod 		if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
362d98f46d7Smiod 		    cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
363d98f46d7Smiod 			return EINVAL;
364d98f46d7Smiod 		sc->sc_out_port = cp->un.ord;
365d98f46d7Smiod 		break;
366d98f46d7Smiod 	default:
367d98f46d7Smiod 		return EINVAL;
368d98f46d7Smiod 		/* NOTREACHED */
369d98f46d7Smiod 	}
370d98f46d7Smiod 	return 0;
371d98f46d7Smiod }
372d98f46d7Smiod 
373d98f46d7Smiod int
am7930_get_port(void * addr,mixer_ctrl_t * cp)374d98f46d7Smiod am7930_get_port(void *addr, mixer_ctrl_t *cp)
375d98f46d7Smiod {
376d98f46d7Smiod 	struct am7930_softc *sc = addr;
377d98f46d7Smiod 
378d98f46d7Smiod 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
379d98f46d7Smiod 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
380d98f46d7Smiod 	    cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
381d98f46d7Smiod 	    cp->dev == AUDIOAMD_MIC_MUTE) {
382d98f46d7Smiod 		if (cp->type != AUDIO_MIXER_ENUM)
383d98f46d7Smiod 			return EINVAL;
384d98f46d7Smiod 	} else if (cp->type != AUDIO_MIXER_VALUE ||
385d98f46d7Smiod 	    cp->un.value.num_channels != 1) {
386d98f46d7Smiod 		return EINVAL;
387d98f46d7Smiod 	}
388d98f46d7Smiod 
389d98f46d7Smiod 	switch(cp->dev) {
390d98f46d7Smiod 	case AUDIOAMD_MIC_VOL:
391d98f46d7Smiod 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
392d98f46d7Smiod 		break;
393d98f46d7Smiod 	case AUDIOAMD_SPEAKER_VOL:
394d98f46d7Smiod 	case AUDIOAMD_HEADPHONES_VOL:
395d98f46d7Smiod 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
396d98f46d7Smiod 		break;
397d98f46d7Smiod 	case AUDIOAMD_MONITOR_VOL:
398d98f46d7Smiod 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
399d98f46d7Smiod 		break;
400d98f46d7Smiod 	case AUDIOAMD_RECORD_SOURCE:
401d98f46d7Smiod 		cp->un.ord = AUDIOAMD_MIC_VOL;
402d98f46d7Smiod 		break;
403d98f46d7Smiod 	case AUDIOAMD_MIC_MUTE:
404d98f46d7Smiod 		cp->un.ord = sc->sc_mic_mute;
405d98f46d7Smiod 		break;
406d98f46d7Smiod 	case AUDIOAMD_MONITOR_OUTPUT:
407d98f46d7Smiod 		cp->un.ord = sc->sc_out_port;
408d98f46d7Smiod 		break;
409d98f46d7Smiod 	default:
410d98f46d7Smiod 		return EINVAL;
411d98f46d7Smiod 		/* NOTREACHED */
412d98f46d7Smiod 	}
413d98f46d7Smiod 	return 0;
414d98f46d7Smiod }
415d98f46d7Smiod 
416d98f46d7Smiod 
417d98f46d7Smiod /*
418d98f46d7Smiod  * Define mixer control facilities.
419d98f46d7Smiod  */
420d98f46d7Smiod int
am7930_query_devinfo(void * addr,mixer_devinfo_t * dip)421d98f46d7Smiod am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
422d98f46d7Smiod {
423d98f46d7Smiod 	DPRINTF(("am7930_query_devinfo()\n"));
424d98f46d7Smiod 
425d98f46d7Smiod 	switch(dip->index) {
426d98f46d7Smiod 	case AUDIOAMD_MIC_VOL:
427d98f46d7Smiod 		dip->type = AUDIO_MIXER_VALUE;
428d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
429d98f46d7Smiod 		dip->prev =  AUDIO_MIXER_LAST;
430d98f46d7Smiod 		dip->next = AUDIOAMD_MIC_MUTE;
431d98f46d7Smiod 		strlcpy(dip->label.name, AudioNmicrophone,
432d98f46d7Smiod 		    sizeof dip->label.name);
433d98f46d7Smiod 		dip->un.v.num_channels = 1;
434d98f46d7Smiod 		strlcpy(dip->un.v.units.name, AudioNvolume,
435d98f46d7Smiod 		    sizeof dip->un.v.units.name);
436d98f46d7Smiod 		break;
437d98f46d7Smiod 	case AUDIOAMD_SPEAKER_VOL:
438d98f46d7Smiod 		dip->type = AUDIO_MIXER_VALUE;
439d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
440d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
441d98f46d7Smiod 		strlcpy(dip->label.name, AudioNspeaker,
442d98f46d7Smiod 		    sizeof dip->label.name);
443d98f46d7Smiod 		dip->un.v.num_channels = 1;
444d98f46d7Smiod 		strlcpy(dip->un.v.units.name, AudioNvolume,
445d98f46d7Smiod 		    sizeof dip->un.v.units.name);
446d98f46d7Smiod 		break;
447d98f46d7Smiod 	case AUDIOAMD_HEADPHONES_VOL:
448d98f46d7Smiod 		dip->type = AUDIO_MIXER_VALUE;
449d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
450d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
451d98f46d7Smiod 		strlcpy(dip->label.name, AudioNheadphone,
452d98f46d7Smiod 		    sizeof dip->label.name);
453d98f46d7Smiod 		dip->un.v.num_channels = 1;
454d98f46d7Smiod 		strlcpy(dip->un.v.units.name, AudioNvolume,
455d98f46d7Smiod 		    sizeof dip->un.v.units.name);
456d98f46d7Smiod 		break;
457d98f46d7Smiod 	case AUDIOAMD_MONITOR_VOL:
458d98f46d7Smiod 		dip->type = AUDIO_MIXER_VALUE;
459d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
460d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
461d98f46d7Smiod 		strlcpy(dip->label.name, AudioNmonitor,
462d98f46d7Smiod 		    sizeof dip->label.name);
463d98f46d7Smiod 		dip->un.v.num_channels = 1;
464d98f46d7Smiod 		strlcpy(dip->un.v.units.name, AudioNvolume,
465d98f46d7Smiod 		    sizeof dip->un.v.units.name);
466d98f46d7Smiod 		break;
467d98f46d7Smiod 	case AUDIOAMD_RECORD_SOURCE:
468d98f46d7Smiod 		dip->type = AUDIO_MIXER_ENUM;
469d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
470d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
471d98f46d7Smiod 		strlcpy(dip->label.name, AudioNsource,
472d98f46d7Smiod 		    sizeof dip->label.name);
473d98f46d7Smiod 		dip->un.e.num_mem = 1;
474d98f46d7Smiod 		strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
475d98f46d7Smiod 		    sizeof dip->un.e.member[0].label.name);
476d98f46d7Smiod 		dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
477d98f46d7Smiod 		break;
478d98f46d7Smiod 	case AUDIOAMD_MONITOR_OUTPUT:
479d98f46d7Smiod 		dip->type = AUDIO_MIXER_ENUM;
480d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
481d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
482d98f46d7Smiod 		strlcpy(dip->label.name, AudioNoutput,
483d98f46d7Smiod 		    sizeof dip->label.name);
484d98f46d7Smiod 		dip->un.e.num_mem = 2;
485d98f46d7Smiod 		strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
486d98f46d7Smiod 		    sizeof dip->un.e.member[0].label.name);
487d98f46d7Smiod 		dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
488d98f46d7Smiod 		strlcpy(dip->un.e.member[1].label.name, AudioNheadphone,
489d98f46d7Smiod 		    sizeof dip->un.e.member[1].label.name);
490d98f46d7Smiod 		dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
491d98f46d7Smiod 		break;
492d98f46d7Smiod 	case AUDIOAMD_MIC_MUTE:
493d98f46d7Smiod 		dip->type = AUDIO_MIXER_ENUM;
494d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
495d98f46d7Smiod 		dip->prev =  AUDIOAMD_MIC_VOL;
496d98f46d7Smiod 		dip->next = AUDIO_MIXER_LAST;
497d98f46d7Smiod 		strlcpy(dip->label.name, AudioNmute,
498d98f46d7Smiod 		    sizeof dip->label.name);
499d98f46d7Smiod 		dip->un.e.num_mem = 2;
500d98f46d7Smiod 		strlcpy(dip->un.e.member[0].label.name, AudioNoff,
501d98f46d7Smiod 		    sizeof dip->un.e.member[0].label.name);
502d98f46d7Smiod 		dip->un.e.member[0].ord = 0;
503d98f46d7Smiod 		strlcpy(dip->un.e.member[1].label.name, AudioNon,
504d98f46d7Smiod 		    sizeof dip->un.e.member[1].label.name);
505d98f46d7Smiod 		dip->un.e.member[1].ord = 1;
506d98f46d7Smiod 		break;
507d98f46d7Smiod 	case AUDIOAMD_INPUT_CLASS:
508d98f46d7Smiod 		dip->type = AUDIO_MIXER_CLASS;
509d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
510d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
511d98f46d7Smiod 		strlcpy(dip->label.name, AudioCinputs,
512d98f46d7Smiod 		    sizeof dip->label.name);
513d98f46d7Smiod 		break;
514d98f46d7Smiod 	case AUDIOAMD_OUTPUT_CLASS:
515d98f46d7Smiod 		dip->type = AUDIO_MIXER_CLASS;
516d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
517d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
518d98f46d7Smiod 		strlcpy(dip->label.name, AudioCoutputs,
519d98f46d7Smiod 		    sizeof dip->label.name);
520d98f46d7Smiod 		break;
521d98f46d7Smiod 	case AUDIOAMD_RECORD_CLASS:
522d98f46d7Smiod 		dip->type = AUDIO_MIXER_CLASS;
523d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
524d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
525d98f46d7Smiod 		strlcpy(dip->label.name, AudioCrecord,
526d98f46d7Smiod 		    sizeof dip->label.name);
527d98f46d7Smiod 		break;
528d98f46d7Smiod 	case AUDIOAMD_MONITOR_CLASS:
529d98f46d7Smiod 		dip->type = AUDIO_MIXER_CLASS;
530d98f46d7Smiod 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
531d98f46d7Smiod 		dip->prev = dip->next = AUDIO_MIXER_LAST;
532d98f46d7Smiod 		strlcpy(dip->label.name, AudioCmonitor,
533d98f46d7Smiod 		    sizeof dip->label.name);
534d98f46d7Smiod 		break;
535d98f46d7Smiod 	default:
536d98f46d7Smiod 		return ENXIO;
537d98f46d7Smiod 		/*NOTREACHED*/
538d98f46d7Smiod 	}
539d98f46d7Smiod 
540d98f46d7Smiod 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
541d98f46d7Smiod 
542d98f46d7Smiod 	return 0;
543d98f46d7Smiod }
544