diff options
author | Michal Nazarewicz <m.nazarewicz@samsung.com> | 2009-10-28 11:57:22 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:19 -0500 |
commit | 9c610213370ad2e58a892f890a11a90615edf020 (patch) | |
tree | c4dc1b738aa33e42916cf26ba5595fac14cbc052 /drivers | |
parent | 606206c271722d613b99c737ce150f58f4485f41 (diff) |
USB: g_mass_storage: fsg_common_init() created
Moved code initialising fsg_common structure to fsg_common_init()
function which is called from fsg_bind(). Moreover, changed
reference counting mechanism: fsg_common has a reference counter
which counts how many fsg_dev structures uses it. When this
reaches zero fsg_common_release() is run which unregisters
LUN devices and frees memory.
fsg_common_init() takes pointer to fsg_common structure as an
argument. If it is NULL function allocates storage otherwise
uses pointed to memory (handy if fsg_common is a field of another
structure or a static variable).
fsg_common_release() will free storage only if
free_storage_on_release is set -- it is initialised by
fsg_common_init(): set if allocation was done, unset
otherwise (one may overwrite it of course).
Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 361 |
1 files changed, 199 insertions, 162 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index b4ec76a3e37..5a0f5708c09 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c | |||
@@ -323,6 +323,8 @@ MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); | |||
323 | 323 | ||
324 | /* Data shared by all the FSG instances. */ | 324 | /* Data shared by all the FSG instances. */ |
325 | struct fsg_common { | 325 | struct fsg_common { |
326 | struct usb_gadget *gadget; | ||
327 | |||
326 | /* filesem protects: backing files in use */ | 328 | /* filesem protects: backing files in use */ |
327 | struct rw_semaphore filesem; | 329 | struct rw_semaphore filesem; |
328 | 330 | ||
@@ -337,6 +339,10 @@ struct fsg_common { | |||
337 | unsigned int lun; | 339 | unsigned int lun; |
338 | struct fsg_lun *luns; | 340 | struct fsg_lun *luns; |
339 | struct fsg_lun *curlun; | 341 | struct fsg_lun *curlun; |
342 | |||
343 | unsigned int free_storage_on_release:1; | ||
344 | |||
345 | struct kref ref; | ||
340 | }; | 346 | }; |
341 | 347 | ||
342 | 348 | ||
@@ -347,9 +353,6 @@ struct fsg_dev { | |||
347 | spinlock_t lock; | 353 | spinlock_t lock; |
348 | struct usb_gadget *gadget; | 354 | struct usb_gadget *gadget; |
349 | 355 | ||
350 | /* reference counting: wait until all LUNs are released */ | ||
351 | struct kref ref; | ||
352 | |||
353 | struct usb_ep *ep0; // Handy copy of gadget->ep0 | 356 | struct usb_ep *ep0; // Handy copy of gadget->ep0 |
354 | struct usb_request *ep0req; // For control responses | 357 | struct usb_request *ep0req; // For control responses |
355 | unsigned int ep0_req_tag; | 358 | unsigned int ep0_req_tag; |
@@ -2757,7 +2760,7 @@ static int fsg_main_thread(void *fsg_) | |||
2757 | } | 2760 | } |
2758 | 2761 | ||
2759 | 2762 | ||
2760 | /*-------------------------------------------------------------------------*/ | 2763 | /*************************** DEVICE ATTRIBUTES ***************************/ |
2761 | 2764 | ||
2762 | 2765 | ||
2763 | /* The write permissions and store_xxx pointers are set in fsg_bind() */ | 2766 | /* The write permissions and store_xxx pointers are set in fsg_bind() */ |
@@ -2765,40 +2768,190 @@ static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); | |||
2765 | static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); | 2768 | static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); |
2766 | 2769 | ||
2767 | 2770 | ||
2768 | /*-------------------------------------------------------------------------*/ | 2771 | /****************************** FSG COMMON ******************************/ |
2772 | |||
2773 | static void fsg_common_release(struct kref *ref); | ||
2769 | 2774 | ||
2770 | static void fsg_release(struct fsg_dev *fsg) | 2775 | static void fsg_lun_release(struct device *dev) |
2771 | { | 2776 | { |
2772 | kfree(fsg->common->luns); | 2777 | /* Nothing needs to be done */ |
2773 | kfree(fsg); | ||
2774 | } | 2778 | } |
2775 | 2779 | ||
2776 | static void lun_release(struct device *dev) | 2780 | static inline void fsg_common_get(struct fsg_common *common) |
2777 | { | 2781 | { |
2782 | kref_get(&common->ref); | ||
2778 | } | 2783 | } |
2779 | 2784 | ||
2785 | static inline void fsg_common_put(struct fsg_common *common) | ||
2786 | { | ||
2787 | kref_put(&common->ref, fsg_common_release); | ||
2788 | } | ||
2789 | |||
2790 | |||
2791 | static struct fsg_common *fsg_common_init(struct fsg_common *common, | ||
2792 | struct usb_gadget *gadget) | ||
2793 | { | ||
2794 | struct fsg_buffhd *bh; | ||
2795 | struct fsg_lun *curlun; | ||
2796 | int nluns, i, rc; | ||
2797 | |||
2798 | /* Find out how many LUNs there should be */ | ||
2799 | nluns = mod_data.nluns; | ||
2800 | if (nluns == 0) | ||
2801 | nluns = max(mod_data.num_filenames, 1u); | ||
2802 | if (nluns < 1 || nluns > FSG_MAX_LUNS) { | ||
2803 | dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); | ||
2804 | return ERR_PTR(-EINVAL); | ||
2805 | } | ||
2806 | |||
2807 | /* Allocate? */ | ||
2808 | if (!common) { | ||
2809 | common = kzalloc(sizeof *common, GFP_KERNEL); | ||
2810 | if (!common) | ||
2811 | return ERR_PTR(-ENOMEM); | ||
2812 | common->free_storage_on_release = 1; | ||
2813 | } else { | ||
2814 | memset(common, 0, sizeof common); | ||
2815 | common->free_storage_on_release = 0; | ||
2816 | } | ||
2817 | common->gadget = gadget; | ||
2818 | |||
2819 | /* Create the LUNs, open their backing files, and register the | ||
2820 | * LUN devices in sysfs. */ | ||
2821 | curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); | ||
2822 | if (!curlun) { | ||
2823 | kfree(common); | ||
2824 | return ERR_PTR(-ENOMEM); | ||
2825 | } | ||
2826 | common->luns = curlun; | ||
2827 | |||
2828 | init_rwsem(&common->filesem); | ||
2829 | |||
2830 | for (i = 0; i < nluns; ++i, ++curlun) { | ||
2831 | curlun->cdrom = !!mod_data.cdrom; | ||
2832 | curlun->ro = mod_data.cdrom || mod_data.ro[i]; | ||
2833 | curlun->removable = mod_data.removable; | ||
2834 | curlun->dev.release = fsg_lun_release; | ||
2835 | curlun->dev.parent = &gadget->dev; | ||
2836 | curlun->dev.driver = &fsg_driver.driver; | ||
2837 | dev_set_drvdata(&curlun->dev, &common->filesem); | ||
2838 | dev_set_name(&curlun->dev,"%s-lun%d", | ||
2839 | dev_name(&gadget->dev), i); | ||
2840 | |||
2841 | rc = device_register(&curlun->dev); | ||
2842 | if (rc) { | ||
2843 | INFO(common, "failed to register LUN%d: %d\n", i, rc); | ||
2844 | common->nluns = i; | ||
2845 | goto error_release; | ||
2846 | } | ||
2847 | |||
2848 | rc = device_create_file(&curlun->dev, &dev_attr_ro); | ||
2849 | if (rc) | ||
2850 | goto error_luns; | ||
2851 | rc = device_create_file(&curlun->dev, &dev_attr_file); | ||
2852 | if (rc) | ||
2853 | goto error_luns; | ||
2854 | |||
2855 | if (mod_data.file[i] && *mod_data.file[i]) { | ||
2856 | rc = fsg_lun_open(curlun, mod_data.file[i]); | ||
2857 | if (rc) | ||
2858 | goto error_luns; | ||
2859 | } else if (!mod_data.removable) { | ||
2860 | ERROR(common, "no file given for LUN%d\n", i); | ||
2861 | rc = -EINVAL; | ||
2862 | goto error_luns; | ||
2863 | } | ||
2864 | } | ||
2865 | common->nluns = nluns; | ||
2866 | |||
2867 | |||
2868 | /* Data buffers cyclic list */ | ||
2869 | /* Buffers in buffhds are static -- no need for additional | ||
2870 | * allocation. */ | ||
2871 | bh = common->buffhds; | ||
2872 | i = FSG_NUM_BUFFERS - 1; | ||
2873 | do { | ||
2874 | bh->next = bh + 1; | ||
2875 | } while (++bh, --i); | ||
2876 | bh->next = common->buffhds; | ||
2877 | |||
2878 | |||
2879 | /* Release */ | ||
2880 | if (mod_data.release == 0xffff) { // Parameter wasn't set | ||
2881 | int gcnum; | ||
2882 | |||
2883 | /* The sa1100 controller is not supported */ | ||
2884 | if (gadget_is_sa1100(gadget)) | ||
2885 | gcnum = -1; | ||
2886 | else | ||
2887 | gcnum = usb_gadget_controller_number(gadget); | ||
2888 | if (gcnum >= 0) | ||
2889 | mod_data.release = 0x0300 + gcnum; | ||
2890 | else { | ||
2891 | WARNING(common, "controller '%s' not recognized\n", | ||
2892 | gadget->name); | ||
2893 | WARNING(common, "controller '%s' not recognized\n", | ||
2894 | gadget->name); | ||
2895 | mod_data.release = 0x0399; | ||
2896 | } | ||
2897 | } | ||
2898 | |||
2899 | |||
2900 | /* Some peripheral controllers are known not to be able to | ||
2901 | * halt bulk endpoints correctly. If one of them is present, | ||
2902 | * disable stalls. | ||
2903 | */ | ||
2904 | if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) | ||
2905 | mod_data.can_stall = 0; | ||
2906 | |||
2907 | |||
2908 | kref_init(&common->ref); | ||
2909 | return common; | ||
2910 | |||
2911 | |||
2912 | error_luns: | ||
2913 | common->nluns = i + 1; | ||
2914 | error_release: | ||
2915 | /* Call fsg_common_release() directly, ref is not initialised */ | ||
2916 | fsg_common_release(&common->ref); | ||
2917 | return ERR_PTR(rc); | ||
2918 | } | ||
2919 | |||
2920 | |||
2921 | static void fsg_common_release(struct kref *ref) | ||
2922 | { | ||
2923 | struct fsg_common *common = | ||
2924 | container_of(ref, struct fsg_common, ref); | ||
2925 | unsigned i = common->nluns; | ||
2926 | struct fsg_lun *lun = common->luns; | ||
2927 | |||
2928 | /* Beware tempting for -> do-while optimization: when in error | ||
2929 | * recovery nluns may be zero. */ | ||
2930 | |||
2931 | for (; i; --i, ++lun) { | ||
2932 | device_remove_file(&lun->dev, &dev_attr_ro); | ||
2933 | device_remove_file(&lun->dev, &dev_attr_file); | ||
2934 | fsg_lun_close(lun); | ||
2935 | device_unregister(&lun->dev); | ||
2936 | } | ||
2937 | |||
2938 | kfree(common->luns); | ||
2939 | if (common->free_storage_on_release) | ||
2940 | kfree(common); | ||
2941 | } | ||
2942 | |||
2943 | |||
2944 | /*-------------------------------------------------------------------------*/ | ||
2945 | |||
2946 | |||
2780 | static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) | 2947 | static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) |
2781 | { | 2948 | { |
2782 | struct fsg_dev *fsg = get_gadget_data(gadget); | 2949 | struct fsg_dev *fsg = get_gadget_data(gadget); |
2783 | int i; | ||
2784 | struct fsg_lun *curlun; | ||
2785 | struct usb_request *req = fsg->ep0req; | 2950 | struct usb_request *req = fsg->ep0req; |
2786 | 2951 | ||
2787 | DBG(fsg, "unbind\n"); | 2952 | DBG(fsg, "unbind\n"); |
2788 | clear_bit(REGISTERED, &fsg->atomic_bitflags); | 2953 | clear_bit(REGISTERED, &fsg->atomic_bitflags); |
2789 | 2954 | ||
2790 | /* Unregister the sysfs attribute files and the LUNs */ | ||
2791 | for (i = 0; i < fsg->common->nluns; ++i) { | ||
2792 | curlun = &fsg->common->luns[i]; | ||
2793 | if (curlun->registered) { | ||
2794 | device_remove_file(&curlun->dev, &dev_attr_ro); | ||
2795 | device_remove_file(&curlun->dev, &dev_attr_file); | ||
2796 | fsg_lun_close(curlun); | ||
2797 | device_unregister(&curlun->dev); | ||
2798 | curlun->registered = 0; | ||
2799 | } | ||
2800 | } | ||
2801 | |||
2802 | /* If the thread isn't already dead, tell it to exit now */ | 2955 | /* If the thread isn't already dead, tell it to exit now */ |
2803 | if (fsg->state != FSG_STATE_TERMINATED) { | 2956 | if (fsg->state != FSG_STATE_TERMINATED) { |
2804 | raise_exception(fsg, FSG_STATE_EXIT); | 2957 | raise_exception(fsg, FSG_STATE_EXIT); |
@@ -2814,43 +2967,15 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) | |||
2814 | usb_ep_free_request(fsg->ep0, req); | 2967 | usb_ep_free_request(fsg->ep0, req); |
2815 | } | 2968 | } |
2816 | 2969 | ||
2970 | fsg_common_put(fsg->common); | ||
2971 | kfree(fsg); | ||
2817 | set_gadget_data(gadget, NULL); | 2972 | set_gadget_data(gadget, NULL); |
2818 | } | 2973 | } |
2819 | 2974 | ||
2820 | 2975 | ||
2821 | static int __init check_parameters(struct fsg_dev *fsg) | ||
2822 | { | ||
2823 | int gcnum; | ||
2824 | |||
2825 | /* Some peripheral controllers are known not to be able to | ||
2826 | * halt bulk endpoints correctly. If one of them is present, | ||
2827 | * disable stalls. | ||
2828 | */ | ||
2829 | if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) | ||
2830 | mod_data.can_stall = 0; | ||
2831 | |||
2832 | if (mod_data.release == 0xffff) { // Parameter wasn't set | ||
2833 | /* The sa1100 controller is not supported */ | ||
2834 | if (gadget_is_sa1100(fsg->gadget)) | ||
2835 | gcnum = -1; | ||
2836 | else | ||
2837 | gcnum = usb_gadget_controller_number(fsg->gadget); | ||
2838 | if (gcnum >= 0) | ||
2839 | mod_data.release = 0x0300 + gcnum; | ||
2840 | else { | ||
2841 | WARNING(fsg, "controller '%s' not recognized\n", | ||
2842 | fsg->gadget->name); | ||
2843 | mod_data.release = 0x0399; | ||
2844 | } | ||
2845 | } | ||
2846 | |||
2847 | return 0; | ||
2848 | } | ||
2849 | |||
2850 | |||
2851 | static int __init fsg_bind(struct usb_gadget *gadget) | 2976 | static int __init fsg_bind(struct usb_gadget *gadget) |
2852 | { | 2977 | { |
2853 | struct fsg_dev *fsg = the_fsg; | 2978 | struct fsg_dev *fsg; |
2854 | int rc; | 2979 | int rc; |
2855 | int i; | 2980 | int i; |
2856 | struct fsg_lun *curlun; | 2981 | struct fsg_lun *curlun; |
@@ -2858,15 +2983,27 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
2858 | struct usb_request *req; | 2983 | struct usb_request *req; |
2859 | char *pathbuf, *p; | 2984 | char *pathbuf, *p; |
2860 | 2985 | ||
2986 | /* Allocate */ | ||
2987 | fsg = kzalloc(sizeof *fsg, GFP_KERNEL); | ||
2988 | if (!fsg) | ||
2989 | return -ENOMEM; | ||
2990 | |||
2991 | /* Initialise common */ | ||
2992 | fsg->common = fsg_common_init(0, gadget); | ||
2993 | if (IS_ERR(fsg->common)) | ||
2994 | return PTR_ERR(fsg->common); | ||
2995 | |||
2996 | /* Basic parameters */ | ||
2861 | fsg->gadget = gadget; | 2997 | fsg->gadget = gadget; |
2862 | set_gadget_data(gadget, fsg); | 2998 | set_gadget_data(gadget, fsg); |
2863 | fsg->ep0 = gadget->ep0; | 2999 | fsg->ep0 = gadget->ep0; |
2864 | fsg->ep0->driver_data = fsg; | 3000 | fsg->ep0->driver_data = fsg; |
2865 | 3001 | ||
2866 | if ((rc = check_parameters(fsg)) != 0) | 3002 | spin_lock_init(&fsg->lock); |
2867 | goto out; | 3003 | init_completion(&fsg->thread_notifier); |
2868 | 3004 | ||
2869 | if (mod_data.removable) { // Enable the store_xxx attributes | 3005 | /* Enable the store_xxx attributes */ |
3006 | if (mod_data.removable) { | ||
2870 | dev_attr_file.attr.mode = 0644; | 3007 | dev_attr_file.attr.mode = 0644; |
2871 | dev_attr_file.store = fsg_store_file; | 3008 | dev_attr_file.store = fsg_store_file; |
2872 | if (!mod_data.cdrom) { | 3009 | if (!mod_data.cdrom) { |
@@ -2875,62 +3012,6 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
2875 | } | 3012 | } |
2876 | } | 3013 | } |
2877 | 3014 | ||
2878 | /* Find out how many LUNs there should be */ | ||
2879 | i = mod_data.nluns; | ||
2880 | if (i == 0) | ||
2881 | i = max(mod_data.num_filenames, 1u); | ||
2882 | if (i > FSG_MAX_LUNS) { | ||
2883 | ERROR(fsg, "invalid number of LUNs: %d\n", i); | ||
2884 | rc = -EINVAL; | ||
2885 | goto out; | ||
2886 | } | ||
2887 | |||
2888 | /* Create the LUNs, open their backing files, and register the | ||
2889 | * LUN devices in sysfs. */ | ||
2890 | fsg->common->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); | ||
2891 | if (!fsg->common->luns) { | ||
2892 | rc = -ENOMEM; | ||
2893 | goto out; | ||
2894 | } | ||
2895 | fsg->common->nluns = i; | ||
2896 | |||
2897 | for (i = 0; i < fsg->common->nluns; ++i) { | ||
2898 | curlun = &fsg->common->luns[i]; | ||
2899 | curlun->cdrom = !!mod_data.cdrom; | ||
2900 | curlun->ro = mod_data.cdrom || mod_data.ro[i]; | ||
2901 | curlun->initially_ro = curlun->ro; | ||
2902 | curlun->removable = mod_data.removable; | ||
2903 | curlun->dev.release = lun_release; | ||
2904 | curlun->dev.parent = &gadget->dev; | ||
2905 | curlun->dev.driver = &fsg_driver.driver; | ||
2906 | dev_set_drvdata(&curlun->dev, &fsg->common->filesem); | ||
2907 | dev_set_name(&curlun->dev,"%s-lun%d", | ||
2908 | dev_name(&gadget->dev), i); | ||
2909 | |||
2910 | if ((rc = device_register(&curlun->dev)) != 0) { | ||
2911 | INFO(fsg, "failed to register LUN%d: %d\n", i, rc); | ||
2912 | goto out; | ||
2913 | } | ||
2914 | if ((rc = device_create_file(&curlun->dev, | ||
2915 | &dev_attr_ro)) != 0 || | ||
2916 | (rc = device_create_file(&curlun->dev, | ||
2917 | &dev_attr_file)) != 0) { | ||
2918 | device_unregister(&curlun->dev); | ||
2919 | goto out; | ||
2920 | } | ||
2921 | curlun->registered = 1; | ||
2922 | |||
2923 | if (mod_data.file[i] && *mod_data.file[i]) { | ||
2924 | if ((rc = fsg_lun_open(curlun, | ||
2925 | mod_data.file[i])) != 0) | ||
2926 | goto out; | ||
2927 | } else if (!mod_data.removable) { | ||
2928 | ERROR(fsg, "no file given for LUN%d\n", i); | ||
2929 | rc = -EINVAL; | ||
2930 | goto out; | ||
2931 | } | ||
2932 | } | ||
2933 | |||
2934 | /* Find all the endpoints we will use */ | 3015 | /* Find all the endpoints we will use */ |
2935 | usb_ep_autoconfig_reset(gadget); | 3016 | usb_ep_autoconfig_reset(gadget); |
2936 | ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); | 3017 | ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); |
@@ -3028,6 +3109,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
3028 | 3109 | ||
3029 | /* Tell the thread to start working */ | 3110 | /* Tell the thread to start working */ |
3030 | wake_up_process(fsg->thread_task); | 3111 | wake_up_process(fsg->thread_task); |
3112 | |||
3113 | the_fsg = fsg; | ||
3031 | return 0; | 3114 | return 0; |
3032 | 3115 | ||
3033 | autoconf_fail: | 3116 | autoconf_fail: |
@@ -3066,64 +3149,18 @@ static struct usb_gadget_driver fsg_driver = { | |||
3066 | }; | 3149 | }; |
3067 | 3150 | ||
3068 | 3151 | ||
3069 | static int __init fsg_alloc(void) | ||
3070 | { | ||
3071 | struct fsg_dev *fsg; | ||
3072 | struct fsg_buffhd *bh; | ||
3073 | unsigned i; | ||
3074 | |||
3075 | fsg = kzalloc(sizeof *fsg, GFP_KERNEL); | ||
3076 | if (!fsg) | ||
3077 | return -ENOMEM; | ||
3078 | |||
3079 | fsg->common = kzalloc(sizeof *fsg->common, GFP_KERNEL); | ||
3080 | if (!fsg->common) { | ||
3081 | kfree(fsg); | ||
3082 | return -ENOMEM; | ||
3083 | } | ||
3084 | |||
3085 | bh = fsg->common->buffhds; | ||
3086 | i = FSG_NUM_BUFFERS - 1; | ||
3087 | do { | ||
3088 | bh->next = bh + 1; | ||
3089 | } while (++bh, --i); | ||
3090 | bh->next = fsg->common->buffhds; | ||
3091 | |||
3092 | spin_lock_init(&fsg->lock); | ||
3093 | init_rwsem(&fsg->common->filesem); | ||
3094 | init_completion(&fsg->thread_notifier); | ||
3095 | |||
3096 | the_fsg = fsg; | ||
3097 | return 0; | ||
3098 | } | ||
3099 | |||
3100 | |||
3101 | static int __init fsg_init(void) | 3152 | static int __init fsg_init(void) |
3102 | { | 3153 | { |
3103 | int rc; | 3154 | return usb_gadget_register_driver(&fsg_driver); |
3104 | struct fsg_dev *fsg; | ||
3105 | |||
3106 | if ((rc = fsg_alloc()) != 0) | ||
3107 | return rc; | ||
3108 | fsg = the_fsg; | ||
3109 | if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) | ||
3110 | fsg_release(fsg); | ||
3111 | return rc; | ||
3112 | } | 3155 | } |
3113 | module_init(fsg_init); | 3156 | module_init(fsg_init); |
3114 | 3157 | ||
3115 | 3158 | ||
3116 | static void __exit fsg_cleanup(void) | 3159 | static void __exit fsg_cleanup(void) |
3117 | { | 3160 | { |
3118 | struct fsg_dev *fsg = the_fsg; | ||
3119 | |||
3120 | /* Unregister the driver iff the thread hasn't already done so */ | 3161 | /* Unregister the driver iff the thread hasn't already done so */ |
3121 | if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) | 3162 | if (the_fsg && |
3163 | test_and_clear_bit(REGISTERED, &the_fsg->atomic_bitflags)) | ||
3122 | usb_gadget_unregister_driver(&fsg_driver); | 3164 | usb_gadget_unregister_driver(&fsg_driver); |
3123 | |||
3124 | /* Wait for the thread to finish up */ | ||
3125 | wait_for_completion(&fsg->thread_notifier); | ||
3126 | |||
3127 | fsg_release(fsg); | ||
3128 | } | 3165 | } |
3129 | module_exit(fsg_cleanup); | 3166 | module_exit(fsg_cleanup); |