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