diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-04-22 12:26:38 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-04-24 11:27:57 -0400 |
commit | c560a6797e3bec1e04f1f6f9f3c2135db0f5c8ee (patch) | |
tree | 433dd8c4dd8c53ef7ebe4411f6dbdae7b1e9b74d /sound/core/info.c | |
parent | 886364f679342a381c9cb4a0b2588fb103bb6a22 (diff) |
ALSA: core: Remove child proc file elements recursively
This patch changes the way to manage the resource release of proc
files: namely, let snd_info_free_entry() freeing the whole children.
This makes it us possible to drop the snd_device_*() management. Then
snd_card_proc_new() becomes merely a wrapper to
snd_info_create_card_entry().
Together with this change, now you need to call snd_info_free_entry()
for a proc entry created via snd_card_proc_new(), while it was freed
via snd_device_free() beforehand.
Acked-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/info.c')
-rw-r--r-- | sound/core/info.c | 79 |
1 files changed, 13 insertions, 66 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index 9c6db5c24da7..96451a130199 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -760,92 +760,39 @@ EXPORT_SYMBOL(snd_info_create_card_entry); | |||
760 | 760 | ||
761 | static void snd_info_disconnect(struct snd_info_entry *entry) | 761 | static void snd_info_disconnect(struct snd_info_entry *entry) |
762 | { | 762 | { |
763 | struct list_head *p, *n; | 763 | struct snd_info_entry *p, *n; |
764 | 764 | ||
765 | list_for_each_safe(p, n, &entry->children) { | 765 | if (!entry->p) |
766 | snd_info_disconnect(list_entry(p, struct snd_info_entry, list)); | ||
767 | } | ||
768 | |||
769 | if (! entry->p) | ||
770 | return; | 766 | return; |
767 | list_for_each_entry_safe(p, n, &entry->children, list) | ||
768 | snd_info_disconnect(p); | ||
771 | list_del_init(&entry->list); | 769 | list_del_init(&entry->list); |
772 | proc_remove(entry->p); | 770 | proc_remove(entry->p); |
773 | entry->p = NULL; | 771 | entry->p = NULL; |
774 | } | 772 | } |
775 | 773 | ||
776 | static int snd_info_dev_free_entry(struct snd_device *device) | ||
777 | { | ||
778 | struct snd_info_entry *entry = device->device_data; | ||
779 | snd_info_free_entry(entry); | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int snd_info_dev_register_entry(struct snd_device *device) | ||
784 | { | ||
785 | struct snd_info_entry *entry = device->device_data; | ||
786 | return snd_info_register(entry); | ||
787 | } | ||
788 | |||
789 | /** | ||
790 | * snd_card_proc_new - create an info entry for the given card | ||
791 | * @card: the card instance | ||
792 | * @name: the file name | ||
793 | * @entryp: the pointer to store the new info entry | ||
794 | * | ||
795 | * Creates a new info entry and assigns it to the given card. | ||
796 | * Unlike snd_info_create_card_entry(), this function registers the | ||
797 | * info entry as an ALSA device component, so that it can be | ||
798 | * unregistered/released without explicit call. | ||
799 | * Also, you don't have to register this entry via snd_info_register(), | ||
800 | * since this will be registered by snd_card_register() automatically. | ||
801 | * | ||
802 | * The parent is assumed as card->proc_root. | ||
803 | * | ||
804 | * For releasing this entry, use snd_device_free() instead of | ||
805 | * snd_info_free_entry(). | ||
806 | * | ||
807 | * Return: Zero if successful, or a negative error code on failure. | ||
808 | */ | ||
809 | int snd_card_proc_new(struct snd_card *card, const char *name, | ||
810 | struct snd_info_entry **entryp) | ||
811 | { | ||
812 | static struct snd_device_ops ops = { | ||
813 | .dev_free = snd_info_dev_free_entry, | ||
814 | .dev_register = snd_info_dev_register_entry, | ||
815 | /* disconnect is done via snd_info_card_disconnect() */ | ||
816 | }; | ||
817 | struct snd_info_entry *entry; | ||
818 | int err; | ||
819 | |||
820 | entry = snd_info_create_card_entry(card, name, card->proc_root); | ||
821 | if (! entry) | ||
822 | return -ENOMEM; | ||
823 | if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) { | ||
824 | snd_info_free_entry(entry); | ||
825 | return err; | ||
826 | } | ||
827 | if (entryp) | ||
828 | *entryp = entry; | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | EXPORT_SYMBOL(snd_card_proc_new); | ||
833 | |||
834 | /** | 774 | /** |
835 | * snd_info_free_entry - release the info entry | 775 | * snd_info_free_entry - release the info entry |
836 | * @entry: the info entry | 776 | * @entry: the info entry |
837 | * | 777 | * |
838 | * Releases the info entry. Don't call this after registered. | 778 | * Releases the info entry. |
839 | */ | 779 | */ |
840 | void snd_info_free_entry(struct snd_info_entry * entry) | 780 | void snd_info_free_entry(struct snd_info_entry * entry) |
841 | { | 781 | { |
842 | if (entry == NULL) | 782 | struct snd_info_entry *p, *n; |
783 | |||
784 | if (!entry) | ||
843 | return; | 785 | return; |
844 | if (entry->p) { | 786 | if (entry->p) { |
845 | mutex_lock(&info_mutex); | 787 | mutex_lock(&info_mutex); |
846 | snd_info_disconnect(entry); | 788 | snd_info_disconnect(entry); |
847 | mutex_unlock(&info_mutex); | 789 | mutex_unlock(&info_mutex); |
848 | } | 790 | } |
791 | |||
792 | /* free all children at first */ | ||
793 | list_for_each_entry_safe(p, n, &entry->children, list) | ||
794 | snd_info_free_entry(p); | ||
795 | |||
849 | kfree(entry->name); | 796 | kfree(entry->name); |
850 | if (entry->private_free) | 797 | if (entry->private_free) |
851 | entry->private_free(entry); | 798 | entry->private_free(entry); |