diff mbox

[4/5,v4] ASoC: soc-core: call snd_soc_remove_card() when component del

Message ID 87y4o24dyq.wl%kuninori.morimoto.gx@renesas.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kuninori Morimoto Feb. 13, 2015, 4:43 a.m. UTC
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

ASoC devices are organized as CPU-CARD-CODEC. Then, CPU/CODEC
are based on component structure. Now, each CARD device knows
connected components. But CARD doesn't notice if connected component
was removed when user used rmmod or unbind in current implementation.
Thus, CARD which lost some components still exist in system.
And then, ALSA sound card will have some problem if user used this CARD
in such timing. This patch temporarily removes CARD from system
if connected component was removed, and re-add it if some component
was added.

Reported-by: Nguyen Viet Dung <nv-dung@jinso.co.jp>
Reported-by: Bui Duc Phuc <bd-phuc@jinso.co.jp>
Reported-by: Cao Minh Hiep <cm-hiep@jinso.co.jp>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v3 -> v4

 - initialize unbinded_list
 - used mutex_lock in snd_soc_unregister_card()
 - check component->probed in snd_soc_component_del_unlocked()

 include/sound/soc.h  |    1 +
 sound/soc/soc-core.c |   27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

Comments

Mark Brown March 22, 2015, 6:43 p.m. UTC | #1
On Fri, Feb 13, 2015 at 04:43:53AM +0000, Kuninori Morimoto wrote:

> +	struct list_head unbinded_list;

This should be "unbound".  However the whole idea of having this list
seems to be a bit problematic - it's moving us back to the old mechanism
we used to have where we open coded deferred probe.  What would be
better would be if we could force the driver to unbind so we go back to
the state we were in prior to the card being instantiated.  I had a
brief look and it looks like device_release_driver() might be what's
needed but it's unclear to me if this will do exactly what we want and
cause the device to try to rebind.  We probably need to ask Greg unless
there's an obvious answer I'm missing right now.
diff mbox

Patch

diff --git a/include/sound/soc.h b/include/sound/soc.h
index ac8b333..a9272a4 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1084,6 +1084,7 @@  struct snd_soc_card {
 	struct list_head paths;
 	struct list_head dapm_list;
 	struct list_head dapm_dirty;
+	struct list_head unbinded_list;
 
 	/* Generic DAPM context for the card */
 	struct snd_soc_dapm_context dapm;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 5d85b5b..f04e97d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -56,6 +56,7 @@  static DEFINE_MUTEX(client_mutex);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
 static LIST_HEAD(component_list);
+static LIST_HEAD(unbinded_card_list);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -2379,6 +2380,7 @@  int snd_soc_register_card(struct snd_soc_card *card)
 		card->rtd_aux[i].card = card;
 
 	INIT_LIST_HEAD(&card->dapm_dirty);
+	INIT_LIST_HEAD(&card->unbinded_list);
 	card->instantiated = 0;
 	mutex_init(&card->mutex);
 	mutex_init(&card->dapm_mutex);
@@ -2406,6 +2408,10 @@  int snd_soc_unregister_card(struct snd_soc_card *card)
 		dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
 	}
 
+	mutex_lock(&client_mutex);
+	list_del_init(&card->unbinded_list);
+	mutex_unlock(&client_mutex);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
@@ -2669,6 +2675,9 @@  EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
 
 static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 {
+	struct snd_soc_card *card, *_card;
+	int ret;
+
 	if (!component->write && !component->read) {
 		if (!component->regmap)
 			component->regmap = dev_get_regmap(component->dev, NULL);
@@ -2677,6 +2686,16 @@  static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 	}
 
 	list_add(&component->list, &component_list);
+
+	/* re-add temporarily removed card if exist */
+	list_for_each_entry_safe(card, _card, &unbinded_card_list,
+				 unbinded_list) {
+		ret = snd_soc_instantiate_card(card);
+		if (ret < 0)
+			continue;
+
+		list_del_init(&card->unbinded_list);
+	}
 }
 
 static void snd_soc_component_add(struct snd_soc_component *component)
@@ -2694,7 +2713,15 @@  static void snd_soc_component_cleanup(struct snd_soc_component *component)
 
 static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
 {
+	struct snd_soc_card *card = component->card;
+
 	list_del(&component->list);
+
+	/* card is removed temporarily */
+	if (component->probed && card->instantiated) {
+		list_add(&card->unbinded_list, &unbinded_card_list);
+		snd_soc_remove_card(card);
+	}
 }
 
 static void snd_soc_component_del(struct snd_soc_component *component)