ALSA: hda - Manage kcontrol lists
Manage all kcontrol elements created in the hda-intel driver. This makes it possible to remove and reconfigure the controls of each codec. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
f44ac8378d
commit
d13bd412dc
5 changed files with 52 additions and 15 deletions
|
@ -574,6 +574,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
#endif
|
#endif
|
||||||
list_del(&codec->list);
|
list_del(&codec->list);
|
||||||
|
snd_array_free(&codec->mixers);
|
||||||
codec->bus->caddr_tbl[codec->addr] = NULL;
|
codec->bus->caddr_tbl[codec->addr] = NULL;
|
||||||
if (codec->patch_ops.free)
|
if (codec->patch_ops.free)
|
||||||
codec->patch_ops.free(codec);
|
codec->patch_ops.free(codec);
|
||||||
|
@ -622,6 +623,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
|
||||||
mutex_init(&codec->spdif_mutex);
|
mutex_init(&codec->spdif_mutex);
|
||||||
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
|
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
|
||||||
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
|
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
|
||||||
|
snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
|
||||||
|
|
||||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||||
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
|
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
|
||||||
|
@ -1090,6 +1092,32 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
||||||
return _snd_hda_find_mixer_ctl(codec, name, 0);
|
return _snd_hda_find_mixer_ctl(codec, name, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add a control element and assign to the codec */
|
||||||
|
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct snd_kcontrol **knewp;
|
||||||
|
|
||||||
|
err = snd_ctl_add(codec->bus->card, kctl);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
knewp = snd_array_new(&codec->mixers);
|
||||||
|
if (!knewp)
|
||||||
|
return -ENOMEM;
|
||||||
|
*knewp = kctl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear all controls assigned to the given codec */
|
||||||
|
void snd_hda_ctls_clear(struct hda_codec *codec)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct snd_kcontrol **kctls = codec->mixers.list;
|
||||||
|
for (i = 0; i < codec->mixers.used; i++)
|
||||||
|
snd_ctl_remove(codec->bus->card, kctls[i]);
|
||||||
|
snd_array_free(&codec->mixers);
|
||||||
|
}
|
||||||
|
|
||||||
/* create a virtual master control and add slaves */
|
/* create a virtual master control and add slaves */
|
||||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||||
unsigned int *tlv, const char **slaves)
|
unsigned int *tlv, const char **slaves)
|
||||||
|
@ -1107,7 +1135,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||||
kctl = snd_ctl_make_virtual_master(name, tlv);
|
kctl = snd_ctl_make_virtual_master(name, tlv);
|
||||||
if (!kctl)
|
if (!kctl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
err = snd_ctl_add(codec->bus->card, kctl);
|
err = snd_hda_ctl_add(codec, kctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -1571,7 +1599,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
|
||||||
kctl = snd_ctl_new1(dig_mix, codec);
|
kctl = snd_ctl_new1(dig_mix, codec);
|
||||||
kctl->id.index = idx;
|
kctl->id.index = idx;
|
||||||
kctl->private_value = nid;
|
kctl->private_value = nid;
|
||||||
err = snd_ctl_add(codec->bus->card, kctl);
|
err = snd_hda_ctl_add(codec, kctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1615,7 +1643,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
|
||||||
if (!mout->dig_out_nid)
|
if (!mout->dig_out_nid)
|
||||||
return 0;
|
return 0;
|
||||||
/* ATTENTION: here mout is passed as private_data, instead of codec */
|
/* ATTENTION: here mout is passed as private_data, instead of codec */
|
||||||
return snd_ctl_add(codec->bus->card,
|
return snd_hda_ctl_add(codec,
|
||||||
snd_ctl_new1(&spdif_share_sw, mout));
|
snd_ctl_new1(&spdif_share_sw, mout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1717,7 +1745,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
|
||||||
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
|
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
|
||||||
kctl = snd_ctl_new1(dig_mix, codec);
|
kctl = snd_ctl_new1(dig_mix, codec);
|
||||||
kctl->private_value = nid;
|
kctl->private_value = nid;
|
||||||
err = snd_ctl_add(codec->bus->card, kctl);
|
err = snd_hda_ctl_add(codec, kctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2440,7 +2468,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
|
||||||
kctl = snd_ctl_new1(knew, codec);
|
kctl = snd_ctl_new1(knew, codec);
|
||||||
if (!kctl)
|
if (!kctl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
err = snd_ctl_add(codec->bus->card, kctl);
|
err = snd_hda_ctl_add(codec, kctl);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (!codec->addr)
|
if (!codec->addr)
|
||||||
return err;
|
return err;
|
||||||
|
@ -2448,7 +2476,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
|
||||||
if (!kctl)
|
if (!kctl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
kctl->id.device = codec->addr;
|
kctl->id.device = codec->addr;
|
||||||
err = snd_ctl_add(codec->bus->card, kctl);
|
err = snd_hda_ctl_add(codec, kctl);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -740,6 +740,8 @@ struct hda_codec {
|
||||||
hda_nid_t start_nid;
|
hda_nid_t start_nid;
|
||||||
u32 *wcaps;
|
u32 *wcaps;
|
||||||
|
|
||||||
|
struct snd_array mixers; /* list of assigned mixer elements */
|
||||||
|
|
||||||
struct hda_cache_rec amp_cache; /* cache for amp access */
|
struct hda_cache_rec amp_cache; /* cache for amp access */
|
||||||
struct hda_cache_rec cmd_cache; /* cache for other commands */
|
struct hda_cache_rec cmd_cache; /* cache for other commands */
|
||||||
|
|
||||||
|
|
|
@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
|
||||||
if (is_loopback)
|
if (is_loopback)
|
||||||
add_input_loopback(codec, node->nid, HDA_INPUT, index);
|
add_input_loopback(codec, node->nid, HDA_INPUT, index);
|
||||||
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
|
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
|
||||||
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
created = 1;
|
created = 1;
|
||||||
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
|
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
|
||||||
|
@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
|
||||||
if (is_loopback)
|
if (is_loopback)
|
||||||
add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
|
add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
|
||||||
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
|
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
|
||||||
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
created = 1;
|
created = 1;
|
||||||
}
|
}
|
||||||
|
@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
|
||||||
(node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
|
(node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
|
||||||
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
|
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
|
||||||
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
|
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
|
||||||
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
created = 1;
|
created = 1;
|
||||||
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
|
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
|
||||||
(node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
|
(node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
|
||||||
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
|
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
|
||||||
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
|
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
|
||||||
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
|
||||||
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
created = 1;
|
created = 1;
|
||||||
}
|
}
|
||||||
|
@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create input MUX if multiple sources are available */
|
/* create input MUX if multiple sources are available */
|
||||||
if ((err = snd_ctl_add(codec->bus->card,
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
|
||||||
snd_ctl_new1(&cap_sel, codec))) < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* no volume control? */
|
/* no volume control? */
|
||||||
|
@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
|
||||||
HDA_CODEC_VOLUME(name, adc_node->nid,
|
HDA_CODEC_VOLUME(name, adc_node->nid,
|
||||||
spec->input_mux.items[i].index,
|
spec->input_mux.items[i].index,
|
||||||
HDA_INPUT);
|
HDA_INPUT);
|
||||||
if ((err = snd_ctl_add(codec->bus->card,
|
err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
|
||||||
snd_ctl_new1(&knew, codec))) < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,9 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
|
||||||
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||||
unsigned int caps);
|
unsigned int caps);
|
||||||
|
|
||||||
|
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
|
||||||
|
void snd_hda_ctls_clear(struct hda_codec *codec);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hwdep interface
|
* hwdep interface
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1250,7 +1250,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
if (spec->num_dmuxes > 0) {
|
if (spec->num_dmuxes > 0) {
|
||||||
stac_dmux_mixer.count = spec->num_dmuxes;
|
stac_dmux_mixer.count = spec->num_dmuxes;
|
||||||
err = snd_ctl_add(codec->bus->card,
|
err = snd_hda_ctl_add(codec,
|
||||||
snd_ctl_new1(&stac_dmux_mixer, codec));
|
snd_ctl_new1(&stac_dmux_mixer, codec));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Add table
Reference in a new issue