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