summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-03 17:22:12 +0100
committerTakashi Iwai <tiwai@suse.de>2015-03-23 13:17:48 +0100
commitc4c2533f802d6877803c4d778def43d8a122f27b (patch)
treeba9b5505cc9da460dd278f7eaf6c55e7211a7f03 /sound/pci/hda/hda_codec.c
parent05852448690d7d810175f8ceccefba083525aa89 (diff)
ALSA: hda - Fix possible runtime PM refcount unbalance
When the driver is unloaded before the codec is bound, it still keeps the runtime PM refcount up, and results in the unbalance. This patch covers these cases by introducing a flag indicating the runtime PM initialization and handling the codec registration procedure more properly. It also fixes the missing input beep device as a gratis, too. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 36483f7dd3ce..145cae7903b6 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -912,6 +912,13 @@ static void codec_release_pcms(struct hda_codec *codec)
void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
{
+ if (codec->registered) {
+ /* pm_runtime_put() is called in snd_hdac_device_exit() */
+ pm_runtime_get_noresume(hda_codec_dev(codec));
+ pm_runtime_disable(hda_codec_dev(codec));
+ codec->registered = 0;
+ }
+
cancel_delayed_work_sync(&codec->jackpoll_work);
if (!codec->in_freeing)
snd_hda_ctls_clear(codec);
@@ -943,15 +950,23 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state);
-static int snd_hda_codec_dev_register(struct snd_device *device)
+/* also called from hda_bind.c */
+void snd_hda_codec_register(struct hda_codec *codec)
{
- struct hda_codec *codec = device->device_data;
-
- snd_hda_register_beep_device(codec);
- if (device_is_registered(hda_codec_dev(codec)))
+ if (codec->registered)
+ return;
+ if (device_is_registered(hda_codec_dev(codec))) {
+ snd_hda_register_beep_device(codec);
pm_runtime_enable(hda_codec_dev(codec));
- /* it was powered up in snd_hda_codec_new(), now all done */
- snd_hda_power_down(codec);
+ /* it was powered up in snd_hda_codec_new(), now all done */
+ snd_hda_power_down(codec);
+ codec->registered = 1;
+ }
+}
+
+static int snd_hda_codec_dev_register(struct snd_device *device)
+{
+ snd_hda_codec_register(device->device_data);
return 0;
}
@@ -1094,7 +1109,6 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
return 0;
error:
- pm_runtime_put_noidle(hda_codec_dev(codec));
put_device(hda_codec_dev(codec));
return err;
}