1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 * Routines for Sound Blaster mixer control
5 */
6
7 #include <linux/io.h>
8 #include <linux/delay.h>
9 #include <linux/string.h>
10 #include <linux/time.h>
11 #include <sound/core.h>
12 #include <sound/sb.h>
13 #include <sound/control.h>
14
15 #undef IO_DEBUG
16
snd_sbmixer_write(struct snd_sb * chip,unsigned char reg,unsigned char data)17 void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
18 {
19 outb(reg, SBP(chip, MIXER_ADDR));
20 udelay(10);
21 outb(data, SBP(chip, MIXER_DATA));
22 udelay(10);
23 #ifdef IO_DEBUG
24 dev_dbg(chip->card->dev, "mixer_write 0x%x 0x%x\n", reg, data);
25 #endif
26 }
27
snd_sbmixer_read(struct snd_sb * chip,unsigned char reg)28 unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
29 {
30 unsigned char result;
31
32 outb(reg, SBP(chip, MIXER_ADDR));
33 udelay(10);
34 result = inb(SBP(chip, MIXER_DATA));
35 udelay(10);
36 #ifdef IO_DEBUG
37 dev_dbg(chip->card->dev, "mixer_read 0x%x 0x%x\n", reg, result);
38 #endif
39 return result;
40 }
41
42 /*
43 * Single channel mixer element
44 */
45
snd_sbmixer_info_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)46 static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
47 {
48 int mask = (kcontrol->private_value >> 24) & 0xff;
49
50 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
51 uinfo->count = 1;
52 uinfo->value.integer.min = 0;
53 uinfo->value.integer.max = mask;
54 return 0;
55 }
56
snd_sbmixer_get_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)57 static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
58 {
59 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
60 unsigned long flags;
61 int reg = kcontrol->private_value & 0xff;
62 int shift = (kcontrol->private_value >> 16) & 0xff;
63 int mask = (kcontrol->private_value >> 24) & 0xff;
64 unsigned char val;
65
66 spin_lock_irqsave(&sb->mixer_lock, flags);
67 val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
68 spin_unlock_irqrestore(&sb->mixer_lock, flags);
69 ucontrol->value.integer.value[0] = val;
70 return 0;
71 }
72
snd_sbmixer_put_single(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)73 static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
74 {
75 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
76 unsigned long flags;
77 int reg = kcontrol->private_value & 0xff;
78 int shift = (kcontrol->private_value >> 16) & 0x07;
79 int mask = (kcontrol->private_value >> 24) & 0xff;
80 int change;
81 unsigned char val, oval;
82
83 val = (ucontrol->value.integer.value[0] & mask) << shift;
84 spin_lock_irqsave(&sb->mixer_lock, flags);
85 oval = snd_sbmixer_read(sb, reg);
86 val = (oval & ~(mask << shift)) | val;
87 change = val != oval;
88 if (change)
89 snd_sbmixer_write(sb, reg, val);
90 spin_unlock_irqrestore(&sb->mixer_lock, flags);
91 return change;
92 }
93
94 /*
95 * Double channel mixer element
96 */
97
snd_sbmixer_info_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)98 static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
99 {
100 int mask = (kcontrol->private_value >> 24) & 0xff;
101
102 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
103 uinfo->count = 2;
104 uinfo->value.integer.min = 0;
105 uinfo->value.integer.max = mask;
106 return 0;
107 }
108
snd_sbmixer_get_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)109 static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
110 {
111 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
112 unsigned long flags;
113 int left_reg = kcontrol->private_value & 0xff;
114 int right_reg = (kcontrol->private_value >> 8) & 0xff;
115 int left_shift = (kcontrol->private_value >> 16) & 0x07;
116 int right_shift = (kcontrol->private_value >> 19) & 0x07;
117 int mask = (kcontrol->private_value >> 24) & 0xff;
118 unsigned char left, right;
119
120 spin_lock_irqsave(&sb->mixer_lock, flags);
121 left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
122 right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
123 spin_unlock_irqrestore(&sb->mixer_lock, flags);
124 ucontrol->value.integer.value[0] = left;
125 ucontrol->value.integer.value[1] = right;
126 return 0;
127 }
128
snd_sbmixer_put_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)129 static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
130 {
131 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
132 unsigned long flags;
133 int left_reg = kcontrol->private_value & 0xff;
134 int right_reg = (kcontrol->private_value >> 8) & 0xff;
135 int left_shift = (kcontrol->private_value >> 16) & 0x07;
136 int right_shift = (kcontrol->private_value >> 19) & 0x07;
137 int mask = (kcontrol->private_value >> 24) & 0xff;
138 int change;
139 unsigned char left, right, oleft, oright;
140
141 left = (ucontrol->value.integer.value[0] & mask) << left_shift;
142 right = (ucontrol->value.integer.value[1] & mask) << right_shift;
143 spin_lock_irqsave(&sb->mixer_lock, flags);
144 if (left_reg == right_reg) {
145 oleft = snd_sbmixer_read(sb, left_reg);
146 left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
147 change = left != oleft;
148 if (change)
149 snd_sbmixer_write(sb, left_reg, left);
150 } else {
151 oleft = snd_sbmixer_read(sb, left_reg);
152 oright = snd_sbmixer_read(sb, right_reg);
153 left = (oleft & ~(mask << left_shift)) | left;
154 right = (oright & ~(mask << right_shift)) | right;
155 change = left != oleft || right != oright;
156 if (change) {
157 snd_sbmixer_write(sb, left_reg, left);
158 snd_sbmixer_write(sb, right_reg, right);
159 }
160 }
161 spin_unlock_irqrestore(&sb->mixer_lock, flags);
162 return change;
163 }
164
165 /*
166 * DT-019x / ALS-007 capture/input switch
167 */
168
snd_dt019x_input_sw_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)169 static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
170 {
171 static const char * const texts[5] = {
172 "CD", "Mic", "Line", "Synth", "Master"
173 };
174
175 return snd_ctl_enum_info(uinfo, 1, 5, texts);
176 }
177
snd_dt019x_input_sw_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)178 static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
179 {
180 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
181 unsigned long flags;
182 unsigned char oval;
183
184 spin_lock_irqsave(&sb->mixer_lock, flags);
185 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
186 spin_unlock_irqrestore(&sb->mixer_lock, flags);
187 switch (oval & 0x07) {
188 case SB_DT019X_CAP_CD:
189 ucontrol->value.enumerated.item[0] = 0;
190 break;
191 case SB_DT019X_CAP_MIC:
192 ucontrol->value.enumerated.item[0] = 1;
193 break;
194 case SB_DT019X_CAP_LINE:
195 ucontrol->value.enumerated.item[0] = 2;
196 break;
197 case SB_DT019X_CAP_MAIN:
198 ucontrol->value.enumerated.item[0] = 4;
199 break;
200 /* To record the synth on these cards you must record the main. */
201 /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
202 /* duplicate case labels if left uncommented. */
203 /* case SB_DT019X_CAP_SYNTH:
204 * ucontrol->value.enumerated.item[0] = 3;
205 * break;
206 */
207 default:
208 ucontrol->value.enumerated.item[0] = 4;
209 break;
210 }
211 return 0;
212 }
213
snd_dt019x_input_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)214 static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
215 {
216 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
217 unsigned long flags;
218 int change;
219 unsigned char nval, oval;
220
221 if (ucontrol->value.enumerated.item[0] > 4)
222 return -EINVAL;
223 switch (ucontrol->value.enumerated.item[0]) {
224 case 0:
225 nval = SB_DT019X_CAP_CD;
226 break;
227 case 1:
228 nval = SB_DT019X_CAP_MIC;
229 break;
230 case 2:
231 nval = SB_DT019X_CAP_LINE;
232 break;
233 case 3:
234 nval = SB_DT019X_CAP_SYNTH;
235 break;
236 case 4:
237 nval = SB_DT019X_CAP_MAIN;
238 break;
239 default:
240 nval = SB_DT019X_CAP_MAIN;
241 }
242 spin_lock_irqsave(&sb->mixer_lock, flags);
243 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
244 change = nval != oval;
245 if (change)
246 snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
247 spin_unlock_irqrestore(&sb->mixer_lock, flags);
248 return change;
249 }
250
251 /*
252 * ALS4000 mono recording control switch
253 */
254
snd_als4k_mono_capture_route_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)255 static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_info *uinfo)
257 {
258 static const char * const texts[3] = {
259 "L chan only", "R chan only", "L ch/2 + R ch/2"
260 };
261
262 return snd_ctl_enum_info(uinfo, 1, 3, texts);
263 }
264
snd_als4k_mono_capture_route_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)265 static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
266 struct snd_ctl_elem_value *ucontrol)
267 {
268 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
269 unsigned long flags;
270 unsigned char oval;
271
272 spin_lock_irqsave(&sb->mixer_lock, flags);
273 oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
274 spin_unlock_irqrestore(&sb->mixer_lock, flags);
275 oval >>= 6;
276 if (oval > 2)
277 oval = 2;
278
279 ucontrol->value.enumerated.item[0] = oval;
280 return 0;
281 }
282
snd_als4k_mono_capture_route_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)283 static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
284 struct snd_ctl_elem_value *ucontrol)
285 {
286 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
287 unsigned long flags;
288 int change;
289 unsigned char nval, oval;
290
291 if (ucontrol->value.enumerated.item[0] > 2)
292 return -EINVAL;
293 spin_lock_irqsave(&sb->mixer_lock, flags);
294 oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
295
296 nval = (oval & ~(3 << 6))
297 | (ucontrol->value.enumerated.item[0] << 6);
298 change = nval != oval;
299 if (change)
300 snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
301 spin_unlock_irqrestore(&sb->mixer_lock, flags);
302 return change;
303 }
304
305 /*
306 * SBPRO input multiplexer
307 */
308
snd_sb8mixer_info_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)309 static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
310 {
311 static const char * const texts[3] = {
312 "Mic", "CD", "Line"
313 };
314
315 return snd_ctl_enum_info(uinfo, 1, 3, texts);
316 }
317
318
snd_sb8mixer_get_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)319 static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
320 {
321 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
322 unsigned long flags;
323 unsigned char oval;
324
325 spin_lock_irqsave(&sb->mixer_lock, flags);
326 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
327 spin_unlock_irqrestore(&sb->mixer_lock, flags);
328 switch ((oval >> 0x01) & 0x03) {
329 case SB_DSP_MIXS_CD:
330 ucontrol->value.enumerated.item[0] = 1;
331 break;
332 case SB_DSP_MIXS_LINE:
333 ucontrol->value.enumerated.item[0] = 2;
334 break;
335 default:
336 ucontrol->value.enumerated.item[0] = 0;
337 break;
338 }
339 return 0;
340 }
341
snd_sb8mixer_put_mux(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)342 static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
343 {
344 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
345 unsigned long flags;
346 int change;
347 unsigned char nval, oval;
348
349 if (ucontrol->value.enumerated.item[0] > 2)
350 return -EINVAL;
351 switch (ucontrol->value.enumerated.item[0]) {
352 case 1:
353 nval = SB_DSP_MIXS_CD;
354 break;
355 case 2:
356 nval = SB_DSP_MIXS_LINE;
357 break;
358 default:
359 nval = SB_DSP_MIXS_MIC;
360 }
361 nval <<= 1;
362 spin_lock_irqsave(&sb->mixer_lock, flags);
363 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
364 nval |= oval & ~0x06;
365 change = nval != oval;
366 if (change)
367 snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
368 spin_unlock_irqrestore(&sb->mixer_lock, flags);
369 return change;
370 }
371
372 /*
373 * SB16 input switch
374 */
375
snd_sb16mixer_info_input_sw(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)376 static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
377 {
378 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
379 uinfo->count = 4;
380 uinfo->value.integer.min = 0;
381 uinfo->value.integer.max = 1;
382 return 0;
383 }
384
snd_sb16mixer_get_input_sw(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)385 static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
386 {
387 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
388 unsigned long flags;
389 int reg1 = kcontrol->private_value & 0xff;
390 int reg2 = (kcontrol->private_value >> 8) & 0xff;
391 int left_shift = (kcontrol->private_value >> 16) & 0x0f;
392 int right_shift = (kcontrol->private_value >> 24) & 0x0f;
393 unsigned char val1, val2;
394
395 spin_lock_irqsave(&sb->mixer_lock, flags);
396 val1 = snd_sbmixer_read(sb, reg1);
397 val2 = snd_sbmixer_read(sb, reg2);
398 spin_unlock_irqrestore(&sb->mixer_lock, flags);
399 ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
400 ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
401 ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
402 ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
403 return 0;
404 }
405
snd_sb16mixer_put_input_sw(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)406 static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
407 {
408 struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
409 unsigned long flags;
410 int reg1 = kcontrol->private_value & 0xff;
411 int reg2 = (kcontrol->private_value >> 8) & 0xff;
412 int left_shift = (kcontrol->private_value >> 16) & 0x0f;
413 int right_shift = (kcontrol->private_value >> 24) & 0x0f;
414 int change;
415 unsigned char val1, val2, oval1, oval2;
416
417 spin_lock_irqsave(&sb->mixer_lock, flags);
418 oval1 = snd_sbmixer_read(sb, reg1);
419 oval2 = snd_sbmixer_read(sb, reg2);
420 val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
421 val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
422 val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
423 val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
424 val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
425 val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
426 change = val1 != oval1 || val2 != oval2;
427 if (change) {
428 snd_sbmixer_write(sb, reg1, val1);
429 snd_sbmixer_write(sb, reg2, val2);
430 }
431 spin_unlock_irqrestore(&sb->mixer_lock, flags);
432 return change;
433 }
434
435
436 /*
437 */
438 /*
439 */
snd_sbmixer_add_ctl(struct snd_sb * chip,const char * name,int index,int type,unsigned long value)440 int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
441 {
442 static const struct snd_kcontrol_new newctls[] = {
443 [SB_MIX_SINGLE] = {
444 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
445 .info = snd_sbmixer_info_single,
446 .get = snd_sbmixer_get_single,
447 .put = snd_sbmixer_put_single,
448 },
449 [SB_MIX_DOUBLE] = {
450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
451 .info = snd_sbmixer_info_double,
452 .get = snd_sbmixer_get_double,
453 .put = snd_sbmixer_put_double,
454 },
455 [SB_MIX_INPUT_SW] = {
456 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
457 .info = snd_sb16mixer_info_input_sw,
458 .get = snd_sb16mixer_get_input_sw,
459 .put = snd_sb16mixer_put_input_sw,
460 },
461 [SB_MIX_CAPTURE_PRO] = {
462 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
463 .info = snd_sb8mixer_info_mux,
464 .get = snd_sb8mixer_get_mux,
465 .put = snd_sb8mixer_put_mux,
466 },
467 [SB_MIX_CAPTURE_DT019X] = {
468 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
469 .info = snd_dt019x_input_sw_info,
470 .get = snd_dt019x_input_sw_get,
471 .put = snd_dt019x_input_sw_put,
472 },
473 [SB_MIX_MONO_CAPTURE_ALS4K] = {
474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
475 .info = snd_als4k_mono_capture_route_info,
476 .get = snd_als4k_mono_capture_route_get,
477 .put = snd_als4k_mono_capture_route_put,
478 },
479 };
480 struct snd_kcontrol *ctl;
481 int err;
482
483 ctl = snd_ctl_new1(&newctls[type], chip);
484 if (! ctl)
485 return -ENOMEM;
486 strscpy(ctl->id.name, name, sizeof(ctl->id.name));
487 ctl->id.index = index;
488 ctl->private_value = value;
489 err = snd_ctl_add(chip->card, ctl);
490 if (err < 0)
491 return err;
492 return 0;
493 }
494
495 /*
496 * SB 2.0 specific mixer elements
497 */
498
499 static const struct sbmix_elem snd_sb20_controls[] = {
500 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
501 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
502 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
503 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
504 };
505
506 static const unsigned char snd_sb20_init_values[][2] = {
507 { SB_DSP20_MASTER_DEV, 0 },
508 { SB_DSP20_FM_DEV, 0 },
509 };
510
511 /*
512 * SB Pro specific mixer elements
513 */
514 static const struct sbmix_elem snd_sbpro_controls[] = {
515 SB_DOUBLE("Master Playback Volume",
516 SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
517 SB_DOUBLE("PCM Playback Volume",
518 SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
519 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
520 SB_DOUBLE("Synth Playback Volume",
521 SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
522 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
523 SB_DOUBLE("Line Playback Volume",
524 SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
525 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
526 {
527 .name = "Capture Source",
528 .type = SB_MIX_CAPTURE_PRO
529 },
530 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
531 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
532 };
533
534 static const unsigned char snd_sbpro_init_values[][2] = {
535 { SB_DSP_MASTER_DEV, 0 },
536 { SB_DSP_PCM_DEV, 0 },
537 { SB_DSP_FM_DEV, 0 },
538 };
539
540 /*
541 * SB16 specific mixer elements
542 */
543 static const struct sbmix_elem snd_sb16_controls[] = {
544 SB_DOUBLE("Master Playback Volume",
545 SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
546 SB_DOUBLE("PCM Playback Volume",
547 SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
548 SB16_INPUT_SW("Synth Capture Route",
549 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
550 SB_DOUBLE("Synth Playback Volume",
551 SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
552 SB16_INPUT_SW("CD Capture Route",
553 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
554 SB_DOUBLE("CD Playback Switch",
555 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
556 SB_DOUBLE("CD Playback Volume",
557 SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
558 SB16_INPUT_SW("Mic Capture Route",
559 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
560 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
561 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
562 SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
563 SB_DOUBLE("Capture Volume",
564 SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
565 SB_DOUBLE("Playback Volume",
566 SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
567 SB16_INPUT_SW("Line Capture Route",
568 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
569 SB_DOUBLE("Line Playback Switch",
570 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
571 SB_DOUBLE("Line Playback Volume",
572 SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
573 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
574 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
575 SB_DOUBLE("Tone Control - Bass",
576 SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
577 SB_DOUBLE("Tone Control - Treble",
578 SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
579 };
580
581 static const unsigned char snd_sb16_init_values[][2] = {
582 { SB_DSP4_MASTER_DEV + 0, 0 },
583 { SB_DSP4_MASTER_DEV + 1, 0 },
584 { SB_DSP4_PCM_DEV + 0, 0 },
585 { SB_DSP4_PCM_DEV + 1, 0 },
586 { SB_DSP4_SYNTH_DEV + 0, 0 },
587 { SB_DSP4_SYNTH_DEV + 1, 0 },
588 { SB_DSP4_INPUT_LEFT, 0 },
589 { SB_DSP4_INPUT_RIGHT, 0 },
590 { SB_DSP4_OUTPUT_SW, 0 },
591 { SB_DSP4_SPEAKER_DEV, 0 },
592 };
593
594 /*
595 * DT019x specific mixer elements
596 */
597 static const struct sbmix_elem snd_dt019x_controls[] = {
598 /* ALS4000 below has some parts which we might be lacking,
599 * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
600 SB_DOUBLE("Master Playback Volume",
601 SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
602 SB_DOUBLE("PCM Playback Switch",
603 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
604 SB_DOUBLE("PCM Playback Volume",
605 SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
606 SB_DOUBLE("Synth Playback Switch",
607 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
608 SB_DOUBLE("Synth Playback Volume",
609 SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
610 SB_DOUBLE("CD Playback Switch",
611 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
612 SB_DOUBLE("CD Playback Volume",
613 SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
614 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
615 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
616 SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7),
617 SB_DOUBLE("Line Playback Switch",
618 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
619 SB_DOUBLE("Line Playback Volume",
620 SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
621 {
622 .name = "Capture Source",
623 .type = SB_MIX_CAPTURE_DT019X
624 }
625 };
626
627 static const unsigned char snd_dt019x_init_values[][2] = {
628 { SB_DT019X_MASTER_DEV, 0 },
629 { SB_DT019X_PCM_DEV, 0 },
630 { SB_DT019X_SYNTH_DEV, 0 },
631 { SB_DT019X_CD_DEV, 0 },
632 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */
633 { SB_DT019X_LINE_DEV, 0 },
634 { SB_DSP4_OUTPUT_SW, 0 },
635 { SB_DT019X_OUTPUT_SW2, 0 },
636 { SB_DT019X_CAPTURE_SW, 0x06 },
637 };
638
639 /*
640 * ALS4000 specific mixer elements
641 */
642 static const struct sbmix_elem snd_als4000_controls[] = {
643 SB_DOUBLE("PCM Playback Switch",
644 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
645 SB_DOUBLE("Synth Playback Switch",
646 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
647 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
648 SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
649 {
650 .name = "Master Mono Capture Route",
651 .type = SB_MIX_MONO_CAPTURE_ALS4K
652 },
653 SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
654 SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
655 SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
656 SB_SINGLE("Digital Loopback Switch",
657 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
658 /* FIXME: functionality of 3D controls might be swapped, I didn't find
659 * a description of how to identify what is supposed to be what */
660 SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
661 /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
662 SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
663 /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
664 * but what ALSA 3D attribute is that actually? "Center", "Depth",
665 * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
666 SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
667 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
668 SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
669 SB_ALS4000_FMDAC, 5, 0x01),
670 #ifdef NOT_AVAILABLE
671 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
672 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
673 #endif
674 };
675
676 static const unsigned char snd_als4000_init_values[][2] = {
677 { SB_DSP4_MASTER_DEV + 0, 0 },
678 { SB_DSP4_MASTER_DEV + 1, 0 },
679 { SB_DSP4_PCM_DEV + 0, 0 },
680 { SB_DSP4_PCM_DEV + 1, 0 },
681 { SB_DSP4_SYNTH_DEV + 0, 0 },
682 { SB_DSP4_SYNTH_DEV + 1, 0 },
683 { SB_DSP4_SPEAKER_DEV, 0 },
684 { SB_DSP4_OUTPUT_SW, 0 },
685 { SB_DSP4_INPUT_LEFT, 0 },
686 { SB_DSP4_INPUT_RIGHT, 0 },
687 { SB_DT019X_OUTPUT_SW2, 0 },
688 { SB_ALS4000_MIC_IN_GAIN, 0 },
689 };
690
691 /*
692 */
snd_sbmixer_init(struct snd_sb * chip,const struct sbmix_elem * controls,int controls_count,const unsigned char map[][2],int map_count,char * name)693 static int snd_sbmixer_init(struct snd_sb *chip,
694 const struct sbmix_elem *controls,
695 int controls_count,
696 const unsigned char map[][2],
697 int map_count,
698 char *name)
699 {
700 unsigned long flags;
701 struct snd_card *card = chip->card;
702 int idx, err;
703
704 /* mixer reset */
705 spin_lock_irqsave(&chip->mixer_lock, flags);
706 snd_sbmixer_write(chip, 0x00, 0x00);
707 spin_unlock_irqrestore(&chip->mixer_lock, flags);
708
709 /* mute and zero volume channels */
710 for (idx = 0; idx < map_count; idx++) {
711 spin_lock_irqsave(&chip->mixer_lock, flags);
712 snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
713 spin_unlock_irqrestore(&chip->mixer_lock, flags);
714 }
715
716 for (idx = 0; idx < controls_count; idx++) {
717 err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
718 if (err < 0)
719 return err;
720 }
721 snd_component_add(card, name);
722 strscpy(card->mixername, name);
723 return 0;
724 }
725
snd_sbmixer_new(struct snd_sb * chip)726 int snd_sbmixer_new(struct snd_sb *chip)
727 {
728 struct snd_card *card;
729 int err;
730
731 if (snd_BUG_ON(!chip || !chip->card))
732 return -EINVAL;
733
734 card = chip->card;
735
736 switch (chip->hardware) {
737 case SB_HW_10:
738 return 0; /* no mixer chip on SB1.x */
739 case SB_HW_20:
740 case SB_HW_201:
741 err = snd_sbmixer_init(chip,
742 snd_sb20_controls,
743 ARRAY_SIZE(snd_sb20_controls),
744 snd_sb20_init_values,
745 ARRAY_SIZE(snd_sb20_init_values),
746 "CTL1335");
747 if (err < 0)
748 return err;
749 break;
750 case SB_HW_PRO:
751 case SB_HW_JAZZ16:
752 err = snd_sbmixer_init(chip,
753 snd_sbpro_controls,
754 ARRAY_SIZE(snd_sbpro_controls),
755 snd_sbpro_init_values,
756 ARRAY_SIZE(snd_sbpro_init_values),
757 "CTL1345");
758 if (err < 0)
759 return err;
760 break;
761 case SB_HW_16:
762 case SB_HW_ALS100:
763 case SB_HW_CS5530:
764 err = snd_sbmixer_init(chip,
765 snd_sb16_controls,
766 ARRAY_SIZE(snd_sb16_controls),
767 snd_sb16_init_values,
768 ARRAY_SIZE(snd_sb16_init_values),
769 "CTL1745");
770 if (err < 0)
771 return err;
772 break;
773 case SB_HW_ALS4000:
774 /* use only the first 16 controls from SB16 */
775 err = snd_sbmixer_init(chip,
776 snd_sb16_controls,
777 16,
778 snd_sb16_init_values,
779 ARRAY_SIZE(snd_sb16_init_values),
780 "ALS4000");
781 if (err < 0)
782 return err;
783 err = snd_sbmixer_init(chip,
784 snd_als4000_controls,
785 ARRAY_SIZE(snd_als4000_controls),
786 snd_als4000_init_values,
787 ARRAY_SIZE(snd_als4000_init_values),
788 "ALS4000");
789 if (err < 0)
790 return err;
791 break;
792 case SB_HW_DT019X:
793 err = snd_sbmixer_init(chip,
794 snd_dt019x_controls,
795 ARRAY_SIZE(snd_dt019x_controls),
796 snd_dt019x_init_values,
797 ARRAY_SIZE(snd_dt019x_init_values),
798 "DT019X");
799 if (err < 0)
800 return err;
801 break;
802 default:
803 strscpy(card->mixername, "???");
804 }
805 return 0;
806 }
807
808 #ifdef CONFIG_PM
809 static const unsigned char sb20_saved_regs[] = {
810 SB_DSP20_MASTER_DEV,
811 SB_DSP20_PCM_DEV,
812 SB_DSP20_FM_DEV,
813 SB_DSP20_CD_DEV,
814 };
815
816 static const unsigned char sbpro_saved_regs[] = {
817 SB_DSP_MASTER_DEV,
818 SB_DSP_PCM_DEV,
819 SB_DSP_PLAYBACK_FILT,
820 SB_DSP_FM_DEV,
821 SB_DSP_CD_DEV,
822 SB_DSP_LINE_DEV,
823 SB_DSP_MIC_DEV,
824 SB_DSP_CAPTURE_SOURCE,
825 SB_DSP_CAPTURE_FILT,
826 };
827
828 static const unsigned char sb16_saved_regs[] = {
829 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
830 SB_DSP4_3DSE,
831 SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
832 SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
833 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
834 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
835 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
836 SB_DSP4_OUTPUT_SW,
837 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
838 SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
839 SB_DSP4_MIC_DEV,
840 SB_DSP4_SPEAKER_DEV,
841 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
842 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
843 SB_DSP4_MIC_AGC
844 };
845
846 static const unsigned char dt019x_saved_regs[] = {
847 SB_DT019X_MASTER_DEV,
848 SB_DT019X_PCM_DEV,
849 SB_DT019X_SYNTH_DEV,
850 SB_DT019X_CD_DEV,
851 SB_DT019X_MIC_DEV,
852 SB_DT019X_SPKR_DEV,
853 SB_DT019X_LINE_DEV,
854 SB_DSP4_OUTPUT_SW,
855 SB_DT019X_OUTPUT_SW2,
856 SB_DT019X_CAPTURE_SW,
857 };
858
859 static const unsigned char als4000_saved_regs[] = {
860 /* please verify in dsheet whether regs to be added
861 are actually real H/W or just dummy */
862 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
863 SB_DSP4_OUTPUT_SW,
864 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
865 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
866 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
867 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
868 SB_DSP4_MIC_DEV,
869 SB_DSP4_SPEAKER_DEV,
870 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
871 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
872 SB_DT019X_OUTPUT_SW2,
873 SB_ALS4000_MONO_IO_CTRL,
874 SB_ALS4000_MIC_IN_GAIN,
875 SB_ALS4000_FMDAC,
876 SB_ALS4000_3D_SND_FX,
877 SB_ALS4000_3D_TIME_DELAY,
878 SB_ALS4000_CR3_CONFIGURATION,
879 };
880
save_mixer(struct snd_sb * chip,const unsigned char * regs,int num_regs)881 static void save_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
882 {
883 unsigned char *val = chip->saved_regs;
884 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
885 return;
886 for (; num_regs; num_regs--)
887 *val++ = snd_sbmixer_read(chip, *regs++);
888 }
889
restore_mixer(struct snd_sb * chip,const unsigned char * regs,int num_regs)890 static void restore_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
891 {
892 unsigned char *val = chip->saved_regs;
893 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
894 return;
895 for (; num_regs; num_regs--)
896 snd_sbmixer_write(chip, *regs++, *val++);
897 }
898
snd_sbmixer_suspend(struct snd_sb * chip)899 void snd_sbmixer_suspend(struct snd_sb *chip)
900 {
901 switch (chip->hardware) {
902 case SB_HW_20:
903 case SB_HW_201:
904 save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
905 break;
906 case SB_HW_PRO:
907 case SB_HW_JAZZ16:
908 save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
909 break;
910 case SB_HW_16:
911 case SB_HW_ALS100:
912 case SB_HW_CS5530:
913 save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
914 break;
915 case SB_HW_ALS4000:
916 save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
917 break;
918 case SB_HW_DT019X:
919 save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
920 break;
921 default:
922 break;
923 }
924 }
925
snd_sbmixer_resume(struct snd_sb * chip)926 void snd_sbmixer_resume(struct snd_sb *chip)
927 {
928 switch (chip->hardware) {
929 case SB_HW_20:
930 case SB_HW_201:
931 restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
932 break;
933 case SB_HW_PRO:
934 case SB_HW_JAZZ16:
935 restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
936 break;
937 case SB_HW_16:
938 case SB_HW_ALS100:
939 case SB_HW_CS5530:
940 restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
941 break;
942 case SB_HW_ALS4000:
943 restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
944 break;
945 case SB_HW_DT019X:
946 restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
947 break;
948 default:
949 break;
950 }
951 }
952 #endif
953