1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 * Routines for Sound Blaster mixer control
8 #include <linux/delay.h>
9 #include <linux/time.h>
10 #include <sound/core.h>
12 #include <sound/control.h>
16 void snd_sbmixer_write(struct snd_sb
*chip
, unsigned char reg
, unsigned char data
)
18 outb(reg
, SBP(chip
, MIXER_ADDR
));
20 outb(data
, SBP(chip
, MIXER_DATA
));
23 snd_printk(KERN_DEBUG
"mixer_write 0x%x 0x%x\n", reg
, data
);
27 unsigned char snd_sbmixer_read(struct snd_sb
*chip
, unsigned char reg
)
31 outb(reg
, SBP(chip
, MIXER_ADDR
));
33 result
= inb(SBP(chip
, MIXER_DATA
));
36 snd_printk(KERN_DEBUG
"mixer_read 0x%x 0x%x\n", reg
, result
);
42 * Single channel mixer element
45 static int snd_sbmixer_info_single(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_info
*uinfo
)
47 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
49 uinfo
->type
= mask
== 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN
: SNDRV_CTL_ELEM_TYPE_INTEGER
;
51 uinfo
->value
.integer
.min
= 0;
52 uinfo
->value
.integer
.max
= mask
;
56 static int snd_sbmixer_get_single(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
58 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
60 int reg
= kcontrol
->private_value
& 0xff;
61 int shift
= (kcontrol
->private_value
>> 16) & 0xff;
62 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
65 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
66 val
= (snd_sbmixer_read(sb
, reg
) >> shift
) & mask
;
67 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
68 ucontrol
->value
.integer
.value
[0] = val
;
72 static int snd_sbmixer_put_single(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
74 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
76 int reg
= kcontrol
->private_value
& 0xff;
77 int shift
= (kcontrol
->private_value
>> 16) & 0x07;
78 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
80 unsigned char val
, oval
;
82 val
= (ucontrol
->value
.integer
.value
[0] & mask
) << shift
;
83 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
84 oval
= snd_sbmixer_read(sb
, reg
);
85 val
= (oval
& ~(mask
<< shift
)) | val
;
88 snd_sbmixer_write(sb
, reg
, val
);
89 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
94 * Double channel mixer element
97 static int snd_sbmixer_info_double(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_info
*uinfo
)
99 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
101 uinfo
->type
= mask
== 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN
: SNDRV_CTL_ELEM_TYPE_INTEGER
;
103 uinfo
->value
.integer
.min
= 0;
104 uinfo
->value
.integer
.max
= mask
;
108 static int snd_sbmixer_get_double(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
110 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
112 int left_reg
= kcontrol
->private_value
& 0xff;
113 int right_reg
= (kcontrol
->private_value
>> 8) & 0xff;
114 int left_shift
= (kcontrol
->private_value
>> 16) & 0x07;
115 int right_shift
= (kcontrol
->private_value
>> 19) & 0x07;
116 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
117 unsigned char left
, right
;
119 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
120 left
= (snd_sbmixer_read(sb
, left_reg
) >> left_shift
) & mask
;
121 right
= (snd_sbmixer_read(sb
, right_reg
) >> right_shift
) & mask
;
122 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
123 ucontrol
->value
.integer
.value
[0] = left
;
124 ucontrol
->value
.integer
.value
[1] = right
;
128 static int snd_sbmixer_put_double(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
130 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
132 int left_reg
= kcontrol
->private_value
& 0xff;
133 int right_reg
= (kcontrol
->private_value
>> 8) & 0xff;
134 int left_shift
= (kcontrol
->private_value
>> 16) & 0x07;
135 int right_shift
= (kcontrol
->private_value
>> 19) & 0x07;
136 int mask
= (kcontrol
->private_value
>> 24) & 0xff;
138 unsigned char left
, right
, oleft
, oright
;
140 left
= (ucontrol
->value
.integer
.value
[0] & mask
) << left_shift
;
141 right
= (ucontrol
->value
.integer
.value
[1] & mask
) << right_shift
;
142 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
143 if (left_reg
== right_reg
) {
144 oleft
= snd_sbmixer_read(sb
, left_reg
);
145 left
= (oleft
& ~((mask
<< left_shift
) | (mask
<< right_shift
))) | left
| right
;
146 change
= left
!= oleft
;
148 snd_sbmixer_write(sb
, left_reg
, left
);
150 oleft
= snd_sbmixer_read(sb
, left_reg
);
151 oright
= snd_sbmixer_read(sb
, right_reg
);
152 left
= (oleft
& ~(mask
<< left_shift
)) | left
;
153 right
= (oright
& ~(mask
<< right_shift
)) | right
;
154 change
= left
!= oleft
|| right
!= oright
;
156 snd_sbmixer_write(sb
, left_reg
, left
);
157 snd_sbmixer_write(sb
, right_reg
, right
);
160 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
165 * DT-019x / ALS-007 capture/input switch
168 static int snd_dt019x_input_sw_info(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_info
*uinfo
)
170 static const char * const texts
[5] = {
171 "CD", "Mic", "Line", "Synth", "Master"
174 return snd_ctl_enum_info(uinfo
, 1, 5, texts
);
177 static int snd_dt019x_input_sw_get(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
179 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
183 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
184 oval
= snd_sbmixer_read(sb
, SB_DT019X_CAPTURE_SW
);
185 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
186 switch (oval
& 0x07) {
187 case SB_DT019X_CAP_CD
:
188 ucontrol
->value
.enumerated
.item
[0] = 0;
190 case SB_DT019X_CAP_MIC
:
191 ucontrol
->value
.enumerated
.item
[0] = 1;
193 case SB_DT019X_CAP_LINE
:
194 ucontrol
->value
.enumerated
.item
[0] = 2;
196 case SB_DT019X_CAP_MAIN
:
197 ucontrol
->value
.enumerated
.item
[0] = 4;
199 /* To record the synth on these cards you must record the main. */
200 /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
201 /* duplicate case labels if left uncommented. */
202 /* case SB_DT019X_CAP_SYNTH:
203 * ucontrol->value.enumerated.item[0] = 3;
207 ucontrol
->value
.enumerated
.item
[0] = 4;
213 static int snd_dt019x_input_sw_put(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
215 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
218 unsigned char nval
, oval
;
220 if (ucontrol
->value
.enumerated
.item
[0] > 4)
222 switch (ucontrol
->value
.enumerated
.item
[0]) {
224 nval
= SB_DT019X_CAP_CD
;
227 nval
= SB_DT019X_CAP_MIC
;
230 nval
= SB_DT019X_CAP_LINE
;
233 nval
= SB_DT019X_CAP_SYNTH
;
236 nval
= SB_DT019X_CAP_MAIN
;
239 nval
= SB_DT019X_CAP_MAIN
;
241 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
242 oval
= snd_sbmixer_read(sb
, SB_DT019X_CAPTURE_SW
);
243 change
= nval
!= oval
;
245 snd_sbmixer_write(sb
, SB_DT019X_CAPTURE_SW
, nval
);
246 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
251 * ALS4000 mono recording control switch
254 static int snd_als4k_mono_capture_route_info(struct snd_kcontrol
*kcontrol
,
255 struct snd_ctl_elem_info
*uinfo
)
257 static const char * const texts
[3] = {
258 "L chan only", "R chan only", "L ch/2 + R ch/2"
261 return snd_ctl_enum_info(uinfo
, 1, 3, texts
);
264 static int snd_als4k_mono_capture_route_get(struct snd_kcontrol
*kcontrol
,
265 struct snd_ctl_elem_value
*ucontrol
)
267 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
271 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
272 oval
= snd_sbmixer_read(sb
, SB_ALS4000_MONO_IO_CTRL
);
273 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
278 ucontrol
->value
.enumerated
.item
[0] = oval
;
282 static int snd_als4k_mono_capture_route_put(struct snd_kcontrol
*kcontrol
,
283 struct snd_ctl_elem_value
*ucontrol
)
285 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
288 unsigned char nval
, oval
;
290 if (ucontrol
->value
.enumerated
.item
[0] > 2)
292 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
293 oval
= snd_sbmixer_read(sb
, SB_ALS4000_MONO_IO_CTRL
);
295 nval
= (oval
& ~(3 << 6))
296 | (ucontrol
->value
.enumerated
.item
[0] << 6);
297 change
= nval
!= oval
;
299 snd_sbmixer_write(sb
, SB_ALS4000_MONO_IO_CTRL
, nval
);
300 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
305 * SBPRO input multiplexer
308 static int snd_sb8mixer_info_mux(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_info
*uinfo
)
310 static const char * const texts
[3] = {
314 return snd_ctl_enum_info(uinfo
, 1, 3, texts
);
318 static int snd_sb8mixer_get_mux(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
320 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
324 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
325 oval
= snd_sbmixer_read(sb
, SB_DSP_CAPTURE_SOURCE
);
326 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
327 switch ((oval
>> 0x01) & 0x03) {
329 ucontrol
->value
.enumerated
.item
[0] = 1;
331 case SB_DSP_MIXS_LINE
:
332 ucontrol
->value
.enumerated
.item
[0] = 2;
335 ucontrol
->value
.enumerated
.item
[0] = 0;
341 static int snd_sb8mixer_put_mux(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
343 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
346 unsigned char nval
, oval
;
348 if (ucontrol
->value
.enumerated
.item
[0] > 2)
350 switch (ucontrol
->value
.enumerated
.item
[0]) {
352 nval
= SB_DSP_MIXS_CD
;
355 nval
= SB_DSP_MIXS_LINE
;
358 nval
= SB_DSP_MIXS_MIC
;
361 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
362 oval
= snd_sbmixer_read(sb
, SB_DSP_CAPTURE_SOURCE
);
363 nval
|= oval
& ~0x06;
364 change
= nval
!= oval
;
366 snd_sbmixer_write(sb
, SB_DSP_CAPTURE_SOURCE
, nval
);
367 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
375 static int snd_sb16mixer_info_input_sw(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_info
*uinfo
)
377 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_BOOLEAN
;
379 uinfo
->value
.integer
.min
= 0;
380 uinfo
->value
.integer
.max
= 1;
384 static int snd_sb16mixer_get_input_sw(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
386 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
388 int reg1
= kcontrol
->private_value
& 0xff;
389 int reg2
= (kcontrol
->private_value
>> 8) & 0xff;
390 int left_shift
= (kcontrol
->private_value
>> 16) & 0x0f;
391 int right_shift
= (kcontrol
->private_value
>> 24) & 0x0f;
392 unsigned char val1
, val2
;
394 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
395 val1
= snd_sbmixer_read(sb
, reg1
);
396 val2
= snd_sbmixer_read(sb
, reg2
);
397 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
398 ucontrol
->value
.integer
.value
[0] = (val1
>> left_shift
) & 0x01;
399 ucontrol
->value
.integer
.value
[1] = (val2
>> left_shift
) & 0x01;
400 ucontrol
->value
.integer
.value
[2] = (val1
>> right_shift
) & 0x01;
401 ucontrol
->value
.integer
.value
[3] = (val2
>> right_shift
) & 0x01;
405 static int snd_sb16mixer_put_input_sw(struct snd_kcontrol
*kcontrol
, struct snd_ctl_elem_value
*ucontrol
)
407 struct snd_sb
*sb
= snd_kcontrol_chip(kcontrol
);
409 int reg1
= kcontrol
->private_value
& 0xff;
410 int reg2
= (kcontrol
->private_value
>> 8) & 0xff;
411 int left_shift
= (kcontrol
->private_value
>> 16) & 0x0f;
412 int right_shift
= (kcontrol
->private_value
>> 24) & 0x0f;
414 unsigned char val1
, val2
, oval1
, oval2
;
416 spin_lock_irqsave(&sb
->mixer_lock
, flags
);
417 oval1
= snd_sbmixer_read(sb
, reg1
);
418 oval2
= snd_sbmixer_read(sb
, reg2
);
419 val1
= oval1
& ~((1 << left_shift
) | (1 << right_shift
));
420 val2
= oval2
& ~((1 << left_shift
) | (1 << right_shift
));
421 val1
|= (ucontrol
->value
.integer
.value
[0] & 1) << left_shift
;
422 val2
|= (ucontrol
->value
.integer
.value
[1] & 1) << left_shift
;
423 val1
|= (ucontrol
->value
.integer
.value
[2] & 1) << right_shift
;
424 val2
|= (ucontrol
->value
.integer
.value
[3] & 1) << right_shift
;
425 change
= val1
!= oval1
|| val2
!= oval2
;
427 snd_sbmixer_write(sb
, reg1
, val1
);
428 snd_sbmixer_write(sb
, reg2
, val2
);
430 spin_unlock_irqrestore(&sb
->mixer_lock
, flags
);
439 int snd_sbmixer_add_ctl(struct snd_sb
*chip
, const char *name
, int index
, int type
, unsigned long value
)
441 static const struct snd_kcontrol_new newctls
[] = {
443 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
444 .info
= snd_sbmixer_info_single
,
445 .get
= snd_sbmixer_get_single
,
446 .put
= snd_sbmixer_put_single
,
449 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
450 .info
= snd_sbmixer_info_double
,
451 .get
= snd_sbmixer_get_double
,
452 .put
= snd_sbmixer_put_double
,
454 [SB_MIX_INPUT_SW
] = {
455 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
456 .info
= snd_sb16mixer_info_input_sw
,
457 .get
= snd_sb16mixer_get_input_sw
,
458 .put
= snd_sb16mixer_put_input_sw
,
460 [SB_MIX_CAPTURE_PRO
] = {
461 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
462 .info
= snd_sb8mixer_info_mux
,
463 .get
= snd_sb8mixer_get_mux
,
464 .put
= snd_sb8mixer_put_mux
,
466 [SB_MIX_CAPTURE_DT019X
] = {
467 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
468 .info
= snd_dt019x_input_sw_info
,
469 .get
= snd_dt019x_input_sw_get
,
470 .put
= snd_dt019x_input_sw_put
,
472 [SB_MIX_MONO_CAPTURE_ALS4K
] = {
473 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
474 .info
= snd_als4k_mono_capture_route_info
,
475 .get
= snd_als4k_mono_capture_route_get
,
476 .put
= snd_als4k_mono_capture_route_put
,
479 struct snd_kcontrol
*ctl
;
482 ctl
= snd_ctl_new1(&newctls
[type
], chip
);
485 strlcpy(ctl
->id
.name
, name
, sizeof(ctl
->id
.name
));
486 ctl
->id
.index
= index
;
487 ctl
->private_value
= value
;
488 if ((err
= snd_ctl_add(chip
->card
, ctl
)) < 0)
494 * SB 2.0 specific mixer elements
497 static const struct sbmix_elem snd_sb20_controls
[] = {
498 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV
, 1, 7),
499 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV
, 1, 3),
500 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV
, 1, 7),
501 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV
, 1, 7)
504 static const unsigned char snd_sb20_init_values
[][2] = {
505 { SB_DSP20_MASTER_DEV
, 0 },
506 { SB_DSP20_FM_DEV
, 0 },
510 * SB Pro specific mixer elements
512 static const struct sbmix_elem snd_sbpro_controls
[] = {
513 SB_DOUBLE("Master Playback Volume",
514 SB_DSP_MASTER_DEV
, SB_DSP_MASTER_DEV
, 5, 1, 7),
515 SB_DOUBLE("PCM Playback Volume",
516 SB_DSP_PCM_DEV
, SB_DSP_PCM_DEV
, 5, 1, 7),
517 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT
, 5, 1),
518 SB_DOUBLE("Synth Playback Volume",
519 SB_DSP_FM_DEV
, SB_DSP_FM_DEV
, 5, 1, 7),
520 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV
, SB_DSP_CD_DEV
, 5, 1, 7),
521 SB_DOUBLE("Line Playback Volume",
522 SB_DSP_LINE_DEV
, SB_DSP_LINE_DEV
, 5, 1, 7),
523 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV
, 1, 3),
525 .name
= "Capture Source",
526 .type
= SB_MIX_CAPTURE_PRO
528 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT
, 5, 1),
529 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT
, 3, 1)
532 static const unsigned char snd_sbpro_init_values
[][2] = {
533 { SB_DSP_MASTER_DEV
, 0 },
534 { SB_DSP_PCM_DEV
, 0 },
535 { SB_DSP_FM_DEV
, 0 },
539 * SB16 specific mixer elements
541 static const struct sbmix_elem snd_sb16_controls
[] = {
542 SB_DOUBLE("Master Playback Volume",
543 SB_DSP4_MASTER_DEV
, (SB_DSP4_MASTER_DEV
+ 1), 3, 3, 31),
544 SB_DOUBLE("PCM Playback Volume",
545 SB_DSP4_PCM_DEV
, (SB_DSP4_PCM_DEV
+ 1), 3, 3, 31),
546 SB16_INPUT_SW("Synth Capture Route",
547 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
, 6, 5),
548 SB_DOUBLE("Synth Playback Volume",
549 SB_DSP4_SYNTH_DEV
, (SB_DSP4_SYNTH_DEV
+ 1), 3, 3, 31),
550 SB16_INPUT_SW("CD Capture Route",
551 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
, 2, 1),
552 SB_DOUBLE("CD Playback Switch",
553 SB_DSP4_OUTPUT_SW
, SB_DSP4_OUTPUT_SW
, 2, 1, 1),
554 SB_DOUBLE("CD Playback Volume",
555 SB_DSP4_CD_DEV
, (SB_DSP4_CD_DEV
+ 1), 3, 3, 31),
556 SB16_INPUT_SW("Mic Capture Route",
557 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
, 0, 0),
558 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW
, 0, 1),
559 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV
, 3, 31),
560 SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV
, 6, 3),
561 SB_DOUBLE("Capture Volume",
562 SB_DSP4_IGAIN_DEV
, (SB_DSP4_IGAIN_DEV
+ 1), 6, 6, 3),
563 SB_DOUBLE("Playback Volume",
564 SB_DSP4_OGAIN_DEV
, (SB_DSP4_OGAIN_DEV
+ 1), 6, 6, 3),
565 SB16_INPUT_SW("Line Capture Route",
566 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
, 4, 3),
567 SB_DOUBLE("Line Playback Switch",
568 SB_DSP4_OUTPUT_SW
, SB_DSP4_OUTPUT_SW
, 4, 3, 1),
569 SB_DOUBLE("Line Playback Volume",
570 SB_DSP4_LINE_DEV
, (SB_DSP4_LINE_DEV
+ 1), 3, 3, 31),
571 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC
, 0, 1),
572 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE
, 0, 1),
573 SB_DOUBLE("Tone Control - Bass",
574 SB_DSP4_BASS_DEV
, (SB_DSP4_BASS_DEV
+ 1), 4, 4, 15),
575 SB_DOUBLE("Tone Control - Treble",
576 SB_DSP4_TREBLE_DEV
, (SB_DSP4_TREBLE_DEV
+ 1), 4, 4, 15)
579 static const unsigned char snd_sb16_init_values
[][2] = {
580 { SB_DSP4_MASTER_DEV
+ 0, 0 },
581 { SB_DSP4_MASTER_DEV
+ 1, 0 },
582 { SB_DSP4_PCM_DEV
+ 0, 0 },
583 { SB_DSP4_PCM_DEV
+ 1, 0 },
584 { SB_DSP4_SYNTH_DEV
+ 0, 0 },
585 { SB_DSP4_SYNTH_DEV
+ 1, 0 },
586 { SB_DSP4_INPUT_LEFT
, 0 },
587 { SB_DSP4_INPUT_RIGHT
, 0 },
588 { SB_DSP4_OUTPUT_SW
, 0 },
589 { SB_DSP4_SPEAKER_DEV
, 0 },
593 * DT019x specific mixer elements
595 static const struct sbmix_elem snd_dt019x_controls
[] = {
596 /* ALS4000 below has some parts which we might be lacking,
597 * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
598 SB_DOUBLE("Master Playback Volume",
599 SB_DT019X_MASTER_DEV
, SB_DT019X_MASTER_DEV
, 4, 0, 15),
600 SB_DOUBLE("PCM Playback Switch",
601 SB_DT019X_OUTPUT_SW2
, SB_DT019X_OUTPUT_SW2
, 2, 1, 1),
602 SB_DOUBLE("PCM Playback Volume",
603 SB_DT019X_PCM_DEV
, SB_DT019X_PCM_DEV
, 4, 0, 15),
604 SB_DOUBLE("Synth Playback Switch",
605 SB_DT019X_OUTPUT_SW2
, SB_DT019X_OUTPUT_SW2
, 4, 3, 1),
606 SB_DOUBLE("Synth Playback Volume",
607 SB_DT019X_SYNTH_DEV
, SB_DT019X_SYNTH_DEV
, 4, 0, 15),
608 SB_DOUBLE("CD Playback Switch",
609 SB_DSP4_OUTPUT_SW
, SB_DSP4_OUTPUT_SW
, 2, 1, 1),
610 SB_DOUBLE("CD Playback Volume",
611 SB_DT019X_CD_DEV
, SB_DT019X_CD_DEV
, 4, 0, 15),
612 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW
, 0, 1),
613 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV
, 4, 7),
614 SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV
, 0, 7),
615 SB_DOUBLE("Line Playback Switch",
616 SB_DSP4_OUTPUT_SW
, SB_DSP4_OUTPUT_SW
, 4, 3, 1),
617 SB_DOUBLE("Line Playback Volume",
618 SB_DT019X_LINE_DEV
, SB_DT019X_LINE_DEV
, 4, 0, 15),
620 .name
= "Capture Source",
621 .type
= SB_MIX_CAPTURE_DT019X
625 static const unsigned char snd_dt019x_init_values
[][2] = {
626 { SB_DT019X_MASTER_DEV
, 0 },
627 { SB_DT019X_PCM_DEV
, 0 },
628 { SB_DT019X_SYNTH_DEV
, 0 },
629 { SB_DT019X_CD_DEV
, 0 },
630 { SB_DT019X_MIC_DEV
, 0 }, /* Includes PC-speaker in high nibble */
631 { SB_DT019X_LINE_DEV
, 0 },
632 { SB_DSP4_OUTPUT_SW
, 0 },
633 { SB_DT019X_OUTPUT_SW2
, 0 },
634 { SB_DT019X_CAPTURE_SW
, 0x06 },
638 * ALS4000 specific mixer elements
640 static const struct sbmix_elem snd_als4000_controls
[] = {
641 SB_DOUBLE("PCM Playback Switch",
642 SB_DT019X_OUTPUT_SW2
, SB_DT019X_OUTPUT_SW2
, 2, 1, 1),
643 SB_DOUBLE("Synth Playback Switch",
644 SB_DT019X_OUTPUT_SW2
, SB_DT019X_OUTPUT_SW2
, 4, 3, 1),
645 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN
, 0, 0x03),
646 SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL
, 5, 1),
648 .name
= "Master Mono Capture Route",
649 .type
= SB_MIX_MONO_CAPTURE_ALS4K
651 SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2
, 0, 1),
652 SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN
, 7, 0x01),
653 SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX
, 6, 0x01),
654 SB_SINGLE("Digital Loopback Switch",
655 SB_ALS4000_CR3_CONFIGURATION
, 7, 0x01),
656 /* FIXME: functionality of 3D controls might be swapped, I didn't find
657 * a description of how to identify what is supposed to be what */
658 SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX
, 0, 0x07),
659 /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
660 SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX
, 4, 0x03),
661 /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
662 * but what ALSA 3D attribute is that actually? "Center", "Depth",
663 * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
664 SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY
, 0, 0x0f),
665 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY
, 4, 0x01),
666 SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
667 SB_ALS4000_FMDAC
, 5, 0x01),
669 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC
, 0, 0x01),
670 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND
, 1, 0x1f),
674 static const unsigned char snd_als4000_init_values
[][2] = {
675 { SB_DSP4_MASTER_DEV
+ 0, 0 },
676 { SB_DSP4_MASTER_DEV
+ 1, 0 },
677 { SB_DSP4_PCM_DEV
+ 0, 0 },
678 { SB_DSP4_PCM_DEV
+ 1, 0 },
679 { SB_DSP4_SYNTH_DEV
+ 0, 0 },
680 { SB_DSP4_SYNTH_DEV
+ 1, 0 },
681 { SB_DSP4_SPEAKER_DEV
, 0 },
682 { SB_DSP4_OUTPUT_SW
, 0 },
683 { SB_DSP4_INPUT_LEFT
, 0 },
684 { SB_DSP4_INPUT_RIGHT
, 0 },
685 { SB_DT019X_OUTPUT_SW2
, 0 },
686 { SB_ALS4000_MIC_IN_GAIN
, 0 },
691 static int snd_sbmixer_init(struct snd_sb
*chip
,
692 const struct sbmix_elem
*controls
,
694 const unsigned char map
[][2],
699 struct snd_card
*card
= chip
->card
;
703 spin_lock_irqsave(&chip
->mixer_lock
, flags
);
704 snd_sbmixer_write(chip
, 0x00, 0x00);
705 spin_unlock_irqrestore(&chip
->mixer_lock
, flags
);
707 /* mute and zero volume channels */
708 for (idx
= 0; idx
< map_count
; idx
++) {
709 spin_lock_irqsave(&chip
->mixer_lock
, flags
);
710 snd_sbmixer_write(chip
, map
[idx
][0], map
[idx
][1]);
711 spin_unlock_irqrestore(&chip
->mixer_lock
, flags
);
714 for (idx
= 0; idx
< controls_count
; idx
++) {
715 err
= snd_sbmixer_add_ctl_elem(chip
, &controls
[idx
]);
719 snd_component_add(card
, name
);
720 strcpy(card
->mixername
, name
);
724 int snd_sbmixer_new(struct snd_sb
*chip
)
726 struct snd_card
*card
;
729 if (snd_BUG_ON(!chip
|| !chip
->card
))
734 switch (chip
->hardware
) {
736 return 0; /* no mixer chip on SB1.x */
739 if ((err
= snd_sbmixer_init(chip
,
741 ARRAY_SIZE(snd_sb20_controls
),
742 snd_sb20_init_values
,
743 ARRAY_SIZE(snd_sb20_init_values
),
749 if ((err
= snd_sbmixer_init(chip
,
751 ARRAY_SIZE(snd_sbpro_controls
),
752 snd_sbpro_init_values
,
753 ARRAY_SIZE(snd_sbpro_init_values
),
760 if ((err
= snd_sbmixer_init(chip
,
762 ARRAY_SIZE(snd_sb16_controls
),
763 snd_sb16_init_values
,
764 ARRAY_SIZE(snd_sb16_init_values
),
769 /* use only the first 16 controls from SB16 */
770 err
= snd_sbmixer_init(chip
,
773 snd_sb16_init_values
,
774 ARRAY_SIZE(snd_sb16_init_values
),
778 if ((err
= snd_sbmixer_init(chip
,
779 snd_als4000_controls
,
780 ARRAY_SIZE(snd_als4000_controls
),
781 snd_als4000_init_values
,
782 ARRAY_SIZE(snd_als4000_init_values
),
787 err
= snd_sbmixer_init(chip
,
789 ARRAY_SIZE(snd_dt019x_controls
),
790 snd_dt019x_init_values
,
791 ARRAY_SIZE(snd_dt019x_init_values
),
797 strcpy(card
->mixername
, "???");
803 static const unsigned char sb20_saved_regs
[] = {
810 static const unsigned char sbpro_saved_regs
[] = {
813 SB_DSP_PLAYBACK_FILT
,
818 SB_DSP_CAPTURE_SOURCE
,
822 static const unsigned char sb16_saved_regs
[] = {
823 SB_DSP4_MASTER_DEV
, SB_DSP4_MASTER_DEV
+ 1,
825 SB_DSP4_BASS_DEV
, SB_DSP4_BASS_DEV
+ 1,
826 SB_DSP4_TREBLE_DEV
, SB_DSP4_TREBLE_DEV
+ 1,
827 SB_DSP4_PCM_DEV
, SB_DSP4_PCM_DEV
+ 1,
828 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
,
829 SB_DSP4_SYNTH_DEV
, SB_DSP4_SYNTH_DEV
+ 1,
831 SB_DSP4_CD_DEV
, SB_DSP4_CD_DEV
+ 1,
832 SB_DSP4_LINE_DEV
, SB_DSP4_LINE_DEV
+ 1,
835 SB_DSP4_IGAIN_DEV
, SB_DSP4_IGAIN_DEV
+ 1,
836 SB_DSP4_OGAIN_DEV
, SB_DSP4_OGAIN_DEV
+ 1,
840 static const unsigned char dt019x_saved_regs
[] = {
841 SB_DT019X_MASTER_DEV
,
849 SB_DT019X_OUTPUT_SW2
,
850 SB_DT019X_CAPTURE_SW
,
853 static const unsigned char als4000_saved_regs
[] = {
854 /* please verify in dsheet whether regs to be added
855 are actually real H/W or just dummy */
856 SB_DSP4_MASTER_DEV
, SB_DSP4_MASTER_DEV
+ 1,
858 SB_DSP4_PCM_DEV
, SB_DSP4_PCM_DEV
+ 1,
859 SB_DSP4_INPUT_LEFT
, SB_DSP4_INPUT_RIGHT
,
860 SB_DSP4_SYNTH_DEV
, SB_DSP4_SYNTH_DEV
+ 1,
861 SB_DSP4_CD_DEV
, SB_DSP4_CD_DEV
+ 1,
864 SB_DSP4_IGAIN_DEV
, SB_DSP4_IGAIN_DEV
+ 1,
865 SB_DSP4_OGAIN_DEV
, SB_DSP4_OGAIN_DEV
+ 1,
866 SB_DT019X_OUTPUT_SW2
,
867 SB_ALS4000_MONO_IO_CTRL
,
868 SB_ALS4000_MIC_IN_GAIN
,
870 SB_ALS4000_3D_SND_FX
,
871 SB_ALS4000_3D_TIME_DELAY
,
872 SB_ALS4000_CR3_CONFIGURATION
,
875 static void save_mixer(struct snd_sb
*chip
, const unsigned char *regs
, int num_regs
)
877 unsigned char *val
= chip
->saved_regs
;
878 if (snd_BUG_ON(num_regs
> ARRAY_SIZE(chip
->saved_regs
)))
880 for (; num_regs
; num_regs
--)
881 *val
++ = snd_sbmixer_read(chip
, *regs
++);
884 static void restore_mixer(struct snd_sb
*chip
, const unsigned char *regs
, int num_regs
)
886 unsigned char *val
= chip
->saved_regs
;
887 if (snd_BUG_ON(num_regs
> ARRAY_SIZE(chip
->saved_regs
)))
889 for (; num_regs
; num_regs
--)
890 snd_sbmixer_write(chip
, *regs
++, *val
++);
893 void snd_sbmixer_suspend(struct snd_sb
*chip
)
895 switch (chip
->hardware
) {
898 save_mixer(chip
, sb20_saved_regs
, ARRAY_SIZE(sb20_saved_regs
));
902 save_mixer(chip
, sbpro_saved_regs
, ARRAY_SIZE(sbpro_saved_regs
));
907 save_mixer(chip
, sb16_saved_regs
, ARRAY_SIZE(sb16_saved_regs
));
910 save_mixer(chip
, als4000_saved_regs
, ARRAY_SIZE(als4000_saved_regs
));
913 save_mixer(chip
, dt019x_saved_regs
, ARRAY_SIZE(dt019x_saved_regs
));
920 void snd_sbmixer_resume(struct snd_sb
*chip
)
922 switch (chip
->hardware
) {
925 restore_mixer(chip
, sb20_saved_regs
, ARRAY_SIZE(sb20_saved_regs
));
929 restore_mixer(chip
, sbpro_saved_regs
, ARRAY_SIZE(sbpro_saved_regs
));
934 restore_mixer(chip
, sb16_saved_regs
, ARRAY_SIZE(sb16_saved_regs
));
937 restore_mixer(chip
, als4000_saved_regs
, ARRAY_SIZE(als4000_saved_regs
));
940 restore_mixer(chip
, dt019x_saved_regs
, ARRAY_SIZE(dt019x_saved_regs
));