am7930.c revision 1.57.4.1 1 1.57.4.1 christos /* $NetBSD: am7930.c,v 1.57.4.1 2019/06/10 22:07:10 christos 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.57.4.1 christos __KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.57.4.1 2019/06/10 22:07:10 christos 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.50 ad #include <sys/cpu.h>
53 1.1 pk
54 1.1 pk #include <sys/audioio.h>
55 1.57.4.1 christos #include <dev/audio/audio_if.h>
56 1.57.4.1 christos #include <dev/audio/mulaw.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.57.4.1 christos static const struct audio_format am7930_format = {
141 1.57.4.1 christos .mode = AUMODE_PLAY | AUMODE_RECORD,
142 1.57.4.1 christos .encoding = AUDIO_ENCODING_ULAW,
143 1.57.4.1 christos .validbits = 8,
144 1.57.4.1 christos .precision = 8,
145 1.57.4.1 christos .channels = 1,
146 1.57.4.1 christos .channel_mask = AUFMT_MONAURAL,
147 1.57.4.1 christos .frequency_type = 1,
148 1.57.4.1 christos .frequency = { 8000 },
149 1.57.4.1 christos };
150 1.1 pk
151 1.1 pk /*
152 1.39 jonathan * Reset chip and set boot-time softc defaults.
153 1.1 pk */
154 1.1 pk void
155 1.47 kent am7930_init(struct am7930_softc *sc, int flag)
156 1.36 pk {
157 1.41 jonathan
158 1.43 augustss DPRINTF(("am7930_init()\n"));
159 1.39 jonathan
160 1.1 pk /* set boot defaults */
161 1.1 pk sc->sc_rlevel = 128;
162 1.1 pk sc->sc_plevel = 128;
163 1.1 pk sc->sc_mlevel = 0;
164 1.43 augustss sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
165 1.43 augustss sc->sc_mic_mute = 0;
166 1.43 augustss
167 1.43 augustss /* disable sample interrupts */
168 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
169 1.43 augustss
170 1.43 augustss /* initialise voice and data, and disable interrupts */
171 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_INIT,
172 1.43 augustss AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
173 1.43 augustss
174 1.43 augustss if (flag == AUDIOAMD_DMA_MODE) {
175 1.43 augustss
176 1.43 augustss /* configure PP for serial (SBP) mode */
177 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
178 1.43 augustss
179 1.43 augustss /*
180 1.43 augustss * Initialise the MUX unit - route the MAP to the PP
181 1.43 augustss */
182 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
183 1.43 augustss (AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
184 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
185 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
186 1.43 augustss
187 1.43 augustss } else {
188 1.43 augustss
189 1.43 augustss /*
190 1.43 augustss * Initialize the MUX unit. We use MCR3 to route the MAP
191 1.43 augustss * through channel Bb. MCR1 and MCR2 are unused.
192 1.43 augustss * Setting the INT enable bit in MCR4 will generate an
193 1.43 augustss * interrupt on each converted audio sample.
194 1.43 augustss */
195 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
196 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
197 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
198 1.43 augustss (AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
199 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
200 1.43 augustss AM7930_MCR4_INT_ENABLE);
201 1.43 augustss }
202 1.43 augustss
203 1.51 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
204 1.51 jmcneill mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
205 1.1 pk }
206 1.1 pk
207 1.1 pk int
208 1.47 kent am7930_open(void *addr, int flags)
209 1.1 pk {
210 1.47 kent struct am7930_softc *sc;
211 1.1 pk
212 1.47 kent sc = addr;
213 1.26 augustss DPRINTF(("sa_open: unit %p\n", sc));
214 1.43 augustss sc->sc_glue->onopen(sc);
215 1.48 christos DPRINTF(("saopen: ok -> sc=%p\n",sc));
216 1.47 kent return 0;
217 1.1 pk }
218 1.1 pk
219 1.1 pk void
220 1.47 kent am7930_close(void *addr)
221 1.1 pk {
222 1.47 kent struct am7930_softc *sc;
223 1.1 pk
224 1.47 kent sc = addr;
225 1.40 pk DPRINTF(("sa_close: sc=%p\n", sc));
226 1.43 augustss sc->sc_glue->onclose(sc);
227 1.1 pk DPRINTF(("sa_close: closed.\n"));
228 1.1 pk }
229 1.1 pk
230 1.1 pk int
231 1.57.4.1 christos am7930_query_format(void *addr, audio_format_query_t *afp)
232 1.1 pk {
233 1.55 nat
234 1.57.4.1 christos return audio_query_format(&am7930_format, 1, afp);
235 1.1 pk }
236 1.1 pk
237 1.1 pk int
238 1.57.4.1 christos am7930_set_format(void *addr, int setmode,
239 1.57.4.1 christos const audio_params_t *play, const audio_params_t *rec,
240 1.57.4.1 christos audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
241 1.47 kent {
242 1.57.4.1 christos
243 1.57.4.1 christos if ((setmode & AUMODE_PLAY) != 0) {
244 1.57.4.1 christos pfil->codec = audio_internal_to_mulaw;
245 1.57.4.1 christos }
246 1.57.4.1 christos if ((setmode & AUMODE_RECORD) != 0) {
247 1.57.4.1 christos rfil->codec = audio_mulaw_to_internal;
248 1.1 pk }
249 1.1 pk
250 1.57.4.1 christos return 0;
251 1.1 pk }
252 1.1 pk
253 1.1 pk int
254 1.47 kent am7930_commit_settings(void *addr)
255 1.1 pk {
256 1.47 kent struct am7930_softc *sc;
257 1.47 kent uint16_t ger, gr, gx, stgr;
258 1.47 kent uint8_t mmr2, mmr3;
259 1.51 jmcneill int level;
260 1.10 pk
261 1.1 pk DPRINTF(("sa_commit.\n"));
262 1.47 kent sc = addr;
263 1.43 augustss gx = gx_coeff[sc->sc_rlevel];
264 1.43 augustss stgr = gx_coeff[sc->sc_mlevel];
265 1.10 pk
266 1.1 pk level = (sc->sc_plevel * (256 + NGER)) >> 8;
267 1.1 pk if (level >= 256) {
268 1.43 augustss ger = ger_coeff[level - 256];
269 1.43 augustss gr = gx_coeff[255];
270 1.1 pk } else {
271 1.43 augustss ger = ger_coeff[0];
272 1.43 augustss gr = gx_coeff[level];
273 1.1 pk }
274 1.1 pk
275 1.51 jmcneill mutex_enter(&sc->sc_intr_lock);
276 1.10 pk
277 1.43 augustss mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
278 1.43 augustss if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
279 1.43 augustss mmr2 |= AM7930_MMR2_LS;
280 1.43 augustss else
281 1.43 augustss mmr2 &= ~AM7930_MMR2_LS;
282 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
283 1.41 jonathan
284 1.43 augustss mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
285 1.43 augustss if (sc->sc_mic_mute)
286 1.43 augustss mmr3 |= AM7930_MMR3_MUTE;
287 1.43 augustss else
288 1.43 augustss mmr3 &= ~AM7930_MMR3_MUTE;
289 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
290 1.41 jonathan
291 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
292 1.43 augustss AM7930_MMR1_GX | AM7930_MMR1_GER |
293 1.43 augustss AM7930_MMR1_GR | AM7930_MMR1_STG);
294 1.43 augustss
295 1.43 augustss AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
296 1.43 augustss AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
297 1.43 augustss AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
298 1.43 augustss AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
299 1.41 jonathan
300 1.51 jmcneill mutex_exit(&sc->sc_intr_lock);
301 1.1 pk
302 1.47 kent return 0;
303 1.1 pk }
304 1.1 pk
305 1.1 pk int
306 1.47 kent am7930_halt_output(void *addr)
307 1.1 pk {
308 1.47 kent struct am7930_softc *sc;
309 1.1 pk
310 1.47 kent sc = addr;
311 1.1 pk /* XXX only halt, if input is also halted ?? */
312 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_INIT,
313 1.47 kent AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
314 1.47 kent return 0;
315 1.1 pk }
316 1.1 pk
317 1.1 pk int
318 1.47 kent am7930_halt_input(void *addr)
319 1.1 pk {
320 1.47 kent struct am7930_softc *sc;
321 1.1 pk
322 1.47 kent sc = addr;
323 1.1 pk /* XXX only halt, if output is also halted ?? */
324 1.43 augustss AM7930_IWRITE(sc, AM7930_IREG_INIT,
325 1.47 kent AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
326 1.47 kent return 0;
327 1.1 pk }
328 1.1 pk
329 1.43 augustss /*
330 1.43 augustss * XXX chip is full-duplex, but really attach-dependent.
331 1.43 augustss * For now we know of no half-duplex attachments.
332 1.43 augustss */
333 1.1 pk int
334 1.47 kent am7930_get_props(void *addr)
335 1.1 pk {
336 1.57.4.1 christos
337 1.57.4.1 christos return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
338 1.57.4.1 christos AUDIO_PROP_FULLDUPLEX;
339 1.43 augustss }
340 1.43 augustss
341 1.43 augustss /*
342 1.43 augustss * Attach-dependent channel set/query
343 1.43 augustss */
344 1.43 augustss int
345 1.47 kent am7930_set_port(void *addr, mixer_ctrl_t *cp)
346 1.43 augustss {
347 1.47 kent struct am7930_softc *sc;
348 1.43 augustss
349 1.43 augustss DPRINTF(("am7930_set_port: port=%d", cp->dev));
350 1.47 kent sc = addr;
351 1.43 augustss if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
352 1.43 augustss cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
353 1.43 augustss cp->dev == AUDIOAMD_MIC_MUTE) {
354 1.43 augustss if (cp->type != AUDIO_MIXER_ENUM)
355 1.47 kent return EINVAL;
356 1.43 augustss } else if (cp->type != AUDIO_MIXER_VALUE ||
357 1.47 kent cp->un.value.num_channels != 1) {
358 1.47 kent return EINVAL;
359 1.43 augustss }
360 1.43 augustss
361 1.43 augustss switch(cp->dev) {
362 1.43 augustss case AUDIOAMD_MIC_VOL:
363 1.43 augustss sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
364 1.43 augustss break;
365 1.43 augustss case AUDIOAMD_SPEAKER_VOL:
366 1.43 augustss case AUDIOAMD_HEADPHONES_VOL:
367 1.43 augustss sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
368 1.43 augustss break;
369 1.43 augustss case AUDIOAMD_MONITOR_VOL:
370 1.43 augustss sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
371 1.43 augustss break;
372 1.43 augustss case AUDIOAMD_RECORD_SOURCE:
373 1.43 augustss if (cp->un.ord != AUDIOAMD_MIC_VOL)
374 1.43 augustss return EINVAL;
375 1.43 augustss break;
376 1.43 augustss case AUDIOAMD_MIC_MUTE:
377 1.43 augustss sc->sc_mic_mute = cp->un.ord;
378 1.43 augustss break;
379 1.43 augustss case AUDIOAMD_MONITOR_OUTPUT:
380 1.43 augustss if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
381 1.43 augustss cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
382 1.43 augustss return EINVAL;
383 1.43 augustss sc->sc_out_port = cp->un.ord;
384 1.43 augustss break;
385 1.43 augustss default:
386 1.47 kent return EINVAL;
387 1.43 augustss /* NOTREACHED */
388 1.43 augustss }
389 1.43 augustss return 0;
390 1.43 augustss }
391 1.43 augustss
392 1.43 augustss int
393 1.47 kent am7930_get_port(void *addr, mixer_ctrl_t *cp)
394 1.43 augustss {
395 1.47 kent struct am7930_softc *sc;
396 1.43 augustss
397 1.43 augustss DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
398 1.47 kent sc = addr;
399 1.43 augustss if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
400 1.43 augustss cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
401 1.43 augustss cp->dev == AUDIOAMD_MIC_MUTE) {
402 1.43 augustss if (cp->type != AUDIO_MIXER_ENUM)
403 1.47 kent return EINVAL;
404 1.43 augustss } else if (cp->type != AUDIO_MIXER_VALUE ||
405 1.43 augustss cp->un.value.num_channels != 1) {
406 1.47 kent return EINVAL;
407 1.43 augustss }
408 1.43 augustss
409 1.43 augustss switch(cp->dev) {
410 1.43 augustss case AUDIOAMD_MIC_VOL:
411 1.43 augustss cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
412 1.43 augustss break;
413 1.43 augustss case AUDIOAMD_SPEAKER_VOL:
414 1.43 augustss case AUDIOAMD_HEADPHONES_VOL:
415 1.43 augustss cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
416 1.43 augustss break;
417 1.43 augustss case AUDIOAMD_MONITOR_VOL:
418 1.43 augustss cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
419 1.43 augustss break;
420 1.43 augustss case AUDIOAMD_RECORD_SOURCE:
421 1.43 augustss cp->un.ord = AUDIOAMD_MIC_VOL;
422 1.43 augustss break;
423 1.43 augustss case AUDIOAMD_MIC_MUTE:
424 1.43 augustss cp->un.ord = sc->sc_mic_mute;
425 1.43 augustss break;
426 1.43 augustss case AUDIOAMD_MONITOR_OUTPUT:
427 1.43 augustss cp->un.ord = sc->sc_out_port;
428 1.43 augustss break;
429 1.43 augustss default:
430 1.47 kent return EINVAL;
431 1.43 augustss /* NOTREACHED */
432 1.43 augustss }
433 1.43 augustss return 0;
434 1.1 pk }
435 1.1 pk
436 1.26 augustss
437 1.39 jonathan /*
438 1.43 augustss * Define mixer control facilities.
439 1.39 jonathan */
440 1.26 augustss int
441 1.47 kent am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
442 1.26 augustss {
443 1.43 augustss
444 1.43 augustss DPRINTF(("am7930_query_devinfo()\n"));
445 1.43 augustss
446 1.43 augustss switch(dip->index) {
447 1.47 kent case AUDIOAMD_MIC_VOL:
448 1.47 kent dip->type = AUDIO_MIXER_VALUE;
449 1.47 kent dip->mixer_class = AUDIOAMD_INPUT_CLASS;
450 1.47 kent dip->prev = AUDIO_MIXER_LAST;
451 1.47 kent dip->next = AUDIOAMD_MIC_MUTE;
452 1.47 kent strcpy(dip->label.name, AudioNmicrophone);
453 1.47 kent dip->un.v.num_channels = 1;
454 1.47 kent strcpy(dip->un.v.units.name, AudioNvolume);
455 1.47 kent break;
456 1.47 kent case AUDIOAMD_SPEAKER_VOL:
457 1.47 kent dip->type = AUDIO_MIXER_VALUE;
458 1.47 kent dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
459 1.47 kent dip->prev = dip->next = AUDIO_MIXER_LAST;
460 1.47 kent strcpy(dip->label.name, AudioNspeaker);
461 1.47 kent dip->un.v.num_channels = 1;
462 1.47 kent strcpy(dip->un.v.units.name, AudioNvolume);
463 1.47 kent break;
464 1.47 kent case AUDIOAMD_HEADPHONES_VOL:
465 1.47 kent dip->type = AUDIO_MIXER_VALUE;
466 1.47 kent dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
467 1.47 kent dip->prev = dip->next = AUDIO_MIXER_LAST;
468 1.47 kent strcpy(dip->label.name, AudioNheadphone);
469 1.47 kent dip->un.v.num_channels = 1;
470 1.47 kent strcpy(dip->un.v.units.name, AudioNvolume);
471 1.47 kent break;
472 1.47 kent case AUDIOAMD_MONITOR_VOL:
473 1.47 kent dip->type = AUDIO_MIXER_VALUE;
474 1.47 kent dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
475 1.47 kent dip->prev = dip->next = AUDIO_MIXER_LAST;
476 1.47 kent strcpy(dip->label.name, AudioNmonitor);
477 1.47 kent dip->un.v.num_channels = 1;
478 1.47 kent strcpy(dip->un.v.units.name, AudioNvolume);
479 1.47 kent break;
480 1.47 kent case AUDIOAMD_RECORD_SOURCE:
481 1.47 kent dip->type = AUDIO_MIXER_ENUM;
482 1.47 kent dip->mixer_class = AUDIOAMD_RECORD_CLASS;
483 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
484 1.47 kent strcpy(dip->label.name, AudioNsource);
485 1.47 kent dip->un.e.num_mem = 1;
486 1.47 kent strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
487 1.47 kent dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
488 1.47 kent break;
489 1.47 kent case AUDIOAMD_MONITOR_OUTPUT:
490 1.47 kent dip->type = AUDIO_MIXER_ENUM;
491 1.47 kent dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
492 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
493 1.47 kent strcpy(dip->label.name, AudioNoutput);
494 1.47 kent dip->un.e.num_mem = 2;
495 1.47 kent strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
496 1.47 kent dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
497 1.47 kent strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
498 1.47 kent dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
499 1.47 kent break;
500 1.47 kent case AUDIOAMD_MIC_MUTE:
501 1.47 kent dip->type = AUDIO_MIXER_ENUM;
502 1.47 kent dip->mixer_class = AUDIOAMD_INPUT_CLASS;
503 1.47 kent dip->prev = AUDIOAMD_MIC_VOL;
504 1.47 kent dip->next = AUDIO_MIXER_LAST;
505 1.47 kent strcpy(dip->label.name, AudioNmute);
506 1.47 kent dip->un.e.num_mem = 2;
507 1.47 kent strcpy(dip->un.e.member[0].label.name, AudioNoff);
508 1.47 kent dip->un.e.member[0].ord = 0;
509 1.47 kent strcpy(dip->un.e.member[1].label.name, AudioNon);
510 1.47 kent dip->un.e.member[1].ord = 1;
511 1.47 kent break;
512 1.47 kent case AUDIOAMD_INPUT_CLASS:
513 1.47 kent dip->type = AUDIO_MIXER_CLASS;
514 1.47 kent dip->mixer_class = AUDIOAMD_INPUT_CLASS;
515 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
516 1.47 kent strcpy(dip->label.name, AudioCinputs);
517 1.47 kent break;
518 1.47 kent case AUDIOAMD_OUTPUT_CLASS:
519 1.47 kent dip->type = AUDIO_MIXER_CLASS;
520 1.47 kent dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
521 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
522 1.47 kent strcpy(dip->label.name, AudioCoutputs);
523 1.47 kent break;
524 1.47 kent case AUDIOAMD_RECORD_CLASS:
525 1.47 kent dip->type = AUDIO_MIXER_CLASS;
526 1.47 kent dip->mixer_class = AUDIOAMD_RECORD_CLASS;
527 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
528 1.47 kent strcpy(dip->label.name, AudioCrecord);
529 1.47 kent break;
530 1.47 kent case AUDIOAMD_MONITOR_CLASS:
531 1.47 kent dip->type = AUDIO_MIXER_CLASS;
532 1.47 kent dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
533 1.47 kent dip->next = dip->prev = AUDIO_MIXER_LAST;
534 1.47 kent strcpy(dip->label.name, AudioCmonitor);
535 1.47 kent break;
536 1.47 kent default:
537 1.47 kent return ENXIO;
538 1.47 kent /*NOTREACHED*/
539 1.43 augustss }
540 1.43 augustss
541 1.43 augustss DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
542 1.43 augustss
543 1.47 kent return 0;
544 1.1 pk }
545 1.43 augustss
546 1.39 jonathan #endif /* NAUDIO */
547