diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-06-23 08:38:23 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:36:58 -0400 |
commit | c461482c8072bb073e6146db320d3da85cdc89ad (patch) | |
tree | 3b69cfd292a488a8cb57ac9b040bd2b1b1a1e26d /sound/core/pcm.c | |
parent | 746d4a02e68499fc6c1f8d0c43d2271853ade181 (diff) |
[ALSA] Unregister device files at disconnection
Orignally proposed by Sam Revitch <sam.revitch@gmail.com>.
Unregister device files at disconnection to avoid the futher accesses.
Also, the dev_unregister callback is removed and replaced with the
combination of disconnect + free.
A new function snd_card_free_when_closed() is introduced, which is
used in USB disconnect callback.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/core/pcm.c')
-rw-r--r-- | sound/core/pcm.c | 48 |
1 files changed, 18 insertions, 30 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index b8602471f7e5..f52178abf120 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm); | |||
42 | static int snd_pcm_dev_free(struct snd_device *device); | 42 | static int snd_pcm_dev_free(struct snd_device *device); |
43 | static int snd_pcm_dev_register(struct snd_device *device); | 43 | static int snd_pcm_dev_register(struct snd_device *device); |
44 | static int snd_pcm_dev_disconnect(struct snd_device *device); | 44 | static int snd_pcm_dev_disconnect(struct snd_device *device); |
45 | static int snd_pcm_dev_unregister(struct snd_device *device); | ||
46 | 45 | ||
47 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) | 46 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) |
48 | { | 47 | { |
@@ -680,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, | |||
680 | .dev_free = snd_pcm_dev_free, | 679 | .dev_free = snd_pcm_dev_free, |
681 | .dev_register = snd_pcm_dev_register, | 680 | .dev_register = snd_pcm_dev_register, |
682 | .dev_disconnect = snd_pcm_dev_disconnect, | 681 | .dev_disconnect = snd_pcm_dev_disconnect, |
683 | .dev_unregister = snd_pcm_dev_unregister | ||
684 | }; | 682 | }; |
685 | 683 | ||
686 | snd_assert(rpcm != NULL, return -EINVAL); | 684 | snd_assert(rpcm != NULL, return -EINVAL); |
@@ -724,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
724 | substream = pstr->substream; | 722 | substream = pstr->substream; |
725 | while (substream) { | 723 | while (substream) { |
726 | substream_next = substream->next; | 724 | substream_next = substream->next; |
725 | snd_pcm_timer_done(substream); | ||
727 | snd_pcm_substream_proc_done(substream); | 726 | snd_pcm_substream_proc_done(substream); |
728 | kfree(substream); | 727 | kfree(substream); |
729 | substream = substream_next; | 728 | substream = substream_next; |
@@ -740,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
740 | 739 | ||
741 | static int snd_pcm_free(struct snd_pcm *pcm) | 740 | static int snd_pcm_free(struct snd_pcm *pcm) |
742 | { | 741 | { |
742 | struct snd_pcm_notify *notify; | ||
743 | |||
743 | snd_assert(pcm != NULL, return -ENXIO); | 744 | snd_assert(pcm != NULL, return -ENXIO); |
745 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | ||
746 | notify->n_unregister(pcm); | ||
747 | } | ||
744 | if (pcm->private_free) | 748 | if (pcm->private_free) |
745 | pcm->private_free(pcm); | 749 | pcm->private_free(pcm); |
746 | snd_pcm_lib_preallocate_free_for_all(pcm); | 750 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -955,35 +959,22 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
955 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 959 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
956 | { | 960 | { |
957 | struct snd_pcm *pcm = device->device_data; | 961 | struct snd_pcm *pcm = device->device_data; |
958 | struct list_head *list; | 962 | struct snd_pcm_notify *notify; |
959 | struct snd_pcm_substream *substream; | 963 | struct snd_pcm_substream *substream; |
960 | int cidx; | 964 | int cidx, devtype; |
961 | 965 | ||
962 | mutex_lock(®ister_mutex); | 966 | mutex_lock(®ister_mutex); |
967 | if (list_empty(&pcm->list)) | ||
968 | goto unlock; | ||
969 | |||
963 | list_del_init(&pcm->list); | 970 | list_del_init(&pcm->list); |
964 | for (cidx = 0; cidx < 2; cidx++) | 971 | for (cidx = 0; cidx < 2; cidx++) |
965 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 972 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
966 | if (substream->runtime) | 973 | if (substream->runtime) |
967 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; | 974 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; |
968 | list_for_each(list, &snd_pcm_notify_list) { | 975 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { |
969 | struct snd_pcm_notify *notify; | ||
970 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
971 | notify->n_disconnect(pcm); | 976 | notify->n_disconnect(pcm); |
972 | } | 977 | } |
973 | mutex_unlock(®ister_mutex); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int snd_pcm_dev_unregister(struct snd_device *device) | ||
978 | { | ||
979 | int cidx, devtype; | ||
980 | struct snd_pcm_substream *substream; | ||
981 | struct list_head *list; | ||
982 | struct snd_pcm *pcm = device->device_data; | ||
983 | |||
984 | snd_assert(pcm != NULL, return -ENXIO); | ||
985 | mutex_lock(®ister_mutex); | ||
986 | list_del(&pcm->list); | ||
987 | for (cidx = 0; cidx < 2; cidx++) { | 978 | for (cidx = 0; cidx < 2; cidx++) { |
988 | devtype = -1; | 979 | devtype = -1; |
989 | switch (cidx) { | 980 | switch (cidx) { |
@@ -995,23 +986,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device) | |||
995 | break; | 986 | break; |
996 | } | 987 | } |
997 | snd_unregister_device(devtype, pcm->card, pcm->device); | 988 | snd_unregister_device(devtype, pcm->card, pcm->device); |
998 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | ||
999 | snd_pcm_timer_done(substream); | ||
1000 | } | ||
1001 | list_for_each(list, &snd_pcm_notify_list) { | ||
1002 | struct snd_pcm_notify *notify; | ||
1003 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
1004 | notify->n_unregister(pcm); | ||
1005 | } | 989 | } |
990 | unlock: | ||
1006 | mutex_unlock(®ister_mutex); | 991 | mutex_unlock(®ister_mutex); |
1007 | return snd_pcm_free(pcm); | 992 | return 0; |
1008 | } | 993 | } |
1009 | 994 | ||
1010 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | 995 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) |
1011 | { | 996 | { |
1012 | struct list_head *p; | 997 | struct list_head *p; |
1013 | 998 | ||
1014 | snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); | 999 | snd_assert(notify != NULL && |
1000 | notify->n_register != NULL && | ||
1001 | notify->n_unregister != NULL && | ||
1002 | notify->n_disconnect, return -EINVAL); | ||
1015 | mutex_lock(®ister_mutex); | 1003 | mutex_lock(®ister_mutex); |
1016 | if (nfree) { | 1004 | if (nfree) { |
1017 | list_del(¬ify->list); | 1005 | list_del(¬ify->list); |