summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/Kconfig60
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/at91_udc.c6
-rw-r--r--drivers/usb/gadget/audio.c115
-rw-r--r--drivers/usb/gadget/composite.c59
-rw-r--r--drivers/usb/gadget/ether.c16
-rw-r--r--drivers/usb/gadget/f_acm.c30
-rw-r--r--drivers/usb/gadget/f_audio.c76
-rw-r--r--drivers/usb/gadget/f_mass_storage.c3091
-rw-r--r--drivers/usb/gadget/f_rndis.c35
-rw-r--r--drivers/usb/gadget/file_storage.c881
-rw-r--r--drivers/usb/gadget/mass_storage.c240
-rw-r--r--drivers/usb/gadget/multi.c358
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/storage_common.c778
-rw-r--r--drivers/usb/gadget/u_ether.h2
16 files changed, 4842 insertions, 911 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index a18e3c5dd82e..ee411206c699 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -732,6 +732,24 @@ config USB_FILE_STORAGE_TEST
behavior of USB Mass Storage hosts. Not needed for
normal operation.
+config USB_MASS_STORAGE
+ tristate "Mass Storage Gadget"
+ depends on BLOCK
+ help
+ The Mass Storage Gadget acts as a USB Mass Storage disk drive.
+ As its storage repository it can use a regular file or a block
+ device (in much the same way as the "loop" device driver),
+ specified as a module parameter or sysfs option.
+
+ This is heavily based on File-backed Storage Gadget and in most
+ cases you will want to use FSG instead. This gadget is mostly
+ here to test the functionality of the Mass Storage Function
+ which may be used with composite framework.
+
+ Say "y" to link the driver statically, or "m" to build
+ a dynamically linked module called "g_file_storage". If unsure,
+ consider File-backed Storage Gadget.
+
config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
help
@@ -794,6 +812,48 @@ config USB_CDC_COMPOSITE
Say "y" to link the driver statically, or "m" to build a
dynamically linked module.
+config USB_G_MULTI
+ tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
+ depends on BLOCK && NET
+ help
+ The Multifunction Composite Gadget provides Ethernet (RNDIS
+ and/or CDC Ethernet), mass storage and ACM serial link
+ interfaces.
+
+ You will be asked to choose which of the two configurations is
+ to be available in the gadget. At least one configuration must
+ be chosen to make the gadget usable. Selecting more than one
+ configuration will prevent Windows from automatically detecting
+ the gadget as a composite gadget, so an INF file will be needed to
+ use the gadget.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_multi".
+
+config USB_G_MULTI_RNDIS
+ bool "RNDIS + CDC Serial + Storage configuration"
+ depends on USB_G_MULTI
+ default y
+ help
+ This option enables a configuration with RNDIS, CDC Serial and
+ Mass Storage functions available in the Multifunction Composite
+ Gadget. This is the configuration dedicated for Windows since RNDIS
+ is Microsoft's protocol.
+
+ If unsure, say "y".
+
+config USB_G_MULTI_CDC
+ bool "CDC Ethernet + CDC Serial + Storage configuration"
+ depends on USB_G_MULTI
+ default n
+ help
+ This option enables a configuration with CDC Ethernet (ECM), CDC
+ Serial and Mass Storage functions available in the Multifunction
+ Composite Gadget.
+
+ If unsure, say "y".
+
+
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 9d7b87c52e9f..2e2c047262b7 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -39,16 +39,20 @@ g_serial-objs := serial.o
g_midi-objs := gmidi.o
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o
+g_mass_storage-objs := mass_storage.o
g_printer-objs := printer.o
g_cdc-objs := cdc2.o
+g_multi-objs := multi.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
+obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+obj-$(CONFIG_USB_G_MULTI) += g_multi.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 66450a1abc22..043e04db2a05 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -892,7 +892,7 @@ static void pullup(struct at91_udc *udc, int is_on)
txvc |= AT91_UDP_TXVC_PUON;
at91_udp_write(udc, AT91_UDP_TXVC, txvc);
- } else if (cpu_is_at91sam9261()) {
+ } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
u32 usbpucr;
usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
@@ -910,7 +910,7 @@ static void pullup(struct at91_udc *udc, int is_on)
txvc &= ~AT91_UDP_TXVC_PUON;
at91_udp_write(udc, AT91_UDP_TXVC, txvc);
- } else if (cpu_is_at91sam9261()) {
+ } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
u32 usbpucr;
usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
@@ -1692,7 +1692,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
udc->ep[3].maxpacket = 64;
udc->ep[4].maxpacket = 512;
udc->ep[5].maxpacket = 512;
- } else if (cpu_is_at91sam9261()) {
+ } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
udc->ep[3].maxpacket = 64;
} else if (cpu_is_at91sam9263()) {
udc->ep[0].maxpacket = 64;
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index a3a0f4a27ef0..58f220323847 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -89,120 +89,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
/*-------------------------------------------------------------------------*/
-/**
- * Handle USB audio endpoint set/get command in setup class request
- */
-
-static int audio_set_endpoint_req(struct usb_configuration *c,
- const struct usb_ctrlrequest *ctrl)
-{
- struct usb_composite_dev *cdev = c->cdev;
- int value = -EOPNOTSUPP;
- u16 ep = le16_to_cpu(ctrl->wIndex);
- u16 len = le16_to_cpu(ctrl->wLength);
- u16 w_value = le16_to_cpu(ctrl->wValue);
-
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
- ctrl->bRequest, w_value, len, ep);
-
- switch (ctrl->bRequest) {
- case UAC_SET_CUR:
- value = 0;
- break;
-
- case UAC_SET_MIN:
- break;
-
- case UAC_SET_MAX:
- break;
-
- case UAC_SET_RES:
- break;
-
- case UAC_SET_MEM:
- break;
-
- default:
- break;
- }
-
- return value;
-}
-
-static int audio_get_endpoint_req(struct usb_configuration *c,
- const struct usb_ctrlrequest *ctrl)
-{
- struct usb_composite_dev *cdev = c->cdev;
- int value = -EOPNOTSUPP;
- u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
- u16 len = le16_to_cpu(ctrl->wLength);
- u16 w_value = le16_to_cpu(ctrl->wValue);
-
- DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
- ctrl->bRequest, w_value, len, ep);
-
- switch (ctrl->bRequest) {
- case UAC_GET_CUR:
- case UAC_GET_MIN:
- case UAC_GET_MAX:
- case UAC_GET_RES:
- value = 3;
- break;
- case UAC_GET_MEM:
- break;
- default:
- break;
- }
-
- return value;
-}
-
-static int
-audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
-{
- struct usb_composite_dev *cdev = c->cdev;
- struct usb_request *req = cdev->req;
- 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);
-
- /* composite driver infrastructure handles everything except
- * Audio class messages; interface activation uses set_alt().
- */
- switch (ctrl->bRequestType) {
- case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
- value = audio_set_endpoint_req(c, ctrl);
- break;
-
- case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
- value = audio_get_endpoint_req(c, ctrl);
- break;
-
- default:
- ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- }
-
- /* respond with data transfer or status phase? */
- if (value >= 0) {
- DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- req->zero = 0;
- req->length = value;
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
- if (value < 0)
- ERROR(cdev, "Audio response on err %d\n", value);
- }
-
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
-/*-------------------------------------------------------------------------*/
-
static int __init audio_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
@@ -220,7 +106,6 @@ static int __init audio_do_config(struct usb_configuration *c)
static struct usb_configuration audio_config_driver = {
.label = DRIVER_DESC,
.bind = audio_do_config,
- .setup = audio_setup,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d05397ec8a18..09289bb1e20f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -373,6 +373,8 @@ static void reset_config(struct usb_composite_dev *cdev)
list_for_each_entry(f, &cdev->config->functions, list) {
if (f->disable)
f->disable(f);
+
+ bitmap_zero(f->endpoints, 32);
}
cdev->config = NULL;
}
@@ -418,10 +420,35 @@ static int set_config(struct usb_composite_dev *cdev,
/* Initialize all interfaces by setting them to altsetting zero. */
for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
struct usb_function *f = c->interface[tmp];
+ struct usb_descriptor_header **descriptors;
if (!f)
break;
+ /*
+ * Record which endpoints are used by the function. This is used
+ * to dispatch control requests targeted at that endpoint to the
+ * function's setup callback instead of the current
+ * configuration's setup callback.
+ */
+ if (gadget->speed == USB_SPEED_HIGH)
+ descriptors = f->hs_descriptors;
+ else
+ descriptors = f->descriptors;
+
+ for (; *descriptors; ++descriptors) {
+ struct usb_endpoint_descriptor *ep;
+ int addr;
+
+ if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
+ continue;
+
+ ep = (struct usb_endpoint_descriptor *)*descriptors;
+ addr = ((ep->bEndpointAddress & 0x80) >> 3)
+ | (ep->bEndpointAddress & 0x0f);
+ set_bit(addr, f->endpoints);
+ }
+
result = f->set_alt(f, tmp, 0);
if (result < 0) {
DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
@@ -688,6 +715,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
struct usb_function *f = NULL;
+ u8 endp;
/* partial re-init of the response message; the function or the
* gadget might need to intercept e.g. a control-OUT completion
@@ -800,23 +828,33 @@ unknown:
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
- /* functions always handle their interfaces ... punt other
- * recipients (endpoint, other, WUSB, ...) to the current
+ /* functions always handle their interfaces and endpoints...
+ * punt other recipients (other, WUSB, ...) to the current
* configuration code.
*
* REVISIT it could make sense to let the composite device
* take such requests too, if that's ever needed: to work
* in config 0, etc.
*/
- if ((ctrl->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_INTERFACE) {
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
f = cdev->config->interface[intf];
- if (f && f->setup)
- value = f->setup(f, ctrl);
- else
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
+ list_for_each_entry(f, &cdev->config->functions, list) {
+ if (test_bit(endp, f->endpoints))
+ break;
+ }
+ if (&f->list == &cdev->config->functions)
f = NULL;
+ break;
}
- if (value < 0 && !f) {
+
+ if (f && f->setup)
+ value = f->setup(f, ctrl);
+ else {
struct usb_configuration *c;
c = cdev->config;
@@ -1054,7 +1092,8 @@ static struct usb_gadget_driver composite_driver = {
.speed = USB_SPEED_HIGH,
.bind = composite_bind,
- .unbind = __exit_p(composite_unbind),
+ /* .unbind = __exit_p(composite_unbind), */
+ .unbind = composite_unbind,
.setup = composite_setup,
.disconnect = composite_disconnect,
@@ -1103,7 +1142,7 @@ int __init usb_composite_register(struct usb_composite_driver *driver)
* This function is used to unregister drivers using the composite
* driver framework.
*/
-void __exit usb_composite_unregister(struct usb_composite_driver *driver)
+void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver)
{
if (composite != driver)
return;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 167cb2a8ecef..141372b6e7a1 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -25,6 +25,14 @@
#include <linux/kernel.h>
#include <linux/utsname.h>
+
+#if defined USB_ETH_RNDIS
+# undef USB_ETH_RNDIS
+#endif
+#ifdef CONFIG_USB_ETH_RNDIS
+# define USB_ETH_RNDIS y
+#endif
+
#include "u_ether.h"
@@ -66,7 +74,7 @@
#define DRIVER_DESC "Ethernet Gadget"
#define DRIVER_VERSION "Memorial Day 2008"
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef USB_ETH_RNDIS
#define PREFIX "RNDIS/"
#else
#define PREFIX ""
@@ -87,7 +95,7 @@
static inline bool has_rndis(void)
{
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef USB_ETH_RNDIS
return true;
#else
return false;
@@ -110,7 +118,7 @@ static inline bool has_rndis(void)
#include "f_ecm.c"
#include "f_subset.c"
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef USB_ETH_RNDIS
#include "f_rndis.c"
#include "rndis.c"
#endif
@@ -251,7 +259,7 @@ static struct usb_configuration rndis_config_driver = {
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_ETH_EEM
+#ifdef USB_ETH_EEM
static int use_eem = 1;
#else
static int use_eem;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7953948bfe4a..d10353d46b86 100644
--- 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(struct gserial *p)
/* 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 acm_fs_out_desc __initdata = {
};
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 acm_hs_out_desc __initdata = {
};
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_hs_function[] __initdata = {
#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 */ },
};
@@ -432,7 +452,7 @@ static void acm_disable(struct usb_function *f)
* @length: size of data
* Context: irqs blocked, acm->lock held, acm_notify_req non-null
*
- * Returns zero on sucess or a negative errno.
+ * Returns zero on success or a negative errno.
*
* See section 6.3.5 of the CDC 1.1 specification for information
* about the only notification we issue: SerialState change.
@@ -563,6 +583,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
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_configuration *c, u8 port_num)
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 */
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 98e9bb977291..c43c89ffa2c8 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -445,6 +445,70 @@ static int audio_get_intf_req(struct usb_function *f,
return len;
}
+static int audio_set_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int value = -EOPNOTSUPP;
+ u16 ep = le16_to_cpu(ctrl->wIndex);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ switch (ctrl->bRequest) {
+ case UAC_SET_CUR:
+ value = 0;
+ break;
+
+ case UAC_SET_MIN:
+ break;
+
+ case UAC_SET_MAX:
+ break;
+
+ case UAC_SET_RES:
+ break;
+
+ case UAC_SET_MEM:
+ break;
+
+ default:
+ break;
+ }
+
+ return value;
+}
+
+static int audio_get_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int value = -EOPNOTSUPP;
+ u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ switch (ctrl->bRequest) {
+ case UAC_GET_CUR:
+ case UAC_GET_MIN:
+ case UAC_GET_MAX:
+ case UAC_GET_RES:
+ value = 3;
+ break;
+ case UAC_GET_MEM:
+ break;
+ default:
+ break;
+ }
+
+ return value;
+}
+
static int
f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
@@ -455,8 +519,8 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
- /* composite driver infrastructure handles everything except
- * Audio class messages; interface activation uses set_alt().
+ /* composite driver infrastructure handles everything; interface
+ * activation uses set_alt().
*/
switch (ctrl->bRequestType) {
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
@@ -467,6 +531,14 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
value = audio_get_intf_req(f, ctrl);
break;
+ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_set_endpoint_req(f, ctrl);
+ break;
+
+ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_get_endpoint_req(f, ctrl);
+ break;
+
default:
ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
new file mode 100644
index 000000000000..a37640eba434
--- /dev/null
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -0,0 +1,3091 @@
+/*
+ * f_mass_storage.c -- Mass Storage USB Composite Function
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * 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 Mass Storage Function 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 composite
+ * function for a USB device, it also illustrates a technique of
+ * double-buffering for increased throughput.
+ *
+ * Function supports multiple logical units (LUNs). Backing storage
+ * for each LUN is provided by a regular file or a block device.
+ * Access for each LUN can be limited to read-only. Moreover, the
+ * function can indicate that LUN is removable and/or CD-ROM. (The
+ * later implies read-only access.)
+ *
+ * MSF is configured by specifying a fsg_config structure. It has the
+ * following fields:
+ *
+ * nluns Number of LUNs function have (anywhere from 1
+ * to FSG_MAX_LUNS which is 8).
+ * luns An array of LUN configuration values. This
+ * should be filled for each LUN that
+ * function will include (ie. for "nluns"
+ * LUNs). Each element of the array has
+ * the following fields:
+ * ->filename The path to the backing file for the LUN.
+ * Required if LUN is not marked as
+ * removable.
+ * ->ro Flag specifying access to the LUN shall be
+ * read-only. This is implied if CD-ROM
+ * emulation is enabled as well as when
+ * it was impossible to open "filename"
+ * in R/W mode.
+ * ->removable Flag specifying that LUN shall be indicated as
+ * being removable.
+ * ->cdrom Flag specifying that LUN shall be reported as
+ * being a CD-ROM.
+ *
+ * lun_name_format A printf-like format for names of the LUN
+ * devices. This determines how the
+ * directory in sysfs will be named.
+ * Unless you are using several MSFs in
+ * a single gadget (as opposed to single
+ * MSF in many configurations) you may
+ * leave it as NULL (in which case
+ * "lun%d" will be used). In the format
+ * you can use "%d" to index LUNs for
+ * MSF's with more than one LUN. (Beware
+ * that there is only one integer given
+ * as an argument for the format and
+ * specifying invalid format may cause
+ * unspecified behaviour.)
+ * thread_name Name of the kernel thread process used by the
+ * MSF. You can safely set it to NULL
+ * (in which case default "file-storage"
+ * will be used).
+ *
+ * vendor_name
+ * product_name
+ * release Information used as a reply to INQUIRY
+ * request. To use default set to NULL,
+ * NULL, 0xffff respectively. The first
+ * field should be 8 and the second 16
+ * characters or less.
+ *
+ * can_stall Set to permit function to halt bulk endpoints.
+ * Disabled on some USB devices known not
+ * to work correctly. You should set it
+ * to true.
+ *
+ * If "removable" is not set for a LUN then a backing file must be
+ * specified. If it is set, then NULL filename means the LUN's medium
+ * is not loaded (an empty string as "filename" in the fsg_config
+ * structure causes error). 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.
+ *
+ *
+ * MSF includes support for module parameters. If gadget using it
+ * decides to use it, the following module parameters will be
+ * available:
+ *
+ * file=filename[,filename...]
+ * Names of the files or block devices used for
+ * backing storage.
+ * ro=b[,b...] Default false, boolean for read-only access.
+ * removable=b[,b...]
+ * Default true, boolean for removable media.
+ * cdrom=b[,b...] Default false, boolean for whether to emulate
+ * a CD-ROM drive.
+ * 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.
+ *
+ * The module parameters may be prefixed with some string. You need
+ * to consult gadget's documentation or source to verify whether it is
+ * using those module parameters and if it does what are the prefixes
+ * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is
+ * the prefix).
+ *
+ *
+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
+ * needed. 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.
+ *
+ *
+ * The pathnames of the backing files and the ro settings are
+ * available in the attribute files "file" and "ro" in the lun<n> (or
+ * to be more precise in a directory which name comes from
+ * "lun_name_format" option!) 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 function is heavily based on "File-backed Storage Gadget" by
+ * Alan Stern which in turn 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 MSF 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. At of this moment, MSF
+ * provides no way to deregister the gadget when thread dies -- maybe
+ * a callback functions is needed.
+ *
+ * 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"
+
+
+
+/*------------------------------------------------------------------------*/
+
+#define FSG_DRIVER_DESC "Mass Storage Function"
+#define FSG_DRIVER_VERSION "2009/09/11"
+
+static const char fsg_string_interface[] = "Mass Storage";
+
+
+#define FSG_NO_INTR_EP 1
+#define FSG_BUFFHD_STATIC_BUFFER 1
+#define FSG_NO_DEVICE_STRINGS 1
+#define FSG_NO_OTG 1
+#define FSG_NO_INTR_EP 1
+
+#include "storage_common.c"
+
+
+/*-------------------------------------------------------------------------*/
+
+struct fsg_dev;
+
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+ struct usb_gadget *gadget;
+ struct fsg_dev *fsg;
+ struct fsg_dev *prev_fsg;
+
+ /* filesem protects: backing files in use */
+ struct rw_semaphore filesem;
+
+ /* lock protects: state, all the req_busy's */
+ spinlock_t lock;
+
+ struct usb_ep *ep0; /* Copy of gadget->ep0 */
+ struct usb_request *ep0req; /* Copy of cdev->req */
+ unsigned int ep0_req_tag;
+ const char *ep0req_name;
+
+ 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;
+
+ unsigned int bulk_out_maxpacket;
+ enum fsg_state state; /* For exception handling */
+ unsigned int exception_req_tag;
+
+ u8 config, new_config;
+ enum data_direction data_dir;
+ u32 data_size;
+ u32 data_size_from_cmnd;
+ u32 tag;
+ u32 residue;
+ u32 usb_amount_left;
+
+ unsigned int can_stall:1;
+ unsigned int free_storage_on_release:1;
+ unsigned int phase_error:1;
+ unsigned int short_packet_received:1;
+ unsigned int bad_lun_okay:1;
+ unsigned int running:1;
+
+ int thread_wakeup_needed;
+ struct completion thread_notifier;
+ struct task_struct *thread_task;
+
+ /* Callback function to call when thread exits. */
+ void (*thread_exits)(struct fsg_common *common);
+ /* Gadget's private data. */
+ void *private_data;
+
+ /* Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte */
+ char inquiry_string[8 + 16 + 4 + 1];
+
+ struct kref ref;
+};
+
+
+struct fsg_config {
+ unsigned nluns;
+ struct fsg_lun_config {
+ const char *filename;
+ char ro;
+ char removable;
+ char cdrom;
+ } luns[FSG_MAX_LUNS];
+
+ const char *lun_name_format;
+ const char *thread_name;
+
+ /* Callback function to call when thread exits. */
+ void (*thread_exits)(struct fsg_common *common);
+ /* Gadget's private data. */
+ void *private_data;
+
+ const char *vendor_name; /* 8 characters or less */
+ const char *product_name; /* 16 characters or less */
+ u16 release;
+
+ char can_stall;
+};
+
+
+struct fsg_dev {
+ struct usb_function function;
+ struct usb_gadget *gadget; /* Copy of cdev->gadget */
+ struct fsg_common *common;
+
+ u16 interface_number;
+
+ unsigned int bulk_in_enabled:1;
+ unsigned int bulk_out_enabled:1;
+
+ unsigned long atomic_bitflags;
+#define IGNORE_BULK_OUT 0
+
+ struct usb_ep *bulk_in;
+ struct usb_ep *bulk_out;
+};
+
+
+static inline int __fsg_is_set(struct fsg_common *common,
+ const char *func, unsigned line)
+{
+ if (common->fsg)
+ return 1;
+ ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
+ return 0;
+}
+
+#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
+
+
+static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
+{
+ return container_of(f, struct fsg_dev, function);
+}
+
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int exception_in_progress(struct fsg_common *common)
+{
+ return common->state > FSG_STATE_IDLE;
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void set_bulk_out_req_length(struct fsg_common *common,
+ struct fsg_buffhd *bh, unsigned int length)
+{
+ unsigned int rem;
+
+ bh->bulk_out_intended_length = length;
+ rem = length % common->bulk_out_maxpacket;
+ if (rem > 0)
+ length += common->bulk_out_maxpacket - rem;
+ bh->outreq->length = length;
+}
+
+/*-------------------------------------------------------------------------*/
+
+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);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+/* Caller must hold fsg->lock */
+static void wakeup_thread(struct fsg_common *common)
+{
+ /* Tell the main thread that something has happened */
+ common->thread_wakeup_needed = 1;
+ if (common->thread_task)
+ wake_up_process(common->thread_task);
+}
+
+
+static void raise_exception(struct fsg_common *common, 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(&common->lock, flags);
+ if (common->state <= new_state) {
+ common->exception_req_tag = common->ep0_req_tag;
+ common->state = new_state;
+ if (common->thread_task)
+ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+ common->thread_task);
+ }
+ spin_unlock_irqrestore(&common->lock, flags);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ep0_queue(struct fsg_common *common)
+{
+ int rc;
+
+ rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
+ common->ep0->driver_data = common;
+ if (rc != 0 && rc != -ESHUTDOWN) {
+ /* We can't do much more than wait for a reset */
+ WARNING(common, "error in submission: %s --> %d\n",
+ common->ep0->name, rc);
+ }
+ return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* 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_common *common = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
+
+ if (req->status || req->actual != req->length)
+ DBG(common, "%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(&common->lock);
+ bh->inreq_busy = 0;
+ bh->state = BUF_STATE_EMPTY;
+ wakeup_thread(common);
+ spin_unlock(&common->lock);
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct fsg_common *common = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
+
+ dump_msg(common, "bulk-out", req->buf, req->actual);
+ if (req->status || req->actual != bh->bulk_out_intended_length)
+ DBG(common, "%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(&common->lock);
+ bh->outreq_busy = 0;
+ bh->state = BUF_STATE_FULL;
+ wakeup_thread(common);
+ spin_unlock(&common->lock);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Ep0 class-specific handlers. These always run in_irq. */
+
+static int fsg_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+ struct usb_request *req = fsg->common->ep0req;
+ 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->common->config)
+ return -EOPNOTSUPP;
+
+ switch (ctrl->bRequest) {
+
+ case USB_BULK_RESET_REQUEST:
+ if (ctrl->bRequestType !=
+ (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+ break;
+ if (w_index != fsg->interface_number || w_value != 0)
+ return -EDOM;
+
+ /* Raise an exception to stop the current operation
+ * and reinitialize our state. */
+ DBG(fsg, "bulk reset request\n");
+ raise_exception(fsg->common, FSG_STATE_RESET);
+ return DELAYED_STATUS;
+
+ case USB_BULK_GET_MAX_LUN_REQUEST:
+ if (ctrl->bRequestType !=
+ (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+ break;
+ if (w_index != fsg->interface_number || w_value != 0)
+ return -EDOM;
+ VDBG(fsg, "get max LUN\n");
+ *(u8 *) req->buf = fsg->common->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;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* 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);
+
+ spin_lock_irq(&fsg->common->lock);
+ *pbusy = 1;
+ *state = BUF_STATE_BUSY;
+ spin_unlock_irq(&fsg->common->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);
+ }
+}
+
+#define START_TRANSFER_OR(common, ep_name, req, pbusy, state) \
+ if (fsg_is_set(common)) \
+ start_transfer((common)->fsg, (common)->fsg->ep_name, \
+ req, pbusy, state); \
+ else
+
+#define START_TRANSFER(common, ep_name, req, pbusy, state) \
+ START_TRANSFER_OR(common, ep_name, req, pbusy, state) (void)0
+
+
+
+static int sleep_thread(struct fsg_common *common)
+{
+ 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 (common->thread_wakeup_needed)
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+ common->thread_wakeup_needed = 0;
+ return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_read(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->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 (common->cmnd[0] == SC_READ_6)
+ lba = get_unaligned_be24(&common->cmnd[1]);
+ else {
+ lba = get_unaligned_be32(&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 ((common->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 = common->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(amount_left, FSG_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 = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ 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;
+ common->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_OR(common, bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state)
+ /* Don't know what to do if
+ * common->fsg is NULL */
+ return -EIO;
+ common->next_buffhd_to_fill = bh->next;
+ }
+
+ return -EIO; /* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_write(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->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 (common->cmnd[0] == SC_WRITE_6)
+ lba = get_unaligned_be24(&common->cmnd[1]);
+ else {
+ lba = get_unaligned_be32(&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 (common->cmnd[1] & ~0x18) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ if (common->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 = common->data_size_from_cmnd;
+ amount_left_to_write = common->data_size_from_cmnd;
+
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+ bh = common->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, FSG_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;
+ common->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 = amount;
+ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+ START_TRANSFER_OR(common, bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state)
+ /* Don't know what to do if
+ * common->fsg is NULL */
+ return -EIO;
+ common->next_buffhd_to_fill = bh->next;
+ continue;
+ }
+
+ /* Write the received data to the backing file */
+ bh = 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();
+ common->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;
+ common->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) {
+ common->short_packet_received = 1;
+ break;
+ }
+ continue;
+ }
+
+ /* Wait for something to happen */
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+
+ return -EIO; /* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_synchronize_cache(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->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_common *common)
+{
+ struct fsg_lun *curlun = common->curlun;
+ u32 lba;
+ u32 verification_length;
+ struct fsg_buffhd *bh = common->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(&common->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 (common->cmnd[1] & ~0x10) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+
+ verification_length = get_unaligned_be16(&common->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(amount_left, FSG_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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ u8 *buf = (u8 *) bh->buf;
+
+ if (!curlun) { /* Unsupported LUNs are okay */
+ common->bad_lun_okay = 1;
+ memset(buf, 0, 36);
+ buf[0] = 0x7f; /* Unsupported, no device-type */
+ buf[4] = 31; /* Additional length */
+ return 36;
+ }
+
+ buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
+ buf[1] = curlun->removable ? 0x80 : 0;
+ buf[2] = 2; /* ANSI SCSI level 2 */
+ buf[3] = 2; /* SCSI-2 INQUIRY data format */
+ buf[4] = 31; /* Additional length */
+ buf[5] = 0; /* No special options */
+ buf[6] = 0;
+ buf[7] = 0;
+ memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
+ return 36;
+}
+
+
+static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->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 */
+ common->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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ u32 lba = get_unaligned_be32(&common->cmnd[2]);
+ int pmi = common->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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ int msf = common->cmnd[1] & 0x02;
+ u32 lba = get_unaligned_be32(&common->cmnd[2]);
+ u8 *buf = (u8 *) bh->buf;
+
+ if (common->cmnd[1] & ~0x02) { /* 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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ int msf = common->cmnd[1] & 0x02;
+ int start_track = common->cmnd[6];
+ u8 *buf = (u8 *) bh->buf;
+
+ if ((common->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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ int mscmnd = common->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 ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ pc = common->cmnd[2] >> 6;
+ page_code = common->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 FSG_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_common *common)
+{
+ if (!common->curlun) {
+ return -EINVAL;
+ } else if (!common->curlun->removable) {
+ common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int do_prevent_allow(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->curlun;
+ int prevent;
+
+ if (!common->curlun) {
+ return -EINVAL;
+ } else if (!common->curlun->removable) {
+ common->curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+
+ prevent = common->cmnd[4] & 0x01;
+ if ((common->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_common *common,
+ struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->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_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+
+ /* We don't support MODE SELECT */
+ if (curlun)
+ 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->common->next_buffhd_to_fill;
+ u32 nkeep = bh->inreq->length;
+ u32 nsend;
+ int rc;
+
+ bh->state = BUF_STATE_EMPTY; /* For the first iteration */
+ fsg->common->usb_amount_left = nkeep + fsg->common->residue;
+ while (fsg->common->usb_amount_left > 0) {
+
+ /* Wait for the next buffer to be free */
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg->common);
+ if (rc)
+ return rc;
+ }
+
+ nsend = min(fsg->common->usb_amount_left, FSG_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->common->next_buffhd_to_fill = bh->next;
+ fsg->common->usb_amount_left -= nsend;
+ nkeep = 0;
+ }
+ return 0;
+}
+
+static int throw_away_data(struct fsg_common *common)
+{
+ struct fsg_buffhd *bh;
+ u32 amount;
+ int rc;
+
+ for (bh = common->next_buffhd_to_drain;
+ bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
+ bh = 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;
+ common->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(common,
+ FSG_STATE_ABORT_BULK_OUT);
+ return -EINTR;
+ }
+ continue;
+ }
+
+ /* Try to submit another request if we need one */
+ bh = common->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY
+ && common->usb_amount_left > 0) {
+ amount = min(common->usb_amount_left, FSG_BUFLEN);
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+ bh->outreq->length = amount;
+ bh->bulk_out_intended_length = amount;
+ bh->outreq->short_not_ok = 1;
+ START_TRANSFER_OR(common, bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state)
+ /* Don't know what to do if
+ * common->fsg is NULL */
+ return -EIO;
+ common->next_buffhd_to_fill = bh->next;
+ common->usb_amount_left -= amount;
+ continue;
+ }
+
+ /* Otherwise wait for something to happen */
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+
+static int finish_reply(struct fsg_common *common)
+{
+ struct fsg_buffhd *bh = common->next_buffhd_to_fill;
+ int rc = 0;
+
+ switch (common->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 (!common->can_stall) {
+ /* Nothing */
+ } else if (fsg_is_set(common)) {
+ fsg_set_halt(common->fsg, common->fsg->bulk_out);
+ rc = halt_bulk_in_endpoint(common->fsg);
+ } else {
+ /* Don't know what to do if common->fsg is NULL */
+ rc = -EIO;
+ }
+ break;
+
+ /* All but the last buffer of data must have already been sent */
+ case DATA_DIR_TO_HOST:
+ if (common->data_size == 0) {
+ /* Nothing to send */
+
+ /* If there's no residue, simply send the last buffer */
+ } else if (common->residue == 0) {
+ bh->inreq->zero = 0;
+ START_TRANSFER_OR(common, bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state)
+ return -EIO;
+ 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
+ * stall, pad out the remaining data with 0's. */
+ } else if (common->can_stall) {
+ bh->inreq->zero = 1;
+ START_TRANSFER_OR(common, bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state)
+ /* Don't know what to do if
+ * common->fsg is NULL */
+ rc = -EIO;
+ common->next_buffhd_to_fill = bh->next;
+ if (common->fsg)
+ rc = halt_bulk_in_endpoint(common->fsg);
+ } else if (fsg_is_set(common)) {
+ rc = pad_with_zeros(common->fsg);
+ } else {
+ /* Don't know what to do if common->fsg is NULL */
+ rc = -EIO;
+ }
+ 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 (common->residue == 0) {
+ /* Nothing to receive */
+
+ /* Did the host stop sending unexpectedly early? */
+ } else if (common->short_packet_received) {
+ raise_exception(common, 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 (common->can_stall) {
+ if (fsg_is_set(common))
+ fsg_set_halt(common->fsg,
+ common->fsg->bulk_out);
+ raise_exception(common, 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(common);
+ }
+ break;
+ }
+ return rc;
+}
+
+
+static int send_status(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->curlun;
+ struct fsg_buffhd *bh;
+ struct bulk_cs_wrap *csw;
+ int rc;
+ u8 status = USB_STATUS_PASS;
+ u32 sd, sdinfo = 0;
+
+ /* Wait for the next buffer to become available */
+ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+
+ if (curlun) {
+ sd = curlun->sense_data;
+ sdinfo = curlun->sense_data_info;
+ } else if (common->bad_lun_okay)
+ sd = SS_NO_SENSE;
+ else
+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+ if (common->phase_error) {
+ DBG(common, "sending phase-error status\n");
+ status = USB_STATUS_PHASE_ERROR;
+ sd = SS_INVALID_COMMAND;
+ } else if (sd != SS_NO_SENSE) {
+ DBG(common, "sending command-failure status\n");
+ status = USB_STATUS_FAIL;
+ VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+ " info x%x\n",
+ SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+ }
+
+ /* Store and send the Bulk-only CSW */
+ csw = (void *)bh->buf;
+
+ csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+ csw->Tag = common->tag;
+ csw->Residue = cpu_to_le32(common->residue);
+ csw->Status = status;
+
+ bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ bh->inreq->zero = 0;
+ START_TRANSFER_OR(common, bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state)
+ /* Don't know what to do if common->fsg is NULL */
+ return -EIO;
+
+ common->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_common *common, int cmnd_size,
+ enum data_direction data_dir, unsigned int mask,
+ int needs_medium, const char *name)
+{
+ int i;
+ int lun = common->cmnd[1] >> 5;
+ static const char dirletter[4] = {'u', 'o', 'i', 'n'};
+ char hdlen[20];
+ struct fsg_lun *curlun;
+
+ hdlen[0] = 0;
+ if (common->data_dir != DATA_DIR_UNKNOWN)
+ sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
+ common->data_size);
+ VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
+ name, cmnd_size, dirletter[(int) data_dir],
+ common->data_size_from_cmnd, common->cmnd_size, hdlen);
+
+ /* We can't reply at all until we know the correct data direction
+ * and size. */
+ if (common->data_size_from_cmnd == 0)
+ data_dir = DATA_DIR_NONE;
+ if (common->data_size < common->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. */
+ common->data_size_from_cmnd = common->data_size;
+ common->phase_error = 1;
+ }
+ common->residue = common->data_size;
+ common->usb_amount_left = common->data_size;
+
+ /* Conflicting data directions is a phase error */
+ if (common->data_dir != data_dir
+ && common->data_size_from_cmnd > 0) {
+ common->phase_error = 1;
+ return -EINVAL;
+ }
+
+ /* Verify the length of the command itself */
+ if (cmnd_size != common->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 <= common->cmnd_size) {
+ DBG(common, "%s is buggy! Expected length %d "
+ "but we got %d\n", name,
+ cmnd_size, common->cmnd_size);
+ cmnd_size = common->cmnd_size;
+ } else {
+ common->phase_error = 1;
+ return -EINVAL;
+ }
+ }
+
+ /* Check that the LUN values are consistent */
+ if (common->lun != lun)
+ DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
+ common->lun, lun);
+
+ /* Check the LUN */
+ if (common->lun >= 0 && common->lun < common->nluns) {
+ curlun = &common->luns[common->lun];
+ common->curlun = curlun;
+ if (common->cmnd[0] != SC_REQUEST_SENSE) {
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+ } else {
+ common->curlun = NULL;
+ curlun = NULL;
+ common->bad_lun_okay = 0;
+
+ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
+ * to use unsupported LUNs; all others may not. */
+ if (common->cmnd[0] != SC_INQUIRY &&
+ common->cmnd[0] != SC_REQUEST_SENSE) {
+ DBG(common, "unsupported LUN %d\n", common->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 &&
+ common->cmnd[0] != SC_INQUIRY &&
+ 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 */
+ common->cmnd[1] &= 0x1f; /* Mask away the LUN */
+ for (i = 1; i < cmnd_size; ++i) {
+ if (common->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_common *common)
+{
+ struct fsg_buffhd *bh;
+ int rc;
+ int reply = -EINVAL;
+ int i;
+ static char unknown[16];
+
+ dump_cdb(common);
+
+ /* Wait for the next buffer to become available for data or status */
+ bh = common->next_buffhd_to_fill;
+ common->next_buffhd_to_drain = bh;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+ common->phase_error = 0;
+ common->short_packet_received = 0;
+
+ down_read(&common->filesem); /* We're using the backing file */
+ switch (common->cmnd[0]) {
+
+ case SC_INQUIRY:
+ common->data_size_from_cmnd = common->cmnd[4];
+ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<4), 0,
+ "INQUIRY");
+ if (reply == 0)
+ reply = do_inquiry(common, bh);
+ break;
+
+ case SC_MODE_SELECT_6:
+ common->data_size_from_cmnd = common->cmnd[4];
+ reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+ (1<<1) | (1<<4), 0,
+ "MODE SELECT(6)");
+ if (reply == 0)
+ reply = do_mode_select(common, bh);
+ break;
+
+ case SC_MODE_SELECT_10:
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+ (1<<1) | (3<<7), 0,
+ "MODE SELECT(10)");
+ if (reply == 0)
+ reply = do_mode_select(common, bh);
+ break;
+
+ case SC_MODE_SENSE_6:
+ common->data_size_from_cmnd = common->cmnd[4];
+ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<1) | (1<<2) | (1<<4), 0,
+ "MODE SENSE(6)");
+ if (reply == 0)
+ reply = do_mode_sense(common, bh);
+ break;
+
+ case SC_MODE_SENSE_10:
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (1<<1) | (1<<2) | (3<<7), 0,
+ "MODE SENSE(10)");
+ if (reply == 0)
+ reply = do_mode_sense(common, bh);
+ break;
+
+ case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ common->data_size_from_cmnd = 0;
+ reply = check_command(common, 6, DATA_DIR_NONE,
+ (1<<4), 0,
+ "PREVENT-ALLOW MEDIUM REMOVAL");
+ if (reply == 0)
+ reply = do_prevent_allow(common);
+ break;
+
+ case SC_READ_6:
+ i = common->cmnd[4];
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (7<<1) | (1<<4), 1,
+ "READ(6)");
+ if (reply == 0)
+ reply = do_read(common);
+ break;
+
+ case SC_READ_10:
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]) << 9;
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "READ(10)");
+ if (reply == 0)
+ reply = do_read(common);
+ break;
+
+ case SC_READ_12:
+ common->data_size_from_cmnd =
+ get_unaligned_be32(&common->cmnd[6]) << 9;
+ reply = check_command(common, 12, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "READ(12)");
+ if (reply == 0)
+ reply = do_read(common);
+ break;
+
+ case SC_READ_CAPACITY:
+ common->data_size_from_cmnd = 8;
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (0xf<<2) | (1<<8), 1,
+ "READ CAPACITY");
+ if (reply == 0)
+ reply = do_read_capacity(common, bh);
+ break;
+
+ case SC_READ_HEADER:
+ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (3<<7) | (0x1f<<1), 1,
+ "READ HEADER");
+ if (reply == 0)
+ reply = do_read_header(common, bh);
+ break;
+
+ case SC_READ_TOC:
+ if (!common->curlun || !common->curlun->cdrom)
+ goto unknown_cmnd;
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (7<<6) | (1<<1), 1,
+ "READ TOC");
+ if (reply == 0)
+ reply = do_read_toc(common, bh);
+ break;
+
+ case SC_READ_FORMAT_CAPACITIES:
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command(common, 10, DATA_DIR_TO_HOST,
+ (3<<7), 1,
+ "READ FORMAT CAPACITIES");
+ if (reply == 0)
+ reply = do_read_format_capacities(common, bh);
+ break;
+
+ case SC_REQUEST_SENSE:
+ common->data_size_from_cmnd = common->cmnd[4];
+ reply = check_command(common, 6, DATA_DIR_TO_HOST,
+ (1<<4), 0,
+ "REQUEST SENSE");
+ if (reply == 0)
+ reply = do_request_sense(common, bh);
+ break;
+
+ case SC_START_STOP_UNIT:
+ common->data_size_from_cmnd = 0;
+ reply = check_command(common, 6, DATA_DIR_NONE,
+ (1<<1) | (1<<4), 0,
+ "START-STOP UNIT");
+ if (reply == 0)
+ reply = do_start_stop(common);
+ break;
+
+ case SC_SYNCHRONIZE_CACHE:
+ common->data_size_from_cmnd = 0;
+ reply = check_command(common, 10, DATA_DIR_NONE,
+ (0xf<<2) | (3<<7), 1,
+ "SYNCHRONIZE CACHE");
+ if (reply == 0)
+ reply = do_synchronize_cache(common);
+ break;
+
+ case SC_TEST_UNIT_READY:
+ common->data_size_from_cmnd = 0;
+ reply = check_command(common, 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:
+ common->data_size_from_cmnd = 0;
+ reply = check_command(common, 10, DATA_DIR_NONE,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "VERIFY");
+ if (reply == 0)
+ reply = do_verify(common);
+ break;
+
+ case SC_WRITE_6:
+ i = common->cmnd[4];
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+ (7<<1) | (1<<4), 1,
+ "WRITE(6)");
+ if (reply == 0)
+ reply = do_write(common);
+ break;
+
+ case SC_WRITE_10:
+ common->data_size_from_cmnd =
+ get_unaligned_be16(&common->cmnd[7]) << 9;
+ reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "WRITE(10)");
+ if (reply == 0)
+ reply = do_write(common);
+ break;
+
+ case SC_WRITE_12:
+ common->data_size_from_cmnd =
+ get_unaligned_be32(&common->cmnd[6]) << 9;
+ reply = check_command(common, 12, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "WRITE(12)");
+ if (reply == 0)
+ reply = do_write(common);
+ 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:
+ common->data_size_from_cmnd = 0;
+ sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
+ reply = check_command(common, common->cmnd_size,
+ DATA_DIR_UNKNOWN, 0xff, 0, unknown);
+ if (reply == 0) {
+ common->curlun->sense_data = SS_INVALID_COMMAND;
+ reply = -EINVAL;
+ }
+ break;
+ }
+ up_read(&common->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 && common->data_dir == DATA_DIR_TO_HOST) {
+ reply = min((u32) reply, common->data_size_from_cmnd);
+ bh->inreq->length = reply;
+ bh->state = BUF_STATE_FULL;
+ common->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;
+ struct fsg_common *common = fsg->common;
+
+ /* 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 (common->can_stall) {
+ fsg_set_halt(fsg, fsg->bulk_out);
+ halt_bulk_in_endpoint(fsg);
+ }
+ return -EINVAL;
+ }
+
+ /* Save the command for later */
+ common->cmnd_size = cbw->Length;
+ memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
+ if (cbw->Flags & USB_BULK_IN_FLAG)
+ common->data_dir = DATA_DIR_TO_HOST;
+ else
+ common->data_dir = DATA_DIR_FROM_HOST;
+ common->data_size = le32_to_cpu(cbw->DataTransferLength);
+ if (common->data_size == 0)
+ common->data_dir = DATA_DIR_NONE;
+ common->lun = cbw->Lun;
+ common->tag = cbw->Tag;
+ return 0;
+}
+
+
+static int get_next_command(struct fsg_common *common)
+{
+ struct fsg_buffhd *bh;
+ int rc = 0;
+
+ /* Wait for the next buffer to become available */
+ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+
+ /* Queue a request to read a Bulk-only CBW */
+ set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
+ bh->outreq->short_not_ok = 1;
+ START_TRANSFER_OR(common, bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state)
+ /* Don't know what to do if common->fsg is NULL */
+ return -EIO;
+
+ /* 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(common);
+ if (rc)
+ return rc;
+ }
+ smp_rmb();
+ rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+ bh->state = BUF_STATE_EMPTY;
+
+ return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *d)
+{
+ int rc;
+
+ ep->driver_data = common;
+ rc = usb_ep_enable(ep, d);
+ if (rc)
+ ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
+ return rc;
+}
+
+static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
+ struct usb_request **preq)
+{
+ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (*preq)
+ return 0;
+ ERROR(common, "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_common *common, int altsetting)
+{
+ int rc = 0;
+ int i;
+ const struct usb_endpoint_descriptor *d;
+
+ if (common->running)
+ DBG(common, "reset interface\n");
+
+reset:
+ /* Deallocate the requests */
+ if (common->prev_fsg) {
+ struct fsg_dev *fsg = common->prev_fsg;
+
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &common->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;
+ }
+ }
+
+ /* 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;
+ }
+
+ common->prev_fsg = 0;
+ }
+
+ common->running = 0;
+ if (altsetting < 0 || rc != 0)
+ return rc;
+
+ DBG(common, "set interface %d\n", altsetting);
+
+ if (fsg_is_set(common)) {
+ struct fsg_dev *fsg = common->fsg;
+ common->prev_fsg = common->fsg;
+
+ /* Enable the endpoints */
+ d = fsg_ep_desc(common->gadget,
+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+ rc = enable_endpoint(common, fsg->bulk_in, d);
+ if (rc)
+ goto reset;
+ fsg->bulk_in_enabled = 1;
+
+ d = fsg_ep_desc(common->gadget,
+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+ rc = enable_endpoint(common, fsg->bulk_out, d);
+ if (rc)
+ goto reset;
+ fsg->bulk_out_enabled = 1;
+ common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+ /* Allocate the requests */
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ struct fsg_buffhd *bh = &common->buffhds[i];
+
+ rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
+ if (rc)
+ goto reset;
+ rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
+ if (rc)
+ 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;
+ }
+
+ common->running = 1;
+ for (i = 0; i < common->nluns; ++i)
+ common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+ return rc;
+ } else {
+ return -EIO;
+ }
+}
+
+
+/*
+ * 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_common *common, u8 new_config)
+{
+ int rc = 0;
+
+ /* Disable the single interface */
+ if (common->config != 0) {
+ DBG(common, "reset config\n");
+ common->config = 0;
+ rc = do_set_interface(common, -1);
+ }
+
+ /* Enable the interface */
+ if (new_config != 0) {
+ common->config = new_config;
+ rc = do_set_interface(common, 0);
+ if (rc != 0)
+ common->config = 0; /* Reset on errors */
+ }
+ return rc;
+}
+
+
+/****************************** ALT CONFIGS ******************************/
+
+
+static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+ fsg->common->prev_fsg = fsg->common->fsg;
+ fsg->common->fsg = fsg;
+ fsg->common->new_config = 1;
+ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ return 0;
+}
+
+static void fsg_disable(struct usb_function *f)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+ fsg->common->prev_fsg = fsg->common->fsg;
+ fsg->common->fsg = fsg;
+ fsg->common->new_config = 0;
+ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_common *common)
+{
+ siginfo_t info;
+ int sig;
+ int i;
+ 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, &current->blocked, &info);
+ if (!sig)
+ break;
+ if (sig != SIGUSR1) {
+ if (common->state < FSG_STATE_EXIT)
+ DBG(common, "Main thread exiting on signal\n");
+ raise_exception(common, FSG_STATE_EXIT);
+ }
+ }
+
+ /* Cancel all the pending transfers */
+ if (fsg_is_set(common)) {
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ bh = &common->buffhds[i];
+ if (bh->inreq_busy)
+ usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
+ if (bh->outreq_busy)
+ usb_ep_dequeue(common->fsg->bulk_out,
+ bh->outreq);
+ }
+
+ /* Wait until everything is idle */
+ for (;;) {
+ int num_active = 0;
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ bh = &common->buffhds[i];
+ num_active += bh->inreq_busy + bh->outreq_busy;
+ }
+ if (num_active == 0)
+ break;
+ if (sleep_thread(common))
+ return;
+ }
+
+ /* Clear out the controller's fifos */
+ if (common->fsg->bulk_in_enabled)
+ usb_ep_fifo_flush(common->fsg->bulk_in);
+ if (common->fsg->bulk_out_enabled)
+ usb_ep_fifo_flush(common->fsg->bulk_out);
+ }
+
+ /* Reset the I/O buffer states and pointers, the SCSI
+ * state, and the exception. Then invoke the handler. */
+ spin_lock_irq(&common->lock);
+
+ for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+ bh = &common->buffhds[i];
+ bh->state = BUF_STATE_EMPTY;
+ }
+ common->next_buffhd_to_fill = &common->buffhds[0];
+ common->next_buffhd_to_drain = &common->buffhds[0];
+ exception_req_tag = common->exception_req_tag;
+ new_config = common->new_config;
+ old_state = common->state;
+
+ if (old_state == FSG_STATE_ABORT_BULK_OUT)
+ common->state = FSG_STATE_STATUS_PHASE;
+ else {
+ for (i = 0; i < common->nluns; ++i) {
+ curlun = &common->luns[i];
+ curlun->prevent_medium_removal = 0;
+ curlun->sense_data = SS_NO_SENSE;
+ curlun->unit_attention_data = SS_NO_SENSE;
+ curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
+ }
+ common->state = FSG_STATE_IDLE;
+ }
+ spin_unlock_irq(&common->lock);
+
+ /* Carry out any extra actions required for the exception */
+ switch (old_state) {
+ case FSG_STATE_ABORT_BULK_OUT:
+ send_status(common);
+ spin_lock_irq(&common->lock);
+ if (common->state == FSG_STATE_STATUS_PHASE)
+ common->state = FSG_STATE_IDLE;
+ spin_unlock_irq(&common->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 (!fsg_is_set(common))
+ break;
+ if (test_and_clear_bit(IGNORE_BULK_OUT,
+ &common->fsg->atomic_bitflags))
+ usb_ep_clear_halt(common->fsg->bulk_in);
+
+ if (common->ep0_req_tag == exception_req_tag)
+ ep0_queue(common); /* Complete the status stage */
+
+ /* 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 < common->nluns; ++i) */
+ /* common->luns[i].unit_attention_data = */
+ /* SS_RESET_OCCURRED; */
+ break;
+
+ case FSG_STATE_CONFIG_CHANGE:
+ rc = do_set_config(common, new_config);
+ if (common->ep0_req_tag != exception_req_tag)
+ break;
+ if (rc != 0) { /* STALL on errors */
+ DBG(common, "ep0 set halt\n");
+ usb_ep_set_halt(common->ep0);
+ } else { /* Complete the status stage */
+ ep0_queue(common);
+ }
+ break;
+
+ case FSG_STATE_EXIT:
+ case FSG_STATE_TERMINATED:
+ do_set_config(common, 0); /* Free resources */
+ spin_lock_irq(&common->lock);
+ common->state = FSG_STATE_TERMINATED; /* Stop the thread */
+ spin_unlock_irq(&common->lock);
+ break;
+
+ case FSG_STATE_INTERFACE_CHANGE:
+ case FSG_STATE_DISCONNECT:
+ case FSG_STATE_COMMAND_PHASE:
+ case FSG_STATE_DATA_PHASE:
+ case FSG_STATE_STATUS_PHASE:
+ case FSG_STATE_IDLE:
+ break;
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_main_thread(void *common_)
+{
+ struct fsg_common *common = common_;
+
+ /* 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 (common->state != FSG_STATE_TERMINATED) {
+ if (exception_in_progress(common) || signal_pending(current)) {
+ handle_exception(common);
+ continue;
+ }
+
+ if (!common->running) {
+ sleep_thread(common);
+ continue;
+ }
+
+ if (get_next_command(common))
+ continue;
+
+ spin_lock_irq(&common->lock);
+ if (!exception_in_progress(common))
+ common->state = FSG_STATE_DATA_PHASE;
+ spin_unlock_irq(&common->lock);
+
+ if (do_scsi_command(common) || finish_reply(common))
+ continue;
+
+ spin_lock_irq(&common->lock);
+ if (!exception_in_progress(common))
+ common->state = FSG_STATE_STATUS_PHASE;
+ spin_unlock_irq(&common->lock);
+
+ if (send_status(common))
+ continue;
+
+ spin_lock_irq(&common->lock);
+ if (!exception_in_progress(common))
+ common->state = FSG_STATE_IDLE;
+ spin_unlock_irq(&common->lock);
+ }
+
+ spin_lock_irq(&common->lock);
+ common->thread_task = NULL;
+ spin_unlock_irq(&common->lock);
+
+ if (common->thread_exits)
+ common->thread_exits(common);
+
+ /* Let the unbind and cleanup routines know the thread has exited */
+ complete_and_exit(&common->thread_notifier, 0);
+}
+
+
+/*************************** DEVICE ATTRIBUTES ***************************/
+
+/* Write permission is checked per LUN in store_*() functions. */
+static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
+static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+
+
+/****************************** FSG COMMON ******************************/
+
+static void fsg_common_release(struct kref *ref);
+
+static void fsg_lun_release(struct device *dev)
+{
+ /* Nothing needs to be done */
+}
+
+static inline void fsg_common_get(struct fsg_common *common)
+{
+ kref_get(&common->ref);
+}
+
+static inline void fsg_common_put(struct fsg_common *common)
+{
+ kref_put(&common->ref, fsg_common_release);
+}
+
+
+static struct fsg_common *fsg_common_init(struct fsg_common *common,
+ struct usb_composite_dev *cdev,
+ struct fsg_config *cfg)
+{
+ struct usb_gadget *gadget = cdev->gadget;
+ struct fsg_buffhd *bh;
+ struct fsg_lun *curlun;
+ struct fsg_lun_config *lcfg;
+ int nluns, i, rc;
+ char *pathbuf;
+
+ /* Find out how many LUNs there should be */
+ nluns = cfg->nluns;
+ if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+ dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* 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->private_data = cfg->private_data;
+
+ common->gadget = gadget;
+ common->ep0 = gadget->ep0;
+ common->ep0req = cdev->req;
+
+ /* Maybe allocate device-global string IDs, and patch descriptors */
+ if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+ rc = usb_string_id(cdev);
+ if (rc < 0) {
+ kfree(common);
+ return ERR_PTR(rc);
+ }
+ fsg_strings[FSG_STRING_INTERFACE].id = rc;
+ fsg_intf_desc.iInterface = rc;
+ }
+
+ /* 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;
+
+ init_rwsem(&common->filesem);
+
+ for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
+ curlun->cdrom = !!lcfg->cdrom;
+ curlun->ro = lcfg->cdrom || lcfg->ro;
+ curlun->removable = lcfg->removable;
+ curlun->dev.release = fsg_lun_release;
+ curlun->dev.parent = &gadget->dev;
+ /* curlun->dev.driver = &fsg_driver.driver; XXX */
+ dev_set_drvdata(&curlun->dev, &common->filesem);
+ dev_set_name(&curlun->dev,
+ cfg->lun_name_format
+ ? cfg->lun_name_format
+ : "lun%d",
+ i);
+
+ 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 (lcfg->filename) {
+ rc = fsg_lun_open(curlun, lcfg->filename);
+ if (rc)
+ goto error_luns;
+ } else if (!curlun->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;
+
+
+ /* Prepare inquiryString */
+ if (cfg->release != 0xffff) {
+ i = cfg->release;
+ } else {
+ /* The sa1100 controller is not supported */
+ i = gadget_is_sa1100(gadget)
+ ? -1
+ : usb_gadget_controller_number(gadget);
+ if (i >= 0) {
+ i = 0x0300 + i;
+ } else {
+ WARNING(common, "controller '%s' not recognized\n",
+ gadget->name);
+ i = 0x0399;
+ }
+ }
+#define OR(x, y) ((x) ? (x) : (y))
+ snprintf(common->inquiry_string, sizeof common->inquiry_string,
+ "%-8s%-16s%04x",
+ OR(cfg->vendor_name, "Linux "),
+ /* Assume product name dependent on the first LUN */
+ OR(cfg->product_name, common->luns->cdrom
+ ? "File-Stor Gadget"
+ : "File-CD Gadget "),
+ i);
+
+
+ /* Some peripheral controllers are known not to be able to
+ * halt bulk endpoints correctly. If one of them is present,
+ * disable stalls.
+ */
+ common->can_stall = cfg->can_stall &&
+ !(gadget_is_sh(common->gadget) ||
+ gadget_is_at91(common->gadget));
+
+
+ spin_lock_init(&common->lock);
+ kref_init(&common->ref);
+
+
+ /* Tell the thread to start working */
+ common->thread_exits = cfg->thread_exits;
+ common->thread_task =
+ kthread_create(fsg_main_thread, common,
+ OR(cfg->thread_name, "file-storage"));
+ if (IS_ERR(common->thread_task)) {
+ rc = PTR_ERR(common->thread_task);
+ goto error_release;
+ }
+ init_completion(&common->thread_notifier);
+#undef OR
+
+
+ /* Information */
+ INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+ INFO(common, "Number of LUNs=%d\n", common->nluns);
+
+ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+ for (i = 0, nluns = common->nluns, curlun = common->luns;
+ i < nluns;
+ ++curlun, ++i) {
+ char *p = "(no medium)";
+ if (fsg_lun_is_open(curlun)) {
+ p = "(error)";
+ if (pathbuf) {
+ p = d_path(&curlun->filp->f_path,
+ pathbuf, PATH_MAX);
+ if (IS_ERR(p))
+ p = "(error)";
+ }
+ }
+ LINFO(curlun, "LUN: %s%s%sfile: %s\n",
+ curlun->removable ? "removable " : "",
+ curlun->ro ? "read only " : "",
+ curlun->cdrom ? "CD-ROM " : "",
+ p);
+ }
+ kfree(pathbuf);
+
+ DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+
+ wake_up_process(common->thread_task);
+
+ return common;
+
+
+error_luns:
+ common->nluns = i + 1;
+error_release:
+ common->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ /* Call fsg_common_release() directly, ref might be not
+ * initialised */
+ fsg_common_release(&common->ref);
+ complete(&common->thread_notifier);
+ 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;
+
+ /* If the thread isn't already dead, tell it to exit now */
+ if (common->state != FSG_STATE_TERMINATED) {
+ raise_exception(common, FSG_STATE_EXIT);
+ wait_for_completion(&common->thread_notifier);
+
+ /* The cleanup routine waits for this completion also */
+ complete(&common->thread_notifier);
+ }
+
+ /* 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 fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+
+ DBG(fsg, "unbind\n");
+ fsg_common_put(fsg->common);
+ kfree(fsg);
+}
+
+
+static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ int rc;
+ int i;
+ struct usb_ep *ep;
+
+ fsg->gadget = gadget;
+
+ /* New interface */
+ i = usb_interface_id(c, f);
+ if (i < 0)
+ return i;
+ fsg_intf_desc.bInterfaceNumber = i;
+ fsg->interface_number = i;
+
+ /* Find all the endpoints we will use */
+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+ ep->driver_data = fsg->common; /* 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->common; /* claim the endpoint */
+ fsg->bulk_out = ep;
+
+ if (gadget_is_dualspeed(gadget)) {
+ /* 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;
+ f->hs_descriptors = fsg_hs_function;
+ }
+
+ return 0;
+
+autoconf_fail:
+ ERROR(fsg, "unable to autoconfigure all endpoints\n");
+ rc = -ENOTSUPP;
+ fsg_unbind(c, f);
+ return rc;
+}
+
+
+/****************************** ADD FUNCTION ******************************/
+
+static struct usb_gadget_strings *fsg_strings_array[] = {
+ &fsg_stringtab,
+ NULL,
+};
+
+static int fsg_add(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct fsg_common *common)
+{
+ struct fsg_dev *fsg;
+ int rc;
+
+ fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+ if (unlikely(!fsg))
+ return -ENOMEM;
+
+ fsg->function.name = FSG_DRIVER_DESC;
+ fsg->function.strings = fsg_strings_array;
+ fsg->function.descriptors = fsg_fs_function;
+ fsg->function.bind = fsg_bind;
+ fsg->function.unbind = fsg_unbind;
+ fsg->function.setup = fsg_setup;
+ fsg->function.set_alt = fsg_set_alt;
+ fsg->function.disable = fsg_disable;
+
+ fsg->common = common;
+ /* Our caller holds a reference to common structure so we
+ * don't have to be worry about it being freed until we return
+ * from this function. So instead of incrementing counter now
+ * and decrement in error recovery we increment it only when
+ * call to usb_add_function() was successful. */
+
+ rc = usb_add_function(c, &fsg->function);
+
+ if (likely(rc == 0))
+ fsg_common_get(fsg->common);
+ else
+ kfree(fsg);
+
+ return rc;
+}
+
+
+
+/************************* Module parameters *************************/
+
+
+struct fsg_module_parameters {
+ char *file[FSG_MAX_LUNS];
+ int ro[FSG_MAX_LUNS];
+ int removable[FSG_MAX_LUNS];
+ int cdrom[FSG_MAX_LUNS];
+
+ unsigned int file_count, ro_count, removable_count, cdrom_count;
+ unsigned int luns; /* nluns */
+ int stall; /* can_stall */
+};
+
+
+#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
+ module_param_array_named(prefix ## name, params.name, type, \
+ &prefix ## params.name ## _count, \
+ S_IRUGO); \
+ MODULE_PARM_DESC(prefix ## name, desc)
+
+#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
+ module_param_named(prefix ## name, params.name, type, \
+ S_IRUGO); \
+ MODULE_PARM_DESC(prefix ## name, desc)
+
+#define FSG_MODULE_PARAMETERS(prefix, params) \
+ _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \
+ "names of backing files or devices"); \
+ _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \
+ "true to force read-only"); \
+ _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \
+ "true to simulate removable media"); \
+ _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
+ "true to simulate CD-ROM instead of disk"); \
+ _FSG_MODULE_PARAM(prefix, params, luns, uint, \
+ "number of LUNs"); \
+ _FSG_MODULE_PARAM(prefix, params, stall, bool, \
+ "false to prevent bulk stalls")
+
+
+static void
+fsg_config_from_params(struct fsg_config *cfg,
+ const struct fsg_module_parameters *params)
+{
+ struct fsg_lun_config *lun;
+ unsigned i;
+
+ /* Configure LUNs */
+ cfg->nluns =
+ min(params->luns ?: (params->file_count ?: 1u),
+ (unsigned)FSG_MAX_LUNS);
+ for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
+ lun->ro = !!params->ro[i];
+ lun->cdrom = !!params->cdrom[i];
+ lun->removable = /* Removable by default */
+ params->removable_count <= i || params->removable[i];
+ lun->filename =
+ params->file_count > i && params->file[i][0]
+ ? params->file[i]
+ : 0;
+ }
+
+ /* Let MSF use defaults */
+ cfg->lun_name_format = 0;
+ cfg->thread_name = 0;
+ cfg->vendor_name = 0;
+ cfg->product_name = 0;
+ cfg->release = 0xffff;
+
+ cfg->thread_exits = 0;
+ cfg->private_data = 0;
+
+ /* Finalise */
+ cfg->can_stall = params->stall;
+}
+
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+ struct usb_composite_dev *cdev,
+ const struct fsg_module_parameters *params)
+ __attribute__((unused));
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+ struct usb_composite_dev *cdev,
+ const struct fsg_module_parameters *params)
+{
+ struct fsg_config cfg;
+ fsg_config_from_params(&cfg, params);
+ return fsg_common_init(common, cdev, &cfg);
+}
+
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index c9966cc07d3a..95dae4c1ea40 100644
--- 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_descriptor call_mgmt_descriptor __initdata = {
.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 rndis_data_intf __initdata = {
/* .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_out_desc __initdata = {
};
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_out_desc __initdata = {
};
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_hs_function[] __initdata = {
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, struct usb_function *f)
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_configuration *c, u8 ethaddr[ETH_ALEN])
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/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 1e6aa504d58a..29dfb0277ffb 100644
--- 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,21 +272,20 @@
#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";
+
+
+#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 DRIVER_VENDOR_ID 0x0525 // NetChip
-#define DRIVER_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
@@ -298,54 +295,12 @@ 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 */
-#define 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;
@@ -372,8 +327,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,
};
@@ -425,125 +380,6 @@ MODULE_PARM_DESC(buflen, "I/O buffer size");
#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 +402,8 @@ 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;
-};
-
-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 */
@@ -662,7 +425,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;
@@ -687,7 +450,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;
@@ -712,8 +475,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 *);
@@ -739,49 +502,9 @@ static void set_bulk_out_req_length(struct fsg_dev *fsg,
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 +522,11 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/*-------------------------------------------------------------------------*/
-/* 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
@@ -832,13 +540,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,
};
@@ -850,86 +558,12 @@ 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,
};
-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 +575,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,
-};
/*
@@ -1032,10 +594,9 @@ static int populate_config_buf(struct usb_gadget *gadget,
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;
- else
- function = fs_function;
+ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
+ ? (const struct usb_descriptor_header **)fsg_hs_function
+ : (const struct usb_descriptor_header **)fsg_fs_function;
/* for now, don't advertise srp-only devices */
if (!gadget_is_otg(gadget))
@@ -1386,7 +947,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;
}
@@ -1551,7 +1112,7 @@ static int sleep_thread(struct fsg_dev *fsg)
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;
@@ -1677,7 +1238,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;
@@ -1713,7 +1274,7 @@ static int do_write(struct fsg_dev *fsg)
}
if (fsg->cmnd[1] & 0x08) { // FUA
spin_lock(&curlun->filp->f_lock);
- curlun->filp->f_flags |= O_SYNC;
+ curlun->filp->f_flags |= O_DSYNC;
spin_unlock(&curlun->filp->f_lock);
}
}
@@ -1864,33 +1425,14 @@ 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;
+ 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;
@@ -1899,7 +1441,7 @@ static int do_synchronize_cache(struct fsg_dev *fsg)
/*-------------------------------------------------------------------------*/
-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;
@@ -1911,7 +1453,7 @@ static void invalidate_sub(struct lun *curlun)
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;
@@ -1944,7 +1486,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;
@@ -2041,7 +1583,7 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
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;
@@ -2095,7 +1637,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
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;
@@ -2113,27 +1655,9 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
-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;
+ 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;
@@ -2156,7 +1680,7 @@ static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
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;
@@ -2184,7 +1708,7 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
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;
@@ -2265,7 +1789,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
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) {
@@ -2295,7 +1819,7 @@ static int do_start_stop(struct fsg_dev *fsg)
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);
}
@@ -2303,7 +1827,7 @@ static int do_start_stop(struct fsg_dev *fsg)
/* 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;
}
@@ -2315,7 +1839,7 @@ static int do_start_stop(struct fsg_dev *fsg)
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) {
@@ -2330,7 +1854,7 @@ static int do_prevent_allow(struct fsg_dev *fsg)
}
if (curlun->prevent_medium_removal && !prevent)
- fsync_sub(curlun);
+ fsg_lun_fsync_sub(curlun);
curlun->prevent_medium_removal = prevent;
return 0;
}
@@ -2339,7 +1863,7 @@ static int do_prevent_allow(struct fsg_dev *fsg)
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;
@@ -2356,7 +1880,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
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;
@@ -2599,7 +2123,7 @@ static int finish_reply(struct fsg_dev *fsg)
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;
@@ -2691,7 +2215,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
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. */
@@ -2820,7 +2344,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
/* 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;
}
@@ -3075,8 +2599,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
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))
@@ -3105,7 +2629,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
/* 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",
@@ -3238,7 +2762,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
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) {
@@ -3276,12 +2800,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;
@@ -3289,14 +2815,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)
@@ -3372,7 +2899,7 @@ static void handle_exception(struct fsg_dev *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;
@@ -3392,7 +2919,7 @@ static void handle_exception(struct fsg_dev *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);
@@ -3403,7 +2930,7 @@ static void handle_exception(struct fsg_dev *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;
}
@@ -3425,7 +2952,7 @@ static void handle_exception(struct fsg_dev *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;
}
@@ -3506,7 +3033,8 @@ static void handle_exception(struct fsg_dev *fsg)
break;
case FSG_STATE_DISCONNECT:
- fsync_all(fsg);
+ for (i = 0; i < fsg->nluns; ++i)
+ fsg_lun_fsync_sub(fsg->luns + i);
do_set_config(fsg, 0); // Unconfigured state
break;
@@ -3595,201 +3123,10 @@ 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);
-
- return sprintf(buf, "%d\n", curlun->ro);
-}
-
-static ssize_t show_file(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct lun *curlun = dev_to_lun(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
- 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 lun *curlun = dev_to_lun(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 (backing_file_is_open(curlun)) {
- LDBG(curlun, "read-only status change prevented\n");
- rc = -EBUSY;
- } else {
- curlun->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 lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = dev_get_drvdata(dev);
- int rc = 0;
-
- if (curlun->prevent_medium_removal && backing_file_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 (backing_file_is_open(curlun)) {
- close_backing_file(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
-
- /* Load new medium */
- if (count > 0 && buf[0]) {
- rc = open_backing_file(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);
/*-------------------------------------------------------------------------*/
@@ -3804,7 +3141,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);
}
@@ -3813,7 +3152,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
{
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");
@@ -3825,7 +3164,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
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;
}
@@ -3841,7 +3180,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
}
/* 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 */
@@ -3948,7 +3287,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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;
@@ -3963,10 +3302,10 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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;
}
}
@@ -3974,7 +3313,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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;
@@ -3982,7 +3321,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* 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;
@@ -3991,13 +3330,14 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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;
- 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);
@@ -4016,7 +3356,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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) {
@@ -4028,20 +3368,20 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* 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
@@ -4055,28 +3395,28 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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;
@@ -4090,7 +3430,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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
@@ -4101,23 +3441,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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,
@@ -4133,7 +3474,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
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,
@@ -4203,7 +3544,7 @@ static struct usb_gadget_driver fsg_driver = {
#else
.speed = USB_SPEED_FULL,
#endif
- .function = (char *) longname,
+ .function = (char *) fsg_string_product,
.bind = fsg_bind,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,
@@ -4212,7 +3553,7 @@ static struct usb_gadget_driver fsg_driver = {
.resume = fsg_resume,
.driver = {
- .name = (char *) shortname,
+ .name = DRIVER_NAME,
.owner = THIS_MODULE,
// .release = ...
// .suspend = ...
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
new file mode 100644
index 000000000000..19619fbf20ac
--- /dev/null
+++ b/drivers/usb/gadget/mass_storage.c
@@ -0,0 +1,240 @@
+/*
+ * mass_storage.c -- Mass Storage USB Gadget
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * All rights reserved.
+ *
+ * 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
+ */
+
+
+/*
+ * The Mass 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.
+ *
+ * Since this file serves only administrative purposes and all the
+ * business logic is implemented in f_mass_storage.* file. Read
+ * comments in this file for more detailed description.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/usb/ch9.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_DESC "Mass Storage Gadget"
+#define DRIVER_VERSION "2009/09/11"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * 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 "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "f_mass_storage.c"
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor msg_device_desc = {
+ .bLength = sizeof msg_device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+
+ /* Vendor and product id can be overridden by module parameters. */
+ .idVendor = cpu_to_le16(FSG_VENDOR_ID),
+ .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
+ /* .bcdDevice = f(hardware) */
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ /* NO SERIAL NUMBER */
+ .bNumConfigurations = 1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+ /* REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ...
+ */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+#define STRING_CONFIGURATION_IDX 2
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer,
+ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ [STRING_CONFIGURATION_IDX].s = "Self Powered",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters mod_data = {
+ .stall = 1
+};
+FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
+
+static unsigned long msg_registered = 0;
+static void msg_cleanup(void);
+
+static int __init msg_do_config(struct usb_configuration *c)
+{
+ struct fsg_common *common;
+ struct fsg_config config;
+ int ret;
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ fsg_config_from_params(&config, &mod_data);
+ config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
+ common = fsg_common_init(0, c->cdev, &config);
+ if (IS_ERR(common))
+ return PTR_ERR(common);
+
+ ret = fsg_add(c->cdev, c, common);
+ fsg_common_put(common);
+ return ret;
+}
+
+static struct usb_configuration msg_config_driver = {
+ .label = "Linux File-Backed Storage",
+ .bind = msg_do_config,
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+
+
+/****************************** Gadget Bind ******************************/
+
+
+static int __init msg_bind(struct usb_composite_dev *cdev)
+{
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+
+ /* Allocate string descriptor numbers ... note that string
+ * contents can be overridden by the composite_dev glue.
+ */
+
+ /* device descriptor strings: manufacturer, product */
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+ msg_device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+ msg_device_desc.iProduct = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ return status;
+ strings_dev[STRING_CONFIGURATION_IDX].id = status;
+ msg_config_driver.iConfiguration = status;
+
+ /* register our second configuration */
+ status = usb_add_config(cdev, &msg_config_driver);
+ if (status < 0)
+ return status;
+
+ dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+ set_bit(0, &msg_registered);
+ return 0;
+}
+
+
+/****************************** Some noise ******************************/
+
+
+static struct usb_composite_driver msg_driver = {
+ .name = "g_mass_storage",
+ .dev = &msg_device_desc,
+ .strings = dev_strings,
+ .bind = msg_bind,
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+static int __init msg_init(void)
+{
+ return usb_composite_register(&msg_driver);
+}
+module_init(msg_init);
+
+static void msg_cleanup(void)
+{
+ if (test_and_clear_bit(0, &msg_registered))
+ usb_composite_unregister(&msg_driver);
+}
+module_exit(msg_cleanup);
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
new file mode 100644
index 000000000000..429560100b10
--- /dev/null
+++ b/drivers/usb/gadget/multi.c
@@ -0,0 +1,358 @@
+/*
+ * multi.c -- Multifunction Composite driver
+ *
+ * Copyright (C) 2008 David Brownell
+ * 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
+ * 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
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+
+
+#if defined USB_ETH_RNDIS
+# undef USB_ETH_RNDIS
+#endif
+#ifdef CONFIG_USB_ETH_RNDIS
+# define USB_ETH_RNDIS y
+#endif
+
+
+#define DRIVER_DESC "Multifunction Composite Gadget"
+#define DRIVER_VERSION "2009/07/21"
+
+/*-------------------------------------------------------------------------*/
+
+#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
+#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * 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 "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "u_serial.c"
+#include "f_acm.c"
+
+#include "f_ecm.c"
+#include "f_subset.c"
+#ifdef USB_ETH_RNDIS
+# include "f_rndis.c"
+# include "rndis.c"
+#endif
+#include "u_ether.c"
+
+#undef DBG /* u_ether.c has broken idea about macros */
+#undef VDBG /* so clean up after it */
+#undef ERROR
+#undef INFO
+#include "f_mass_storage.c"
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16(0x0200),
+
+ /* .bDeviceClass = USB_CLASS_COMM, */
+ /* .bDeviceSubClass = 0, */
+ /* .bDeviceProtocol = 0, */
+ .bDeviceClass = 0xEF,
+ .bDeviceSubClass = 2,
+ .bDeviceProtocol = 1,
+ /* .bMaxPacketSize0 = f(hardware) */
+
+ /* Vendor and product id can be overridden by module parameters. */
+ .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
+ .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
+ /* .bcdDevice = f(hardware) */
+ /* .iManufacturer = DYNAMIC */
+ /* .iProduct = DYNAMIC */
+ /* NO SERIAL NUMBER */
+ .bNumConfigurations = 1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+ /* REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ...
+ */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer,
+ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+static u8 hostaddr[ETH_ALEN];
+
+
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters mod_data = {
+ .stall = 1
+};
+FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
+
+static struct fsg_common *fsg_common;
+
+
+#ifdef USB_ETH_RNDIS
+
+static int __init rndis_do_config(struct usb_configuration *c)
+{
+ int ret;
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ ret = rndis_bind_config(c, hostaddr);
+ if (ret < 0)
+ return ret;
+
+ ret = acm_bind_config(c, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = fsg_add(c->cdev, c, fsg_common);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct usb_configuration rndis_config_driver = {
+ .label = "Multifunction Composite (RNDIS + MS + ACM)",
+ .bind = rndis_do_config,
+ .bConfigurationValue = 2,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_CDC
+
+static int __init cdc_do_config(struct usb_configuration *c)
+{
+ int ret;
+
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ ret = ecm_bind_config(c, hostaddr);
+ if (ret < 0)
+ return ret;
+
+ ret = acm_bind_config(c, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = fsg_add(c->cdev, c, fsg_common);
+ if (ret < 0)
+ return ret;
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct usb_configuration cdc_config_driver = {
+ .label = "Multifunction Composite (CDC + MS + ACM)",
+ .bind = cdc_do_config,
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};
+
+#endif
+
+
+
+/****************************** Gadget Bind ******************************/
+
+
+static int __init multi_bind(struct usb_composite_dev *cdev)
+{
+ struct usb_gadget *gadget = cdev->gadget;
+ int status, gcnum;
+
+ if (!can_support_ecm(cdev->gadget)) {
+ dev_err(&gadget->dev, "controller '%s' not usable\n",
+ gadget->name);
+ return -EINVAL;
+ }
+
+ /* set up network link layer */
+ status = gether_setup(cdev->gadget, hostaddr);
+ if (status < 0)
+ return status;
+
+ /* set up serial link layer */
+ status = gserial_setup(cdev->gadget, 1);
+ if (status < 0)
+ goto fail0;
+
+ /* set up mass storage function */
+ fsg_common = fsg_common_from_params(0, cdev, &mod_data);
+ if (IS_ERR(fsg_common)) {
+ status = PTR_ERR(fsg_common);
+ goto fail1;
+ }
+
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+ else {
+ /* We assume that can_support_ecm() tells the truth;
+ * but if the controller isn't recognized at all then
+ * that assumption is a bit more likely to be wrong.
+ */
+ WARNING(cdev, "controller '%s' not recognized\n",
+ gadget->name);
+ device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
+ }
+
+
+ /* Allocate string descriptor numbers ... note that string
+ * contents can be overridden by the composite_dev glue.
+ */
+
+ /* device descriptor strings: manufacturer, product */
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail2;
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+ device_desc.iManufacturer = status;
+
+ status = usb_string_id(cdev);
+ if (status < 0)
+ goto fail2;
+ strings_dev[STRING_PRODUCT_IDX].id = status;
+ device_desc.iProduct = status;
+
+#ifdef USB_ETH_RNDIS
+ /* register our first configuration */
+ status = usb_add_config(cdev, &rndis_config_driver);
+ if (status < 0)
+ goto fail2;
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_CDC
+ /* register our second configuration */
+ status = usb_add_config(cdev, &cdc_config_driver);
+ if (status < 0)
+ goto fail2;
+#endif
+
+ dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+ fsg_common_put(fsg_common);
+ return 0;
+
+fail2:
+ fsg_common_put(fsg_common);
+fail1:
+ gserial_cleanup();
+fail0:
+ gether_cleanup();
+ return status;
+}
+
+static int __exit multi_unbind(struct usb_composite_dev *cdev)
+{
+ gserial_cleanup();
+ gether_cleanup();
+ return 0;
+}
+
+
+/****************************** Some noise ******************************/
+
+
+static struct usb_composite_driver multi_driver = {
+ .name = "g_multi",
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .bind = multi_bind,
+ .unbind = __exit_p(multi_unbind),
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+static int __init g_multi_init(void)
+{
+ return usb_composite_register(&multi_driver);
+}
+module_init(g_multi_init);
+
+static void __exit g_multi_cleanup(void)
+{
+ usb_composite_unregister(&multi_driver);
+}
+module_exit(g_multi_cleanup);
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 1937d8c7b433..adda1208a1ec 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1524,7 +1524,7 @@ static int pxa_udc_get_frame(struct usb_gadget *_gadget)
* pxa_udc_wakeup - Force udc device out of suspend
* @_gadget: usb gadget
*
- * Returns 0 if succesfull, error code otherwise
+ * Returns 0 if successfull, error code otherwise
*/
static int pxa_udc_wakeup(struct usb_gadget *_gadget)
{
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
new file mode 100644
index 000000000000..868d8ee86756
--- /dev/null
+++ b/drivers/usb/gadget/storage_common.c
@@ -0,0 +1,778 @@
+/*
+ * 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)
+ *
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 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>
+
+
+/* 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 */
+
+
+/*-------------------------------------------------------------------------*/
+
+
+#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)
+
+/* Keep those macros in sync with thos in
+ * include/linux/ubs/composite.h or else GCC will complain. If they
+ * are identical (the same names of arguments, white spaces in the
+ * same places) GCC will allow redefinition otherwise (even if some
+ * white space is removed or added) warning will be issued. No
+ * checking if those symbols is defined is performed because warning
+ * is desired when those macros were defined by someone else to mean
+ * something else. */
+#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 fsg_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
+
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE 16
+
+/* 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 fsg_lun {
+ struct file *filp;
+ 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;
+
+ u32 sense_data;
+ u32 sense_data_info;
+ u32 unit_attention_data;
+
+ struct device dev;
+};
+
+#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
+
+static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+{
+ return container_of(dev, struct fsg_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 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,
+ BUF_STATE_BUSY
+};
+
+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;
+
+ /* 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 {
+ /* This one isn't used anywhere */
+ FSG_STATE_COMMAND_PHASE = -10,
+ 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);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+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,
+ .bDescriptorType = USB_DT_OTG,
+
+ .bmAttributes = USB_OTG_SRP,
+};
+#endif
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor
+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 = FSG_STRING_INTERFACE,
+};
+
+/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
+ * and interrupt-in. */
+
+static struct usb_endpoint_descriptor
+fsg_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
+fsg_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 */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_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 */
+};
+
+#ifndef FSG_NO_OTG
+# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
+#else
+# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
+#endif
+
+#endif
+
+static 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,
+};
+
+
+/*
+ * 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
+fsg_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
+fsg_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 */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_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 */
+};
+
+#ifndef FSG_NO_OTG
+# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
+#else
+# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
+#endif
+
+#endif
+
+static 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,
+};
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+static struct usb_endpoint_descriptor *
+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)
+ return hs;
+ return fs;
+}
+
+
+/* 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},
+ {}
+};
+
+static struct usb_gadget_strings fsg_stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = fsg_strings,
+};
+
+
+ /*-------------------------------------------------------------------------*/
+
+/* If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing. */
+
+static int fsg_lun_open(struct fsg_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->initially_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 (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) {
+ 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 fsg_lun_close(struct fsg_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 fsg_lun_fsync_sub(struct fsg_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);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+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/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 91b39ffdf6ea..fd55f450bc0e 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -112,7 +112,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int eem_bind_config(struct usb_configuration *c);
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef USB_ETH_RNDIS
int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);