diff options
Diffstat (limited to 'sound/core/init.c')
-rw-r--r-- | sound/core/init.c | 69 |
1 files changed, 54 insertions, 15 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index 1ecb029ff4c9..5850d99d21e3 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -327,22 +327,10 @@ EXPORT_SYMBOL(snd_card_disconnect); | |||
327 | * Returns zero. Frees all associated devices and frees the control | 327 | * Returns zero. Frees all associated devices and frees the control |
328 | * interface associated to given soundcard. | 328 | * interface associated to given soundcard. |
329 | */ | 329 | */ |
330 | int snd_card_free(struct snd_card *card) | 330 | static int snd_card_do_free(struct snd_card *card) |
331 | { | 331 | { |
332 | struct snd_shutdown_f_ops *s_f_ops; | 332 | struct snd_shutdown_f_ops *s_f_ops; |
333 | 333 | ||
334 | if (card == NULL) | ||
335 | return -EINVAL; | ||
336 | mutex_lock(&snd_card_mutex); | ||
337 | snd_cards[card->number] = NULL; | ||
338 | mutex_unlock(&snd_card_mutex); | ||
339 | |||
340 | #ifdef CONFIG_PM | ||
341 | wake_up(&card->power_sleep); | ||
342 | #endif | ||
343 | /* wait, until all devices are ready for the free operation */ | ||
344 | wait_event(card->shutdown_sleep, card->files == NULL); | ||
345 | |||
346 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 334 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
347 | if (snd_mixer_oss_notify_callback) | 335 | if (snd_mixer_oss_notify_callback) |
348 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); | 336 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); |
@@ -371,10 +359,55 @@ int snd_card_free(struct snd_card *card) | |||
371 | card->s_f_ops = s_f_ops->next; | 359 | card->s_f_ops = s_f_ops->next; |
372 | kfree(s_f_ops); | 360 | kfree(s_f_ops); |
373 | } | 361 | } |
362 | kfree(card); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int snd_card_free_prepare(struct snd_card *card) | ||
367 | { | ||
368 | if (card == NULL) | ||
369 | return -EINVAL; | ||
370 | (void) snd_card_disconnect(card); | ||
374 | mutex_lock(&snd_card_mutex); | 371 | mutex_lock(&snd_card_mutex); |
372 | snd_cards[card->number] = NULL; | ||
375 | snd_cards_lock &= ~(1 << card->number); | 373 | snd_cards_lock &= ~(1 << card->number); |
376 | mutex_unlock(&snd_card_mutex); | 374 | mutex_unlock(&snd_card_mutex); |
377 | kfree(card); | 375 | #ifdef CONFIG_PM |
376 | wake_up(&card->power_sleep); | ||
377 | #endif | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | int snd_card_free_when_closed(struct snd_card *card) | ||
382 | { | ||
383 | int free_now = 0; | ||
384 | int ret = snd_card_free_prepare(card); | ||
385 | if (ret) | ||
386 | return ret; | ||
387 | |||
388 | spin_lock(&card->files_lock); | ||
389 | if (card->files == NULL) | ||
390 | free_now = 1; | ||
391 | else | ||
392 | card->free_on_last_close = 1; | ||
393 | spin_unlock(&card->files_lock); | ||
394 | |||
395 | if (free_now) | ||
396 | snd_card_do_free(card); | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | EXPORT_SYMBOL(snd_card_free_when_closed); | ||
401 | |||
402 | int snd_card_free(struct snd_card *card) | ||
403 | { | ||
404 | int ret = snd_card_free_prepare(card); | ||
405 | if (ret) | ||
406 | return ret; | ||
407 | |||
408 | /* wait, until all devices are ready for the free operation */ | ||
409 | wait_event(card->shutdown_sleep, card->files == NULL); | ||
410 | snd_card_do_free(card); | ||
378 | return 0; | 411 | return 0; |
379 | } | 412 | } |
380 | 413 | ||
@@ -718,6 +751,7 @@ EXPORT_SYMBOL(snd_card_file_add); | |||
718 | int snd_card_file_remove(struct snd_card *card, struct file *file) | 751 | int snd_card_file_remove(struct snd_card *card, struct file *file) |
719 | { | 752 | { |
720 | struct snd_monitor_file *mfile, *pfile = NULL; | 753 | struct snd_monitor_file *mfile, *pfile = NULL; |
754 | int last_close = 0; | ||
721 | 755 | ||
722 | spin_lock(&card->files_lock); | 756 | spin_lock(&card->files_lock); |
723 | mfile = card->files; | 757 | mfile = card->files; |
@@ -732,9 +766,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
732 | pfile = mfile; | 766 | pfile = mfile; |
733 | mfile = mfile->next; | 767 | mfile = mfile->next; |
734 | } | 768 | } |
735 | spin_unlock(&card->files_lock); | ||
736 | if (card->files == NULL) | 769 | if (card->files == NULL) |
770 | last_close = 1; | ||
771 | spin_unlock(&card->files_lock); | ||
772 | if (last_close) { | ||
737 | wake_up(&card->shutdown_sleep); | 773 | wake_up(&card->shutdown_sleep); |
774 | if (card->free_on_last_close) | ||
775 | snd_card_do_free(card); | ||
776 | } | ||
738 | if (!mfile) { | 777 | if (!mfile) { |
739 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); | 778 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); |
740 | return -ENOENT; | 779 | return -ENOENT; |