Unverified Commit bd26974f authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/dapm' into asoc-next

parents aa38bff8 c42c5ac4
Loading
Loading
Loading
Loading
+90 −60
Original line number Diff line number Diff line
@@ -2884,7 +2884,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
{
	int i, r, ret = 0;

	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
	for (i = 0; i < num; i++) {
		r = snd_soc_dapm_add_route(dapm, route);
		if (r < 0) {
@@ -2915,7 +2915,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
{
	int i;

	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
	for (i = 0; i < num; i++) {
		snd_soc_dapm_del_route(dapm, route);
		route++;
@@ -3778,18 +3778,27 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
	return 0;
}

int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
static void
snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
			unsigned long *private_value,
			int num_params,
			const char **w_param_text)
{
	int count;

	devm_kfree(card->dev, (void *)*private_value);
	for (count = 0 ; count < num_params; count++)
		devm_kfree(card->dev, (void *)w_param_text[count]);
	devm_kfree(card->dev, w_param_text);
}

static struct snd_kcontrol_new *
snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
			char *link_name,
			const struct snd_soc_pcm_stream *params,
			 unsigned int num_params,
			 struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink)
			int num_params, const char **w_param_text,
			unsigned long *private_value)
{
	struct snd_soc_dapm_widget template;
	struct snd_soc_dapm_widget *w;
	char *link_name;
	int ret, count;
	unsigned long private_value;
	const char **w_param_text;
	struct soc_enum w_param_enum[] = {
		SOC_ENUM_SINGLE(0, 0, 0, NULL),
	};
@@ -3798,19 +3807,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
			     snd_soc_dapm_dai_link_get,
			     snd_soc_dapm_dai_link_put),
	};
	struct snd_kcontrol_new *kcontrol_news;
	const struct snd_soc_pcm_stream *config = params;

	w_param_text = devm_kcalloc(card->dev, num_params,
					sizeof(char *), GFP_KERNEL);
	if (!w_param_text)
		return -ENOMEM;

	link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
				   source->name, sink->name);
	if (!link_name) {
		ret = -ENOMEM;
		goto outfree_w_param;
	}
	int count;

	for (count = 0 ; count < num_params; count++) {
		if (!config->stream_name) {
@@ -3821,57 +3820,94 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
				devm_kasprintf(card->dev, GFP_KERNEL,
					       "Anonymous Configuration %d",
					       count);
			if (!w_param_text[count]) {
				ret = -ENOMEM;
				goto outfree_link_name;
			}
		} else {
			w_param_text[count] = devm_kmemdup(card->dev,
						config->stream_name,
						strlen(config->stream_name) + 1,
						GFP_KERNEL);
			if (!w_param_text[count]) {
				ret = -ENOMEM;
				goto outfree_link_name;
			}
		}
		if (!w_param_text[count])
			goto outfree_w_param;
		config++;
	}

	w_param_enum[0].items = num_params;
	w_param_enum[0].texts = w_param_text;

	memset(&template, 0, sizeof(template));
	template.reg = SND_SOC_NOPM;
	template.id = snd_soc_dapm_dai_link;
	template.name = link_name;
	template.event = snd_soc_dai_link_event;
	template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
		SND_SOC_DAPM_PRE_PMD;
	template.num_kcontrols = 1;
	/* duplicate w_param_enum on heap so that memory persists */
	private_value =
	*private_value =
		(unsigned long) devm_kmemdup(card->dev,
			(void *)(kcontrol_dai_link[0].private_value),
			sizeof(struct soc_enum), GFP_KERNEL);
	if (!private_value) {
	if (!*private_value) {
		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
			link_name);
		ret = -ENOMEM;
		goto outfree_link_name;
		goto outfree_w_param;
	}
	kcontrol_dai_link[0].private_value = private_value;
	kcontrol_dai_link[0].private_value = *private_value;
	/* duplicate kcontrol_dai_link on heap so that memory persists */
	template.kcontrol_news =
				devm_kmemdup(card->dev, &kcontrol_dai_link[0],
	kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
					sizeof(struct snd_kcontrol_new),
					GFP_KERNEL);
	if (!template.kcontrol_news) {
	if (!kcontrol_news) {
		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
			link_name);
		goto outfree_w_param;
	}
	return kcontrol_news;

outfree_w_param:
	snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
	return NULL;
}

int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
			 const struct snd_soc_pcm_stream *params,
			 unsigned int num_params,
			 struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink)
{
	struct snd_soc_dapm_widget template;
	struct snd_soc_dapm_widget *w;
	const char **w_param_text;
	unsigned long private_value;
	char *link_name;
	int ret;

	link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
				   source->name, sink->name);
	if (!link_name)
		return -ENOMEM;

	memset(&template, 0, sizeof(template));
	template.reg = SND_SOC_NOPM;
	template.id = snd_soc_dapm_dai_link;
	template.name = link_name;
	template.event = snd_soc_dai_link_event;
	template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
		SND_SOC_DAPM_PRE_PMD;
	template.kcontrol_news = NULL;

	/* allocate memory for control, only in case of multiple configs */
	if (num_params > 1) {
		w_param_text = devm_kcalloc(card->dev, num_params,
					sizeof(char *), GFP_KERNEL);
		if (!w_param_text) {
			ret = -ENOMEM;
		goto outfree_private_value;
			goto param_fail;
		}

		template.num_kcontrols = 1;
		template.kcontrol_news =
					snd_soc_dapm_alloc_kcontrol(card,
						link_name, params, num_params,
						w_param_text, &private_value);
		if (!template.kcontrol_news) {
			ret = -ENOMEM;
			goto param_fail;
		}
	} else {
		w_param_text = NULL;
	}
	dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);

	w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
@@ -3903,15 +3939,9 @@ outfree_w:
	devm_kfree(card->dev, w);
outfree_kcontrol_news:
	devm_kfree(card->dev, (void *)template.kcontrol_news);
outfree_private_value:
	devm_kfree(card->dev, (void *)private_value);
outfree_link_name:
	snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
param_fail:
	devm_kfree(card->dev, link_name);
outfree_w_param:
	for (count = 0 ; count < num_params; count++)
		devm_kfree(card->dev, (void *)w_param_text[count]);
	devm_kfree(card->dev, w_param_text);

	return ret;
}