summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-11-10 21:41:45 (GMT)
committerMark Brown <broonie@kernel.org>2014-11-18 15:26:05 (GMT)
commit70f3af3ca15affaef3d026a5aa6e44c4627ea6c7 (patch)
tree214ed9e55bd37bc22922e44a31a28b71ac0d24f3
parent65c72efd1ea370f0311a5d89754996fff9fc0747 (diff)
downloadlinux-70f3af3ca15affaef3d026a5aa6e44c4627ea6c7.tar.xz
ASoC: Properly handle AC'97 device lifetime management
The memory that a struct device is contained in must not be freed except from within the device's release callback. The ASoC code currently does not adhere to this rule for the AC'97 device. This patch fixes it by moving the freeing of the AC'97 to the release callback and splitting up the registration and unregistration of the device into separate steps for getting/putting the reference to the device and adding/removing it to the device hierarchy. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/soc-core.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4c8f8a2..7084c6f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -504,13 +504,10 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
{
if (codec->ac97->dev.bus)
- device_unregister(&codec->ac97->dev);
+ device_del(&codec->ac97->dev);
return 0;
}
-/* stop no dev release warning */
-static void soc_ac97_device_release(struct device *dev){}
-
/* register ac97 codec to bus */
static int soc_ac97_dev_register(struct snd_soc_codec *codec)
{
@@ -518,12 +515,11 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
codec->ac97->dev.bus = &ac97_bus_type;
codec->ac97->dev.parent = codec->component.card->dev;
- codec->ac97->dev.release = soc_ac97_device_release;
dev_set_name(&codec->ac97->dev, "%d-%d:%s",
codec->component.card->snd_card->number, 0,
codec->component.name);
- err = device_register(&codec->ac97->dev);
+ err = device_add(&codec->ac97->dev);
if (err < 0) {
dev_err(codec->dev, "ASoC: Can't register ac97 bus\n");
codec->ac97->dev.bus = NULL;
@@ -1948,6 +1944,11 @@ static struct platform_driver soc_driver = {
.remove = soc_remove,
};
+static void soc_ac97_device_release(struct device *dev)
+{
+ kfree(to_ac97_t(dev));
+}
+
/**
* snd_soc_new_ac97_codec - initailise AC97 device
* @codec: audio codec
@@ -1972,12 +1973,14 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
codec->ac97->bus->ops = ops;
codec->ac97->num = num;
+ codec->ac97->dev.release = soc_ac97_device_release;
/*
* Mark the AC97 device to be created by us. This way we ensure that the
* device will be registered with the device subsystem later on.
*/
codec->ac97_created = 1;
+ device_initialize(&codec->ac97->dev);
return 0;
}
@@ -2152,7 +2155,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
soc_unregister_ac97_codec(codec);
#endif
kfree(codec->ac97->bus);
- kfree(codec->ac97);
+ codec->ac97->bus = NULL;
+ put_device(&codec->ac97->dev);
codec->ac97 = NULL;
codec->ac97_created = 0;
}