aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/f_mass_storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/f_mass_storage.c')
-rw-r--r--drivers/usb/gadget/f_mass_storage.c138
1 files changed, 104 insertions, 34 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index f4911c09022e..7d05a0be5c60 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -163,6 +163,10 @@
163 * ro setting are not allowed when the medium is loaded or if CD-ROM 163 * ro setting are not allowed when the medium is loaded or if CD-ROM
164 * emulation is being used. 164 * emulation is being used.
165 * 165 *
166 * When a LUN receive an "eject" SCSI request (Start/Stop Unit),
167 * if the LUN is removable, the backing file is released to simulate
168 * ejection.
169 *
166 * 170 *
167 * This function is heavily based on "File-backed Storage Gadget" by 171 * This function is heavily based on "File-backed Storage Gadget" by
168 * Alan Stern which in turn is heavily based on "Gadget Zero" by David 172 * Alan Stern which in turn is heavily based on "Gadget Zero" by David
@@ -302,7 +306,6 @@ static const char fsg_string_interface[] = "Mass Storage";
302 306
303 307
304#define FSG_NO_INTR_EP 1 308#define FSG_NO_INTR_EP 1
305#define FSG_BUFFHD_STATIC_BUFFER 1
306#define FSG_NO_DEVICE_STRINGS 1 309#define FSG_NO_DEVICE_STRINGS 1
307#define FSG_NO_OTG 1 310#define FSG_NO_OTG 1
308#define FSG_NO_INTR_EP 1 311#define FSG_NO_INTR_EP 1
@@ -1385,12 +1388,50 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
1385 1388
1386static int do_start_stop(struct fsg_common *common) 1389static int do_start_stop(struct fsg_common *common)
1387{ 1390{
1388 if (!common->curlun) { 1391 struct fsg_lun *curlun = common->curlun;
1392 int loej, start;
1393
1394 if (!curlun) {
1389 return -EINVAL; 1395 return -EINVAL;
1390 } else if (!common->curlun->removable) { 1396 } else if (!curlun->removable) {
1391 common->curlun->sense_data = SS_INVALID_COMMAND; 1397 curlun->sense_data = SS_INVALID_COMMAND;
1392 return -EINVAL; 1398 return -EINVAL;
1393 } 1399 }
1400
1401 loej = common->cmnd[4] & 0x02;
1402 start = common->cmnd[4] & 0x01;
1403
1404 /* eject code from file_storage.c:do_start_stop() */
1405
1406 if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
1407 (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
1408 curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1409 return -EINVAL;
1410 }
1411
1412 if (!start) {
1413 /* Are we allowed to unload the media? */
1414 if (curlun->prevent_medium_removal) {
1415 LDBG(curlun, "unload attempt prevented\n");
1416 curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
1417 return -EINVAL;
1418 }
1419 if (loej) { /* Simulate an unload/eject */
1420 up_read(&common->filesem);
1421 down_write(&common->filesem);
1422 fsg_lun_close(curlun);
1423 up_write(&common->filesem);
1424 down_read(&common->filesem);
1425 }
1426 } else {
1427
1428 /* Our emulation doesn't support mounting; the medium is
1429 * available for use as soon as it is loaded. */
1430 if (!fsg_lun_is_open(curlun)) {
1431 curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
1432 return -EINVAL;
1433 }
1434 }
1394 return 0; 1435 return 0;
1395} 1436}
1396 1437
@@ -2701,10 +2742,8 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
2701 /* Maybe allocate device-global string IDs, and patch descriptors */ 2742 /* Maybe allocate device-global string IDs, and patch descriptors */
2702 if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { 2743 if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
2703 rc = usb_string_id(cdev); 2744 rc = usb_string_id(cdev);
2704 if (rc < 0) { 2745 if (unlikely(rc < 0))
2705 kfree(common); 2746 goto error_release;
2706 return ERR_PTR(rc);
2707 }
2708 fsg_strings[FSG_STRING_INTERFACE].id = rc; 2747 fsg_strings[FSG_STRING_INTERFACE].id = rc;
2709 fsg_intf_desc.iInterface = rc; 2748 fsg_intf_desc.iInterface = rc;
2710 } 2749 }
@@ -2712,9 +2751,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
2712 /* Create the LUNs, open their backing files, and register the 2751 /* Create the LUNs, open their backing files, and register the
2713 * LUN devices in sysfs. */ 2752 * LUN devices in sysfs. */
2714 curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); 2753 curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
2715 if (!curlun) { 2754 if (unlikely(!curlun)) {
2716 kfree(common); 2755 rc = -ENOMEM;
2717 return ERR_PTR(-ENOMEM); 2756 goto error_release;
2718 } 2757 }
2719 common->luns = curlun; 2758 common->luns = curlun;
2720 2759
@@ -2762,13 +2801,19 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
2762 2801
2763 2802
2764 /* Data buffers cyclic list */ 2803 /* Data buffers cyclic list */
2765 /* Buffers in buffhds are static -- no need for additional
2766 * allocation. */
2767 bh = common->buffhds; 2804 bh = common->buffhds;
2768 i = FSG_NUM_BUFFERS - 1; 2805 i = FSG_NUM_BUFFERS;
2806 goto buffhds_first_it;
2769 do { 2807 do {
2770 bh->next = bh + 1; 2808 bh->next = bh + 1;
2771 } while (++bh, --i); 2809 ++bh;
2810buffhds_first_it:
2811 bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
2812 if (unlikely(!bh->buf)) {
2813 rc = -ENOMEM;
2814 goto error_release;
2815 }
2816 } while (--i);
2772 bh->next = common->buffhds; 2817 bh->next = common->buffhds;
2773 2818
2774 2819
@@ -2867,10 +2912,7 @@ error_release:
2867 2912
2868static void fsg_common_release(struct kref *ref) 2913static void fsg_common_release(struct kref *ref)
2869{ 2914{
2870 struct fsg_common *common = 2915 struct fsg_common *common = container_of(ref, struct fsg_common, ref);
2871 container_of(ref, struct fsg_common, ref);
2872 unsigned i = common->nluns;
2873 struct fsg_lun *lun = common->luns;
2874 2916
2875 /* If the thread isn't already dead, tell it to exit now */ 2917 /* If the thread isn't already dead, tell it to exit now */
2876 if (common->state != FSG_STATE_TERMINATED) { 2918 if (common->state != FSG_STATE_TERMINATED) {
@@ -2881,17 +2923,29 @@ static void fsg_common_release(struct kref *ref)
2881 complete(&common->thread_notifier); 2923 complete(&common->thread_notifier);
2882 } 2924 }
2883 2925
2884 /* Beware tempting for -> do-while optimization: when in error 2926 if (likely(common->luns)) {
2885 * recovery nluns may be zero. */ 2927 struct fsg_lun *lun = common->luns;
2928 unsigned i = common->nluns;
2929
2930 /* In error recovery common->nluns may be zero. */
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 }
2886 2940
2887 for (; i; --i, ++lun) { 2941 {
2888 device_remove_file(&lun->dev, &dev_attr_ro); 2942 struct fsg_buffhd *bh = common->buffhds;
2889 device_remove_file(&lun->dev, &dev_attr_file); 2943 unsigned i = FSG_NUM_BUFFERS;
2890 fsg_lun_close(lun); 2944 do {
2891 device_unregister(&lun->dev); 2945 kfree(bh->buf);
2946 } while (++bh, --i);
2892 } 2947 }
2893 2948
2894 kfree(common->luns);
2895 if (common->free_storage_on_release) 2949 if (common->free_storage_on_release)
2896 kfree(common); 2950 kfree(common);
2897} 2951}
@@ -2906,11 +2960,13 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
2906 2960
2907 DBG(fsg, "unbind\n"); 2961 DBG(fsg, "unbind\n");
2908 fsg_common_put(fsg->common); 2962 fsg_common_put(fsg->common);
2963 usb_free_descriptors(fsg->function.descriptors);
2964 usb_free_descriptors(fsg->function.hs_descriptors);
2909 kfree(fsg); 2965 kfree(fsg);
2910} 2966}
2911 2967
2912 2968
2913static int __init fsg_bind(struct usb_configuration *c, struct usb_function *f) 2969static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
2914{ 2970{
2915 struct fsg_dev *fsg = fsg_from_func(f); 2971 struct fsg_dev *fsg = fsg_from_func(f);
2916 struct usb_gadget *gadget = c->cdev->gadget; 2972 struct usb_gadget *gadget = c->cdev->gadget;
@@ -2946,7 +3002,9 @@ static int __init fsg_bind(struct usb_configuration *c, struct usb_function *f)
2946 fsg_fs_bulk_in_desc.bEndpointAddress; 3002 fsg_fs_bulk_in_desc.bEndpointAddress;
2947 fsg_hs_bulk_out_desc.bEndpointAddress = 3003 fsg_hs_bulk_out_desc.bEndpointAddress =
2948 fsg_fs_bulk_out_desc.bEndpointAddress; 3004 fsg_fs_bulk_out_desc.bEndpointAddress;
2949 f->hs_descriptors = fsg_hs_function; 3005 f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
3006 if (unlikely(!f->hs_descriptors))
3007 return -ENOMEM;
2950 } 3008 }
2951 3009
2952 return 0; 3010 return 0;
@@ -2978,7 +3036,11 @@ static int fsg_add(struct usb_composite_dev *cdev,
2978 3036
2979 fsg->function.name = FSG_DRIVER_DESC; 3037 fsg->function.name = FSG_DRIVER_DESC;
2980 fsg->function.strings = fsg_strings_array; 3038 fsg->function.strings = fsg_strings_array;
2981 fsg->function.descriptors = fsg_fs_function; 3039 fsg->function.descriptors = usb_copy_descriptors(fsg_fs_function);
3040 if (unlikely(!fsg->function.descriptors)) {
3041 rc = -ENOMEM;
3042 goto error_free_fsg;
3043 }
2982 fsg->function.bind = fsg_bind; 3044 fsg->function.bind = fsg_bind;
2983 fsg->function.unbind = fsg_unbind; 3045 fsg->function.unbind = fsg_unbind;
2984 fsg->function.setup = fsg_setup; 3046 fsg->function.setup = fsg_setup;
@@ -2993,11 +3055,19 @@ static int fsg_add(struct usb_composite_dev *cdev,
2993 * call to usb_add_function() was successful. */ 3055 * call to usb_add_function() was successful. */
2994 3056
2995 rc = usb_add_function(c, &fsg->function); 3057 rc = usb_add_function(c, &fsg->function);
3058 if (unlikely(rc))
3059 goto error_free_all;
2996 3060
2997 if (likely(rc == 0)) 3061 fsg_common_get(fsg->common);
2998 fsg_common_get(fsg->common); 3062 return 0;
2999 else 3063
3000 kfree(fsg); 3064error_free_all:
3065 usb_free_descriptors(fsg->function.descriptors);
3066 /* fsg_bind() might have copied those; or maybe not? who cares
3067 * -- free it just in case. */
3068 usb_free_descriptors(fsg->function.hs_descriptors);
3069error_free_fsg:
3070 kfree(fsg);
3001 3071
3002 return rc; 3072 return rc;
3003} 3073}