aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-02-27 12:17:28 -0500
committerTakashi Iwai <tiwai@suse.de>2015-03-03 05:28:12 -0500
commit9a6246ff78ac33af78f82704cde6fec361597eea (patch)
treeabb77fd575a77c4fe97ac1d5b3d76682d465935a /sound/pci/hda
parente086e3035e0691b362755d1b5e24df631eee335a (diff)
ALSA: hda - Implement unbind more safely
Now we have all pieces ready, and put them into places: - add the hda_pcm refcount to azx_pcm_open() and azx_pcm_close(), - call the most of cleanup code in hda_codec_reset() from the codec driver remove, - call the same code also from the hda_codec object free. Then the codec driver can be unbound more safely now. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_bind.c3
-rw-r--r--sound/pci/hda/hda_codec.c70
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_controller.c3
-rw-r--r--sound/pci/hda/hda_local.h1
5 files changed, 43 insertions, 35 deletions
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index 2d00417494e2..311896a23cd1 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -125,8 +125,7 @@ static int hda_codec_driver_remove(struct device *dev)
125 125
126 if (codec->patch_ops.free) 126 if (codec->patch_ops.free)
127 codec->patch_ops.free(codec); 127 codec->patch_ops.free(codec);
128 codec->preset = NULL; 128 snd_hda_codec_cleanup_for_unbind(codec);
129 memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
130 module_put(dev->driver->owner); 129 module_put(dev->driver->owner);
131 return 0; 130 return 0;
132} 131}
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 3bd9158addc2..2c7e481a9171 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1160,36 +1160,62 @@ struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
1160} 1160}
1161EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new); 1161EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new);
1162 1162
1163/*
1164 * codec destructor
1165 */
1163static void codec_release_pcms(struct hda_codec *codec) 1166static void codec_release_pcms(struct hda_codec *codec)
1164{ 1167{
1165 struct hda_pcm *pcm, *n; 1168 struct hda_pcm *pcm, *n;
1166 1169
1167 list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) { 1170 list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) {
1168 list_del_init(&pcm->list); 1171 list_del_init(&pcm->list);
1172 if (pcm->pcm)
1173 snd_device_disconnect(codec->card, pcm->pcm);
1169 snd_hda_codec_pcm_put(pcm); 1174 snd_hda_codec_pcm_put(pcm);
1170 } 1175 }
1171} 1176}
1172 1177
1173/* 1178void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
1174 * codec destructor 1179{
1175 */ 1180 cancel_delayed_work_sync(&codec->jackpoll_work);
1181 flush_workqueue(codec->bus->workq);
1182 if (!codec->in_freeing)
1183 snd_hda_ctls_clear(codec);
1184 codec_release_pcms(codec);
1185 snd_hda_detach_beep_device(codec);
1186 memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
1187 snd_hda_jack_tbl_clear(codec);
1188 codec->proc_widget_hook = NULL;
1189 codec->spec = NULL;
1190
1191 free_hda_cache(&codec->amp_cache);
1192 free_hda_cache(&codec->cmd_cache);
1193 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
1194 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
1195
1196 /* free only driver_pins so that init_pins + user_pins are restored */
1197 snd_array_free(&codec->driver_pins);
1198 snd_array_free(&codec->cvt_setups);
1199 snd_array_free(&codec->spdif_out);
1200 snd_array_free(&codec->verbs);
1201 codec->preset = NULL;
1202 codec->slave_dig_outs = NULL;
1203 codec->spdif_status_reset = 0;
1204 snd_array_free(&codec->mixers);
1205 snd_array_free(&codec->nids);
1206 remove_conn_list(codec);
1207}
1208
1176static void snd_hda_codec_free(struct hda_codec *codec) 1209static void snd_hda_codec_free(struct hda_codec *codec)
1177{ 1210{
1178 if (!codec) 1211 if (!codec)
1179 return; 1212 return;
1180 cancel_delayed_work_sync(&codec->jackpoll_work); 1213 codec->in_freeing = 1;
1181 codec_release_pcms(codec);
1182 if (device_is_registered(hda_codec_dev(codec))) 1214 if (device_is_registered(hda_codec_dev(codec)))
1183 device_del(hda_codec_dev(codec)); 1215 device_del(hda_codec_dev(codec));
1184 snd_hda_jack_tbl_clear(codec);
1185 free_init_pincfgs(codec); 1216 free_init_pincfgs(codec);
1186 flush_workqueue(codec->bus->workq); 1217 flush_workqueue(codec->bus->workq);
1187 list_del(&codec->list); 1218 list_del(&codec->list);
1188 snd_array_free(&codec->mixers);
1189 snd_array_free(&codec->nids);
1190 snd_array_free(&codec->cvt_setups);
1191 snd_array_free(&codec->spdif_out);
1192 remove_conn_list(codec);
1193 codec->bus->caddr_tbl[codec->addr] = NULL; 1219 codec->bus->caddr_tbl[codec->addr] = NULL;
1194 clear_bit(codec->addr, &codec->bus->codec_powered); 1220 clear_bit(codec->addr, &codec->bus->codec_powered);
1195 snd_hda_sysfs_clear(codec); 1221 snd_hda_sysfs_clear(codec);
@@ -2479,31 +2505,9 @@ int snd_hda_codec_reset(struct hda_codec *codec)
2479 return -EBUSY; 2505 return -EBUSY;
2480 2506
2481 /* OK, let it free */ 2507 /* OK, let it free */
2482 cancel_delayed_work_sync(&codec->jackpoll_work);
2483 flush_workqueue(bus->workq);
2484 snd_hda_ctls_clear(codec);
2485 codec_release_pcms(codec);
2486 snd_hda_detach_beep_device(codec);
2487 if (device_is_registered(hda_codec_dev(codec))) 2508 if (device_is_registered(hda_codec_dev(codec)))
2488 device_del(hda_codec_dev(codec)); 2509 device_del(hda_codec_dev(codec));
2489 2510
2490 memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
2491 snd_hda_jack_tbl_clear(codec);
2492 codec->proc_widget_hook = NULL;
2493 codec->spec = NULL;
2494 free_hda_cache(&codec->amp_cache);
2495 free_hda_cache(&codec->cmd_cache);
2496 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
2497 init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
2498 /* free only driver_pins so that init_pins + user_pins are restored */
2499 snd_array_free(&codec->driver_pins);
2500 snd_array_free(&codec->cvt_setups);
2501 snd_array_free(&codec->spdif_out);
2502 snd_array_free(&codec->verbs);
2503 codec->preset = NULL;
2504 codec->slave_dig_outs = NULL;
2505 codec->spdif_status_reset = 0;
2506
2507 /* allow device access again */ 2511 /* allow device access again */
2508 snd_hda_unlock_devices(bus); 2512 snd_hda_unlock_devices(bus);
2509 return 0; 2513 return 0;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 2ccd6f9a91fe..fc62ca51fd35 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -350,6 +350,7 @@ struct hda_codec {
350#endif 350#endif
351 351
352 /* misc flags */ 352 /* misc flags */
353 unsigned int in_freeing:1; /* being released */
353 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each 354 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
354 * status change 355 * status change
355 * (e.g. Realtek codecs) 356 * (e.g. Realtek codecs)
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index ad85f9bfaf57..cae50d5ffb81 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -420,6 +420,7 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
420 hinfo->ops.close(hinfo, apcm->codec, substream); 420 hinfo->ops.close(hinfo, apcm->codec, substream);
421 snd_hda_power_down(apcm->codec); 421 snd_hda_power_down(apcm->codec);
422 mutex_unlock(&chip->open_mutex); 422 mutex_unlock(&chip->open_mutex);
423 snd_hda_codec_pcm_put(apcm->info);
423 return 0; 424 return 0;
424} 425}
425 426
@@ -806,6 +807,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
806 int err; 807 int err;
807 int buff_step; 808 int buff_step;
808 809
810 snd_hda_codec_pcm_get(apcm->info);
809 mutex_lock(&chip->open_mutex); 811 mutex_lock(&chip->open_mutex);
810 azx_dev = azx_assign_device(chip, substream); 812 azx_dev = azx_assign_device(chip, substream);
811 if (azx_dev == NULL) { 813 if (azx_dev == NULL) {
@@ -887,6 +889,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
887 snd_hda_power_down(apcm->codec); 889 snd_hda_power_down(apcm->codec);
888 unlock: 890 unlock:
889 mutex_unlock(&chip->open_mutex); 891 mutex_unlock(&chip->open_mutex);
892 snd_hda_codec_pcm_put(apcm->info);
890 return err; 893 return err;
891} 894}
892 895
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 8588813163e3..1d001647fc47 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_cleanup_for_unbind(struct hda_codec *codec);
153 154
154enum { 155enum {
155 HDA_VMUTE_OFF, 156 HDA_VMUTE_OFF,