aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-03 11:22:12 -0500
committerTakashi Iwai <tiwai@suse.de>2015-03-23 08:17:48 -0400
commitc4c2533f802d6877803c4d778def43d8a122f27b (patch)
treeba9b5505cc9da460dd278f7eaf6c55e7211a7f03 /sound/pci
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')
-rw-r--r--sound/pci/hda/hda_bind.c1
-rw-r--r--sound/pci/hda/hda_codec.c30
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_local.h1
4 files changed, 25 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index 130f672e6f37..7b269c3237e3 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -95,6 +95,7 @@ static int hda_codec_driver_probe(struct device *dev)
95 err = snd_card_register(codec->card); 95 err = snd_card_register(codec->card);
96 if (err < 0) 96 if (err < 0)
97 goto error_module; 97 goto error_module;
98 snd_hda_codec_register(codec);
98 } 99 }
99 100
100 return 0; 101 return 0;
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)
912 912
913void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) 913void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
914{ 914{
915 if (codec->registered) {
916 /* pm_runtime_put() is called in snd_hdac_device_exit() */
917 pm_runtime_get_noresume(hda_codec_dev(codec));
918 pm_runtime_disable(hda_codec_dev(codec));
919 codec->registered = 0;
920 }
921
915 cancel_delayed_work_sync(&codec->jackpoll_work); 922 cancel_delayed_work_sync(&codec->jackpoll_work);
916 if (!codec->in_freeing) 923 if (!codec->in_freeing)
917 snd_hda_ctls_clear(codec); 924 snd_hda_ctls_clear(codec);
@@ -943,15 +950,23 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
943static unsigned int hda_set_power_state(struct hda_codec *codec, 950static unsigned int hda_set_power_state(struct hda_codec *codec,
944 unsigned int power_state); 951 unsigned int power_state);
945 952
946static int snd_hda_codec_dev_register(struct snd_device *device) 953/* also called from hda_bind.c */
954void snd_hda_codec_register(struct hda_codec *codec)
947{ 955{
948 struct hda_codec *codec = device->device_data; 956 if (codec->registered)
949 957 return;
950 snd_hda_register_beep_device(codec); 958 if (device_is_registered(hda_codec_dev(codec))) {
951 if (device_is_registered(hda_codec_dev(codec))) 959 snd_hda_register_beep_device(codec);
952 pm_runtime_enable(hda_codec_dev(codec)); 960 pm_runtime_enable(hda_codec_dev(codec));
953 /* it was powered up in snd_hda_codec_new(), now all done */ 961 /* it was powered up in snd_hda_codec_new(), now all done */
954 snd_hda_power_down(codec); 962 snd_hda_power_down(codec);
963 codec->registered = 1;
964 }
965}
966
967static int snd_hda_codec_dev_register(struct snd_device *device)
968{
969 snd_hda_codec_register(device->device_data);
955 return 0; 970 return 0;
956} 971}
957 972
@@ -1094,7 +1109,6 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
1094 return 0; 1109 return 0;
1095 1110
1096 error: 1111 error:
1097 pm_runtime_put_noidle(hda_codec_dev(codec));
1098 put_device(hda_codec_dev(codec)); 1112 put_device(hda_codec_dev(codec));
1099 return err; 1113 return err;
1100} 1114}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index e7c47a439762..76776164623d 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -314,6 +314,7 @@ struct hda_codec {
314 314
315 /* misc flags */ 315 /* misc flags */
316 unsigned int in_freeing:1; /* being released */ 316 unsigned int in_freeing:1; /* being released */
317 unsigned int registered:1; /* codec was registered */
317 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each 318 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
318 * status change 319 * status change
319 * (e.g. Realtek codecs) 320 * (e.g. Realtek codecs)
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index e0db30c66e5f..8a83775e0e27 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -150,6 +150,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
150#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \ 150#define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
151 __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL) 151 __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
152int snd_hda_codec_reset(struct hda_codec *codec); 152int snd_hda_codec_reset(struct hda_codec *codec);
153void snd_hda_codec_register(struct hda_codec *codec);
153void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec); 154void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
154 155
155enum { 156enum {