]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
f30c2269 | 2 | * sound/oss/sb_mixer.c |
1da177e4 LT |
3 | * |
4 | * The low level mixer driver for the Sound Blaster compatible cards. | |
5 | */ | |
6 | /* | |
7 | * Copyright (C) by Hannu Savolainen 1993-1997 | |
8 | * | |
9 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | |
10 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | |
11 | * for more info. | |
12 | * | |
13 | * | |
14 | * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) | |
15 | * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] | |
16 | * Stanislav Voronyi <[email protected]> : Support for AWE 3DSE device (Jun 7 1999) | |
17 | */ | |
18 | ||
19 | #include "sound_config.h" | |
20 | ||
21 | #define __SB_MIXER_C__ | |
22 | ||
23 | #include "sb.h" | |
24 | #include "sb_mixer.h" | |
25 | ||
26 | #include "sb_ess.h" | |
27 | ||
28 | #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) | |
29 | ||
30 | /* Same as SB Pro, unless I find otherwise */ | |
31 | #define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES | |
32 | ||
33 | #define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ | |
34 | SOUND_MASK_CD | SOUND_MASK_VOLUME) | |
35 | ||
36 | /* SG NX Pro has treble and bass settings on the mixer. The 'speaker' | |
37 | * channel is the COVOX/DisneySoundSource emulation volume control | |
38 | * on the mixer. It does NOT control speaker volume. Should have own | |
39 | * mask eventually? | |
40 | */ | |
41 | #define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ | |
42 | SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) | |
43 | ||
44 | #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ | |
45 | SOUND_MASK_CD) | |
46 | ||
47 | #define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ | |
48 | SOUND_MASK_CD) | |
49 | ||
50 | #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ | |
51 | SOUND_MASK_CD | \ | |
52 | SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ | |
53 | SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ | |
54 | SOUND_MASK_IMIX) | |
55 | ||
56 | /* These are the only devices that are working at the moment. Others could | |
57 | * be added once they are identified and a method is found to control them. | |
58 | */ | |
59 | #define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ | |
60 | SOUND_MASK_PCM | SOUND_MASK_MIC | \ | |
61 | SOUND_MASK_CD | \ | |
62 | SOUND_MASK_VOLUME) | |
63 | ||
64 | static mixer_tab sbpro_mix = { | |
65 | MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), | |
66 | MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), | |
67 | MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), | |
68 | MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), | |
69 | MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), | |
70 | MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), | |
71 | MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), | |
72 | MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), | |
73 | MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), | |
74 | MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), | |
75 | MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), | |
76 | MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) | |
77 | }; | |
78 | ||
79 | static mixer_tab sb16_mix = { | |
80 | MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), | |
81 | MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), | |
82 | MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), | |
83 | MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), | |
84 | MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), | |
85 | MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), | |
86 | MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), | |
87 | MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), | |
88 | MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), | |
89 | MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0), | |
90 | MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), | |
91 | MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ | |
92 | MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), | |
93 | MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) | |
94 | }; | |
95 | ||
96 | static mixer_tab als007_mix = | |
97 | { | |
98 | MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4), | |
99 | MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), | |
100 | MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), | |
101 | MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), | |
102 | MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), | |
103 | MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), | |
104 | MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), | |
105 | MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0), | |
106 | MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), | |
107 | MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), | |
108 | MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), | |
109 | MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */ | |
110 | MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), | |
111 | MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) | |
112 | }; | |
113 | ||
114 | ||
115 | /* SM_GAMES Master volume is lower and PCM & FM volumes | |
116 | higher than with SB Pro. This improves the | |
117 | sound quality */ | |
118 | ||
119 | static int smg_default_levels[32] = | |
120 | { | |
121 | 0x2020, /* Master Volume */ | |
122 | 0x4b4b, /* Bass */ | |
123 | 0x4b4b, /* Treble */ | |
124 | 0x6464, /* FM */ | |
125 | 0x6464, /* PCM */ | |
126 | 0x4b4b, /* PC Speaker */ | |
127 | 0x4b4b, /* Ext Line */ | |
128 | 0x0000, /* Mic */ | |
129 | 0x4b4b, /* CD */ | |
130 | 0x4b4b, /* Recording monitor */ | |
131 | 0x4b4b, /* SB PCM */ | |
132 | 0x4b4b, /* Recording level */ | |
133 | 0x4b4b, /* Input gain */ | |
134 | 0x4b4b, /* Output gain */ | |
135 | 0x4040, /* Line1 */ | |
136 | 0x4040, /* Line2 */ | |
137 | 0x1515 /* Line3 */ | |
138 | }; | |
139 | ||
140 | static int sb_default_levels[32] = | |
141 | { | |
142 | 0x5a5a, /* Master Volume */ | |
143 | 0x4b4b, /* Bass */ | |
144 | 0x4b4b, /* Treble */ | |
145 | 0x4b4b, /* FM */ | |
146 | 0x4b4b, /* PCM */ | |
147 | 0x4b4b, /* PC Speaker */ | |
148 | 0x4b4b, /* Ext Line */ | |
149 | 0x1010, /* Mic */ | |
150 | 0x4b4b, /* CD */ | |
151 | 0x0000, /* Recording monitor */ | |
152 | 0x4b4b, /* SB PCM */ | |
153 | 0x4b4b, /* Recording level */ | |
154 | 0x4b4b, /* Input gain */ | |
155 | 0x4b4b, /* Output gain */ | |
156 | 0x4040, /* Line1 */ | |
157 | 0x4040, /* Line2 */ | |
158 | 0x1515 /* Line3 */ | |
159 | }; | |
160 | ||
161 | static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = | |
162 | { | |
163 | 0x00, /* SOUND_MIXER_VOLUME */ | |
164 | 0x00, /* SOUND_MIXER_BASS */ | |
165 | 0x00, /* SOUND_MIXER_TREBLE */ | |
166 | 0x40, /* SOUND_MIXER_SYNTH */ | |
167 | 0x00, /* SOUND_MIXER_PCM */ | |
168 | 0x00, /* SOUND_MIXER_SPEAKER */ | |
169 | 0x10, /* SOUND_MIXER_LINE */ | |
170 | 0x01, /* SOUND_MIXER_MIC */ | |
171 | 0x04, /* SOUND_MIXER_CD */ | |
172 | 0x00, /* SOUND_MIXER_IMIX */ | |
173 | 0x00, /* SOUND_MIXER_ALTPCM */ | |
174 | 0x00, /* SOUND_MIXER_RECLEV */ | |
175 | 0x00, /* SOUND_MIXER_IGAIN */ | |
176 | 0x00 /* SOUND_MIXER_OGAIN */ | |
177 | }; | |
178 | ||
179 | static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = | |
180 | { | |
181 | 0x00, /* SOUND_MIXER_VOLUME */ | |
182 | 0x00, /* SOUND_MIXER_BASS */ | |
183 | 0x00, /* SOUND_MIXER_TREBLE */ | |
184 | 0x20, /* SOUND_MIXER_SYNTH */ | |
185 | 0x00, /* SOUND_MIXER_PCM */ | |
186 | 0x00, /* SOUND_MIXER_SPEAKER */ | |
187 | 0x08, /* SOUND_MIXER_LINE */ | |
188 | 0x01, /* SOUND_MIXER_MIC */ | |
189 | 0x02, /* SOUND_MIXER_CD */ | |
190 | 0x00, /* SOUND_MIXER_IMIX */ | |
191 | 0x00, /* SOUND_MIXER_ALTPCM */ | |
192 | 0x00, /* SOUND_MIXER_RECLEV */ | |
193 | 0x00, /* SOUND_MIXER_IGAIN */ | |
194 | 0x00 /* SOUND_MIXER_OGAIN */ | |
195 | }; | |
196 | ||
197 | static char smw_mix_regs[] = /* Left mixer registers */ | |
198 | { | |
199 | 0x0b, /* SOUND_MIXER_VOLUME */ | |
200 | 0x0d, /* SOUND_MIXER_BASS */ | |
201 | 0x0d, /* SOUND_MIXER_TREBLE */ | |
202 | 0x05, /* SOUND_MIXER_SYNTH */ | |
203 | 0x09, /* SOUND_MIXER_PCM */ | |
204 | 0x00, /* SOUND_MIXER_SPEAKER */ | |
205 | 0x03, /* SOUND_MIXER_LINE */ | |
206 | 0x01, /* SOUND_MIXER_MIC */ | |
207 | 0x07, /* SOUND_MIXER_CD */ | |
208 | 0x00, /* SOUND_MIXER_IMIX */ | |
209 | 0x00, /* SOUND_MIXER_ALTPCM */ | |
210 | 0x00, /* SOUND_MIXER_RECLEV */ | |
211 | 0x00, /* SOUND_MIXER_IGAIN */ | |
212 | 0x00, /* SOUND_MIXER_OGAIN */ | |
213 | 0x00, /* SOUND_MIXER_LINE1 */ | |
214 | 0x00, /* SOUND_MIXER_LINE2 */ | |
215 | 0x00 /* SOUND_MIXER_LINE3 */ | |
216 | }; | |
217 | ||
218 | static int sbmixnum = 1; | |
219 | ||
220 | static void sb_mixer_reset(sb_devc * devc); | |
221 | ||
222 | void sb_mixer_set_stereo(sb_devc * devc, int mode) | |
223 | { | |
224 | sb_chgmixer(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC)); | |
225 | } | |
226 | ||
227 | static int detect_mixer(sb_devc * devc) | |
228 | { | |
229 | /* Just trust the mixer is there */ | |
230 | return 1; | |
231 | } | |
232 | ||
233 | static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) | |
234 | { | |
235 | unsigned char mask; | |
236 | int shift; | |
237 | ||
238 | mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; | |
239 | newval = (int) ((newval * mask) + 50) / 100; /* Scale */ | |
240 | ||
241 | shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; | |
242 | ||
243 | *regval &= ~(mask << shift); /* Mask out previous value */ | |
244 | *regval |= (newval & mask) << shift; /* Set the new value */ | |
245 | } | |
246 | ||
247 | static int sb_mixer_get(sb_devc * devc, int dev) | |
248 | { | |
249 | if (!((1 << dev) & devc->supported_devices)) | |
250 | return -EINVAL; | |
251 | return devc->levels[dev]; | |
252 | } | |
253 | ||
254 | void smw_mixer_init(sb_devc * devc) | |
255 | { | |
256 | int i; | |
257 | ||
258 | sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ | |
259 | sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ | |
260 | ||
261 | devc->supported_devices = 0; | |
262 | for (i = 0; i < sizeof(smw_mix_regs); i++) | |
263 | if (smw_mix_regs[i] != 0) | |
264 | devc->supported_devices |= (1 << i); | |
265 | ||
266 | devc->supported_rec_devices = devc->supported_devices & | |
267 | ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); | |
268 | sb_mixer_reset(devc); | |
269 | } | |
270 | ||
271 | int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right) | |
272 | { | |
273 | int regoffs; | |
274 | unsigned char val; | |
275 | ||
fe9bab2d ET |
276 | if ((dev < 0) || (dev >= devc->iomap_sz)) |
277 | return -EINVAL; | |
278 | ||
1da177e4 LT |
279 | regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; |
280 | ||
281 | if (regoffs == 0) | |
282 | return -EINVAL; | |
283 | ||
1da177e4 LT |
284 | val = sb_getmixer(devc, regoffs); |
285 | change_bits(devc, &val, dev, LEFT_CHN, left); | |
286 | ||
287 | if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* | |
288 | * Change register | |
289 | */ | |
290 | { | |
291 | sb_setmixer(devc, regoffs, val); /* | |
292 | * Save the old one | |
293 | */ | |
294 | regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; | |
295 | ||
296 | if (regoffs == 0) | |
297 | return left | (left << 8); /* | |
298 | * Just left channel present | |
299 | */ | |
300 | ||
301 | val = sb_getmixer(devc, regoffs); /* | |
302 | * Read the new one | |
303 | */ | |
304 | } | |
305 | change_bits(devc, &val, dev, RIGHT_CHN, right); | |
306 | ||
307 | sb_setmixer(devc, regoffs, val); | |
308 | ||
309 | return left | (right << 8); | |
310 | } | |
311 | ||
312 | static int smw_mixer_set(sb_devc * devc, int dev, int left, int right) | |
313 | { | |
314 | int reg, val; | |
315 | ||
316 | switch (dev) | |
317 | { | |
318 | case SOUND_MIXER_VOLUME: | |
319 | sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ | |
320 | sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); | |
321 | break; | |
322 | ||
323 | case SOUND_MIXER_BASS: | |
324 | case SOUND_MIXER_TREBLE: | |
325 | devc->levels[dev] = left | (right << 8); | |
326 | /* Set left bass and treble values */ | |
327 | val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; | |
328 | val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; | |
329 | sb_setmixer(devc, 0x0d, val); | |
330 | ||
331 | /* Set right bass and treble values */ | |
332 | val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; | |
333 | val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; | |
334 | sb_setmixer(devc, 0x0e, val); | |
335 | ||
336 | break; | |
337 | ||
338 | default: | |
339 | /* bounds check */ | |
340 | if (dev < 0 || dev >= ARRAY_SIZE(smw_mix_regs)) | |
341 | return -EINVAL; | |
342 | reg = smw_mix_regs[dev]; | |
343 | if (reg == 0) | |
344 | return -EINVAL; | |
345 | sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ | |
346 | sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); | |
347 | } | |
348 | ||
349 | devc->levels[dev] = left | (right << 8); | |
350 | return left | (right << 8); | |
351 | } | |
352 | ||
353 | static int sb_mixer_set(sb_devc * devc, int dev, int value) | |
354 | { | |
355 | int left = value & 0x000000ff; | |
356 | int right = (value & 0x0000ff00) >> 8; | |
357 | int retval; | |
358 | ||
359 | if (left > 100) | |
360 | left = 100; | |
361 | if (right > 100) | |
362 | right = 100; | |
363 | ||
364 | if ((dev < 0) || (dev > 31)) | |
365 | return -EINVAL; | |
366 | ||
367 | if (!(devc->supported_devices & (1 << dev))) /* | |
368 | * Not supported | |
369 | */ | |
370 | return -EINVAL; | |
371 | ||
372 | /* Differentiate depending on the chipsets */ | |
373 | switch (devc->model) { | |
374 | case MDL_SMW: | |
375 | retval = smw_mixer_set(devc, dev, left, right); | |
376 | break; | |
377 | case MDL_ESS: | |
378 | retval = ess_mixer_set(devc, dev, left, right); | |
379 | break; | |
380 | default: | |
381 | retval = sb_common_mixer_set(devc, dev, left, right); | |
382 | } | |
383 | if (retval >= 0) devc->levels[dev] = retval; | |
384 | ||
385 | return retval; | |
386 | } | |
387 | ||
388 | /* | |
389 | * set_recsrc doesn't apply to ES188x | |
390 | */ | |
391 | static void set_recsrc(sb_devc * devc, int src) | |
392 | { | |
393 | sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); | |
394 | } | |
395 | ||
396 | static int set_recmask(sb_devc * devc, int mask) | |
397 | { | |
398 | int devmask, i; | |
399 | unsigned char regimageL, regimageR; | |
400 | ||
401 | devmask = mask & devc->supported_rec_devices; | |
402 | ||
403 | switch (devc->model) | |
404 | { | |
405 | case MDL_SBPRO: | |
406 | case MDL_ESS: | |
407 | case MDL_JAZZ: | |
408 | case MDL_SMW: | |
409 | if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) { | |
410 | break; | |
411 | }; | |
412 | if (devmask != SOUND_MASK_MIC && | |
413 | devmask != SOUND_MASK_LINE && | |
414 | devmask != SOUND_MASK_CD) | |
415 | { | |
416 | /* | |
417 | * More than one device selected. Drop the | |
418 | * previous selection | |
419 | */ | |
420 | devmask &= ~devc->recmask; | |
421 | } | |
422 | if (devmask != SOUND_MASK_MIC && | |
423 | devmask != SOUND_MASK_LINE && | |
424 | devmask != SOUND_MASK_CD) | |
425 | { | |
426 | /* | |
427 | * More than one device selected. Default to | |
428 | * mic | |
429 | */ | |
430 | devmask = SOUND_MASK_MIC; | |
431 | } | |
432 | if (devmask ^ devc->recmask) /* | |
433 | * Input source changed | |
434 | */ | |
435 | { | |
436 | switch (devmask) | |
437 | { | |
438 | case SOUND_MASK_MIC: | |
439 | set_recsrc(devc, SRC__MIC); | |
440 | break; | |
441 | ||
442 | case SOUND_MASK_LINE: | |
443 | set_recsrc(devc, SRC__LINE); | |
444 | break; | |
445 | ||
446 | case SOUND_MASK_CD: | |
447 | set_recsrc(devc, SRC__CD); | |
448 | break; | |
449 | ||
450 | default: | |
451 | set_recsrc(devc, SRC__MIC); | |
452 | } | |
453 | } | |
454 | break; | |
455 | ||
456 | case MDL_SB16: | |
457 | if (!devmask) | |
458 | devmask = SOUND_MASK_MIC; | |
459 | ||
460 | if (devc->submodel == SUBMDL_ALS007) | |
461 | { | |
462 | switch (devmask) | |
463 | { | |
464 | case SOUND_MASK_LINE: | |
465 | sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE); | |
466 | break; | |
467 | case SOUND_MASK_CD: | |
468 | sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD); | |
469 | break; | |
470 | case SOUND_MASK_SYNTH: | |
471 | sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH); | |
472 | break; | |
473 | default: /* Also takes care of SOUND_MASK_MIC case */ | |
474 | sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC); | |
475 | break; | |
476 | } | |
477 | } | |
478 | else | |
479 | { | |
480 | regimageL = regimageR = 0; | |
481 | for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) | |
482 | { | |
483 | if ((1 << i) & devmask) | |
484 | { | |
485 | regimageL |= sb16_recmasks_L[i]; | |
486 | regimageR |= sb16_recmasks_R[i]; | |
487 | } | |
488 | sb_setmixer (devc, SB16_IMASK_L, regimageL); | |
489 | sb_setmixer (devc, SB16_IMASK_R, regimageR); | |
490 | } | |
491 | } | |
492 | break; | |
493 | } | |
494 | devc->recmask = devmask; | |
495 | return devc->recmask; | |
496 | } | |
497 | ||
498 | static int set_outmask(sb_devc * devc, int mask) | |
499 | { | |
500 | int devmask, i; | |
501 | unsigned char regimage; | |
502 | ||
503 | devmask = mask & devc->supported_out_devices; | |
504 | ||
505 | switch (devc->model) | |
506 | { | |
507 | case MDL_SB16: | |
508 | if (devc->submodel == SUBMDL_ALS007) | |
509 | break; | |
510 | else | |
511 | { | |
512 | regimage = 0; | |
513 | for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) | |
514 | { | |
515 | if ((1 << i) & devmask) | |
516 | { | |
517 | regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]); | |
518 | } | |
519 | sb_setmixer (devc, SB16_OMASK, regimage); | |
520 | } | |
521 | } | |
522 | break; | |
523 | default: | |
524 | break; | |
525 | } | |
526 | ||
527 | devc->outmask = devmask; | |
528 | return devc->outmask; | |
529 | } | |
530 | ||
531 | static int sb_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) | |
532 | { | |
533 | sb_devc *devc = mixer_devs[dev]->devc; | |
534 | int val, ret; | |
535 | int __user *p = arg; | |
536 | ||
537 | /* | |
538 | * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). | |
539 | * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) | |
540 | * or mode==2 put 3DSE state to mode. | |
541 | */ | |
542 | if (devc->model == MDL_SB16) { | |
543 | if (cmd == SOUND_MIXER_AGC) | |
544 | { | |
545 | if (get_user(val, p)) | |
546 | return -EFAULT; | |
547 | sb_setmixer(devc, 0x43, (~val) & 0x01); | |
548 | return 0; | |
549 | } | |
550 | if (cmd == SOUND_MIXER_3DSE) | |
551 | { | |
552 | /* I put here 15, but I don't know the exact version. | |
553 | At least my 4.13 havn't 3DSE, 4.16 has it. */ | |
554 | if (devc->minor < 15) | |
555 | return -EINVAL; | |
556 | if (get_user(val, p)) | |
557 | return -EFAULT; | |
558 | if (val == 0 || val == 1) | |
559 | sb_chgmixer(devc, AWE_3DSE, 0x01, val); | |
560 | else if (val == 2) | |
561 | { | |
562 | ret = sb_getmixer(devc, AWE_3DSE)&0x01; | |
563 | return put_user(ret, p); | |
564 | } | |
565 | else | |
566 | return -EINVAL; | |
567 | return 0; | |
568 | } | |
569 | } | |
570 | if (((cmd >> 8) & 0xff) == 'M') | |
571 | { | |
572 | if (_SIOC_DIR(cmd) & _SIOC_WRITE) | |
573 | { | |
574 | if (get_user(val, p)) | |
575 | return -EFAULT; | |
576 | switch (cmd & 0xff) | |
577 | { | |
578 | case SOUND_MIXER_RECSRC: | |
579 | ret = set_recmask(devc, val); | |
580 | break; | |
581 | ||
582 | case SOUND_MIXER_OUTSRC: | |
583 | ret = set_outmask(devc, val); | |
584 | break; | |
585 | ||
586 | default: | |
587 | ret = sb_mixer_set(devc, cmd & 0xff, val); | |
588 | } | |
589 | } | |
590 | else switch (cmd & 0xff) | |
591 | { | |
592 | case SOUND_MIXER_RECSRC: | |
593 | ret = devc->recmask; | |
594 | break; | |
595 | ||
596 | case SOUND_MIXER_OUTSRC: | |
597 | ret = devc->outmask; | |
598 | break; | |
599 | ||
600 | case SOUND_MIXER_DEVMASK: | |
601 | ret = devc->supported_devices; | |
602 | break; | |
603 | ||
604 | case SOUND_MIXER_STEREODEVS: | |
605 | ret = devc->supported_devices; | |
606 | /* The ESS seems to have stereo mic controls */ | |
607 | if (devc->model == MDL_ESS) | |
608 | ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); | |
609 | else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) | |
610 | ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); | |
611 | break; | |
612 | ||
613 | case SOUND_MIXER_RECMASK: | |
614 | ret = devc->supported_rec_devices; | |
615 | break; | |
616 | ||
617 | case SOUND_MIXER_OUTMASK: | |
618 | ret = devc->supported_out_devices; | |
619 | break; | |
620 | ||
621 | case SOUND_MIXER_CAPS: | |
622 | ret = devc->mixer_caps; | |
623 | break; | |
624 | ||
625 | default: | |
626 | ret = sb_mixer_get(devc, cmd & 0xff); | |
627 | break; | |
628 | } | |
629 | return put_user(ret, p); | |
630 | } else | |
631 | return -EINVAL; | |
632 | } | |
633 | ||
634 | static struct mixer_operations sb_mixer_operations = | |
635 | { | |
636 | .owner = THIS_MODULE, | |
637 | .id = "SB", | |
638 | .name = "Sound Blaster", | |
639 | .ioctl = sb_mixer_ioctl | |
640 | }; | |
641 | ||
642 | static struct mixer_operations als007_mixer_operations = | |
643 | { | |
644 | .owner = THIS_MODULE, | |
645 | .id = "ALS007", | |
646 | .name = "Avance ALS-007", | |
647 | .ioctl = sb_mixer_ioctl | |
648 | }; | |
649 | ||
650 | static void sb_mixer_reset(sb_devc * devc) | |
651 | { | |
652 | char name[32]; | |
653 | int i; | |
654 | ||
655 | sprintf(name, "SB_%d", devc->sbmixnum); | |
656 | ||
657 | if (devc->sbmo.sm_games) | |
658 | devc->levels = load_mixer_volumes(name, smg_default_levels, 1); | |
659 | else | |
660 | devc->levels = load_mixer_volumes(name, sb_default_levels, 1); | |
661 | ||
662 | for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) | |
663 | sb_mixer_set(devc, i, devc->levels[i]); | |
664 | ||
665 | if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) { | |
666 | set_recmask(devc, SOUND_MASK_MIC); | |
667 | }; | |
668 | } | |
669 | ||
670 | int sb_mixer_init(sb_devc * devc, struct module *owner) | |
671 | { | |
672 | int mixer_type = 0; | |
673 | int m; | |
674 | ||
675 | devc->sbmixnum = sbmixnum++; | |
676 | devc->levels = NULL; | |
677 | ||
678 | sb_setmixer(devc, 0x00, 0); /* Reset mixer */ | |
679 | ||
680 | if (!(mixer_type = detect_mixer(devc))) | |
681 | return 0; /* No mixer. Why? */ | |
682 | ||
683 | switch (devc->model) | |
684 | { | |
685 | case MDL_ESSPCI: | |
686 | case MDL_YMPCI: | |
687 | case MDL_SBPRO: | |
688 | case MDL_AZTECH: | |
689 | case MDL_JAZZ: | |
690 | devc->mixer_caps = SOUND_CAP_EXCL_INPUT; | |
691 | devc->supported_devices = SBPRO_MIXER_DEVICES; | |
692 | devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; | |
693 | devc->iomap = &sbpro_mix; | |
694 | devc->iomap_sz = ARRAY_SIZE(sbpro_mix); | |
695 | break; | |
696 | ||
697 | case MDL_ESS: | |
698 | ess_mixer_init (devc); | |
699 | break; | |
700 | ||
701 | case MDL_SMW: | |
702 | devc->mixer_caps = SOUND_CAP_EXCL_INPUT; | |
703 | devc->supported_devices = 0; | |
704 | devc->supported_rec_devices = 0; | |
705 | devc->iomap = &sbpro_mix; | |
706 | devc->iomap_sz = ARRAY_SIZE(sbpro_mix); | |
707 | smw_mixer_init(devc); | |
708 | break; | |
709 | ||
710 | case MDL_SB16: | |
711 | devc->mixer_caps = 0; | |
712 | devc->supported_rec_devices = SB16_RECORDING_DEVICES; | |
713 | devc->supported_out_devices = SB16_OUTFILTER_DEVICES; | |
714 | if (devc->submodel != SUBMDL_ALS007) | |
715 | { | |
716 | devc->supported_devices = SB16_MIXER_DEVICES; | |
717 | devc->iomap = &sb16_mix; | |
718 | devc->iomap_sz = ARRAY_SIZE(sb16_mix); | |
719 | } | |
720 | else | |
721 | { | |
722 | devc->supported_devices = ALS007_MIXER_DEVICES; | |
723 | devc->iomap = &als007_mix; | |
724 | devc->iomap_sz = ARRAY_SIZE(als007_mix); | |
725 | } | |
726 | break; | |
727 | ||
728 | default: | |
729 | printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model); | |
730 | return 0; | |
731 | } | |
732 | ||
733 | m = sound_alloc_mixerdev(); | |
734 | if (m == -1) | |
735 | return 0; | |
736 | ||
5cbded58 | 737 | mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); |
1da177e4 LT |
738 | if (mixer_devs[m] == NULL) |
739 | { | |
740 | printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); | |
741 | sound_unload_mixerdev(m); | |
742 | return 0; | |
743 | } | |
744 | ||
745 | if (devc->submodel != SUBMDL_ALS007) | |
746 | memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations)); | |
747 | else | |
748 | memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); | |
749 | ||
750 | mixer_devs[m]->devc = devc; | |
751 | ||
752 | if (owner) | |
753 | mixer_devs[m]->owner = owner; | |
754 | ||
755 | devc->my_mixerdev = m; | |
756 | sb_mixer_reset(devc); | |
757 | return 1; | |
758 | } | |
759 | ||
760 | void sb_mixer_unload(sb_devc *devc) | |
761 | { | |
762 | if (devc->my_mixerdev == -1) | |
763 | return; | |
764 | ||
765 | kfree(mixer_devs[devc->my_mixerdev]); | |
766 | sound_unload_mixerdev(devc->my_mixerdev); | |
767 | sbmixnum--; | |
768 | } |