Skip to content

Commit d045bce

Browse files
perexgtiwai
authored andcommitted
ALSA: hda: Fix the control element identification for multiple codecs
Some motherboards have multiple HDA codecs connected to the serial bus. The current code may create multiple mixer controls with the almost identical identification. The current code use id.device field from the control element structure to store the codec address to avoid such clashes for multiple codecs. Unfortunately, the user space do not handle this correctly. For mixer controls, only name and index are used for the identifiers. This patch fixes this problem to compose the index using the codec address as an offset in case, when the control already exists. It is really unlikely that one codec will create 10 similar controls. This patch adds new kernel module parameter 'ctl_dev_id' to allow select the old behaviour, too. The CONFIG_SND_HDA_CTL_DEV_ID Kconfig option sets the default value. BugLink: alsa-project/alsa-lib#294 BugLink: alsa-project/alsa-lib#205 Fixes: 54d1740 ("[ALSA] hda-codec - Fix connection list parsing") Fixes: 1afe206 ("ALSA: hda - Try to find an empty control index when it's occupied") Signed-off-by: Jaroslav Kysela <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 372a0d7 commit d045bce

File tree

6 files changed

+32
-3
lines changed

6 files changed

+32
-3
lines changed

include/sound/hda_codec.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ struct hda_codec {
259259
unsigned int relaxed_resume:1; /* don't resume forcibly for jack */
260260
unsigned int forced_resume:1; /* forced resume for jack */
261261
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
262+
unsigned int ctl_dev_id:1; /* old control element id build behaviour */
262263

263264
#ifdef CONFIG_PM
264265
unsigned long power_on_acct;

sound/pci/hda/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,20 @@ config SND_HDA_INTEL_HDMI_SILENT_STREAM
302302
This feature can impact power consumption as resources
303303
are kept reserved both at transmitter and receiver.
304304

305+
config SND_HDA_CTL_DEV_ID
306+
bool "Use the device identifier field for controls"
307+
depends on SND_HDA_INTEL
308+
help
309+
Say Y to use the device identifier field for (mixer)
310+
controls (old behaviour until this option is available).
311+
312+
When enabled, the multiple HDA codecs may set the device
313+
field in control (mixer) element identifiers. The use
314+
of this field is not recommended and defined for mixer controls.
315+
316+
The old behaviour (Y) is obsolete and will be removed. Consider
317+
to not enable this option.
318+
305319
endif
306320

307321
endmenu

sound/pci/hda/hda_codec.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3389,7 +3389,12 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
33893389
kctl = snd_ctl_new1(knew, codec);
33903390
if (!kctl)
33913391
return -ENOMEM;
3392-
if (addr > 0)
3392+
/* Do not use the id.device field for MIXER elements.
3393+
* This field is for real device numbers (like PCM) but codecs
3394+
* are hidden components from the user space view (unrelated
3395+
* to the mixer element identification).
3396+
*/
3397+
if (addr > 0 && codec->ctl_dev_id)
33933398
kctl->id.device = addr;
33943399
if (idx > 0)
33953400
kctl->id.index = idx;
@@ -3400,9 +3405,11 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
34003405
* the codec addr; if it still fails (or it's the
34013406
* primary codec), then try another control index
34023407
*/
3403-
if (!addr && codec->core.addr)
3408+
if (!addr && codec->core.addr) {
34043409
addr = codec->core.addr;
3405-
else if (!idx && !knew->index) {
3410+
if (!codec->ctl_dev_id)
3411+
idx += 10 * addr;
3412+
} else if (!idx && !knew->index) {
34063413
idx = find_empty_mixer_ctl_idx(codec,
34073414
knew->name, 0);
34083415
if (idx <= 0)

sound/pci/hda/hda_controller.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
12311231
continue;
12321232
codec->jackpoll_interval = chip->jackpoll_interval;
12331233
codec->beep_mode = chip->beep_mode;
1234+
codec->ctl_dev_id = chip->ctl_dev_id;
12341235
codecs++;
12351236
}
12361237
}

sound/pci/hda/hda_controller.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ struct azx {
124124
/* HD codec */
125125
int codec_probe_mask; /* copied from probe_mask option */
126126
unsigned int beep_mode;
127+
bool ctl_dev_id;
127128

128129
#ifdef CONFIG_SND_HDA_PATCH_LOADER
129130
const struct firmware *fw;

sound/pci/hda/hda_intel.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
119119
CONFIG_SND_HDA_INPUT_BEEP_MODE};
120120
#endif
121121
static bool dmic_detect = 1;
122+
static bool ctl_dev_id = IS_ENABLED(CONFIG_SND_HDA_CTL_DEV_ID) ? 1 : 0;
122123

123124
module_param_array(index, int, NULL, 0444);
124125
MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -157,6 +158,8 @@ module_param(dmic_detect, bool, 0444);
157158
MODULE_PARM_DESC(dmic_detect, "Allow DSP driver selection (bypass this driver) "
158159
"(0=off, 1=on) (default=1); "
159160
"deprecated, use snd-intel-dspcfg.dsp_driver option instead");
161+
module_param(ctl_dev_id, bool, 0444);
162+
MODULE_PARM_DESC(ctl_dev_id, "Use control device identifier (based on codec address).");
160163

161164
#ifdef CONFIG_PM
162165
static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -2278,6 +2281,8 @@ static int azx_probe_continue(struct azx *chip)
22782281
chip->beep_mode = beep_mode[dev];
22792282
#endif
22802283

2284+
chip->ctl_dev_id = ctl_dev_id;
2285+
22812286
/* create codec instances */
22822287
if (bus->codec_mask) {
22832288
err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);

0 commit comments

Comments
 (0)