diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-11-06 15:33:47 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-11-06 15:33:47 -0800 |
| commit | 7106234213fae9f7169ff0f17b8befc30ca03583 (patch) | |
| tree | e765b56267b62c7b78261dc3e39de75d89ef2c49 /usb | |
| parent | f878c4f193b7327244af8f7de8cf8bc61fb78fe1 (diff) | |
| download | patches-7106234213fae9f7169ff0f17b8befc30ca03583.tar.gz | |
lots o patches
Diffstat (limited to 'usb')
16 files changed, 10094 insertions, 0 deletions
diff --git a/usb/usb-add-scatter-gather-support-to-usbmon.patch b/usb/usb-add-scatter-gather-support-to-usbmon.patch new file mode 100644 index 00000000000000..9cfd515c396205 --- /dev/null +++ b/usb/usb-add-scatter-gather-support-to-usbmon.patch @@ -0,0 +1,160 @@ +From stern@rowland.harvard.edu Fri Nov 6 14:55:20 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Fri, 6 Nov 2009 12:32:23 -0500 (EST) +Subject: USB: add scatter-gather support to usbmon +To: Greg KH <greg@kroah.com>, Pete Zaitcev <zaitcev@redhat.com> +Message-ID: <Pine.LNX.4.44L0.0911061229410.2643-100000@iolanthe.rowland.org> + + +This patch (as1301) adds support to usbmon for scatter-gather URBs. +The text interface looks at only the first scatterlist element, since +it never copies more than 32 bytes of data anyway. The binary +interface copies as much data as possible up to the first +non-addressable buffer. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +CC: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/mon/mon_bin.c | 51 +++++++++++++++++++++++++++++++++++++-------- + drivers/usb/mon/mon_text.c | 23 +++++++++++++++++--- + 2 files changed, 62 insertions(+), 12 deletions(-) + +--- a/drivers/usb/mon/mon_bin.c ++++ b/drivers/usb/mon/mon_bin.c +@@ -16,6 +16,7 @@ + #include <linux/compat.h> + #include <linux/mm.h> + #include <linux/smp_lock.h> ++#include <linux/scatterlist.h> + + #include <asm/uaccess.h> + +@@ -221,7 +222,7 @@ static void mon_free_buff(struct mon_pgm + /* + * This is a "chunked memcpy". It does not manipulate any counters. + */ +-static void mon_copy_to_buff(const struct mon_reader_bin *this, ++static unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, + unsigned int off, const unsigned char *from, unsigned int length) + { + unsigned int step_len; +@@ -246,6 +247,7 @@ static void mon_copy_to_buff(const struc + from += step_len; + length -= step_len; + } ++ return off; + } + + /* +@@ -394,14 +396,44 @@ static inline char mon_bin_get_setup(uns + return 0; + } + +-static char mon_bin_get_data(const struct mon_reader_bin *rp, +- unsigned int offset, struct urb *urb, unsigned int length) ++static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp, ++ unsigned int offset, struct urb *urb, unsigned int length, ++ char *flag) + { ++ int i; ++ struct scatterlist *sg; ++ unsigned int this_len; + +- if (urb->transfer_buffer == NULL) +- return 'Z'; +- mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); +- return 0; ++ *flag = 0; ++ if (urb->num_sgs == 0) { ++ if (urb->transfer_buffer == NULL) { ++ *flag = 'Z'; ++ return length; ++ } ++ mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); ++ length = 0; ++ ++ } else { ++ /* If IOMMU coalescing occurred, we cannot trust sg_page */ ++ if (urb->sg->nents != urb->num_sgs) { ++ *flag = 'D'; ++ return length; ++ } ++ ++ /* Copy up to the first non-addressable segment */ ++ for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) { ++ if (length == 0 || PageHighMem(sg_page(sg))) ++ break; ++ this_len = min_t(unsigned int, sg->length, length); ++ offset = mon_copy_to_buff(rp, offset, sg_virt(sg), ++ this_len); ++ length -= this_len; ++ } ++ if (i == 0) ++ *flag = 'D'; ++ } ++ ++ return length; + } + + static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, +@@ -536,8 +568,9 @@ static void mon_bin_event(struct mon_rea + } + + if (length != 0) { +- ep->flag_data = mon_bin_get_data(rp, offset, urb, length); +- if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ ++ length = mon_bin_get_data(rp, offset, urb, length, ++ &ep->flag_data); ++ if (length > 0) { + delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + ep->len_cap -= length; + delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); +--- a/drivers/usb/mon/mon_text.c ++++ b/drivers/usb/mon/mon_text.c +@@ -10,6 +10,7 @@ + #include <linux/time.h> + #include <linux/mutex.h> + #include <linux/debugfs.h> ++#include <linux/scatterlist.h> + #include <asm/uaccess.h> + + #include "usb_mon.h" +@@ -137,6 +138,8 @@ static inline char mon_text_get_setup(st + static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, + int len, char ev_type, struct mon_bus *mbus) + { ++ void *src; ++ + if (len <= 0) + return 'L'; + if (len >= DATA_MAX) +@@ -150,10 +153,24 @@ static inline char mon_text_get_data(str + return '>'; + } + +- if (urb->transfer_buffer == NULL) +- return 'Z'; /* '0' would be not as pretty. */ ++ if (urb->num_sgs == 0) { ++ src = urb->transfer_buffer; ++ if (src == NULL) ++ return 'Z'; /* '0' would be not as pretty. */ ++ } else { ++ struct scatterlist *sg = urb->sg->sg; ++ ++ /* If IOMMU coalescing occurred, we cannot trust sg_page */ ++ if (urb->sg->nents != urb->num_sgs || ++ PageHighMem(sg_page(sg))) ++ return 'D'; ++ ++ /* For the text interface we copy only the first sg buffer */ ++ len = min_t(int, sg->length, len); ++ src = sg_virt(sg); ++ } + +- memcpy(ep->data, urb->transfer_buffer, len); ++ memcpy(ep->data, src, len); + return 0; + } + diff --git a/usb/usb-check-results-of-dma_map_single.patch b/usb/usb-check-results-of-dma_map_single.patch new file mode 100644 index 00000000000000..62cca59b85e755 --- /dev/null +++ b/usb/usb-check-results-of-dma_map_single.patch @@ -0,0 +1,65 @@ +From Larry.Finger@lwfinger.net Fri Nov 6 14:59:45 2009 +From: Larry Finger <Larry.Finger@lwfinger.net> +Date: Thu, 05 Nov 2009 10:37:03 -0600 +Subject: USB: Check results of dma_map_single +To: Greg Kroah-Hartman <gregkh@suse.de> +Message-ID: <4af2ff2f.kX7PBMN9YqPE1zMk%Larry.Finger@lwfinger.net> + +In map_urb_for_dma(), the DMA address returned by dma_map_single() +is not checked to determine if it is legal. This lack of checking +contributed to a problem with the libertas wireless driver +(http://marc.info/?l=linux-wireless&m=125695331205062&w=2). The +difficulty was not detected until the buffer was unmapped. By this time +memory corruption had occurred. + +The situation is fixed by testing the returned DMA address, and +returning -EAGAIN if the address is invalid. + +Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> +Cc: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/hcd.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -1275,13 +1275,16 @@ static int map_urb_for_dma(struct usb_hc + + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { +- if (hcd->self.uses_dma) ++ if (hcd->self.uses_dma) { + urb->setup_dma = dma_map_single( + hcd->self.controller, + urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); +- else if (hcd->driver->flags & HCD_LOCAL_MEM) ++ if (dma_mapping_error(hcd->self.controller, ++ urb->setup_dma)) ++ return -EAGAIN; ++ } else if (hcd->driver->flags & HCD_LOCAL_MEM) + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->setup_dma, +@@ -1293,13 +1296,16 @@ static int map_urb_for_dma(struct usb_hc + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (ret == 0 && urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { +- if (hcd->self.uses_dma) ++ if (hcd->self.uses_dma) { + urb->transfer_dma = dma_map_single ( + hcd->self.controller, + urb->transfer_buffer, + urb->transfer_buffer_length, + dir); +- else if (hcd->driver->flags & HCD_LOCAL_MEM) { ++ if (dma_mapping_error(hcd->self.controller, ++ urb->transfer_dma)) ++ return -EAGAIN; ++ } else if (hcd->driver->flags & HCD_LOCAL_MEM) { + ret = hcd_alloc_coherent( + urb->dev->bus, mem_flags, + &urb->transfer_dma, diff --git a/usb/usb-ehci-add-native-scatter-gather-support.patch b/usb/usb-ehci-add-native-scatter-gather-support.patch new file mode 100644 index 00000000000000..a6b43e0821991b --- /dev/null +++ b/usb/usb-ehci-add-native-scatter-gather-support.patch @@ -0,0 +1,93 @@ +From stern@rowland.harvard.edu Fri Nov 6 14:54:48 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Fri, 6 Nov 2009 12:29:40 -0500 (EST) +Subject: USB: EHCI: add native scatter-gather support +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0911061226530.2643-100000@iolanthe.rowland.org> + + +This patch (as1300) adds native scatter-gather support to ehci-hcd. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ehci-hcd.c | 2 ++ + drivers/usb/host/ehci-q.c | 32 +++++++++++++++++++++++++++----- + 2 files changed, 29 insertions(+), 5 deletions(-) + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -604,6 +604,8 @@ static int ehci_init(struct usb_hcd *hcd + } + ehci->command = temp; + ++ /* Accept arbitrarily long scatter-gather lists */ ++ hcd->self.sg_tablesize = ~0; + return 0; + } + +--- a/drivers/usb/host/ehci-q.c ++++ b/drivers/usb/host/ehci-q.c +@@ -604,9 +604,11 @@ qh_urb_transaction ( + ) { + struct ehci_qtd *qtd, *qtd_prev; + dma_addr_t buf; +- int len, maxpacket; ++ int len, this_sg_len, maxpacket; + int is_input; + u32 token; ++ int i; ++ struct scatterlist *sg; + + /* + * URBs map to sequences of QTDs: one logical transaction +@@ -647,7 +649,20 @@ qh_urb_transaction ( + /* + * data transfer stage: buffer setup + */ +- buf = urb->transfer_dma; ++ i = urb->num_sgs; ++ if (len > 0 && i > 0) { ++ sg = urb->sg->sg; ++ buf = sg_dma_address(sg); ++ ++ /* urb->transfer_buffer_length may be smaller than the ++ * size of the scatterlist (or vice versa) ++ */ ++ this_sg_len = min_t(int, sg_dma_len(sg), len); ++ } else { ++ sg = NULL; ++ buf = urb->transfer_dma; ++ this_sg_len = len; ++ } + + if (is_input) + token |= (1 /* "in" */ << 8); +@@ -663,7 +678,9 @@ qh_urb_transaction ( + for (;;) { + int this_qtd_len; + +- this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket); ++ this_qtd_len = qtd_fill(ehci, qtd, buf, this_sg_len, token, ++ maxpacket); ++ this_sg_len -= this_qtd_len; + len -= this_qtd_len; + buf += this_qtd_len; + +@@ -679,8 +696,13 @@ qh_urb_transaction ( + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + +- if (likely (len <= 0)) +- break; ++ if (likely(this_sg_len <= 0)) { ++ if (--i <= 0 || len <= 0) ++ break; ++ sg = sg_next(sg); ++ buf = sg_dma_address(sg); ++ this_sg_len = min_t(int, sg_dma_len(sg), len); ++ } + + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); diff --git a/usb/usb-ehci-allow-ehci-to-be-built-on-omap3.patch b/usb/usb-ehci-allow-ehci-to-be-built-on-omap3.patch new file mode 100644 index 00000000000000..5cf8478a159628 --- /dev/null +++ b/usb/usb-ehci-allow-ehci-to-be-built-on-omap3.patch @@ -0,0 +1,36 @@ +From gadiyar@ti.com Fri Nov 6 14:56:05 2009 +From: Anand Gadiyar <gadiyar@ti.com> +Date: Sat, 7 Nov 2009 01:16:32 +0530 +Subject: USB: ehci: Allow EHCI to be built on OMAP3 +Cc: Anand Gadiyar <gadiyar@ti.com>, Vikram Pandita <vikram.pandita@ti.com>, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1257536793-15291-1-git-send-email-gadiyar@ti.com> + + +usb: ehci: Allow EHCI to be built on OMAP3 + +OMAP3 chips have a built-in EHCI controller. +The recently introduced omap ehci-hcd driver missed +out on selecting USB_ARCH_HAS_EHCI in Kconfig. + +Without this, the driver cannot be built. + +Signed-off-by: Anand Gadiyar <gadiyar@ti.com> +Cc: Vikram Pandita <vikram.pandita@ti.com> +Cc: Ajay Kumar Gupta <ajay.gupta@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -61,6 +61,7 @@ config USB_ARCH_HAS_EHCI + default y if ARCH_W90X900 + default y if ARCH_AT91SAM9G45 + default y if ARCH_MXC ++ default y if ARCH_OMAP34XX + default PCI + + # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff --git a/usb/usb-g_file_storage-fsg_-prefix-added-to-some-identifiers.patch b/usb/usb-g_file_storage-fsg_-prefix-added-to-some-identifiers.patch new file mode 100644 index 00000000000000..3addf42dc1012b --- /dev/null +++ b/usb/usb-g_file_storage-fsg_-prefix-added-to-some-identifiers.patch @@ -0,0 +1,1027 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:41:26 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:15 +0100 +Subject: USB: g_file_storage: "fsg_" prefix added to some identifiers +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <0fe0bf82c16b935b856cf9f51d60cee853d92230.1256745228.git.m.nazarewicz@samsung.com> + + +Prefixed some identifiers that were defined in storage_common.c file +with "fsg_". Not all identifiers were prefixed but the ones that are +most likely to produce conflicts when used with other USB functions. + +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> + +--- + drivers/usb/gadget/file_storage.c | 203 ++++++++++++++++++------------------ + drivers/usb/gadget/storage_common.c | 132 ++++++++++++++--------- + 2 files changed, 183 insertions(+), 152 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -248,8 +248,6 @@ + #include <linux/freezer.h> + #include <linux/utsname.h> + +-#include <asm/unaligned.h> +- + #include <linux/usb/ch9.h> + #include <linux/usb/gadget.h> + +@@ -274,8 +272,11 @@ + #define DRIVER_NAME "g_file_storage" + #define DRIVER_VERSION "20 November 2008" + +-static const char longname[] = DRIVER_DESC; +-static const char shortname[] = DRIVER_NAME; ++static char fsg_string_manufacturer[64]; ++static const char fsg_string_product[] = DRIVER_DESC; ++static char fsg_string_serial[13]; ++static const char fsg_string_config[] = "Self-powered"; ++static const char fsg_string_interface[] = "Mass Storage"; + + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_AUTHOR("Alan Stern"); +@@ -285,8 +286,8 @@ MODULE_LICENSE("Dual BSD/GPL"); + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. */ +-#define DRIVER_VENDOR_ID 0x0525 // NetChip +-#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget ++#define FSG_VENDOR_ID 0x0525 // NetChip ++#define FSG_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget + + + /* +@@ -301,11 +302,11 @@ MODULE_LICENSE("Dual BSD/GPL"); + + /* Encapsulate the module parameter settings */ + +-#define MAX_LUNS 8 ++#define FSG_MAX_LUNS 8 + + static struct { +- char *file[MAX_LUNS]; +- int ro[MAX_LUNS]; ++ char *file[FSG_MAX_LUNS]; ++ int ro[FSG_MAX_LUNS]; + unsigned int num_filenames; + unsigned int num_ros; + unsigned int nluns; +@@ -332,8 +333,8 @@ static struct { + .removable = 0, + .can_stall = 1, + .cdrom = 0, +- .vendor = DRIVER_VENDOR_ID, +- .product = DRIVER_PRODUCT_ID, ++ .vendor = FSG_VENDOR_ID, ++ .product = FSG_PRODUCT_ID, + .release = 0xffff, // Use controller chip type + .buflen = 16384, + }; +@@ -434,7 +435,7 @@ struct fsg_dev { + int intreq_busy; + struct fsg_buffhd *intr_buffhd; + +- unsigned int bulk_out_maxpacket; ++ unsigned int bulk_out_maxpacket; + enum fsg_state state; // For exception handling + unsigned int exception_req_tag; + +@@ -459,7 +460,7 @@ struct fsg_dev { + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; +- struct fsg_buffhd buffhds[NUM_BUFFERS]; ++ struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; + + int thread_wakeup_needed; + struct completion thread_notifier; +@@ -484,8 +485,8 @@ struct fsg_dev { + u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; + + unsigned int nluns; +- struct lun *luns; +- struct lun *curlun; ++ struct fsg_lun *luns; ++ struct fsg_lun *curlun; + }; + + typedef void (*fsg_routine_t)(struct fsg_dev *); +@@ -549,13 +550,13 @@ device_desc = { + .bDeviceClass = USB_CLASS_PER_INTERFACE, + + /* The next three values can be overridden by module parameters */ +- .idVendor = cpu_to_le16(DRIVER_VENDOR_ID), +- .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID), ++ .idVendor = cpu_to_le16(FSG_VENDOR_ID), ++ .idProduct = cpu_to_le16(FSG_PRODUCT_ID), + .bcdDevice = cpu_to_le16(0xffff), + +- .iManufacturer = STRING_MANUFACTURER, +- .iProduct = STRING_PRODUCT, +- .iSerialNumber = STRING_SERIAL, ++ .iManufacturer = FSG_STRING_MANUFACTURER, ++ .iProduct = FSG_STRING_PRODUCT, ++ .iSerialNumber = FSG_STRING_SERIAL, + .bNumConfigurations = 1, + }; + +@@ -567,7 +568,7 @@ config_desc = { + /* wTotalLength computed by usb_gadget_config_buf() */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_VALUE, +- .iConfiguration = STRING_CONFIG, ++ .iConfiguration = FSG_STRING_CONFIG, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, + }; +@@ -604,9 +605,9 @@ static int populate_config_buf(struct us + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) +- function = hs_function; ++ function = fsg_hs_function; + else +- function = fs_function; ++ function = fsg_fs_function; + + /* for now, don't advertise srp-only devices */ + if (!gadget_is_otg(gadget)) +@@ -957,7 +958,7 @@ get_config: + VDBG(fsg, "get string descriptor\n"); + + /* wIndex == language code */ +- value = usb_gadget_get_string(&stringtab, ++ value = usb_gadget_get_string(&fsg_stringtab, + w_value & 0xff, req->buf); + break; + } +@@ -1122,7 +1123,7 @@ static int sleep_thread(struct fsg_dev * + + static int do_read(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; +@@ -1248,7 +1249,7 @@ static int do_read(struct fsg_dev *fsg) + + static int do_write(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; +@@ -1437,12 +1438,12 @@ static int do_write(struct fsg_dev *fsg) + + static int do_synchronize_cache(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int rc; + + /* We ignore the requested LBA and write out all file's + * dirty data buffers. */ +- rc = fsync_sub(curlun); ++ rc = fsg_lun_fsync_sub(curlun); + if (rc) + curlun->sense_data = SS_WRITE_ERROR; + return 0; +@@ -1451,7 +1452,7 @@ static int do_synchronize_cache(struct f + + /*-------------------------------------------------------------------------*/ + +-static void invalidate_sub(struct lun *curlun) ++static void invalidate_sub(struct fsg_lun *curlun) + { + struct file *filp = curlun->filp; + struct inode *inode = filp->f_path.dentry->d_inode; +@@ -1463,7 +1464,7 @@ static void invalidate_sub(struct lun *c + + static int do_verify(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u32 lba; + u32 verification_length; + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; +@@ -1496,7 +1497,7 @@ static int do_verify(struct fsg_dev *fsg + file_offset = ((loff_t) lba) << 9; + + /* Write out all the dirty buffers before invalidating them */ +- fsync_sub(curlun); ++ fsg_lun_fsync_sub(curlun); + if (signal_pending(current)) + return -EINTR; + +@@ -1593,7 +1594,7 @@ static int do_inquiry(struct fsg_dev *fs + + static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + int valid; +@@ -1647,7 +1648,7 @@ static int do_request_sense(struct fsg_d + + static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u32 lba = get_unaligned_be32(&fsg->cmnd[2]); + int pmi = fsg->cmnd[8]; + u8 *buf = (u8 *) bh->buf; +@@ -1667,7 +1668,7 @@ static int do_read_capacity(struct fsg_d + + static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + u32 lba = get_unaligned_be32(&fsg->cmnd[2]); + u8 *buf = (u8 *) bh->buf; +@@ -1690,7 +1691,7 @@ static int do_read_header(struct fsg_dev + + static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + int start_track = fsg->cmnd[6]; + u8 *buf = (u8 *) bh->buf; +@@ -1718,7 +1719,7 @@ static int do_read_toc(struct fsg_dev *f + + static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int mscmnd = fsg->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; +@@ -1799,7 +1800,7 @@ static int do_mode_sense(struct fsg_dev + + static int do_start_stop(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int loej, start; + + if (!mod_data.removable) { +@@ -1829,7 +1830,7 @@ static int do_start_stop(struct fsg_dev + if (loej) { // Simulate an unload/eject + up_read(&fsg->filesem); + down_write(&fsg->filesem); +- close_backing_file(curlun); ++ fsg_lun_close(curlun); + up_write(&fsg->filesem); + down_read(&fsg->filesem); + } +@@ -1837,7 +1838,7 @@ static int do_start_stop(struct fsg_dev + + /* Our emulation doesn't support mounting; the medium is + * available for use as soon as it is loaded. */ +- if (!backing_file_is_open(curlun)) { ++ if (!fsg_lun_is_open(curlun)) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } +@@ -1849,7 +1850,7 @@ static int do_start_stop(struct fsg_dev + + static int do_prevent_allow(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + int prevent; + + if (!mod_data.removable) { +@@ -1864,7 +1865,7 @@ static int do_prevent_allow(struct fsg_d + } + + if (curlun->prevent_medium_removal && !prevent) +- fsync_sub(curlun); ++ fsg_lun_fsync_sub(curlun); + curlun->prevent_medium_removal = prevent; + return 0; + } +@@ -1873,7 +1874,7 @@ static int do_prevent_allow(struct fsg_d + static int do_read_format_capacities(struct fsg_dev *fsg, + struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + + buf[0] = buf[1] = buf[2] = 0; +@@ -1890,7 +1891,7 @@ static int do_read_format_capacities(str + + static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + + /* We don't support MODE SELECT */ + curlun->sense_data = SS_INVALID_COMMAND; +@@ -2133,7 +2134,7 @@ static int finish_reply(struct fsg_dev * + + static int send_status(struct fsg_dev *fsg) + { +- struct lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->curlun; + struct fsg_buffhd *bh; + int rc; + u8 status = USB_STATUS_PASS; +@@ -2225,7 +2226,7 @@ static int check_command(struct fsg_dev + int lun = fsg->cmnd[1] >> 5; + static const char dirletter[4] = {'u', 'o', 'i', 'n'}; + char hdlen[20]; +- struct lun *curlun; ++ struct fsg_lun *curlun; + + /* Adjust the expected cmnd_size for protocol encapsulation padding. + * Transparent SCSI doesn't pad. */ +@@ -2354,7 +2355,7 @@ static int check_command(struct fsg_dev + + /* If the medium isn't mounted and the command needs to access + * it, return an error. */ +- if (curlun && !backing_file_is_open(curlun) && needs_medium) { ++ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + return -EINVAL; + } +@@ -2609,8 +2610,8 @@ static int do_scsi_command(struct fsg_de + + static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct usb_request *req = bh->outreq; +- struct bulk_cb_wrap *cbw = req->buf; ++ struct usb_request *req = bh->outreq; ++ struct fsg_bulk_cb_wrap *cbw = req->buf; + + /* Was this a real packet? Should it be ignored? */ + if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) +@@ -2639,7 +2640,7 @@ static int received_cbw(struct fsg_dev * + } + + /* Is the CBW meaningful? */ +- if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || ++ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " + "cmdlen %u\n", +@@ -2772,7 +2773,7 @@ static int do_set_interface(struct fsg_d + + reset: + /* Deallocate the requests */ +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if (bh->inreq) { +@@ -2810,12 +2811,14 @@ reset: + DBG(fsg, "set interface %d\n", altsetting); + + /* Enable the endpoints */ +- d = ep_desc(fsg->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc); ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) + goto reset; + fsg->bulk_in_enabled = 1; + +- d = ep_desc(fsg->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc); ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) + goto reset; + fsg->bulk_out_enabled = 1; +@@ -2823,14 +2826,15 @@ reset: + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + + if (transport_is_cbi()) { +- d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc); + if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) + goto reset; + fsg->intr_in_enabled = 1; + } + + /* Allocate the requests */ +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) +@@ -2906,7 +2910,7 @@ static void handle_exception(struct fsg_ + struct fsg_buffhd *bh; + enum fsg_state old_state; + u8 new_config; +- struct lun *curlun; ++ struct fsg_lun *curlun; + unsigned int exception_req_tag; + int rc; + +@@ -2926,7 +2930,7 @@ static void handle_exception(struct fsg_ + /* Cancel all the pending transfers */ + if (fsg->intreq_busy) + usb_ep_dequeue(fsg->intr_in, fsg->intreq); +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + if (bh->inreq_busy) + usb_ep_dequeue(fsg->bulk_in, bh->inreq); +@@ -2937,7 +2941,7 @@ static void handle_exception(struct fsg_ + /* Wait until everything is idle */ + for (;;) { + num_active = fsg->intreq_busy; +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; + } +@@ -2959,7 +2963,7 @@ static void handle_exception(struct fsg_ + * state, and the exception. Then invoke the handler. */ + spin_lock_irq(&fsg->lock); + +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + bh->state = BUF_STATE_EMPTY; + } +@@ -3041,7 +3045,7 @@ static void handle_exception(struct fsg_ + + case FSG_STATE_DISCONNECT: + for (i = 0; i < fsg->nluns; ++i) +- fsync_sub(fsg->luns + i); ++ fsg_lun_fsync_sub(fsg->luns + i); + do_set_config(fsg, 0); // Unconfigured state + break; + +@@ -3132,7 +3136,7 @@ static int fsg_main_thread(void *fsg_) + + static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) + { +- struct lun *curlun = dev_to_lun(dev); ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%d\n", curlun->ro); + } +@@ -3140,13 +3144,13 @@ static ssize_t show_ro(struct device *de + static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) + { +- struct lun *curlun = dev_to_lun(dev); ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); + char *p; + ssize_t rc; + + down_read(&fsg->filesem); +- if (backing_file_is_open(curlun)) { // Get the complete pathname ++ if (fsg_lun_is_open(curlun)) { // Get the complete pathname + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + if (IS_ERR(p)) + rc = PTR_ERR(p); +@@ -3169,7 +3173,7 @@ static ssize_t store_ro(struct device *d + const char *buf, size_t count) + { + ssize_t rc = count; +- struct lun *curlun = dev_to_lun(dev); ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); + int i; + +@@ -3179,7 +3183,7 @@ static ssize_t store_ro(struct device *d + /* Allow the write-enable status to change only while the backing file + * is closed. */ + down_read(&fsg->filesem); +- if (backing_file_is_open(curlun)) { ++ if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { +@@ -3193,11 +3197,11 @@ static ssize_t store_ro(struct device *d + static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +- struct lun *curlun = dev_to_lun(dev); ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); + int rc = 0; + +- if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { ++ if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; // "Door is locked" + } +@@ -3208,14 +3212,14 @@ static ssize_t store_file(struct device + + /* Eject current medium */ + down_write(&fsg->filesem); +- if (backing_file_is_open(curlun)) { +- close_backing_file(curlun); ++ if (fsg_lun_is_open(curlun)) { ++ fsg_lun_close(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + + /* Load new medium */ + if (count > 0 && buf[0]) { +- rc = open_backing_file(curlun, buf); ++ rc = fsg_lun_open(curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; +@@ -3251,7 +3255,7 @@ static void /* __init_or_exit */ fsg_unb + { + struct fsg_dev *fsg = get_gadget_data(gadget); + int i; +- struct lun *curlun; ++ struct fsg_lun *curlun; + struct usb_request *req = fsg->ep0req; + + DBG(fsg, "unbind\n"); +@@ -3263,7 +3267,7 @@ static void /* __init_or_exit */ fsg_unb + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_ro); + device_remove_file(&curlun->dev, &dev_attr_file); +- close_backing_file(curlun); ++ fsg_lun_close(curlun); + device_unregister(&curlun->dev); + curlun->registered = 0; + } +@@ -3279,7 +3283,7 @@ static void /* __init_or_exit */ fsg_unb + } + + /* Free the data buffers */ +- for (i = 0; i < NUM_BUFFERS; ++i) ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) + kfree(fsg->buffhds[i].buf); + + /* Free the request and buffer for endpoint 0 */ +@@ -3386,7 +3390,7 @@ static int __init fsg_bind(struct usb_ga + struct fsg_dev *fsg = the_fsg; + int rc; + int i; +- struct lun *curlun; ++ struct fsg_lun *curlun; + struct usb_ep *ep; + struct usb_request *req; + char *pathbuf, *p; +@@ -3412,7 +3416,7 @@ static int __init fsg_bind(struct usb_ga + i = mod_data.nluns; + if (i == 0) + i = max(mod_data.num_filenames, 1u); +- if (i > MAX_LUNS) { ++ if (i > FSG_MAX_LUNS) { + ERROR(fsg, "invalid number of LUNs: %d\n", i); + rc = -EINVAL; + goto out; +@@ -3420,7 +3424,7 @@ static int __init fsg_bind(struct usb_ga + + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ +- fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); ++ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); + if (!fsg->luns) { + rc = -ENOMEM; + goto out; +@@ -3454,7 +3458,7 @@ static int __init fsg_bind(struct usb_ga + kref_get(&fsg->ref); + + if (mod_data.file[i] && *mod_data.file[i]) { +- if ((rc = open_backing_file(curlun, ++ if ((rc = fsg_lun_open(curlun, + mod_data.file[i])) != 0) + goto out; + } else if (!mod_data.removable) { +@@ -3466,20 +3470,20 @@ static int __init fsg_bind(struct usb_ga + + /* Find all the endpoints we will use */ + usb_ep_autoconfig_reset(gadget); +- ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc); ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint + fsg->bulk_in = ep; + +- ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc); ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint + fsg->bulk_out = ep; + + if (transport_is_cbi()) { +- ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc); ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint +@@ -3493,28 +3497,28 @@ static int __init fsg_bind(struct usb_ga + device_desc.bcdDevice = cpu_to_le16(mod_data.release); + + i = (transport_is_cbi() ? 3 : 2); // Number of endpoints +- intf_desc.bNumEndpoints = i; +- intf_desc.bInterfaceSubClass = mod_data.protocol_type; +- intf_desc.bInterfaceProtocol = mod_data.transport_type; +- fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; ++ fsg_intf_desc.bNumEndpoints = i; ++ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; ++ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; ++ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; + + if (gadget_is_dualspeed(gadget)) { +- hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; ++ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + + /* Assume endpoint addresses are the same for both speeds */ +- hs_bulk_in_desc.bEndpointAddress = +- fs_bulk_in_desc.bEndpointAddress; +- hs_bulk_out_desc.bEndpointAddress = +- fs_bulk_out_desc.bEndpointAddress; +- hs_intr_in_desc.bEndpointAddress = +- fs_intr_in_desc.bEndpointAddress; ++ fsg_hs_bulk_in_desc.bEndpointAddress = ++ fsg_fs_bulk_in_desc.bEndpointAddress; ++ fsg_hs_bulk_out_desc.bEndpointAddress = ++ fsg_fs_bulk_out_desc.bEndpointAddress; ++ fsg_hs_intr_in_desc.bEndpointAddress = ++ fsg_fs_intr_in_desc.bEndpointAddress; + } + + if (gadget_is_otg(gadget)) +- otg_desc.bmAttributes |= USB_OTG_HNP; ++ fsg_otg_desc.bmAttributes |= USB_OTG_HNP; + + rc = -ENOMEM; + +@@ -3528,7 +3532,7 @@ static int __init fsg_bind(struct usb_ga + req->complete = ep0_complete; + + /* Allocate the data buffers */ +- for (i = 0; i < NUM_BUFFERS; ++i) { ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + /* Allocate for the bulk-in endpoint. We assume that +@@ -3539,23 +3543,24 @@ static int __init fsg_bind(struct usb_ga + goto out; + bh->next = bh + 1; + } +- fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0]; ++ fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + + /* This should reflect the actual gadget power source */ + usb_gadget_set_selfpowered(gadget); + +- snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", ++ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, ++ "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + gadget->name); + + /* On a real device, serial[] would be loaded from permanent + * storage. We just encode it from the driver version string. */ +- for (i = 0; i < sizeof(serial) - 2; i += 2) { ++ for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) { + unsigned char c = DRIVER_VERSION[i / 2]; + + if (!c) + break; +- sprintf(&serial[i], "%02X", c); ++ sprintf(&fsg_string_serial[i], "%02X", c); + } + + fsg->thread_task = kthread_create(fsg_main_thread, fsg, +@@ -3571,7 +3576,7 @@ static int __init fsg_bind(struct usb_ga + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; +- if (backing_file_is_open(curlun)) { ++ if (fsg_lun_is_open(curlun)) { + p = NULL; + if (pathbuf) { + p = d_path(&curlun->filp->f_path, +@@ -3641,7 +3646,7 @@ static struct usb_gadget_driver fsg_dri + #else + .speed = USB_SPEED_FULL, + #endif +- .function = (char *) longname, ++ .function = (char *) fsg_string_product, + .bind = fsg_bind, + .unbind = fsg_unbind, + .disconnect = fsg_disconnect, +@@ -3650,7 +3655,7 @@ static struct usb_gadget_driver fsg_dri + .resume = fsg_resume, + + .driver = { +- .name = (char *) shortname, ++ .name = DRIVER_NAME, + .owner = THIS_MODULE, + // .release = ... + // .suspend = ... +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -4,9 +4,38 @@ + * Copyright (C) 2003-2008 Alan Stern + * Copyeight (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++/* ++ * This file requires the following identifiers used in USB strings to ++ * be defined (each of type pointer to char): ++ * - fsg_string_manufacturer -- name of the manufacturer ++ * - fsg_string_product -- name of the product ++ * - fsg_string_serial -- product's serial ++ * - fsg_string_config -- name of the configuration ++ * - fsg_string_interface -- name of the interface ++ * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS ++ * macro is defined prior to including this file. + */ + + ++#include <asm/unaligned.h> ++ + + /*-------------------------------------------------------------------------*/ + +@@ -93,7 +122,7 @@ + /* Bulk-only data structures */ + + /* Command Block Wrapper */ +-struct bulk_cb_wrap { ++struct fsg_bulk_cb_wrap { + __le32 Signature; // Contains 'USBC' + u32 Tag; // Unique per command id + __le32 DataTransferLength; // Size of the data +@@ -191,7 +220,7 @@ struct interrupt_data { + /*-------------------------------------------------------------------------*/ + + +-struct lun { ++struct fsg_lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; +@@ -208,11 +237,11 @@ struct lun { + struct device dev; + }; + +-#define backing_file_is_open(curlun) ((curlun)->filp != NULL) ++#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) + +-static struct lun *dev_to_lun(struct device *dev) ++static struct fsg_lun *fsg_lun_from_dev(struct device *dev) + { +- return container_of(dev, struct lun, dev); ++ return container_of(dev, struct fsg_lun, dev); + } + + +@@ -221,7 +250,7 @@ static struct lun *dev_to_lun(struct dev + #define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value + + /* Number of buffers we will use. 2 is enough for double-buffering */ +-#define NUM_BUFFERS 2 ++#define FSG_NUM_BUFFERS 2 + + enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, +@@ -280,16 +309,18 @@ static inline u32 get_unaligned_be24(u8 + /*-------------------------------------------------------------------------*/ + + +-#define STRING_MANUFACTURER 1 +-#define STRING_PRODUCT 2 +-#define STRING_SERIAL 3 +-#define STRING_CONFIG 4 +-#define STRING_INTERFACE 5 ++enum { ++ FSG_STRING_MANUFACTURER = 1, ++ FSG_STRING_PRODUCT, ++ FSG_STRING_SERIAL, ++ FSG_STRING_CONFIG, ++ FSG_STRING_INTERFACE ++}; + + + static struct usb_otg_descriptor +-otg_desc = { +- .bLength = sizeof(otg_desc), ++fsg_otg_desc = { ++ .bLength = sizeof fsg_otg_desc, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +@@ -298,22 +329,22 @@ otg_desc = { + /* There is only one interface. */ + + static struct usb_interface_descriptor +-intf_desc = { +- .bLength = sizeof intf_desc, ++fsg_intf_desc = { ++ .bLength = sizeof fsg_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, // Adjusted during fsg_bind() + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() + .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() +- .iInterface = STRING_INTERFACE, ++ .iInterface = FSG_STRING_INTERFACE, + }; + + /* Three full-speed endpoint descriptors: bulk-in, bulk-out, + * and interrupt-in. */ + + static struct usb_endpoint_descriptor +-fs_bulk_in_desc = { ++fsg_fs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -323,7 +354,7 @@ fs_bulk_in_desc = { + }; + + static struct usb_endpoint_descriptor +-fs_bulk_out_desc = { ++fsg_fs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -333,7 +364,7 @@ fs_bulk_out_desc = { + }; + + static struct usb_endpoint_descriptor +-fs_intr_in_desc = { ++fsg_fs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -343,15 +374,15 @@ fs_intr_in_desc = { + .bInterval = 32, // frames -> 32 ms + }; + +-static const struct usb_descriptor_header *fs_function[] = { +- (struct usb_descriptor_header *) &otg_desc, +- (struct usb_descriptor_header *) &intf_desc, +- (struct usb_descriptor_header *) &fs_bulk_in_desc, +- (struct usb_descriptor_header *) &fs_bulk_out_desc, +- (struct usb_descriptor_header *) &fs_intr_in_desc, ++static const struct usb_descriptor_header *fsg_fs_function[] = { ++ (struct usb_descriptor_header *) &fsg_otg_desc, ++ (struct usb_descriptor_header *) &fsg_intf_desc, ++ (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, ++ (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, ++ (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, + NULL, + }; +-#define FS_FUNCTION_PRE_EP_ENTRIES 2 ++#define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 + + + /* +@@ -363,7 +394,7 @@ static const struct usb_descriptor_heade + * for the config descriptor. + */ + static struct usb_endpoint_descriptor +-hs_bulk_in_desc = { ++fsg_hs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -373,7 +404,7 @@ hs_bulk_in_desc = { + }; + + static struct usb_endpoint_descriptor +-hs_bulk_out_desc = { ++fsg_hs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -384,7 +415,7 @@ hs_bulk_out_desc = { + }; + + static struct usb_endpoint_descriptor +-hs_intr_in_desc = { ++fsg_hs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +@@ -394,19 +425,19 @@ hs_intr_in_desc = { + .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms + }; + +-static const struct usb_descriptor_header *hs_function[] = { +- (struct usb_descriptor_header *) &otg_desc, +- (struct usb_descriptor_header *) &intf_desc, +- (struct usb_descriptor_header *) &hs_bulk_in_desc, +- (struct usb_descriptor_header *) &hs_bulk_out_desc, +- (struct usb_descriptor_header *) &hs_intr_in_desc, ++static const struct usb_descriptor_header *fsg_hs_function[] = { ++ (struct usb_descriptor_header *) &fsg_otg_desc, ++ (struct usb_descriptor_header *) &fsg_intf_desc, ++ (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, ++ (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, ++ (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, + NULL, + }; +-#define HS_FUNCTION_PRE_EP_ENTRIES 2 ++#define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 + + /* Maxpacket and other transfer characteristics vary by speed. */ + static struct usb_endpoint_descriptor * +-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, ++fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) + { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) +@@ -415,24 +446,19 @@ ep_desc(struct usb_gadget *g, struct usb + } + + +-/* The CBI specification limits the serial string to 12 uppercase hexadecimal +- * characters. */ +-static char manufacturer[64]; +-static char serial[13]; +- + /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +-static struct usb_string strings[] = { +- {STRING_MANUFACTURER, manufacturer}, +- {STRING_PRODUCT, longname}, +- {STRING_SERIAL, serial}, +- {STRING_CONFIG, "Self-powered"}, +- {STRING_INTERFACE, "Mass Storage"}, ++static struct usb_string fsg_strings[] = { ++ {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, ++ {FSG_STRING_PRODUCT, fsg_string_product}, ++ {FSG_STRING_SERIAL, fsg_string_serial}, ++ {FSG_STRING_CONFIG, fsg_string_config}, ++ {FSG_STRING_INTERFACE, fsg_string_interface}, + {} + }; + +-static struct usb_gadget_strings stringtab = { ++static struct usb_gadget_strings fsg_stringtab = { + .language = 0x0409, // en-us +- .strings = strings, ++ .strings = fsg_strings, + }; + + +@@ -441,7 +467,7 @@ static struct usb_gadget_strings stringt + /* If the next two routines are called while the gadget is registered, + * the caller must own fsg->filesem for writing. */ + +-static int open_backing_file(struct lun *curlun, const char *filename) ++static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) + { + int ro; + struct file *filp = NULL; +@@ -525,7 +551,7 @@ out: + } + + +-static void close_backing_file(struct lun *curlun) ++static void fsg_lun_close(struct fsg_lun *curlun) + { + if (curlun->filp) { + LDBG(curlun, "close backing file\n"); +@@ -539,7 +565,7 @@ static void close_backing_file(struct lu + + /* Sync the file data, don't bother with the metadata. + * This code was copied from fs/buffer.c:sys_fdatasync(). */ +-static int fsync_sub(struct lun *curlun) ++static int fsg_lun_fsync_sub(struct fsg_lun *curlun) + { + struct file *filp = curlun->filp; + diff --git a/usb/usb-g_file_storage-more-code-from-file_storage.c-moved-to-storage_common.c.patch b/usb/usb-g_file_storage-more-code-from-file_storage.c-moved-to-storage_common.c.patch new file mode 100644 index 00000000000000..270bc6499db55f --- /dev/null +++ b/usb/usb-g_file_storage-more-code-from-file_storage.c-moved-to-storage_common.c.patch @@ -0,0 +1,354 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:42:12 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:17 +0100 +Subject: USB: g_file_storage: more code from file_storage.c moved to storage_common.c +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <25ba01e250a1b6ac950cd4202d9d630dad3e2b67.1256745228.git.m.nazarewicz@samsung.com> + + +Since storage_common.c no longer references mod_data object +it is now possible to include it before mod_data object is +defined. This makes it possible to move some defines that +are used as default values of mod_data fields to be defined +in storage_common.c file (where they should be set from +the beginning). + +Also, show_ro(), show_file(), store_ro() and store_file() +have been moved to storage_common.c with LUN's device's +drvdata changed from pointing to fsg_dev to pointing to +rw_semaphore (&fsg->filesem). + +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> +--- + drivers/usb/gadget/file_storage.c | 129 +++--------------------------------- + drivers/usb/gadget/storage_common.c | 116 ++++++++++++++++++++++++++++++++ + 2 files changed, 128 insertions(+), 117 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -278,18 +278,14 @@ static char fsg_string_serial[13]; + static const char fsg_string_config[] = "Self-powered"; + static const char fsg_string_interface[] = "Mass Storage"; + ++ ++#include "storage_common.c" ++ ++ + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_AUTHOR("Alan Stern"); + MODULE_LICENSE("Dual BSD/GPL"); + +-/* Thanks to NetChip Technologies for donating this product ID. +- * +- * DO NOT REUSE THESE IDs with any other driver!! Ever!! +- * Instead: allocate your own, using normal USB-IF procedures. */ +-#define FSG_VENDOR_ID 0x0525 // NetChip +-#define FSG_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget +- +- + /* + * This driver assumes self-powered hardware and has no way for users to + * trigger remote wakeup. It uses autoconfiguration to select endpoints +@@ -302,8 +298,6 @@ MODULE_LICENSE("Dual BSD/GPL"); + + /* Encapsulate the module parameter settings */ + +-#define FSG_MAX_LUNS 8 +- + static struct { + char *file[FSG_MAX_LUNS]; + int ro[FSG_MAX_LUNS]; +@@ -410,10 +404,6 @@ MODULE_PARM_DESC(buflen, "I/O buffer siz + + /*-------------------------------------------------------------------------*/ + +-#include "storage_common.c" +- +-/*-------------------------------------------------------------------------*/ +- + + struct fsg_dev { + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ +@@ -3134,107 +3124,10 @@ static int fsg_main_thread(void *fsg_) + + /*-------------------------------------------------------------------------*/ + +-static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) +-{ +- struct fsg_lun *curlun = fsg_lun_from_dev(dev); +- +- return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) +- ? curlun->ro +- : curlun->initially_ro); +-} +- +-static ssize_t show_file(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct fsg_lun *curlun = fsg_lun_from_dev(dev); +- struct fsg_dev *fsg = dev_get_drvdata(dev); +- char *p; +- ssize_t rc; +- +- down_read(&fsg->filesem); +- if (fsg_lun_is_open(curlun)) { // Get the complete pathname +- p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); +- if (IS_ERR(p)) +- rc = PTR_ERR(p); +- else { +- rc = strlen(p); +- memmove(buf, p, rc); +- buf[rc] = '\n'; // Add a newline +- buf[++rc] = 0; +- } +- } else { // No file, return 0 bytes +- *buf = 0; +- rc = 0; +- } +- up_read(&fsg->filesem); +- return rc; +-} +- +- +-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- ssize_t rc = count; +- struct fsg_lun *curlun = fsg_lun_from_dev(dev); +- struct fsg_dev *fsg = dev_get_drvdata(dev); +- int i; +- +- if (sscanf(buf, "%d", &i) != 1) +- return -EINVAL; +- +- /* Allow the write-enable status to change only while the backing file +- * is closed. */ +- down_read(&fsg->filesem); +- if (fsg_lun_is_open(curlun)) { +- LDBG(curlun, "read-only status change prevented\n"); +- rc = -EBUSY; +- } else { +- curlun->ro = !!i; +- curlun->initially_ro = !!i; +- LDBG(curlun, "read-only status set to %d\n", curlun->ro); +- } +- up_read(&fsg->filesem); +- return rc; +-} +- +-static ssize_t store_file(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct fsg_lun *curlun = fsg_lun_from_dev(dev); +- struct fsg_dev *fsg = dev_get_drvdata(dev); +- int rc = 0; +- +- if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { +- LDBG(curlun, "eject attempt prevented\n"); +- return -EBUSY; // "Door is locked" +- } +- +- /* Remove a trailing newline */ +- if (count > 0 && buf[count-1] == '\n') +- ((char *) buf)[count-1] = 0; // Ugh! +- +- /* Eject current medium */ +- down_write(&fsg->filesem); +- if (fsg_lun_is_open(curlun)) { +- fsg_lun_close(curlun); +- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; +- } +- +- /* Load new medium */ +- if (count > 0 && buf[0]) { +- rc = fsg_lun_open(curlun, buf); +- if (rc == 0) +- curlun->unit_attention_data = +- SS_NOT_READY_TO_READY_TRANSITION; +- } +- up_write(&fsg->filesem); +- return (rc < 0 ? rc : count); +-} +- + + /* The write permissions and store_xxx pointers are set in fsg_bind() */ +-static DEVICE_ATTR(ro, 0444, show_ro, NULL); +-static DEVICE_ATTR(file, 0444, show_file, NULL); ++static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); ++static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); + + + /*-------------------------------------------------------------------------*/ +@@ -3249,7 +3142,9 @@ static void fsg_release(struct kref *ref + + static void lun_release(struct device *dev) + { +- struct fsg_dev *fsg = dev_get_drvdata(dev); ++ struct rw_semaphore *filesem = dev_get_drvdata(dev); ++ struct fsg_dev *fsg = ++ container_of(filesem, struct fsg_dev, filesem); + + kref_put(&fsg->ref, fsg_release); + } +@@ -3408,10 +3303,10 @@ static int __init fsg_bind(struct usb_ga + + if (mod_data.removable) { // Enable the store_xxx attributes + dev_attr_file.attr.mode = 0644; +- dev_attr_file.store = store_file; ++ dev_attr_file.store = fsg_store_file; + if (!mod_data.cdrom) { + dev_attr_ro.attr.mode = 0644; +- dev_attr_ro.store = store_ro; ++ dev_attr_ro.store = fsg_store_ro; + } + } + +@@ -3443,7 +3338,7 @@ static int __init fsg_bind(struct usb_ga + curlun->dev.release = lun_release; + curlun->dev.parent = &gadget->dev; + curlun->dev.driver = &fsg_driver.driver; +- dev_set_drvdata(&curlun->dev, fsg); ++ dev_set_drvdata(&curlun->dev, &fsg->filesem); + dev_set_name(&curlun->dev,"%s-lun%d", + dev_name(&gadget->dev), i); + +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -37,6 +37,14 @@ + #include <asm/unaligned.h> + + ++/* Thanks to NetChip Technologies for donating this product ID. ++ * ++ * DO NOT REUSE THESE IDs with any other driver!! Ever!! ++ * Instead: allocate your own, using normal USB-IF procedures. */ ++#define FSG_VENDOR_ID 0x0525 // NetChip ++#define FSG_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget ++ ++ + /*-------------------------------------------------------------------------*/ + + +@@ -255,6 +263,12 @@ static struct fsg_lun *fsg_lun_from_dev( + /* Number of buffers we will use. 2 is enough for double-buffering */ + #define FSG_NUM_BUFFERS 2 + ++/* Default size of buffer length. */ ++#define FSG_BUFLEN ((u32)16384) ++ ++/* Maximal number of LUNs supported in mass storage function */ ++#define FSG_MAX_LUNS 8 ++ + enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, +@@ -594,3 +608,105 @@ static void store_cdrom_address(u8 *dest + put_unaligned_be32(addr, dest); + } + } ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); ++ ++ return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) ++ ? curlun->ro ++ : curlun->initially_ro); ++} ++ ++static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); ++ struct rw_semaphore *filesem = dev_get_drvdata(dev); ++ char *p; ++ ssize_t rc; ++ ++ down_read(filesem); ++ if (fsg_lun_is_open(curlun)) { // Get the complete pathname ++ p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); ++ if (IS_ERR(p)) ++ rc = PTR_ERR(p); ++ else { ++ rc = strlen(p); ++ memmove(buf, p, rc); ++ buf[rc] = '\n'; // Add a newline ++ buf[++rc] = 0; ++ } ++ } else { // No file, return 0 bytes ++ *buf = 0; ++ rc = 0; ++ } ++ up_read(filesem); ++ return rc; ++} ++ ++ ++static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ ssize_t rc = count; ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); ++ struct rw_semaphore *filesem = dev_get_drvdata(dev); ++ int i; ++ ++ if (sscanf(buf, "%d", &i) != 1) ++ return -EINVAL; ++ ++ /* Allow the write-enable status to change only while the backing file ++ * is closed. */ ++ down_read(filesem); ++ if (fsg_lun_is_open(curlun)) { ++ LDBG(curlun, "read-only status change prevented\n"); ++ rc = -EBUSY; ++ } else { ++ curlun->ro = !!i; ++ curlun->initially_ro = !!i; ++ LDBG(curlun, "read-only status set to %d\n", curlun->ro); ++ } ++ up_read(filesem); ++ return rc; ++} ++ ++static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fsg_lun *curlun = fsg_lun_from_dev(dev); ++ struct rw_semaphore *filesem = dev_get_drvdata(dev); ++ int rc = 0; ++ ++ if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { ++ LDBG(curlun, "eject attempt prevented\n"); ++ return -EBUSY; // "Door is locked" ++ } ++ ++ /* Remove a trailing newline */ ++ if (count > 0 && buf[count-1] == '\n') ++ ((char *) buf)[count-1] = 0; // Ugh! ++ ++ /* Eject current medium */ ++ down_write(filesem); ++ if (fsg_lun_is_open(curlun)) { ++ fsg_lun_close(curlun); ++ curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; ++ } ++ ++ /* Load new medium */ ++ if (count > 0 && buf[0]) { ++ rc = fsg_lun_open(curlun, buf); ++ if (rc == 0) ++ curlun->unit_attention_data = ++ SS_NOT_READY_TO_READY_TRANSITION; ++ } ++ up_write(filesem); ++ return (rc < 0 ? rc : count); ++} diff --git a/usb/usb-g_file_storage-parts-of-file_storage.c-moved-to-separate-file.patch b/usb/usb-g_file_storage-parts-of-file_storage.c-moved-to-separate-file.patch new file mode 100644 index 00000000000000..156757a0129247 --- /dev/null +++ b/usb/usb-g_file_storage-parts-of-file_storage.c-moved-to-separate-file.patch @@ -0,0 +1,1256 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:39:40 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:14 +0100 +Subject: USB: g_file_storage: parts of file_storage.c moved to separate file +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <c45c54c1a7c770ef7ed7859f8d8ec33909fe4cea.1256745228.git.m.nazarewicz@samsung.com> + + +Moved parts of the file_storage.c file which do not reference fsg_dev +structure to newly created storage_common.c file. dump_msg() and +dump_cdb() have been changed to macros to remove fsg_dev reference. + +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> + +--- + drivers/usb/gadget/file_storage.c | 572 ------------------------------------ + drivers/usb/gadget/storage_common.c | 567 +++++++++++++++++++++++++++++++++++ + 2 files changed, 572 insertions(+), 567 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -298,46 +298,6 @@ MODULE_LICENSE("Dual BSD/GPL"); + + /*-------------------------------------------------------------------------*/ + +-#define LDBG(lun,fmt,args...) \ +- dev_dbg(&(lun)->dev , fmt , ## args) +-#define MDBG(fmt,args...) \ +- pr_debug(DRIVER_NAME ": " fmt , ## args) +- +-#ifndef DEBUG +-#undef VERBOSE_DEBUG +-#undef DUMP_MSGS +-#endif /* !DEBUG */ +- +-#ifdef VERBOSE_DEBUG +-#define VLDBG LDBG +-#else +-#define VLDBG(lun,fmt,args...) \ +- do { } while (0) +-#endif /* VERBOSE_DEBUG */ +- +-#define LERROR(lun,fmt,args...) \ +- dev_err(&(lun)->dev , fmt , ## args) +-#define LWARN(lun,fmt,args...) \ +- dev_warn(&(lun)->dev , fmt , ## args) +-#define LINFO(lun,fmt,args...) \ +- dev_info(&(lun)->dev , fmt , ## args) +- +-#define MINFO(fmt,args...) \ +- pr_info(DRIVER_NAME ": " fmt , ## args) +- +-#define DBG(d, fmt, args...) \ +- dev_dbg(&(d)->gadget->dev , fmt , ## args) +-#define VDBG(d, fmt, args...) \ +- dev_vdbg(&(d)->gadget->dev , fmt , ## args) +-#define ERROR(d, fmt, args...) \ +- dev_err(&(d)->gadget->dev , fmt , ## args) +-#define WARNING(d, fmt, args...) \ +- dev_warn(&(d)->gadget->dev , fmt , ## args) +-#define INFO(d, fmt, args...) \ +- dev_info(&(d)->gadget->dev , fmt , ## args) +- +- +-/*-------------------------------------------------------------------------*/ + + /* Encapsulate the module parameter settings */ + +@@ -425,125 +385,6 @@ MODULE_PARM_DESC(buflen, "I/O buffer siz + #endif /* CONFIG_USB_FILE_STORAGE_TEST */ + + +-/*-------------------------------------------------------------------------*/ +- +-/* SCSI device types */ +-#define TYPE_DISK 0x00 +-#define TYPE_CDROM 0x05 +- +-/* USB protocol value = the transport method */ +-#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt +-#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt +-#define USB_PR_BULK 0x50 // Bulk-only +- +-/* USB subclass value = the protocol encapsulation */ +-#define USB_SC_RBC 0x01 // Reduced Block Commands (flash) +-#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM) +-#define USB_SC_QIC 0x03 // QIC-157 (tape) +-#define USB_SC_UFI 0x04 // UFI (floppy) +-#define USB_SC_8070 0x05 // SFF-8070i (removable) +-#define USB_SC_SCSI 0x06 // Transparent SCSI +- +-/* Bulk-only data structures */ +- +-/* Command Block Wrapper */ +-struct bulk_cb_wrap { +- __le32 Signature; // Contains 'USBC' +- u32 Tag; // Unique per command id +- __le32 DataTransferLength; // Size of the data +- u8 Flags; // Direction in bit 7 +- u8 Lun; // LUN (normally 0) +- u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE +- u8 CDB[16]; // Command Data Block +-}; +- +-#define USB_BULK_CB_WRAP_LEN 31 +-#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC +-#define USB_BULK_IN_FLAG 0x80 +- +-/* Command Status Wrapper */ +-struct bulk_cs_wrap { +- __le32 Signature; // Should = 'USBS' +- u32 Tag; // Same as original command +- __le32 Residue; // Amount not transferred +- u8 Status; // See below +-}; +- +-#define USB_BULK_CS_WRAP_LEN 13 +-#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS' +-#define USB_STATUS_PASS 0 +-#define USB_STATUS_FAIL 1 +-#define USB_STATUS_PHASE_ERROR 2 +- +-/* Bulk-only class specific requests */ +-#define USB_BULK_RESET_REQUEST 0xff +-#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe +- +- +-/* CBI Interrupt data structure */ +-struct interrupt_data { +- u8 bType; +- u8 bValue; +-}; +- +-#define CBI_INTERRUPT_DATA_LEN 2 +- +-/* CBI Accept Device-Specific Command request */ +-#define USB_CBI_ADSC_REQUEST 0x00 +- +- +-#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block +- +-/* SCSI commands that we recognize */ +-#define SC_FORMAT_UNIT 0x04 +-#define SC_INQUIRY 0x12 +-#define SC_MODE_SELECT_6 0x15 +-#define SC_MODE_SELECT_10 0x55 +-#define SC_MODE_SENSE_6 0x1a +-#define SC_MODE_SENSE_10 0x5a +-#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +-#define SC_READ_6 0x08 +-#define SC_READ_10 0x28 +-#define SC_READ_12 0xa8 +-#define SC_READ_CAPACITY 0x25 +-#define SC_READ_FORMAT_CAPACITIES 0x23 +-#define SC_READ_HEADER 0x44 +-#define SC_READ_TOC 0x43 +-#define SC_RELEASE 0x17 +-#define SC_REQUEST_SENSE 0x03 +-#define SC_RESERVE 0x16 +-#define SC_SEND_DIAGNOSTIC 0x1d +-#define SC_START_STOP_UNIT 0x1b +-#define SC_SYNCHRONIZE_CACHE 0x35 +-#define SC_TEST_UNIT_READY 0x00 +-#define SC_VERIFY 0x2f +-#define SC_WRITE_6 0x0a +-#define SC_WRITE_10 0x2a +-#define SC_WRITE_12 0xaa +- +-/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +-#define SS_NO_SENSE 0 +-#define SS_COMMUNICATION_FAILURE 0x040800 +-#define SS_INVALID_COMMAND 0x052000 +-#define SS_INVALID_FIELD_IN_CDB 0x052400 +-#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +-#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +-#define SS_MEDIUM_NOT_PRESENT 0x023a00 +-#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +-#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +-#define SS_RESET_OCCURRED 0x062900 +-#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +-#define SS_UNRECOVERED_READ_ERROR 0x031100 +-#define SS_WRITE_ERROR 0x030c02 +-#define SS_WRITE_PROTECTED 0x072700 +- +-#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. +-#define ASC(x) ((u8) ((x) >> 8)) +-#define ASCQ(x) ((u8) (x)) +- +- +-/*-------------------------------------------------------------------------*/ +- + /* + * These definitions will permit the compiler to avoid generating code for + * parts of the driver that aren't used in the non-TEST version. Even gcc +@@ -566,81 +407,12 @@ struct interrupt_data { + #endif /* CONFIG_USB_FILE_STORAGE_TEST */ + + +-struct lun { +- struct file *filp; +- loff_t file_length; +- loff_t num_sectors; +- +- unsigned int ro : 1; +- unsigned int prevent_medium_removal : 1; +- unsigned int registered : 1; +- unsigned int info_valid : 1; +- +- u32 sense_data; +- u32 sense_data_info; +- u32 unit_attention_data; +- +- struct device dev; +-}; +- +-#define backing_file_is_open(curlun) ((curlun)->filp != NULL) +- +-static struct lun *dev_to_lun(struct device *dev) +-{ +- return container_of(dev, struct lun, dev); +-} +- +- +-/* Big enough to hold our biggest descriptor */ +-#define EP0_BUFSIZE 256 +-#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value +- +-/* Number of buffers we will use. 2 is enough for double-buffering */ +-#define NUM_BUFFERS 2 +- +-enum fsg_buffer_state { +- BUF_STATE_EMPTY = 0, +- BUF_STATE_FULL, +- BUF_STATE_BUSY +-}; ++/*-------------------------------------------------------------------------*/ + +-struct fsg_buffhd { +- void *buf; +- enum fsg_buffer_state state; +- struct fsg_buffhd *next; +- +- /* The NetChip 2280 is faster, and handles some protocol faults +- * better, if we don't submit any short bulk-out read requests. +- * So we will record the intended request length here. */ +- unsigned int bulk_out_intended_length; +- +- struct usb_request *inreq; +- int inreq_busy; +- struct usb_request *outreq; +- int outreq_busy; +-}; ++#include "storage_common.c" + +-enum fsg_state { +- FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere +- FSG_STATE_DATA_PHASE, +- FSG_STATE_STATUS_PHASE, +- +- FSG_STATE_IDLE = 0, +- FSG_STATE_ABORT_BULK_OUT, +- FSG_STATE_RESET, +- FSG_STATE_INTERFACE_CHANGE, +- FSG_STATE_CONFIG_CHANGE, +- FSG_STATE_DISCONNECT, +- FSG_STATE_EXIT, +- FSG_STATE_TERMINATED +-}; ++/*-------------------------------------------------------------------------*/ + +-enum data_direction { +- DATA_DIR_UNKNOWN = 0, +- DATA_DIR_FROM_HOST, +- DATA_DIR_TO_HOST, +- DATA_DIR_NONE +-}; + + struct fsg_dev { + /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ +@@ -739,49 +511,9 @@ static void set_bulk_out_req_length(stru + static struct fsg_dev *the_fsg; + static struct usb_gadget_driver fsg_driver; + +-static void close_backing_file(struct lun *curlun); +- + + /*-------------------------------------------------------------------------*/ + +-#ifdef DUMP_MSGS +- +-static void dump_msg(struct fsg_dev *fsg, const char *label, +- const u8 *buf, unsigned int length) +-{ +- if (length < 512) { +- DBG(fsg, "%s, length %u:\n", label, length); +- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, +- 16, 1, buf, length, 0); +- } +-} +- +-static void dump_cdb(struct fsg_dev *fsg) +-{} +- +-#else +- +-static void dump_msg(struct fsg_dev *fsg, const char *label, +- const u8 *buf, unsigned int length) +-{} +- +-#ifdef VERBOSE_DEBUG +- +-static void dump_cdb(struct fsg_dev *fsg) +-{ +- print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, +- 16, 1, fsg->cmnd, fsg->cmnd_size, 0); +-} +- +-#else +- +-static void dump_cdb(struct fsg_dev *fsg) +-{} +- +-#endif /* VERBOSE_DEBUG */ +-#endif /* DUMP_MSGS */ +- +- + static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) + { + const char *name; +@@ -799,26 +531,11 @@ static int fsg_set_halt(struct fsg_dev * + + /*-------------------------------------------------------------------------*/ + +-/* Routines for unaligned data access */ +- +-static u32 get_unaligned_be24(u8 *buf) +-{ +- return 0xffffff & (u32) get_unaligned_be32(buf - 1); +-} +- +- +-/*-------------------------------------------------------------------------*/ +- + /* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. Also the (static) config and interface + * descriptors are adjusted during fsg_bind(). + */ +-#define STRING_MANUFACTURER 1 +-#define STRING_PRODUCT 2 +-#define STRING_SERIAL 3 +-#define STRING_CONFIG 4 +-#define STRING_INTERFACE 5 + + /* There is only one configuration. */ + #define CONFIG_VALUE 1 +@@ -855,81 +572,7 @@ config_desc = { + .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, + }; + +-static struct usb_otg_descriptor +-otg_desc = { +- .bLength = sizeof(otg_desc), +- .bDescriptorType = USB_DT_OTG, + +- .bmAttributes = USB_OTG_SRP, +-}; +- +-/* There is only one interface. */ +- +-static struct usb_interface_descriptor +-intf_desc = { +- .bLength = sizeof intf_desc, +- .bDescriptorType = USB_DT_INTERFACE, +- +- .bNumEndpoints = 2, // Adjusted during fsg_bind() +- .bInterfaceClass = USB_CLASS_MASS_STORAGE, +- .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() +- .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() +- .iInterface = STRING_INTERFACE, +-}; +- +-/* Three full-speed endpoint descriptors: bulk-in, bulk-out, +- * and interrupt-in. */ +- +-static struct usb_endpoint_descriptor +-fs_bulk_in_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- .bEndpointAddress = USB_DIR_IN, +- .bmAttributes = USB_ENDPOINT_XFER_BULK, +- /* wMaxPacketSize set by autoconfiguration */ +-}; +- +-static struct usb_endpoint_descriptor +-fs_bulk_out_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- .bEndpointAddress = USB_DIR_OUT, +- .bmAttributes = USB_ENDPOINT_XFER_BULK, +- /* wMaxPacketSize set by autoconfiguration */ +-}; +- +-static struct usb_endpoint_descriptor +-fs_intr_in_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- .bEndpointAddress = USB_DIR_IN, +- .bmAttributes = USB_ENDPOINT_XFER_INT, +- .wMaxPacketSize = cpu_to_le16(2), +- .bInterval = 32, // frames -> 32 ms +-}; +- +-static const struct usb_descriptor_header *fs_function[] = { +- (struct usb_descriptor_header *) &otg_desc, +- (struct usb_descriptor_header *) &intf_desc, +- (struct usb_descriptor_header *) &fs_bulk_in_desc, +- (struct usb_descriptor_header *) &fs_bulk_out_desc, +- (struct usb_descriptor_header *) &fs_intr_in_desc, +- NULL, +-}; +-#define FS_FUNCTION_PRE_EP_ENTRIES 2 +- +- +-/* +- * USB 2.0 devices need to expose both high speed and full speed +- * descriptors, unless they only run at full speed. +- * +- * That means alternate endpoint descriptors (bigger packets) +- * and a "device qualifier" ... plus more construction options +- * for the config descriptor. +- */ + static struct usb_qualifier_descriptor + dev_qualifier = { + .bLength = sizeof dev_qualifier, +@@ -941,78 +584,6 @@ dev_qualifier = { + .bNumConfigurations = 1, + }; + +-static struct usb_endpoint_descriptor +-hs_bulk_in_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ +- .bmAttributes = USB_ENDPOINT_XFER_BULK, +- .wMaxPacketSize = cpu_to_le16(512), +-}; +- +-static struct usb_endpoint_descriptor +-hs_bulk_out_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ +- .bmAttributes = USB_ENDPOINT_XFER_BULK, +- .wMaxPacketSize = cpu_to_le16(512), +- .bInterval = 1, // NAK every 1 uframe +-}; +- +-static struct usb_endpoint_descriptor +-hs_intr_in_desc = { +- .bLength = USB_DT_ENDPOINT_SIZE, +- .bDescriptorType = USB_DT_ENDPOINT, +- +- /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ +- .bmAttributes = USB_ENDPOINT_XFER_INT, +- .wMaxPacketSize = cpu_to_le16(2), +- .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms +-}; +- +-static const struct usb_descriptor_header *hs_function[] = { +- (struct usb_descriptor_header *) &otg_desc, +- (struct usb_descriptor_header *) &intf_desc, +- (struct usb_descriptor_header *) &hs_bulk_in_desc, +- (struct usb_descriptor_header *) &hs_bulk_out_desc, +- (struct usb_descriptor_header *) &hs_intr_in_desc, +- NULL, +-}; +-#define HS_FUNCTION_PRE_EP_ENTRIES 2 +- +-/* Maxpacket and other transfer characteristics vary by speed. */ +-static struct usb_endpoint_descriptor * +-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, +- struct usb_endpoint_descriptor *hs) +-{ +- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) +- return hs; +- return fs; +-} +- +- +-/* The CBI specification limits the serial string to 12 uppercase hexadecimal +- * characters. */ +-static char manufacturer[64]; +-static char serial[13]; +- +-/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +-static struct usb_string strings[] = { +- {STRING_MANUFACTURER, manufacturer}, +- {STRING_PRODUCT, longname}, +- {STRING_SERIAL, serial}, +- {STRING_CONFIG, "Self-powered"}, +- {STRING_INTERFACE, "Mass Storage"}, +- {} +-}; +- +-static struct usb_gadget_strings stringtab = { +- .language = 0x0409, // en-us +- .strings = strings, +-}; + + + /* +@@ -1864,25 +1435,6 @@ static int do_write(struct fsg_dev *fsg) + + /*-------------------------------------------------------------------------*/ + +-/* Sync the file data, don't bother with the metadata. +- * This code was copied from fs/buffer.c:sys_fdatasync(). */ +-static int fsync_sub(struct lun *curlun) +-{ +- struct file *filp = curlun->filp; +- +- if (curlun->ro || !filp) +- return 0; +- return vfs_fsync(filp, filp->f_path.dentry, 1); +-} +- +-static void fsync_all(struct fsg_dev *fsg) +-{ +- int i; +- +- for (i = 0; i < fsg->nluns; ++i) +- fsync_sub(&fsg->luns[i]); +-} +- + static int do_synchronize_cache(struct fsg_dev *fsg) + { + struct lun *curlun = fsg->curlun; +@@ -2113,24 +1665,6 @@ static int do_read_capacity(struct fsg_d + } + + +-static void store_cdrom_address(u8 *dest, int msf, u32 addr) +-{ +- if (msf) { +- /* Convert to Minutes-Seconds-Frames */ +- addr >>= 2; /* Convert to 2048-byte frames */ +- addr += 2*75; /* Lead-in occupies 2 seconds */ +- dest[3] = addr % 75; /* Frames */ +- addr /= 75; +- dest[2] = addr % 60; /* Seconds */ +- addr /= 60; +- dest[1] = addr; /* Minutes */ +- dest[0] = 0; /* Reserved */ +- } else { +- /* Absolute sector */ +- put_unaligned_be32(addr, dest); +- } +-} +- + static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { + struct lun *curlun = fsg->curlun; +@@ -3506,7 +3040,8 @@ static void handle_exception(struct fsg_ + break; + + case FSG_STATE_DISCONNECT: +- fsync_all(fsg); ++ for (i = 0; i < fsg->nluns; ++i) ++ fsync_sub(fsg->luns + i); + do_set_config(fsg, 0); // Unconfigured state + break; + +@@ -3595,103 +3130,6 @@ static int fsg_main_thread(void *fsg_) + + /*-------------------------------------------------------------------------*/ + +-/* If the next two routines are called while the gadget is registered, +- * the caller must own fsg->filesem for writing. */ +- +-static int open_backing_file(struct lun *curlun, const char *filename) +-{ +- int ro; +- struct file *filp = NULL; +- int rc = -EINVAL; +- struct inode *inode = NULL; +- loff_t size; +- loff_t num_sectors; +- loff_t min_sectors; +- +- /* R/W if we can, R/O if we must */ +- ro = curlun->ro; +- if (!ro) { +- filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); +- if (-EROFS == PTR_ERR(filp)) +- ro = 1; +- } +- if (ro) +- filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); +- if (IS_ERR(filp)) { +- LINFO(curlun, "unable to open backing file: %s\n", filename); +- return PTR_ERR(filp); +- } +- +- if (!(filp->f_mode & FMODE_WRITE)) +- ro = 1; +- +- if (filp->f_path.dentry) +- inode = filp->f_path.dentry->d_inode; +- if (inode && S_ISBLK(inode->i_mode)) { +- if (bdev_read_only(inode->i_bdev)) +- ro = 1; +- } else if (!inode || !S_ISREG(inode->i_mode)) { +- LINFO(curlun, "invalid file type: %s\n", filename); +- goto out; +- } +- +- /* If we can't read the file, it's no good. +- * If we can't write the file, use it read-only. */ +- if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { +- LINFO(curlun, "file not readable: %s\n", filename); +- goto out; +- } +- if (!(filp->f_op->write || filp->f_op->aio_write)) +- ro = 1; +- +- size = i_size_read(inode->i_mapping->host); +- if (size < 0) { +- LINFO(curlun, "unable to find file size: %s\n", filename); +- rc = (int) size; +- goto out; +- } +- num_sectors = size >> 9; // File size in 512-byte blocks +- min_sectors = 1; +- if (mod_data.cdrom) { +- num_sectors &= ~3; // Reduce to a multiple of 2048 +- min_sectors = 300*4; // Smallest track is 300 frames +- if (num_sectors >= 256*60*75*4) { +- num_sectors = (256*60*75 - 1) * 4; +- LINFO(curlun, "file too big: %s\n", filename); +- LINFO(curlun, "using only first %d blocks\n", +- (int) num_sectors); +- } +- } +- if (num_sectors < min_sectors) { +- LINFO(curlun, "file too small: %s\n", filename); +- rc = -ETOOSMALL; +- goto out; +- } +- +- get_file(filp); +- curlun->ro = ro; +- curlun->filp = filp; +- curlun->file_length = size; +- curlun->num_sectors = num_sectors; +- LDBG(curlun, "open backing file: %s\n", filename); +- rc = 0; +- +-out: +- filp_close(filp, current->files); +- return rc; +-} +- +- +-static void close_backing_file(struct lun *curlun) +-{ +- if (curlun->filp) { +- LDBG(curlun, "close backing file\n"); +- fput(curlun->filp); +- curlun->filp = NULL; +- } +-} +- +- + static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) + { + struct lun *curlun = dev_to_lun(dev); +--- /dev/null ++++ b/drivers/usb/gadget/storage_common.c +@@ -0,0 +1,567 @@ ++/* ++ * storage_common.c -- Common definitions for mass storage functionality ++ * ++ * Copyright (C) 2003-2008 Alan Stern ++ * Copyeight (C) 2009 Samsung Electronics ++ * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) ++ */ ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++#ifndef DEBUG ++#undef VERBOSE_DEBUG ++#undef DUMP_MSGS ++#endif /* !DEBUG */ ++ ++#ifdef VERBOSE_DEBUG ++#define VLDBG LDBG ++#else ++#define VLDBG(lun, fmt, args...) do { } while (0) ++#endif /* VERBOSE_DEBUG */ ++ ++#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args) ++#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) ++#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) ++#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) ++ ++#define DBG(d, fmt, args...) dev_dbg (&(d)->gadget->dev, fmt, ## args) ++#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev, fmt, ## args) ++#define ERROR(d, fmt, args...) dev_err (&(d)->gadget->dev, fmt, ## args) ++#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev, fmt, ## args) ++#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev, fmt, ## args) ++ ++ ++ ++#ifdef DUMP_MSGS ++ ++# define dump_msg(fsg, /* const char * */ label, \ ++ /* const u8 * */ buf, /* unsigned */ length) do { \ ++ if (length < 512) { \ ++ DBG(fsg, "%s, length %u:\n", label, length); \ ++ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ ++ 16, 1, buf, length, 0); \ ++ } \ ++} while (0) ++ ++# define dump_cdb(fsg) do { } while (0) ++ ++#else ++ ++# define dump_msg(fsg, /* const char * */ label, \ ++ /* const u8 * */ buf, /* unsigned */ length) do { } while (0) ++ ++# ifdef VERBOSE_DEBUG ++ ++#define dump_cdb(fsg) \ ++ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ ++ 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ ++ ++# else ++ ++# define dump_cdb(fsg) do { } while (0) ++ ++# endif /* VERBOSE_DEBUG */ ++ ++#endif /* DUMP_MSGS */ ++ ++ ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* SCSI device types */ ++#define TYPE_DISK 0x00 ++#define TYPE_CDROM 0x05 ++ ++/* USB protocol value = the transport method */ ++#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt ++#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt ++#define USB_PR_BULK 0x50 // Bulk-only ++ ++/* USB subclass value = the protocol encapsulation */ ++#define USB_SC_RBC 0x01 // Reduced Block Commands (flash) ++#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM) ++#define USB_SC_QIC 0x03 // QIC-157 (tape) ++#define USB_SC_UFI 0x04 // UFI (floppy) ++#define USB_SC_8070 0x05 // SFF-8070i (removable) ++#define USB_SC_SCSI 0x06 // Transparent SCSI ++ ++/* Bulk-only data structures */ ++ ++/* Command Block Wrapper */ ++struct bulk_cb_wrap { ++ __le32 Signature; // Contains 'USBC' ++ u32 Tag; // Unique per command id ++ __le32 DataTransferLength; // Size of the data ++ u8 Flags; // Direction in bit 7 ++ u8 Lun; // LUN (normally 0) ++ u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE ++ u8 CDB[16]; // Command Data Block ++}; ++ ++#define USB_BULK_CB_WRAP_LEN 31 ++#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC ++#define USB_BULK_IN_FLAG 0x80 ++ ++/* Command Status Wrapper */ ++struct bulk_cs_wrap { ++ __le32 Signature; // Should = 'USBS' ++ u32 Tag; // Same as original command ++ __le32 Residue; // Amount not transferred ++ u8 Status; // See below ++}; ++ ++#define USB_BULK_CS_WRAP_LEN 13 ++#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS' ++#define USB_STATUS_PASS 0 ++#define USB_STATUS_FAIL 1 ++#define USB_STATUS_PHASE_ERROR 2 ++ ++/* Bulk-only class specific requests */ ++#define USB_BULK_RESET_REQUEST 0xff ++#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe ++ ++ ++/* CBI Interrupt data structure */ ++struct interrupt_data { ++ u8 bType; ++ u8 bValue; ++}; ++ ++#define CBI_INTERRUPT_DATA_LEN 2 ++ ++/* CBI Accept Device-Specific Command request */ ++#define USB_CBI_ADSC_REQUEST 0x00 ++ ++ ++#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block ++ ++/* SCSI commands that we recognize */ ++#define SC_FORMAT_UNIT 0x04 ++#define SC_INQUIRY 0x12 ++#define SC_MODE_SELECT_6 0x15 ++#define SC_MODE_SELECT_10 0x55 ++#define SC_MODE_SENSE_6 0x1a ++#define SC_MODE_SENSE_10 0x5a ++#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e ++#define SC_READ_6 0x08 ++#define SC_READ_10 0x28 ++#define SC_READ_12 0xa8 ++#define SC_READ_CAPACITY 0x25 ++#define SC_READ_FORMAT_CAPACITIES 0x23 ++#define SC_READ_HEADER 0x44 ++#define SC_READ_TOC 0x43 ++#define SC_RELEASE 0x17 ++#define SC_REQUEST_SENSE 0x03 ++#define SC_RESERVE 0x16 ++#define SC_SEND_DIAGNOSTIC 0x1d ++#define SC_START_STOP_UNIT 0x1b ++#define SC_SYNCHRONIZE_CACHE 0x35 ++#define SC_TEST_UNIT_READY 0x00 ++#define SC_VERIFY 0x2f ++#define SC_WRITE_6 0x0a ++#define SC_WRITE_10 0x2a ++#define SC_WRITE_12 0xaa ++ ++/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ ++#define SS_NO_SENSE 0 ++#define SS_COMMUNICATION_FAILURE 0x040800 ++#define SS_INVALID_COMMAND 0x052000 ++#define SS_INVALID_FIELD_IN_CDB 0x052400 ++#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 ++#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 ++#define SS_MEDIUM_NOT_PRESENT 0x023a00 ++#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 ++#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 ++#define SS_RESET_OCCURRED 0x062900 ++#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 ++#define SS_UNRECOVERED_READ_ERROR 0x031100 ++#define SS_WRITE_ERROR 0x030c02 ++#define SS_WRITE_PROTECTED 0x072700 ++ ++#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. ++#define ASC(x) ((u8) ((x) >> 8)) ++#define ASCQ(x) ((u8) (x)) ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++struct lun { ++ struct file *filp; ++ loff_t file_length; ++ loff_t num_sectors; ++ ++ unsigned int ro : 1; ++ unsigned int prevent_medium_removal : 1; ++ unsigned int registered : 1; ++ unsigned int info_valid : 1; ++ ++ u32 sense_data; ++ u32 sense_data_info; ++ u32 unit_attention_data; ++ ++ struct device dev; ++}; ++ ++#define backing_file_is_open(curlun) ((curlun)->filp != NULL) ++ ++static struct lun *dev_to_lun(struct device *dev) ++{ ++ return container_of(dev, struct lun, dev); ++} ++ ++ ++/* Big enough to hold our biggest descriptor */ ++#define EP0_BUFSIZE 256 ++#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value ++ ++/* Number of buffers we will use. 2 is enough for double-buffering */ ++#define NUM_BUFFERS 2 ++ ++enum fsg_buffer_state { ++ BUF_STATE_EMPTY = 0, ++ BUF_STATE_FULL, ++ BUF_STATE_BUSY ++}; ++ ++struct fsg_buffhd { ++ void *buf; ++ enum fsg_buffer_state state; ++ struct fsg_buffhd *next; ++ ++ /* The NetChip 2280 is faster, and handles some protocol faults ++ * better, if we don't submit any short bulk-out read requests. ++ * So we will record the intended request length here. */ ++ unsigned int bulk_out_intended_length; ++ ++ struct usb_request *inreq; ++ int inreq_busy; ++ struct usb_request *outreq; ++ int outreq_busy; ++}; ++ ++enum fsg_state { ++ FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere ++ FSG_STATE_DATA_PHASE, ++ FSG_STATE_STATUS_PHASE, ++ ++ FSG_STATE_IDLE = 0, ++ FSG_STATE_ABORT_BULK_OUT, ++ FSG_STATE_RESET, ++ FSG_STATE_INTERFACE_CHANGE, ++ FSG_STATE_CONFIG_CHANGE, ++ FSG_STATE_DISCONNECT, ++ FSG_STATE_EXIT, ++ FSG_STATE_TERMINATED ++}; ++ ++enum data_direction { ++ DATA_DIR_UNKNOWN = 0, ++ DATA_DIR_FROM_HOST, ++ DATA_DIR_TO_HOST, ++ DATA_DIR_NONE ++}; ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++static inline u32 get_unaligned_be24(u8 *buf) ++{ ++ return 0xffffff & (u32) get_unaligned_be32(buf - 1); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++#define STRING_MANUFACTURER 1 ++#define STRING_PRODUCT 2 ++#define STRING_SERIAL 3 ++#define STRING_CONFIG 4 ++#define STRING_INTERFACE 5 ++ ++ ++static struct usb_otg_descriptor ++otg_desc = { ++ .bLength = sizeof(otg_desc), ++ .bDescriptorType = USB_DT_OTG, ++ ++ .bmAttributes = USB_OTG_SRP, ++}; ++ ++/* There is only one interface. */ ++ ++static struct usb_interface_descriptor ++intf_desc = { ++ .bLength = sizeof intf_desc, ++ .bDescriptorType = USB_DT_INTERFACE, ++ ++ .bNumEndpoints = 2, // Adjusted during fsg_bind() ++ .bInterfaceClass = USB_CLASS_MASS_STORAGE, ++ .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() ++ .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() ++ .iInterface = STRING_INTERFACE, ++}; ++ ++/* Three full-speed endpoint descriptors: bulk-in, bulk-out, ++ * and interrupt-in. */ ++ ++static struct usb_endpoint_descriptor ++fs_bulk_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ /* wMaxPacketSize set by autoconfiguration */ ++}; ++ ++static struct usb_endpoint_descriptor ++fs_bulk_out_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_OUT, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ /* wMaxPacketSize set by autoconfiguration */ ++}; ++ ++static struct usb_endpoint_descriptor ++fs_intr_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(2), ++ .bInterval = 32, // frames -> 32 ms ++}; ++ ++static const struct usb_descriptor_header *fs_function[] = { ++ (struct usb_descriptor_header *) &otg_desc, ++ (struct usb_descriptor_header *) &intf_desc, ++ (struct usb_descriptor_header *) &fs_bulk_in_desc, ++ (struct usb_descriptor_header *) &fs_bulk_out_desc, ++ (struct usb_descriptor_header *) &fs_intr_in_desc, ++ NULL, ++}; ++#define FS_FUNCTION_PRE_EP_ENTRIES 2 ++ ++ ++/* ++ * USB 2.0 devices need to expose both high speed and full speed ++ * descriptors, unless they only run at full speed. ++ * ++ * That means alternate endpoint descriptors (bigger packets) ++ * and a "device qualifier" ... plus more construction options ++ * for the config descriptor. ++ */ ++static struct usb_endpoint_descriptor ++hs_bulk_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = cpu_to_le16(512), ++}; ++ ++static struct usb_endpoint_descriptor ++hs_bulk_out_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = cpu_to_le16(512), ++ .bInterval = 1, // NAK every 1 uframe ++}; ++ ++static struct usb_endpoint_descriptor ++hs_intr_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(2), ++ .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms ++}; ++ ++static const struct usb_descriptor_header *hs_function[] = { ++ (struct usb_descriptor_header *) &otg_desc, ++ (struct usb_descriptor_header *) &intf_desc, ++ (struct usb_descriptor_header *) &hs_bulk_in_desc, ++ (struct usb_descriptor_header *) &hs_bulk_out_desc, ++ (struct usb_descriptor_header *) &hs_intr_in_desc, ++ NULL, ++}; ++#define HS_FUNCTION_PRE_EP_ENTRIES 2 ++ ++/* Maxpacket and other transfer characteristics vary by speed. */ ++static struct usb_endpoint_descriptor * ++ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, ++ struct usb_endpoint_descriptor *hs) ++{ ++ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) ++ return hs; ++ return fs; ++} ++ ++ ++/* The CBI specification limits the serial string to 12 uppercase hexadecimal ++ * characters. */ ++static char manufacturer[64]; ++static char serial[13]; ++ ++/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ ++static struct usb_string strings[] = { ++ {STRING_MANUFACTURER, manufacturer}, ++ {STRING_PRODUCT, longname}, ++ {STRING_SERIAL, serial}, ++ {STRING_CONFIG, "Self-powered"}, ++ {STRING_INTERFACE, "Mass Storage"}, ++ {} ++}; ++ ++static struct usb_gadget_strings stringtab = { ++ .language = 0x0409, // en-us ++ .strings = strings, ++}; ++ ++ ++ /*-------------------------------------------------------------------------*/ ++ ++/* If the next two routines are called while the gadget is registered, ++ * the caller must own fsg->filesem for writing. */ ++ ++static int open_backing_file(struct lun *curlun, const char *filename) ++{ ++ int ro; ++ struct file *filp = NULL; ++ int rc = -EINVAL; ++ struct inode *inode = NULL; ++ loff_t size; ++ loff_t num_sectors; ++ loff_t min_sectors; ++ ++ /* R/W if we can, R/O if we must */ ++ ro = curlun->ro; ++ if (!ro) { ++ filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); ++ if (-EROFS == PTR_ERR(filp)) ++ ro = 1; ++ } ++ if (ro) ++ filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); ++ if (IS_ERR(filp)) { ++ LINFO(curlun, "unable to open backing file: %s\n", filename); ++ return PTR_ERR(filp); ++ } ++ ++ if (!(filp->f_mode & FMODE_WRITE)) ++ ro = 1; ++ ++ if (filp->f_path.dentry) ++ inode = filp->f_path.dentry->d_inode; ++ if (inode && S_ISBLK(inode->i_mode)) { ++ if (bdev_read_only(inode->i_bdev)) ++ ro = 1; ++ } else if (!inode || !S_ISREG(inode->i_mode)) { ++ LINFO(curlun, "invalid file type: %s\n", filename); ++ goto out; ++ } ++ ++ /* If we can't read the file, it's no good. ++ * If we can't write the file, use it read-only. */ ++ if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { ++ LINFO(curlun, "file not readable: %s\n", filename); ++ goto out; ++ } ++ if (!(filp->f_op->write || filp->f_op->aio_write)) ++ ro = 1; ++ ++ size = i_size_read(inode->i_mapping->host); ++ if (size < 0) { ++ LINFO(curlun, "unable to find file size: %s\n", filename); ++ rc = (int) size; ++ goto out; ++ } ++ num_sectors = size >> 9; // File size in 512-byte blocks ++ min_sectors = 1; ++ if (mod_data.cdrom) { ++ num_sectors &= ~3; // Reduce to a multiple of 2048 ++ min_sectors = 300*4; // Smallest track is 300 frames ++ if (num_sectors >= 256*60*75*4) { ++ num_sectors = (256*60*75 - 1) * 4; ++ LINFO(curlun, "file too big: %s\n", filename); ++ LINFO(curlun, "using only first %d blocks\n", ++ (int) num_sectors); ++ } ++ } ++ if (num_sectors < min_sectors) { ++ LINFO(curlun, "file too small: %s\n", filename); ++ rc = -ETOOSMALL; ++ goto out; ++ } ++ ++ get_file(filp); ++ curlun->ro = ro; ++ curlun->filp = filp; ++ curlun->file_length = size; ++ curlun->num_sectors = num_sectors; ++ LDBG(curlun, "open backing file: %s\n", filename); ++ rc = 0; ++ ++out: ++ filp_close(filp, current->files); ++ return rc; ++} ++ ++ ++static void close_backing_file(struct lun *curlun) ++{ ++ if (curlun->filp) { ++ LDBG(curlun, "close backing file\n"); ++ fput(curlun->filp); ++ curlun->filp = NULL; ++ } ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Sync the file data, don't bother with the metadata. ++ * This code was copied from fs/buffer.c:sys_fdatasync(). */ ++static int fsync_sub(struct lun *curlun) ++{ ++ struct file *filp = curlun->filp; ++ ++ if (curlun->ro || !filp) ++ return 0; ++ return vfs_fsync(filp, filp->f_path.dentry, 1); ++} ++ ++static void store_cdrom_address(u8 *dest, int msf, u32 addr) ++{ ++ if (msf) { ++ /* Convert to Minutes-Seconds-Frames */ ++ addr >>= 2; /* Convert to 2048-byte frames */ ++ addr += 2*75; /* Lead-in occupies 2 seconds */ ++ dest[3] = addr % 75; /* Frames */ ++ addr /= 75; ++ dest[2] = addr % 60; /* Seconds */ ++ addr /= 60; ++ dest[1] = addr; /* Minutes */ ++ dest[0] = 0; /* Reserved */ ++ } else { ++ /* Absolute sector */ ++ put_unaligned_be32(addr, dest); ++ } ++} diff --git a/usb/usb-g_file_storage-per-lun-ro-removable-and-cdrom-flags-handling-changed.patch b/usb/usb-g_file_storage-per-lun-ro-removable-and-cdrom-flags-handling-changed.patch new file mode 100644 index 00000000000000..d9a5f3e22f4bbe --- /dev/null +++ b/usb/usb-g_file_storage-per-lun-ro-removable-and-cdrom-flags-handling-changed.patch @@ -0,0 +1,95 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:41:51 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:16 +0100 +Subject: USB: g_file_storage: per-LUN ro, removable and cdrom flags handling changed +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <574b69a65f0c5aae640ab5fe28e57b0a0a3e1676.1256745228.git.m.nazarewicz@samsung.com> + + +removable and cdrom flag has been added to the fsg_lun structure +removing any references to mod_data object from storage_common.c. + +As of read-only flag, previously it was set if a read-only +backing file was specified (which is good) and remained set +even after the file has been closed (which may be considered an +issue). Currently, the initial read-only flag is preserved so +if it was unset each time file is opened code will try to open +it read-write even if previous file was opened read-only. + +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> + +--- + drivers/usb/gadget/file_storage.c | 12 ++++++++---- + drivers/usb/gadget/storage_common.c | 7 +++++-- + 2 files changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -3138,7 +3138,9 @@ static ssize_t show_ro(struct device *de + { + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + +- return sprintf(buf, "%d\n", curlun->ro); ++ return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) ++ ? curlun->ro ++ : curlun->initially_ro); + } + + static ssize_t show_file(struct device *dev, struct device_attribute *attr, +@@ -3188,6 +3190,7 @@ static ssize_t store_ro(struct device *d + rc = -EBUSY; + } else { + curlun->ro = !!i; ++ curlun->initially_ro = !!i; + LDBG(curlun, "read-only status set to %d\n", curlun->ro); + } + up_read(&fsg->filesem); +@@ -3433,9 +3436,10 @@ static int __init fsg_bind(struct usb_ga + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; +- curlun->ro = mod_data.ro[i]; +- if (mod_data.cdrom) +- curlun->ro = 1; ++ curlun->cdrom = !!mod_data.cdrom; ++ curlun->ro = mod_data.cdrom || mod_data.ro[i]; ++ curlun->initially_ro = curlun->ro; ++ curlun->removable = mod_data.removable; + curlun->dev.release = lun_release; + curlun->dev.parent = &gadget->dev; + curlun->dev.driver = &fsg_driver.driver; +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -225,7 +225,10 @@ struct fsg_lun { + loff_t file_length; + loff_t num_sectors; + ++ unsigned int initially_ro : 1; + unsigned int ro : 1; ++ unsigned int removable : 1; ++ unsigned int cdrom : 1; + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + unsigned int info_valid : 1; +@@ -478,7 +481,7 @@ static int fsg_lun_open(struct fsg_lun * + loff_t min_sectors; + + /* R/W if we can, R/O if we must */ +- ro = curlun->ro; ++ ro = curlun->initially_ro; + if (!ro) { + filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); + if (-EROFS == PTR_ERR(filp)) +@@ -521,7 +524,7 @@ static int fsg_lun_open(struct fsg_lun * + } + num_sectors = size >> 9; // File size in 512-byte blocks + min_sectors = 1; +- if (mod_data.cdrom) { ++ if (curlun->cdrom) { + num_sectors &= ~3; // Reduce to a multiple of 2048 + min_sectors = 300*4; // Smallest track is 300 frames + if (num_sectors >= 256*60*75*4) { diff --git a/usb/usb-g_mass_storage-constant-length-buffers-used.patch b/usb/usb-g_mass_storage-constant-length-buffers-used.patch new file mode 100644 index 00000000000000..1b6f01ebdb73ab --- /dev/null +++ b/usb/usb-g_mass_storage-constant-length-buffers-used.patch @@ -0,0 +1,127 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:43:08 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:21 +0100 +Subject: USB: g_mass_storage: constant length buffers used +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <9684085ca293823f2789d23e50eff8b03bec6c43.1256745228.git.m.nazarewicz@samsung.com> + + +Using version of fsg_buffhd structure with buf field being an +array of characters with predefined size. Since mass storage +function does not define changing buffer size on run-time it is +not required for the field to be a pointer to void and allocating +space dynamically. + +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> +--- + drivers/usb/gadget/f_mass_storage.c | 31 +++++++++++-------------------- + drivers/usb/gadget/storage_common.c | 10 ++++++++++ + 2 files changed, 21 insertions(+), 20 deletions(-) + +--- a/drivers/usb/gadget/f_mass_storage.c ++++ b/drivers/usb/gadget/f_mass_storage.c +@@ -258,6 +258,7 @@ static const char fsg_string_interface[] + + + #define FSG_NO_INTR_EP 1 ++#define FSG_BUFFHD_STATIC_BUFFER 1 + + #include "storage_common.c" + +@@ -1894,9 +1895,8 @@ static int send_status(struct fsg_dev *f + SK(sd), ASC(sd), ASCQ(sd), sdinfo); + } + +- + /* Store and send the Bulk-only CSW */ +- csw = bh->buf; ++ csw = (void*)bh->buf; + + csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); + csw->Tag = fsg->tag; +@@ -2808,10 +2808,6 @@ static void /* __init_or_exit */ fsg_unb + complete(&fsg->thread_notifier); + } + +- /* Free the data buffers */ +- for (i = 0; i < FSG_NUM_BUFFERS; ++i) +- kfree(fsg->common->buffhds[i].buf); +- + /* Free the request and buffer for endpoint 0 */ + if (req) { + kfree(req->buf); +@@ -2978,20 +2974,6 @@ static int __init fsg_bind(struct usb_ga + goto out; + req->complete = ep0_complete; + +- /* Allocate the data buffers */ +- for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- struct fsg_buffhd *bh = &fsg->common->buffhds[i]; +- +- /* Allocate for the bulk-in endpoint. We assume that +- * the buffer will also work with the bulk-out (and +- * interrupt-in) endpoint. */ +- bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); +- if (!bh->buf) +- goto out; +- bh->next = bh + 1; +- } +- fsg->common->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->common->buffhds[0]; +- + /* This should reflect the actual gadget power source */ + usb_gadget_set_selfpowered(gadget); + +@@ -3087,6 +3069,8 @@ static struct usb_gadget_driver fsg_dri + static int __init fsg_alloc(void) + { + struct fsg_dev *fsg; ++ struct fsg_buffhd *bh; ++ unsigned i; + + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + if (!fsg) +@@ -3098,6 +3082,13 @@ static int __init fsg_alloc(void) + return -ENOMEM; + } + ++ bh = fsg->common->buffhds; ++ i = FSG_NUM_BUFFERS - 1; ++ do { ++ bh->next = bh + 1; ++ } while (++bh, --i); ++ bh->next = fsg->common->buffhds; ++ + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->common->filesem); + init_completion(&fsg->thread_notifier); +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -47,6 +47,12 @@ + * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. + */ + ++/* ++ * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included ++ * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN ++ * characters rather then a pointer to void. ++ */ ++ + + #include <asm/unaligned.h> + +@@ -290,7 +296,11 @@ enum fsg_buffer_state { + }; + + struct fsg_buffhd { ++#ifdef FSG_BUFFHD_STATIC_BUFFER ++ char buf[FSG_BUFLEN]; ++#else + void *buf; ++#endif + enum fsg_buffer_state state; + struct fsg_buffhd *next; + diff --git a/usb/usb-g_mass_storage-fsg_common_init-created.patch b/usb/usb-g_mass_storage-fsg_common_init-created.patch new file mode 100644 index 00000000000000..2b29372553f75e --- /dev/null +++ b/usb/usb-g_mass_storage-fsg_common_init-created.patch @@ -0,0 +1,511 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:43:21 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:22 +0100 +Subject: USB: g_mass_storage: fsg_common_init() created +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <7125966df6e9d532ef4dcaf148e69a310f793824.1256745228.git.m.nazarewicz@samsung.com> + + +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> +--- + drivers/usb/gadget/f_mass_storage.c | 361 +++++++++++++++++++----------------- + 1 file changed, 199 insertions(+), 162 deletions(-) + +--- 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 + + /* Data shared by all the FSG instances. */ + struct fsg_common { ++ struct usb_gadget *gadget; ++ + /* filesem protects: backing files in use */ + struct rw_semaphore filesem; + +@@ -337,6 +339,10 @@ struct fsg_common { + unsigned int lun; + struct fsg_lun *luns; + struct fsg_lun *curlun; ++ ++ unsigned int free_storage_on_release:1; ++ ++ struct kref ref; + }; + + +@@ -347,9 +353,6 @@ struct fsg_dev { + spinlock_t lock; + struct usb_gadget *gadget; + +- /* reference counting: wait until all LUNs are released */ +- struct kref ref; +- + struct usb_ep *ep0; // Handy copy of gadget->ep0 + struct usb_request *ep0req; // For control responses + unsigned int ep0_req_tag; +@@ -2757,7 +2760,7 @@ static int fsg_main_thread(void *fsg_) + } + + +-/*-------------------------------------------------------------------------*/ ++/*************************** DEVICE ATTRIBUTES ***************************/ + + + /* The write permissions and store_xxx pointers are set in fsg_bind() */ +@@ -2765,92 +2768,214 @@ static DEVICE_ATTR(ro, 0444, fsg_show_ro + static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); + + +-/*-------------------------------------------------------------------------*/ ++/****************************** FSG COMMON ******************************/ ++ ++static void fsg_common_release(struct kref *ref); + +-static void fsg_release(struct fsg_dev *fsg) ++static void fsg_lun_release(struct device *dev) + { +- kfree(fsg->common->luns); +- kfree(fsg); ++ /* Nothing needs to be done */ + } + +-static void lun_release(struct device *dev) ++static inline void fsg_common_get(struct fsg_common *common) + { ++ kref_get(&common->ref); + } + +-static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) ++static inline void fsg_common_put(struct fsg_common *common) + { +- struct fsg_dev *fsg = get_gadget_data(gadget); +- int i; +- struct fsg_lun *curlun; +- struct usb_request *req = fsg->ep0req; ++ kref_put(&common->ref, fsg_common_release); ++} + +- DBG(fsg, "unbind\n"); +- clear_bit(REGISTERED, &fsg->atomic_bitflags); + +- /* Unregister the sysfs attribute files and the LUNs */ +- for (i = 0; i < fsg->common->nluns; ++i) { +- curlun = &fsg->common->luns[i]; +- if (curlun->registered) { +- device_remove_file(&curlun->dev, &dev_attr_ro); +- device_remove_file(&curlun->dev, &dev_attr_file); +- fsg_lun_close(curlun); +- device_unregister(&curlun->dev); +- curlun->registered = 0; +- } +- } ++static struct fsg_common *fsg_common_init(struct fsg_common *common, ++ struct usb_gadget *gadget) ++{ ++ struct fsg_buffhd *bh; ++ struct fsg_lun *curlun; ++ int nluns, i, rc; + +- /* If the thread isn't already dead, tell it to exit now */ +- if (fsg->state != FSG_STATE_TERMINATED) { +- raise_exception(fsg, FSG_STATE_EXIT); +- wait_for_completion(&fsg->thread_notifier); ++ /* Find out how many LUNs there should be */ ++ nluns = mod_data.nluns; ++ if (nluns == 0) ++ nluns = max(mod_data.num_filenames, 1u); ++ if (nluns < 1 || nluns > FSG_MAX_LUNS) { ++ dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); ++ return ERR_PTR(-EINVAL); ++ } + +- /* The cleanup routine waits for this completion also */ +- complete(&fsg->thread_notifier); ++ /* Allocate? */ ++ if (!common) { ++ common = kzalloc(sizeof *common, GFP_KERNEL); ++ if (!common) ++ return ERR_PTR(-ENOMEM); ++ common->free_storage_on_release = 1; ++ } else { ++ memset(common, 0, sizeof common); ++ common->free_storage_on_release = 0; + } ++ common->gadget = gadget; + +- /* Free the request and buffer for endpoint 0 */ +- if (req) { +- kfree(req->buf); +- usb_ep_free_request(fsg->ep0, req); ++ /* Create the LUNs, open their backing files, and register the ++ * LUN devices in sysfs. */ ++ curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); ++ if (!curlun) { ++ kfree(common); ++ return ERR_PTR(-ENOMEM); + } ++ common->luns = curlun; + +- set_gadget_data(gadget, NULL); +-} ++ init_rwsem(&common->filesem); + ++ for (i = 0; i < nluns; ++i, ++curlun) { ++ curlun->cdrom = !!mod_data.cdrom; ++ curlun->ro = mod_data.cdrom || mod_data.ro[i]; ++ curlun->removable = mod_data.removable; ++ curlun->dev.release = fsg_lun_release; ++ curlun->dev.parent = &gadget->dev; ++ curlun->dev.driver = &fsg_driver.driver; ++ dev_set_drvdata(&curlun->dev, &common->filesem); ++ dev_set_name(&curlun->dev,"%s-lun%d", ++ dev_name(&gadget->dev), i); + +-static int __init check_parameters(struct fsg_dev *fsg) +-{ +- int gcnum; ++ rc = device_register(&curlun->dev); ++ if (rc) { ++ INFO(common, "failed to register LUN%d: %d\n", i, rc); ++ common->nluns = i; ++ goto error_release; ++ } ++ ++ rc = device_create_file(&curlun->dev, &dev_attr_ro); ++ if (rc) ++ goto error_luns; ++ rc = device_create_file(&curlun->dev, &dev_attr_file); ++ if (rc) ++ goto error_luns; ++ ++ if (mod_data.file[i] && *mod_data.file[i]) { ++ rc = fsg_lun_open(curlun, mod_data.file[i]); ++ if (rc) ++ goto error_luns; ++ } else if (!mod_data.removable) { ++ ERROR(common, "no file given for LUN%d\n", i); ++ rc = -EINVAL; ++ goto error_luns; ++ } ++ } ++ common->nluns = nluns; ++ ++ ++ /* Data buffers cyclic list */ ++ /* Buffers in buffhds are static -- no need for additional ++ * allocation. */ ++ bh = common->buffhds; ++ i = FSG_NUM_BUFFERS - 1; ++ do { ++ bh->next = bh + 1; ++ } while (++bh, --i); ++ bh->next = common->buffhds; + +- /* Some peripheral controllers are known not to be able to +- * halt bulk endpoints correctly. If one of them is present, +- * disable stalls. +- */ +- if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) +- mod_data.can_stall = 0; + ++ /* Release */ + if (mod_data.release == 0xffff) { // Parameter wasn't set ++ int gcnum; ++ + /* The sa1100 controller is not supported */ +- if (gadget_is_sa1100(fsg->gadget)) ++ if (gadget_is_sa1100(gadget)) + gcnum = -1; + else +- gcnum = usb_gadget_controller_number(fsg->gadget); ++ gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) + mod_data.release = 0x0300 + gcnum; + else { +- WARNING(fsg, "controller '%s' not recognized\n", +- fsg->gadget->name); ++ WARNING(common, "controller '%s' not recognized\n", ++ gadget->name); ++ WARNING(common, "controller '%s' not recognized\n", ++ gadget->name); + mod_data.release = 0x0399; + } + } + +- return 0; ++ ++ /* Some peripheral controllers are known not to be able to ++ * halt bulk endpoints correctly. If one of them is present, ++ * disable stalls. ++ */ ++ if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) ++ mod_data.can_stall = 0; ++ ++ ++ kref_init(&common->ref); ++ return common; ++ ++ ++error_luns: ++ common->nluns = i + 1; ++error_release: ++ /* Call fsg_common_release() directly, ref is not initialised */ ++ fsg_common_release(&common->ref); ++ return ERR_PTR(rc); ++} ++ ++ ++static void fsg_common_release(struct kref *ref) ++{ ++ struct fsg_common *common = ++ container_of(ref, struct fsg_common, ref); ++ unsigned i = common->nluns; ++ struct fsg_lun *lun = common->luns; ++ ++ /* Beware tempting for -> do-while optimization: when in error ++ * recovery nluns may be zero. */ ++ ++ for (; i; --i, ++lun) { ++ device_remove_file(&lun->dev, &dev_attr_ro); ++ device_remove_file(&lun->dev, &dev_attr_file); ++ fsg_lun_close(lun); ++ device_unregister(&lun->dev); ++ } ++ ++ kfree(common->luns); ++ if (common->free_storage_on_release) ++ kfree(common); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ struct usb_request *req = fsg->ep0req; ++ ++ DBG(fsg, "unbind\n"); ++ clear_bit(REGISTERED, &fsg->atomic_bitflags); ++ ++ /* If the thread isn't already dead, tell it to exit now */ ++ if (fsg->state != FSG_STATE_TERMINATED) { ++ raise_exception(fsg, FSG_STATE_EXIT); ++ wait_for_completion(&fsg->thread_notifier); ++ ++ /* The cleanup routine waits for this completion also */ ++ complete(&fsg->thread_notifier); ++ } ++ ++ /* Free the request and buffer for endpoint 0 */ ++ if (req) { ++ kfree(req->buf); ++ usb_ep_free_request(fsg->ep0, req); ++ } ++ ++ fsg_common_put(fsg->common); ++ kfree(fsg); ++ set_gadget_data(gadget, NULL); + } + + + static int __init fsg_bind(struct usb_gadget *gadget) + { +- struct fsg_dev *fsg = the_fsg; ++ struct fsg_dev *fsg; + int rc; + int i; + struct fsg_lun *curlun; +@@ -2858,15 +2983,27 @@ static int __init fsg_bind(struct usb_ga + struct usb_request *req; + char *pathbuf, *p; + ++ /* Allocate */ ++ fsg = kzalloc(sizeof *fsg, GFP_KERNEL); ++ if (!fsg) ++ return -ENOMEM; ++ ++ /* Initialise common */ ++ fsg->common = fsg_common_init(0, gadget); ++ if (IS_ERR(fsg->common)) ++ return PTR_ERR(fsg->common); ++ ++ /* Basic parameters */ + fsg->gadget = gadget; + set_gadget_data(gadget, fsg); + fsg->ep0 = gadget->ep0; + fsg->ep0->driver_data = fsg; + +- if ((rc = check_parameters(fsg)) != 0) +- goto out; ++ spin_lock_init(&fsg->lock); ++ init_completion(&fsg->thread_notifier); + +- if (mod_data.removable) { // Enable the store_xxx attributes ++ /* Enable the store_xxx attributes */ ++ if (mod_data.removable) { + dev_attr_file.attr.mode = 0644; + dev_attr_file.store = fsg_store_file; + if (!mod_data.cdrom) { +@@ -2875,62 +3012,6 @@ static int __init fsg_bind(struct usb_ga + } + } + +- /* Find out how many LUNs there should be */ +- i = mod_data.nluns; +- if (i == 0) +- i = max(mod_data.num_filenames, 1u); +- if (i > FSG_MAX_LUNS) { +- ERROR(fsg, "invalid number of LUNs: %d\n", i); +- rc = -EINVAL; +- goto out; +- } +- +- /* Create the LUNs, open their backing files, and register the +- * LUN devices in sysfs. */ +- fsg->common->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); +- if (!fsg->common->luns) { +- rc = -ENOMEM; +- goto out; +- } +- fsg->common->nluns = i; +- +- for (i = 0; i < fsg->common->nluns; ++i) { +- curlun = &fsg->common->luns[i]; +- curlun->cdrom = !!mod_data.cdrom; +- curlun->ro = mod_data.cdrom || mod_data.ro[i]; +- curlun->initially_ro = curlun->ro; +- curlun->removable = mod_data.removable; +- curlun->dev.release = lun_release; +- curlun->dev.parent = &gadget->dev; +- curlun->dev.driver = &fsg_driver.driver; +- dev_set_drvdata(&curlun->dev, &fsg->common->filesem); +- dev_set_name(&curlun->dev,"%s-lun%d", +- dev_name(&gadget->dev), i); +- +- if ((rc = device_register(&curlun->dev)) != 0) { +- INFO(fsg, "failed to register LUN%d: %d\n", i, rc); +- goto out; +- } +- if ((rc = device_create_file(&curlun->dev, +- &dev_attr_ro)) != 0 || +- (rc = device_create_file(&curlun->dev, +- &dev_attr_file)) != 0) { +- device_unregister(&curlun->dev); +- goto out; +- } +- curlun->registered = 1; +- +- if (mod_data.file[i] && *mod_data.file[i]) { +- if ((rc = fsg_lun_open(curlun, +- mod_data.file[i])) != 0) +- goto out; +- } else if (!mod_data.removable) { +- ERROR(fsg, "no file given for LUN%d\n", i); +- rc = -EINVAL; +- goto out; +- } +- } +- + /* Find all the endpoints we will use */ + usb_ep_autoconfig_reset(gadget); + ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); +@@ -3028,6 +3109,8 @@ static int __init fsg_bind(struct usb_ga + + /* Tell the thread to start working */ + wake_up_process(fsg->thread_task); ++ ++ the_fsg = fsg; + return 0; + + autoconf_fail: +@@ -3066,64 +3149,18 @@ static struct usb_gadget_driver fsg_dri + }; + + +-static int __init fsg_alloc(void) +-{ +- struct fsg_dev *fsg; +- struct fsg_buffhd *bh; +- unsigned i; +- +- fsg = kzalloc(sizeof *fsg, GFP_KERNEL); +- if (!fsg) +- return -ENOMEM; +- +- fsg->common = kzalloc(sizeof *fsg->common, GFP_KERNEL); +- if (!fsg->common) { +- kfree(fsg); +- return -ENOMEM; +- } +- +- bh = fsg->common->buffhds; +- i = FSG_NUM_BUFFERS - 1; +- do { +- bh->next = bh + 1; +- } while (++bh, --i); +- bh->next = fsg->common->buffhds; +- +- spin_lock_init(&fsg->lock); +- init_rwsem(&fsg->common->filesem); +- init_completion(&fsg->thread_notifier); +- +- the_fsg = fsg; +- return 0; +-} +- +- + static int __init fsg_init(void) + { +- int rc; +- struct fsg_dev *fsg; +- +- if ((rc = fsg_alloc()) != 0) +- return rc; +- fsg = the_fsg; +- if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) +- fsg_release(fsg); +- return rc; ++ return usb_gadget_register_driver(&fsg_driver); + } + module_init(fsg_init); + + + static void __exit fsg_cleanup(void) + { +- struct fsg_dev *fsg = the_fsg; +- + /* Unregister the driver iff the thread hasn't already done so */ +- if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) ++ if (the_fsg && ++ test_and_clear_bit(REGISTERED, &the_fsg->atomic_bitflags)) + usb_gadget_unregister_driver(&fsg_driver); +- +- /* Wait for the thread to finish up */ +- wait_for_completion(&fsg->thread_notifier); +- +- fsg_release(fsg); + } + module_exit(fsg_cleanup); diff --git a/usb/usb-g_mass_storage-parts-of-fsg_dev-moved-to-fsg_common-structure.patch b/usb/usb-g_mass_storage-parts-of-fsg_dev-moved-to-fsg_common-structure.patch new file mode 100644 index 00000000000000..e011c57a7ad693 --- /dev/null +++ b/usb/usb-g_mass_storage-parts-of-fsg_dev-moved-to-fsg_common-structure.patch @@ -0,0 +1,1068 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:42:54 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:20 +0100 +Subject: USB: g_mass_storage: parts of fsg_dev moved to fsg_common structure +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <60d12ee71b49793c94a8bec8121f2be32fad1bc5.1256745228.git.m.nazarewicz@samsung.com> + + +In the final version, many fsg_dev structures will (be able to) +refer to a single fsg_common structure and so it is required +to move common data to another object which can be shared. + +Situation where many fsg_dev structures refer single fsg_common +structure is when a single instance of MSF is used in several +USB configurations. + +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> +--- + drivers/usb/gadget/f_mass_storage.c | 341 ++++++++++++++++++------------------ + 1 file changed, 173 insertions(+), 168 deletions(-) + +--- a/drivers/usb/gadget/f_mass_storage.c ++++ b/drivers/usb/gadget/f_mass_storage.c +@@ -320,14 +320,32 @@ MODULE_PARM_DESC(cdrom, "true to emulate + /*-------------------------------------------------------------------------*/ + + ++/* Data shared by all the FSG instances. */ ++struct fsg_common { ++ /* filesem protects: backing files in use */ ++ struct rw_semaphore filesem; ++ ++ struct fsg_buffhd *next_buffhd_to_fill; ++ struct fsg_buffhd *next_buffhd_to_drain; ++ struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; ++ ++ int cmnd_size; ++ u8 cmnd[MAX_COMMAND_SIZE]; ++ ++ unsigned int nluns; ++ unsigned int lun; ++ struct fsg_lun *luns; ++ struct fsg_lun *curlun; ++}; ++ ++ + struct fsg_dev { +- /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ ++ struct fsg_common *common; ++ ++ /* lock protects: state, all the req_busy's */ + spinlock_t lock; + struct usb_gadget *gadget; + +- /* filesem protects: backing files in use */ +- struct rw_semaphore filesem; +- + /* reference counting: wait until all LUNs are released */ + struct kref ref; + +@@ -356,27 +374,16 @@ struct fsg_dev { + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; + +- struct fsg_buffhd *next_buffhd_to_fill; +- struct fsg_buffhd *next_buffhd_to_drain; +- struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; +- + int thread_wakeup_needed; + struct completion thread_notifier; + struct task_struct *thread_task; + +- int cmnd_size; +- u8 cmnd[MAX_COMMAND_SIZE]; + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; +- unsigned int lun; + u32 residue; + u32 usb_amount_left; +- +- unsigned int nluns; +- struct fsg_lun *luns; +- struct fsg_lun *curlun; + }; + + typedef void (*fsg_routine_t)(struct fsg_dev *); +@@ -674,7 +681,7 @@ static int class_setup_req(struct fsg_de + if (w_index != 0 || w_value != 0) + return -EDOM; + VDBG(fsg, "get max LUN\n"); +- *(u8 *) req->buf = fsg->nluns - 1; ++ *(u8 *) req->buf = fsg->common->nluns - 1; + return 1; + } + +@@ -903,7 +910,7 @@ static int sleep_thread(struct fsg_dev * + + static int do_read(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; +@@ -915,15 +922,15 @@ static int do_read(struct fsg_dev *fsg) + + /* Get the starting Logical Block Address and check that it's + * not too big */ +- if (fsg->cmnd[0] == SC_READ_6) +- lba = get_unaligned_be24(&fsg->cmnd[1]); ++ if (fsg->common->cmnd[0] == SC_READ_6) ++ lba = get_unaligned_be24(&fsg->common->cmnd[1]); + else { +- lba = get_unaligned_be32(&fsg->cmnd[2]); ++ lba = get_unaligned_be32(&fsg->common->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = don't read from the + * cache), but we don't implement them. */ +- if ((fsg->cmnd[1] & ~0x18) != 0) { ++ if ((fsg->common->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } +@@ -958,7 +965,7 @@ static int do_read(struct fsg_dev *fsg) + partial_page); + + /* Wait for the next buffer to become available */ +- bh = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) +@@ -1018,7 +1025,7 @@ static int do_read(struct fsg_dev *fsg) + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + } + + return -EIO; // No default reply +@@ -1029,7 +1036,7 @@ static int do_read(struct fsg_dev *fsg) + + static int do_write(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; +@@ -1050,20 +1057,20 @@ static int do_write(struct fsg_dev *fsg) + + /* Get the starting Logical Block Address and check that it's + * not too big */ +- if (fsg->cmnd[0] == SC_WRITE_6) +- lba = get_unaligned_be24(&fsg->cmnd[1]); ++ if (fsg->common->cmnd[0] == SC_WRITE_6) ++ lba = get_unaligned_be24(&fsg->common->cmnd[1]); + else { +- lba = get_unaligned_be32(&fsg->cmnd[2]); ++ lba = get_unaligned_be32(&fsg->common->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = write directly to the + * medium). We don't implement DPO; we implement FUA by + * performing synchronous output. */ +- if ((fsg->cmnd[1] & ~0x18) != 0) { ++ if ((fsg->common->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } +- if (fsg->cmnd[1] & 0x08) { // FUA ++ if (fsg->common->cmnd[1] & 0x08) { // FUA + spin_lock(&curlun->filp->f_lock); + curlun->filp->f_flags |= O_SYNC; + spin_unlock(&curlun->filp->f_lock); +@@ -1082,7 +1089,7 @@ static int do_write(struct fsg_dev *fsg) + while (amount_left_to_write > 0) { + + /* Queue a request for more data from the host */ +- bh = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && get_some_more) { + + /* Figure out how much we want to get: +@@ -1133,17 +1140,17 @@ static int do_write(struct fsg_dev *fsg) + bh->outreq->short_not_ok = 1; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + continue; + } + + /* Write the received data to the backing file */ +- bh = fsg->next_buffhd_to_drain; ++ bh = fsg->common->next_buffhd_to_drain; + if (bh->state == BUF_STATE_EMPTY && !get_some_more) + break; // We stopped early + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); +- fsg->next_buffhd_to_drain = bh->next; ++ fsg->common->next_buffhd_to_drain = bh->next; + bh->state = BUF_STATE_EMPTY; + + /* Did something go wrong with the transfer? */ +@@ -1218,7 +1225,7 @@ static int do_write(struct fsg_dev *fsg) + + static int do_synchronize_cache(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + int rc; + + /* We ignore the requested LBA and write out all file's +@@ -1244,10 +1251,10 @@ static void invalidate_sub(struct fsg_lu + + static int do_verify(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + u32 lba; + u32 verification_length; +- struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill; + loff_t file_offset, file_offset_tmp; + u32 amount_left; + unsigned int amount; +@@ -1255,7 +1262,7 @@ static int do_verify(struct fsg_dev *fsg + + /* Get the starting Logical Block Address and check that it's + * not too big */ +- lba = get_unaligned_be32(&fsg->cmnd[2]); ++ lba = get_unaligned_be32(&fsg->common->cmnd[2]); + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; +@@ -1263,12 +1270,12 @@ static int do_verify(struct fsg_dev *fsg + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) but we don't implement it. */ +- if ((fsg->cmnd[1] & ~0x10) != 0) { ++ if ((fsg->common->cmnd[1] & ~0x10) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + +- verification_length = get_unaligned_be16(&fsg->cmnd[7]); ++ verification_length = get_unaligned_be16(&fsg->common->cmnd[7]); + if (unlikely(verification_length == 0)) + return -EIO; // No default reply + +@@ -1348,7 +1355,7 @@ static int do_inquiry(struct fsg_dev *fs + static char product_disk_id[] = "File-Stor Gadget"; + static char product_cdrom_id[] = "File-CD Gadget "; + +- if (!fsg->curlun) { // Unsupported LUNs are okay ++ if (!fsg->common->curlun) { // Unsupported LUNs are okay + fsg->bad_lun_okay = 1; + memset(buf, 0, 36); + buf[0] = 0x7f; // Unsupported, no device-type +@@ -1374,7 +1381,7 @@ static int do_inquiry(struct fsg_dev *fs + + static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + int valid; +@@ -1428,9 +1435,9 @@ static int do_request_sense(struct fsg_d + + static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; +- u32 lba = get_unaligned_be32(&fsg->cmnd[2]); +- int pmi = fsg->cmnd[8]; ++ struct fsg_lun *curlun = fsg->common->curlun; ++ u32 lba = get_unaligned_be32(&fsg->common->cmnd[2]); ++ int pmi = fsg->common->cmnd[8]; + u8 *buf = (u8 *) bh->buf; + + /* Check the PMI and LBA fields */ +@@ -1448,12 +1455,12 @@ static int do_read_capacity(struct fsg_d + + static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; +- int msf = fsg->cmnd[1] & 0x02; +- u32 lba = get_unaligned_be32(&fsg->cmnd[2]); ++ struct fsg_lun *curlun = fsg->common->curlun; ++ int msf = fsg->common->cmnd[1] & 0x02; ++ u32 lba = get_unaligned_be32(&fsg->common->cmnd[2]); + u8 *buf = (u8 *) bh->buf; + +- if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ ++ if ((fsg->common->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } +@@ -1471,12 +1478,12 @@ static int do_read_header(struct fsg_dev + + static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; +- int msf = fsg->cmnd[1] & 0x02; +- int start_track = fsg->cmnd[6]; ++ struct fsg_lun *curlun = fsg->common->curlun; ++ int msf = fsg->common->cmnd[1] & 0x02; ++ int start_track = fsg->common->cmnd[6]; + u8 *buf = (u8 *) bh->buf; + +- if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ ++ if ((fsg->common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ + start_track > 1) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; +@@ -1499,8 +1506,8 @@ static int do_read_toc(struct fsg_dev *f + + static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; +- int mscmnd = fsg->cmnd[0]; ++ struct fsg_lun *curlun = fsg->common->curlun; ++ int mscmnd = fsg->common->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; + int pc, page_code; +@@ -1508,12 +1515,12 @@ static int do_mode_sense(struct fsg_dev + int valid_page = 0; + int len, limit; + +- if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD ++ if ((fsg->common->cmnd[1] & ~0x08) != 0) { // Mask away DBD + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } +- pc = fsg->cmnd[2] >> 6; +- page_code = fsg->cmnd[2] & 0x3f; ++ pc = fsg->common->cmnd[2] >> 6; ++ page_code = fsg->common->cmnd[2] & 0x3f; + if (pc == 3) { + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + return -EINVAL; +@@ -1581,7 +1588,7 @@ static int do_mode_sense(struct fsg_dev + static int do_start_stop(struct fsg_dev *fsg) + { + if (!mod_data.removable) { +- fsg->curlun->sense_data = SS_INVALID_COMMAND; ++ fsg->common->curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } + return 0; +@@ -1590,7 +1597,7 @@ static int do_start_stop(struct fsg_dev + + static int do_prevent_allow(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + int prevent; + + if (!mod_data.removable) { +@@ -1598,8 +1605,8 @@ static int do_prevent_allow(struct fsg_d + return -EINVAL; + } + +- prevent = fsg->cmnd[4] & 0x01; +- if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent ++ prevent = fsg->common->cmnd[4] & 0x01; ++ if ((fsg->common->cmnd[4] & ~0x01) != 0) { // Mask away Prevent + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } +@@ -1614,7 +1621,7 @@ static int do_prevent_allow(struct fsg_d + static int do_read_format_capacities(struct fsg_dev *fsg, + struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + u8 *buf = (u8 *) bh->buf; + + buf[0] = buf[1] = buf[2] = 0; +@@ -1631,7 +1638,7 @@ static int do_read_format_capacities(str + + static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + + /* We don't support MODE SELECT */ + curlun->sense_data = SS_INVALID_COMMAND; +@@ -1688,7 +1695,7 @@ static int wedge_bulk_in_endpoint(struct + + static int pad_with_zeros(struct fsg_dev *fsg) + { +- struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill; + u32 nkeep = bh->inreq->length; + u32 nsend; + int rc; +@@ -1710,7 +1717,7 @@ static int pad_with_zeros(struct fsg_dev + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); +- bh = fsg->next_buffhd_to_fill = bh->next; ++ bh = fsg->common->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= nsend; + nkeep = 0; + } +@@ -1723,14 +1730,15 @@ static int throw_away_data(struct fsg_de + u32 amount; + int rc; + +- while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || +- fsg->usb_amount_left > 0) { ++ for (bh = fsg->common->next_buffhd_to_drain; ++ bh->state != BUF_STATE_EMPTY || fsg->usb_amount_left > 0; ++ bh = fsg->common->next_buffhd_to_drain) { + + /* Throw away the data in a filled buffer */ + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); + bh->state = BUF_STATE_EMPTY; +- fsg->next_buffhd_to_drain = bh->next; ++ fsg->common->next_buffhd_to_drain = bh->next; + + /* A short packet or an error ends everything */ + if (bh->outreq->actual != bh->outreq->length || +@@ -1742,7 +1750,7 @@ static int throw_away_data(struct fsg_de + } + + /* Try to submit another request if we need one */ +- bh = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { + amount = min(fsg->usb_amount_left, FSG_BUFLEN); + +@@ -1753,7 +1761,7 @@ static int throw_away_data(struct fsg_de + bh->outreq->short_not_ok = 1; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= amount; + continue; + } +@@ -1769,7 +1777,7 @@ static int throw_away_data(struct fsg_de + + static int finish_reply(struct fsg_dev *fsg) + { +- struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill; + int rc = 0; + + switch (fsg->data_dir) { +@@ -1797,7 +1805,7 @@ static int finish_reply(struct fsg_dev * + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't +@@ -1806,7 +1814,7 @@ static int finish_reply(struct fsg_dev * + bh->inreq->zero = 1; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + rc = halt_bulk_in_endpoint(fsg); + } else { + rc = pad_with_zeros(fsg); +@@ -1851,7 +1859,7 @@ static int finish_reply(struct fsg_dev * + + static int send_status(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_lun *curlun = fsg->common->curlun; + struct fsg_buffhd *bh; + struct bulk_cs_wrap *csw; + int rc; +@@ -1859,7 +1867,7 @@ static int send_status(struct fsg_dev *f + u32 sd, sdinfo = 0; + + /* Wait for the next buffer to become available */ +- bh = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) +@@ -1900,7 +1908,7 @@ static int send_status(struct fsg_dev *f + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + +- fsg->next_buffhd_to_fill = bh->next; ++ fsg->common->next_buffhd_to_fill = bh->next; + return 0; + } + +@@ -1914,7 +1922,7 @@ static int check_command(struct fsg_dev + int needs_medium, const char *name) + { + int i; +- int lun = fsg->cmnd[1] >> 5; ++ int lun = fsg->common->cmnd[1] >> 5; + static const char dirletter[4] = {'u', 'o', 'i', 'n'}; + char hdlen[20]; + struct fsg_lun *curlun; +@@ -1925,7 +1933,7 @@ static int check_command(struct fsg_dev + fsg->data_size); + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], +- fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); ++ fsg->data_size_from_cmnd, fsg->common->cmnd_size, hdlen); + + /* We can't reply at all until we know the correct data direction + * and size. */ +@@ -1954,7 +1962,7 @@ static int check_command(struct fsg_dev + } + + /* Verify the length of the command itself */ +- if (cmnd_size != fsg->cmnd_size) { ++ if (cmnd_size != fsg->common->cmnd_size) { + + /* Special case workaround: There are plenty of buggy SCSI + * implementations. Many have issues with cbw->Length +@@ -1968,11 +1976,11 @@ static int check_command(struct fsg_dev + * REQUEST SENSE with cbw->Length == 10 where it should + * be 6 as well. + */ +- if (cmnd_size <= fsg->cmnd_size) { ++ if (cmnd_size <= fsg->common->cmnd_size) { + DBG(fsg, "%s is buggy! Expected length %d " +- "but we got %d\n", name, +- cmnd_size, fsg->cmnd_size); +- cmnd_size = fsg->cmnd_size; ++ "but we got %d\n", name, ++ cmnd_size, fsg->common->cmnd_size); ++ cmnd_size = fsg->common->cmnd_size; + } else { + fsg->phase_error = 1; + return -EINVAL; +@@ -1980,27 +1988,27 @@ static int check_command(struct fsg_dev + } + + /* Check that the LUN values are consistent */ +- if (fsg->lun != lun) ++ if (fsg->common->lun != lun) + DBG(fsg, "using LUN %d from CBW, not LUN %d from CDB\n", +- fsg->lun, lun); ++ fsg->common->lun, lun); + + /* Check the LUN */ +- if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { +- fsg->curlun = curlun = &fsg->luns[fsg->lun]; +- if (fsg->cmnd[0] != SC_REQUEST_SENSE) { ++ if (fsg->common->lun >= 0 && fsg->common->lun < fsg->common->nluns) { ++ fsg->common->curlun = curlun = &fsg->common->luns[fsg->common->lun]; ++ if (fsg->common->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + } else { +- fsg->curlun = curlun = NULL; ++ fsg->common->curlun = curlun = NULL; + fsg->bad_lun_okay = 0; + + /* INQUIRY and REQUEST SENSE commands are explicitly allowed + * to use unsupported LUNs; all others may not. */ +- if (fsg->cmnd[0] != SC_INQUIRY && +- fsg->cmnd[0] != SC_REQUEST_SENSE) { +- DBG(fsg, "unsupported LUN %d\n", fsg->lun); ++ if (fsg->common->cmnd[0] != SC_INQUIRY && ++ fsg->common->cmnd[0] != SC_REQUEST_SENSE) { ++ DBG(fsg, "unsupported LUN %d\n", fsg->common->lun); + return -EINVAL; + } + } +@@ -2008,17 +2016,17 @@ static int check_command(struct fsg_dev + /* If a unit attention condition exists, only INQUIRY and + * REQUEST SENSE commands are allowed; anything else must fail. */ + if (curlun && curlun->unit_attention_data != SS_NO_SENSE && +- fsg->cmnd[0] != SC_INQUIRY && +- fsg->cmnd[0] != SC_REQUEST_SENSE) { ++ fsg->common->cmnd[0] != SC_INQUIRY && ++ fsg->common->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + return -EINVAL; + } + + /* Check that only command bytes listed in the mask are non-zero */ +- fsg->cmnd[1] &= 0x1f; // Mask away the LUN ++ fsg->common->cmnd[1] &= 0x1f; // Mask away the LUN + for (i = 1; i < cmnd_size; ++i) { +- if (fsg->cmnd[i] && !(mask & (1 << i))) { ++ if (fsg->common->cmnd[i] && !(mask & (1 << i))) { + if (curlun) + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; +@@ -2044,10 +2052,10 @@ static int do_scsi_command(struct fsg_de + int i; + static char unknown[16]; + +- dump_cdb(fsg); ++ dump_cdb(fsg->common); + + /* Wait for the next buffer to become available for data or status */ +- bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_drain = fsg->common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) +@@ -2056,11 +2064,11 @@ static int do_scsi_command(struct fsg_de + fsg->phase_error = 0; + fsg->short_packet_received = 0; + +- down_read(&fsg->filesem); // We're using the backing file +- switch (fsg->cmnd[0]) { ++ down_read(&fsg->common->filesem); // We're using the backing file ++ switch (fsg->common->cmnd[0]) { + + case SC_INQUIRY: +- fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = fsg->common->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "INQUIRY")) == 0) +@@ -2068,7 +2076,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_MODE_SELECT_6: +- fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = fsg->common->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (1<<1) | (1<<4), 0, + "MODE SELECT(6)")) == 0) +@@ -2076,7 +2084,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_MODE_SELECT_10: +- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (3<<7), 0, + "MODE SELECT(10)")) == 0) +@@ -2084,7 +2092,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_MODE_SENSE_6: +- fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = fsg->common->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (1<<4), 0, + "MODE SENSE(6)")) == 0) +@@ -2092,7 +2100,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_MODE_SENSE_10: +- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (3<<7), 0, + "MODE SENSE(10)")) == 0) +@@ -2108,7 +2116,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_READ_6: +- i = fsg->cmnd[4]; ++ i = fsg->common->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (7<<1) | (1<<4), 1, +@@ -2118,7 +2126,7 @@ static int do_scsi_command(struct fsg_de + + case SC_READ_10: + fsg->data_size_from_cmnd = +- get_unaligned_be16(&fsg->cmnd[7]) << 9; ++ get_unaligned_be16(&fsg->common->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "READ(10)")) == 0) +@@ -2127,7 +2135,7 @@ static int do_scsi_command(struct fsg_de + + case SC_READ_12: + fsg->data_size_from_cmnd = +- get_unaligned_be32(&fsg->cmnd[6]) << 9; ++ get_unaligned_be32(&fsg->common->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "READ(12)")) == 0) +@@ -2145,7 +2153,7 @@ static int do_scsi_command(struct fsg_de + case SC_READ_HEADER: + if (!mod_data.cdrom) + goto unknown_cmnd; +- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7) | (0x1f<<1), 1, + "READ HEADER")) == 0) +@@ -2155,7 +2163,7 @@ static int do_scsi_command(struct fsg_de + case SC_READ_TOC: + if (!mod_data.cdrom) + goto unknown_cmnd; +- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (7<<6) | (1<<1), 1, + "READ TOC")) == 0) +@@ -2163,7 +2171,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_READ_FORMAT_CAPACITIES: +- fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7), 1, + "READ FORMAT CAPACITIES")) == 0) +@@ -2171,7 +2179,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_REQUEST_SENSE: +- fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = fsg->common->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "REQUEST SENSE")) == 0) +@@ -2212,7 +2220,7 @@ static int do_scsi_command(struct fsg_de + break; + + case SC_WRITE_6: +- i = fsg->cmnd[4]; ++ i = fsg->common->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (7<<1) | (1<<4), 1, +@@ -2222,7 +2230,7 @@ static int do_scsi_command(struct fsg_de + + case SC_WRITE_10: + fsg->data_size_from_cmnd = +- get_unaligned_be16(&fsg->cmnd[7]) << 9; ++ get_unaligned_be16(&fsg->common->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "WRITE(10)")) == 0) +@@ -2231,7 +2239,7 @@ static int do_scsi_command(struct fsg_de + + case SC_WRITE_12: + fsg->data_size_from_cmnd = +- get_unaligned_be32(&fsg->cmnd[6]) << 9; ++ get_unaligned_be32(&fsg->common->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "WRITE(12)")) == 0) +@@ -2251,15 +2259,15 @@ static int do_scsi_command(struct fsg_de + default: + unknown_cmnd: + fsg->data_size_from_cmnd = 0; +- sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); +- if ((reply = check_command(fsg, fsg->cmnd_size, ++ sprintf(unknown, "Unknown x%02x", fsg->common->cmnd[0]); ++ if ((reply = check_command(fsg, fsg->common->cmnd_size, + DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { +- fsg->curlun->sense_data = SS_INVALID_COMMAND; ++ fsg->common->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } + break; + } +- up_read(&fsg->filesem); ++ up_read(&fsg->common->filesem); + + if (reply == -EINTR || signal_pending(current)) + return -EINTR; +@@ -2328,8 +2336,8 @@ static int received_cbw(struct fsg_dev * + } + + /* Save the command for later */ +- fsg->cmnd_size = cbw->Length; +- memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); ++ fsg->common->cmnd_size = cbw->Length; ++ memcpy(fsg->common->cmnd, cbw->CDB, fsg->common->cmnd_size); + if (cbw->Flags & USB_BULK_IN_FLAG) + fsg->data_dir = DATA_DIR_TO_HOST; + else +@@ -2337,7 +2345,7 @@ static int received_cbw(struct fsg_dev * + fsg->data_size = le32_to_cpu(cbw->DataTransferLength); + if (fsg->data_size == 0) + fsg->data_dir = DATA_DIR_NONE; +- fsg->lun = cbw->Lun; ++ fsg->common->lun = cbw->Lun; + fsg->tag = cbw->Tag; + return 0; + } +@@ -2349,7 +2357,7 @@ static int get_next_command(struct fsg_d + int rc = 0; + + /* Wait for the next buffer to become available */ +- bh = fsg->next_buffhd_to_fill; ++ bh = fsg->common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) +@@ -2421,7 +2429,7 @@ static int do_set_interface(struct fsg_d + reset: + /* Deallocate the requests */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ struct fsg_buffhd *bh = &fsg->common->buffhds[i]; + + if (bh->inreq) { + usb_ep_free_request(fsg->bulk_in, bh->inreq); +@@ -2466,7 +2474,7 @@ reset: + + /* Allocate the requests */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ struct fsg_buffhd *bh = &fsg->common->buffhds[i]; + + if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) + goto reset; +@@ -2479,8 +2487,8 @@ reset: + } + + fsg->running = 1; +- for (i = 0; i < fsg->nluns; ++i) +- fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; ++ for (i = 0; i < fsg->common->nluns; ++i) ++ fsg->common->luns[i].unit_attention_data = SS_RESET_OCCURRED; + return rc; + } + +@@ -2532,7 +2540,6 @@ static void handle_exception(struct fsg_ + siginfo_t info; + int sig; + int i; +- int num_active; + struct fsg_buffhd *bh; + enum fsg_state old_state; + u8 new_config; +@@ -2555,7 +2562,7 @@ static void handle_exception(struct fsg_ + + /* Cancel all the pending transfers */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- bh = &fsg->buffhds[i]; ++ bh = &fsg->common->buffhds[i]; + if (bh->inreq_busy) + usb_ep_dequeue(fsg->bulk_in, bh->inreq); + if (bh->outreq_busy) +@@ -2564,9 +2571,9 @@ static void handle_exception(struct fsg_ + + /* Wait until everything is idle */ + for (;;) { +- num_active = 0; ++ int num_active = 0; + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- bh = &fsg->buffhds[i]; ++ bh = &fsg->common->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; + } + if (num_active == 0) +@@ -2586,11 +2593,11 @@ static void handle_exception(struct fsg_ + spin_lock_irq(&fsg->lock); + + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- bh = &fsg->buffhds[i]; ++ bh = &fsg->common->buffhds[i]; + bh->state = BUF_STATE_EMPTY; + } +- fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = +- &fsg->buffhds[0]; ++ fsg->common->next_buffhd_to_fill = fsg->common->next_buffhd_to_drain = ++ &fsg->common->buffhds[0]; + + exception_req_tag = fsg->exception_req_tag; + new_config = fsg->new_config; +@@ -2599,8 +2606,8 @@ static void handle_exception(struct fsg_ + if (old_state == FSG_STATE_ABORT_BULK_OUT) + fsg->state = FSG_STATE_STATUS_PHASE; + else { +- for (i = 0; i < fsg->nluns; ++i) { +- curlun = &fsg->luns[i]; ++ for (i = 0; i < fsg->common->nluns; ++i) { ++ curlun = &fsg->common->luns[i]; + curlun->prevent_medium_removal = 0; + curlun->sense_data = curlun->unit_attention_data = + SS_NO_SENSE; +@@ -2637,8 +2644,8 @@ static void handle_exception(struct fsg_ + /* Technically this should go here, but it would only be + * a waste of time. Ditto for the INTERFACE_CHANGE and + * CONFIG_CHANGE cases. */ +- // for (i = 0; i < fsg->nluns; ++i) +- // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; ++ // for (i = 0; i < fsg->common->nluns; ++i) ++ // fsg->common->luns[i].unit_attention_data = SS_RESET_OCCURRED; + break; + + case FSG_STATE_INTERFACE_CHANGE: +@@ -2662,8 +2669,8 @@ static void handle_exception(struct fsg_ + break; + + case FSG_STATE_DISCONNECT: +- for (i = 0; i < fsg->nluns; ++i) +- fsg_lun_fsync_sub(fsg->luns + i); ++ for (i = 0; i < fsg->common->nluns; ++i) ++ fsg_lun_fsync_sub(&fsg->common->luns[i]); + do_set_config(fsg, 0); // Unconfigured state + break; + +@@ -2760,21 +2767,14 @@ static DEVICE_ATTR(file, 0444, fsg_show_ + + /*-------------------------------------------------------------------------*/ + +-static void fsg_release(struct kref *ref) ++static void fsg_release(struct fsg_dev *fsg) + { +- struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); +- +- kfree(fsg->luns); ++ kfree(fsg->common->luns); + kfree(fsg); + } + + static void lun_release(struct device *dev) + { +- struct rw_semaphore *filesem = dev_get_drvdata(dev); +- struct fsg_dev *fsg = +- container_of(filesem, struct fsg_dev, filesem); +- +- kref_put(&fsg->ref, fsg_release); + } + + static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) +@@ -2788,8 +2788,8 @@ static void /* __init_or_exit */ fsg_unb + clear_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Unregister the sysfs attribute files and the LUNs */ +- for (i = 0; i < fsg->nluns; ++i) { +- curlun = &fsg->luns[i]; ++ for (i = 0; i < fsg->common->nluns; ++i) { ++ curlun = &fsg->common->luns[i]; + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_ro); + device_remove_file(&curlun->dev, &dev_attr_file); +@@ -2810,7 +2810,7 @@ static void /* __init_or_exit */ fsg_unb + + /* Free the data buffers */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) +- kfree(fsg->buffhds[i].buf); ++ kfree(fsg->common->buffhds[i].buf); + + /* Free the request and buffer for endpoint 0 */ + if (req) { +@@ -2891,15 +2891,15 @@ static int __init fsg_bind(struct usb_ga + + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ +- fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); +- if (!fsg->luns) { ++ fsg->common->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); ++ if (!fsg->common->luns) { + rc = -ENOMEM; + goto out; + } +- fsg->nluns = i; ++ fsg->common->nluns = i; + +- for (i = 0; i < fsg->nluns; ++i) { +- curlun = &fsg->luns[i]; ++ for (i = 0; i < fsg->common->nluns; ++i) { ++ curlun = &fsg->common->luns[i]; + curlun->cdrom = !!mod_data.cdrom; + curlun->ro = mod_data.cdrom || mod_data.ro[i]; + curlun->initially_ro = curlun->ro; +@@ -2907,7 +2907,7 @@ static int __init fsg_bind(struct usb_ga + curlun->dev.release = lun_release; + curlun->dev.parent = &gadget->dev; + curlun->dev.driver = &fsg_driver.driver; +- dev_set_drvdata(&curlun->dev, &fsg->filesem); ++ dev_set_drvdata(&curlun->dev, &fsg->common->filesem); + dev_set_name(&curlun->dev,"%s-lun%d", + dev_name(&gadget->dev), i); + +@@ -2923,7 +2923,6 @@ static int __init fsg_bind(struct usb_ga + goto out; + } + curlun->registered = 1; +- kref_get(&fsg->ref); + + if (mod_data.file[i] && *mod_data.file[i]) { + if ((rc = fsg_lun_open(curlun, +@@ -2981,7 +2980,7 @@ static int __init fsg_bind(struct usb_ga + + /* Allocate the data buffers */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { +- struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ struct fsg_buffhd *bh = &fsg->common->buffhds[i]; + + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and +@@ -2991,7 +2990,7 @@ static int __init fsg_bind(struct usb_ga + goto out; + bh->next = bh + 1; + } +- fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; ++ fsg->common->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->common->buffhds[0]; + + /* This should reflect the actual gadget power source */ + usb_gadget_set_selfpowered(gadget); +@@ -3019,11 +3018,11 @@ static int __init fsg_bind(struct usb_ga + } + + INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); +- INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); ++ INFO(fsg, "Number of LUNs=%d\n", fsg->common->nluns); + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); +- for (i = 0; i < fsg->nluns; ++i) { +- curlun = &fsg->luns[i]; ++ for (i = 0; i < fsg->common->nluns; ++i) { ++ curlun = &fsg->common->luns[i]; + if (fsg_lun_is_open(curlun)) { + p = NULL; + if (pathbuf) { +@@ -3092,9 +3091,15 @@ static int __init fsg_alloc(void) + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + if (!fsg) + return -ENOMEM; ++ ++ fsg->common = kzalloc(sizeof *fsg->common, GFP_KERNEL); ++ if (!fsg->common) { ++ kfree(fsg); ++ return -ENOMEM; ++ } ++ + spin_lock_init(&fsg->lock); +- init_rwsem(&fsg->filesem); +- kref_init(&fsg->ref); ++ init_rwsem(&fsg->common->filesem); + init_completion(&fsg->thread_notifier); + + the_fsg = fsg; +@@ -3111,7 +3116,7 @@ static int __init fsg_init(void) + return rc; + fsg = the_fsg; + if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) +- kref_put(&fsg->ref, fsg_release); ++ fsg_release(fsg); + return rc; + } + module_init(fsg_init); +@@ -3128,6 +3133,6 @@ static void __exit fsg_cleanup(void) + /* Wait for the thread to finish up */ + wait_for_completion(&fsg->thread_notifier); + +- kref_put(&fsg->ref, fsg_release); ++ fsg_release(fsg); + } + module_exit(fsg_cleanup); diff --git a/usb/usb-g_mass_storage-template-f_mass_storage.c-file-created.patch b/usb/usb-g_mass_storage-template-f_mass_storage.c-file-created.patch new file mode 100644 index 00000000000000..fcd7e2d6342336 --- /dev/null +++ b/usb/usb-g_mass_storage-template-f_mass_storage.c-file-created.patch @@ -0,0 +1,3635 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:42:27 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:18 +0100 +Subject: USB: g_mass_storage: template f_mass_storage.c file created +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <53259a9a80ee26e4975303f7f4f8492fb346f891.1256745228.git.m.nazarewicz@samsung.com> + + +Copied file_storage.c to f_mass_storage.c which will be used as +template for the Mass Storage composite Function. + +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> +--- + drivers/usb/gadget/f_mass_storage.c | 3611 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 3611 insertions(+) + create mode 100644 drivers/usb/gadget/f_mass_storage.c + +--- /dev/null ++++ b/drivers/usb/gadget/f_mass_storage.c +@@ -0,0 +1,3611 @@ ++/* ++ * file_storage.c -- File-backed USB Storage Gadget, for USB development ++ * ++ * Copyright (C) 2003-2008 Alan Stern ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/* ++ * The File-backed Storage Gadget acts as a USB Mass Storage device, ++ * appearing to the host as a disk drive or as a CD-ROM drive. In addition ++ * to providing an example of a genuinely useful gadget driver for a USB ++ * device, it also illustrates a technique of double-buffering for increased ++ * throughput. Last but not least, it gives an easy way to probe the ++ * behavior of the Mass Storage drivers in a USB host. ++ * ++ * Backing storage is provided by a regular file or a block device, specified ++ * by the "file" module parameter. Access can be limited to read-only by ++ * setting the optional "ro" module parameter. (For CD-ROM emulation, ++ * access is always read-only.) The gadget will indicate that it has ++ * removable media if the optional "removable" module parameter is set. ++ * ++ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), ++ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected ++ * by the optional "transport" module parameter. It also supports the ++ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), ++ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by ++ * the optional "protocol" module parameter. In addition, the default ++ * Vendor ID, Product ID, and release number can be overridden. ++ * ++ * There is support for multiple logical units (LUNs), each of which has ++ * its own backing file. The number of LUNs can be set using the optional ++ * "luns" module parameter (anywhere from 1 to 8), and the corresponding ++ * files are specified using comma-separated lists for "file" and "ro". ++ * The default number of LUNs is taken from the number of "file" elements; ++ * it is 1 if "file" is not given. If "removable" is not set then a backing ++ * file must be specified for each LUN. If it is set, then an unspecified ++ * or empty backing filename means the LUN's medium is not loaded. Ideally ++ * each LUN would be settable independently as a disk drive or a CD-ROM ++ * drive, but currently all LUNs have to be the same type. The CD-ROM ++ * emulation includes a single data track and no audio tracks; hence there ++ * need be only one backing file per LUN. Note also that the CD-ROM block ++ * length is set to 512 rather than the more common value 2048. ++ * ++ * Requirements are modest; only a bulk-in and a bulk-out endpoint are ++ * needed (an interrupt-out endpoint is also needed for CBI). The memory ++ * requirement amounts to two 16K buffers, size configurable by a parameter. ++ * Support is included for both full-speed and high-speed operation. ++ * ++ * Note that the driver is slightly non-portable in that it assumes a ++ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and ++ * interrupt-in endpoints. With most device controllers this isn't an ++ * issue, but there may be some with hardware restrictions that prevent ++ * a buffer from being used by more than one endpoint. ++ * ++ * Module options: ++ * ++ * file=filename[,filename...] ++ * Required if "removable" is not set, names of ++ * the files or block devices used for ++ * backing storage ++ * ro=b[,b...] Default false, booleans for read-only access ++ * removable Default false, boolean for removable media ++ * luns=N Default N = number of filenames, number of ++ * LUNs to support ++ * stall Default determined according to the type of ++ * USB device controller (usually true), ++ * boolean to permit the driver to halt ++ * bulk endpoints ++ * cdrom Default false, boolean for whether to emulate ++ * a CD-ROM drive ++ * transport=XXX Default BBB, transport name (CB, CBI, or BBB) ++ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or ++ * ATAPI, QIC, UFI, 8070, or SCSI; ++ * also 1 - 6) ++ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID ++ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID ++ * release=0xRRRR Override the USB release number (bcdDevice) ++ * buflen=N Default N=16384, buffer size used (will be ++ * rounded down to a multiple of ++ * PAGE_CACHE_SIZE) ++ * ++ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", ++ * "removable", "luns", "stall", and "cdrom" options are available; default ++ * values are used for everything else. ++ * ++ * The pathnames of the backing files and the ro settings are available in ++ * the attribute files "file" and "ro" in the lun<n> subdirectory of the ++ * gadget's sysfs directory. If the "removable" option is set, writing to ++ * these files will simulate ejecting/loading the medium (writing an empty ++ * line means eject) and adjusting a write-enable tab. Changes to the ro ++ * setting are not allowed when the medium is loaded or if CD-ROM emulation ++ * is being used. ++ * ++ * This gadget driver is heavily based on "Gadget Zero" by David Brownell. ++ * The driver's SCSI command interface was based on the "Information ++ * technology - Small Computer System Interface - 2" document from ++ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at ++ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception ++ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the ++ * "Universal Serial Bus Mass Storage Class UFI Command Specification" ++ * document, Revision 1.0, December 14, 1998, available at ++ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. ++ */ ++ ++ ++/* ++ * Driver Design ++ * ++ * The FSG driver is fairly straightforward. There is a main kernel ++ * thread that handles most of the work. Interrupt routines field ++ * callbacks from the controller driver: bulk- and interrupt-request ++ * completion notifications, endpoint-0 events, and disconnect events. ++ * Completion events are passed to the main thread by wakeup calls. Many ++ * ep0 requests are handled at interrupt time, but SetInterface, ++ * SetConfiguration, and device reset requests are forwarded to the ++ * thread in the form of "exceptions" using SIGUSR1 signals (since they ++ * should interrupt any ongoing file I/O operations). ++ * ++ * The thread's main routine implements the standard command/data/status ++ * parts of a SCSI interaction. It and its subroutines are full of tests ++ * for pending signals/exceptions -- all this polling is necessary since ++ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an ++ * indication that the driver really wants to be running in userspace.) ++ * An important point is that so long as the thread is alive it keeps an ++ * open reference to the backing file. This will prevent unmounting ++ * the backing file's underlying filesystem and could cause problems ++ * during system shutdown, for example. To prevent such problems, the ++ * thread catches INT, TERM, and KILL signals and converts them into ++ * an EXIT exception. ++ * ++ * In normal operation the main thread is started during the gadget's ++ * fsg_bind() callback and stopped during fsg_unbind(). But it can also ++ * exit when it receives a signal, and there's no point leaving the ++ * gadget running when the thread is dead. So just before the thread ++ * exits, it deregisters the gadget driver. This makes things a little ++ * tricky: The driver is deregistered at two places, and the exiting ++ * thread can indirectly call fsg_unbind() which in turn can tell the ++ * thread to exit. The first problem is resolved through the use of the ++ * REGISTERED atomic bitflag; the driver will only be deregistered once. ++ * The second problem is resolved by having fsg_unbind() check ++ * fsg->state; it won't try to stop the thread if the state is already ++ * FSG_STATE_TERMINATED. ++ * ++ * To provide maximum throughput, the driver uses a circular pipeline of ++ * buffer heads (struct fsg_buffhd). In principle the pipeline can be ++ * arbitrarily long; in practice the benefits don't justify having more ++ * than 2 stages (i.e., double buffering). But it helps to think of the ++ * pipeline as being a long one. Each buffer head contains a bulk-in and ++ * a bulk-out request pointer (since the buffer can be used for both ++ * output and input -- directions always are given from the host's ++ * point of view) as well as a pointer to the buffer and various state ++ * variables. ++ * ++ * Use of the pipeline follows a simple protocol. There is a variable ++ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. ++ * At any time that buffer head may still be in use from an earlier ++ * request, so each buffer head has a state variable indicating whether ++ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the ++ * buffer head to be EMPTY, filling the buffer either by file I/O or by ++ * USB I/O (during which the buffer head is BUSY), and marking the buffer ++ * head FULL when the I/O is complete. Then the buffer will be emptied ++ * (again possibly by USB I/O, during which it is marked BUSY) and ++ * finally marked EMPTY again (possibly by a completion routine). ++ * ++ * A module parameter tells the driver to avoid stalling the bulk ++ * endpoints wherever the transport specification allows. This is ++ * necessary for some UDCs like the SuperH, which cannot reliably clear a ++ * halt on a bulk endpoint. However, under certain circumstances the ++ * Bulk-only specification requires a stall. In such cases the driver ++ * will halt the endpoint and set a flag indicating that it should clear ++ * the halt in software during the next device reset. Hopefully this ++ * will permit everything to work correctly. Furthermore, although the ++ * specification allows the bulk-out endpoint to halt when the host sends ++ * too much data, implementing this would cause an unavoidable race. ++ * The driver will always use the "no-stall" approach for OUT transfers. ++ * ++ * One subtle point concerns sending status-stage responses for ep0 ++ * requests. Some of these requests, such as device reset, can involve ++ * interrupting an ongoing file I/O operation, which might take an ++ * arbitrarily long time. During that delay the host might give up on ++ * the original ep0 request and issue a new one. When that happens the ++ * driver should not notify the host about completion of the original ++ * request, as the host will no longer be waiting for it. So the driver ++ * assigns to each ep0 request a unique tag, and it keeps track of the ++ * tag value of the request associated with a long-running exception ++ * (device-reset, interface-change, or configuration-change). When the ++ * exception handler is finished, the status-stage response is submitted ++ * only if the current ep0 request tag is equal to the exception request ++ * tag. Thus only the most recently received ep0 request will get a ++ * status-stage response. ++ * ++ * Warning: This driver source file is too long. It ought to be split up ++ * into a header file plus about 3 separate .c files, to handle the details ++ * of the Gadget, USB Mass Storage, and SCSI protocols. ++ */ ++ ++ ++/* #define VERBOSE_DEBUG */ ++/* #define DUMP_MSGS */ ++ ++ ++#include <linux/blkdev.h> ++#include <linux/completion.h> ++#include <linux/dcache.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/fcntl.h> ++#include <linux/file.h> ++#include <linux/fs.h> ++#include <linux/kref.h> ++#include <linux/kthread.h> ++#include <linux/limits.h> ++#include <linux/rwsem.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/string.h> ++#include <linux/freezer.h> ++#include <linux/utsname.h> ++ ++#include <linux/usb/ch9.h> ++#include <linux/usb/gadget.h> ++ ++#include "gadget_chips.h" ++ ++ ++ ++/* ++ * Kbuild is not very cooperative with respect to linking separately ++ * compiled library objects into one module. So for now we won't use ++ * separate compilation ... ensuring init/exit sections work to shrink ++ * the runtime footprint, and giving us at least some parts of what ++ * a "gcc --combine ... part1.c part2.c part3.c ... " build would. ++ */ ++#include "usbstring.c" ++#include "config.c" ++#include "epautoconf.c" ++ ++/*-------------------------------------------------------------------------*/ ++ ++#define DRIVER_DESC "File-backed Storage Gadget" ++#define DRIVER_NAME "g_file_storage" ++#define DRIVER_VERSION "20 November 2008" ++ ++static char fsg_string_manufacturer[64]; ++static const char fsg_string_product[] = DRIVER_DESC; ++static char fsg_string_serial[13]; ++static const char fsg_string_config[] = "Self-powered"; ++static const char fsg_string_interface[] = "Mass Storage"; ++ ++ ++#include "storage_common.c" ++ ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Alan Stern"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++/* ++ * This driver assumes self-powered hardware and has no way for users to ++ * trigger remote wakeup. It uses autoconfiguration to select endpoints ++ * and endpoint addresses. ++ */ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++/* Encapsulate the module parameter settings */ ++ ++static struct { ++ char *file[FSG_MAX_LUNS]; ++ int ro[FSG_MAX_LUNS]; ++ unsigned int num_filenames; ++ unsigned int num_ros; ++ unsigned int nluns; ++ ++ int removable; ++ int can_stall; ++ int cdrom; ++ ++ char *transport_parm; ++ char *protocol_parm; ++ unsigned short vendor; ++ unsigned short product; ++ unsigned short release; ++ unsigned int buflen; ++ ++ int transport_type; ++ char *transport_name; ++ int protocol_type; ++ char *protocol_name; ++ ++} mod_data = { // Default values ++ .transport_parm = "BBB", ++ .protocol_parm = "SCSI", ++ .removable = 0, ++ .can_stall = 1, ++ .cdrom = 0, ++ .vendor = FSG_VENDOR_ID, ++ .product = FSG_PRODUCT_ID, ++ .release = 0xffff, // Use controller chip type ++ .buflen = 16384, ++ }; ++ ++ ++module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, ++ S_IRUGO); ++MODULE_PARM_DESC(file, "names of backing files or devices"); ++ ++module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); ++MODULE_PARM_DESC(ro, "true to force read-only"); ++ ++module_param_named(luns, mod_data.nluns, uint, S_IRUGO); ++MODULE_PARM_DESC(luns, "number of LUNs"); ++ ++module_param_named(removable, mod_data.removable, bool, S_IRUGO); ++MODULE_PARM_DESC(removable, "true to simulate removable media"); ++ ++module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); ++MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); ++ ++module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); ++MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); ++ ++ ++/* In the non-TEST version, only the module parameters listed above ++ * are available. */ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++ ++module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); ++MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); ++ ++module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); ++MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " ++ "8070, or SCSI)"); ++ ++module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); ++MODULE_PARM_DESC(vendor, "USB Vendor ID"); ++ ++module_param_named(product, mod_data.product, ushort, S_IRUGO); ++MODULE_PARM_DESC(product, "USB Product ID"); ++ ++module_param_named(release, mod_data.release, ushort, S_IRUGO); ++MODULE_PARM_DESC(release, "USB release number"); ++ ++module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); ++MODULE_PARM_DESC(buflen, "I/O buffer size"); ++ ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ ++ ++/* ++ * These definitions will permit the compiler to avoid generating code for ++ * parts of the driver that aren't used in the non-TEST version. Even gcc ++ * can recognize when a test of a constant expression yields a dead code ++ * path. ++ */ ++ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++ ++#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) ++#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) ++#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) ++ ++#else ++ ++#define transport_is_bbb() 1 ++#define transport_is_cbi() 0 ++#define protocol_is_scsi() 1 ++ ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++struct fsg_dev { ++ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ ++ spinlock_t lock; ++ struct usb_gadget *gadget; ++ ++ /* filesem protects: backing files in use */ ++ struct rw_semaphore filesem; ++ ++ /* reference counting: wait until all LUNs are released */ ++ struct kref ref; ++ ++ struct usb_ep *ep0; // Handy copy of gadget->ep0 ++ struct usb_request *ep0req; // For control responses ++ unsigned int ep0_req_tag; ++ const char *ep0req_name; ++ ++ struct usb_request *intreq; // For interrupt responses ++ int intreq_busy; ++ struct fsg_buffhd *intr_buffhd; ++ ++ unsigned int bulk_out_maxpacket; ++ enum fsg_state state; // For exception handling ++ unsigned int exception_req_tag; ++ ++ u8 config, new_config; ++ ++ unsigned int running : 1; ++ unsigned int bulk_in_enabled : 1; ++ unsigned int bulk_out_enabled : 1; ++ unsigned int intr_in_enabled : 1; ++ unsigned int phase_error : 1; ++ unsigned int short_packet_received : 1; ++ unsigned int bad_lun_okay : 1; ++ ++ unsigned long atomic_bitflags; ++#define REGISTERED 0 ++#define IGNORE_BULK_OUT 1 ++#define SUSPENDED 2 ++ ++ struct usb_ep *bulk_in; ++ struct usb_ep *bulk_out; ++ struct usb_ep *intr_in; ++ ++ struct fsg_buffhd *next_buffhd_to_fill; ++ struct fsg_buffhd *next_buffhd_to_drain; ++ struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; ++ ++ int thread_wakeup_needed; ++ struct completion thread_notifier; ++ struct task_struct *thread_task; ++ ++ int cmnd_size; ++ u8 cmnd[MAX_COMMAND_SIZE]; ++ enum data_direction data_dir; ++ u32 data_size; ++ u32 data_size_from_cmnd; ++ u32 tag; ++ unsigned int lun; ++ u32 residue; ++ u32 usb_amount_left; ++ ++ /* The CB protocol offers no way for a host to know when a command ++ * has completed. As a result the next command may arrive early, ++ * and we will still have to handle it. For that reason we need ++ * a buffer to store new commands when using CB (or CBI, which ++ * does not oblige a host to wait for command completion either). */ ++ int cbbuf_cmnd_size; ++ u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; ++ ++ unsigned int nluns; ++ struct fsg_lun *luns; ++ struct fsg_lun *curlun; ++}; ++ ++typedef void (*fsg_routine_t)(struct fsg_dev *); ++ ++static int exception_in_progress(struct fsg_dev *fsg) ++{ ++ return (fsg->state > FSG_STATE_IDLE); ++} ++ ++/* Make bulk-out requests be divisible by the maxpacket size */ ++static void set_bulk_out_req_length(struct fsg_dev *fsg, ++ struct fsg_buffhd *bh, unsigned int length) ++{ ++ unsigned int rem; ++ ++ bh->bulk_out_intended_length = length; ++ rem = length % fsg->bulk_out_maxpacket; ++ if (rem > 0) ++ length += fsg->bulk_out_maxpacket - rem; ++ bh->outreq->length = length; ++} ++ ++static struct fsg_dev *the_fsg; ++static struct usb_gadget_driver fsg_driver; ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) ++{ ++ const char *name; ++ ++ if (ep == fsg->bulk_in) ++ name = "bulk-in"; ++ else if (ep == fsg->bulk_out) ++ name = "bulk-out"; ++ else ++ name = ep->name; ++ DBG(fsg, "%s set halt\n", name); ++ return usb_ep_set_halt(ep); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * DESCRIPTORS ... most are static, but strings and (full) configuration ++ * descriptors are built on demand. Also the (static) config and interface ++ * descriptors are adjusted during fsg_bind(). ++ */ ++ ++/* There is only one configuration. */ ++#define CONFIG_VALUE 1 ++ ++static struct usb_device_descriptor ++device_desc = { ++ .bLength = sizeof device_desc, ++ .bDescriptorType = USB_DT_DEVICE, ++ ++ .bcdUSB = cpu_to_le16(0x0200), ++ .bDeviceClass = USB_CLASS_PER_INTERFACE, ++ ++ /* The next three values can be overridden by module parameters */ ++ .idVendor = cpu_to_le16(FSG_VENDOR_ID), ++ .idProduct = cpu_to_le16(FSG_PRODUCT_ID), ++ .bcdDevice = cpu_to_le16(0xffff), ++ ++ .iManufacturer = FSG_STRING_MANUFACTURER, ++ .iProduct = FSG_STRING_PRODUCT, ++ .iSerialNumber = FSG_STRING_SERIAL, ++ .bNumConfigurations = 1, ++}; ++ ++static struct usb_config_descriptor ++config_desc = { ++ .bLength = sizeof config_desc, ++ .bDescriptorType = USB_DT_CONFIG, ++ ++ /* wTotalLength computed by usb_gadget_config_buf() */ ++ .bNumInterfaces = 1, ++ .bConfigurationValue = CONFIG_VALUE, ++ .iConfiguration = FSG_STRING_CONFIG, ++ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, ++ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, ++}; ++ ++ ++static struct usb_qualifier_descriptor ++dev_qualifier = { ++ .bLength = sizeof dev_qualifier, ++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER, ++ ++ .bcdUSB = cpu_to_le16(0x0200), ++ .bDeviceClass = USB_CLASS_PER_INTERFACE, ++ ++ .bNumConfigurations = 1, ++}; ++ ++ ++ ++/* ++ * Config descriptors must agree with the code that sets configurations ++ * and with code managing interfaces and their altsettings. They must ++ * also handle different speeds and other-speed requests. ++ */ ++static int populate_config_buf(struct usb_gadget *gadget, ++ u8 *buf, u8 type, unsigned index) ++{ ++ enum usb_device_speed speed = gadget->speed; ++ int len; ++ const struct usb_descriptor_header **function; ++ ++ if (index > 0) ++ return -EINVAL; ++ ++ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) ++ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; ++ if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) ++ function = fsg_hs_function; ++ else ++ function = fsg_fs_function; ++ ++ /* for now, don't advertise srp-only devices */ ++ if (!gadget_is_otg(gadget)) ++ function++; ++ ++ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); ++ ((struct usb_config_descriptor *) buf)->bDescriptorType = type; ++ return len; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* These routines may be called in process context or in_irq */ ++ ++/* Caller must hold fsg->lock */ ++static void wakeup_thread(struct fsg_dev *fsg) ++{ ++ /* Tell the main thread that something has happened */ ++ fsg->thread_wakeup_needed = 1; ++ if (fsg->thread_task) ++ wake_up_process(fsg->thread_task); ++} ++ ++ ++static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) ++{ ++ unsigned long flags; ++ ++ /* Do nothing if a higher-priority exception is already in progress. ++ * If a lower-or-equal priority exception is in progress, preempt it ++ * and notify the main thread by sending it a signal. */ ++ spin_lock_irqsave(&fsg->lock, flags); ++ if (fsg->state <= new_state) { ++ fsg->exception_req_tag = fsg->ep0_req_tag; ++ fsg->state = new_state; ++ if (fsg->thread_task) ++ send_sig_info(SIGUSR1, SEND_SIG_FORCED, ++ fsg->thread_task); ++ } ++ spin_unlock_irqrestore(&fsg->lock, flags); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* The disconnect callback and ep0 routines. These always run in_irq, ++ * except that ep0_queue() is called in the main thread to acknowledge ++ * completion of various requests: set config, set interface, and ++ * Bulk-only device reset. */ ++ ++static void fsg_disconnect(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ ++ DBG(fsg, "disconnect or port reset\n"); ++ raise_exception(fsg, FSG_STATE_DISCONNECT); ++} ++ ++ ++static int ep0_queue(struct fsg_dev *fsg) ++{ ++ int rc; ++ ++ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); ++ if (rc != 0 && rc != -ESHUTDOWN) { ++ ++ /* We can't do much more than wait for a reset */ ++ WARNING(fsg, "error in submission: %s --> %d\n", ++ fsg->ep0->name, rc); ++ } ++ return rc; ++} ++ ++static void ep0_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct fsg_dev *fsg = ep->driver_data; ++ ++ if (req->actual > 0) ++ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); ++ if (req->status || req->actual != req->length) ++ DBG(fsg, "%s --> %d, %u/%u\n", __func__, ++ req->status, req->actual, req->length); ++ if (req->status == -ECONNRESET) // Request was cancelled ++ usb_ep_fifo_flush(ep); ++ ++ if (req->status == 0 && req->context) ++ ((fsg_routine_t) (req->context))(fsg); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Bulk and interrupt endpoint completion handlers. ++ * These always run in_irq. */ ++ ++static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct fsg_dev *fsg = ep->driver_data; ++ struct fsg_buffhd *bh = req->context; ++ ++ if (req->status || req->actual != req->length) ++ DBG(fsg, "%s --> %d, %u/%u\n", __func__, ++ req->status, req->actual, req->length); ++ if (req->status == -ECONNRESET) // Request was cancelled ++ usb_ep_fifo_flush(ep); ++ ++ /* Hold the lock while we update the request and buffer states */ ++ smp_wmb(); ++ spin_lock(&fsg->lock); ++ bh->inreq_busy = 0; ++ bh->state = BUF_STATE_EMPTY; ++ wakeup_thread(fsg); ++ spin_unlock(&fsg->lock); ++} ++ ++static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct fsg_dev *fsg = ep->driver_data; ++ struct fsg_buffhd *bh = req->context; ++ ++ dump_msg(fsg, "bulk-out", req->buf, req->actual); ++ if (req->status || req->actual != bh->bulk_out_intended_length) ++ DBG(fsg, "%s --> %d, %u/%u\n", __func__, ++ req->status, req->actual, ++ bh->bulk_out_intended_length); ++ if (req->status == -ECONNRESET) // Request was cancelled ++ usb_ep_fifo_flush(ep); ++ ++ /* Hold the lock while we update the request and buffer states */ ++ smp_wmb(); ++ spin_lock(&fsg->lock); ++ bh->outreq_busy = 0; ++ bh->state = BUF_STATE_FULL; ++ wakeup_thread(fsg); ++ spin_unlock(&fsg->lock); ++} ++ ++ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct fsg_dev *fsg = ep->driver_data; ++ struct fsg_buffhd *bh = req->context; ++ ++ if (req->status || req->actual != req->length) ++ DBG(fsg, "%s --> %d, %u/%u\n", __func__, ++ req->status, req->actual, req->length); ++ if (req->status == -ECONNRESET) // Request was cancelled ++ usb_ep_fifo_flush(ep); ++ ++ /* Hold the lock while we update the request and buffer states */ ++ smp_wmb(); ++ spin_lock(&fsg->lock); ++ fsg->intreq_busy = 0; ++ bh->state = BUF_STATE_EMPTY; ++ wakeup_thread(fsg); ++ spin_unlock(&fsg->lock); ++} ++ ++#else ++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) ++{} ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Ep0 class-specific handlers. These always run in_irq. */ ++ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct usb_request *req = fsg->ep0req; ++ static u8 cbi_reset_cmnd[6] = { ++ SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; ++ ++ /* Error in command transfer? */ ++ if (req->status || req->length != req->actual || ++ req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { ++ ++ /* Not all controllers allow a protocol stall after ++ * receiving control-out data, but we'll try anyway. */ ++ fsg_set_halt(fsg, fsg->ep0); ++ return; // Wait for reset ++ } ++ ++ /* Is it the special reset command? */ ++ if (req->actual >= sizeof cbi_reset_cmnd && ++ memcmp(req->buf, cbi_reset_cmnd, ++ sizeof cbi_reset_cmnd) == 0) { ++ ++ /* Raise an exception to stop the current operation ++ * and reinitialize our state. */ ++ DBG(fsg, "cbi reset request\n"); ++ raise_exception(fsg, FSG_STATE_RESET); ++ return; ++ } ++ ++ VDBG(fsg, "CB[I] accept device-specific command\n"); ++ spin_lock(&fsg->lock); ++ ++ /* Save the command for later */ ++ if (fsg->cbbuf_cmnd_size) ++ WARNING(fsg, "CB[I] overwriting previous command\n"); ++ fsg->cbbuf_cmnd_size = req->actual; ++ memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); ++ ++ wakeup_thread(fsg); ++ spin_unlock(&fsg->lock); ++} ++ ++#else ++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{} ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ ++ ++static int class_setup_req(struct fsg_dev *fsg, ++ const struct usb_ctrlrequest *ctrl) ++{ ++ struct usb_request *req = fsg->ep0req; ++ int value = -EOPNOTSUPP; ++ u16 w_index = le16_to_cpu(ctrl->wIndex); ++ u16 w_value = le16_to_cpu(ctrl->wValue); ++ u16 w_length = le16_to_cpu(ctrl->wLength); ++ ++ if (!fsg->config) ++ return value; ++ ++ /* Handle Bulk-only class-specific requests */ ++ if (transport_is_bbb()) { ++ switch (ctrl->bRequest) { ++ ++ case USB_BULK_RESET_REQUEST: ++ if (ctrl->bRequestType != (USB_DIR_OUT | ++ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) ++ break; ++ if (w_index != 0 || w_value != 0) { ++ value = -EDOM; ++ break; ++ } ++ ++ /* Raise an exception to stop the current operation ++ * and reinitialize our state. */ ++ DBG(fsg, "bulk reset request\n"); ++ raise_exception(fsg, FSG_STATE_RESET); ++ value = DELAYED_STATUS; ++ break; ++ ++ case USB_BULK_GET_MAX_LUN_REQUEST: ++ if (ctrl->bRequestType != (USB_DIR_IN | ++ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) ++ break; ++ if (w_index != 0 || w_value != 0) { ++ value = -EDOM; ++ break; ++ } ++ VDBG(fsg, "get max LUN\n"); ++ *(u8 *) req->buf = fsg->nluns - 1; ++ value = 1; ++ break; ++ } ++ } ++ ++ /* Handle CBI class-specific requests */ ++ else { ++ switch (ctrl->bRequest) { ++ ++ case USB_CBI_ADSC_REQUEST: ++ if (ctrl->bRequestType != (USB_DIR_OUT | ++ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) ++ break; ++ if (w_index != 0 || w_value != 0) { ++ value = -EDOM; ++ break; ++ } ++ if (w_length > MAX_COMMAND_SIZE) { ++ value = -EOVERFLOW; ++ break; ++ } ++ value = w_length; ++ fsg->ep0req->context = received_cbi_adsc; ++ break; ++ } ++ } ++ ++ if (value == -EOPNOTSUPP) ++ VDBG(fsg, ++ "unknown class-specific control req " ++ "%02x.%02x v%04x i%04x l%u\n", ++ ctrl->bRequestType, ctrl->bRequest, ++ le16_to_cpu(ctrl->wValue), w_index, w_length); ++ return value; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Ep0 standard request handlers. These always run in_irq. */ ++ ++static int standard_setup_req(struct fsg_dev *fsg, ++ const struct usb_ctrlrequest *ctrl) ++{ ++ struct usb_request *req = fsg->ep0req; ++ int value = -EOPNOTSUPP; ++ u16 w_index = le16_to_cpu(ctrl->wIndex); ++ u16 w_value = le16_to_cpu(ctrl->wValue); ++ ++ /* Usually this just stores reply data in the pre-allocated ep0 buffer, ++ * but config change events will also reconfigure hardware. */ ++ switch (ctrl->bRequest) { ++ ++ case USB_REQ_GET_DESCRIPTOR: ++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | ++ USB_RECIP_DEVICE)) ++ break; ++ switch (w_value >> 8) { ++ ++ case USB_DT_DEVICE: ++ VDBG(fsg, "get device descriptor\n"); ++ value = sizeof device_desc; ++ memcpy(req->buf, &device_desc, value); ++ break; ++ case USB_DT_DEVICE_QUALIFIER: ++ VDBG(fsg, "get device qualifier\n"); ++ if (!gadget_is_dualspeed(fsg->gadget)) ++ break; ++ value = sizeof dev_qualifier; ++ memcpy(req->buf, &dev_qualifier, value); ++ break; ++ ++ case USB_DT_OTHER_SPEED_CONFIG: ++ VDBG(fsg, "get other-speed config descriptor\n"); ++ if (!gadget_is_dualspeed(fsg->gadget)) ++ break; ++ goto get_config; ++ case USB_DT_CONFIG: ++ VDBG(fsg, "get configuration descriptor\n"); ++get_config: ++ value = populate_config_buf(fsg->gadget, ++ req->buf, ++ w_value >> 8, ++ w_value & 0xff); ++ break; ++ ++ case USB_DT_STRING: ++ VDBG(fsg, "get string descriptor\n"); ++ ++ /* wIndex == language code */ ++ value = usb_gadget_get_string(&fsg_stringtab, ++ w_value & 0xff, req->buf); ++ break; ++ } ++ break; ++ ++ /* One config, two speeds */ ++ case USB_REQ_SET_CONFIGURATION: ++ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | ++ USB_RECIP_DEVICE)) ++ break; ++ VDBG(fsg, "set configuration\n"); ++ if (w_value == CONFIG_VALUE || w_value == 0) { ++ fsg->new_config = w_value; ++ ++ /* Raise an exception to wipe out previous transaction ++ * state (queued bufs, etc) and set the new config. */ ++ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); ++ value = DELAYED_STATUS; ++ } ++ break; ++ case USB_REQ_GET_CONFIGURATION: ++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | ++ USB_RECIP_DEVICE)) ++ break; ++ VDBG(fsg, "get configuration\n"); ++ *(u8 *) req->buf = fsg->config; ++ value = 1; ++ break; ++ ++ case USB_REQ_SET_INTERFACE: ++ if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | ++ USB_RECIP_INTERFACE)) ++ break; ++ if (fsg->config && w_index == 0) { ++ ++ /* Raise an exception to wipe out previous transaction ++ * state (queued bufs, etc) and install the new ++ * interface altsetting. */ ++ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); ++ value = DELAYED_STATUS; ++ } ++ break; ++ case USB_REQ_GET_INTERFACE: ++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | ++ USB_RECIP_INTERFACE)) ++ break; ++ if (!fsg->config) ++ break; ++ if (w_index != 0) { ++ value = -EDOM; ++ break; ++ } ++ VDBG(fsg, "get interface\n"); ++ *(u8 *) req->buf = 0; ++ value = 1; ++ break; ++ ++ default: ++ VDBG(fsg, ++ "unknown control req %02x.%02x v%04x i%04x l%u\n", ++ ctrl->bRequestType, ctrl->bRequest, ++ w_value, w_index, le16_to_cpu(ctrl->wLength)); ++ } ++ ++ return value; ++} ++ ++ ++static int fsg_setup(struct usb_gadget *gadget, ++ const struct usb_ctrlrequest *ctrl) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ int rc; ++ int w_length = le16_to_cpu(ctrl->wLength); ++ ++ ++fsg->ep0_req_tag; // Record arrival of a new request ++ fsg->ep0req->context = NULL; ++ fsg->ep0req->length = 0; ++ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); ++ ++ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) ++ rc = class_setup_req(fsg, ctrl); ++ else ++ rc = standard_setup_req(fsg, ctrl); ++ ++ /* Respond with data/status or defer until later? */ ++ if (rc >= 0 && rc != DELAYED_STATUS) { ++ rc = min(rc, w_length); ++ fsg->ep0req->length = rc; ++ fsg->ep0req->zero = rc < w_length; ++ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? ++ "ep0-in" : "ep0-out"); ++ rc = ep0_queue(fsg); ++ } ++ ++ /* Device either stalls (rc < 0) or reports success */ ++ return rc; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* All the following routines run in process context */ ++ ++ ++/* Use this for bulk or interrupt transfers, not ep0 */ ++static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, ++ struct usb_request *req, int *pbusy, ++ enum fsg_buffer_state *state) ++{ ++ int rc; ++ ++ if (ep == fsg->bulk_in) ++ dump_msg(fsg, "bulk-in", req->buf, req->length); ++ else if (ep == fsg->intr_in) ++ dump_msg(fsg, "intr-in", req->buf, req->length); ++ ++ spin_lock_irq(&fsg->lock); ++ *pbusy = 1; ++ *state = BUF_STATE_BUSY; ++ spin_unlock_irq(&fsg->lock); ++ rc = usb_ep_queue(ep, req, GFP_KERNEL); ++ if (rc != 0) { ++ *pbusy = 0; ++ *state = BUF_STATE_EMPTY; ++ ++ /* We can't do much more than wait for a reset */ ++ ++ /* Note: currently the net2280 driver fails zero-length ++ * submissions if DMA is enabled. */ ++ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && ++ req->length == 0)) ++ WARNING(fsg, "error in submission: %s --> %d\n", ++ ep->name, rc); ++ } ++} ++ ++ ++static int sleep_thread(struct fsg_dev *fsg) ++{ ++ int rc = 0; ++ ++ /* Wait until a signal arrives or we are woken up */ ++ for (;;) { ++ try_to_freeze(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (signal_pending(current)) { ++ rc = -EINTR; ++ break; ++ } ++ if (fsg->thread_wakeup_needed) ++ break; ++ schedule(); ++ } ++ __set_current_state(TASK_RUNNING); ++ fsg->thread_wakeup_needed = 0; ++ return rc; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int do_read(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u32 lba; ++ struct fsg_buffhd *bh; ++ int rc; ++ u32 amount_left; ++ loff_t file_offset, file_offset_tmp; ++ unsigned int amount; ++ unsigned int partial_page; ++ ssize_t nread; ++ ++ /* Get the starting Logical Block Address and check that it's ++ * not too big */ ++ if (fsg->cmnd[0] == SC_READ_6) ++ lba = get_unaligned_be24(&fsg->cmnd[1]); ++ else { ++ lba = get_unaligned_be32(&fsg->cmnd[2]); ++ ++ /* We allow DPO (Disable Page Out = don't save data in the ++ * cache) and FUA (Force Unit Access = don't read from the ++ * cache), but we don't implement them. */ ++ if ((fsg->cmnd[1] & ~0x18) != 0) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ } ++ if (lba >= curlun->num_sectors) { ++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ return -EINVAL; ++ } ++ file_offset = ((loff_t) lba) << 9; ++ ++ /* Carry out the file reads */ ++ amount_left = fsg->data_size_from_cmnd; ++ if (unlikely(amount_left == 0)) ++ return -EIO; // No default reply ++ ++ for (;;) { ++ ++ /* Figure out how much we need to read: ++ * Try to read the remaining amount. ++ * But don't read more than the buffer size. ++ * And don't try to read past the end of the file. ++ * Finally, if we're not at a page boundary, don't read past ++ * the next page. ++ * If this means reading 0 then we were asked to read past ++ * the end of file. */ ++ amount = min((unsigned int) amount_left, mod_data.buflen); ++ amount = min((loff_t) amount, ++ curlun->file_length - file_offset); ++ partial_page = file_offset & (PAGE_CACHE_SIZE - 1); ++ if (partial_page > 0) ++ amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - ++ partial_page); ++ ++ /* Wait for the next buffer to become available */ ++ bh = fsg->next_buffhd_to_fill; ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ /* If we were asked to read past the end of file, ++ * end with an empty buffer. */ ++ if (amount == 0) { ++ curlun->sense_data = ++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ bh->inreq->length = 0; ++ bh->state = BUF_STATE_FULL; ++ break; ++ } ++ ++ /* Perform the read */ ++ file_offset_tmp = file_offset; ++ nread = vfs_read(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, ++ (unsigned long long) file_offset, ++ (int) nread); ++ if (signal_pending(current)) ++ return -EINTR; ++ ++ if (nread < 0) { ++ LDBG(curlun, "error in file read: %d\n", ++ (int) nread); ++ nread = 0; ++ } else if (nread < amount) { ++ LDBG(curlun, "partial file read: %d/%u\n", ++ (int) nread, amount); ++ nread -= (nread & 511); // Round down to a block ++ } ++ file_offset += nread; ++ amount_left -= nread; ++ fsg->residue -= nread; ++ bh->inreq->length = nread; ++ bh->state = BUF_STATE_FULL; ++ ++ /* If an error occurred, report it and its position */ ++ if (nread < amount) { ++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ break; ++ } ++ ++ if (amount_left == 0) ++ break; // No more left to read ++ ++ /* Send this buffer and go read some more */ ++ bh->inreq->zero = 0; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ } ++ ++ return -EIO; // No default reply ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int do_write(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u32 lba; ++ struct fsg_buffhd *bh; ++ int get_some_more; ++ u32 amount_left_to_req, amount_left_to_write; ++ loff_t usb_offset, file_offset, file_offset_tmp; ++ unsigned int amount; ++ unsigned int partial_page; ++ ssize_t nwritten; ++ int rc; ++ ++ if (curlun->ro) { ++ curlun->sense_data = SS_WRITE_PROTECTED; ++ return -EINVAL; ++ } ++ spin_lock(&curlun->filp->f_lock); ++ curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait ++ spin_unlock(&curlun->filp->f_lock); ++ ++ /* Get the starting Logical Block Address and check that it's ++ * not too big */ ++ if (fsg->cmnd[0] == SC_WRITE_6) ++ lba = get_unaligned_be24(&fsg->cmnd[1]); ++ else { ++ lba = get_unaligned_be32(&fsg->cmnd[2]); ++ ++ /* We allow DPO (Disable Page Out = don't save data in the ++ * cache) and FUA (Force Unit Access = write directly to the ++ * medium). We don't implement DPO; we implement FUA by ++ * performing synchronous output. */ ++ if ((fsg->cmnd[1] & ~0x18) != 0) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ if (fsg->cmnd[1] & 0x08) { // FUA ++ spin_lock(&curlun->filp->f_lock); ++ curlun->filp->f_flags |= O_SYNC; ++ spin_unlock(&curlun->filp->f_lock); ++ } ++ } ++ if (lba >= curlun->num_sectors) { ++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ return -EINVAL; ++ } ++ ++ /* Carry out the file writes */ ++ get_some_more = 1; ++ file_offset = usb_offset = ((loff_t) lba) << 9; ++ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; ++ ++ while (amount_left_to_write > 0) { ++ ++ /* Queue a request for more data from the host */ ++ bh = fsg->next_buffhd_to_fill; ++ if (bh->state == BUF_STATE_EMPTY && get_some_more) { ++ ++ /* Figure out how much we want to get: ++ * Try to get the remaining amount. ++ * But don't get more than the buffer size. ++ * And don't try to go past the end of the file. ++ * If we're not at a page boundary, ++ * don't go past the next page. ++ * If this means getting 0, then we were asked ++ * to write past the end of file. ++ * Finally, round down to a block boundary. */ ++ amount = min(amount_left_to_req, mod_data.buflen); ++ amount = min((loff_t) amount, curlun->file_length - ++ usb_offset); ++ partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); ++ if (partial_page > 0) ++ amount = min(amount, ++ (unsigned int) PAGE_CACHE_SIZE - partial_page); ++ ++ if (amount == 0) { ++ get_some_more = 0; ++ curlun->sense_data = ++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ curlun->sense_data_info = usb_offset >> 9; ++ curlun->info_valid = 1; ++ continue; ++ } ++ amount -= (amount & 511); ++ if (amount == 0) { ++ ++ /* Why were we were asked to transfer a ++ * partial block? */ ++ get_some_more = 0; ++ continue; ++ } ++ ++ /* Get the next buffer */ ++ usb_offset += amount; ++ fsg->usb_amount_left -= amount; ++ amount_left_to_req -= amount; ++ if (amount_left_to_req == 0) ++ get_some_more = 0; ++ ++ /* amount is always divisible by 512, hence by ++ * the bulk-out maxpacket size */ ++ bh->outreq->length = bh->bulk_out_intended_length = ++ amount; ++ bh->outreq->short_not_ok = 1; ++ start_transfer(fsg, fsg->bulk_out, bh->outreq, ++ &bh->outreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ continue; ++ } ++ ++ /* Write the received data to the backing file */ ++ bh = fsg->next_buffhd_to_drain; ++ if (bh->state == BUF_STATE_EMPTY && !get_some_more) ++ break; // We stopped early ++ if (bh->state == BUF_STATE_FULL) { ++ smp_rmb(); ++ fsg->next_buffhd_to_drain = bh->next; ++ bh->state = BUF_STATE_EMPTY; ++ ++ /* Did something go wrong with the transfer? */ ++ if (bh->outreq->status != 0) { ++ curlun->sense_data = SS_COMMUNICATION_FAILURE; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ break; ++ } ++ ++ amount = bh->outreq->actual; ++ if (curlun->file_length - file_offset < amount) { ++ LERROR(curlun, ++ "write %u @ %llu beyond end %llu\n", ++ amount, (unsigned long long) file_offset, ++ (unsigned long long) curlun->file_length); ++ amount = curlun->file_length - file_offset; ++ } ++ ++ /* Perform the write */ ++ file_offset_tmp = file_offset; ++ nwritten = vfs_write(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, ++ (unsigned long long) file_offset, ++ (int) nwritten); ++ if (signal_pending(current)) ++ return -EINTR; // Interrupted! ++ ++ if (nwritten < 0) { ++ LDBG(curlun, "error in file write: %d\n", ++ (int) nwritten); ++ nwritten = 0; ++ } else if (nwritten < amount) { ++ LDBG(curlun, "partial file write: %d/%u\n", ++ (int) nwritten, amount); ++ nwritten -= (nwritten & 511); ++ // Round down to a block ++ } ++ file_offset += nwritten; ++ amount_left_to_write -= nwritten; ++ fsg->residue -= nwritten; ++ ++ /* If an error occurred, report it and its position */ ++ if (nwritten < amount) { ++ curlun->sense_data = SS_WRITE_ERROR; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ break; ++ } ++ ++ /* Did the host decide to stop early? */ ++ if (bh->outreq->actual != bh->outreq->length) { ++ fsg->short_packet_received = 1; ++ break; ++ } ++ continue; ++ } ++ ++ /* Wait for something to happen */ ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ return -EIO; // No default reply ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int do_synchronize_cache(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int rc; ++ ++ /* We ignore the requested LBA and write out all file's ++ * dirty data buffers. */ ++ rc = fsg_lun_fsync_sub(curlun); ++ if (rc) ++ curlun->sense_data = SS_WRITE_ERROR; ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void invalidate_sub(struct fsg_lun *curlun) ++{ ++ struct file *filp = curlun->filp; ++ struct inode *inode = filp->f_path.dentry->d_inode; ++ unsigned long rc; ++ ++ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); ++ VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); ++} ++ ++static int do_verify(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u32 lba; ++ u32 verification_length; ++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ loff_t file_offset, file_offset_tmp; ++ u32 amount_left; ++ unsigned int amount; ++ ssize_t nread; ++ ++ /* Get the starting Logical Block Address and check that it's ++ * not too big */ ++ lba = get_unaligned_be32(&fsg->cmnd[2]); ++ if (lba >= curlun->num_sectors) { ++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ return -EINVAL; ++ } ++ ++ /* We allow DPO (Disable Page Out = don't save data in the ++ * cache) but we don't implement it. */ ++ if ((fsg->cmnd[1] & ~0x10) != 0) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ verification_length = get_unaligned_be16(&fsg->cmnd[7]); ++ if (unlikely(verification_length == 0)) ++ return -EIO; // No default reply ++ ++ /* Prepare to carry out the file verify */ ++ amount_left = verification_length << 9; ++ file_offset = ((loff_t) lba) << 9; ++ ++ /* Write out all the dirty buffers before invalidating them */ ++ fsg_lun_fsync_sub(curlun); ++ if (signal_pending(current)) ++ return -EINTR; ++ ++ invalidate_sub(curlun); ++ if (signal_pending(current)) ++ return -EINTR; ++ ++ /* Just try to read the requested blocks */ ++ while (amount_left > 0) { ++ ++ /* Figure out how much we need to read: ++ * Try to read the remaining amount, but not more than ++ * the buffer size. ++ * And don't try to read past the end of the file. ++ * If this means reading 0 then we were asked to read ++ * past the end of file. */ ++ amount = min((unsigned int) amount_left, mod_data.buflen); ++ amount = min((loff_t) amount, ++ curlun->file_length - file_offset); ++ if (amount == 0) { ++ curlun->sense_data = ++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ break; ++ } ++ ++ /* Perform the read */ ++ file_offset_tmp = file_offset; ++ nread = vfs_read(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, ++ (unsigned long long) file_offset, ++ (int) nread); ++ if (signal_pending(current)) ++ return -EINTR; ++ ++ if (nread < 0) { ++ LDBG(curlun, "error in file verify: %d\n", ++ (int) nread); ++ nread = 0; ++ } else if (nread < amount) { ++ LDBG(curlun, "partial file verify: %d/%u\n", ++ (int) nread, amount); ++ nread -= (nread & 511); // Round down to a sector ++ } ++ if (nread == 0) { ++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR; ++ curlun->sense_data_info = file_offset >> 9; ++ curlun->info_valid = 1; ++ break; ++ } ++ file_offset += nread; ++ amount_left -= nread; ++ } ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ u8 *buf = (u8 *) bh->buf; ++ ++ static char vendor_id[] = "Linux "; ++ static char product_disk_id[] = "File-Stor Gadget"; ++ static char product_cdrom_id[] = "File-CD Gadget "; ++ ++ if (!fsg->curlun) { // Unsupported LUNs are okay ++ fsg->bad_lun_okay = 1; ++ memset(buf, 0, 36); ++ buf[0] = 0x7f; // Unsupported, no device-type ++ buf[4] = 31; // Additional length ++ return 36; ++ } ++ ++ memset(buf, 0, 8); ++ buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK); ++ if (mod_data.removable) ++ buf[1] = 0x80; ++ buf[2] = 2; // ANSI SCSI level 2 ++ buf[3] = 2; // SCSI-2 INQUIRY data format ++ buf[4] = 31; // Additional length ++ // No special options ++ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, ++ (mod_data.cdrom ? product_cdrom_id : ++ product_disk_id), ++ mod_data.release); ++ return 36; ++} ++ ++ ++static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u8 *buf = (u8 *) bh->buf; ++ u32 sd, sdinfo; ++ int valid; ++ ++ /* ++ * From the SCSI-2 spec., section 7.9 (Unit attention condition): ++ * ++ * If a REQUEST SENSE command is received from an initiator ++ * with a pending unit attention condition (before the target ++ * generates the contingent allegiance condition), then the ++ * target shall either: ++ * a) report any pending sense data and preserve the unit ++ * attention condition on the logical unit, or, ++ * b) report the unit attention condition, may discard any ++ * pending sense data, and clear the unit attention ++ * condition on the logical unit for that initiator. ++ * ++ * FSG normally uses option a); enable this code to use option b). ++ */ ++#if 0 ++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { ++ curlun->sense_data = curlun->unit_attention_data; ++ curlun->unit_attention_data = SS_NO_SENSE; ++ } ++#endif ++ ++ if (!curlun) { // Unsupported LUNs are okay ++ fsg->bad_lun_okay = 1; ++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; ++ sdinfo = 0; ++ valid = 0; ++ } else { ++ sd = curlun->sense_data; ++ sdinfo = curlun->sense_data_info; ++ valid = curlun->info_valid << 7; ++ curlun->sense_data = SS_NO_SENSE; ++ curlun->sense_data_info = 0; ++ curlun->info_valid = 0; ++ } ++ ++ memset(buf, 0, 18); ++ buf[0] = valid | 0x70; // Valid, current error ++ buf[2] = SK(sd); ++ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ ++ buf[7] = 18 - 8; // Additional sense length ++ buf[12] = ASC(sd); ++ buf[13] = ASCQ(sd); ++ return 18; ++} ++ ++ ++static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]); ++ int pmi = fsg->cmnd[8]; ++ u8 *buf = (u8 *) bh->buf; ++ ++ /* Check the PMI and LBA fields */ ++ if (pmi > 1 || (pmi == 0 && lba != 0)) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); ++ /* Max logical block */ ++ put_unaligned_be32(512, &buf[4]); /* Block length */ ++ return 8; ++} ++ ++ ++static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int msf = fsg->cmnd[1] & 0x02; ++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]); ++ u8 *buf = (u8 *) bh->buf; ++ ++ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ if (lba >= curlun->num_sectors) { ++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; ++ return -EINVAL; ++ } ++ ++ memset(buf, 0, 8); ++ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ ++ store_cdrom_address(&buf[4], msf, lba); ++ return 8; ++} ++ ++ ++static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int msf = fsg->cmnd[1] & 0x02; ++ int start_track = fsg->cmnd[6]; ++ u8 *buf = (u8 *) bh->buf; ++ ++ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ ++ start_track > 1) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ memset(buf, 0, 20); ++ buf[1] = (20-2); /* TOC data length */ ++ buf[2] = 1; /* First track number */ ++ buf[3] = 1; /* Last track number */ ++ buf[5] = 0x16; /* Data track, copying allowed */ ++ buf[6] = 0x01; /* Only track is number 1 */ ++ store_cdrom_address(&buf[8], msf, 0); ++ ++ buf[13] = 0x16; /* Lead-out track is data */ ++ buf[14] = 0xAA; /* Lead-out track number */ ++ store_cdrom_address(&buf[16], msf, curlun->num_sectors); ++ return 20; ++} ++ ++ ++static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int mscmnd = fsg->cmnd[0]; ++ u8 *buf = (u8 *) bh->buf; ++ u8 *buf0 = buf; ++ int pc, page_code; ++ int changeable_values, all_pages; ++ int valid_page = 0; ++ int len, limit; ++ ++ if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ pc = fsg->cmnd[2] >> 6; ++ page_code = fsg->cmnd[2] & 0x3f; ++ if (pc == 3) { ++ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; ++ return -EINVAL; ++ } ++ changeable_values = (pc == 1); ++ all_pages = (page_code == 0x3f); ++ ++ /* Write the mode parameter header. Fixed values are: default ++ * medium type, no cache control (DPOFUA), and no block descriptors. ++ * The only variable value is the WriteProtect bit. We will fill in ++ * the mode data length later. */ ++ memset(buf, 0, 8); ++ if (mscmnd == SC_MODE_SENSE_6) { ++ buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA ++ buf += 4; ++ limit = 255; ++ } else { // SC_MODE_SENSE_10 ++ buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA ++ buf += 8; ++ limit = 65535; // Should really be mod_data.buflen ++ } ++ ++ /* No block descriptors */ ++ ++ /* The mode pages, in numerical order. The only page we support ++ * is the Caching page. */ ++ if (page_code == 0x08 || all_pages) { ++ valid_page = 1; ++ buf[0] = 0x08; // Page code ++ buf[1] = 10; // Page length ++ memset(buf+2, 0, 10); // None of the fields are changeable ++ ++ if (!changeable_values) { ++ buf[2] = 0x04; // Write cache enable, ++ // Read cache not disabled ++ // No cache retention priorities ++ put_unaligned_be16(0xffff, &buf[4]); ++ /* Don't disable prefetch */ ++ /* Minimum prefetch = 0 */ ++ put_unaligned_be16(0xffff, &buf[8]); ++ /* Maximum prefetch */ ++ put_unaligned_be16(0xffff, &buf[10]); ++ /* Maximum prefetch ceiling */ ++ } ++ buf += 12; ++ } ++ ++ /* Check that a valid page was requested and the mode data length ++ * isn't too long. */ ++ len = buf - buf0; ++ if (!valid_page || len > limit) { ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ /* Store the mode data length */ ++ if (mscmnd == SC_MODE_SENSE_6) ++ buf0[0] = len - 1; ++ else ++ put_unaligned_be16(len - 2, buf0); ++ return len; ++} ++ ++ ++static int do_start_stop(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int loej, start; ++ ++ if (!mod_data.removable) { ++ curlun->sense_data = SS_INVALID_COMMAND; ++ return -EINVAL; ++ } ++ ++ // int immed = fsg->cmnd[1] & 0x01; ++ loej = fsg->cmnd[4] & 0x02; ++ start = fsg->cmnd[4] & 0x01; ++ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed ++ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ if (!start) { ++ ++ /* Are we allowed to unload the media? */ ++ if (curlun->prevent_medium_removal) { ++ LDBG(curlun, "unload attempt prevented\n"); ++ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; ++ return -EINVAL; ++ } ++ if (loej) { // Simulate an unload/eject ++ up_read(&fsg->filesem); ++ down_write(&fsg->filesem); ++ fsg_lun_close(curlun); ++ up_write(&fsg->filesem); ++ down_read(&fsg->filesem); ++ } ++ } else { ++ ++ /* Our emulation doesn't support mounting; the medium is ++ * available for use as soon as it is loaded. */ ++ if (!fsg_lun_is_open(curlun)) { ++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT; ++ return -EINVAL; ++ } ++ } ++#endif ++ return 0; ++} ++ ++ ++static int do_prevent_allow(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ int prevent; ++ ++ if (!mod_data.removable) { ++ curlun->sense_data = SS_INVALID_COMMAND; ++ return -EINVAL; ++ } ++ ++ prevent = fsg->cmnd[4] & 0x01; ++ if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ ++ if (curlun->prevent_medium_removal && !prevent) ++ fsg_lun_fsync_sub(curlun); ++ curlun->prevent_medium_removal = prevent; ++ return 0; ++} ++ ++ ++static int do_read_format_capacities(struct fsg_dev *fsg, ++ struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ u8 *buf = (u8 *) bh->buf; ++ ++ buf[0] = buf[1] = buf[2] = 0; ++ buf[3] = 8; // Only the Current/Maximum Capacity Descriptor ++ buf += 4; ++ ++ put_unaligned_be32(curlun->num_sectors, &buf[0]); ++ /* Number of blocks */ ++ put_unaligned_be32(512, &buf[4]); /* Block length */ ++ buf[4] = 0x02; /* Current capacity */ ++ return 12; ++} ++ ++ ++static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ ++ /* We don't support MODE SELECT */ ++ curlun->sense_data = SS_INVALID_COMMAND; ++ return -EINVAL; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int halt_bulk_in_endpoint(struct fsg_dev *fsg) ++{ ++ int rc; ++ ++ rc = fsg_set_halt(fsg, fsg->bulk_in); ++ if (rc == -EAGAIN) ++ VDBG(fsg, "delayed bulk-in endpoint halt\n"); ++ while (rc != 0) { ++ if (rc != -EAGAIN) { ++ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); ++ rc = 0; ++ break; ++ } ++ ++ /* Wait for a short time and then try again */ ++ if (msleep_interruptible(100) != 0) ++ return -EINTR; ++ rc = usb_ep_set_halt(fsg->bulk_in); ++ } ++ return rc; ++} ++ ++static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) ++{ ++ int rc; ++ ++ DBG(fsg, "bulk-in set wedge\n"); ++ rc = usb_ep_set_wedge(fsg->bulk_in); ++ if (rc == -EAGAIN) ++ VDBG(fsg, "delayed bulk-in endpoint wedge\n"); ++ while (rc != 0) { ++ if (rc != -EAGAIN) { ++ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); ++ rc = 0; ++ break; ++ } ++ ++ /* Wait for a short time and then try again */ ++ if (msleep_interruptible(100) != 0) ++ return -EINTR; ++ rc = usb_ep_set_wedge(fsg->bulk_in); ++ } ++ return rc; ++} ++ ++static int pad_with_zeros(struct fsg_dev *fsg) ++{ ++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ u32 nkeep = bh->inreq->length; ++ u32 nsend; ++ int rc; ++ ++ bh->state = BUF_STATE_EMPTY; // For the first iteration ++ fsg->usb_amount_left = nkeep + fsg->residue; ++ while (fsg->usb_amount_left > 0) { ++ ++ /* Wait for the next buffer to be free */ ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen); ++ memset(bh->buf + nkeep, 0, nsend - nkeep); ++ bh->inreq->length = nsend; ++ bh->inreq->zero = 0; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ bh = fsg->next_buffhd_to_fill = bh->next; ++ fsg->usb_amount_left -= nsend; ++ nkeep = 0; ++ } ++ return 0; ++} ++ ++static int throw_away_data(struct fsg_dev *fsg) ++{ ++ struct fsg_buffhd *bh; ++ u32 amount; ++ int rc; ++ ++ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || ++ fsg->usb_amount_left > 0) { ++ ++ /* Throw away the data in a filled buffer */ ++ if (bh->state == BUF_STATE_FULL) { ++ smp_rmb(); ++ bh->state = BUF_STATE_EMPTY; ++ fsg->next_buffhd_to_drain = bh->next; ++ ++ /* A short packet or an error ends everything */ ++ if (bh->outreq->actual != bh->outreq->length || ++ bh->outreq->status != 0) { ++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); ++ return -EINTR; ++ } ++ continue; ++ } ++ ++ /* Try to submit another request if we need one */ ++ bh = fsg->next_buffhd_to_fill; ++ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { ++ amount = min(fsg->usb_amount_left, ++ (u32) mod_data.buflen); ++ ++ /* amount is always divisible by 512, hence by ++ * the bulk-out maxpacket size */ ++ bh->outreq->length = bh->bulk_out_intended_length = ++ amount; ++ bh->outreq->short_not_ok = 1; ++ start_transfer(fsg, fsg->bulk_out, bh->outreq, ++ &bh->outreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ fsg->usb_amount_left -= amount; ++ continue; ++ } ++ ++ /* Otherwise wait for something to happen */ ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ return 0; ++} ++ ++ ++static int finish_reply(struct fsg_dev *fsg) ++{ ++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; ++ int rc = 0; ++ ++ switch (fsg->data_dir) { ++ case DATA_DIR_NONE: ++ break; // Nothing to send ++ ++ /* If we don't know whether the host wants to read or write, ++ * this must be CB or CBI with an unknown command. We mustn't ++ * try to send or receive any data. So stall both bulk pipes ++ * if we can and wait for a reset. */ ++ case DATA_DIR_UNKNOWN: ++ if (mod_data.can_stall) { ++ fsg_set_halt(fsg, fsg->bulk_out); ++ rc = halt_bulk_in_endpoint(fsg); ++ } ++ break; ++ ++ /* All but the last buffer of data must have already been sent */ ++ case DATA_DIR_TO_HOST: ++ if (fsg->data_size == 0) ++ ; // Nothing to send ++ ++ /* If there's no residue, simply send the last buffer */ ++ else if (fsg->residue == 0) { ++ bh->inreq->zero = 0; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ } ++ ++ /* There is a residue. For CB and CBI, simply mark the end ++ * of the data with a short packet. However, if we are ++ * allowed to stall, there was no data at all (residue == ++ * data_size), and the command failed (invalid LUN or ++ * sense data is set), then halt the bulk-in endpoint ++ * instead. */ ++ else if (!transport_is_bbb()) { ++ if (mod_data.can_stall && ++ fsg->residue == fsg->data_size && ++ (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { ++ bh->state = BUF_STATE_EMPTY; ++ rc = halt_bulk_in_endpoint(fsg); ++ } else { ++ bh->inreq->zero = 1; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ } ++ } ++ ++ /* For Bulk-only, if we're allowed to stall then send the ++ * short packet and halt the bulk-in endpoint. If we can't ++ * stall, pad out the remaining data with 0's. */ ++ else { ++ if (mod_data.can_stall) { ++ bh->inreq->zero = 1; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ rc = halt_bulk_in_endpoint(fsg); ++ } else ++ rc = pad_with_zeros(fsg); ++ } ++ break; ++ ++ /* We have processed all we want from the data the host has sent. ++ * There may still be outstanding bulk-out requests. */ ++ case DATA_DIR_FROM_HOST: ++ if (fsg->residue == 0) ++ ; // Nothing to receive ++ ++ /* Did the host stop sending unexpectedly early? */ ++ else if (fsg->short_packet_received) { ++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); ++ rc = -EINTR; ++ } ++ ++ /* We haven't processed all the incoming data. Even though ++ * we may be allowed to stall, doing so would cause a race. ++ * The controller may already have ACK'ed all the remaining ++ * bulk-out packets, in which case the host wouldn't see a ++ * STALL. Not realizing the endpoint was halted, it wouldn't ++ * clear the halt -- leading to problems later on. */ ++#if 0 ++ else if (mod_data.can_stall) { ++ fsg_set_halt(fsg, fsg->bulk_out); ++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); ++ rc = -EINTR; ++ } ++#endif ++ ++ /* We can't stall. Read in the excess data and throw it ++ * all away. */ ++ else ++ rc = throw_away_data(fsg); ++ break; ++ } ++ return rc; ++} ++ ++ ++static int send_status(struct fsg_dev *fsg) ++{ ++ struct fsg_lun *curlun = fsg->curlun; ++ struct fsg_buffhd *bh; ++ int rc; ++ u8 status = USB_STATUS_PASS; ++ u32 sd, sdinfo = 0; ++ ++ /* Wait for the next buffer to become available */ ++ bh = fsg->next_buffhd_to_fill; ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ if (curlun) { ++ sd = curlun->sense_data; ++ sdinfo = curlun->sense_data_info; ++ } else if (fsg->bad_lun_okay) ++ sd = SS_NO_SENSE; ++ else ++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; ++ ++ if (fsg->phase_error) { ++ DBG(fsg, "sending phase-error status\n"); ++ status = USB_STATUS_PHASE_ERROR; ++ sd = SS_INVALID_COMMAND; ++ } else if (sd != SS_NO_SENSE) { ++ DBG(fsg, "sending command-failure status\n"); ++ status = USB_STATUS_FAIL; ++ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" ++ " info x%x\n", ++ SK(sd), ASC(sd), ASCQ(sd), sdinfo); ++ } ++ ++ if (transport_is_bbb()) { ++ struct bulk_cs_wrap *csw = bh->buf; ++ ++ /* Store and send the Bulk-only CSW */ ++ csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); ++ csw->Tag = fsg->tag; ++ csw->Residue = cpu_to_le32(fsg->residue); ++ csw->Status = status; ++ ++ bh->inreq->length = USB_BULK_CS_WRAP_LEN; ++ bh->inreq->zero = 0; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ ++ } else if (mod_data.transport_type == USB_PR_CB) { ++ ++ /* Control-Bulk transport has no status phase! */ ++ return 0; ++ ++ } else { // USB_PR_CBI ++ struct interrupt_data *buf = bh->buf; ++ ++ /* Store and send the Interrupt data. UFI sends the ASC ++ * and ASCQ bytes. Everything else sends a Type (which ++ * is always 0) and the status Value. */ ++ if (mod_data.protocol_type == USB_SC_UFI) { ++ buf->bType = ASC(sd); ++ buf->bValue = ASCQ(sd); ++ } else { ++ buf->bType = 0; ++ buf->bValue = status; ++ } ++ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; ++ ++ fsg->intr_buffhd = bh; // Point to the right buffhd ++ fsg->intreq->buf = bh->inreq->buf; ++ fsg->intreq->context = bh; ++ start_transfer(fsg, fsg->intr_in, fsg->intreq, ++ &fsg->intreq_busy, &bh->state); ++ } ++ ++ fsg->next_buffhd_to_fill = bh->next; ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Check whether the command is properly formed and whether its data size ++ * and direction agree with the values we already have. */ ++static int check_command(struct fsg_dev *fsg, int cmnd_size, ++ enum data_direction data_dir, unsigned int mask, ++ int needs_medium, const char *name) ++{ ++ int i; ++ int lun = fsg->cmnd[1] >> 5; ++ static const char dirletter[4] = {'u', 'o', 'i', 'n'}; ++ char hdlen[20]; ++ struct fsg_lun *curlun; ++ ++ /* Adjust the expected cmnd_size for protocol encapsulation padding. ++ * Transparent SCSI doesn't pad. */ ++ if (protocol_is_scsi()) ++ ; ++ ++ /* There's some disagreement as to whether RBC pads commands or not. ++ * We'll play it safe and accept either form. */ ++ else if (mod_data.protocol_type == USB_SC_RBC) { ++ if (fsg->cmnd_size == 12) ++ cmnd_size = 12; ++ ++ /* All the other protocols pad to 12 bytes */ ++ } else ++ cmnd_size = 12; ++ ++ hdlen[0] = 0; ++ if (fsg->data_dir != DATA_DIR_UNKNOWN) ++ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], ++ fsg->data_size); ++ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", ++ name, cmnd_size, dirletter[(int) data_dir], ++ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); ++ ++ /* We can't reply at all until we know the correct data direction ++ * and size. */ ++ if (fsg->data_size_from_cmnd == 0) ++ data_dir = DATA_DIR_NONE; ++ if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI ++ fsg->data_dir = data_dir; ++ fsg->data_size = fsg->data_size_from_cmnd; ++ ++ } else { // Bulk-only ++ if (fsg->data_size < fsg->data_size_from_cmnd) { ++ ++ /* Host data size < Device data size is a phase error. ++ * Carry out the command, but only transfer as much ++ * as we are allowed. */ ++ fsg->data_size_from_cmnd = fsg->data_size; ++ fsg->phase_error = 1; ++ } ++ } ++ fsg->residue = fsg->usb_amount_left = fsg->data_size; ++ ++ /* Conflicting data directions is a phase error */ ++ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { ++ fsg->phase_error = 1; ++ return -EINVAL; ++ } ++ ++ /* Verify the length of the command itself */ ++ if (cmnd_size != fsg->cmnd_size) { ++ ++ /* Special case workaround: There are plenty of buggy SCSI ++ * implementations. Many have issues with cbw->Length ++ * field passing a wrong command size. For those cases we ++ * always try to work around the problem by using the length ++ * sent by the host side provided it is at least as large ++ * as the correct command length. ++ * Examples of such cases would be MS-Windows, which issues ++ * REQUEST SENSE with cbw->Length == 12 where it should ++ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and ++ * REQUEST SENSE with cbw->Length == 10 where it should ++ * be 6 as well. ++ */ ++ if (cmnd_size <= fsg->cmnd_size) { ++ DBG(fsg, "%s is buggy! Expected length %d " ++ "but we got %d\n", name, ++ cmnd_size, fsg->cmnd_size); ++ cmnd_size = fsg->cmnd_size; ++ } else { ++ fsg->phase_error = 1; ++ return -EINVAL; ++ } ++ } ++ ++ /* Check that the LUN values are consistent */ ++ if (transport_is_bbb()) { ++ if (fsg->lun != lun) ++ DBG(fsg, "using LUN %d from CBW, " ++ "not LUN %d from CDB\n", ++ fsg->lun, lun); ++ } else ++ fsg->lun = lun; // Use LUN from the command ++ ++ /* Check the LUN */ ++ if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { ++ fsg->curlun = curlun = &fsg->luns[fsg->lun]; ++ if (fsg->cmnd[0] != SC_REQUEST_SENSE) { ++ curlun->sense_data = SS_NO_SENSE; ++ curlun->sense_data_info = 0; ++ curlun->info_valid = 0; ++ } ++ } else { ++ fsg->curlun = curlun = NULL; ++ fsg->bad_lun_okay = 0; ++ ++ /* INQUIRY and REQUEST SENSE commands are explicitly allowed ++ * to use unsupported LUNs; all others may not. */ ++ if (fsg->cmnd[0] != SC_INQUIRY && ++ fsg->cmnd[0] != SC_REQUEST_SENSE) { ++ DBG(fsg, "unsupported LUN %d\n", fsg->lun); ++ return -EINVAL; ++ } ++ } ++ ++ /* If a unit attention condition exists, only INQUIRY and ++ * REQUEST SENSE commands are allowed; anything else must fail. */ ++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE && ++ fsg->cmnd[0] != SC_INQUIRY && ++ fsg->cmnd[0] != SC_REQUEST_SENSE) { ++ curlun->sense_data = curlun->unit_attention_data; ++ curlun->unit_attention_data = SS_NO_SENSE; ++ return -EINVAL; ++ } ++ ++ /* Check that only command bytes listed in the mask are non-zero */ ++ fsg->cmnd[1] &= 0x1f; // Mask away the LUN ++ for (i = 1; i < cmnd_size; ++i) { ++ if (fsg->cmnd[i] && !(mask & (1 << i))) { ++ if (curlun) ++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ return -EINVAL; ++ } ++ } ++ ++ /* If the medium isn't mounted and the command needs to access ++ * it, return an error. */ ++ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { ++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT; ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++static int do_scsi_command(struct fsg_dev *fsg) ++{ ++ struct fsg_buffhd *bh; ++ int rc; ++ int reply = -EINVAL; ++ int i; ++ static char unknown[16]; ++ ++ dump_cdb(fsg); ++ ++ /* Wait for the next buffer to become available for data or status */ ++ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ fsg->phase_error = 0; ++ fsg->short_packet_received = 0; ++ ++ down_read(&fsg->filesem); // We're using the backing file ++ switch (fsg->cmnd[0]) { ++ ++ case SC_INQUIRY: ++ fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, ++ (1<<4), 0, ++ "INQUIRY")) == 0) ++ reply = do_inquiry(fsg, bh); ++ break; ++ ++ case SC_MODE_SELECT_6: ++ fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, ++ (1<<1) | (1<<4), 0, ++ "MODE SELECT(6)")) == 0) ++ reply = do_mode_select(fsg, bh); ++ break; ++ ++ case SC_MODE_SELECT_10: ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, ++ (1<<1) | (3<<7), 0, ++ "MODE SELECT(10)")) == 0) ++ reply = do_mode_select(fsg, bh); ++ break; ++ ++ case SC_MODE_SENSE_6: ++ fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, ++ (1<<1) | (1<<2) | (1<<4), 0, ++ "MODE SENSE(6)")) == 0) ++ reply = do_mode_sense(fsg, bh); ++ break; ++ ++ case SC_MODE_SENSE_10: ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (1<<1) | (1<<2) | (3<<7), 0, ++ "MODE SENSE(10)")) == 0) ++ reply = do_mode_sense(fsg, bh); ++ break; ++ ++ case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: ++ fsg->data_size_from_cmnd = 0; ++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE, ++ (1<<4), 0, ++ "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) ++ reply = do_prevent_allow(fsg); ++ break; ++ ++ case SC_READ_6: ++ i = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; ++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, ++ (7<<1) | (1<<4), 1, ++ "READ(6)")) == 0) ++ reply = do_read(fsg); ++ break; ++ ++ case SC_READ_10: ++ fsg->data_size_from_cmnd = ++ get_unaligned_be16(&fsg->cmnd[7]) << 9; ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (1<<1) | (0xf<<2) | (3<<7), 1, ++ "READ(10)")) == 0) ++ reply = do_read(fsg); ++ break; ++ ++ case SC_READ_12: ++ fsg->data_size_from_cmnd = ++ get_unaligned_be32(&fsg->cmnd[6]) << 9; ++ if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, ++ (1<<1) | (0xf<<2) | (0xf<<6), 1, ++ "READ(12)")) == 0) ++ reply = do_read(fsg); ++ break; ++ ++ case SC_READ_CAPACITY: ++ fsg->data_size_from_cmnd = 8; ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (0xf<<2) | (1<<8), 1, ++ "READ CAPACITY")) == 0) ++ reply = do_read_capacity(fsg, bh); ++ break; ++ ++ case SC_READ_HEADER: ++ if (!mod_data.cdrom) ++ goto unknown_cmnd; ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (3<<7) | (0x1f<<1), 1, ++ "READ HEADER")) == 0) ++ reply = do_read_header(fsg, bh); ++ break; ++ ++ case SC_READ_TOC: ++ if (!mod_data.cdrom) ++ goto unknown_cmnd; ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (7<<6) | (1<<1), 1, ++ "READ TOC")) == 0) ++ reply = do_read_toc(fsg, bh); ++ break; ++ ++ case SC_READ_FORMAT_CAPACITIES: ++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); ++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, ++ (3<<7), 1, ++ "READ FORMAT CAPACITIES")) == 0) ++ reply = do_read_format_capacities(fsg, bh); ++ break; ++ ++ case SC_REQUEST_SENSE: ++ fsg->data_size_from_cmnd = fsg->cmnd[4]; ++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, ++ (1<<4), 0, ++ "REQUEST SENSE")) == 0) ++ reply = do_request_sense(fsg, bh); ++ break; ++ ++ case SC_START_STOP_UNIT: ++ fsg->data_size_from_cmnd = 0; ++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE, ++ (1<<1) | (1<<4), 0, ++ "START-STOP UNIT")) == 0) ++ reply = do_start_stop(fsg); ++ break; ++ ++ case SC_SYNCHRONIZE_CACHE: ++ fsg->data_size_from_cmnd = 0; ++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE, ++ (0xf<<2) | (3<<7), 1, ++ "SYNCHRONIZE CACHE")) == 0) ++ reply = do_synchronize_cache(fsg); ++ break; ++ ++ case SC_TEST_UNIT_READY: ++ fsg->data_size_from_cmnd = 0; ++ reply = check_command(fsg, 6, DATA_DIR_NONE, ++ 0, 1, ++ "TEST UNIT READY"); ++ break; ++ ++ /* Although optional, this command is used by MS-Windows. We ++ * support a minimal version: BytChk must be 0. */ ++ case SC_VERIFY: ++ fsg->data_size_from_cmnd = 0; ++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE, ++ (1<<1) | (0xf<<2) | (3<<7), 1, ++ "VERIFY")) == 0) ++ reply = do_verify(fsg); ++ break; ++ ++ case SC_WRITE_6: ++ i = fsg->cmnd[4]; ++ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; ++ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, ++ (7<<1) | (1<<4), 1, ++ "WRITE(6)")) == 0) ++ reply = do_write(fsg); ++ break; ++ ++ case SC_WRITE_10: ++ fsg->data_size_from_cmnd = ++ get_unaligned_be16(&fsg->cmnd[7]) << 9; ++ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, ++ (1<<1) | (0xf<<2) | (3<<7), 1, ++ "WRITE(10)")) == 0) ++ reply = do_write(fsg); ++ break; ++ ++ case SC_WRITE_12: ++ fsg->data_size_from_cmnd = ++ get_unaligned_be32(&fsg->cmnd[6]) << 9; ++ if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, ++ (1<<1) | (0xf<<2) | (0xf<<6), 1, ++ "WRITE(12)")) == 0) ++ reply = do_write(fsg); ++ break; ++ ++ /* Some mandatory commands that we recognize but don't implement. ++ * They don't mean much in this setting. It's left as an exercise ++ * for anyone interested to implement RESERVE and RELEASE in terms ++ * of Posix locks. */ ++ case SC_FORMAT_UNIT: ++ case SC_RELEASE: ++ case SC_RESERVE: ++ case SC_SEND_DIAGNOSTIC: ++ // Fall through ++ ++ default: ++ unknown_cmnd: ++ fsg->data_size_from_cmnd = 0; ++ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); ++ if ((reply = check_command(fsg, fsg->cmnd_size, ++ DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { ++ fsg->curlun->sense_data = SS_INVALID_COMMAND; ++ reply = -EINVAL; ++ } ++ break; ++ } ++ up_read(&fsg->filesem); ++ ++ if (reply == -EINTR || signal_pending(current)) ++ return -EINTR; ++ ++ /* Set up the single reply buffer for finish_reply() */ ++ if (reply == -EINVAL) ++ reply = 0; // Error reply length ++ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { ++ reply = min((u32) reply, fsg->data_size_from_cmnd); ++ bh->inreq->length = reply; ++ bh->state = BUF_STATE_FULL; ++ fsg->residue -= reply; ++ } // Otherwise it's already set ++ ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) ++{ ++ struct usb_request *req = bh->outreq; ++ struct fsg_bulk_cb_wrap *cbw = req->buf; ++ ++ /* Was this a real packet? Should it be ignored? */ ++ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) ++ return -EINVAL; ++ ++ /* Is the CBW valid? */ ++ if (req->actual != USB_BULK_CB_WRAP_LEN || ++ cbw->Signature != cpu_to_le32( ++ USB_BULK_CB_SIG)) { ++ DBG(fsg, "invalid CBW: len %u sig 0x%x\n", ++ req->actual, ++ le32_to_cpu(cbw->Signature)); ++ ++ /* The Bulk-only spec says we MUST stall the IN endpoint ++ * (6.6.1), so it's unavoidable. It also says we must ++ * retain this state until the next reset, but there's ++ * no way to tell the controller driver it should ignore ++ * Clear-Feature(HALT) requests. ++ * ++ * We aren't required to halt the OUT endpoint; instead ++ * we can simply accept and discard any data received ++ * until the next reset. */ ++ wedge_bulk_in_endpoint(fsg); ++ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); ++ return -EINVAL; ++ } ++ ++ /* Is the CBW meaningful? */ ++ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || ++ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { ++ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " ++ "cmdlen %u\n", ++ cbw->Lun, cbw->Flags, cbw->Length); ++ ++ /* We can do anything we want here, so let's stall the ++ * bulk pipes if we are allowed to. */ ++ if (mod_data.can_stall) { ++ fsg_set_halt(fsg, fsg->bulk_out); ++ halt_bulk_in_endpoint(fsg); ++ } ++ return -EINVAL; ++ } ++ ++ /* Save the command for later */ ++ fsg->cmnd_size = cbw->Length; ++ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); ++ if (cbw->Flags & USB_BULK_IN_FLAG) ++ fsg->data_dir = DATA_DIR_TO_HOST; ++ else ++ fsg->data_dir = DATA_DIR_FROM_HOST; ++ fsg->data_size = le32_to_cpu(cbw->DataTransferLength); ++ if (fsg->data_size == 0) ++ fsg->data_dir = DATA_DIR_NONE; ++ fsg->lun = cbw->Lun; ++ fsg->tag = cbw->Tag; ++ return 0; ++} ++ ++ ++static int get_next_command(struct fsg_dev *fsg) ++{ ++ struct fsg_buffhd *bh; ++ int rc = 0; ++ ++ if (transport_is_bbb()) { ++ ++ /* Wait for the next buffer to become available */ ++ bh = fsg->next_buffhd_to_fill; ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ /* Queue a request to read a Bulk-only CBW */ ++ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); ++ bh->outreq->short_not_ok = 1; ++ start_transfer(fsg, fsg->bulk_out, bh->outreq, ++ &bh->outreq_busy, &bh->state); ++ ++ /* We will drain the buffer in software, which means we ++ * can reuse it for the next filling. No need to advance ++ * next_buffhd_to_fill. */ ++ ++ /* Wait for the CBW to arrive */ ++ while (bh->state != BUF_STATE_FULL) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ smp_rmb(); ++ rc = received_cbw(fsg, bh); ++ bh->state = BUF_STATE_EMPTY; ++ ++ } else { // USB_PR_CB or USB_PR_CBI ++ ++ /* Wait for the next command to arrive */ ++ while (fsg->cbbuf_cmnd_size == 0) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } ++ ++ /* Is the previous status interrupt request still busy? ++ * The host is allowed to skip reading the status, ++ * so we must cancel it. */ ++ if (fsg->intreq_busy) ++ usb_ep_dequeue(fsg->intr_in, fsg->intreq); ++ ++ /* Copy the command and mark the buffer empty */ ++ fsg->data_dir = DATA_DIR_UNKNOWN; ++ spin_lock_irq(&fsg->lock); ++ fsg->cmnd_size = fsg->cbbuf_cmnd_size; ++ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); ++ fsg->cbbuf_cmnd_size = 0; ++ spin_unlock_irq(&fsg->lock); ++ } ++ return rc; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, ++ const struct usb_endpoint_descriptor *d) ++{ ++ int rc; ++ ++ ep->driver_data = fsg; ++ rc = usb_ep_enable(ep, d); ++ if (rc) ++ ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); ++ return rc; ++} ++ ++static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, ++ struct usb_request **preq) ++{ ++ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); ++ if (*preq) ++ return 0; ++ ERROR(fsg, "can't allocate request for %s\n", ep->name); ++ return -ENOMEM; ++} ++ ++/* ++ * Reset interface setting and re-init endpoint state (toggle etc). ++ * Call with altsetting < 0 to disable the interface. The only other ++ * available altsetting is 0, which enables the interface. ++ */ ++static int do_set_interface(struct fsg_dev *fsg, int altsetting) ++{ ++ int rc = 0; ++ int i; ++ const struct usb_endpoint_descriptor *d; ++ ++ if (fsg->running) ++ DBG(fsg, "reset interface\n"); ++ ++reset: ++ /* Deallocate the requests */ ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ ++ if (bh->inreq) { ++ usb_ep_free_request(fsg->bulk_in, bh->inreq); ++ bh->inreq = NULL; ++ } ++ if (bh->outreq) { ++ usb_ep_free_request(fsg->bulk_out, bh->outreq); ++ bh->outreq = NULL; ++ } ++ } ++ if (fsg->intreq) { ++ usb_ep_free_request(fsg->intr_in, fsg->intreq); ++ fsg->intreq = NULL; ++ } ++ ++ /* Disable the endpoints */ ++ if (fsg->bulk_in_enabled) { ++ usb_ep_disable(fsg->bulk_in); ++ fsg->bulk_in_enabled = 0; ++ } ++ if (fsg->bulk_out_enabled) { ++ usb_ep_disable(fsg->bulk_out); ++ fsg->bulk_out_enabled = 0; ++ } ++ if (fsg->intr_in_enabled) { ++ usb_ep_disable(fsg->intr_in); ++ fsg->intr_in_enabled = 0; ++ } ++ ++ fsg->running = 0; ++ if (altsetting < 0 || rc != 0) ++ return rc; ++ ++ DBG(fsg, "set interface %d\n", altsetting); ++ ++ /* Enable the endpoints */ ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); ++ if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) ++ goto reset; ++ fsg->bulk_in_enabled = 1; ++ ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); ++ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) ++ goto reset; ++ fsg->bulk_out_enabled = 1; ++ fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); ++ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); ++ ++ if (transport_is_cbi()) { ++ d = fsg_ep_desc(fsg->gadget, ++ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc); ++ if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) ++ goto reset; ++ fsg->intr_in_enabled = 1; ++ } ++ ++ /* Allocate the requests */ ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ ++ if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) ++ goto reset; ++ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) ++ goto reset; ++ bh->inreq->buf = bh->outreq->buf = bh->buf; ++ bh->inreq->context = bh->outreq->context = bh; ++ bh->inreq->complete = bulk_in_complete; ++ bh->outreq->complete = bulk_out_complete; ++ } ++ if (transport_is_cbi()) { ++ if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) ++ goto reset; ++ fsg->intreq->complete = intr_in_complete; ++ } ++ ++ fsg->running = 1; ++ for (i = 0; i < fsg->nluns; ++i) ++ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; ++ return rc; ++} ++ ++ ++/* ++ * Change our operational configuration. This code must agree with the code ++ * that returns config descriptors, and with interface altsetting code. ++ * ++ * It's also responsible for power management interactions. Some ++ * configurations might not work with our current power sources. ++ * For now we just assume the gadget is always self-powered. ++ */ ++static int do_set_config(struct fsg_dev *fsg, u8 new_config) ++{ ++ int rc = 0; ++ ++ /* Disable the single interface */ ++ if (fsg->config != 0) { ++ DBG(fsg, "reset config\n"); ++ fsg->config = 0; ++ rc = do_set_interface(fsg, -1); ++ } ++ ++ /* Enable the interface */ ++ if (new_config != 0) { ++ fsg->config = new_config; ++ if ((rc = do_set_interface(fsg, 0)) != 0) ++ fsg->config = 0; // Reset on errors ++ else { ++ char *speed; ++ ++ switch (fsg->gadget->speed) { ++ case USB_SPEED_LOW: speed = "low"; break; ++ case USB_SPEED_FULL: speed = "full"; break; ++ case USB_SPEED_HIGH: speed = "high"; break; ++ default: speed = "?"; break; ++ } ++ INFO(fsg, "%s speed config #%d\n", speed, fsg->config); ++ } ++ } ++ return rc; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void handle_exception(struct fsg_dev *fsg) ++{ ++ siginfo_t info; ++ int sig; ++ int i; ++ int num_active; ++ struct fsg_buffhd *bh; ++ enum fsg_state old_state; ++ u8 new_config; ++ struct fsg_lun *curlun; ++ unsigned int exception_req_tag; ++ int rc; ++ ++ /* Clear the existing signals. Anything but SIGUSR1 is converted ++ * into a high-priority EXIT exception. */ ++ for (;;) { ++ sig = dequeue_signal_lock(current, ¤t->blocked, &info); ++ if (!sig) ++ break; ++ if (sig != SIGUSR1) { ++ if (fsg->state < FSG_STATE_EXIT) ++ DBG(fsg, "Main thread exiting on signal\n"); ++ raise_exception(fsg, FSG_STATE_EXIT); ++ } ++ } ++ ++ /* Cancel all the pending transfers */ ++ if (fsg->intreq_busy) ++ usb_ep_dequeue(fsg->intr_in, fsg->intreq); ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ bh = &fsg->buffhds[i]; ++ if (bh->inreq_busy) ++ usb_ep_dequeue(fsg->bulk_in, bh->inreq); ++ if (bh->outreq_busy) ++ usb_ep_dequeue(fsg->bulk_out, bh->outreq); ++ } ++ ++ /* Wait until everything is idle */ ++ for (;;) { ++ num_active = fsg->intreq_busy; ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ bh = &fsg->buffhds[i]; ++ num_active += bh->inreq_busy + bh->outreq_busy; ++ } ++ if (num_active == 0) ++ break; ++ if (sleep_thread(fsg)) ++ return; ++ } ++ ++ /* Clear out the controller's fifos */ ++ if (fsg->bulk_in_enabled) ++ usb_ep_fifo_flush(fsg->bulk_in); ++ if (fsg->bulk_out_enabled) ++ usb_ep_fifo_flush(fsg->bulk_out); ++ if (fsg->intr_in_enabled) ++ usb_ep_fifo_flush(fsg->intr_in); ++ ++ /* Reset the I/O buffer states and pointers, the SCSI ++ * state, and the exception. Then invoke the handler. */ ++ spin_lock_irq(&fsg->lock); ++ ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ bh = &fsg->buffhds[i]; ++ bh->state = BUF_STATE_EMPTY; ++ } ++ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = ++ &fsg->buffhds[0]; ++ ++ exception_req_tag = fsg->exception_req_tag; ++ new_config = fsg->new_config; ++ old_state = fsg->state; ++ ++ if (old_state == FSG_STATE_ABORT_BULK_OUT) ++ fsg->state = FSG_STATE_STATUS_PHASE; ++ else { ++ for (i = 0; i < fsg->nluns; ++i) { ++ curlun = &fsg->luns[i]; ++ curlun->prevent_medium_removal = 0; ++ curlun->sense_data = curlun->unit_attention_data = ++ SS_NO_SENSE; ++ curlun->sense_data_info = 0; ++ curlun->info_valid = 0; ++ } ++ fsg->state = FSG_STATE_IDLE; ++ } ++ spin_unlock_irq(&fsg->lock); ++ ++ /* Carry out any extra actions required for the exception */ ++ switch (old_state) { ++ default: ++ break; ++ ++ case FSG_STATE_ABORT_BULK_OUT: ++ send_status(fsg); ++ spin_lock_irq(&fsg->lock); ++ if (fsg->state == FSG_STATE_STATUS_PHASE) ++ fsg->state = FSG_STATE_IDLE; ++ spin_unlock_irq(&fsg->lock); ++ break; ++ ++ case FSG_STATE_RESET: ++ /* In case we were forced against our will to halt a ++ * bulk endpoint, clear the halt now. (The SuperH UDC ++ * requires this.) */ ++ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) ++ usb_ep_clear_halt(fsg->bulk_in); ++ ++ if (transport_is_bbb()) { ++ if (fsg->ep0_req_tag == exception_req_tag) ++ ep0_queue(fsg); // Complete the status stage ++ ++ } else if (transport_is_cbi()) ++ send_status(fsg); // Status by interrupt pipe ++ ++ /* Technically this should go here, but it would only be ++ * a waste of time. Ditto for the INTERFACE_CHANGE and ++ * CONFIG_CHANGE cases. */ ++ // for (i = 0; i < fsg->nluns; ++i) ++ // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; ++ break; ++ ++ case FSG_STATE_INTERFACE_CHANGE: ++ rc = do_set_interface(fsg, 0); ++ if (fsg->ep0_req_tag != exception_req_tag) ++ break; ++ if (rc != 0) // STALL on errors ++ fsg_set_halt(fsg, fsg->ep0); ++ else // Complete the status stage ++ ep0_queue(fsg); ++ break; ++ ++ case FSG_STATE_CONFIG_CHANGE: ++ rc = do_set_config(fsg, new_config); ++ if (fsg->ep0_req_tag != exception_req_tag) ++ break; ++ if (rc != 0) // STALL on errors ++ fsg_set_halt(fsg, fsg->ep0); ++ else // Complete the status stage ++ ep0_queue(fsg); ++ break; ++ ++ case FSG_STATE_DISCONNECT: ++ for (i = 0; i < fsg->nluns; ++i) ++ fsg_lun_fsync_sub(fsg->luns + i); ++ do_set_config(fsg, 0); // Unconfigured state ++ break; ++ ++ case FSG_STATE_EXIT: ++ case FSG_STATE_TERMINATED: ++ do_set_config(fsg, 0); // Free resources ++ spin_lock_irq(&fsg->lock); ++ fsg->state = FSG_STATE_TERMINATED; // Stop the thread ++ spin_unlock_irq(&fsg->lock); ++ break; ++ } ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int fsg_main_thread(void *fsg_) ++{ ++ struct fsg_dev *fsg = fsg_; ++ ++ /* Allow the thread to be killed by a signal, but set the signal mask ++ * to block everything but INT, TERM, KILL, and USR1. */ ++ allow_signal(SIGINT); ++ allow_signal(SIGTERM); ++ allow_signal(SIGKILL); ++ allow_signal(SIGUSR1); ++ ++ /* Allow the thread to be frozen */ ++ set_freezable(); ++ ++ /* Arrange for userspace references to be interpreted as kernel ++ * pointers. That way we can pass a kernel pointer to a routine ++ * that expects a __user pointer and it will work okay. */ ++ set_fs(get_ds()); ++ ++ /* The main loop */ ++ while (fsg->state != FSG_STATE_TERMINATED) { ++ if (exception_in_progress(fsg) || signal_pending(current)) { ++ handle_exception(fsg); ++ continue; ++ } ++ ++ if (!fsg->running) { ++ sleep_thread(fsg); ++ continue; ++ } ++ ++ if (get_next_command(fsg)) ++ continue; ++ ++ spin_lock_irq(&fsg->lock); ++ if (!exception_in_progress(fsg)) ++ fsg->state = FSG_STATE_DATA_PHASE; ++ spin_unlock_irq(&fsg->lock); ++ ++ if (do_scsi_command(fsg) || finish_reply(fsg)) ++ continue; ++ ++ spin_lock_irq(&fsg->lock); ++ if (!exception_in_progress(fsg)) ++ fsg->state = FSG_STATE_STATUS_PHASE; ++ spin_unlock_irq(&fsg->lock); ++ ++ if (send_status(fsg)) ++ continue; ++ ++ spin_lock_irq(&fsg->lock); ++ if (!exception_in_progress(fsg)) ++ fsg->state = FSG_STATE_IDLE; ++ spin_unlock_irq(&fsg->lock); ++ } ++ ++ spin_lock_irq(&fsg->lock); ++ fsg->thread_task = NULL; ++ spin_unlock_irq(&fsg->lock); ++ ++ /* If we are exiting because of a signal, unregister the ++ * gadget driver. */ ++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) ++ usb_gadget_unregister_driver(&fsg_driver); ++ ++ /* Let the unbind and cleanup routines know the thread has exited */ ++ complete_and_exit(&fsg->thread_notifier, 0); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++/* The write permissions and store_xxx pointers are set in fsg_bind() */ ++static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); ++static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void fsg_release(struct kref *ref) ++{ ++ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); ++ ++ kfree(fsg->luns); ++ kfree(fsg); ++} ++ ++static void lun_release(struct device *dev) ++{ ++ struct rw_semaphore *filesem = dev_get_drvdata(dev); ++ struct fsg_dev *fsg = ++ container_of(filesem, struct fsg_dev, filesem); ++ ++ kref_put(&fsg->ref, fsg_release); ++} ++ ++static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ int i; ++ struct fsg_lun *curlun; ++ struct usb_request *req = fsg->ep0req; ++ ++ DBG(fsg, "unbind\n"); ++ clear_bit(REGISTERED, &fsg->atomic_bitflags); ++ ++ /* Unregister the sysfs attribute files and the LUNs */ ++ for (i = 0; i < fsg->nluns; ++i) { ++ curlun = &fsg->luns[i]; ++ if (curlun->registered) { ++ device_remove_file(&curlun->dev, &dev_attr_ro); ++ device_remove_file(&curlun->dev, &dev_attr_file); ++ fsg_lun_close(curlun); ++ device_unregister(&curlun->dev); ++ curlun->registered = 0; ++ } ++ } ++ ++ /* If the thread isn't already dead, tell it to exit now */ ++ if (fsg->state != FSG_STATE_TERMINATED) { ++ raise_exception(fsg, FSG_STATE_EXIT); ++ wait_for_completion(&fsg->thread_notifier); ++ ++ /* The cleanup routine waits for this completion also */ ++ complete(&fsg->thread_notifier); ++ } ++ ++ /* Free the data buffers */ ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) ++ kfree(fsg->buffhds[i].buf); ++ ++ /* Free the request and buffer for endpoint 0 */ ++ if (req) { ++ kfree(req->buf); ++ usb_ep_free_request(fsg->ep0, req); ++ } ++ ++ set_gadget_data(gadget, NULL); ++} ++ ++ ++static int __init check_parameters(struct fsg_dev *fsg) ++{ ++ int prot; ++ int gcnum; ++ ++ /* Store the default values */ ++ mod_data.transport_type = USB_PR_BULK; ++ mod_data.transport_name = "Bulk-only"; ++ mod_data.protocol_type = USB_SC_SCSI; ++ mod_data.protocol_name = "Transparent SCSI"; ++ ++ /* Some peripheral controllers are known not to be able to ++ * halt bulk endpoints correctly. If one of them is present, ++ * disable stalls. ++ */ ++ if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget)) ++ mod_data.can_stall = 0; ++ ++ if (mod_data.release == 0xffff) { // Parameter wasn't set ++ /* The sa1100 controller is not supported */ ++ if (gadget_is_sa1100(fsg->gadget)) ++ gcnum = -1; ++ else ++ gcnum = usb_gadget_controller_number(fsg->gadget); ++ if (gcnum >= 0) ++ mod_data.release = 0x0300 + gcnum; ++ else { ++ WARNING(fsg, "controller '%s' not recognized\n", ++ fsg->gadget->name); ++ mod_data.release = 0x0399; ++ } ++ } ++ ++ prot = simple_strtol(mod_data.protocol_parm, NULL, 0); ++ ++#ifdef CONFIG_USB_FILE_STORAGE_TEST ++ if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { ++ ; // Use default setting ++ } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { ++ mod_data.transport_type = USB_PR_CB; ++ mod_data.transport_name = "Control-Bulk"; ++ } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { ++ mod_data.transport_type = USB_PR_CBI; ++ mod_data.transport_name = "Control-Bulk-Interrupt"; ++ } else { ++ ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); ++ return -EINVAL; ++ } ++ ++ if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || ++ prot == USB_SC_SCSI) { ++ ; // Use default setting ++ } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || ++ prot == USB_SC_RBC) { ++ mod_data.protocol_type = USB_SC_RBC; ++ mod_data.protocol_name = "RBC"; ++ } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || ++ strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || ++ prot == USB_SC_8020) { ++ mod_data.protocol_type = USB_SC_8020; ++ mod_data.protocol_name = "8020i (ATAPI)"; ++ } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || ++ prot == USB_SC_QIC) { ++ mod_data.protocol_type = USB_SC_QIC; ++ mod_data.protocol_name = "QIC-157"; ++ } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || ++ prot == USB_SC_UFI) { ++ mod_data.protocol_type = USB_SC_UFI; ++ mod_data.protocol_name = "UFI"; ++ } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || ++ prot == USB_SC_8070) { ++ mod_data.protocol_type = USB_SC_8070; ++ mod_data.protocol_name = "8070i"; ++ } else { ++ ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); ++ return -EINVAL; ++ } ++ ++ mod_data.buflen &= PAGE_CACHE_MASK; ++ if (mod_data.buflen <= 0) { ++ ERROR(fsg, "invalid buflen\n"); ++ return -ETOOSMALL; ++ } ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ ++ return 0; ++} ++ ++ ++static int __init fsg_bind(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = the_fsg; ++ int rc; ++ int i; ++ struct fsg_lun *curlun; ++ struct usb_ep *ep; ++ struct usb_request *req; ++ char *pathbuf, *p; ++ ++ fsg->gadget = gadget; ++ set_gadget_data(gadget, fsg); ++ fsg->ep0 = gadget->ep0; ++ fsg->ep0->driver_data = fsg; ++ ++ if ((rc = check_parameters(fsg)) != 0) ++ goto out; ++ ++ if (mod_data.removable) { // Enable the store_xxx attributes ++ dev_attr_file.attr.mode = 0644; ++ dev_attr_file.store = fsg_store_file; ++ if (!mod_data.cdrom) { ++ dev_attr_ro.attr.mode = 0644; ++ dev_attr_ro.store = fsg_store_ro; ++ } ++ } ++ ++ /* Find out how many LUNs there should be */ ++ i = mod_data.nluns; ++ if (i == 0) ++ i = max(mod_data.num_filenames, 1u); ++ if (i > FSG_MAX_LUNS) { ++ ERROR(fsg, "invalid number of LUNs: %d\n", i); ++ rc = -EINVAL; ++ goto out; ++ } ++ ++ /* Create the LUNs, open their backing files, and register the ++ * LUN devices in sysfs. */ ++ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); ++ if (!fsg->luns) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ fsg->nluns = i; ++ ++ for (i = 0; i < fsg->nluns; ++i) { ++ curlun = &fsg->luns[i]; ++ curlun->cdrom = !!mod_data.cdrom; ++ curlun->ro = mod_data.cdrom || mod_data.ro[i]; ++ curlun->initially_ro = curlun->ro; ++ curlun->removable = mod_data.removable; ++ curlun->dev.release = lun_release; ++ curlun->dev.parent = &gadget->dev; ++ curlun->dev.driver = &fsg_driver.driver; ++ dev_set_drvdata(&curlun->dev, &fsg->filesem); ++ dev_set_name(&curlun->dev,"%s-lun%d", ++ dev_name(&gadget->dev), i); ++ ++ if ((rc = device_register(&curlun->dev)) != 0) { ++ INFO(fsg, "failed to register LUN%d: %d\n", i, rc); ++ goto out; ++ } ++ if ((rc = device_create_file(&curlun->dev, ++ &dev_attr_ro)) != 0 || ++ (rc = device_create_file(&curlun->dev, ++ &dev_attr_file)) != 0) { ++ device_unregister(&curlun->dev); ++ goto out; ++ } ++ curlun->registered = 1; ++ kref_get(&fsg->ref); ++ ++ if (mod_data.file[i] && *mod_data.file[i]) { ++ if ((rc = fsg_lun_open(curlun, ++ mod_data.file[i])) != 0) ++ goto out; ++ } else if (!mod_data.removable) { ++ ERROR(fsg, "no file given for LUN%d\n", i); ++ rc = -EINVAL; ++ goto out; ++ } ++ } ++ ++ /* Find all the endpoints we will use */ ++ usb_ep_autoconfig_reset(gadget); ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); ++ if (!ep) ++ goto autoconf_fail; ++ ep->driver_data = fsg; // claim the endpoint ++ fsg->bulk_in = ep; ++ ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); ++ if (!ep) ++ goto autoconf_fail; ++ ep->driver_data = fsg; // claim the endpoint ++ fsg->bulk_out = ep; ++ ++ if (transport_is_cbi()) { ++ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); ++ if (!ep) ++ goto autoconf_fail; ++ ep->driver_data = fsg; // claim the endpoint ++ fsg->intr_in = ep; ++ } ++ ++ /* Fix up the descriptors */ ++ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; ++ device_desc.idVendor = cpu_to_le16(mod_data.vendor); ++ device_desc.idProduct = cpu_to_le16(mod_data.product); ++ device_desc.bcdDevice = cpu_to_le16(mod_data.release); ++ ++ i = (transport_is_cbi() ? 3 : 2); // Number of endpoints ++ fsg_intf_desc.bNumEndpoints = i; ++ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; ++ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; ++ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; ++ ++ if (gadget_is_dualspeed(gadget)) { ++ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; ++ ++ /* Assume ep0 uses the same maxpacket value for both speeds */ ++ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; ++ ++ /* Assume endpoint addresses are the same for both speeds */ ++ fsg_hs_bulk_in_desc.bEndpointAddress = ++ fsg_fs_bulk_in_desc.bEndpointAddress; ++ fsg_hs_bulk_out_desc.bEndpointAddress = ++ fsg_fs_bulk_out_desc.bEndpointAddress; ++ fsg_hs_intr_in_desc.bEndpointAddress = ++ fsg_fs_intr_in_desc.bEndpointAddress; ++ } ++ ++ if (gadget_is_otg(gadget)) ++ fsg_otg_desc.bmAttributes |= USB_OTG_HNP; ++ ++ rc = -ENOMEM; ++ ++ /* Allocate the request and buffer for endpoint 0 */ ++ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); ++ if (!req) ++ goto out; ++ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); ++ if (!req->buf) ++ goto out; ++ req->complete = ep0_complete; ++ ++ /* Allocate the data buffers */ ++ for (i = 0; i < FSG_NUM_BUFFERS; ++i) { ++ struct fsg_buffhd *bh = &fsg->buffhds[i]; ++ ++ /* Allocate for the bulk-in endpoint. We assume that ++ * the buffer will also work with the bulk-out (and ++ * interrupt-in) endpoint. */ ++ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); ++ if (!bh->buf) ++ goto out; ++ bh->next = bh + 1; ++ } ++ fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; ++ ++ /* This should reflect the actual gadget power source */ ++ usb_gadget_set_selfpowered(gadget); ++ ++ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, ++ "%s %s with %s", ++ init_utsname()->sysname, init_utsname()->release, ++ gadget->name); ++ ++ /* On a real device, serial[] would be loaded from permanent ++ * storage. We just encode it from the driver version string. */ ++ for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) { ++ unsigned char c = DRIVER_VERSION[i / 2]; ++ ++ if (!c) ++ break; ++ sprintf(&fsg_string_serial[i], "%02X", c); ++ } ++ ++ fsg->thread_task = kthread_create(fsg_main_thread, fsg, ++ "file-storage-gadget"); ++ if (IS_ERR(fsg->thread_task)) { ++ rc = PTR_ERR(fsg->thread_task); ++ goto out; ++ } ++ ++ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); ++ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); ++ ++ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); ++ for (i = 0; i < fsg->nluns; ++i) { ++ curlun = &fsg->luns[i]; ++ if (fsg_lun_is_open(curlun)) { ++ p = NULL; ++ if (pathbuf) { ++ p = d_path(&curlun->filp->f_path, ++ pathbuf, PATH_MAX); ++ if (IS_ERR(p)) ++ p = NULL; ++ } ++ LINFO(curlun, "ro=%d, file: %s\n", ++ curlun->ro, (p ? p : "(error)")); ++ } ++ } ++ kfree(pathbuf); ++ ++ DBG(fsg, "transport=%s (x%02x)\n", ++ mod_data.transport_name, mod_data.transport_type); ++ DBG(fsg, "protocol=%s (x%02x)\n", ++ mod_data.protocol_name, mod_data.protocol_type); ++ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", ++ mod_data.vendor, mod_data.product, mod_data.release); ++ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", ++ mod_data.removable, mod_data.can_stall, ++ mod_data.cdrom, mod_data.buflen); ++ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); ++ ++ set_bit(REGISTERED, &fsg->atomic_bitflags); ++ ++ /* Tell the thread to start working */ ++ wake_up_process(fsg->thread_task); ++ return 0; ++ ++autoconf_fail: ++ ERROR(fsg, "unable to autoconfigure all endpoints\n"); ++ rc = -ENOTSUPP; ++ ++out: ++ fsg->state = FSG_STATE_TERMINATED; // The thread is dead ++ fsg_unbind(gadget); ++ complete(&fsg->thread_notifier); ++ return rc; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void fsg_suspend(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ ++ DBG(fsg, "suspend\n"); ++ set_bit(SUSPENDED, &fsg->atomic_bitflags); ++} ++ ++static void fsg_resume(struct usb_gadget *gadget) ++{ ++ struct fsg_dev *fsg = get_gadget_data(gadget); ++ ++ DBG(fsg, "resume\n"); ++ clear_bit(SUSPENDED, &fsg->atomic_bitflags); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct usb_gadget_driver fsg_driver = { ++#ifdef CONFIG_USB_GADGET_DUALSPEED ++ .speed = USB_SPEED_HIGH, ++#else ++ .speed = USB_SPEED_FULL, ++#endif ++ .function = (char *) fsg_string_product, ++ .bind = fsg_bind, ++ .unbind = fsg_unbind, ++ .disconnect = fsg_disconnect, ++ .setup = fsg_setup, ++ .suspend = fsg_suspend, ++ .resume = fsg_resume, ++ ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ // .release = ... ++ // .suspend = ... ++ // .resume = ... ++ }, ++}; ++ ++ ++static int __init fsg_alloc(void) ++{ ++ struct fsg_dev *fsg; ++ ++ fsg = kzalloc(sizeof *fsg, GFP_KERNEL); ++ if (!fsg) ++ return -ENOMEM; ++ spin_lock_init(&fsg->lock); ++ init_rwsem(&fsg->filesem); ++ kref_init(&fsg->ref); ++ init_completion(&fsg->thread_notifier); ++ ++ the_fsg = fsg; ++ return 0; ++} ++ ++ ++static int __init fsg_init(void) ++{ ++ int rc; ++ struct fsg_dev *fsg; ++ ++ if ((rc = fsg_alloc()) != 0) ++ return rc; ++ fsg = the_fsg; ++ if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) ++ kref_put(&fsg->ref, fsg_release); ++ return rc; ++} ++module_init(fsg_init); ++ ++ ++static void __exit fsg_cleanup(void) ++{ ++ struct fsg_dev *fsg = the_fsg; ++ ++ /* Unregister the driver iff the thread hasn't already done so */ ++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) ++ usb_gadget_unregister_driver(&fsg_driver); ++ ++ /* Wait for the thread to finish up */ ++ wait_for_completion(&fsg->thread_notifier); ++ ++ kref_put(&fsg->ref, fsg_release); ++} ++module_exit(fsg_cleanup); diff --git a/usb/usb-g_mass_storage-testing-code-from-f_mass_storage.c-removed.patch b/usb/usb-g_mass_storage-testing-code-from-f_mass_storage.c-removed.patch new file mode 100644 index 00000000000000..0e132ddda44235 --- /dev/null +++ b/usb/usb-g_mass_storage-testing-code-from-f_mass_storage.c-removed.patch @@ -0,0 +1,1171 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:42:40 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:19 +0100 +Subject: USB: g_mass_storage: testing code from f_mass_storage.c removed +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <3dbe4d5bd68793548b52a22be33477a93bb4c8e1.1256745228.git.m.nazarewicz@samsung.com> + + +Removed code that was included when CONFIG_USB_FILE_STORAGE_TEST +was defined. If this functionality is required one may still use +the original File-backed Storage Gadget. It has been agreed that +testing functionality is not required in the composite function. + +Also removed fsg_suspend() and fsg_resume() which were no +operations. + +Moreover, storage_common.c has been modified in such a way that +defining certain macros skips parts of the file. Those macros +are: +* FSG_NO_INTR_EP -- skips interrupt endpoint descriptors +* FSG_NO_DEVICE_STRINGS -- skips certain strings +* FSG_NO_OTG -- skips OTG descriptor + +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> +--- + drivers/usb/gadget/f_mass_storage.c | 668 +++++------------------------------- + drivers/usb/gadget/storage_common.c | 50 ++ + 2 files changed, 143 insertions(+), 575 deletions(-) + +--- a/drivers/usb/gadget/f_mass_storage.c ++++ b/drivers/usb/gadget/f_mass_storage.c +@@ -50,14 +50,6 @@ + * access is always read-only.) The gadget will indicate that it has + * removable media if the optional "removable" module parameter is set. + * +- * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), +- * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected +- * by the optional "transport" module parameter. It also supports the +- * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), +- * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by +- * the optional "protocol" module parameter. In addition, the default +- * Vendor ID, Product ID, and release number can be overridden. +- * + * There is support for multiple logical units (LUNs), each of which has + * its own backing file. The number of LUNs can be set using the optional + * "luns" module parameter (anywhere from 1 to 8), and the corresponding +@@ -99,20 +91,6 @@ + * bulk endpoints + * cdrom Default false, boolean for whether to emulate + * a CD-ROM drive +- * transport=XXX Default BBB, transport name (CB, CBI, or BBB) +- * protocol=YYY Default SCSI, protocol name (RBC, 8020 or +- * ATAPI, QIC, UFI, 8070, or SCSI; +- * also 1 - 6) +- * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID +- * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID +- * release=0xRRRR Override the USB release number (bcdDevice) +- * buflen=N Default N=16384, buffer size used (will be +- * rounded down to a multiple of +- * PAGE_CACHE_SIZE) +- * +- * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", +- * "removable", "luns", "stall", and "cdrom" options are available; default +- * values are used for everything else. + * + * The pathnames of the backing files and the ro settings are available in + * the attribute files "file" and "ro" in the lun<n> subdirectory of the +@@ -279,6 +257,8 @@ static const char fsg_string_config[] = + static const char fsg_string_interface[] = "Mass Storage"; + + ++#define FSG_NO_INTR_EP 1 ++ + #include "storage_common.c" + + +@@ -309,28 +289,11 @@ static struct { + int can_stall; + int cdrom; + +- char *transport_parm; +- char *protocol_parm; +- unsigned short vendor; +- unsigned short product; + unsigned short release; +- unsigned int buflen; +- +- int transport_type; +- char *transport_name; +- int protocol_type; +- char *protocol_name; +- + } mod_data = { // Default values +- .transport_parm = "BBB", +- .protocol_parm = "SCSI", + .removable = 0, + .can_stall = 1, + .cdrom = 0, +- .vendor = FSG_VENDOR_ID, +- .product = FSG_PRODUCT_ID, +- .release = 0xffff, // Use controller chip type +- .buflen = 16384, + }; + + +@@ -354,54 +317,6 @@ module_param_named(cdrom, mod_data.cdrom + MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); + + +-/* In the non-TEST version, only the module parameters listed above +- * are available. */ +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +- +-module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); +-MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); +- +-module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); +-MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " +- "8070, or SCSI)"); +- +-module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); +-MODULE_PARM_DESC(vendor, "USB Vendor ID"); +- +-module_param_named(product, mod_data.product, ushort, S_IRUGO); +-MODULE_PARM_DESC(product, "USB Product ID"); +- +-module_param_named(release, mod_data.release, ushort, S_IRUGO); +-MODULE_PARM_DESC(release, "USB release number"); +- +-module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); +-MODULE_PARM_DESC(buflen, "I/O buffer size"); +- +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- +- +-/* +- * These definitions will permit the compiler to avoid generating code for +- * parts of the driver that aren't used in the non-TEST version. Even gcc +- * can recognize when a test of a constant expression yields a dead code +- * path. +- */ +- +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +- +-#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) +-#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) +-#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) +- +-#else +- +-#define transport_is_bbb() 1 +-#define transport_is_cbi() 0 +-#define protocol_is_scsi() 1 +- +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- +- + /*-------------------------------------------------------------------------*/ + + +@@ -421,10 +336,6 @@ struct fsg_dev { + unsigned int ep0_req_tag; + const char *ep0req_name; + +- struct usb_request *intreq; // For interrupt responses +- int intreq_busy; +- struct fsg_buffhd *intr_buffhd; +- + unsigned int bulk_out_maxpacket; + enum fsg_state state; // For exception handling + unsigned int exception_req_tag; +@@ -434,7 +345,6 @@ struct fsg_dev { + unsigned int running : 1; + unsigned int bulk_in_enabled : 1; + unsigned int bulk_out_enabled : 1; +- unsigned int intr_in_enabled : 1; + unsigned int phase_error : 1; + unsigned int short_packet_received : 1; + unsigned int bad_lun_okay : 1; +@@ -442,11 +352,9 @@ struct fsg_dev { + unsigned long atomic_bitflags; + #define REGISTERED 0 + #define IGNORE_BULK_OUT 1 +-#define SUSPENDED 2 + + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; +- struct usb_ep *intr_in; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; +@@ -466,14 +374,6 @@ struct fsg_dev { + u32 residue; + u32 usb_amount_left; + +- /* The CB protocol offers no way for a host to know when a command +- * has completed. As a result the next command may arrive early, +- * and we will still have to handle it. For that reason we need +- * a buffer to store new commands when using CB (or CBI, which +- * does not oblige a host to wait for command completion either). */ +- int cbbuf_cmnd_size; +- u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; +- + unsigned int nluns; + struct fsg_lun *luns; + struct fsg_lun *curlun; +@@ -737,161 +637,53 @@ static void bulk_out_complete(struct usb + } + + +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +-static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +-{ +- struct fsg_dev *fsg = ep->driver_data; +- struct fsg_buffhd *bh = req->context; +- +- if (req->status || req->actual != req->length) +- DBG(fsg, "%s --> %d, %u/%u\n", __func__, +- req->status, req->actual, req->length); +- if (req->status == -ECONNRESET) // Request was cancelled +- usb_ep_fifo_flush(ep); +- +- /* Hold the lock while we update the request and buffer states */ +- smp_wmb(); +- spin_lock(&fsg->lock); +- fsg->intreq_busy = 0; +- bh->state = BUF_STATE_EMPTY; +- wakeup_thread(fsg); +- spin_unlock(&fsg->lock); +-} +- +-#else +-static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +-{} +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- +- + /*-------------------------------------------------------------------------*/ + + /* Ep0 class-specific handlers. These always run in_irq. */ + +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +-static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +-{ +- struct usb_request *req = fsg->ep0req; +- static u8 cbi_reset_cmnd[6] = { +- SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; +- +- /* Error in command transfer? */ +- if (req->status || req->length != req->actual || +- req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { +- +- /* Not all controllers allow a protocol stall after +- * receiving control-out data, but we'll try anyway. */ +- fsg_set_halt(fsg, fsg->ep0); +- return; // Wait for reset +- } +- +- /* Is it the special reset command? */ +- if (req->actual >= sizeof cbi_reset_cmnd && +- memcmp(req->buf, cbi_reset_cmnd, +- sizeof cbi_reset_cmnd) == 0) { +- +- /* Raise an exception to stop the current operation +- * and reinitialize our state. */ +- DBG(fsg, "cbi reset request\n"); +- raise_exception(fsg, FSG_STATE_RESET); +- return; +- } +- +- VDBG(fsg, "CB[I] accept device-specific command\n"); +- spin_lock(&fsg->lock); +- +- /* Save the command for later */ +- if (fsg->cbbuf_cmnd_size) +- WARNING(fsg, "CB[I] overwriting previous command\n"); +- fsg->cbbuf_cmnd_size = req->actual; +- memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); +- +- wakeup_thread(fsg); +- spin_unlock(&fsg->lock); +-} +- +-#else +-static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +-{} +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- +- + static int class_setup_req(struct fsg_dev *fsg, + const struct usb_ctrlrequest *ctrl) + { + struct usb_request *req = fsg->ep0req; +- int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); +- u16 w_value = le16_to_cpu(ctrl->wValue); ++ u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + if (!fsg->config) +- return value; +- +- /* Handle Bulk-only class-specific requests */ +- if (transport_is_bbb()) { +- switch (ctrl->bRequest) { +- +- case USB_BULK_RESET_REQUEST: +- if (ctrl->bRequestType != (USB_DIR_OUT | +- USB_TYPE_CLASS | USB_RECIP_INTERFACE)) +- break; +- if (w_index != 0 || w_value != 0) { +- value = -EDOM; +- break; +- } ++ return -EOPNOTSUPP; + +- /* Raise an exception to stop the current operation +- * and reinitialize our state. */ +- DBG(fsg, "bulk reset request\n"); +- raise_exception(fsg, FSG_STATE_RESET); +- value = DELAYED_STATUS; +- break; ++ switch (ctrl->bRequest) { + +- case USB_BULK_GET_MAX_LUN_REQUEST: +- if (ctrl->bRequestType != (USB_DIR_IN | +- USB_TYPE_CLASS | USB_RECIP_INTERFACE)) +- break; +- if (w_index != 0 || w_value != 0) { +- value = -EDOM; +- break; +- } +- VDBG(fsg, "get max LUN\n"); +- *(u8 *) req->buf = fsg->nluns - 1; +- value = 1; ++ case USB_BULK_RESET_REQUEST: ++ if (ctrl->bRequestType != ++ (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; +- } +- } +- +- /* Handle CBI class-specific requests */ +- else { +- switch (ctrl->bRequest) { ++ if (w_index != 0 || w_value != 0) ++ return -EDOM; + +- case USB_CBI_ADSC_REQUEST: +- if (ctrl->bRequestType != (USB_DIR_OUT | +- USB_TYPE_CLASS | USB_RECIP_INTERFACE)) +- break; +- if (w_index != 0 || w_value != 0) { +- value = -EDOM; +- break; +- } +- if (w_length > MAX_COMMAND_SIZE) { +- value = -EOVERFLOW; +- break; +- } +- value = w_length; +- fsg->ep0req->context = received_cbi_adsc; +- break; +- } +- } ++ /* Raise an exception to stop the current operation ++ * and reinitialize our state. */ ++ DBG(fsg, "bulk reset request\n"); ++ raise_exception(fsg, FSG_STATE_RESET); ++ return DELAYED_STATUS; + +- if (value == -EOPNOTSUPP) +- VDBG(fsg, +- "unknown class-specific control req " +- "%02x.%02x v%04x i%04x l%u\n", +- ctrl->bRequestType, ctrl->bRequest, +- le16_to_cpu(ctrl->wValue), w_index, w_length); +- return value; ++ case USB_BULK_GET_MAX_LUN_REQUEST: ++ if (ctrl->bRequestType != ++ (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) ++ break; ++ if (w_index != 0 || w_value != 0) ++ return -EDOM; ++ VDBG(fsg, "get max LUN\n"); ++ *(u8 *) req->buf = fsg->nluns - 1; ++ return 1; ++ } ++ ++ VDBG(fsg, ++ "unknown class-specific control req " ++ "%02x.%02x v%04x i%04x l%u\n", ++ ctrl->bRequestType, ctrl->bRequest, ++ le16_to_cpu(ctrl->wValue), w_index, w_length); ++ return -EOPNOTSUPP; + } + + +@@ -1063,8 +855,6 @@ static void start_transfer(struct fsg_de + + if (ep == fsg->bulk_in) + dump_msg(fsg, "bulk-in", req->buf, req->length); +- else if (ep == fsg->intr_in) +- dump_msg(fsg, "intr-in", req->buf, req->length); + + spin_lock_irq(&fsg->lock); + *pbusy = 1; +@@ -1159,7 +949,7 @@ static int do_read(struct fsg_dev *fsg) + * the next page. + * If this means reading 0 then we were asked to read past + * the end of file. */ +- amount = min((unsigned int) amount_left, mod_data.buflen); ++ amount = min(amount_left, FSG_BUFLEN); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + partial_page = file_offset & (PAGE_CACHE_SIZE - 1); +@@ -1304,7 +1094,7 @@ static int do_write(struct fsg_dev *fsg) + * If this means getting 0, then we were asked + * to write past the end of file. + * Finally, round down to a block boundary. */ +- amount = min(amount_left_to_req, mod_data.buflen); ++ amount = min(amount_left_to_req, FSG_BUFLEN); + amount = min((loff_t) amount, curlun->file_length - + usb_offset); + partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); +@@ -1504,7 +1294,7 @@ static int do_verify(struct fsg_dev *fsg + * And don't try to read past the end of the file. + * If this means reading 0 then we were asked to read + * past the end of file. */ +- amount = min((unsigned int) amount_left, mod_data.buflen); ++ amount = min(amount_left, FSG_BUFLEN); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + if (amount == 0) { +@@ -1743,7 +1533,7 @@ static int do_mode_sense(struct fsg_dev + } else { // SC_MODE_SENSE_10 + buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA + buf += 8; +- limit = 65535; // Should really be mod_data.buflen ++ limit = 65535; // Should really be FSG_BUFLEN + } + + /* No block descriptors */ +@@ -1790,50 +1580,10 @@ static int do_mode_sense(struct fsg_dev + + static int do_start_stop(struct fsg_dev *fsg) + { +- struct fsg_lun *curlun = fsg->curlun; +- int loej, start; +- + if (!mod_data.removable) { +- curlun->sense_data = SS_INVALID_COMMAND; +- return -EINVAL; +- } +- +- // int immed = fsg->cmnd[1] & 0x01; +- loej = fsg->cmnd[4] & 0x02; +- start = fsg->cmnd[4] & 0x01; +- +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +- if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed +- (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start +- curlun->sense_data = SS_INVALID_FIELD_IN_CDB; ++ fsg->curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; + } +- +- if (!start) { +- +- /* Are we allowed to unload the media? */ +- if (curlun->prevent_medium_removal) { +- LDBG(curlun, "unload attempt prevented\n"); +- curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; +- return -EINVAL; +- } +- if (loej) { // Simulate an unload/eject +- up_read(&fsg->filesem); +- down_write(&fsg->filesem); +- fsg_lun_close(curlun); +- up_write(&fsg->filesem); +- down_read(&fsg->filesem); +- } +- } else { +- +- /* Our emulation doesn't support mounting; the medium is +- * available for use as soon as it is loaded. */ +- if (!fsg_lun_is_open(curlun)) { +- curlun->sense_data = SS_MEDIUM_NOT_PRESENT; +- return -EINVAL; +- } +- } +-#endif + return 0; + } + +@@ -1954,7 +1704,7 @@ static int pad_with_zeros(struct fsg_dev + return rc; + } + +- nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen); ++ nsend = min(fsg->usb_amount_left, FSG_BUFLEN); + memset(bh->buf + nkeep, 0, nsend - nkeep); + bh->inreq->length = nsend; + bh->inreq->zero = 0; +@@ -1994,8 +1744,7 @@ static int throw_away_data(struct fsg_de + /* Try to submit another request if we need one */ + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { +- amount = min(fsg->usb_amount_left, +- (u32) mod_data.buflen); ++ amount = min(fsg->usb_amount_left, FSG_BUFLEN); + + /* amount is always divisible by 512, hence by + * the bulk-out maxpacket size */ +@@ -2040,49 +1789,27 @@ static int finish_reply(struct fsg_dev * + + /* All but the last buffer of data must have already been sent */ + case DATA_DIR_TO_HOST: +- if (fsg->data_size == 0) +- ; // Nothing to send ++ if (fsg->data_size == 0) { ++ /* Nothing to send */ + + /* If there's no residue, simply send the last buffer */ +- else if (fsg->residue == 0) { ++ } else if (fsg->residue == 0) { + bh->inreq->zero = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; +- } +- +- /* There is a residue. For CB and CBI, simply mark the end +- * of the data with a short packet. However, if we are +- * allowed to stall, there was no data at all (residue == +- * data_size), and the command failed (invalid LUN or +- * sense data is set), then halt the bulk-in endpoint +- * instead. */ +- else if (!transport_is_bbb()) { +- if (mod_data.can_stall && +- fsg->residue == fsg->data_size && +- (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { +- bh->state = BUF_STATE_EMPTY; +- rc = halt_bulk_in_endpoint(fsg); +- } else { +- bh->inreq->zero = 1; +- start_transfer(fsg, fsg->bulk_in, bh->inreq, +- &bh->inreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; +- } +- } + + /* For Bulk-only, if we're allowed to stall then send the + * short packet and halt the bulk-in endpoint. If we can't + * stall, pad out the remaining data with 0's. */ +- else { +- if (mod_data.can_stall) { +- bh->inreq->zero = 1; +- start_transfer(fsg, fsg->bulk_in, bh->inreq, +- &bh->inreq_busy, &bh->state); +- fsg->next_buffhd_to_fill = bh->next; +- rc = halt_bulk_in_endpoint(fsg); +- } else +- rc = pad_with_zeros(fsg); ++ } else if (mod_data.can_stall) { ++ bh->inreq->zero = 1; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); ++ fsg->next_buffhd_to_fill = bh->next; ++ rc = halt_bulk_in_endpoint(fsg); ++ } else { ++ rc = pad_with_zeros(fsg); + } + break; + +@@ -2126,6 +1853,7 @@ static int send_status(struct fsg_dev *f + { + struct fsg_lun *curlun = fsg->curlun; + struct fsg_buffhd *bh; ++ struct bulk_cs_wrap *csw; + int rc; + u8 status = USB_STATUS_PASS; + u32 sd, sdinfo = 0; +@@ -2158,46 +1886,19 @@ static int send_status(struct fsg_dev *f + SK(sd), ASC(sd), ASCQ(sd), sdinfo); + } + +- if (transport_is_bbb()) { +- struct bulk_cs_wrap *csw = bh->buf; +- +- /* Store and send the Bulk-only CSW */ +- csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); +- csw->Tag = fsg->tag; +- csw->Residue = cpu_to_le32(fsg->residue); +- csw->Status = status; + +- bh->inreq->length = USB_BULK_CS_WRAP_LEN; +- bh->inreq->zero = 0; +- start_transfer(fsg, fsg->bulk_in, bh->inreq, +- &bh->inreq_busy, &bh->state); +- +- } else if (mod_data.transport_type == USB_PR_CB) { +- +- /* Control-Bulk transport has no status phase! */ +- return 0; ++ /* Store and send the Bulk-only CSW */ ++ csw = bh->buf; + +- } else { // USB_PR_CBI +- struct interrupt_data *buf = bh->buf; +- +- /* Store and send the Interrupt data. UFI sends the ASC +- * and ASCQ bytes. Everything else sends a Type (which +- * is always 0) and the status Value. */ +- if (mod_data.protocol_type == USB_SC_UFI) { +- buf->bType = ASC(sd); +- buf->bValue = ASCQ(sd); +- } else { +- buf->bType = 0; +- buf->bValue = status; +- } +- fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; +- +- fsg->intr_buffhd = bh; // Point to the right buffhd +- fsg->intreq->buf = bh->inreq->buf; +- fsg->intreq->context = bh; +- start_transfer(fsg, fsg->intr_in, fsg->intreq, +- &fsg->intreq_busy, &bh->state); +- } ++ csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); ++ csw->Tag = fsg->tag; ++ csw->Residue = cpu_to_le32(fsg->residue); ++ csw->Status = status; ++ ++ bh->inreq->length = USB_BULK_CS_WRAP_LEN; ++ bh->inreq->zero = 0; ++ start_transfer(fsg, fsg->bulk_in, bh->inreq, ++ &bh->inreq_busy, &bh->state); + + fsg->next_buffhd_to_fill = bh->next; + return 0; +@@ -2218,21 +1919,6 @@ static int check_command(struct fsg_dev + char hdlen[20]; + struct fsg_lun *curlun; + +- /* Adjust the expected cmnd_size for protocol encapsulation padding. +- * Transparent SCSI doesn't pad. */ +- if (protocol_is_scsi()) +- ; +- +- /* There's some disagreement as to whether RBC pads commands or not. +- * We'll play it safe and accept either form. */ +- else if (mod_data.protocol_type == USB_SC_RBC) { +- if (fsg->cmnd_size == 12) +- cmnd_size = 12; +- +- /* All the other protocols pad to 12 bytes */ +- } else +- cmnd_size = 12; +- + hdlen[0] = 0; + if (fsg->data_dir != DATA_DIR_UNKNOWN) + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], +@@ -2294,13 +1980,9 @@ static int check_command(struct fsg_dev + } + + /* Check that the LUN values are consistent */ +- if (transport_is_bbb()) { +- if (fsg->lun != lun) +- DBG(fsg, "using LUN %d from CBW, " +- "not LUN %d from CDB\n", +- fsg->lun, lun); +- } else +- fsg->lun = lun; // Use LUN from the command ++ if (fsg->lun != lun) ++ DBG(fsg, "using LUN %d from CBW, not LUN %d from CDB\n", ++ fsg->lun, lun); + + /* Check the LUN */ + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { +@@ -2666,59 +2348,34 @@ static int get_next_command(struct fsg_d + struct fsg_buffhd *bh; + int rc = 0; + +- if (transport_is_bbb()) { +- +- /* Wait for the next buffer to become available */ +- bh = fsg->next_buffhd_to_fill; +- while (bh->state != BUF_STATE_EMPTY) { +- rc = sleep_thread(fsg); +- if (rc) +- return rc; +- } +- +- /* Queue a request to read a Bulk-only CBW */ +- set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); +- bh->outreq->short_not_ok = 1; +- start_transfer(fsg, fsg->bulk_out, bh->outreq, +- &bh->outreq_busy, &bh->state); +- +- /* We will drain the buffer in software, which means we +- * can reuse it for the next filling. No need to advance +- * next_buffhd_to_fill. */ +- +- /* Wait for the CBW to arrive */ +- while (bh->state != BUF_STATE_FULL) { +- rc = sleep_thread(fsg); +- if (rc) +- return rc; +- } +- smp_rmb(); +- rc = received_cbw(fsg, bh); +- bh->state = BUF_STATE_EMPTY; +- +- } else { // USB_PR_CB or USB_PR_CBI +- +- /* Wait for the next command to arrive */ +- while (fsg->cbbuf_cmnd_size == 0) { +- rc = sleep_thread(fsg); +- if (rc) +- return rc; +- } ++ /* Wait for the next buffer to become available */ ++ bh = fsg->next_buffhd_to_fill; ++ while (bh->state != BUF_STATE_EMPTY) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; ++ } + +- /* Is the previous status interrupt request still busy? +- * The host is allowed to skip reading the status, +- * so we must cancel it. */ +- if (fsg->intreq_busy) +- usb_ep_dequeue(fsg->intr_in, fsg->intreq); ++ /* Queue a request to read a Bulk-only CBW */ ++ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); ++ bh->outreq->short_not_ok = 1; ++ start_transfer(fsg, fsg->bulk_out, bh->outreq, ++ &bh->outreq_busy, &bh->state); ++ ++ /* We will drain the buffer in software, which means we ++ * can reuse it for the next filling. No need to advance ++ * next_buffhd_to_fill. */ + +- /* Copy the command and mark the buffer empty */ +- fsg->data_dir = DATA_DIR_UNKNOWN; +- spin_lock_irq(&fsg->lock); +- fsg->cmnd_size = fsg->cbbuf_cmnd_size; +- memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); +- fsg->cbbuf_cmnd_size = 0; +- spin_unlock_irq(&fsg->lock); ++ /* Wait for the CBW to arrive */ ++ while (bh->state != BUF_STATE_FULL) { ++ rc = sleep_thread(fsg); ++ if (rc) ++ return rc; + } ++ smp_rmb(); ++ rc = received_cbw(fsg, bh); ++ bh->state = BUF_STATE_EMPTY; ++ + return rc; + } + +@@ -2775,10 +2432,6 @@ reset: + bh->outreq = NULL; + } + } +- if (fsg->intreq) { +- usb_ep_free_request(fsg->intr_in, fsg->intreq); +- fsg->intreq = NULL; +- } + + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { +@@ -2789,10 +2442,6 @@ reset: + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } +- if (fsg->intr_in_enabled) { +- usb_ep_disable(fsg->intr_in); +- fsg->intr_in_enabled = 0; +- } + + fsg->running = 0; + if (altsetting < 0 || rc != 0) +@@ -2815,14 +2464,6 @@ reset: + fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + +- if (transport_is_cbi()) { +- d = fsg_ep_desc(fsg->gadget, +- &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc); +- if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) +- goto reset; +- fsg->intr_in_enabled = 1; +- } +- + /* Allocate the requests */ + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; +@@ -2836,11 +2477,6 @@ reset: + bh->inreq->complete = bulk_in_complete; + bh->outreq->complete = bulk_out_complete; + } +- if (transport_is_cbi()) { +- if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) +- goto reset; +- fsg->intreq->complete = intr_in_complete; +- } + + fsg->running = 1; + for (i = 0; i < fsg->nluns; ++i) +@@ -2918,8 +2554,6 @@ static void handle_exception(struct fsg_ + } + + /* Cancel all the pending transfers */ +- if (fsg->intreq_busy) +- usb_ep_dequeue(fsg->intr_in, fsg->intreq); + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + if (bh->inreq_busy) +@@ -2930,7 +2564,7 @@ static void handle_exception(struct fsg_ + + /* Wait until everything is idle */ + for (;;) { +- num_active = fsg->intreq_busy; ++ num_active = 0; + for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; +@@ -2946,8 +2580,6 @@ static void handle_exception(struct fsg_ + usb_ep_fifo_flush(fsg->bulk_in); + if (fsg->bulk_out_enabled) + usb_ep_fifo_flush(fsg->bulk_out); +- if (fsg->intr_in_enabled) +- usb_ep_fifo_flush(fsg->intr_in); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ +@@ -2999,12 +2631,8 @@ static void handle_exception(struct fsg_ + if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) + usb_ep_clear_halt(fsg->bulk_in); + +- if (transport_is_bbb()) { +- if (fsg->ep0_req_tag == exception_req_tag) +- ep0_queue(fsg); // Complete the status stage +- +- } else if (transport_is_cbi()) +- send_status(fsg); // Status by interrupt pipe ++ if (fsg->ep0_req_tag == exception_req_tag) ++ ep0_queue(fsg); // Complete the status stage + + /* Technically this should go here, but it would only be + * a waste of time. Ditto for the INTERFACE_CHANGE and +@@ -3196,15 +2824,8 @@ static void /* __init_or_exit */ fsg_unb + + static int __init check_parameters(struct fsg_dev *fsg) + { +- int prot; + int gcnum; + +- /* Store the default values */ +- mod_data.transport_type = USB_PR_BULK; +- mod_data.transport_name = "Bulk-only"; +- mod_data.protocol_type = USB_SC_SCSI; +- mod_data.protocol_name = "Transparent SCSI"; +- + /* Some peripheral controllers are known not to be able to + * halt bulk endpoints correctly. If one of them is present, + * disable stalls. +@@ -3227,58 +2848,6 @@ static int __init check_parameters(struc + } + } + +- prot = simple_strtol(mod_data.protocol_parm, NULL, 0); +- +-#ifdef CONFIG_USB_FILE_STORAGE_TEST +- if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { +- ; // Use default setting +- } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { +- mod_data.transport_type = USB_PR_CB; +- mod_data.transport_name = "Control-Bulk"; +- } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { +- mod_data.transport_type = USB_PR_CBI; +- mod_data.transport_name = "Control-Bulk-Interrupt"; +- } else { +- ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); +- return -EINVAL; +- } +- +- if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || +- prot == USB_SC_SCSI) { +- ; // Use default setting +- } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || +- prot == USB_SC_RBC) { +- mod_data.protocol_type = USB_SC_RBC; +- mod_data.protocol_name = "RBC"; +- } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || +- strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || +- prot == USB_SC_8020) { +- mod_data.protocol_type = USB_SC_8020; +- mod_data.protocol_name = "8020i (ATAPI)"; +- } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || +- prot == USB_SC_QIC) { +- mod_data.protocol_type = USB_SC_QIC; +- mod_data.protocol_name = "QIC-157"; +- } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || +- prot == USB_SC_UFI) { +- mod_data.protocol_type = USB_SC_UFI; +- mod_data.protocol_name = "UFI"; +- } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || +- prot == USB_SC_8070) { +- mod_data.protocol_type = USB_SC_8070; +- mod_data.protocol_name = "8070i"; +- } else { +- ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); +- return -EINVAL; +- } +- +- mod_data.buflen &= PAGE_CACHE_MASK; +- if (mod_data.buflen <= 0) { +- ERROR(fsg, "invalid buflen\n"); +- return -ETOOSMALL; +- } +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- + return 0; + } + +@@ -3381,29 +2950,11 @@ static int __init fsg_bind(struct usb_ga + ep->driver_data = fsg; // claim the endpoint + fsg->bulk_out = ep; + +- if (transport_is_cbi()) { +- ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); +- if (!ep) +- goto autoconf_fail; +- ep->driver_data = fsg; // claim the endpoint +- fsg->intr_in = ep; +- } +- + /* Fix up the descriptors */ + device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; +- device_desc.idVendor = cpu_to_le16(mod_data.vendor); +- device_desc.idProduct = cpu_to_le16(mod_data.product); + device_desc.bcdDevice = cpu_to_le16(mod_data.release); + +- i = (transport_is_cbi() ? 3 : 2); // Number of endpoints +- fsg_intf_desc.bNumEndpoints = i; +- fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; +- fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; +- fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; +- + if (gadget_is_dualspeed(gadget)) { +- fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; +- + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + +@@ -3412,8 +2963,6 @@ static int __init fsg_bind(struct usb_ga + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_hs_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; +- fsg_hs_intr_in_desc.bEndpointAddress = +- fsg_fs_intr_in_desc.bEndpointAddress; + } + + if (gadget_is_otg(gadget)) +@@ -3437,7 +2986,7 @@ static int __init fsg_bind(struct usb_ga + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and + * interrupt-in) endpoint. */ +- bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); ++ bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); + if (!bh->buf) + goto out; + bh->next = bh + 1; +@@ -3489,15 +3038,9 @@ static int __init fsg_bind(struct usb_ga + } + kfree(pathbuf); + +- DBG(fsg, "transport=%s (x%02x)\n", +- mod_data.transport_name, mod_data.transport_type); +- DBG(fsg, "protocol=%s (x%02x)\n", +- mod_data.protocol_name, mod_data.protocol_type); +- DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", +- mod_data.vendor, mod_data.product, mod_data.release); + DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", + mod_data.removable, mod_data.can_stall, +- mod_data.cdrom, mod_data.buflen); ++ mod_data.cdrom, FSG_BUFLEN); + DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); + + set_bit(REGISTERED, &fsg->atomic_bitflags); +@@ -3520,25 +3063,6 @@ out: + + /*-------------------------------------------------------------------------*/ + +-static void fsg_suspend(struct usb_gadget *gadget) +-{ +- struct fsg_dev *fsg = get_gadget_data(gadget); +- +- DBG(fsg, "suspend\n"); +- set_bit(SUSPENDED, &fsg->atomic_bitflags); +-} +- +-static void fsg_resume(struct usb_gadget *gadget) +-{ +- struct fsg_dev *fsg = get_gadget_data(gadget); +- +- DBG(fsg, "resume\n"); +- clear_bit(SUSPENDED, &fsg->atomic_bitflags); +-} +- +- +-/*-------------------------------------------------------------------------*/ +- + static struct usb_gadget_driver fsg_driver = { + #ifdef CONFIG_USB_GADGET_DUALSPEED + .speed = USB_SPEED_HIGH, +@@ -3550,8 +3074,6 @@ static struct usb_gadget_driver fsg_dri + .unbind = fsg_unbind, + .disconnect = fsg_disconnect, + .setup = fsg_setup, +- .suspend = fsg_suspend, +- .resume = fsg_resume, + + .driver = { + .name = DRIVER_NAME, +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -33,6 +33,20 @@ + * macro is defined prior to including this file. + */ + ++/* ++ * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and ++ * fsg_hs_intr_in_desc objects as well as ++ * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES ++ * macros are not defined. ++ * ++ * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, ++ * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not ++ * defined (as well as corresponding entries in string tables are ++ * missing) and FSG_STRING_INTERFACE has value of zero. ++ * ++ * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. ++ */ ++ + + #include <asm/unaligned.h> + +@@ -327,14 +341,17 @@ static inline u32 get_unaligned_be24(u8 + + + enum { ++#ifndef FSG_NO_DEVICE_STRINGS + FSG_STRING_MANUFACTURER = 1, + FSG_STRING_PRODUCT, + FSG_STRING_SERIAL, + FSG_STRING_CONFIG, ++#endif + FSG_STRING_INTERFACE + }; + + ++#ifndef FSG_NO_OTG + static struct usb_otg_descriptor + fsg_otg_desc = { + .bLength = sizeof fsg_otg_desc, +@@ -342,6 +359,7 @@ fsg_otg_desc = { + + .bmAttributes = USB_OTG_SRP, + }; ++#endif + + /* There is only one interface. */ + +@@ -380,6 +398,8 @@ fsg_fs_bulk_out_desc = { + /* wMaxPacketSize set by autoconfiguration */ + }; + ++#ifndef FSG_NO_INTR_EP ++ + static struct usb_endpoint_descriptor + fsg_fs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, +@@ -391,15 +411,26 @@ fsg_fs_intr_in_desc = { + .bInterval = 32, // frames -> 32 ms + }; + ++#ifndef FSG_NO_OTG ++# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 ++#else ++# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 ++#endif ++ ++#endif ++ + static const struct usb_descriptor_header *fsg_fs_function[] = { ++#ifndef FSG_NO_OTG + (struct usb_descriptor_header *) &fsg_otg_desc, ++#endif + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, ++#ifndef FSG_NO_INTR_EP + (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, ++#endif + NULL, + }; +-#define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 + + + /* +@@ -431,6 +462,8 @@ fsg_hs_bulk_out_desc = { + .bInterval = 1, // NAK every 1 uframe + }; + ++#ifndef FSG_NO_INTR_EP ++ + static struct usb_endpoint_descriptor + fsg_hs_intr_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, +@@ -442,15 +475,26 @@ fsg_hs_intr_in_desc = { + .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms + }; + ++#ifndef FSG_NO_OTG ++# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 ++#else ++# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 ++#endif ++ ++#endif ++ + static const struct usb_descriptor_header *fsg_hs_function[] = { ++#ifndef FSG_NO_OTG + (struct usb_descriptor_header *) &fsg_otg_desc, ++#endif + (struct usb_descriptor_header *) &fsg_intf_desc, + (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, + (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, ++#ifndef FSG_NO_INTR_EP + (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, ++#endif + NULL, + }; +-#define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 + + /* Maxpacket and other transfer characteristics vary by speed. */ + static struct usb_endpoint_descriptor * +@@ -465,10 +509,12 @@ fsg_ep_desc(struct usb_gadget *g, struct + + /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ + static struct usb_string fsg_strings[] = { ++#ifndef FSG_NO_DEVICE_STRINGS + {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, + {FSG_STRING_PRODUCT, fsg_string_product}, + {FSG_STRING_SERIAL, fsg_string_serial}, + {FSG_STRING_CONFIG, fsg_string_config}, ++#endif + {FSG_STRING_INTERFACE, fsg_string_interface}, + {} + }; diff --git a/usb/usb-interface-association-descriptors-added-to-cdc-rndis.patch b/usb/usb-interface-association-descriptors-added-to-cdc-rndis.patch new file mode 100644 index 00000000000000..3f39b6f2f92fa8 --- /dev/null +++ b/usb/usb-interface-association-descriptors-added-to-cdc-rndis.patch @@ -0,0 +1,209 @@ +From m.nazarewicz@samsung.com Fri Nov 6 14:44:55 2009 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Wed, 28 Oct 2009 16:57:30 +0100 +Subject: USB: Interface Association Descriptors added to CDC & RNDIS +To: Greg KH <greg@kroah.com> +Cc: Michal Nazarewicz <m.nazarewicz@samsung.com> +Message-ID: <139ab77aa2e84ec611da329404733979e1a5189e.1256745228.git.m.nazarewicz@samsung.com> + + +Without Interface Association Descriptor, the CDC serial and +RNDIS functions did not work correctly when added to a +composite gadget with other functions. This is because, it +defined two interfaces and some hosts tried to treat each +interface separatelly. + +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> +--- + drivers/usb/gadget/f_acm.c | 28 ++++++++++++++++++++++++++++ + drivers/usb/gadget/f_rndis.c | 35 +++++++++++++++++++++++++++++++---- + 2 files changed, 59 insertions(+), 4 deletions(-) + +--- a/drivers/usb/gadget/f_acm.c ++++ b/drivers/usb/gadget/f_acm.c +@@ -4,6 +4,8 @@ + * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) + * Copyright (C) 2008 by David Brownell + * Copyright (C) 2008 by Nokia Corporation ++ * Copyright (C) 2009 by Samsung Electronics ++ * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, +@@ -99,6 +101,20 @@ static inline struct f_acm *port_to_acm( + + /* interface and class descriptors: */ + ++static struct usb_interface_assoc_descriptor ++acm_iad_descriptor = { ++ .bLength = sizeof acm_iad_descriptor, ++ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, ++ ++ /* .bFirstInterface = DYNAMIC, */ ++ .bInterfaceCount = 2, // control + data ++ .bFunctionClass = USB_CLASS_COMM, ++ .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, ++ .bFunctionProtocol = USB_CDC_PROTO_NONE, ++ /* .iFunction = DYNAMIC */ ++}; ++ ++ + static struct usb_interface_descriptor acm_control_interface_desc __initdata = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, +@@ -178,6 +194,7 @@ static struct usb_endpoint_descriptor ac + }; + + static struct usb_descriptor_header *acm_fs_function[] __initdata = { ++ (struct usb_descriptor_header *) &acm_iad_descriptor, + (struct usb_descriptor_header *) &acm_control_interface_desc, + (struct usb_descriptor_header *) &acm_header_desc, + (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, +@@ -216,6 +233,7 @@ static struct usb_endpoint_descriptor ac + }; + + static struct usb_descriptor_header *acm_hs_function[] __initdata = { ++ (struct usb_descriptor_header *) &acm_iad_descriptor, + (struct usb_descriptor_header *) &acm_control_interface_desc, + (struct usb_descriptor_header *) &acm_header_desc, + (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, +@@ -232,11 +250,13 @@ static struct usb_descriptor_header *acm + + #define ACM_CTRL_IDX 0 + #define ACM_DATA_IDX 1 ++#define ACM_IAD_IDX 2 + + /* static strings, in UTF-8 */ + static struct usb_string acm_string_defs[] = { + [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", + [ACM_DATA_IDX].s = "CDC ACM Data", ++ [ACM_IAD_IDX ].s = "CDC Serial", + { /* ZEROES END LIST */ }, + }; + +@@ -563,6 +583,7 @@ acm_bind(struct usb_configuration *c, st + if (status < 0) + goto fail; + acm->ctrl_id = status; ++ acm_iad_descriptor.bFirstInterface = status; + + acm_control_interface_desc.bInterfaceNumber = status; + acm_union_desc .bMasterInterface0 = status; +@@ -732,6 +753,13 @@ int __init acm_bind_config(struct usb_co + acm_string_defs[ACM_DATA_IDX].id = status; + + acm_data_interface_desc.iInterface = status; ++ ++ status = usb_string_id(c->cdev); ++ if (status < 0) ++ return status; ++ acm_string_defs[ACM_IAD_IDX].id = status; ++ ++ acm_iad_descriptor.iFunction = status; + } + + /* allocate and initialize one new instance */ +--- a/drivers/usb/gadget/f_rndis.c ++++ b/drivers/usb/gadget/f_rndis.c +@@ -4,6 +4,8 @@ + * Copyright (C) 2003-2005,2008 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger + * Copyright (C) 2008 Nokia Corporation ++ * Copyright (C) 2009 Samsung Electronics ++ * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -149,8 +151,8 @@ static struct usb_cdc_call_mgmt_descript + .bDataInterface = 0x01, + }; + +-static struct usb_cdc_acm_descriptor acm_descriptor __initdata = { +- .bLength = sizeof acm_descriptor, ++static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = { ++ .bLength = sizeof rndis_acm_descriptor, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + +@@ -179,6 +181,20 @@ static struct usb_interface_descriptor r + /* .iInterface = DYNAMIC */ + }; + ++ ++static struct usb_interface_assoc_descriptor ++rndis_iad_descriptor = { ++ .bLength = sizeof rndis_iad_descriptor, ++ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, ++ ++ .bFirstInterface = 0, /* XXX, hardcoded */ ++ .bInterfaceCount = 2, // control + data ++ .bFunctionClass = USB_CLASS_COMM, ++ .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, ++ .bFunctionProtocol = USB_CDC_PROTO_NONE, ++ /* .iFunction = DYNAMIC */ ++}; ++ + /* full speed support: */ + + static struct usb_endpoint_descriptor fs_notify_desc __initdata = { +@@ -208,11 +224,12 @@ static struct usb_endpoint_descriptor fs + }; + + static struct usb_descriptor_header *eth_fs_function[] __initdata = { ++ (struct usb_descriptor_header *) &rndis_iad_descriptor, + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, +- (struct usb_descriptor_header *) &acm_descriptor, ++ (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &fs_notify_desc, + /* data interface has no altsetting */ +@@ -252,11 +269,12 @@ static struct usb_endpoint_descriptor hs + }; + + static struct usb_descriptor_header *eth_hs_function[] __initdata = { ++ (struct usb_descriptor_header *) &rndis_iad_descriptor, + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, +- (struct usb_descriptor_header *) &acm_descriptor, ++ (struct usb_descriptor_header *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &rndis_union_desc, + (struct usb_descriptor_header *) &hs_notify_desc, + /* data interface has no altsetting */ +@@ -271,6 +289,7 @@ static struct usb_descriptor_header *eth + static struct usb_string rndis_string_defs[] = { + [0].s = "RNDIS Communications Control", + [1].s = "RNDIS Ethernet Data", ++ [2].s = "RNDIS", + { } /* end of list */ + }; + +@@ -587,6 +606,7 @@ rndis_bind(struct usb_configuration *c, + if (status < 0) + goto fail; + rndis->ctrl_id = status; ++ rndis_iad_descriptor.bFirstInterface = status; + + rndis_control_intf.bInterfaceNumber = status; + rndis_union_desc.bMasterInterface0 = status; +@@ -798,6 +818,13 @@ int __init rndis_bind_config(struct usb_ + return status; + rndis_string_defs[1].id = status; + rndis_data_intf.iInterface = status; ++ ++ /* IAD iFunction label */ ++ status = usb_string_id(c->cdev); ++ if (status < 0) ++ return status; ++ rndis_string_defs[2].id = status; ++ rndis_iad_descriptor.iFunction = status; + } + + /* allocate and initialize one new instance */ diff --git a/usb/usb-omap-update-mach-usb.h-to-allow-ehci-driver-to-build.patch b/usb/usb-omap-update-mach-usb.h-to-allow-ehci-driver-to-build.patch new file mode 100644 index 00000000000000..a1250acf60865e --- /dev/null +++ b/usb/usb-omap-update-mach-usb.h-to-allow-ehci-driver-to-build.patch @@ -0,0 +1,55 @@ +From gadiyar@ti.com Fri Nov 6 14:55:49 2009 +From: Anand Gadiyar <gadiyar@ti.com> +Date: Sat, 7 Nov 2009 01:15:59 +0530 +Subject: USB: OMAP: update mach/usb.h to allow ehci driver to build +Cc: Anand Gadiyar <gadiyar@ti.com>, Felipe Balbi <felipe.balbi@nokia.com>, Tony Lindgren <tony@atomide.com> +Message-ID: <1257536759-15242-1-git-send-email-gadiyar@ti.com> + + +OMAP: update mach/usb.h to allow ehci driver to build + +Add missing declarations to allow the recently introduced +ehci-omap driver to build on OMAP3 + +Signed-off-by: Anand Gadiyar <gadiyar@ti.com> +Cc: Felipe Balbi <felipe.balbi@nokia.com> +Cc: Tony Lindgren <tony@atomide.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + arch/arm/plat-omap/include/mach/usb.h | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/arch/arm/plat-omap/include/mach/usb.h ++++ b/arch/arm/plat-omap/include/mach/usb.h +@@ -5,6 +5,21 @@ + + #include <mach/board.h> + ++#define OMAP3_HS_USB_PORTS 3 ++enum ehci_hcd_omap_mode { ++ EHCI_HCD_OMAP_MODE_UNKNOWN, ++ EHCI_HCD_OMAP_MODE_PHY, ++ EHCI_HCD_OMAP_MODE_TLL, ++}; ++ ++struct ehci_hcd_omap_platform_data { ++ enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS]; ++ unsigned phy_reset:1; ++ ++ /* have to be valid if phy_reset is true and portx is in phy mode */ ++ int reset_gpio_port[OMAP3_HS_USB_PORTS]; ++}; ++ + /*-------------------------------------------------------------------------*/ + + #define OMAP1_OTG_BASE 0xfffb0400 +@@ -29,6 +44,8 @@ + + extern void usb_musb_init(void); + ++extern void usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata); ++ + #endif + + void omap_usb_init(struct omap_usb_config *pdata); diff --git a/usb/usb-serial-sierra-driver-memory-reduction.patch b/usb/usb-serial-sierra-driver-memory-reduction.patch new file mode 100644 index 00000000000000..133030ba05021f --- /dev/null +++ b/usb/usb-serial-sierra-driver-memory-reduction.patch @@ -0,0 +1,232 @@ +From epasheva@sierrawireless.com Fri Nov 6 14:51:32 2009 +From: Elina Pasheva <epasheva@sierrawireless.com> +Date: Wed, 4 Nov 2009 10:25:48 -0800 +Subject: USB: serial: sierra driver memory reduction +To: <gregkh@suse.de> +Cc: <epasheva@sierrawireless.com>, <rfiler@sierrawireless.com> +Message-ID: <1257359148.6455.2.camel@Linuxdev4-laptop> + + +From: Elina Pasheva <epasheva@sierrawireless.com> + +This patch deals with reducing the memory footprint for sierra driver. +This optimization is aimed for embedded software customers. + +Some sierra modems can expose upwards of 7 USB interfaces, each possibly +offering different services. In general, interfaces used for the +exchange of wireless data require much higher throughput, hence require +more memory (i.e. more URBs) than lower performance interfaces. URBs +used for the IN direction are pre-allocated by the driver and this patch +introduces a way to configure the number of IN URBs allocated on a +per-interface basis. Interfaces with lower throughput requirements +receive fewer URBs, thereby reducing the RAM memory consumed by the +driver. + +NOTE1: This driver has always pre-allocated URBs for the IN direction. + +NOTE2: The number of URBs pre-allocated for the low-performance +interfaces has already been extensively tested in previous versions of +this driver. + +We also added the capability to log function calls by adding DEBUG flag. +Please note that this flag is commented out because this is the default +state +for it. + +Signed-off-by: Elina Pasheva <epasheva@sierrawireless.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/sierra.c | 89 ++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 77 insertions(+), 12 deletions(-) + +--- a/drivers/usb/serial/sierra.c ++++ b/drivers/usb/serial/sierra.c +@@ -16,8 +16,9 @@ + Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> + Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> + */ +- +-#define DRIVER_VERSION "v.1.3.8" ++/* Uncomment to log function calls */ ++/* #define DEBUG */ ++#define DRIVER_VERSION "v.1.7.16" + #define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" + #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" + +@@ -33,8 +34,10 @@ + #define SWIMS_USB_REQUEST_SetPower 0x00 + #define SWIMS_USB_REQUEST_SetNmea 0x07 + +-#define N_IN_URB 8 +-#define N_OUT_URB 64 ++#define N_IN_URB_HM 8 ++#define N_OUT_URB_HM 64 ++#define N_IN_URB 4 ++#define N_OUT_URB 4 + #define IN_BUFLEN 4096 + + #define MAX_TRANSFER (PAGE_SIZE - 512) +@@ -124,6 +127,23 @@ static int is_blacklisted(const u8 ifnum + return 0; + } + ++static int is_himemory(const u8 ifnum, ++ const struct sierra_iface_info *himemorylist) ++{ ++ const u8 *info; ++ int i; ++ ++ if (himemorylist) { ++ info = himemorylist->ifaceinfo; ++ ++ for (i=0; i < himemorylist->infolen; i++) { ++ if (info[i] == ifnum) ++ return 1; ++ } ++ } ++ return 0; ++} ++ + static int sierra_calc_interface(struct usb_serial *serial) + { + int interface; +@@ -186,6 +206,20 @@ static int sierra_probe(struct usb_seria + return result; + } + ++/* interfaces with higher memory requirements */ ++static const u8 hi_memory_typeA_ifaces[] = { 0, 2 }; ++static const struct sierra_iface_info typeA_interface_list = { ++ .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces), ++ .ifaceinfo = hi_memory_typeA_ifaces, ++}; ++ ++static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 }; ++static const struct sierra_iface_info typeB_interface_list = { ++ .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces), ++ .ifaceinfo = hi_memory_typeB_ifaces, ++}; ++ ++/* 'blacklist' of interfaces not served by this driver */ + static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; + static const struct sierra_iface_info direct_ip_interface_blacklist = { + .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), +@@ -286,8 +320,10 @@ struct sierra_port_private { + struct usb_anchor active; + struct usb_anchor delayed; + ++ int num_out_urbs; ++ int num_in_urbs; + /* Input endpoints and buffers for this port */ +- struct urb *in_urbs[N_IN_URB]; ++ struct urb *in_urbs[N_IN_URB_HM]; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ +@@ -460,7 +496,7 @@ static int sierra_write(struct tty_struc + spin_lock_irqsave(&portdata->lock, flags); + dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, + portdata->outstanding_urbs); +- if (portdata->outstanding_urbs > N_OUT_URB) { ++ if (portdata->outstanding_urbs > portdata->num_out_urbs) { + spin_unlock_irqrestore(&portdata->lock, flags); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); + return 0; +@@ -665,7 +701,7 @@ static int sierra_write_room(struct tty_ + /* try to give a good number back based on if we have any free urbs at + * this point in time */ + spin_lock_irqsave(&portdata->lock, flags); +- if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) { ++ if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) { + spin_unlock_irqrestore(&portdata->lock, flags); + dev_dbg(&port->dev, "%s - write limit hit\n", __func__); + return 0; +@@ -680,7 +716,7 @@ static void sierra_stop_rx_urbs(struct u + int i; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + +- for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) ++ for (i = 0; i < portdata->num_in_urbs; i++) + usb_kill_urb(portdata->in_urbs[i]); + + usb_kill_urb(port->interrupt_in_urb); +@@ -695,7 +731,7 @@ static int sierra_submit_rx_urbs(struct + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + + ok_cnt = 0; +- for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { ++ for (i = 0; i < portdata->num_in_urbs; i++) { + urb = portdata->in_urbs[i]; + if (!urb) + continue; +@@ -791,7 +827,7 @@ static void sierra_close(struct usb_seri + /* Stop reading urbs */ + sierra_stop_rx_urbs(port); + /* .. and release them */ +- for (i = 0; i < N_IN_URB; i++) { ++ for (i = 0; i < portdata->num_in_urbs; i++) { + sierra_release_urb(portdata->in_urbs[i]); + portdata->in_urbs[i] = NULL; + } +@@ -818,7 +854,7 @@ static int sierra_open(struct tty_struct + + + endpoint = port->bulk_in_endpointAddress; +- for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { ++ for (i = 0; i < portdata->num_in_urbs; i++) { + urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, + IN_BUFLEN, GFP_KERNEL, + sierra_indat_callback); +@@ -869,7 +905,9 @@ static int sierra_startup(struct usb_ser + { + struct usb_serial_port *port; + struct sierra_port_private *portdata; ++ struct sierra_iface_info *himemoryp = NULL; + int i; ++ u8 ifnum; + + dev_dbg(&serial->dev->dev, "%s\n", __func__); + +@@ -886,13 +924,40 @@ static int sierra_startup(struct usb_ser + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dev_dbg(&port->dev, "%s: kmalloc for " +- "sierra_port_private (%d) failed!.\n", ++ "sierra_port_private (%d) failed!\n", + __func__, i); + return -ENOMEM; + } + spin_lock_init(&portdata->lock); + init_usb_anchor(&portdata->active); + init_usb_anchor(&portdata->delayed); ++ ifnum = i; ++ /* Assume low memory requirements */ ++ portdata->num_out_urbs = N_OUT_URB; ++ portdata->num_in_urbs = N_IN_URB; ++ ++ /* Determine actual memory requirements */ ++ if (serial->num_ports == 1) { ++ /* Get interface number for composite device */ ++ ifnum = sierra_calc_interface(serial); ++ himemoryp = ++ (struct sierra_iface_info *)&typeB_interface_list; ++ if (is_himemory(ifnum, himemoryp)) { ++ portdata->num_out_urbs = N_OUT_URB_HM; ++ portdata->num_in_urbs = N_IN_URB_HM; ++ } ++ } ++ else { ++ himemoryp = ++ (struct sierra_iface_info *)&typeA_interface_list; ++ if (is_himemory(i, himemoryp)) { ++ portdata->num_out_urbs = N_OUT_URB_HM; ++ portdata->num_in_urbs = N_IN_URB_HM; ++ } ++ } ++ dev_dbg(&serial->dev->dev, ++ "Memory usage (urbs) interface #%d, in=%d, out=%d\n", ++ ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); + /* Set the port private data pointer */ + usb_set_serial_port_data(port, portdata); + } |
