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