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 | |
| 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>
| -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 b4ec76a3e37d..5a0f5708c094 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, " | ||
