Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d13bd412 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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: default avatarTakashi Iwai <tiwai@suse.de>
parent f44ac837
Loading
Loading
Loading
Loading
+34 −6
Original line number Original line Diff line number Diff line
@@ -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;
		}
		}
+2 −0
Original line number Original line Diff line number Diff line
@@ -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 */


+12 −8
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}


+3 −0
Original line number Original line Diff line number Diff line
@@ -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
 */
 */
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;