diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h index 2bd26451..bfd174f7 100644 --- a/arch/arm/mach-msm/include/mach/msm_hsusb.h +++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h @@ -47,10 +47,6 @@ struct msm_hsusb_platform_data { /* 1 : uart, 0 : usb */ void (*usb_uart_switch)(int); void (*config_usb_id_gpios)(bool enable); - void (*usb_hub_enable)(bool); - void (*serial_debug_gpios)(int); - int (*china_ac_detect)(void); - void (*disable_usb_charger)(void); /* val, reg pairs terminated by -1 */ int *phy_init_seq; @@ -80,11 +76,8 @@ struct msm_hsusb_platform_data { #endif char *serial_number; int usb_id_pin_gpio; - int dock_pin_gpio; - int id_pin_irq; bool enable_car_kit_detect; __u8 accessory_detect; - bool dock_detect; }; int usb_get_connect_type(void); diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 908b8a78..f2a3f3ee 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -53,6 +53,59 @@ MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; +enum { + USB_FUNCTION_UMS = 0, + USB_FUNCTION_ADB = 1, + USB_FUNCTION_RNDIS, + USB_FUNCTION_DIAG, + USB_FUNCTION_SERIAL, + USB_FUNCTION_PROJECTOR, + USB_FUNCTION_FSYNC, + USB_FUNCTION_MTP, + USB_FUNCTION_MODEM, +}; + +#ifdef CONFIG_USB_ANDROID_MTP +#define MS_VENDOR_CODE 0x0b +#define FEATURE_DESC_SIZE 64 +#define PID_MTP 0x0c93 +#define PID_MTP_ADB 0x0ca8 +struct ms_comp_feature_descriptor { + __le32 dwLength; + __le16 bcdVersion; + __le16 wIndex; + __u8 bCount; + __u8 resv1[7]; + /* for MTP */ + __u8 bFirstInterfaceNumber; + __u8 resv2; + __u8 compatibleID[8]; + __u8 subCompatibleID[8]; + __u8 resv3[6]; + /* for adb */ + __u8 bFirstInterfaceNumber2; + __u8 resv4; + __u8 compatibleID2[8]; + __u8 subCompatibleID2[8]; + __u8 resv5[6]; +} __attribute__ ((packed)); + + +static struct ms_comp_feature_descriptor ms_comp_desc = { + .dwLength = __constant_cpu_to_le32(FEATURE_DESC_SIZE), + .bcdVersion = __constant_cpu_to_le16(0x0100), + .wIndex = __constant_cpu_to_le16(0x0004), + .bCount = 0x02, + /* for MTP */ + .bFirstInterfaceNumber = 0, + .resv2 = 1, + .compatibleID = "MTP", + /* for adb */ + .bFirstInterfaceNumber2 = 1, + .resv4 = 1, +}; +#endif + /* Default vendor and product IDs, overridden by platform data */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 @@ -109,6 +162,17 @@ static struct usb_device_descriptor device_desc = { static struct list_head _functions = LIST_HEAD_INIT(_functions); static int _registered_function_count = 0; +static int get_product_id(struct android_dev *dev); + +void android_usb_set_connected(int connected) +{ + if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) { + if (connected) + usb_gadget_connect(_android_dev->cdev->gadget); + else + usb_gadget_disconnect(_android_dev->cdev->gadget); + } +} static struct android_usb_function *get_function(const char *name) { @@ -124,6 +188,7 @@ static void bind_functions(struct android_dev *dev) { struct android_usb_function *f; char **functions = dev->functions; + int product_id; int i; for (i = 0; i < dev->num_functions; i++) { @@ -134,9 +199,14 @@ static void bind_functions(struct android_dev *dev) else printk(KERN_ERR "function %s not found in bind_functions\n", name); } + product_id = get_product_id(dev); + printk(KERN_INFO "usb: product_id=0x%x\n", product_id); + device_desc.idProduct = __constant_cpu_to_le16(product_id); + if (dev->cdev) + dev->cdev->desc.idProduct = device_desc.idProduct; } -static int android_bind_config(struct usb_configuration *c) +static int __init android_bind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; @@ -167,7 +237,46 @@ static int android_setup_config(struct usb_configuration *c, { int i; int ret = -EOPNOTSUPP; +#ifdef CONFIG_USB_ANDROID_MTP + struct usb_composite_dev *cdev = c->cdev; + struct usb_request *req = cdev->req; + struct android_dev *dev = _android_dev; + int product_id; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_length = le16_to_cpu(ctrl->wLength); + /* vendor request to GET OS feature descriptor */ + if (((ctrl->bRequestType << 8) | ctrl->bRequest) == + (((USB_DIR_IN | USB_TYPE_VENDOR) << 8) | MS_VENDOR_CODE)) { + printk(KERN_DEBUG "usb: get OS feature descriptor\n"); + if (w_index != 0x0004 || w_length > FEATURE_DESC_SIZE) + return ret; + + product_id = get_product_id(dev); + printk(KERN_INFO "mtp: product_id = 0x%x\n", product_id); + if (product_id == PID_MTP) { + ms_comp_desc.bCount = 1; + ms_comp_desc.dwLength = + __constant_cpu_to_le32(40); + ret = w_length; + } else if (product_id == PID_MTP_ADB) { + ms_comp_desc.bCount = 2; + ms_comp_desc.dwLength = + __constant_cpu_to_le32(64); + ret = w_length; + } + /* respond with data transfer or status phase? */ + if (ret >= 0) { + memcpy(req->buf, (char *)&ms_comp_desc, w_length); + req->zero = 0; + req->length = ret; + ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (ret < 0) + ERROR(cdev, "get feature desc err %d\n", ret); + return ret; + } + } +#endif for (i = 0; i < android_config_driver.next_interface_id; i++) { if (android_config_driver.interface[i]->setup) { ret = android_config_driver.interface[i]->setup( @@ -198,7 +307,7 @@ static int product_matches_functions(struct android_usb_product *p) { struct usb_function *f; list_for_each_entry(f, &android_config_driver.functions, list) { - if (product_has_function(p, f) == !!f->disabled) + if (product_has_function(p, f) == !!f->hidden) return 0; } return 1; @@ -220,7 +329,7 @@ static int get_product_id(struct android_dev *dev) return dev->product_id; } -static int android_bind(struct usb_composite_dev *cdev) +static int __init android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; @@ -249,6 +358,9 @@ static int android_bind(struct usb_composite_dev *cdev) strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; + if (gadget->ops->wakeup) + android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + /* register our configuration */ ret = usb_add_config(cdev, &android_config_driver); if (ret) { @@ -300,9 +412,84 @@ void android_register_function(struct android_usb_function *f) /* bind our functions if they have all registered * and the main driver has bound. */ - if (dev && dev->config && _registered_function_count == dev->num_functions) + if (dev->config && _registered_function_count == dev->num_functions) bind_functions(dev); } +int android_show_function(char *buf) +{ + unsigned length = 0; + struct usb_function *f; + list_for_each_entry(f, &android_config_driver.functions, list) { + length += sprintf(buf + length, "%s:%s\n", f->name, + (f->hidden)?"disable":"enable"); + } + return length; +} + +int android_switch_function(unsigned func) +{ + struct usb_function *f; + struct android_dev *dev = _android_dev; + int product_id; + printk(KERN_INFO "%s: %u\n", __func__, func); + list_for_each_entry(f, &android_config_driver.functions, list) { + if ((func & (1 << USB_FUNCTION_UMS)) && + !strcmp(f->name, "usb_mass_storage")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_ADB)) && + !strcmp(f->name, "adb")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_RNDIS)) && + !strcmp(f->name, "rndis")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_DIAG)) && + !strcmp(f->name, "diag")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_MODEM)) && + !strcmp(f->name, "modem")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_SERIAL)) && + !strcmp(f->name, "serial")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_MTP)) && + !strcmp(f->name, "mtp")) + f->hidden = 0; + /* also enable adb with MTP function */ + else if ((func & (1 << USB_FUNCTION_MTP)) && + !strcmp(f->name, "adb")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_PROJECTOR)) && + !strcmp(f->name, "projector")) + f->hidden = 0; + else + f->hidden = 1; + } + product_id = get_product_id(dev); + device_desc.idProduct = __constant_cpu_to_le16(product_id); + if (dev->cdev) + dev->cdev->desc.idProduct = device_desc.idProduct; + + /* We need to specify the COMM class in the device descriptor + * if we are using RNDIS. + */ + if (func & (1 << USB_FUNCTION_RNDIS)) + dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; + else + dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; + +#ifdef CONFIG_USB_GADGET_MSM_72K + msm_hsusb_request_reset(); +#else + /* force reenumeration */ + if (dev->cdev && dev->cdev->gadget && + dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) { + usb_gadget_disconnect(dev->cdev->gadget); + msleep(10); + usb_gadget_connect(dev->cdev->gadget); + } +#endif + return 0; +} void android_enable_function(struct usb_function *f, int enable) { @@ -310,12 +497,12 @@ void android_enable_function(struct usb_function *f, int enable) int disable = !enable; int product_id; - if (!!f->disabled != disable) { - usb_function_set_enabled(f, !disable); + if (!!f->hidden != disable) { + f->hidden = disable; #ifdef CONFIG_USB_ANDROID_RNDIS if (!strcmp(f->name, "rndis")) { - struct usb_function *func; + struct usb_function *func; /* We need to specify the COMM class in the device descriptor * if we are using RNDIS. @@ -330,12 +517,12 @@ void android_enable_function(struct usb_function *f, int enable) dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; /* Windows does not support other interfaces when RNDIS is enabled, - * so we disable UMS and MTP when RNDIS is on. + * so we disable UMS when RNDIS is on. */ list_for_each_entry(func, &android_config_driver.functions, list) { - if (!strcmp(func->name, "usb_mass_storage") - || !strcmp(func->name, "mtp")) { - usb_function_set_enabled(func, !enable); + if (!strcmp(func->name, "usb_mass_storage")) { + func->hidden = enable; + break; } } } @@ -345,10 +532,20 @@ void android_enable_function(struct usb_function *f, int enable) device_desc.idProduct = __constant_cpu_to_le16(product_id); if (dev->cdev) dev->cdev->desc.idProduct = device_desc.idProduct; - usb_composite_force_reset(dev->cdev); + +#ifdef CONFIG_USB_GADGET_MSM_72K + msm_hsusb_request_reset(); +#else + /* force reenumeration */ + if (dev->cdev && dev->cdev->gadget && + dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) { + usb_gadget_disconnect(dev->cdev->gadget); + msleep(10); + usb_gadget_connect(dev->cdev->gadget); + } +#endif } } - void android_set_serialno(char *serialno) { strings_dev[STRING_SERIAL_IDX].s = serialno; @@ -360,7 +557,8 @@ int android_get_model_id(void) return dev->product_id; } -static int android_probe(struct platform_device *pdev) + +static int __init android_probe(struct platform_device *pdev) { struct android_usb_platform_data *pdata = pdev->dev.platform_data; struct android_dev *dev = _android_dev; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 4b21f63d..aeec3900 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -36,7 +36,7 @@ */ /* big enough to hold our biggest descriptor */ -#define USB_BUFSIZ 1024 +#define USB_BUFSIZ 512 static struct usb_composite_driver *composite; @@ -75,7 +75,7 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_function *f = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", !f->disabled); + return sprintf(buf, "%d\n", !f->hidden); } static ssize_t enable_store( @@ -90,36 +90,13 @@ static ssize_t enable_store( if (driver->enable_function) driver->enable_function(f, value); else - usb_function_set_enabled(f, value); + f->hidden = !value; return size; } static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); -void usb_function_set_enabled(struct usb_function *f, int enabled) -{ - f->disabled = !enabled; - kobject_uevent(&f->dev->kobj, KOBJ_CHANGE); -} - - -void usb_composite_force_reset(struct usb_composite_dev *cdev) -{ - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - /* force reenumeration */ - if (cdev && cdev->gadget && cdev->gadget->speed != USB_SPEED_UNKNOWN) { - spin_unlock_irqrestore(&cdev->lock, flags); - - usb_gadget_disconnect(cdev->gadget); - msleep(10); - usb_gadget_connect(cdev->gadget); - } else { - spin_unlock_irqrestore(&cdev->lock, flags); - } -} /** * usb_add_function() - add a function to a configuration @@ -135,7 +112,7 @@ void usb_composite_force_reset(struct usb_composite_dev *cdev) * This function returns the value of the function's bind(), which is * zero for success else a negative errno value. */ -int usb_add_function(struct usb_configuration *config, +int __init usb_add_function(struct usb_configuration *config, struct usb_function *function) { struct usb_composite_dev *cdev = config->cdev; @@ -280,7 +257,7 @@ int usb_function_activate(struct usb_function *function) * Returns the interface ID which was allocated; or -ENODEV if no * more interface IDs can be allocated. */ -int usb_interface_id(struct usb_configuration *config, +int __init usb_interface_id(struct usb_configuration *config, struct usb_function *function) { unsigned id = config->next_interface_id; @@ -293,6 +270,34 @@ int usb_interface_id(struct usb_configuration *config, return -ENODEV; } +static struct usb_function *get_function_by_intf(struct usb_composite_dev *cdev, + int intf) +{ + struct usb_configuration *config = cdev->config; + enum usb_device_speed speed = cdev->gadget->speed; + struct usb_function *f; + struct usb_descriptor_header *descriptor; + struct usb_interface_descriptor *intf_desc; + int i; + for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { + f = config->interface[i]; + if (!f) + return NULL; + if (f->hidden) + continue; + + if (speed == USB_SPEED_HIGH) + descriptor = *(f->hs_descriptors); + else + descriptor = *(f->descriptors); + intf_desc = (struct usb_interface_descriptor *)descriptor; + if (intf_desc->bDescriptorType == USB_DT_INTERFACE && + intf_desc->bInterfaceNumber == intf) + return f; + } + return NULL; +} + static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { @@ -334,7 +339,7 @@ static int config_buf(struct usb_configuration *config, descriptors = f->hs_descriptors; else descriptors = f->descriptors; - if (f->disabled || !descriptors || descriptors[0] == NULL) + if (f->hidden || !descriptors || descriptors[0] == NULL) continue; status = usb_descriptor_fillbuf(next, len, (const struct usb_descriptor_header **) descriptors); @@ -346,11 +351,9 @@ static int config_buf(struct usb_configuration *config, while ((descriptor = *descriptors++) != NULL) { intf = (struct usb_interface_descriptor *)dest; if (intf->bDescriptorType == USB_DT_INTERFACE) { - /* don't increment bInterfaceNumber for alternate settings */ - if (intf->bAlternateSetting == 0) - intf->bInterfaceNumber = interfaceCount++; - else - intf->bInterfaceNumber = interfaceCount - 1; + intf->bInterfaceNumber = interfaceCount; + intf = (struct usb_interface_descriptor *)descriptor; + intf->bInterfaceNumber = interfaceCount++; } dest += intf->bLength; } @@ -457,8 +460,6 @@ 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; } @@ -504,36 +505,9 @@ 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; - if (f->disabled) - continue; - - /* - * 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) { @@ -549,8 +523,6 @@ static int set_config(struct usb_composite_dev *cdev, power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; done: usb_gadget_vbus_draw(gadget, power); - - schedule_work(&cdev->switch_work); return result; } @@ -568,7 +540,7 @@ done: * assigns global resources including string IDs, and per-configuration * resources such as interface IDs and endpoints. */ -int usb_add_config(struct usb_composite_dev *cdev, +int __init usb_add_config(struct usb_composite_dev *cdev, struct usb_configuration *config) { int status = -EINVAL; @@ -765,7 +737,7 @@ static int get_string(struct usb_composite_dev *cdev, * ensure that for example different functions don't wrongly assign * different meanings to the same identifier. */ -int usb_string_id(struct usb_composite_dev *cdev) +int __init usb_string_id(struct usb_composite_dev *cdev) { if (cdev->next_string_id < 254) { /* string id 0 is reserved */ @@ -784,7 +756,6 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } - /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like @@ -803,15 +774,6 @@ 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; - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - if (!cdev->connected) { - cdev->connected = 1; - schedule_work(&cdev->switch_work); - } - spin_unlock_irqrestore(&cdev->lock, flags); /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion @@ -855,21 +817,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_STRING: value = get_string(cdev, req->buf, w_index, w_value & 0xff); - - /* Allow functions to handle USB_DT_STRING. - * This is required for MTP. - */ - if (value < 0) { - struct usb_configuration *cfg; - list_for_each_entry(cfg, &cdev->configs, list) { - if (cfg && cfg->setup) { - value = cfg->setup(cfg, ctrl); - if (value >= 0) - break; - } - } - } - if (value >= 0) value = min(w_length, (u16) value); break; @@ -910,7 +857,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) goto unknown; if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) break; - f = cdev->config->interface[intf]; + f = get_function_by_intf(cdev, intf); if (!f) break; if (w_value && !f->set_alt) @@ -922,7 +869,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) goto unknown; if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) break; - f = cdev->config->interface[intf]; + f = get_function_by_intf(cdev, intf); if (!f) break; /* lots of interfaces only need altsetting zero... */ @@ -939,36 +886,26 @@ unknown: ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); - /* functions always handle their interfaces and endpoints... - * punt other recipients (other, WUSB, ...) to the current + /* functions always handle their interfaces ... punt other + * recipients (endpoint, 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. */ - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: + if ((ctrl->bRequestType & USB_RECIP_MASK) + == USB_RECIP_INTERFACE) { if (cdev->config == NULL) return value; - f = cdev->config->interface[intf]; - 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 = get_function_by_intf(cdev, intf); + if (f && f->setup) + value = f->setup(f, ctrl); + else f = NULL; - break; } - - if (f && f->setup) - value = f->setup(f, ctrl); - else { + if (value < 0 && !f) { struct usb_configuration *c; c = cdev->config; @@ -1026,27 +963,13 @@ static void composite_disconnect(struct usb_gadget *gadget) spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) reset_config(cdev); - - cdev->connected = 0; - schedule_work(&cdev->switch_work); spin_unlock_irqrestore(&cdev->lock, flags); } /*-------------------------------------------------------------------------*/ -static ssize_t composite_show_suspended(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_gadget *gadget = dev_to_usb_gadget(dev); - struct usb_composite_dev *cdev = get_gadget_data(gadget); - - return sprintf(buf, "%d\n", cdev->suspended); -} - -static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); - -static void composite_unbind(struct usb_gadget *gadget) +static void /* __init_or_exit */ +composite_unbind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); @@ -1089,16 +1012,13 @@ static void composite_unbind(struct usb_gadget *gadget) kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } - - switch_dev_unregister(&cdev->sw_connected); - switch_dev_unregister(&cdev->sw_config); kfree(cdev); set_gadget_data(gadget, NULL); - device_remove_file(&gadget->dev, &dev_attr_suspended); composite = NULL; } -static void string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) +static void __init +string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) { struct usb_string *str = tab->strings; @@ -1110,7 +1030,8 @@ static void string_override_one(struct usb_gadget_strings *tab, u8 id, const cha } } -static void string_override(struct usb_gadget_strings **tab, u8 id, const char *s) +static void __init +string_override(struct usb_gadget_strings **tab, u8 id, const char *s) { while (*tab) { string_override_one(*tab, id, s); @@ -1118,30 +1039,7 @@ static void string_override(struct usb_gadget_strings **tab, u8 id, const char * } } -static void composite_switch_work(struct work_struct *data) -{ - struct usb_composite_dev *cdev = - container_of(data, struct usb_composite_dev, switch_work); - struct usb_configuration *config = cdev->config; - int connected; - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - if (cdev->connected != cdev->sw_connected.state) { - connected = cdev->connected; - spin_unlock_irqrestore(&cdev->lock, flags); - switch_set_state(&cdev->sw_connected, connected); - } else { - spin_unlock_irqrestore(&cdev->lock, flags); - } - - if (config) - switch_set_state(&cdev->sw_config, config->bConfigurationValue); - else - switch_set_state(&cdev->sw_config, 0); -} - -static int composite_bind(struct usb_gadget *gadget) +static int __init composite_bind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; int status = -ENOMEM; @@ -1176,14 +1074,6 @@ static int composite_bind(struct usb_gadget *gadget) */ usb_ep_autoconfig_reset(cdev->gadget); - /* standardized runtime overrides for device ID data */ - if (idVendor) - cdev->desc.idVendor = cpu_to_le16(idVendor); - if (idProduct) - cdev->desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); - /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc @@ -1192,19 +1082,17 @@ static int composite_bind(struct usb_gadget *gadget) if (status < 0) goto fail; - cdev->sw_connected.name = "usb_connected"; - status = switch_dev_register(&cdev->sw_connected); - if (status < 0) - goto fail; - cdev->sw_config.name = "usb_configuration"; - status = switch_dev_register(&cdev->sw_config); - if (status < 0) - goto fail; - INIT_WORK(&cdev->switch_work, composite_switch_work); - cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + /* standardized runtime overrides for device ID data */ + if (idVendor) + cdev->desc.idVendor = cpu_to_le16(idVendor); + if (idProduct) + cdev->desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + /* strings can't be assigned before bind() allocates the * releavnt identifiers */ @@ -1218,10 +1106,6 @@ static int composite_bind(struct usb_gadget *gadget) string_override(composite->strings, cdev->desc.iSerialNumber, iSerialNumber); - status = device_create_file(&gadget->dev, &dev_attr_suspended); - if (status) - goto fail; - INFO(cdev, "%s ready\n", composite->name); return 0; @@ -1232,7 +1116,8 @@ fail: /*-------------------------------------------------------------------------*/ -static void composite_suspend(struct usb_gadget *gadget) +static void +composite_suspend(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; @@ -1249,11 +1134,10 @@ static void composite_suspend(struct usb_gadget *gadget) } if (composite->suspend) composite->suspend(cdev); - - cdev->suspended = 1; } -static void composite_resume(struct usb_gadget *gadget) +static void +composite_resume(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; @@ -1270,24 +1154,6 @@ static void composite_resume(struct usb_gadget *gadget) f->resume(f); } } - - cdev->suspended = 0; -} - -static int composite_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_function *f = dev_get_drvdata(dev); - - if (!f) { - /* this happens when the device is first created */ - return 0; - } - - if (add_uevent_var(env, "FUNCTION=%s", f->name)) - return -ENOMEM; - if (add_uevent_var(env, "ENABLED=%d", !f->disabled)) - return -ENOMEM; - return 0; } /*-------------------------------------------------------------------------*/ @@ -1296,7 +1162,7 @@ static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, .bind = composite_bind, - .unbind = composite_unbind, + .unbind = __exit_p(composite_unbind), .setup = composite_setup, .disconnect = composite_disconnect, @@ -1324,7 +1190,7 @@ static struct usb_gadget_driver composite_driver = { * while it was binding. That would usually be done in order to wait for * some userspace participation. */ -int usb_composite_register(struct usb_composite_driver *driver) +int __init usb_composite_register(struct usb_composite_driver *driver) { if (!driver || !driver->dev || !driver->bind || composite) return -EINVAL; @@ -1338,7 +1204,6 @@ int usb_composite_register(struct usb_composite_driver *driver) driver->class = class_create(THIS_MODULE, "usb_composite"); if (IS_ERR(driver->class)) return PTR_ERR(driver->class); - driver->class->dev_uevent = composite_uevent; return usb_gadget_register_driver(&composite_driver); } @@ -1350,7 +1215,7 @@ int usb_composite_register(struct usb_composite_driver *driver) * This function is used to unregister drivers using the composite * driver framework. */ -void 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/diag.c b/drivers/usb/gadget/diag.c index ca82e7b8..d963d7f7 100644 --- a/drivers/usb/gadget/diag.c +++ b/drivers/usb/gadget/diag.c @@ -71,6 +71,7 @@ static void TRACE(const char *tag, const void *_data, int len, int decode) #endif #define HDLC_MAX 4096 +#define SMD_MAX 8192 #define TX_REQ_BUF_SZ 8192 #define RX_REQ_BUF_SZ 8192 @@ -87,6 +88,8 @@ struct diag_context struct usb_ep *in; struct list_head tx_req_idle; struct list_head rx_req_idle; + struct list_head rx_arm9_idle; + struct list_head rx_arm9_done; spinlock_t req_lock; #if ROUTE_TO_USERSPACE struct mutex user_lock; @@ -103,12 +106,11 @@ struct diag_context unsigned char id_table[ID_TABLE_SZ]; #endif smd_channel_t *ch; + struct mutex smd_lock; int in_busy; -#ifdef CONFIG_ARCH_QSD8X50 - smd_channel_t *ch_dsp; - int in_busy_dsp; -#endif int online; + int error; + int init_done; /* assembly buffer for USB->A9 HDLC frames */ unsigned char hdlc_buf[HDLC_MAX]; @@ -119,6 +121,22 @@ struct diag_context u64 rx_count; /* from smd */ int function_enable; + +#if defined(CONFIG_MSM_N_WAY_SMD) + smd_channel_t *chqdsp; + struct list_head tx_qdsp_idle; +#endif + /* for slate test */ + int is2ARM11; + struct mutex diag2arm9_lock; + struct mutex diag2arm9_read_lock; + struct mutex diag2arm9_write_lock; + bool diag2arm9_opened; + unsigned char toARM9_buf[SMD_MAX]; + unsigned read_arm9_count; + unsigned char *read_arm9_buf; + wait_queue_head_t read_arm9_wq; + struct usb_request *read_arm9_req; }; static struct usb_interface_descriptor diag_interface_desc = { @@ -175,6 +193,23 @@ static struct usb_descriptor_header *hs_diag_descs[] = { NULL, }; +/* string descriptors: */ + +static struct usb_string diag_string_defs[] = { + [0].s = "HTC DIAG", + { } /* end of list */ +}; + +static struct usb_gadget_strings diag_string_table = { + .language = 0x0409, /* en-us */ + .strings = diag_string_defs, +}; + +static struct usb_gadget_strings *diag_strings[] = { + &diag_string_table, + NULL, +}; + static struct diag_context _context; static inline struct diag_context *func_to_dev(struct usb_function *f) @@ -183,11 +218,42 @@ static inline struct diag_context *func_to_dev(struct usb_function *f) } static void smd_try_to_send(struct diag_context *ctxt); -#ifdef CONFIG_ARCH_QSD8X50 -static void dsp_try_to_send(struct diag_context *ctxt); -#endif +static void smd_diag_notify(void *priv, unsigned event); static void diag_queue_out(struct diag_context *ctxt); +#if defined(CONFIG_MSM_N_WAY_SMD) +static void diag_qdsp_complete_in(struct usb_ep *ept, + struct usb_request *req); +#endif + +static struct usb_request *diag_req_new(unsigned len) +{ + struct usb_request *req; + if (len > SMD_MAX) + return NULL; + req = kmalloc(sizeof(struct usb_request), GFP_KERNEL); + if (!req) + return NULL; + req->buf = kmalloc(len, GFP_KERNEL); + if (!req->buf) { + kfree(req); + return NULL; + } + return req; +} + +static void diag_req_free(struct usb_request *req) +{ + if (!req) + return; + + if (req->buf) { + kfree(req->buf); + req->buf = 0; + } + kfree(req); + req = 0; +} /* add a request to the tail of a list */ static void req_put(struct diag_context *ctxt, struct list_head *head, @@ -227,29 +293,82 @@ static void reqs_free(struct diag_context *ctxt, struct usb_ep *ep, } } +static void smd_diag_enable(char *src, int enable) +{ + struct diag_context *ctxt = &_context; + + printk(KERN_INFO "smd_try_open(%s): %d\n", src, enable); + if (!ctxt->init_done) + return; + + mutex_lock(&ctxt->smd_lock); + if (enable) { + if (!ctxt->ch) + smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify); + } else { + if (ctxt->ch) { + smd_close(ctxt->ch); + ctxt->ch = NULL; + } + } + mutex_unlock(&ctxt->smd_lock); + +} + + #if ROUTE_TO_USERSPACE #define USB_DIAG_IOC_MAGIC 0xFF -#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *) +#define USB_DIAG_FUNC_IOC_ENABLE_SET _IOW(USB_DIAG_IOC_MAGIC, 1, int) +#define USB_DIAG_FUNC_IOC_ENABLE_GET _IOR(USB_DIAG_IOC_MAGIC, 2, int) +#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *) +#define USB_DIAG_FUNC_IOC_AMR_SET _IOW(USB_DIAG_IOC_MAGIC, 4, int) static long diag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct diag_context *ctxt = &_context; void __user *argp = (void __user *)arg; + int tmp_value; unsigned long flags; unsigned char temp_id_table[ID_TABLE_SZ]; - if (cmd != USB_DIAG_FUNC_IOC_REGISTER_SET) { - pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd)); - return -EINVAL; + printk(KERN_INFO "diag:diag_ioctl() cmd=%d\n", cmd); + + if (_IOC_TYPE(cmd) != USB_DIAG_IOC_MAGIC) + return -ENOTTY; + + switch (cmd) { + case USB_DIAG_FUNC_IOC_ENABLE_SET: + if (copy_from_user(&tmp_value, argp, sizeof(int))) + return -EFAULT; + printk(KERN_INFO "diag: enable %d\n", tmp_value); + android_enable_function(&_context.function, tmp_value); + smd_diag_enable("diag_ioctl", tmp_value); + /* force diag_read to return error when disable diag */ + if (tmp_value == 0) + ctxt->error = 1; + wake_up(&ctxt->read_wq); + break; + case USB_DIAG_FUNC_IOC_ENABLE_GET: + tmp_value = !_context.function.hidden; + if (copy_to_user(argp, &tmp_value, sizeof(tmp_value))) + return -EFAULT; + break; + + case USB_DIAG_FUNC_IOC_REGISTER_SET: + if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ)) + return -EFAULT; + spin_lock_irqsave(&ctxt->req_lock, flags); + memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ); + spin_unlock_irqrestore(&ctxt->req_lock, flags); + break; + case USB_DIAG_FUNC_IOC_AMR_SET: + if (copy_from_user(&ctxt->is2ARM11, argp, sizeof(int))) + return -EFAULT; + printk(KERN_INFO "diag: is2ARM11 %d\n", ctxt->is2ARM11); + break; + default: + return -ENOTTY; } - - if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ)) - return -EFAULT; - - spin_lock_irqsave(&ctxt->req_lock, flags); - memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ); - spin_unlock_irqrestore(&ctxt->req_lock, flags); - return 0; } @@ -260,6 +379,13 @@ static ssize_t diag_read(struct file *fp, char __user *buf, struct usb_request *req = 0; int ret = 0; + /* we will block until we're online */ + if (!ctxt->online) { + ret = wait_event_interruptible(ctxt->read_wq, (ctxt->online || ctxt->error)); + if (ret < 0 || ctxt->error) + return -EFAULT; + } + mutex_lock(&ctxt->user_lock); if (ctxt->user_read_len && ctxt->user_readp) { @@ -285,7 +411,7 @@ static ssize_t diag_read(struct file *fp, char __user *buf, goto end; } if (!ctxt->online) { - pr_err("%s: offline\n", __func__); + /* pr_err("%s: offline\n", __func__); */ ret = -EIO; goto end; } @@ -357,6 +483,8 @@ static ssize_t diag_write(struct file *fp, const char __user *buf, } ret = req->length; + /* zero this so we don't put it back to idle queue */ + req = 0; } end: @@ -388,6 +516,8 @@ static int diag_open(struct inode *ip, struct file *fp) } } ctxt->opened = true; + /* clear the error latch */ + ctxt->error = 0; done: mutex_unlock(&ctxt->user_lock); @@ -427,6 +557,174 @@ static struct miscdevice diag_device_fops = { }; #endif +static int diag2arm9_open(struct inode *ip, struct file *fp) +{ + struct diag_context *ctxt = &_context; + struct usb_request *req; + int rc = 0; + int n; + printk(KERN_INFO "%s\n", __func__); + mutex_lock(&ctxt->diag2arm9_lock); + if (ctxt->diag2arm9_opened) { + pr_err("%s: already opened\n", __func__); + rc = -EBUSY; + goto done; + } + /* clear pending data if any */ + while ((req = req_get(ctxt, &ctxt->rx_arm9_done))) + diag_req_free(req); + + for (n = 0; n < 4; n++) { + req = diag_req_new(SMD_MAX); + if (!req) { + while ((req = req_get(ctxt, &ctxt->rx_arm9_idle))) + diag_req_free(req); + rc = -EFAULT; + goto done; + } + req_put(ctxt, &ctxt->rx_arm9_idle, req); + } + ctxt->read_arm9_count = 0; + ctxt->read_arm9_buf = 0; + ctxt->read_arm9_req = 0; + ctxt->diag2arm9_opened = true; + + smd_diag_enable("diag2arm9_open", 1); +done: + mutex_unlock(&ctxt->diag2arm9_lock); + return rc; +} + +static int diag2arm9_release(struct inode *ip, struct file *fp) +{ + struct diag_context *ctxt = &_context; + struct usb_request *req; + + printk(KERN_INFO "%s\n", __func__); + mutex_lock(&ctxt->diag2arm9_lock); + ctxt->diag2arm9_opened = false; + wake_up(&ctxt->read_arm9_wq); + mutex_lock(&ctxt->diag2arm9_read_lock); + while ((req = req_get(ctxt, &ctxt->rx_arm9_idle))) + diag_req_free(req); + while ((req = req_get(ctxt, &ctxt->rx_arm9_done))) + diag_req_free(req); + if (ctxt->read_arm9_req) + diag_req_free(ctxt->read_arm9_req); + mutex_unlock(&ctxt->diag2arm9_read_lock); + + /************************************* + * If smd is closed, it will lead to slate can't be tested. + * slate will open it for one time + * but close it for several times and never open + *************************************/ + /*smd_diag_enable("diag2arm9_release", 0);*/ + mutex_unlock(&ctxt->diag2arm9_lock); + + return 0; +} + +static ssize_t diag2arm9_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct diag_context *ctxt = &_context; + int r = count; + int writed = 0; + + mutex_lock(&ctxt->diag2arm9_write_lock); + + while (count > 0) { + writed = count > SMD_MAX ? SMD_MAX : count; + if (copy_from_user(ctxt->toARM9_buf, buf, writed)) { + r = -EFAULT; + break; + } + if (ctxt->ch == NULL) { + printk(KERN_ERR "%s: ctxt->ch == NULL", __func__); + r = -EFAULT; + break; + } else if (ctxt->toARM9_buf == NULL) { + printk(KERN_ERR "%s: ctxt->toARM9_buf == NULL", __func__); + r = -EFAULT; + break; + } + smd_write(ctxt->ch, ctxt->toARM9_buf, writed); + buf += writed; + count -= writed; + } + + mutex_unlock(&ctxt->diag2arm9_write_lock); + return r; +} + +static ssize_t diag2arm9_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + struct diag_context *ctxt = &_context; + struct usb_request *req; + int r = 0, xfer; + int ret; + + mutex_lock(&ctxt->diag2arm9_read_lock); + + /* if we have data pending, give it to userspace */ + if (ctxt->read_arm9_count > 0) + req = ctxt->read_arm9_req; + else { +retry: + /* get data from done queue */ + req = 0; + ret = wait_event_interruptible(ctxt->read_arm9_wq, + ((req = req_get(ctxt, &ctxt->rx_arm9_done)) || + !ctxt->diag2arm9_opened)); + if (!ctxt->diag2arm9_opened) { + if (req) + req_put(ctxt, &ctxt->rx_arm9_idle, req); + goto done; + } + if (ret < 0 || req == 0) + goto done; + + if (req->actual == 0) { + req_put(ctxt, &ctxt->rx_arm9_idle, req); + goto retry; + } + ctxt->read_arm9_req = req; + ctxt->read_arm9_count = req->actual; + ctxt->read_arm9_buf = req->buf; + } + xfer = (ctxt->read_arm9_count < count) ? ctxt->read_arm9_count : count; + if (copy_to_user(buf, ctxt->read_arm9_buf, xfer)) { + printk(KERN_INFO "diag: copy_to_user fail\n"); + r = -EFAULT; + goto done; + } + ctxt->read_arm9_buf += xfer; + ctxt->read_arm9_count -= xfer; + r += xfer; + /* if we've emptied the buffer, release the request */ + if (ctxt->read_arm9_count == 0) { + req_put(ctxt, &ctxt->rx_arm9_idle, ctxt->read_arm9_req); + ctxt->read_arm9_req = 0; + } +done: + mutex_unlock(&ctxt->diag2arm9_read_lock); + return r; +} +static struct file_operations diag2arm9_fops = { + .owner = THIS_MODULE, + .open = diag2arm9_open, + .release = diag2arm9_release, + .write = diag2arm9_write, + .read = diag2arm9_read, +}; + +static struct miscdevice diag2arm9_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "diag_arm9", + .fops = &diag2arm9_fops, +}; + static void diag_in_complete(struct usb_ep *ept, struct usb_request *req) { struct diag_context *ctxt = req->context; @@ -446,19 +744,7 @@ static void diag_in_complete(struct usb_ep *ept, struct usb_request *req) smd_try_to_send(ctxt); } -#ifdef CONFIG_ARCH_QSD8X50 -static void diag_dsp_in_complete(struct usb_ep *ept, struct usb_request *req) -{ - struct diag_context *ctxt = req->context; - - ctxt->in_busy_dsp = 0; - req_put(ctxt, &ctxt->tx_req_idle, req); - dsp_try_to_send(ctxt); - wake_up(&ctxt->write_wq); -} -#endif - -#if 0 +#if !NO_HDLC static void diag_process_hdlc(struct diag_context *ctxt, void *_data, unsigned len) { unsigned char *data = _data; @@ -585,8 +871,27 @@ again: int r = smd_read_avail(ctxt->ch); if (r > TX_REQ_BUF_SZ) { + printk(KERN_ERR "The SMD data is too large to send!!\n"); return; } + if (r > 0 && ctxt->is2ARM11) { + /* to arm11 user space */ + struct usb_request *req; + if (!ctxt->diag2arm9_opened) + return; + req = req_get(ctxt, &ctxt->rx_arm9_idle); + if (!req) { + printk(KERN_ERR "There is no enough request to ARM11!!\n"); + return; + } + smd_read(ctxt->ch, req->buf, r); + req->actual = r; + req_put(ctxt, &ctxt->rx_arm9_done, req); + wake_up(&ctxt->read_arm9_wq); + return; + } + if (!ctxt->online) + return; if (r > 0) { struct usb_request *req; req = req_get(ctxt, &ctxt->tx_req_idle); @@ -626,55 +931,6 @@ static void smd_diag_notify(void *priv, unsigned event) smd_try_to_send(ctxt); } -#ifdef CONFIG_ARCH_QSD8X50 -static void dsp_try_to_send(struct diag_context *ctxt) -{ -again: - if (ctxt->ch_dsp && (!ctxt->in_busy_dsp)) { - int r = smd_read_avail(ctxt->ch_dsp); - - if (r > TX_REQ_BUF_SZ) { - return; - } - if (r > 0) { - struct usb_request *req; - req = req_get(ctxt, &ctxt->tx_req_idle); - if (!req) { - pr_err("%s: tx req queue is out of buffers\n", - __func__); - return; - } - smd_read(ctxt->ch_dsp, req->buf, r); - - if (!ctxt->online) { -// printk("$$$ discard %d\n", r); - req_put(ctxt, &ctxt->tx_req_idle, req); - goto again; - } - req->complete = diag_dsp_in_complete; - req->context = ctxt; - req->length = r; - - TRACE("Q6>", req->buf, r, 1); - ctxt->in_busy_dsp = 1; - r = usb_ep_queue(ctxt->in, req, GFP_ATOMIC); - if (r < 0) { - pr_err("%s: usb_ep_queue failed: %d\n", - __func__, r); - req_put(ctxt, &ctxt->tx_req_idle, req); - ctxt->in_busy_dsp = 0; - } - } - } -} - -static void dsp_diag_notify(void *priv, unsigned event) -{ - struct diag_context *ctxt = priv; - dsp_try_to_send(ctxt); -} -#endif - static int __init create_bulk_endpoints(struct diag_context *ctxt, struct usb_endpoint_descriptor *in_desc, struct usb_endpoint_descriptor *out_desc) @@ -689,12 +945,14 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt, DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); return -ENODEV; } + ep->driver_data = ctxt; /* claim the endpoint */ ctxt->in = ep; ep = usb_ep_autoconfig(cdev->gadget, out_desc); if (!ep) { return -ENODEV; } + ep->driver_data = ctxt; /* claim the endpoint */ ctxt->out = ep; ctxt->tx_count = ctxt->rx_count = 0; @@ -733,8 +991,30 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt, req_put(ctxt, &ctxt->tx_req_idle, req); } - return 0; +#if defined(CONFIG_MSM_N_WAY_SMD) + for (n = 0; n < TX_REQ_NUM; n++) { + req = usb_ep_alloc_request(ctxt->in, GFP_KERNEL); + if (!req) { + DBG(cdev, "%s: usb_ep_alloc_request out of memory\n", + __func__); + goto qdsp_tx_fail; + } + req->buf = kmalloc(TX_REQ_BUF_SZ, GFP_KERNEL); + if (!req->buf) { + DBG(cdev, "%s: kmalloc out of memory\n", __func__); + goto qdsp_tx_fail; + } + req->context = ctxt; + req->complete = diag_qdsp_complete_in; + req_put(ctxt, &ctxt->tx_qdsp_idle, req); + } +#endif + return 0; +#if defined(CONFIG_MSM_N_WAY_SMD) +qdsp_tx_fail: + reqs_free(ctxt, ctxt->in, &ctxt->tx_qdsp_idle); +#endif tx_fail: reqs_free(ctxt, ctxt->in, &ctxt->tx_req_idle); rx_fail: @@ -775,6 +1055,7 @@ diag_function_bind(struct usb_configuration *c, struct usb_function *f) #if ROUTE_TO_USERSPACE misc_register(&diag_device_fops); #endif + misc_register(&diag2arm9_device); return 0; } @@ -789,6 +1070,7 @@ diag_function_unbind(struct usb_configuration *c, struct usb_function *f) #if ROUTE_TO_USERSPACE misc_deregister(&diag_device_fops); #endif + misc_deregister(&diag2arm9_device); ctxt->tx_count = ctxt->rx_count = 0; } @@ -817,7 +1099,7 @@ static int diag_function_set_alt(struct usb_function *f, usb_ep_disable(ctxt->in); return ret; } - ctxt->online = 1; + ctxt->online = !ctxt->function.hidden; #if ROUTE_TO_USERSPACE /* recycle unhandled rx reqs to user if any */ @@ -825,12 +1107,10 @@ static int diag_function_set_alt(struct usb_function *f, req_put(ctxt, &ctxt->rx_req_idle, req); #endif - diag_queue_out(ctxt); - smd_try_to_send(ctxt); -#ifdef CONFIG_ARCH_QSD8X50 - dsp_try_to_send(ctxt); -#endif - + if (ctxt->online) { + diag_queue_out(ctxt); + smd_try_to_send(ctxt); + } #if ROUTE_TO_USERSPACE wake_up(&ctxt->read_wq); wake_up(&ctxt->write_wq); @@ -852,12 +1132,78 @@ static void diag_function_disable(struct usb_function *f) usb_ep_disable(ctxt->out); } +#if defined(CONFIG_MSM_N_WAY_SMD) +static void diag_qdsp_send(struct diag_context *ctxt) +{ + int ret, r; + struct usb_request *req; + if (ctxt->chqdsp && ctxt->online) { + r = smd_read_avail(ctxt->chqdsp); + if (r > SMD_MAX || r <= 0) + return; + + req = req_get(ctxt, &ctxt->tx_qdsp_idle); + if (!req) + return; + + smd_read(ctxt->chqdsp, req->buf, r); + req->length = r; + + ret = usb_ep_queue(ctxt->in, req, GFP_ATOMIC); + if (ret < 0) { + printk(KERN_INFO "diag: failed to queue qdsp req %d\n", + ret); + req_put(ctxt, &ctxt->tx_qdsp_idle, req); + } + } +} + +static void diag_qdsp_complete_in(struct usb_ep *ept, + struct usb_request *req) +{ + struct diag_context *ctxt = req->context; + + req_put(ctxt, &ctxt->tx_qdsp_idle, req); + diag_qdsp_send(ctxt); + +#if ROUTE_TO_USERSPACE + wake_up(&ctxt->write_wq); +#endif +} + + +static void diag_qdsp_notify(void *priv, unsigned event) +{ + struct diag_context *ctxt = priv; + diag_qdsp_send(ctxt); +} + +static int msm_diag_probe(struct platform_device *pdev) +{ + struct diag_context *ctxt = &_context; + printk(KERN_INFO "diag:msm_diag_probe(), pdev->id=0x%x\n", pdev->id); + + if (pdev->id == 1) + smd_open("DSP_DIAG", &ctxt->chqdsp, ctxt, diag_qdsp_notify); + return 0; +} + +static struct platform_driver msm_smd_qdsp_ch1_driver = { + .probe = msm_diag_probe, + .driver = { + .name = "DSP_DIAG", + .owner = THIS_MODULE, + }, +}; +#endif + static int diag_set_enabled(const char *val, struct kernel_param *kp) { int enabled = simple_strtol(val, NULL, 0); if (_context.cdev) android_enable_function(&_context.function, enabled); _context.function_enable = !!enabled; + smd_diag_enable("diag_set_enabled", enabled); return 0; } @@ -872,7 +1218,7 @@ module_param_call(tx_rx_count, NULL, diag_get_tx_rx_count, NULL, 0444); static int diag_get_enabled(char *buffer, struct kernel_param *kp) { - buffer[0] = '0' + !_context.function.disabled; + buffer[0] = '0' + !_context.function.hidden; return 1; } module_param_call(enabled, diag_set_enabled, diag_get_enabled, NULL, 0664); @@ -885,20 +1231,15 @@ int diag_bind_config(struct usb_configuration *c) printk(KERN_INFO "diag_bind_config\n"); - ret = smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify); - if (ret) + ret = usb_string_id(c->cdev); + if (ret < 0) return ret; - -#ifdef CONFIG_ARCH_QSD8X50 - ret = smd_open("DSP_DIAG", &ctxt->ch_dsp, ctxt, dsp_diag_notify); - if (ret) { - pr_err("%s: smd_open failed (DSP_DIAG)\n", __func__); - return ret; - } -#endif + diag_string_defs[0].id = ret; + diag_interface_desc.iInterface = ret; ctxt->cdev = c->cdev; ctxt->function.name = "diag"; + ctxt->function.strings = diag_strings; ctxt->function.descriptors = fs_diag_descs; ctxt->function.hs_descriptors = hs_diag_descs; ctxt->function.bind = diag_function_bind; @@ -906,7 +1247,9 @@ int diag_bind_config(struct usb_configuration *c) ctxt->function.set_alt = diag_function_set_alt; ctxt->function.disable = diag_function_disable; - ctxt->function.disabled = !_context.function_enable; + ctxt->function.hidden = !_context.function_enable; + if (!ctxt->function.hidden) + smd_diag_enable("diag_bind_config", 1); return usb_add_function(c, &ctxt->function); } @@ -924,12 +1267,26 @@ static int __init init(void) spin_lock_init(&ctxt->req_lock); INIT_LIST_HEAD(&ctxt->rx_req_idle); INIT_LIST_HEAD(&ctxt->tx_req_idle); + INIT_LIST_HEAD(&ctxt->rx_arm9_idle); + INIT_LIST_HEAD(&ctxt->rx_arm9_done); #if ROUTE_TO_USERSPACE mutex_init(&ctxt->user_lock); INIT_LIST_HEAD(&ctxt->rx_req_user); init_waitqueue_head(&ctxt->read_wq); init_waitqueue_head(&ctxt->write_wq); #endif + init_waitqueue_head(&ctxt->read_arm9_wq); + mutex_init(&ctxt->diag2arm9_lock); + mutex_init(&ctxt->diag2arm9_read_lock); + mutex_init(&ctxt->diag2arm9_write_lock); + mutex_init(&ctxt->smd_lock); + ctxt->is2ARM11 = 0; + +#if defined(CONFIG_MSM_N_WAY_SMD) + INIT_LIST_HEAD(&ctxt->tx_qdsp_idle); + platform_driver_register(&msm_smd_qdsp_ch1_driver); +#endif + ctxt->init_done = 1; android_register_function(&diag_function); return 0; diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index a0b0774b..39fc2f17 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -31,11 +31,13 @@ #include #include +#include #define BULK_BUFFER_SIZE 4096 /* number of tx requests to allocate */ #define TX_REQ_MAX 4 +#define RX_REQ_MAX 32 static const char shortname[] = "android_adb"; @@ -55,11 +57,18 @@ struct adb_dev { atomic_t open_excl; struct list_head tx_idle; + struct list_head rx_idle; + struct list_head rx_done; wait_queue_head_t read_wq; wait_queue_head_t write_wq; - struct usb_request *rx_req; - int rx_done; + + /* the request we're currently reading from */ + struct usb_request *read_req; + unsigned char *read_buf; + unsigned read_count; + + int maxsize; }; static struct usb_interface_descriptor adb_interface_desc = { @@ -116,6 +125,22 @@ static struct usb_descriptor_header *hs_adb_descs[] = { NULL, }; +/* string descriptors: */ + +static struct usb_string adb_string_defs[] = { + [0].s = "ADB", + { } /* end of list */ +}; + +static struct usb_gadget_strings adb_string_table = { + .language = 0x0409, /* en-us */ + .strings = adb_string_defs, +}; + +static struct usb_gadget_strings *adb_strings[] = { + &adb_string_table, + NULL, +}; /* temporary variable used between adb_open() and adb_gadget_bind() */ static struct adb_dev *_adb_dev; @@ -211,9 +236,11 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) { struct adb_dev *dev = _adb_dev; - dev->rx_done = 1; - if (req->status != 0) + if (req->status != 0) { dev->error = 1; + req_put(dev, &dev->rx_idle, req); + } else + req_put(dev, &dev->rx_done, req); wake_up(&dev->read_wq); } @@ -248,11 +275,13 @@ static int __init create_bulk_endpoints(struct adb_dev *dev, dev->ep_out = ep; /* now allocate requests for our endpoints */ - req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = adb_complete_out; - dev->rx_req = req; + for (i = 0; i < RX_REQ_MAX; i++) { + req = adb_request_new(dev->ep_out, 512); + if (!req) + goto fail; + req->complete = adb_complete_out; + req_put(dev, &dev->rx_idle, req); + } for (i = 0; i < TX_REQ_MAX; i++) { req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE); @@ -300,40 +329,70 @@ static ssize_t adb_read(struct file *fp, char __user *buf, r = -EIO; goto done; } + while (count > 0) { + if (dev->error) { + r = -EIO; + break; + } + /* if we have idle read requests, get them queued */ + while ((req = req_get(dev, &dev->rx_idle))) { requeue_req: - /* queue a request */ - req = dev->rx_req; - req->length = count; - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); - if (ret < 0) { - DBG(cdev, "adb_read: failed to queue req %p (%d)\n", req, ret); - r = -EIO; - dev->error = 1; - goto done; - } else { - DBG(cdev, "rx %p queue\n", req); - } + req->length = dev->maxsize?dev->maxsize:512; + ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); + if (ret < 0) { + printk(KERN_INFO "adb_read: failed to queue req (%d)\n", ret); + r = -EIO; + dev->error = 1; + req_put(dev, &dev->rx_idle, req); + goto done; + } + } - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->read_wq, dev->rx_done); - if (ret < 0) { - dev->error = 1; - r = ret; - goto done; - } - if (!dev->error) { - /* If we got a 0-len packet, throw it back and try again. */ - if (req->actual == 0) - goto requeue_req; + /* if we have data pending, give it to userspace */ + if (dev->read_count > 0) { + xfer = (dev->read_count < count) ? dev->read_count : count; - DBG(cdev, "rx %p %d\n", req, req->actual); - xfer = (req->actual < count) ? req->actual : count; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; - } else - r = -EIO; + if (copy_to_user(buf, dev->read_buf, xfer)) { + r = -EFAULT; + break; + } + dev->read_buf += xfer; + dev->read_count -= xfer; + buf += xfer; + count -= xfer; + + /* if we've emptied the buffer, release the request */ + if (dev->read_count == 0) { + req_put(dev, &dev->rx_idle, dev->read_req); + dev->read_req = 0; + } + continue; + } + + /* wait for a request to complete */ + req = 0; + ret = wait_event_interruptible(dev->read_wq, + ((req = req_get(dev, &dev->rx_done)) || dev->error)); + + if (req != 0) { + /* if we got a 0-len one we need to put it back into + ** service. if we made it the current read req we'd + ** be stuck forever + */ + if (req->actual == 0) + goto requeue_req; + + dev->read_req = req; + dev->read_count = req->actual; + dev->read_buf = req->buf; + } + + if (ret < 0) { + r = ret; + break; + } + } done: _unlock(&dev->read_excl); @@ -521,7 +580,10 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) spin_lock_irq(&dev->lock); - adb_request_free(dev->rx_req, dev->ep_out); + while ((req = req_get(dev, &dev->rx_done))) + adb_request_free(req, dev->ep_out); + while ((req = req_get(dev, &dev->rx_idle))) + adb_request_free(req, dev->ep_out); while ((req = req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); @@ -541,6 +603,7 @@ static int adb_function_set_alt(struct usb_function *f, struct adb_dev *dev = func_to_dev(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; + struct usb_request *req; DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt); ret = usb_ep_enable(dev->ep_in, @@ -557,7 +620,17 @@ static int adb_function_set_alt(struct usb_function *f, usb_ep_disable(dev->ep_in); return ret; } - dev->online = 1; + if (cdev->gadget->speed == USB_SPEED_FULL) + dev->maxsize = 64; + else + dev->maxsize = 512; + printk(KERN_INFO "%s: maxsize = %d\n", __func__, dev->maxsize); + + /* retire any completed rx requests from previous session */ + while ((req = req_get(dev, &dev->rx_done))) + req_put(dev, &dev->rx_idle, req); + + dev->online = !dev->function.hidden; /* readers may be blocked waiting for us to go online */ wake_up(&dev->read_wq); @@ -572,6 +645,7 @@ static void adb_function_disable(struct usb_function *f) DBG(cdev, "adb_function_disable\n"); dev->online = 0; dev->error = 1; + dev->maxsize = 0; usb_ep_disable(dev->ep_in); usb_ep_disable(dev->ep_out); @@ -602,18 +676,27 @@ static int adb_bind_config(struct usb_configuration *c) atomic_set(&dev->write_excl, 0); INIT_LIST_HEAD(&dev->tx_idle); + INIT_LIST_HEAD(&dev->rx_idle); + INIT_LIST_HEAD(&dev->rx_done); + ret = usb_string_id(c->cdev); + if (ret < 0) + return ret; + adb_string_defs[0].id = ret; + adb_interface_desc.iInterface = ret; dev->cdev = c->cdev; dev->function.name = "adb"; + dev->function.strings = adb_strings; dev->function.descriptors = fs_adb_descs; dev->function.hs_descriptors = hs_adb_descs; dev->function.bind = adb_function_bind; dev->function.unbind = adb_function_unbind; dev->function.set_alt = adb_function_set_alt; dev->function.disable = adb_function_disable; + dev->maxsize = 512; - /* start disabled */ - dev->function.disabled = 1; + if (board_mfg_mode() != 2) + dev->function.hidden = 1; /* _adb_dev must be set before calling usb_gadget_register_driver */ _adb_dev = dev; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 33166787..17b5c400 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1,9 +1,15 @@ /* - * f_mass_storage.c -- Mass Storage USB Composite Function + * drivers/usb/gadget/f_mass_storage.c * - * Copyright (C) 2003-2008 Alan Stern - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz + * Function Driver for USB Mass Storage + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood + * + * Based heavily on the file_storage gadget driver in + * drivers/usb/gadget/file_storage.c and licensed under the same terms: + * + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,237 +43,7 @@ * 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 (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. - * - * When a LUN receive an "eject" SCSI request (Start/Stop Unit), - * if the LUN is removable, the backing file is released to simulate - * ejection. - * - * - * 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 . - * 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 - * . - */ - - -/* - * 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 DEBUG */ /* #define VERBOSE_DEBUG */ /* #define DUMP_MSGS */ @@ -287,263 +63,563 @@ #include #include #include +#include #include #include +#include +#include +#include +#include #include -#include +#include +#include #include "gadget_chips.h" -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE -#include -#include -#define FUNCTION_NAME "usb_mass_storage" -#endif +#define BULK_BUFFER_SIZE 16384 -/*------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ -#define FSG_DRIVER_DESC "Mass Storage Function" -#define FSG_DRIVER_VERSION "2009/09/11" +#define DRIVER_NAME "usb_mass_storage" +#define MAX_LUNS 8 -static const char fsg_string_interface[] = "Mass Storage"; +static const char shortname[] = DRIVER_NAME; +#ifdef DEBUG +#define LDBG(lun, fmt, args...) \ + dev_dbg(&(lun)->dev , fmt , ## args) +#define MDBG(fmt,args...) \ + printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) +#else +#define LDBG(lun, fmt, args...) \ + do { } while (0) +#define MDBG(fmt,args...) \ + do { } while (0) +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* DEBUG */ -#define FSG_NO_INTR_EP 1 -#define FSG_NO_DEVICE_STRINGS 1 -#define FSG_NO_OTG 1 -#define FSG_NO_INTR_EP 1 +#ifdef VERBOSE_DEBUG +#define VLDBG LDBG +#else +#define VLDBG(lun, fmt, args...) \ + do { } while (0) +#endif /* VERBOSE_DEBUG */ -#include "storage_common.c" +#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...) \ + printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) + +#undef DBG +#undef VDBG +#undef ERROR +#undef WARNING +#undef INFO +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->cdev->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->cdev->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->cdev->gadget->dev , fmt , ## args) +#define WARNING(d, fmt, args...) \ + dev_warn(&(d)->cdev->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->cdev->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ -struct fsg_dev; +/* 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 + +/* 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)) -/* Data shared by all the FSG instances. */ -struct fsg_common { - struct usb_gadget *gadget; - struct fsg_dev *fsg, *new_fsg; - wait_queue_head_t fsg_wait; +/*-------------------------------------------------------------------------*/ + +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; + unsigned int cdrom : 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 + +/* Number of buffers we will use. 2 is enough for double-buffering */ +#define NUM_BUFFERS 4 + +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 { + /* 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_CONFIG_CHANGE, + 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 { + struct usb_function function; + struct usb_composite_dev *cdev; + + /* optional "usb_mass_storage" platform device */ + struct platform_device *pdev; + + /* lock protects: state and all the req_busy's */ + spinlock_t lock; /* 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; + /* reference counting: wait until all LUNs are released */ + struct kref ref; unsigned int bulk_out_maxpacket; enum fsg_state state; /* For exception handling */ - unsigned int exception_req_tag; - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - u32 residue; - u32 usb_amount_left; + u8 config, new_config; + u8 ums_state; - 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; + unsigned int running : 1; + unsigned int bulk_in_enabled : 1; + unsigned int bulk_out_enabled : 1; + unsigned int phase_error : 1; + unsigned int short_packet_received : 1; + unsigned int bad_lun_okay : 1; + + unsigned long atomic_bitflags; +#define REGISTERED 0 +#define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 + + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd buffhds[NUM_BUFFERS]; int thread_wakeup_needed; struct completion thread_notifier; struct task_struct *thread_task; - /* Callback function to call when thread exits. */ - int (*thread_exits)(struct fsg_common *common); - /* Gadget's private data. */ - void *private_data; + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + unsigned int lun; + u32 residue; + u32 usb_amount_left; - /* Vendor (8 chars), product (16 chars), release (4 - * hexadecimal digits) and NUL byte */ - char inquiry_string[8 + 16 + 4 + 1]; + unsigned int nluns; + struct lun *luns; + struct lun *curlun; - struct kref ref; + u32 buf_size; + const char *vendor; + const char *product; + int release; + + struct switch_dev sdev; + + struct wake_lock wake_lock; + int cdrom_lun; }; - -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. If no - * callback is set or it returns value lower then zero MSF - * will force eject all LUNs it operates on (including those - * marked as non-removable or with prevent_medium_removal flag - * set). */ - int (*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; - -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - struct platform_device *pdev; -#endif -}; - - -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; - struct switch_dev sdev; -}; - - -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) +static inline struct fsg_dev *func_to_dev(struct usb_function *f) { return container_of(f, struct fsg_dev, function); } - -typedef void (*fsg_routine_t)(struct fsg_dev *); -static int send_status(struct fsg_common *common); - -static int exception_in_progress(struct fsg_common *common) +static int exception_in_progress(struct fsg_dev *fsg) { - return common->state > FSG_STATE_IDLE; + return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_common *common, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; bh->bulk_out_intended_length = length; - rem = length % common->bulk_out_maxpacket; + rem = length % fsg->bulk_out_maxpacket; if (rem > 0) - length += common->bulk_out_maxpacket - rem; + length += fsg->bulk_out_maxpacket - rem; bh->outreq->length = length; } +static struct fsg_dev *the_fsg; + +static void close_backing_file(struct fsg_dev *fsg, struct lun *curlun); +static void close_all_backing_files(struct fsg_dev *fsg); +static void fsg_set_ums_state(int connect_status); + +static struct t_usb_status_notifier connect_status_notifier = { + .name = "connect_status", + .func = fsg_set_ums_state, +}; + +/*-------------------------------------------------------------------------*/ + +static void fsg_set_ums_state(int connect_status) +{ + if (!the_fsg) + return; + printk(KERN_INFO "%s: %d\n", __func__, connect_status); + /* USB connected */ + if (connect_status == 1) { + if (!the_fsg->ums_state) { + the_fsg->ums_state = 1; + printk(KERN_INFO "ums: set state 1\n"); + switch_set_state(&the_fsg->sdev, 1); + } + } else { + if (the_fsg->ums_state) { + the_fsg->ums_state = 0; + printk(KERN_INFO "ums: set state 0\n"); + switch_set_state(&the_fsg->sdev, 0); + } + } +} + +#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 */ + + +/*-------------------------------------------------------------------------*/ + +/* Routines for unaligned data access */ + +static u16 get_be16(u8 *buf) +{ + return ((u16) buf[0] << 8) | ((u16) buf[1]); +} + +static u32 get_be32(u8 *buf) +{ + return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | + ((u32) buf[2] << 8) | ((u32) buf[3]); +} + +static void put_be16(u8 *buf, u16 val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static void put_be32(u8 *buf, u32 val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val & 0xff; +} + /*-------------------------------------------------------------------------*/ -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. Also the (static) config and interface + * descriptors are adjusted during fsg_bind(). + */ + +/* There is only one 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 = US_SC_SCSI, + .bInterfaceProtocol = US_PR_BULK, +}; + +/* 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_descriptor_header *fs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_bulk_in_desc, + (struct usb_descriptor_header *) &fs_bulk_out_desc, + NULL, +}; +#define FS_FUNCTION_PRE_EP_ENTRIES 2 + + +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 = __constant_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 = __constant_cpu_to_le16(512), + .bInterval = 1, /* NAK every 1 uframe */ +}; + + +static struct usb_descriptor_header *hs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_bulk_in_desc, + (struct usb_descriptor_header *) &hs_bulk_out_desc, + NULL, +}; + +/* 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) { - 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); + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } - /*-------------------------------------------------------------------------*/ /* These routines may be called in process context or in_irq */ /* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_common *common) +static void wakeup_thread(struct fsg_dev *fsg) { /* Tell the main thread that something has happened */ - common->thread_wakeup_needed = 1; - if (common->thread_task) - wake_up_process(common->thread_task); + fsg->thread_wakeup_needed = 1; + if (fsg->thread_task) + wake_up_process(fsg->thread_task); } -static void raise_exception(struct fsg_common *common, enum fsg_state new_state) +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) { unsigned long flags; + DBG(fsg, "raise_exception %d\n", (int)new_state); /* 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) + spin_lock_irqsave(&fsg->lock, flags); + if (fsg->state <= new_state) { + fsg->state = new_state; + if (fsg->thread_task) send_sig_info(SIGUSR1, SEND_SIG_FORCED, - common->thread_task); + fsg->thread_task); } - spin_unlock_irqrestore(&common->lock, flags); + spin_unlock_irqrestore(&fsg->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. @@ -551,103 +627,107 @@ static int ep0_queue(struct fsg_common *common) static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_common *common = ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; struct fsg_buffhd *bh = req->context; + unsigned long flags; if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + DBG(fsg, "%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); - spin_lock(&common->lock); + spin_lock_irqsave(&fsg->lock, flags); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; - wakeup_thread(common); - spin_unlock(&common->lock); + wakeup_thread(fsg); + spin_unlock_irqrestore(&fsg->lock, flags); } static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_common *common = ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; struct fsg_buffhd *bh = req->context; + unsigned long flags; - dump_msg(common, "bulk-out", req->buf, req->actual); + dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, + DBG(fsg, "%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ smp_wmb(); - spin_lock(&common->lock); + spin_lock_irqsave(&fsg->lock, flags); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; - wakeup_thread(common); - spin_unlock(&common->lock); + wakeup_thread(fsg); + spin_unlock_irqrestore(&fsg->lock, flags); } - -/*-------------------------------------------------------------------------*/ - -/* Ep0 class-specific handlers. These always run in_irq. */ - -static int fsg_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) +static int fsg_function_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; + struct fsg_dev *fsg = func_to_dev(f); + struct usb_composite_dev *cdev = fsg->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); - if (!fsg_is_set(fsg->common)) - return -EOPNOTSUPP; + DBG(fsg, "fsg_function_setup\n"); + if (w_index != intf_desc.bInterfaceNumber) + return value; + /* Handle Bulk-only class-specific requests */ + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + DBG(fsg, "USB_TYPE_CLASS\n"); + switch (ctrl->bRequest) { + case USB_BULK_RESET_REQUEST: + if (ctrl->bRequestType != (USB_DIR_OUT | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_value != 0) { + value = -EDOM; + break; + } - switch (ctrl->bRequest) { - - case USB_BULK_RESET_REQUEST: - if (ctrl->bRequestType != - (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + /* Raise an exception to stop the current operation + * and reinitialize our state. */ + DBG(fsg, "bulk reset request\n"); + value = 0; 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)) + case USB_BULK_GET_MAX_LUN_REQUEST: + if (ctrl->bRequestType != (USB_DIR_IN | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_value != 0) { + value = -EDOM; + break; + } + VDBG(fsg, "get max LUN\n"); + *(u8 *)cdev->req->buf = fsg->nluns - 1; + value = 1; 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; - - /* Respond with data/status */ - req->length = min((u16)1, w_length); - fsg->common->ep0req_name = - ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"; - return ep0_queue(fsg->common); + } } - 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; + if (value == -EOPNOTSUPP) + VDBG(fsg, + "unknown class-specific control req " + "%02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + le16_to_cpu(ctrl->wValue), w_index, w_length); + if (value >= 0) { + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + req->status = 0; + } + return value; } - /*-------------------------------------------------------------------------*/ /* All the following routines run in process context */ @@ -659,14 +739,16 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, enum fsg_buffer_state *state) { int rc; + unsigned long flags; + DBG(fsg, "start_transfer req: %p, req->buf: %p\n", req, req->buf); if (ep == fsg->bulk_in) dump_msg(fsg, "bulk-in", req->buf, req->length); - spin_lock_irq(&fsg->common->lock); + spin_lock_irqsave(&fsg->lock, flags); *pbusy = 1; *state = BUF_STATE_BUSY; - spin_unlock_irq(&fsg->common->lock); + spin_unlock_irqrestore(&fsg->lock, flags); rc = usb_ep_queue(ep, req, GFP_KERNEL); if (rc != 0) { *pbusy = 0; @@ -678,23 +760,14 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, * submissions if DMA is enabled. */ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); + WARN(fsg, "error in submission: %s --> %d\n", + (ep == fsg->bulk_in ? "bulk-in" : "bulk-out"), + 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) +static int sleep_thread(struct fsg_dev *fsg) { int rc = 0; @@ -706,21 +779,21 @@ static int sleep_thread(struct fsg_common *common) rc = -EINTR; break; } - if (common->thread_wakeup_needed) + if (fsg->thread_wakeup_needed) break; schedule(); } __set_current_state(TASK_RUNNING); - common->thread_wakeup_needed = 0; + fsg->thread_wakeup_needed = 0; return rc; } /*-------------------------------------------------------------------------*/ -static int do_read(struct fsg_common *common) +static int do_read(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; u32 lba; struct fsg_buffhd *bh; int rc; @@ -732,15 +805,15 @@ static int do_read(struct fsg_common *common) /* 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]); + if (fsg->cmnd[0] == SC_READ_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); else { - lba = get_unaligned_be32(&common->cmnd[2]); + lba = get_be32(&fsg->cmnd[2]); /* We allow DPO (Disable Page Out = don't save data in the * cache) and FUA (Force Unit Access = don't read from the * cache), but we don't implement them. */ - if ((common->cmnd[1] & ~0x18) != 0) { + if ((fsg->cmnd[1] & ~0x18) != 0) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } @@ -752,7 +825,7 @@ static int do_read(struct fsg_common *common) file_offset = ((loff_t) lba) << 9; /* Carry out the file reads */ - amount_left = common->data_size_from_cmnd; + amount_left = fsg->data_size_from_cmnd; if (unlikely(amount_left == 0)) return -EIO; /* No default reply */ @@ -766,7 +839,8 @@ static int do_read(struct fsg_common *common) * 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((unsigned int) amount_left, + (unsigned int)fsg->buf_size); amount = min((loff_t) amount, curlun->file_length - file_offset); partial_page = file_offset & (PAGE_CACHE_SIZE - 1); @@ -775,9 +849,9 @@ static int do_read(struct fsg_common *common) partial_page); /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; + bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } @@ -816,7 +890,7 @@ static int do_read(struct fsg_common *common) } file_offset += nread; amount_left -= nread; - common->residue -= nread; + fsg->residue -= nread; bh->inreq->length = nread; bh->state = BUF_STATE_FULL; @@ -832,13 +906,9 @@ static int do_read(struct fsg_common *common) 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; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; } return -EIO; /* No default reply */ @@ -847,9 +917,9 @@ static int do_read(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int do_write(struct fsg_common *common) +static int do_write(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; u32 lba; struct fsg_buffhd *bh; int get_some_more; @@ -864,30 +934,25 @@ static int do_write(struct fsg_common *common) 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]); + if (fsg->cmnd[0] == SC_WRITE_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); else { - lba = get_unaligned_be32(&common->cmnd[2]); + lba = get_be32(&fsg->cmnd[2]); /* We allow DPO (Disable Page Out = don't save data in the * cache) and FUA (Force Unit Access = write directly to the * medium). We don't implement DPO; we implement FUA by * performing synchronous output. */ - if (common->cmnd[1] & ~0x18) { + if ((fsg->cmnd[1] & ~0x18) != 0) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - if (common->cmnd[1] & 0x08) { /* FUA */ - spin_lock(&curlun->filp->f_lock); + if (fsg->cmnd[1] & 0x08) /* FUA */ 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; @@ -897,13 +962,12 @@ static int do_write(struct fsg_common *common) /* 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; + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; while (amount_left_to_write > 0) { /* Queue a request for more data from the host */ - bh = common->next_buffhd_to_fill; + bh = fsg->next_buffhd_to_fill; if (bh->state == BUF_STATE_EMPTY && get_some_more) { /* Figure out how much we want to get: @@ -915,7 +979,7 @@ static int do_write(struct fsg_common *common) * 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(amount_left_to_req, (u32)fsg->buf_size); amount = min((loff_t) amount, curlun->file_length - usb_offset); partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); @@ -942,32 +1006,28 @@ static int do_write(struct fsg_common *common) /* Get the next buffer */ usb_offset += amount; - common->usb_amount_left -= amount; + fsg->usb_amount_left -= amount; amount_left_to_req -= amount; if (amount_left_to_req == 0) get_some_more = 0; /* amount is always divisible by 512, hence by * the bulk-out maxpacket size */ - bh->outreq->length = 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; + bh->outreq->length = bh->bulk_out_intended_length = + amount; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; continue; } /* Write the received data to the backing file */ - bh = common->next_buffhd_to_drain; + bh = fsg->next_buffhd_to_drain; if (bh->state == BUF_STATE_EMPTY && !get_some_more) break; /* We stopped early */ if (bh->state == BUF_STATE_FULL) { smp_rmb(); - common->next_buffhd_to_drain = bh->next; + fsg->next_buffhd_to_drain = bh->next; bh->state = BUF_STATE_EMPTY; /* Did something go wrong with the transfer? */ @@ -1006,11 +1066,11 @@ static int do_write(struct fsg_common *common) LDBG(curlun, "partial file write: %d/%u\n", (int) nwritten, amount); nwritten -= (nwritten & 511); - /* Round down to a block */ + /* Round down to a block */ } file_offset += nwritten; amount_left_to_write -= nwritten; - common->residue -= nwritten; + fsg->residue -= nwritten; /* If an error occurred, report it and its position */ if (nwritten < amount) { @@ -1022,14 +1082,14 @@ static int do_write(struct fsg_common *common) /* Did the host decide to stop early? */ if (bh->outreq->actual != bh->outreq->length) { - common->short_packet_received = 1; + fsg->short_packet_received = 1; break; } continue; } /* Wait for something to happen */ - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } @@ -1040,14 +1100,50 @@ static int do_write(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int do_synchronize_cache(struct fsg_common *common) +/* Sync the file data, don't bother with the metadata. + * The caller must own fsg->filesem. + * This code was copied from fs/buffer.c:sys_fdatasync(). */ +static int fsync_sub(struct lun *curlun) { - struct fsg_lun *curlun = common->curlun; + struct file *filp = curlun->filp; + struct inode *inode; + int rc, err; + + if (curlun->ro || !filp) + return 0; + if (!filp->f_op->fsync) + return -EINVAL; + + inode = filp->f_path.dentry->d_inode; + mutex_lock(&inode->i_mutex); + rc = filemap_fdatawrite(inode->i_mapping); + err = filp->f_op->fsync(filp, filp->f_path.dentry, 1); + if (!rc) + rc = err; + err = filemap_fdatawait(inode->i_mapping); + if (!rc) + rc = err; + mutex_unlock(&inode->i_mutex); + VLDBG(curlun, "fdatasync -> %d\n", rc); + return rc; +} + +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; int rc; /* We ignore the requested LBA and write out all file's * dirty data buffers. */ - rc = fsg_lun_fsync_sub(curlun); + rc = fsync_sub(curlun); if (rc) curlun->sense_data = SS_WRITE_ERROR; return 0; @@ -1056,22 +1152,22 @@ static int do_synchronize_cache(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static void invalidate_sub(struct fsg_lun *curlun) +static void invalidate_sub(struct 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_mapping_pages -> %ld\n", rc); + VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); } -static int do_verify(struct fsg_common *common) +static int do_verify(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; u32 lba; u32 verification_length; - struct fsg_buffhd *bh = common->next_buffhd_to_fill; + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; loff_t file_offset, file_offset_tmp; u32 amount_left; unsigned int amount; @@ -1079,7 +1175,7 @@ static int do_verify(struct fsg_common *common) /* Get the starting Logical Block Address and check that it's * not too big */ - lba = get_unaligned_be32(&common->cmnd[2]); + lba = get_be32(&fsg->cmnd[2]); if (lba >= curlun->num_sectors) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; @@ -1087,12 +1183,12 @@ static int do_verify(struct fsg_common *common) /* We allow DPO (Disable Page Out = don't save data in the * cache) but we don't implement it. */ - if (common->cmnd[1] & ~0x10) { + if ((fsg->cmnd[1] & ~0x10) != 0) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - verification_length = get_unaligned_be16(&common->cmnd[7]); + verification_length = get_be16(&fsg->cmnd[7]); if (unlikely(verification_length == 0)) return -EIO; /* No default reply */ @@ -1101,7 +1197,7 @@ static int do_verify(struct fsg_common *common) file_offset = ((loff_t) lba) << 9; /* Write out all the dirty buffers before invalidating them */ - fsg_lun_fsync_sub(curlun); + fsync_sub(curlun); if (signal_pending(current)) return -EINTR; @@ -1118,7 +1214,8 @@ static int do_verify(struct fsg_common *common) * 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((unsigned int) amount_left, + (unsigned int)fsg->buf_size); amount = min((loff_t) amount, curlun->file_length - file_offset); if (amount == 0) { @@ -1164,35 +1261,47 @@ static int do_verify(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; u8 *buf = (u8 *) bh->buf; + u32 ret = 36; - if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; + if (!fsg->curlun) { /* Unsupported LUNs are okay */ + fsg->bad_lun_okay = 1; memset(buf, 0, 36); buf[0] = 0x7f; /* Unsupported, no device-type */ buf[4] = 31; /* Additional length */ return 36; } - buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK; - buf[1] = curlun->removable ? 0x80 : 0; + memset(buf, 0, 8); /* Non-removable, direct-access device */ + + if (fsg->curlun->cdrom) + buf[0] = 0x05; + else + buf[1] = 0x80; /* set removable bit */ 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; + /* No special options */ + sprintf(buf + 8, "%-8s%-16s%04x", fsg->vendor, + fsg->product, fsg->release); + if (fsg->data_size_from_cmnd == 56) { + int model_id = android_get_model_id(); + u16 *us; + memset(buf + 36, 0, 20); + buf[4] = 51; /* Additional length */ + us = (unsigned short *)(buf + 36); + *us = __constant_cpu_to_le16(model_id); + ret = 56; + } + return ret; } -static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; u8 *buf = (u8 *) bh->buf; u32 sd, sdinfo; int valid; @@ -1220,7 +1329,7 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) #endif if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; + fsg->bad_lun_okay = 1; sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; sdinfo = 0; valid = 0; @@ -1236,7 +1345,7 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) memset(buf, 0, 18); buf[0] = valid | 0x70; /* Valid, current error */ buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ + put_be32(&buf[3], sdinfo); /* Sense information */ buf[7] = 18 - 8; /* Additional sense length */ buf[12] = ASC(sd); buf[13] = ASCQ(sd); @@ -1244,11 +1353,11 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) } -static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - int pmi = common->cmnd[8]; + struct lun *curlun = fsg->curlun; + u32 lba = get_be32(&fsg->cmnd[2]); + int pmi = fsg->cmnd[8]; u8 *buf = (u8 *) bh->buf; /* Check the PMI and LBA fields */ @@ -1257,21 +1366,38 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) return -EINVAL; } - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_be32(&buf[0], curlun->num_sectors - 1); /* Max logical block */ + put_be32(&buf[4], 512); /* Block length */ return 8; } - -static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) +static void store_cdrom_address(u8 *dest, int msf, u32 addr) { - struct fsg_lun *curlun = common->curlun; - int msf = common->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&common->cmnd[2]); + 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_be32(dest, addr); + } +} + +static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + u32 lba = get_be32(&fsg->cmnd[2]); u8 *buf = (u8 *) bh->buf; - if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ + if ((fsg->cmnd[1] & ~0x02) != 0) { + /* Mask away MSF */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } @@ -1286,39 +1412,37 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) return 8; } - -static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) +static int do_read_toc(struct fsg_dev *fsg, 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; + struct lun *curlun = fsg->curlun; + int msf = fsg->cmnd[1] & 0x02; + int start_track = fsg->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; + if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ + start_track > 1) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; } memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ + 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 */ + 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) +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - int mscmnd = common->cmnd[0]; + struct lun *curlun = fsg->curlun; + int mscmnd = fsg->cmnd[0]; u8 *buf = (u8 *) bh->buf; u8 *buf0 = buf; int pc, page_code; @@ -1326,12 +1450,12 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) int valid_page = 0; int len, limit; - if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ + if ((fsg->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; + pc = fsg->cmnd[2] >> 6; + page_code = fsg->cmnd[2] & 0x3f; if (pc == 3) { curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; return -EINVAL; @@ -1351,11 +1475,14 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) } else { /* SC_MODE_SENSE_10 */ buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ buf += 8; - limit = 65535; /* Should really be FSG_BUFLEN */ + limit = 65535; } /* No block descriptors */ + /* Disabled to workaround USB reset problems with a Vista host. + */ +#if 0 /* The mode pages, in numerical order. The only page we support * is the Caching page. */ if (page_code == 0x08 || all_pages) { @@ -1368,16 +1495,17 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) buf[2] = 0x04; /* Write cache enable, */ /* Read cache not disabled */ /* No cache retention priorities */ - put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ + put_be16(&buf[4], 0xffff); /* Don't disable prefetch */ /* Minimum prefetch = 0 */ - put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ - put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ + put_be16(&buf[8], 0xffff); /* Maximum prefetch */ + /* Maximum prefetch ceiling */ + put_be16(&buf[10], 0xffff); } buf += 12; } +#else + valid_page = 1; +#endif /* Check that a valid page was requested and the mode data length * isn't too long. */ @@ -1391,242 +1519,178 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) if (mscmnd == SC_MODE_SENSE_6) buf0[0] = len - 1; else - put_unaligned_be16(len - 2, buf0); + put_be16(buf0, len - 2); return len; } - -static int do_start_stop(struct fsg_common *common) +static int do_start_stop(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; int loej, start; - if (!curlun) { - return -EINVAL; - } else if (!curlun->removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } + /* int immed = fsg->cmnd[1] & 0x01; */ + loej = fsg->cmnd[4] & 0x02; + start = fsg->cmnd[4] & 0x01; - loej = common->cmnd[4] & 0x02; - start = common->cmnd[4] & 0x01; - - /* eject code from file_storage.c:do_start_stop() */ - - if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ - (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (!start) { - /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { - LDBG(curlun, "unload attempt prevented\n"); - curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -EINVAL; - } - if (loej) { /* Simulate an unload/eject */ - up_read(&common->filesem); - down_write(&common->filesem); - fsg_lun_close(curlun); - up_write(&common->filesem); - down_read(&common->filesem); - } - } else { - - /* Our emulation doesn't support mounting; the medium is - * available for use as soon as it is loaded. */ - if (!fsg_lun_is_open(curlun)) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; + if (loej) { + /* eject request from the host */ + if (backing_file_is_open(curlun)) { + close_backing_file(fsg, curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; } } + return 0; } - -static int do_prevent_allow(struct fsg_common *common) +static int do_prevent_allow(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->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 */ + prevent = fsg->cmnd[4] & 0x01; + if ((fsg->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); + fsync_sub(curlun); curlun->prevent_medium_removal = prevent; return 0; } -static int do_read_format_capacities(struct fsg_common *common, +static int do_read_format_capacities(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; u8 *buf = (u8 *) bh->buf; buf[0] = buf[1] = buf[2] = 0; buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ buf += 4; - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ - buf[4] = 0x02; /* Current capacity */ + put_be32(&buf[0], curlun->num_sectors); /* Number of blocks */ + put_be32(&buf[4], 512); /* Block length */ + buf[4] = 0x02; /* Current capacity */ return 12; } -static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; /* We don't support MODE SELECT */ - if (curlun) - curlun->sense_data = SS_INVALID_COMMAND; + curlun->sense_data = SS_INVALID_COMMAND; return -EINVAL; } - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) +static int do_reserve(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - int rc; + int call_us_ret = -1; + char *envp[] = { + "HOME=/", + "PATH=/sbin:/system/sbin:/system/bin:/system/xbin", + NULL, + }; + char *exec_path[2] = {"/system/bin/stop", "/system/bin/start" }; + char *argv_stop[] = { exec_path[0], "adbd", NULL, }; + char *argv_start[] = { exec_path[1], "adbd", NULL, }; - 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; + if (fsg->cmnd[1] == ('h'&0x1f) && fsg->cmnd[2] == 't' + && fsg->cmnd[3] == 'c') { + /* No special options */ + switch (fsg->cmnd[5]) { + case 0x01: /* enable adbd */ + call_us_ret = call_usermodehelper(exec_path[1], + argv_start, envp, UMH_WAIT_PROC); + break; + case 0x02: /*disable adbd */ + call_us_ret = call_usermodehelper(exec_path[0], + argv_stop, envp, UMH_WAIT_PROC); + break; + default: + printk(KERN_DEBUG "Unknown hTC specific command...(0x%2.2X)\n", + fsg->cmnd[5]); + 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; } + printk(KERN_NOTICE "%s adb daemon from mass_storage %s(%d)\n", + (fsg->cmnd[5] == 0x01)?"Enable":(fsg->cmnd[5] == 0x02)?"Disable":"Unknown", + (call_us_ret == 0)?"DONE":"FAIL", call_us_ret); return 0; } -static int throw_away_data(struct fsg_common *common) +/*-------------------------------------------------------------------------*/ +#if 0 +static int write_zero(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc; + + DBG(fsg, "write_zero\n"); + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + bh->inreq->length = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + + fsg->next_buffhd_to_fill = bh->next; + return 0; +} +#endif + +static int throw_away_data(struct fsg_dev *fsg) { 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) { + DBG(fsg, "throw_away_data\n"); + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || + fsg->usb_amount_left > 0) { /* Throw away the data in a filled buffer */ if (bh->state == BUF_STATE_FULL) { smp_rmb(); bh->state = BUF_STATE_EMPTY; - common->next_buffhd_to_drain = bh->next; + fsg->next_buffhd_to_drain = bh->next; /* A short packet or an error ends everything */ if (bh->outreq->actual != bh->outreq->length || bh->outreq->status != 0) { - raise_exception(common, - FSG_STATE_ABORT_BULK_OUT); + raise_exception(fsg, 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); + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { + amount = min(fsg->usb_amount_left, (u32) fsg->buf_size); /* 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; + bh->outreq->length = bh->bulk_out_intended_length = + amount; + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= amount; continue; } /* Otherwise wait for something to happen */ - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } @@ -1634,75 +1698,52 @@ static int throw_away_data(struct fsg_common *common) } -static int finish_reply(struct fsg_common *common) +static int finish_reply(struct fsg_dev *fsg) { - struct fsg_buffhd *bh = common->next_buffhd_to_fill; + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; int rc = 0; - switch (common->data_dir) { + switch (fsg->data_dir) { case DATA_DIR_NONE: break; /* Nothing to send */ - /* If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. */ case DATA_DIR_UNKNOWN: - if (!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; - } + rc = -EINVAL; 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 (fsg->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 if (fsg->residue == 0) { + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; } else { - /* Don't know what to do if common->fsg is NULL */ - rc = -EIO; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; +#if 0 + /* this is unnecessary, and was causing problems with MacOS */ + if (bh->inreq->length > 0) + write_zero(fsg); +#endif } 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 */ + if (fsg->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); + else if (fsg->short_packet_received) { + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; + } /* We haven't processed all the incoming data. Even though * we may be allowed to stall, doing so would cause a race. @@ -1711,38 +1752,35 @@ static int finish_reply(struct fsg_common *common) * 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; + fsg_set_halt(fsg, fsg->bulk_out); + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; #endif /* We can't stall. Read in the excess data and throw it * all away. */ - } else { - rc = throw_away_data(common); - } + else + rc = throw_away_data(fsg); break; } return rc; } -static int send_status(struct fsg_common *common) +static int send_status(struct fsg_dev *fsg) { - struct fsg_lun *curlun = common->curlun; + struct lun *curlun = fsg->curlun; struct fsg_buffhd *bh; - struct bulk_cs_wrap *csw; int rc; u8 status = USB_STATUS_PASS; u32 sd, sdinfo = 0; + struct bulk_cs_wrap *csw; + DBG(fsg, "send_status\n"); /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; + bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } @@ -1750,39 +1788,36 @@ static int send_status(struct fsg_common *common) if (curlun) { sd = curlun->sense_data; sdinfo = curlun->sense_data_info; - } else if (common->bad_lun_okay) + } else if (fsg->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"); + if (fsg->phase_error) { + DBG(fsg, "sending phase-error status\n"); status = USB_STATUS_PHASE_ERROR; sd = SS_INVALID_COMMAND; } else if (sd != SS_NO_SENSE) { - DBG(common, "sending command-failure status\n"); + DBG(fsg, "sending command-failure status\n"); status = USB_STATUS_FAIL; - VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" + VDBG(fsg, " 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 = bh->buf; - csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); - csw->Tag = common->tag; - csw->Residue = cpu_to_le32(common->residue); + /* Store and send the Bulk-only CSW */ + csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); + csw->Tag = fsg->tag; + csw->Residue = cpu_to_le32(fsg->residue); csw->Status = status; bh->inreq->length = USB_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - START_TRANSFER_OR(common, bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); - common->next_buffhd_to_fill = bh->next; + fsg->next_buffhd_to_fill = bh->next; return 0; } @@ -1791,95 +1826,91 @@ static int send_status(struct fsg_common *common) /* 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, +static int check_command(struct fsg_dev *fsg, int cmnd_size, enum data_direction data_dir, unsigned int mask, int needs_medium, const char *name) { int i; - int lun = common->cmnd[1] >> 5; + int lun = fsg->cmnd[1] >> 5; static const char dirletter[4] = {'u', 'o', 'i', 'n'}; char hdlen[20]; - struct fsg_lun *curlun; + struct 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); + if (fsg->data_dir != DATA_DIR_UNKNOWN) + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], + fsg->data_size); + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); /* We can't reply at all until we know the correct data direction * and size. */ - if (common->data_size_from_cmnd == 0) + if (fsg->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; + if (fsg->data_dir == DATA_DIR_UNKNOWN) { /* CB or CBI */ + fsg->data_dir = data_dir; + fsg->data_size = fsg->data_size_from_cmnd; + + } else { /* Bulk-only */ + if (fsg->data_size < fsg->data_size_from_cmnd) { + + /* Host data size < Device data size is a phase error. + * Carry out the command, but only transfer as much + * as we are allowed. */ + DBG(fsg, "phase error 1\n"); + fsg->data_size_from_cmnd = fsg->data_size; + fsg->phase_error = 1; + } } - common->residue = common->data_size; - common->usb_amount_left = common->data_size; + fsg->residue = fsg->usb_amount_left = fsg->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; + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + DBG(fsg, "phase error 2\n"); return -EINVAL; } /* Verify the length of the command itself */ - if (cmnd_size != common->cmnd_size) { + if (cmnd_size != fsg->cmnd_size) { - /* Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= 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; + /* Special case workaround: MS-Windows issues REQUEST SENSE/ + * INQUIRY with cbw->Length == 12 (it should be 6). */ + if ((fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) + || (fsg->cmnd[0] == SC_INQUIRY && fsg->cmnd_size == 12)) + cmnd_size = fsg->cmnd_size; + else if (fsg->cmnd[0] == SC_RESERVE) + cmnd_size = fsg->cmnd_size; + else { + fsg->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); + if (fsg->lun != lun) + DBG(fsg, "using LUN %d from CBW, " + "not LUN %d from CDB\n", + fsg->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) { + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { + fsg->curlun = curlun = &fsg->luns[fsg->lun]; + if (fsg->cmnd[0] != SC_REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } } else { - common->curlun = NULL; - curlun = NULL; - common->bad_lun_okay = 0; + fsg->curlun = curlun = NULL; + fsg->bad_lun_okay = 0; /* INQUIRY and REQUEST SENSE commands are explicitly allowed * to use unsupported LUNs; all others may not. */ - if (common->cmnd[0] != SC_INQUIRY && - common->cmnd[0] != SC_REQUEST_SENSE) { - DBG(common, "unsupported LUN %d\n", common->lun); + if (fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { + DBG(fsg, "unsupported LUN %d\n", fsg->lun); return -EINVAL; } } @@ -1887,27 +1918,29 @@ static int check_command(struct fsg_common *common, int cmnd_size, /* 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) { + fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { curlun->sense_data = curlun->unit_attention_data; curlun->unit_attention_data = SS_NO_SENSE; return -EINVAL; } /* Check that only command bytes listed in the mask are non-zero */ - common->cmnd[1] &= 0x1f; /* Mask away the LUN */ + fsg->cmnd[1] &= 0x1f; /* Mask away the LUN */ for (i = 1; i < cmnd_size; ++i) { - if (common->cmnd[i] && !(mask & (1 << i))) { + if (fsg->cmnd[i] && !(mask & (1 << i))) { if (curlun) curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + DBG(fsg, "SS_INVALID_FIELD_IN_CDB\n"); 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) { + if (curlun && !backing_file_is_open(curlun) && needs_medium) { curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + DBG(fsg, "SS_MEDIUM_NOT_PRESENT\n"); return -EINVAL; } @@ -1915,7 +1948,7 @@ static int check_command(struct fsg_common *common, int cmnd_size, } -static int do_scsi_command(struct fsg_common *common) +static int do_scsi_command(struct fsg_dev *fsg) { struct fsg_buffhd *bh; int rc; @@ -1923,181 +1956,159 @@ static int do_scsi_command(struct fsg_common *common) int i; static char unknown[16]; - dump_cdb(common); + dump_cdb(fsg); /* Wait for the next buffer to become available for data or status */ - bh = common->next_buffhd_to_fill; - common->next_buffhd_to_drain = bh; + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } - common->phase_error = 0; - common->short_packet_received = 0; + fsg->phase_error = 0; + fsg->short_packet_received = 0; - down_read(&common->filesem); /* We're using the backing file */ - switch (common->cmnd[0]) { + down_read(&fsg->filesem); /* We're using the backing file */ + switch (fsg->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); + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "INQUIRY")) == 0) + reply = do_inquiry(fsg, bh); break; case SC_MODE_SELECT_6: - 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); + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (1<<1) | (1<<4), 0, + "MODE SELECT(6)")) == 0) + reply = do_mode_select(fsg, bh); break; case SC_MODE_SELECT_10: - 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); + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (3<<7), 0, + "MODE SELECT(10)")) == 0) + reply = do_mode_select(fsg, bh); break; case SC_MODE_SENSE_6: - 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); + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (1<<4), 0, + "MODE SENSE(6)")) == 0) + reply = do_mode_sense(fsg, bh); break; case SC_MODE_SENSE_10: - 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); + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (3<<7), 0, + "MODE SENSE(10)")) == 0) + reply = do_mode_sense(fsg, bh); break; case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: - 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); + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<4), 0, + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) + reply = do_prevent_allow(fsg); break; case SC_READ_6: - i = 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); + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (7<<1) | (1<<4), 1, + "READ(6)")) == 0) + reply = do_read(fsg); break; case SC_READ_10: - 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); + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "READ(10)")) == 0) + reply = do_read(fsg); break; case SC_READ_12: - 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); + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "READ(12)")) == 0) + reply = do_read(fsg); break; case SC_READ_CAPACITY: - 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); + fsg->data_size_from_cmnd = 8; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (0xf<<2) | (1<<8), 1, + "READ CAPACITY")) == 0) + reply = do_read_capacity(fsg, bh); break; case SC_READ_HEADER: - if (!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); + if (!fsg->curlun->cdrom) + goto unknown_cmd; + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7) | (0x1f<<1), 1, + "READ HEADER")) == 0) + reply = do_read_header(fsg, bh); + break; case SC_READ_TOC: - if (!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); + if (!fsg->curlun->cdrom) + goto unknown_cmd; + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (7<<6) | (1<<1), 1, + "READ TOC")) == 0) + reply = do_read_toc(fsg, bh); + break; case SC_READ_FORMAT_CAPACITIES: - 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); + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7), 1, + "READ FORMAT CAPACITIES")) == 0) + reply = do_read_format_capacities(fsg, bh); break; case SC_REQUEST_SENSE: - 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); + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "REQUEST SENSE")) == 0) + reply = do_request_sense(fsg, bh); break; case SC_START_STOP_UNIT: - 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); + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<1) | (1<<4), 0, + "START-STOP UNIT")) == 0) + reply = do_start_stop(fsg); break; case SC_SYNCHRONIZE_CACHE: - 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); + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (0xf<<2) | (3<<7), 1, + "SYNCHRONIZE CACHE")) == 0) + reply = do_synchronize_cache(fsg); break; case SC_TEST_UNIT_READY: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, + fsg->data_size_from_cmnd = 0; + reply = check_command(fsg, 6, DATA_DIR_NONE, 0, 1, "TEST UNIT READY"); break; @@ -2105,79 +2116,80 @@ static int do_scsi_command(struct fsg_common *common) /* 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); + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (1<<1) | (0xf<<2) | (3<<7), 1, + "VERIFY")) == 0) + reply = do_verify(fsg); break; case SC_WRITE_6: - i = 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); + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (7<<1) | (1<<4), 1, + "WRITE(6)")) == 0) + reply = do_write(fsg); break; case SC_WRITE_10: - 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); + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "WRITE(10)")) == 0) + reply = do_write(fsg); break; case SC_WRITE_12: - 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); + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "WRITE(12)")) == 0) + reply = do_write(fsg); break; + case SC_RESERVE: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) , 0, + "RESERVE(6)")) == 0) + reply = do_reserve(fsg, bh); + 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; +unknown_cmd: + fsg->data_size_from_cmnd = 0; + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); + if ((reply = check_command(fsg, fsg->cmnd_size, + DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { + fsg->curlun->sense_data = SS_INVALID_COMMAND; reply = -EINVAL; } break; } - up_read(&common->filesem); + up_read(&fsg->filesem); + VDBG(fsg, "reply: %d, fsg->data_size_from_cmnd: %d\n", + reply, fsg->data_size_from_cmnd); 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); + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { + reply = min((u32) reply, fsg->data_size_from_cmnd); bh->inreq->length = reply; bh->state = BUF_STATE_FULL; - common->residue -= reply; + fsg->residue -= reply; } /* Otherwise it's already set */ return 0; @@ -2189,87 +2201,64 @@ unknown_cmnd: 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; + struct 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)) + /* Was this a real packet? */ + if (req->status) return -EINVAL; /* Is the CBW valid? */ if (req->actual != USB_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( + cbw->Signature != __constant_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 || + if (cbw->Lun >= 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); + fsg->cmnd_size = cbw->Length; + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); if (cbw->Flags & USB_BULK_IN_FLAG) - common->data_dir = DATA_DIR_TO_HOST; + fsg->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; + fsg->data_dir = DATA_DIR_FROM_HOST; + fsg->data_size = le32_to_cpu(cbw->DataTransferLength); + if (fsg->data_size == 0) + fsg->data_dir = DATA_DIR_NONE; + fsg->lun = cbw->Lun; + fsg->tag = cbw->Tag; return 0; } -static int get_next_command(struct fsg_common *common) +static int get_next_command(struct fsg_dev *fsg) { struct fsg_buffhd *bh; int rc = 0; /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; + bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); + rc = sleep_thread(fsg); 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; + set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); /* We will drain the buffer in software, which means we * can reuse it for the next filling. No need to advance @@ -2277,12 +2266,12 @@ static int get_next_command(struct fsg_common *common) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(common); + rc = sleep_thread(fsg); if (rc) return rc; } smp_rmb(); - rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO; + rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; return rc; @@ -2291,103 +2280,96 @@ static int get_next_command(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep, +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, const struct usb_endpoint_descriptor *d) { int rc; - ep->driver_data = common; + DBG(fsg, "usb_ep_enable %s\n", ep->name); + ep->driver_data = fsg; rc = usb_ep_enable(ep, d); if (rc) - ERROR(common, "can't enable %s, result %d\n", ep->name, rc); + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); return rc; } -static int alloc_request(struct fsg_common *common, struct usb_ep *ep, +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, struct usb_request **preq) { *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); if (*preq) return 0; - ERROR(common, "can't allocate request for %s\n", ep->name); + ERROR(fsg, "can't allocate request for %s\n", ep->name); return -ENOMEM; } -/* Reset interface setting and re-init endpoint state (toggle etc). */ -static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) +/* + * Reset interface setting and re-init endpoint state (toggle etc). + * Call with altsetting < 0 to disable the interface. The only other + * available altsetting is 0, which enables the interface. + */ +static int do_set_interface(struct fsg_dev *fsg, int altsetting) { - const struct usb_endpoint_descriptor *d; - struct fsg_dev *fsg; - int i, rc = 0; - - if (common->running) - DBG(common, "reset interface\n"); + struct usb_composite_dev *cdev = fsg->cdev; + int rc = 0; + int i; + const struct usb_endpoint_descriptor *d; + if (fsg->running) + DBG(fsg, "reset interface\n"); reset: /* Deallocate the requests */ - if (common->fsg) { - fsg = common->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; - } + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + if (bh->inreq) { + usb_ep_free_request(fsg->bulk_in, bh->inreq); + bh->inreq = NULL; } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; + if (bh->outreq) { + usb_ep_free_request(fsg->bulk_out, bh->outreq); + bh->outreq = NULL; } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - - common->fsg = NULL; - wake_up(&common->fsg_wait); } - common->running = 0; - if (!new_fsg || rc) + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name); + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name); + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + + fsg->running = 0; + if (altsetting < 0 || rc != 0) return rc; - common->fsg = new_fsg; - fsg = common->fsg; + DBG(fsg, "set interface %d\n", altsetting); /* 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) + d = ep_desc(cdev->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) goto reset; fsg->bulk_in_enabled = 1; - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); - rc = enable_endpoint(common, fsg->bulk_out, d); - if (rc) + d = ep_desc(cdev->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) goto reset; fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; - rc = alloc_request(common, fsg->bulk_in, &bh->inreq); - if (rc) + rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq); + if (rc != 0) goto reset; - rc = alloc_request(common, fsg->bulk_out, &bh->outreq); - if (rc) + rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq); + if (rc != 0) goto reset; bh->inreq->buf = bh->outreq->buf = bh->buf; bh->inreq->context = bh->outreq->context = bh; @@ -2395,168 +2377,168 @@ reset: 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; + fsg->running = 1; + for (i = 0; i < fsg->nluns; ++i) + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; + + return rc; +} + +static void adjust_wake_lock(struct fsg_dev *fsg) +{ + int ums_active = 0; + int i; + unsigned long flags; + + spin_lock_irqsave(&fsg->lock, flags); + + if (fsg->config) { + for (i = 0; i < fsg->nluns; ++i) { + if (backing_file_is_open(&fsg->luns[i])) + ums_active = 1; + } + } + + if (ums_active) + wake_lock(&fsg->wake_lock); + else + wake_unlock(&fsg->wake_lock); + + spin_unlock_irqrestore(&fsg->lock, flags); +} + +/* + * Change our operational configuration. This code must agree with the code + * that returns config descriptors, and with interface altsetting code. + * + * It's also responsible for power management interactions. Some + * configurations might not work with our current power sources. + * For now we just assume the gadget is always self-powered. + */ +static int do_set_config(struct fsg_dev *fsg, u8 new_config) +{ + int rc = 0; + + if (new_config == fsg->config) + return rc; + + /* Disable the single interface */ + if (fsg->config != 0) { + DBG(fsg, "reset config\n"); + fsg->config = 0; + } + + /* Enable the interface */ + if (new_config != 0) + fsg->config = new_config; + + if (new_config || fsg->function.hidden) { + fsg->ums_state = new_config; + printk(KERN_INFO "ums: set state %d\n", new_config); + switch_set_state(&fsg->sdev, new_config); + } + adjust_wake_lock(fsg); 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->new_fsg = fsg; - 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->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); -} - - /*-------------------------------------------------------------------------*/ -static struct fsg_dev *the_fsg; - -static void handle_exception(struct fsg_common *common) +static void handle_exception(struct fsg_dev *fsg) { siginfo_t info; + int sig; int i; struct fsg_buffhd *bh; enum fsg_state old_state; - struct fsg_lun *curlun; - unsigned int exception_req_tag; + u8 new_config; + struct lun *curlun; + int rc; + unsigned long flags; + DBG(fsg, "handle_exception state: %d\n", (int)fsg->state); /* Clear the existing signals. Anything but SIGUSR1 is converted * into a high-priority EXIT exception. */ for (;;) { - int sig = - dequeue_signal_lock(current, ¤t->blocked, &info); + sig = dequeue_signal_lock(current, ¤t->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); + if (fsg->state < FSG_STATE_EXIT) + DBG(fsg, "Main thread exiting on signal\n"); + raise_exception(fsg, FSG_STATE_EXIT); } } - /* Cancel all the pending transfers */ - if (likely(common->fsg)) { - 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); - } + /* Clear out the controller's fifos */ + if (fsg->bulk_in_enabled) + usb_ep_fifo_flush(fsg->bulk_in); + if (fsg->bulk_out_enabled) + usb_ep_fifo_flush(fsg->bulk_out); /* Reset the I/O buffer states and pointers, the SCSI * state, and the exception. Then invoke the handler. */ - spin_lock_irq(&common->lock); + spin_lock_irqsave(&fsg->lock, flags); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - bh = &common->buffhds[i]; + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->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; - old_state = common->state; + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = + &fsg->buffhds[0]; + + new_config = fsg->new_config; + old_state = fsg->state; if (old_state == FSG_STATE_ABORT_BULK_OUT) - common->state = FSG_STATE_STATUS_PHASE; + fsg->state = FSG_STATE_STATUS_PHASE; else { - for (i = 0; i < common->nluns; ++i) { - curlun = &common->luns[i]; + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; curlun->prevent_medium_removal = 0; - curlun->sense_data = SS_NO_SENSE; - curlun->unit_attention_data = SS_NO_SENSE; + curlun->sense_data = curlun->unit_attention_data = + SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } - common->state = FSG_STATE_IDLE; + fsg->state = FSG_STATE_IDLE; } - spin_unlock_irq(&common->lock); + spin_unlock_irqrestore(&fsg->lock, flags); /* Carry out any extra actions required for the exception */ switch (old_state) { + default: + break; + 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); + DBG(fsg, "FSG_STATE_ABORT_BULK_OUT\n"); + spin_lock_irqsave(&fsg->lock, flags); + if (fsg->state == FSG_STATE_STATUS_PHASE) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irqrestore(&fsg->lock, flags); 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; */ + /* really not much to do here */ break; case FSG_STATE_CONFIG_CHANGE: - do_set_interface(common, common->new_fsg); - switch_set_state(&the_fsg->sdev, !!common->new_fsg); + rc = do_set_config(fsg, new_config); + if (new_config == 0) { + /* We're using the backing file */ + down_read(&fsg->filesem); + fsync_all(fsg); + up_read(&fsg->filesem); + } break; case FSG_STATE_EXIT: case FSG_STATE_TERMINATED: - do_set_interface(common, NULL); /* 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: + do_set_interface(fsg, -1); + do_set_config(fsg, 0); /* Free resources */ + spin_lock_irqsave(&fsg->lock, flags); + fsg->state = FSG_STATE_TERMINATED; /* Stop the thread */ + spin_unlock_irqrestore(&fsg->lock, flags); break; } } @@ -2564,9 +2546,10 @@ static void handle_exception(struct fsg_common *common) /*-------------------------------------------------------------------------*/ -static int fsg_main_thread(void *common_) +static int fsg_main_thread(void *fsg_) { - struct fsg_common *common = common_; + struct fsg_dev *fsg = fsg_; + unsigned long flags; /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ @@ -2584,641 +2567,610 @@ static int fsg_main_thread(void *common_) set_fs(get_ds()); /* The main loop */ - while (common->state != FSG_STATE_TERMINATED) { - if (exception_in_progress(common) || signal_pending(current)) { - handle_exception(common); + while (fsg->state != FSG_STATE_TERMINATED) { + if (exception_in_progress(fsg) || signal_pending(current)) { + handle_exception(fsg); continue; } - if (!common->running) { - sleep_thread(common); + if (!fsg->running) { + sleep_thread(fsg); continue; } - if (get_next_command(common)) + if (get_next_command(fsg)) continue; - spin_lock_irq(&common->lock); - if (!exception_in_progress(common)) - common->state = FSG_STATE_DATA_PHASE; - spin_unlock_irq(&common->lock); + spin_lock_irqsave(&fsg->lock, flags); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_DATA_PHASE; + spin_unlock_irqrestore(&fsg->lock, flags); - if (do_scsi_command(common) || finish_reply(common)) + if (do_scsi_command(fsg) || finish_reply(fsg)) continue; - spin_lock_irq(&common->lock); - if (!exception_in_progress(common)) - common->state = FSG_STATE_STATUS_PHASE; - spin_unlock_irq(&common->lock); + spin_lock_irqsave(&fsg->lock, flags); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_STATUS_PHASE; + spin_unlock_irqrestore(&fsg->lock, flags); - if (send_status(common)) + if (send_status(fsg)) 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) < 0) { - struct fsg_lun *curlun = common->luns; - unsigned i = common->nluns; - - down_write(&common->filesem); - for (; i--; ++curlun) { - if (!fsg_lun_is_open(curlun)) - continue; - - fsg_lun_close(curlun); - curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + spin_lock_irqsave(&fsg->lock, flags); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irqrestore(&fsg->lock, flags); } - up_write(&common->filesem); - } + + spin_lock_irqsave(&fsg->lock, flags); + fsg->thread_task = NULL; + spin_unlock_irqrestore(&fsg->lock, flags); + + /* In case we are exiting because of a signal, unregister the + * gadget driver and close the backing file. */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) + close_all_backing_files(fsg); /* 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 (unlikely(rc < 0)) - goto error_release; - 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 (unlikely(!curlun)) { - rc = -ENOMEM; - goto error_release; - } - 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; - -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - /* use "usb_mass_storage" platform device as parent */ - curlun->dev.parent = &cfg->pdev->dev; -#else - curlun->dev.parent = &gadget->dev; -#endif - /* 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 */ - bh = common->buffhds; - i = FSG_NUM_BUFFERS; - goto buffhds_first_it; - do { - bh->next = bh + 1; - ++bh; -buffhds_first_it: - bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); - if (unlikely(!bh->buf)) { - rc = -ENOMEM; - goto error_release; - } - } while (--i); - bh->next = common->buffhds; - - - /* Prepare inquiryString */ - if (cfg->release != 0xffff) { - i = cfg->release; - } else { - i = 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_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); - init_waitqueue_head(&common->fsg_wait); -#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); - return ERR_PTR(rc); -} - - -static void fsg_common_release(struct kref *ref) -{ - struct fsg_common *common = container_of(ref, struct fsg_common, ref); - - /* 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); - } - - if (likely(common->luns)) { - struct fsg_lun *lun = common->luns; - unsigned i = common->nluns; - - /* In error recovery common->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); - } - - { - struct fsg_buffhd *bh = common->buffhds; - unsigned i = FSG_NUM_BUFFERS; - do { - kfree(bh->buf); - } while (++bh, --i); - } - - if (common->free_storage_on_release) - kfree(common); + complete_and_exit(&fsg->thread_notifier, 0); } /*-------------------------------------------------------------------------*/ +/* If the next two routines are called while the gadget is registered, + * the caller must own fsg->filesem for writing. */ -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) +static int open_backing_file(struct fsg_dev *fsg, struct lun *curlun, + const char *filename) { - struct fsg_dev *fsg = fsg_from_func(f); - struct fsg_common *common = fsg->common; + int ro; + struct file *filp = NULL; + int rc = -EINVAL; + struct inode *inode = NULL; + loff_t size; + loff_t num_sectors; + loff_t min_sectors; - DBG(fsg, "unbind\n"); - if (fsg->common->fsg == fsg) { - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - /* FIXME: make interruptible or killable somehow? */ - wait_event(common->fsg_wait, common->fsg != fsg); + /* 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); } - fsg_common_put(common); - usb_free_descriptors(fsg->function.descriptors); - usb_free_descriptors(fsg->function.hs_descriptors); - switch_dev_unregister(&fsg->sdev); - kfree(fsg); -} + 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; + } -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 i; - struct usb_ep *ep; + /* 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; - 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; - - /* Copy descriptors */ - f->descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - 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 = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) { - usb_free_descriptors(f->descriptors); - return -ENOMEM; + 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 sectors */ + min_sectors = 1; + if (curlun->cdrom) { + num_sectors &= ~3; /* Reduce to a multiple of 2048 */ +#if 0 + min_sectors = 300*4; /* Smallest track is 300 frames */ +#endif + 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; + } - return 0; + get_file(filp); + curlun->ro = ro; + curlun->filp = filp; + curlun->file_length = size; + curlun->num_sectors = num_sectors; + LDBG(curlun, "open backing file: %s size: %lld num_sectors: %lld\n", + filename, size, num_sectors); + rc = 0; + adjust_wake_lock(fsg); -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - return -ENOTSUPP; -} - - -/****************************** ADD FUNCTION ******************************/ - -static struct usb_gadget_strings *fsg_strings_array[] = { - &fsg_stringtab, - NULL, -}; - -static ssize_t print_switch_name(struct switch_dev *sdev, char *buf) -{ - return sprintf(buf, "%s\n", FUNCTION_NAME); -} - -static ssize_t print_switch_state(struct switch_dev *sdev, char *buf) -{ - struct fsg_dev *fsg = container_of(sdev, struct fsg_dev, sdev); - return sprintf(buf, "%s\n", (fsg->common->new_fsg ? "online" : "offline")); -} - -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; - - the_fsg = fsg; - fsg->sdev.name = FUNCTION_NAME; - fsg->sdev.print_name = print_switch_name; - fsg->sdev.print_state = print_switch_state; - rc = switch_dev_register(&fsg->sdev); - if (rc < 0) - return rc; - -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - fsg->function.name = FUNCTION_NAME; -#else - fsg->function.name = FSG_DRIVER_DESC; -#endif - fsg->function.strings = fsg_strings_array; - 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 (unlikely(rc)) - kfree(fsg); - else - fsg_common_get(fsg->common); +out: + filp_close(filp, current->files); 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) +static void close_backing_file(struct fsg_dev *fsg, struct lun *curlun) { - struct fsg_lun_config *lun; - unsigned i; + if (curlun->filp) { + int rc; - /* 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; + /* + * XXX: San: Ugly hack here added to ensure that + * our pages get synced to disk. + * Also drop caches here just to be extra-safe + */ + rc = vfs_fsync(curlun->filp, curlun->filp->f_path.dentry, 1); + if (rc < 0) + printk(KERN_ERR "ums: Error syncing data (%d)\n", rc); + /* drop_pagecache and drop_slab are no longer available */ + /* drop_pagecache(); */ + /* drop_slab(); */ + + LDBG(curlun, "close backing file\n"); + fput(curlun->filp); + curlun->filp = NULL; + adjust_wake_lock(fsg); + } +} + +static void close_all_backing_files(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + close_backing_file(fsg, &fsg->luns[i]); +} + +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_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; + + DBG(fsg, "store_file: \"%s\"\n", buf); +#if 0 + /* disabled because we need to allow closing the backing file if the media was removed */ + if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; /* "Door is locked" */ + } +#endif + + /* Remove a trailing newline */ + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; + + /* Eject current medium */ + down_write(&fsg->filesem); + if (backing_file_is_open(curlun)) { + close_backing_file(fsg, curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; } - /* 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; + /* Load new medium */ + if (count > 0 && buf[0]) { + rc = open_backing_file(fsg, curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; + } + up_write(&fsg->filesem); + return (rc < 0 ? rc : count); } -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) + +static DEVICE_ATTR(file, 0444, show_file, store_file); + +/*-------------------------------------------------------------------------*/ + +static void fsg_release(struct kref *ref) { - struct fsg_config cfg; - fsg_config_from_params(&cfg, params); - return fsg_common_init(common, cdev, &cfg); + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); + + kfree(fsg->luns); + kfree(fsg); } -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE +static void lun_release(struct device *dev) +{ + struct fsg_dev *fsg = dev_get_drvdata(dev); -static struct fsg_config fsg_cfg; + kref_put(&fsg->ref, fsg_release); +} -static int fsg_probe(struct platform_device *pdev) + +/*-------------------------------------------------------------------------*/ + +static int __init fsg_alloc(void) +{ + struct fsg_dev *fsg; + + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + if (!fsg) + return -ENOMEM; + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->filesem); + kref_init(&fsg->ref); + init_completion(&fsg->thread_notifier); + + the_fsg = fsg; + return 0; +} + +static ssize_t print_switch_name(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_NAME); +} + +static ssize_t print_switch_state(struct switch_dev *sdev, char *buf) +{ + struct fsg_dev *fsg = container_of(sdev, struct fsg_dev, sdev); + return sprintf(buf, "%s\n", (fsg->ums_state ? "online" : "offline")); +} + +static void +fsg_function_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + int i; + struct lun *curlun; + + DBG(fsg, "fsg_function_unbind\n"); + clear_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Unregister the sysfs attribute files and the LUNs */ + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_file); + device_unregister(&curlun->dev); + curlun->registered = 0; + } + } + + /* If the thread isn't already dead, tell it to exit now */ + if (fsg->state != FSG_STATE_TERMINATED) { + raise_exception(fsg, FSG_STATE_EXIT); + wait_for_completion(&fsg->thread_notifier); + + /* The cleanup routine waits for this completion also */ + complete(&fsg->thread_notifier); + } + + /* Free the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + kfree(fsg->buffhds[i].buf); + fsg->buffhds[i].buf = NULL; + } + switch_dev_unregister(&the_fsg->sdev); +} + +static int +fsg_function_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct fsg_dev *fsg = func_to_dev(f); + int rc; + int i; + int id; + struct lun *curlun; + struct usb_ep *ep; + char *pathbuf, *p; + + fsg->cdev = cdev; + DBG(fsg, "fsg_function_bind\n"); + + dev_attr_file.attr.mode = 0644; + + /* Find out how many LUNs there should be */ + i = fsg->nluns; + if (i == 0) + i = 1; + if (i > MAX_LUNS) { + ERROR(fsg, "invalid number of LUNs: %d\n", i); + rc = -EINVAL; + goto out; + } + + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ + fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); + if (!fsg->luns) { + rc = -ENOMEM; + goto out; + } + fsg->nluns = i; + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + curlun->ro = 0; + if (fsg->cdrom_lun & (1 << i)) { + curlun->cdrom = 1; + curlun->ro = 1; + } + curlun->dev.release = lun_release; + /* use "usb_mass_storage" platform device as parent if available */ + if (fsg->pdev) + curlun->dev.parent = &fsg->pdev->dev; + else + curlun->dev.parent = &cdev->gadget->dev; + dev_set_drvdata(&curlun->dev, fsg); + dev_set_name(&curlun->dev,"lun%d", i); + + rc = device_register(&curlun->dev); + if (rc != 0) { + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + goto out; + } + rc = device_create_file(&curlun->dev, &dev_attr_file); + if (rc != 0) { + ERROR(fsg, "device_create_file failed: %d\n", rc); + device_unregister(&curlun->dev); + goto out; + } + curlun->registered = 1; + kref_get(&fsg->ref); + } + + /* allocate interface ID(s) */ + id = usb_interface_id(c, f); + if (id < 0) + return id; + intf_desc.bInterfaceNumber = id; + + ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; /* claim the endpoint */ + fsg->bulk_in = ep; + + ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_out_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; /* claim the endpoint */ + fsg->bulk_out = ep; + + rc = -ENOMEM; + + if (gadget_is_dualspeed(cdev->gadget)) { + /* 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; + + f->hs_descriptors = hs_function; + } + + /* Allocate the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and + * interrupt-in) endpoint. */ + bh->buf = kmalloc(fsg->buf_size, GFP_KERNEL); + if (!bh->buf) + goto out; + bh->next = bh + 1; + } + fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + + fsg->thread_task = kthread_create(fsg_main_thread, fsg, + shortname); + if (IS_ERR(fsg->thread_task)) { + rc = PTR_ERR(fsg->thread_task); + ERROR(fsg, "kthread_create failed: %d\n", rc); + goto out; + } + + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if (backing_file_is_open(curlun)) { + p = NULL; + if (pathbuf) { + p = d_path(&curlun->filp->f_path, + pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = NULL; + } + LINFO(curlun, "ro=%d, file: %s\n", + curlun->ro, (p ? p : "(error)")); + } + } + kfree(pathbuf); + + set_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Tell the thread to start working */ + wake_up_process(fsg->thread_task); + return 0; + +autoconf_fail: + ERROR(fsg, "unable to autoconfigure all endpoints\n"); + rc = -ENOTSUPP; + +out: + DBG(fsg, "fsg_function_bind failed: %d\n", rc); + fsg->state = FSG_STATE_TERMINATED; /* The thread is dead */ + fsg_function_unbind(c, f); + close_all_backing_files(fsg); + return rc; +} + +static int fsg_function_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct fsg_dev *fsg = func_to_dev(f); + DBG(fsg, "fsg_function_set_alt intf: %d alt: %d\n", intf, alt); + fsg->new_config = 1; + do_set_interface(fsg, 0); + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); + return 0; +} + +static void fsg_function_disable(struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + DBG(fsg, "fsg_function_disable\n"); + if (fsg->new_config) + do_set_interface(fsg, -1); + fsg->new_config = 0; + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); +} + +static int __init fsg_probe(struct platform_device *pdev) { struct usb_mass_storage_platform_data *pdata = pdev->dev.platform_data; - int i, nluns; + struct fsg_dev *fsg = the_fsg; - printk(KERN_INFO "fsg_probe pdev: %p, pdata: %p\n", pdev, pdata); - if (!pdata) - return -1; + fsg->pdev = pdev; + printk(KERN_INFO "fsg_probe pdata: %p\n", pdata); - nluns = pdata->nluns; - if (nluns > FSG_MAX_LUNS) - nluns = FSG_MAX_LUNS; - fsg_cfg.nluns = nluns; - for (i = 0; i < nluns; i++) - fsg_cfg.luns[i].removable = 1; + if (pdata) { + if (pdata->vendor) + fsg->vendor = pdata->vendor; - fsg_cfg.vendor_name = pdata->vendor; - fsg_cfg.product_name = pdata->product; - fsg_cfg.release = pdata->release; - fsg_cfg.can_stall = 0; - fsg_cfg.pdev = pdev; + if (pdata->product) + fsg->product = pdata->product; + + if (pdata->release) + fsg->release = pdata->release; + fsg->nluns = pdata->nluns; + fsg->cdrom_lun = pdata->cdrom_lun; + } return 0; } static struct platform_driver fsg_platform_driver = { - .driver = { .name = FUNCTION_NAME, }, + .driver = { .name = "usb_mass_storage", }, .probe = fsg_probe, }; int mass_storage_bind_config(struct usb_configuration *c) { - struct fsg_common *common = fsg_common_init(NULL, c->cdev, &fsg_cfg); - if (IS_ERR(common)) - return -1; - return fsg_add(c->cdev, c, common); + int rc; + struct fsg_dev *fsg; + + printk(KERN_INFO "mass_storage_bind_config\n"); + rc = fsg_alloc(); + if (rc) + return rc; + fsg = the_fsg; + + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->filesem); + kref_init(&fsg->ref); + init_completion(&fsg->thread_notifier); + + the_fsg->buf_size = BULK_BUFFER_SIZE; + + the_fsg->sdev.name = DRIVER_NAME; + the_fsg->sdev.print_name = print_switch_name; + the_fsg->sdev.print_state = print_switch_state; + rc = switch_dev_register(&the_fsg->sdev); + if (rc < 0) + goto err_switch_dev_register; + + rc = platform_driver_register(&fsg_platform_driver); + if (rc != 0) + goto err_platform_driver_register; + + wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND, + "usb_mass_storage"); + + fsg->cdev = c->cdev; + fsg->function.name = shortname; + fsg->function.descriptors = fs_function; + fsg->function.bind = fsg_function_bind; + fsg->function.unbind = fsg_function_unbind; + fsg->function.setup = fsg_function_setup; + fsg->function.set_alt = fsg_function_set_alt; + fsg->function.disable = fsg_function_disable; + + usb_register_notifier(&connect_status_notifier); + rc = usb_add_function(c, &fsg->function); + if (rc != 0) + goto err_usb_add_function; + + + return 0; + +err_usb_add_function: + wake_lock_destroy(&the_fsg->wake_lock); + platform_driver_unregister(&fsg_platform_driver); +err_platform_driver_register: + switch_dev_unregister(&the_fsg->sdev); +err_switch_dev_register: + kref_put(&the_fsg->ref, fsg_release); + + return rc; } static struct android_usb_function mass_storage_function = { - .name = FUNCTION_NAME, + .name = "usb_mass_storage", .bind_config = mass_storage_bind_config, }; static int __init init(void) { - int rc; printk(KERN_INFO "f_mass_storage init\n"); - rc = platform_driver_register(&fsg_platform_driver); - if (rc != 0) - return rc; android_register_function(&mass_storage_function); return 0; -}module_init(init); - -#endif /* CONFIG_USB_ANDROID_MASS_STORAGE */ +} +module_init(init); diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c deleted file mode 100644 index c0e67a2d..00000000 --- a/drivers/usb/gadget/f_mtp.c +++ /dev/null @@ -1,1265 +0,0 @@ -/* - * Gadget Function Driver for MTP - * - * Copyright (C) 2010 Google, Inc. - * Author: Mike Lockwood - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define BULK_BUFFER_SIZE 16384 -#define INTR_BUFFER_SIZE 28 - -/* String IDs */ -#define INTERFACE_STRING_INDEX 0 - -/* values for mtp_dev.state */ -#define STATE_OFFLINE 0 /* initial state, disconnected */ -#define STATE_READY 1 /* ready for userspace calls */ -#define STATE_BUSY 2 /* processing userspace calls */ -#define STATE_CANCELED 3 /* transaction canceled by host */ -#define STATE_ERROR 4 /* error from completion routine */ - -/* number of tx and rx requests to allocate */ -#define TX_REQ_MAX 4 -#define RX_REQ_MAX 2 - -/* ID for Microsoft MTP OS String */ -#define MTP_OS_STRING_ID 0xEE - -/* MTP class reqeusts */ -#define MTP_REQ_CANCEL 0x64 -#define MTP_REQ_GET_EXT_EVENT_DATA 0x65 -#define MTP_REQ_RESET 0x66 -#define MTP_REQ_GET_DEVICE_STATUS 0x67 - -/* constants for device status */ -#define MTP_RESPONSE_OK 0x2001 -#define MTP_RESPONSE_DEVICE_BUSY 0x2019 - -static const char shortname[] = "mtp_usb"; - -struct mtp_dev { - struct usb_function function; - struct usb_composite_dev *cdev; - spinlock_t lock; - - /* appear as MTP or PTP when enumerating */ - int interface_mode; - - struct usb_ep *ep_in; - struct usb_ep *ep_out; - struct usb_ep *ep_intr; - - int state; - - /* synchronize access to our device file */ - atomic_t open_excl; - /* to enforce only one ioctl at a time */ - atomic_t ioctl_excl; - - struct list_head tx_idle; - - wait_queue_head_t read_wq; - wait_queue_head_t write_wq; - wait_queue_head_t intr_wq; - struct usb_request *rx_req[RX_REQ_MAX]; - struct usb_request *intr_req; - int rx_done; - /* true if interrupt endpoint is busy */ - int intr_busy; - - /* for processing MTP_SEND_FILE and MTP_RECEIVE_FILE - * ioctls on a work queue - */ - struct workqueue_struct *wq; - struct work_struct send_file_work; - struct work_struct receive_file_work; - struct file *xfer_file; - loff_t xfer_file_offset; - int64_t xfer_file_length; - int xfer_result; -}; - -static struct usb_interface_descriptor mtp_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, - .bInterfaceProtocol = 0, -}; - -static struct usb_interface_descriptor ptp_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_STILL_IMAGE, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 1, -}; - -static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor mtp_intr_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), - .bInterval = 6, -}; - -static struct usb_descriptor_header *fs_mtp_descs[] = { - (struct usb_descriptor_header *) &mtp_interface_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_mtp_descs[] = { - (struct usb_descriptor_header *) &mtp_interface_desc, - (struct usb_descriptor_header *) &mtp_highspeed_in_desc, - (struct usb_descriptor_header *) &mtp_highspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *fs_ptp_descs[] = { - (struct usb_descriptor_header *) &ptp_interface_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_ptp_descs[] = { - (struct usb_descriptor_header *) &ptp_interface_desc, - (struct usb_descriptor_header *) &mtp_highspeed_in_desc, - (struct usb_descriptor_header *) &mtp_highspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_string mtp_string_defs[] = { - /* Naming interface "MTP" so libmtp will recognize us */ - [INTERFACE_STRING_INDEX].s = "MTP", - { }, /* end of list */ -}; - -static struct usb_gadget_strings mtp_string_table = { - .language = 0x0409, /* en-US */ - .strings = mtp_string_defs, -}; - -static struct usb_gadget_strings *mtp_strings[] = { - &mtp_string_table, - NULL, -}; - -/* Microsoft MTP OS String */ -static u8 mtp_os_string[] = { - 18, /* sizeof(mtp_os_string) */ - USB_DT_STRING, - /* Signature field: "MSFT100" */ - 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, - /* vendor code */ - 1, - /* padding */ - 0 -}; - -/* Microsoft Extended Configuration Descriptor Header Section */ -struct mtp_ext_config_desc_header { - __le32 dwLength; - __u16 bcdVersion; - __le16 wIndex; - __u8 bCount; - __u8 reserved[7]; -}; - -/* Microsoft Extended Configuration Descriptor Function Section */ -struct mtp_ext_config_desc_function { - __u8 bFirstInterfaceNumber; - __u8 bInterfaceCount; - __u8 compatibleID[8]; - __u8 subCompatibleID[8]; - __u8 reserved[6]; -}; - -/* MTP Extended Configuration Descriptor */ -struct { - struct mtp_ext_config_desc_header header; - struct mtp_ext_config_desc_function function; -} mtp_ext_config_desc = { - .header = { - .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), - .bcdVersion = __constant_cpu_to_le16(0x0100), - .wIndex = __constant_cpu_to_le16(4), - .bCount = __constant_cpu_to_le16(1), - }, - .function = { - .bFirstInterfaceNumber = 0, - .bInterfaceCount = 1, - .compatibleID = { 'M', 'T', 'P' }, - }, -}; - -struct mtp_device_status { - __le16 wLength; - __le16 wCode; -}; - -/* temporary variable used between mtp_open() and mtp_gadget_bind() */ -static struct mtp_dev *_mtp_dev; - -static inline struct mtp_dev *func_to_dev(struct usb_function *f) -{ - return container_of(f, struct mtp_dev, function); -} - -static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) -{ - struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) - return NULL; - - /* now allocate buffers for the requests */ - req->buf = kmalloc(buffer_size, GFP_KERNEL); - if (!req->buf) { - usb_ep_free_request(ep, req); - return NULL; - } - - return req; -} - -static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) -{ - if (req) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -static inline int _lock(atomic_t *excl) -{ - if (atomic_inc_return(excl) == 1) { - return 0; - } else { - atomic_dec(excl); - return -1; - } -} - -static inline void _unlock(atomic_t *excl) -{ - atomic_dec(excl); -} - -/* add a request to the tail of a list */ -static void req_put(struct mtp_dev *dev, struct list_head *head, - struct usb_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&req->list, head); - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* remove a request from the head of a list */ -static struct usb_request *req_get(struct mtp_dev *dev, struct list_head *head) -{ - unsigned long flags; - struct usb_request *req; - - spin_lock_irqsave(&dev->lock, flags); - if (list_empty(head)) { - req = 0; - } else { - req = list_first_entry(head, struct usb_request, list); - list_del(&req->list); - } - spin_unlock_irqrestore(&dev->lock, flags); - return req; -} - -static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - if (req->status != 0) - dev->state = STATE_ERROR; - - req_put(dev, &dev->tx_idle, req); - - wake_up(&dev->write_wq); -} - -static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - dev->rx_done = 1; - if (req->status != 0) - dev->state = STATE_ERROR; - - wake_up(&dev->read_wq); -} - -static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - DBG(dev->cdev, "mtp_complete_intr status: %d actual: %d\n", req->status, req->actual); - dev->intr_busy = 0; - if (req->status != 0) - dev->state = STATE_ERROR; - - wake_up(&dev->intr_wq); -} - -static int __init create_bulk_endpoints(struct mtp_dev *dev, - struct usb_endpoint_descriptor *in_desc, - struct usb_endpoint_descriptor *out_desc, - struct usb_endpoint_descriptor *intr_desc) -{ - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - struct usb_ep *ep; - int i; - - DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); - - ep = usb_ep_autoconfig(cdev->gadget, in_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_in = ep; - - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; - - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; - - ep = usb_ep_autoconfig(cdev->gadget, intr_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_intr = ep; - - /* now allocate requests for our endpoints */ - for (i = 0; i < TX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_in, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_in; - req_put(dev, &dev->tx_idle, req); - } - for (i = 0; i < RX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_out, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_out; - dev->rx_req[i] = req; - } - req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_intr; - dev->intr_req = req; - - return 0; - -fail: - printk(KERN_ERR "mtp_bind() could not allocate requests\n"); - return -1; -} - -static ssize_t mtp_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - struct mtp_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - int r = count, xfer; - int ret = 0; - - DBG(cdev, "mtp_read(%d)\n", count); - - if (count > BULK_BUFFER_SIZE) - return -EINVAL; - - /* we will block until we're online */ - DBG(cdev, "mtp_read: waiting for online state\n"); - ret = wait_event_interruptible(dev->read_wq, - dev->state != STATE_OFFLINE); - if (ret < 0) { - r = ret; - goto done; - } - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - return -ECANCELED; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - -requeue_req: - /* queue a request */ - req = dev->rx_req[0]; - req->length = count; - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); - if (ret < 0) { - r = -EIO; - goto done; - } else { - DBG(cdev, "rx %p queue\n", req); - } - - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->read_wq, dev->rx_done); - if (ret < 0) { - r = ret; - goto done; - } - if (dev->state == STATE_BUSY) { - /* If we got a 0-len packet, throw it back and try again. */ - if (req->actual == 0) - goto requeue_req; - - DBG(cdev, "rx %p %d\n", req, req->actual); - xfer = (req->actual < count) ? req->actual : count; - r = xfer; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; - } else - r = -EIO; - -done: - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - r = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - - DBG(cdev, "mtp_read returning %d\n", r); - return r; -} - -static ssize_t mtp_write(struct file *fp, const char __user *buf, - size_t count, loff_t *pos) -{ - struct mtp_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req = 0; - int r = count, xfer; - int sendZLP = 0; - int ret; - - DBG(cdev, "mtp_write(%d)\n", count); - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - return -ECANCELED; - } - if (dev->state == STATE_OFFLINE) { - spin_unlock_irq(&dev->lock); - return -ENODEV; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - - /* we need to send a zero length packet to signal the end of transfer - * if the transfer size is aligned to a packet boundary. - */ - if ((count & (dev->ep_in->maxpacket - 1)) == 0) { - sendZLP = 1; - } - - while (count > 0 || sendZLP) { - /* so we exit after sending ZLP */ - if (count == 0) - sendZLP = 0; - - if (dev->state != STATE_BUSY) { - DBG(cdev, "mtp_write dev->error\n"); - r = -EIO; - break; - } - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - ((req = req_get(dev, &dev->tx_idle)) - || dev->state != STATE_BUSY)); - if (!req) { - r = ret; - break; - } - - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; - else - xfer = count; - if (xfer && copy_from_user(req->buf, buf, xfer)) { - r = -EFAULT; - break; - } - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); - if (ret < 0) { - DBG(cdev, "mtp_write: xfer error %d\n", ret); - r = -EIO; - break; - } - - buf += xfer; - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - - if (req) - req_put(dev, &dev->tx_idle, req); - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - r = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - - DBG(cdev, "mtp_write returning %d\n", r); - return r; -} - -/* read from a local file and write to USB */ -static void send_file_work(struct work_struct *data) { - struct mtp_dev *dev = container_of(data, struct mtp_dev, send_file_work); - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req = 0; - struct file *filp; - loff_t offset; - int64_t count; - int xfer, ret; - int r = 0; - int sendZLP = 0; - - /* read our parameters */ - smp_rmb(); - filp = dev->xfer_file; - offset = dev->xfer_file_offset; - count = dev->xfer_file_length; - - DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); - - /* we need to send a zero length packet to signal the end of transfer - * if the transfer size is aligned to a packet boundary. - */ - if ((dev->xfer_file_length & (dev->ep_in->maxpacket - 1)) == 0) { - sendZLP = 1; - } - - while (count > 0 || sendZLP) { - /* so we exit after sending ZLP */ - if (count == 0) - sendZLP = 0; - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - (req = req_get(dev, &dev->tx_idle)) - || dev->state != STATE_BUSY); - if (!req) { - r = ret; - break; - } - - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; - else - xfer = count; - ret = vfs_read(filp, req->buf, xfer, &offset); - if (ret < 0) { - r = ret; - break; - } - xfer = ret; - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); - if (ret < 0) { - DBG(cdev, "send_file_work: xfer error %d\n", ret); - dev->state = STATE_ERROR; - r = -EIO; - break; - } - - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - - if (req) - req_put(dev, &dev->tx_idle, req); - - DBG(cdev, "send_file_work returning %d\n", r); - /* write the result */ - dev->xfer_result = r; - smp_wmb(); -} - -/* read from USB and write to a local file */ -static void receive_file_work(struct work_struct *data) -{ - struct mtp_dev *dev = container_of(data, struct mtp_dev, receive_file_work); - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *read_req = NULL, *write_req = NULL; - struct file *filp; - loff_t offset; - int64_t count; - int ret, cur_buf = 0; - int r = 0; - - /* read our parameters */ - smp_rmb(); - filp = dev->xfer_file; - offset = dev->xfer_file_offset; - count = dev->xfer_file_length; - - DBG(cdev, "receive_file_work(%lld)\n", count); - - while (count > 0 || write_req) { - if (count > 0) { - /* queue a request */ - read_req = dev->rx_req[cur_buf]; - cur_buf = (cur_buf + 1) % RX_REQ_MAX; - - read_req->length = (count > BULK_BUFFER_SIZE - ? BULK_BUFFER_SIZE : count); - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); - if (ret < 0) { - r = -EIO; - dev->state = STATE_ERROR; - break; - } - } - - if (write_req) { - DBG(cdev, "rx %p %d\n", write_req, write_req->actual); - ret = vfs_write(filp, write_req->buf, write_req->actual, - &offset); - DBG(cdev, "vfs_write %d\n", ret); - if (ret != write_req->actual) { - r = -EIO; - dev->state = STATE_ERROR; - break; - } - write_req = NULL; - } - - if (read_req) { - /* wait for our last read to complete */ - ret = wait_event_interruptible(dev->read_wq, - dev->rx_done || dev->state != STATE_BUSY); - if (ret < 0 || dev->state != STATE_BUSY) { - r = ret; - break; - } - /* if xfer_file_length is 0xFFFFFFFF, then we read until - * we get a zero length packet - */ - if (count != 0xFFFFFFFF) - count -= read_req->actual; - if (read_req->actual < read_req->length) { - /* short packet is used to signal EOF for sizes > 4 gig */ - DBG(cdev, "got short packet\n"); - count = 0; - } - - write_req = read_req; - read_req = NULL; - } - } - - DBG(cdev, "receive_file_work returning %d\n", r); - /* write the result */ - dev->xfer_result = r; - smp_wmb(); -} - -static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) -{ - struct usb_request *req; - int ret; - int length = event->length; - - DBG(dev->cdev, "mtp_send_event(%d)\n", event->length); - - if (length < 0 || length > INTR_BUFFER_SIZE) - return -EINVAL; - - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->intr_wq, !dev->intr_busy || dev->state == STATE_OFFLINE); - if (ret < 0) - return ret; - if (dev->state == STATE_OFFLINE) - return -ENODEV; - req = dev->intr_req; - if (copy_from_user(req->buf, (void __user *)event->data, length)) - return -EFAULT; - req->length = length; - dev->intr_busy = 1; - ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); - if (ret) - dev->intr_busy = 0; - - return ret; -} - -static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) -{ - struct mtp_dev *dev = fp->private_data; - struct file *filp = NULL; - int ret = -EINVAL; - - if (_lock(&dev->ioctl_excl)) - return -EBUSY; - - switch (code) { - case MTP_SEND_FILE: - case MTP_RECEIVE_FILE: - { - struct mtp_file_range mfr; - struct work_struct *work; - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - ret = -ECANCELED; - goto out; - } - if (dev->state == STATE_OFFLINE) { - spin_unlock_irq(&dev->lock); - ret = -ENODEV; - goto out; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - - if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { - ret = -EFAULT; - goto fail; - } - /* hold a reference to the file while we are working with it */ - filp = fget(mfr.fd); - if (!filp) { - ret = -EBADF; - goto fail; - } - - /* write the parameters */ - dev->xfer_file = filp; - dev->xfer_file_offset = mfr.offset; - dev->xfer_file_length = mfr.length; - smp_wmb(); - - if (code == MTP_SEND_FILE) - work = &dev->send_file_work; - else - work = &dev->receive_file_work; - - /* We do the file transfer on a work queue so it will run - * in kernel context, which is necessary for vfs_read and - * vfs_write to use our buffers in the kernel address space. - */ - queue_work(dev->wq, work); - /* wait for operation to complete */ - flush_workqueue(dev->wq); - fput(filp); - - /* read the result */ - smp_rmb(); - ret = dev->xfer_result; - break; - } - case MTP_SET_INTERFACE_MODE: - if (value == MTP_INTERFACE_MODE_MTP || - value == MTP_INTERFACE_MODE_PTP) { - dev->interface_mode = value; - if (value == MTP_INTERFACE_MODE_PTP) { - dev->function.descriptors = fs_ptp_descs; - dev->function.hs_descriptors = hs_ptp_descs; - } else { - dev->function.descriptors = fs_mtp_descs; - dev->function.hs_descriptors = hs_mtp_descs; - } - ret = 0; - } - break; - case MTP_SEND_EVENT: - { - struct mtp_event event; - /* return here so we don't change dev->state below, - * which would interfere with bulk transfer state. - */ - if (copy_from_user(&event, (void __user *)value, sizeof(event))) - ret = -EFAULT; - else - ret = mtp_send_event(dev, &event); - goto out; - } - } - -fail: - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - ret = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); -out: - _unlock(&dev->ioctl_excl); - DBG(dev->cdev, "ioctl returning %d\n", ret); - return ret; -} - -static int mtp_open(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "mtp_open\n"); - if (_lock(&_mtp_dev->open_excl)) - return -EBUSY; - - /* clear any error condition */ - if (_mtp_dev->state != STATE_OFFLINE) - _mtp_dev->state = STATE_READY; - - fp->private_data = _mtp_dev; - return 0; -} - -static int mtp_release(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "mtp_release\n"); - - _unlock(&_mtp_dev->open_excl); - return 0; -} - -/* file operations for /dev/mtp_usb */ -static const struct file_operations mtp_fops = { - .owner = THIS_MODULE, - .read = mtp_read, - .write = mtp_write, - .unlocked_ioctl = mtp_ioctl, - .open = mtp_open, - .release = mtp_release, -}; - -static struct miscdevice mtp_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = shortname, - .fops = &mtp_fops, -}; - -static int -mtp_function_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct mtp_dev *dev = func_to_dev(f); - int id; - int ret; - - dev->cdev = cdev; - DBG(cdev, "mtp_function_bind dev: %p\n", dev); - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - mtp_interface_desc.bInterfaceNumber = id; - - /* allocate endpoints */ - ret = create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, - &mtp_fullspeed_out_desc, &mtp_intr_desc); - if (ret) - return ret; - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - mtp_highspeed_in_desc.bEndpointAddress = - mtp_fullspeed_in_desc.bEndpointAddress; - mtp_highspeed_out_desc.bEndpointAddress = - mtp_fullspeed_out_desc.bEndpointAddress; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - f->name, dev->ep_in->name, dev->ep_out->name); - return 0; -} - -static void -mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct mtp_dev *dev = func_to_dev(f); - struct usb_request *req; - int i; - - spin_lock_irq(&dev->lock); - while ((req = req_get(dev, &dev->tx_idle))) - mtp_request_free(req, dev->ep_in); - for (i = 0; i < RX_REQ_MAX; i++) - mtp_request_free(dev->rx_req[i], dev->ep_out); - mtp_request_free(dev->intr_req, dev->ep_intr); - dev->state = STATE_OFFLINE; - spin_unlock_irq(&dev->lock); - wake_up(&dev->intr_wq); - - misc_deregister(&mtp_device); - kfree(_mtp_dev); - _mtp_dev = NULL; -} - -static int mtp_function_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct mtp_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = dev->cdev; - 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); - unsigned long flags; - - /* do nothing if we are disabled */ - if (dev->function.disabled) - return value; - - VDBG(cdev, "mtp_function_setup " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - - /* Handle MTP OS string */ - if (dev->interface_mode == MTP_INTERFACE_MODE_MTP - && ctrl->bRequestType == - (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) - && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR - && (w_value >> 8) == USB_DT_STRING - && (w_value & 0xFF) == MTP_OS_STRING_ID) { - value = (w_length < sizeof(mtp_os_string) - ? w_length : sizeof(mtp_os_string)); - memcpy(cdev->req->buf, mtp_os_string, value); - /* return here since composite.c will send for us */ - return value; - } - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { - /* Handle MTP OS descriptor */ - DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", - ctrl->bRequest, w_index, w_value, w_length); - - if (dev->interface_mode == MTP_INTERFACE_MODE_MTP - && ctrl->bRequest == 1 - && (ctrl->bRequestType & USB_DIR_IN) - && (w_index == 4 || w_index == 5)) { - value = (w_length < sizeof(mtp_ext_config_desc) ? - w_length : sizeof(mtp_ext_config_desc)); - memcpy(cdev->req->buf, &mtp_ext_config_desc, value); - } - } - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { - DBG(cdev, "class request: %d index: %d value: %d length: %d\n", - ctrl->bRequest, w_index, w_value, w_length); - - if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0 - && w_value == 0) { - DBG(cdev, "MTP_REQ_CANCEL\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (dev->state == STATE_BUSY) { - dev->state = STATE_CANCELED; - wake_up(&dev->read_wq); - wake_up(&dev->write_wq); - } - spin_unlock_irqrestore(&dev->lock, flags); - - /* We need to queue a request to read the remaining - * bytes, but we don't actually need to look at - * the contents. - */ - value = w_length; - } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS - && w_index == 0 && w_value == 0) { - struct mtp_device_status *status = cdev->req->buf; - status->wLength = - __constant_cpu_to_le16(sizeof(*status)); - - DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n"); - spin_lock_irqsave(&dev->lock, flags); - /* device status is "busy" until we report - * the cancelation to userspace - */ - if (dev->state == STATE_BUSY - || dev->state == STATE_CANCELED) - status->wCode = - __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); - else - status->wCode = - __cpu_to_le16(MTP_RESPONSE_OK); - spin_unlock_irqrestore(&dev->lock, flags); - value = sizeof(*status); - } - } - - /* respond with data transfer or status phase? */ - if (value >= 0) { - int rc; - cdev->req->zero = value < w_length; - cdev->req->length = value; - rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); - if (rc < 0) - ERROR(cdev, "%s setup response queue error\n", __func__); - } - - if (value == -EOPNOTSUPP) - VDBG(cdev, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - return value; -} - -static int mtp_function_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct mtp_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = f->config->cdev; - int ret; - - DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt); - ret = usb_ep_enable(dev->ep_in, - ep_choose(cdev->gadget, - &mtp_highspeed_in_desc, - &mtp_fullspeed_in_desc)); - if (ret) - return ret; - ret = usb_ep_enable(dev->ep_out, - ep_choose(cdev->gadget, - &mtp_highspeed_out_desc, - &mtp_fullspeed_out_desc)); - if (ret) { - usb_ep_disable(dev->ep_in); - return ret; - } - ret = usb_ep_enable(dev->ep_intr, &mtp_intr_desc); - if (ret) { - usb_ep_disable(dev->ep_out); - usb_ep_disable(dev->ep_in); - return ret; - } - dev->state = STATE_READY; - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - return 0; -} - -static void mtp_function_disable(struct usb_function *f) -{ - struct mtp_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = dev->cdev; - - DBG(cdev, "mtp_function_disable\n"); - dev->state = STATE_OFFLINE; - usb_ep_disable(dev->ep_in); - usb_ep_disable(dev->ep_out); - usb_ep_disable(dev->ep_intr); - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - wake_up(&dev->intr_wq); - - VDBG(cdev, "%s disabled\n", dev->function.name); -} - -static int mtp_bind_config(struct usb_configuration *c) -{ - struct mtp_dev *dev; - int ret = 0; - - printk(KERN_INFO "mtp_bind_config\n"); - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - /* allocate a string ID for our interface */ - if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) { - ret = usb_string_id(c->cdev); - if (ret < 0) - return ret; - mtp_string_defs[INTERFACE_STRING_INDEX].id = ret; - mtp_interface_desc.iInterface = ret; - } - - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_wq); - init_waitqueue_head(&dev->intr_wq); - atomic_set(&dev->open_excl, 0); - atomic_set(&dev->ioctl_excl, 0); - INIT_LIST_HEAD(&dev->tx_idle); - - dev->wq = create_singlethread_workqueue("f_mtp"); - if (!dev->wq) - goto err1; - INIT_WORK(&dev->send_file_work, send_file_work); - INIT_WORK(&dev->receive_file_work, receive_file_work); - - dev->cdev = c->cdev; - dev->function.name = "mtp"; - dev->function.strings = mtp_strings, - dev->function.descriptors = fs_mtp_descs; - dev->function.hs_descriptors = hs_mtp_descs; - dev->function.bind = mtp_function_bind; - dev->function.unbind = mtp_function_unbind; - dev->function.setup = mtp_function_setup; - dev->function.set_alt = mtp_function_set_alt; - dev->function.disable = mtp_function_disable; - - /* MTP mode by default */ - dev->interface_mode = MTP_INTERFACE_MODE_MTP; - - /* _mtp_dev must be set before calling usb_gadget_register_driver */ - _mtp_dev = dev; - - ret = misc_register(&mtp_device); - if (ret) - goto err1; - - ret = usb_add_function(c, &dev->function); - if (ret) - goto err2; - - return 0; - -err2: - misc_deregister(&mtp_device); -err1: - if (dev->wq) - destroy_workqueue(dev->wq); - kfree(dev); - printk(KERN_ERR "mtp gadget driver failed to initialize\n"); - return ret; -} - -static struct android_usb_function mtp_function = { - .name = "mtp", - .bind_config = mtp_bind_config, -}; - -static int __init init(void) -{ - printk(KERN_INFO "f_mtp init\n"); - android_register_function(&mtp_function); - return 0; -} -module_init(init); diff --git a/drivers/usb/gadget/f_mtp.h b/drivers/usb/gadget/f_mtp.h deleted file mode 100644 index e4fd8806..00000000 --- a/drivers/usb/gadget/f_mtp.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Gadget Function Driver for MTP - * - * Copyright (C) 2010 Google, Inc. - * Author: Mike Lockwood - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#ifndef __LINUX_USB_F_MTP_H -#define __LINUX_USB_F_MTP_H - -/* Constants for MTP_SET_INTERFACE_MODE */ -#define MTP_INTERFACE_MODE_MTP 0 -#define MTP_INTERFACE_MODE_PTP 1 - - -struct mtp_file_range { - /* file descriptor for file to transfer */ - int fd; - /* offset in file for start of transfer */ - loff_t offset; - /* number of bytes to transfer */ - int64_t length; -}; - -struct mtp_event { - /* size of the event */ - size_t length; - /* event data to send */ - void *data; -}; - -/* Sends the specified file range to the host */ -#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) -/* Receives data from the host and writes it to a file. - * The file is created if it does not exist. - */ -#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) -/* Sets the driver mode to either MTP or PTP */ -#define MTP_SET_INTERFACE_MODE _IOW('M', 2, int) -/* Sends an event to the host via the interrupt endpoint */ -#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) - -#endif /* __LINUX_USB_F_MTP_H */ diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 2d9d97ec..689093b2 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -4,8 +4,6 @@ * 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 @@ -24,7 +22,6 @@ /* #define VERBOSE_DEBUG */ -#include #include #include #include @@ -123,7 +120,7 @@ static unsigned int bitrate(struct usb_gadget *g) /* interface descriptor: */ -static struct usb_interface_descriptor rndis_control_intf = { +static struct usb_interface_descriptor rndis_control_intf __initdata = { .bLength = sizeof rndis_control_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -133,7 +130,7 @@ static struct usb_interface_descriptor rndis_control_intf = { #ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS /* "Wireless" RNDIS; auto-detected by Windows */ .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER, - .bInterfaceSubClass = 1, + .bInterfaceSubClass = 1, .bInterfaceProtocol = 3, #else .bInterfaceClass = USB_CLASS_COMM, @@ -143,7 +140,7 @@ static struct usb_interface_descriptor rndis_control_intf = { /* .iInterface = DYNAMIC */ }; -static struct usb_cdc_header_desc header_desc = { +static struct usb_cdc_header_desc header_desc __initdata = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, @@ -151,7 +148,7 @@ static struct usb_cdc_header_desc header_desc = { .bcdCDC = cpu_to_le16(0x0110), }; -static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { +static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = { .bLength = sizeof call_mgmt_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, @@ -160,15 +157,15 @@ static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { .bDataInterface = 0x01, }; -static struct usb_cdc_acm_descriptor rndis_acm_descriptor = { - .bLength = sizeof rndis_acm_descriptor, +static struct usb_cdc_acm_descriptor acm_descriptor __initdata = { + .bLength = sizeof acm_descriptor, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, .bmCapabilities = 0x00, }; -static struct usb_cdc_union_desc rndis_union_desc = { +static struct usb_cdc_union_desc rndis_union_desc __initdata = { .bLength = sizeof(rndis_union_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_UNION_TYPE, @@ -178,7 +175,7 @@ static struct usb_cdc_union_desc rndis_union_desc = { /* the data interface has two bulk endpoints */ -static struct usb_interface_descriptor rndis_data_intf = { +static struct usb_interface_descriptor rndis_data_intf __initdata = { .bLength = sizeof rndis_data_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -190,23 +187,9 @@ static struct usb_interface_descriptor rndis_data_intf = { /* .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 = { +static struct usb_endpoint_descriptor fs_notify_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -216,7 +199,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = { .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, }; -static struct usb_endpoint_descriptor fs_in_desc = { +static struct usb_endpoint_descriptor fs_in_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -224,7 +207,7 @@ static struct usb_endpoint_descriptor fs_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor fs_out_desc = { +static struct usb_endpoint_descriptor fs_out_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -232,13 +215,12 @@ static struct usb_endpoint_descriptor fs_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *eth_fs_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, +static struct usb_descriptor_header *eth_fs_function[] __initdata = { /* 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 *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &fs_notify_desc, /* data interface has no altsetting */ @@ -250,7 +232,7 @@ static struct usb_descriptor_header *eth_fs_function[] = { /* high speed support: */ -static struct usb_endpoint_descriptor hs_notify_desc = { +static struct usb_endpoint_descriptor hs_notify_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -259,7 +241,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; -static struct usb_endpoint_descriptor hs_in_desc = { +static struct usb_endpoint_descriptor hs_in_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -268,7 +250,7 @@ static struct usb_endpoint_descriptor hs_in_desc = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_endpoint_descriptor hs_out_desc = { +static struct usb_endpoint_descriptor hs_out_desc __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -277,13 +259,12 @@ static struct usb_endpoint_descriptor hs_out_desc = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_descriptor_header *eth_hs_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, +static struct usb_descriptor_header *eth_hs_function[] __initdata = { /* 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 *) &rndis_acm_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, (struct usb_descriptor_header *) &rndis_union_desc, (struct usb_descriptor_header *) &hs_notify_desc, /* data interface has no altsetting */ @@ -298,7 +279,6 @@ static struct usb_descriptor_header *eth_hs_function[] = { static struct usb_string rndis_string_defs[] = { [0].s = "RNDIS Communications Control", [1].s = "RNDIS Ethernet Data", - [2].s = "RNDIS", { } /* end of list */ }; @@ -606,7 +586,7 @@ static void rndis_close(struct gether *geth) /* ethernet function driver setup/binding */ -static int +static int __init rndis_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; @@ -619,7 +599,6 @@ 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; @@ -783,6 +762,10 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) /* Some controllers can't support RNDIS ... */ static inline bool can_support_rndis(struct usb_configuration *c) { + /* only two endpoints on sa1100 */ + if (gadget_is_sa1100(c->cdev->gadget)) + return false; + /* everything else is *presumably* fine */ return true; } @@ -799,8 +782,7 @@ static inline bool can_support_rndis(struct usb_configuration *c) * Caller must have called @gether_setup(). Caller is also responsible * for calling @gether_cleanup() before module unload. */ -int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) { struct f_rndis *rndis; int status; @@ -829,13 +811,6 @@ 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 */ @@ -865,7 +840,7 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) #ifdef CONFIG_USB_ANDROID_RNDIS /* start disabled */ - rndis->port.func.disabled = 1; + rndis->port.func.hidden = 1; #endif status = usb_add_function(c, &rndis->port.func); @@ -880,7 +855,7 @@ fail: #ifdef CONFIG_USB_ANDROID_RNDIS #include "rndis.c" -static int rndis_probe(struct platform_device *pdev) +static int __init rndis_probe(struct platform_device *pdev) { rndis_pdata = pdev->dev.platform_data; return 0; diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 490b00b0..68ee7acb 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -10,14 +10,14 @@ * either version 2 of that License or (at your option) any later version. */ -#include #include #include +#include #include "u_serial.h" #include "gadget_chips.h" - +#define CONFIG_MODEM_SUPPORT /* * This function packages a simple "generic serial" port with no real * control mechanisms, just raw data transfer over two bulk endpoints. @@ -30,78 +30,187 @@ struct gser_descs { struct usb_endpoint_descriptor *in; struct usb_endpoint_descriptor *out; +#ifdef CONFIG_MODEM_SUPPORT + struct usb_endpoint_descriptor *notify; +#endif }; struct f_gser { struct gserial port; u8 data_id; u8 port_num; + u8 disabled; + u8 configured; struct gser_descs fs; struct gser_descs hs; + u8 online; +#ifdef CONFIG_MODEM_SUPPORT + u8 pending; + spinlock_t lock; + struct usb_ep *notify; + struct usb_endpoint_descriptor *notify_desc; + struct usb_request *notify_req; + + struct usb_cdc_line_coding port_line_coding; + + /* SetControlLineState request */ + u16 port_handshake_bits; +#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ +#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ + + /* SerialState notification */ + u16 serial_state; +#define ACM_CTRL_OVERRUN (1 << 6) +#define ACM_CTRL_PARITY (1 << 5) +#define ACM_CTRL_FRAMING (1 << 4) +#define ACM_CTRL_RI (1 << 3) +#define ACM_CTRL_BRK (1 << 2) +#define ACM_CTRL_DSR (1 << 1) +#define ACM_CTRL_DCD (1 << 0) +#endif }; +static struct usb_function *modem_function; +static struct usb_function *serial_function; static inline struct f_gser *func_to_gser(struct usb_function *f) { return container_of(f, struct f_gser, port.func); } +#ifdef CONFIG_MODEM_SUPPORT +static inline struct f_gser *port_to_gser(struct gserial *p) +{ + return container_of(p, struct f_gser, port); +} +#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ +#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ +#endif /*-------------------------------------------------------------------------*/ /* interface descriptor: */ -static struct usb_interface_descriptor gser_interface_desc __initdata = { +static struct usb_interface_descriptor gser_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, /* .bInterfaceNumber = DYNAMIC */ +#ifdef CONFIG_MODEM_SUPPORT + .bNumEndpoints = 3, +#else .bNumEndpoints = 2, +#endif .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, /* .iInterface = DYNAMIC */ }; +#ifdef CONFIG_MODEM_SUPPORT +static struct usb_cdc_header_desc gser_header_desc = { + .bLength = sizeof(gser_header_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x0110), +}; +static struct usb_cdc_call_mgmt_descriptor +gser_call_mgmt_descriptor = { + .bLength = sizeof(gser_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + /* .bDataInterface = DYNAMIC */ +}; + +static struct usb_cdc_acm_descriptor gser_descriptor = { + .bLength = sizeof(gser_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = USB_CDC_CAP_LINE, +}; + +static struct usb_cdc_union_desc gser_union_desc = { + .bLength = sizeof(gser_union_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + /* .bMasterInterface0 = DYNAMIC */ + /* .bSlaveInterface0 = DYNAMIC */ +}; +#endif /* full speed support: */ +#ifdef CONFIG_MODEM_SUPPORT +static struct usb_endpoint_descriptor gser_fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, +}; +#endif -static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = { +static struct usb_endpoint_descriptor gser_fs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = { +static struct usb_endpoint_descriptor gser_fs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *gser_fs_function[] __initdata = { +static struct usb_descriptor_header *gser_fs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, +#ifdef CONFIG_MODEM_SUPPORT + (struct usb_descriptor_header *) &gser_header_desc, + (struct usb_descriptor_header *) &gser_call_mgmt_descriptor, + (struct usb_descriptor_header *) &gser_descriptor, + (struct usb_descriptor_header *) &gser_union_desc, + (struct usb_descriptor_header *) &gser_fs_notify_desc, +#endif (struct usb_descriptor_header *) &gser_fs_in_desc, (struct usb_descriptor_header *) &gser_fs_out_desc, NULL, }; /* high speed support: */ +#ifdef CONFIG_MODEM_SUPPORT +static struct usb_endpoint_descriptor gser_hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, +}; +#endif -static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = { +static struct usb_endpoint_descriptor gser_hs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), + .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = { +static struct usb_endpoint_descriptor gser_hs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), + .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static struct usb_descriptor_header *gser_hs_function[] __initdata = { +static struct usb_descriptor_header *gser_hs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, +#ifdef CONFIG_MODEM_SUPPORT + (struct usb_descriptor_header *) &gser_header_desc, + (struct usb_descriptor_header *) &gser_call_mgmt_descriptor, + (struct usb_descriptor_header *) &gser_descriptor, + (struct usb_descriptor_header *) &gser_union_desc, + (struct usb_descriptor_header *) &gser_hs_notify_desc, +#endif (struct usb_descriptor_header *) &gser_hs_in_desc, (struct usb_descriptor_header *) &gser_hs_out_desc, NULL, @@ -109,64 +218,365 @@ static struct usb_descriptor_header *gser_hs_function[] __initdata = { /* string descriptors: */ -static struct usb_string gser_string_defs[] = { - [0].s = "Generic Serial", +static struct usb_string modem_string_defs[] = { + [0].s = "HTC Modem", { } /* end of list */ }; -static struct usb_gadget_strings gser_string_table = { +static struct usb_gadget_strings modem_string_table = { .language = 0x0409, /* en-us */ - .strings = gser_string_defs, + .strings = modem_string_defs, }; -static struct usb_gadget_strings *gser_strings[] = { - &gser_string_table, +static struct usb_gadget_strings *modem_strings[] = { + &modem_string_table, NULL, }; -/*-------------------------------------------------------------------------*/ +static struct usb_string serial_string_defs[] = { + [0].s = "HTC Serial", + { } /* end of list */ +}; +static struct usb_gadget_strings serial_string_table = { + .language = 0x0409, /* en-us */ + .strings = serial_string_defs, +}; + +static struct usb_gadget_strings *serial_strings[] = { + &serial_string_table, + NULL, +}; +#ifdef CONFIG_MODEM_SUPPORT +static void gser_complete_set_line_coding(struct usb_ep *ep, + struct usb_request *req) +{ + struct f_gser *gser = ep->driver_data; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + + if (req->status != 0) { + DBG(cdev, "gser ttyGS%d completion, err %d\n", + gser->port_num, req->status); + return; + } + + /* normal completion */ + if (req->actual != sizeof(gser->port_line_coding)) { + DBG(cdev, "gser ttyGS%d short resp, len %d\n", + gser->port_num, req->actual); + usb_ep_set_halt(ep); + } else { + struct usb_cdc_line_coding *value = req->buf; + gser->port_line_coding = *value; + } +} +/*-------------------------------------------------------------------------*/ +static int +gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct f_gser *gser = func_to_gser(f); + struct usb_composite_dev *cdev = f->config->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); + + switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { + + /* SET_LINE_CODING ... just read and save what the host sends */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_LINE_CODING: + if (w_length != sizeof(struct usb_cdc_line_coding) + || w_index != gser->data_id) + goto invalid; + value = w_length; + cdev->gadget->ep0->driver_data = gser; + req->complete = gser_complete_set_line_coding; + break; + + /* GET_LINE_CODING ... return what host sent, or initial value */ + case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_GET_LINE_CODING: + if (w_index != gser->data_id) + goto invalid; + + value = min_t(unsigned, w_length, + sizeof(struct usb_cdc_line_coding)); + memcpy(req->buf, &gser->port_line_coding, value); + break; + + /* SET_CONTROL_LINE_STATE ... save what the host sent */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_CONTROL_LINE_STATE: + if (w_index != gser->data_id) + goto invalid; + + value = 0; + gser->port_handshake_bits = w_value; + break; + + default: +invalid: + 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, "gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n", + gser->port_num, 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, "gser response on ttyGS%d, err %d\n", + gser->port_num, value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} +#endif static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { - struct f_gser *gser = func_to_gser(f); + struct f_gser *gser = func_to_gser(f); struct usb_composite_dev *cdev = f->config->cdev; + struct usb_interface_descriptor *desc; /* we know alt == 0, so this is an activation or a reset */ + if (cdev->gadget->speed == USB_SPEED_HIGH) + desc = (struct usb_interface_descriptor *) *(f->hs_descriptors); + else + desc = (struct usb_interface_descriptor *) *(f->descriptors); + gser->data_id = desc->bInterfaceNumber; +#ifdef CONFIG_MODEM_SUPPORT +#if 0 + if (gser->notify->driver_data) { + DBG(cdev, "reset generic ttyGS%d\n", gser->port_num); + usb_ep_disable(gser->notify); + } +#endif + gser->notify_desc = ep_choose(cdev->gadget, + gser->hs.notify, + gser->fs.notify); + usb_ep_enable(gser->notify, gser->notify_desc); + gser->notify->driver_data = gser; +#endif +#if 0 if (gser->port.in->driver_data) { DBG(cdev, "reset generic ttyGS%d\n", gser->port_num); gserial_disconnect(&gser->port); } else { DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - gser->port.in_desc = ep_choose(cdev->gadget, - gser->hs.in, gser->fs.in); - gser->port.out_desc = ep_choose(cdev->gadget, - gser->hs.out, gser->fs.out); } +#endif + gser->port.in_desc = ep_choose(cdev->gadget, + gser->hs.in, gser->fs.in); + gser->port.out_desc = ep_choose(cdev->gadget, + gser->hs.out, gser->fs.out); gserial_connect(&gser->port, gser->port_num); + gser->online = 1; return 0; } static void gser_disable(struct usb_function *f) { - struct f_gser *gser = func_to_gser(f); + struct f_gser *gser = func_to_gser(f); struct usb_composite_dev *cdev = f->config->cdev; DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num); gserial_disconnect(&gser->port); +#if 0 + /* disable endpoints, aborting down any active I/O */ + usb_ep_fifo_flush(gser->port.out); + usb_ep_disable(gser->port.out); + gser->port.out->driver_data = NULL; + + usb_ep_fifo_flush(gser->port.in); + usb_ep_disable(gser->port.in); + gser->port.in->driver_data = NULL; +#endif +#ifdef CONFIG_MODEM_SUPPORT + usb_ep_fifo_flush(gser->notify); + usb_ep_disable(gser->notify); + gser->notify->driver_data = NULL; +#endif + gser->online = 0; +} +#ifdef CONFIG_MODEM_SUPPORT +static int gser_notify(struct f_gser *gser, u8 type, u16 value, + void *data, unsigned length) +{ + struct usb_ep *ep = gser->notify; + struct usb_request *req; + struct usb_cdc_notification *notify; + const unsigned len = sizeof(*notify) + length; + void *buf; + int status; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + + req = gser->notify_req; + gser->notify_req = NULL; + gser->pending = false; + + req->length = len; + notify = req->buf; + buf = notify + 1; + + notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS + | USB_RECIP_INTERFACE; + notify->bNotificationType = type; + notify->wValue = cpu_to_le16(value); + notify->wIndex = cpu_to_le16(gser->data_id); + notify->wLength = cpu_to_le16(length); + memcpy(buf, data, length); + + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status < 0) { + ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n", + gser->port_num, status); + gser->notify_req = req; + } + + return status; } +static int gser_notify_serial_state(struct f_gser *gser) +{ + int status; + unsigned long flags; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + if (gser->disabled) + return 0; + + spin_lock_irqsave(&gser->lock, flags); + if (gser->notify_req) { + DBG(cdev, "gser ttyGS%d serial state %04x\n", + gser->port_num, gser->serial_state); + status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE, + 0, &gser->serial_state, + sizeof(gser->serial_state)); + } else { + gser->pending = true; + status = 0; + } + spin_unlock_irqrestore(&gser->lock, flags); + return status; +} + +static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_gser *gser = req->context; + u8 doit = false; + unsigned long flags; + + /* on this call path we do NOT hold the port spinlock, + * which is why ACM needs its own spinlock + */ + spin_lock_irqsave(&gser->lock, flags); + if (req->status != -ESHUTDOWN) + doit = gser->pending; + gser->notify_req = req; + spin_unlock_irqrestore(&gser->lock, flags); + + if (doit && gser->online) + gser_notify_serial_state(gser); +} +static void gser_connect(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; + gser_notify_serial_state(gser); +} + +unsigned int gser_get_dtr(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + if (gser->port_handshake_bits & ACM_CTRL_DTR) + return 1; + else + return 0; +} + +unsigned int gser_get_rts(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + if (gser->port_handshake_bits & ACM_CTRL_RTS) + return 1; + else + return 0; +} + +unsigned int gser_send_carrier_detect(struct gserial *port, unsigned int yes) +{ + struct f_gser *gser = port_to_gser(port); + u16 state; + + state = gser->serial_state; + state &= ~ACM_CTRL_DCD; + if (yes) + state |= ACM_CTRL_DCD; + + gser->serial_state = state; + return gser_notify_serial_state(gser); + +} + +unsigned int gser_send_ring_indicator(struct gserial *port, unsigned int yes) +{ + struct f_gser *gser = port_to_gser(port); + u16 state; + + state = gser->serial_state; + state &= ~ACM_CTRL_RI; + if (yes) + state |= ACM_CTRL_RI; + + gser->serial_state = state; + return gser_notify_serial_state(gser); + +} +static void gser_disconnect(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); + gser_notify_serial_state(gser); +} + +static int gser_send_break(struct gserial *port, int duration) +{ + struct f_gser *gser = port_to_gser(port); + u16 state; + + state = gser->serial_state; + state &= ~ACM_CTRL_BRK; + if (duration) + state |= ACM_CTRL_BRK; + + gser->serial_state = state; + return gser_notify_serial_state(gser); +} +#endif /*-------------------------------------------------------------------------*/ /* serial function driver setup/binding */ -static int __init +static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; - struct f_gser *gser = func_to_gser(f); - int status; - struct usb_ep *ep; + struct f_gser *gser = func_to_gser(f); + int status; + struct usb_ep *ep; + struct usb_gadget_strings *s; /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); @@ -174,6 +584,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) goto fail; gser->data_id = status; gser_interface_desc.bInterfaceNumber = status; + if (f->strings) { + s = *(f->strings); + gser_interface_desc.iInterface = s->strings[0].id; + } status = -ENODEV; @@ -182,13 +596,30 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) if (!ep) goto fail; gser->port.in = ep; - ep->driver_data = cdev; /* claim */ + ep->driver_data = gser; /* claim */ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); if (!ep) goto fail; gser->port.out = ep; - ep->driver_data = cdev; /* claim */ + ep->driver_data = gser; /* claim */ + +#ifdef CONFIG_MODEM_SUPPORT + ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); + if (!ep) + goto fail; + gser->notify = ep; + ep->driver_data = gser; /* claim */ + /* allocate notification */ + gser->notify_req = gs_alloc_req(ep, + sizeof(struct usb_cdc_notification) + 2, + GFP_KERNEL); + if (!gser->notify_req) + goto fail; + + gser->notify_req->complete = gser_notify_complete; + gser->notify_req->context = gser; +#endif /* copy descriptors, and track endpoint copies */ f->descriptors = usb_copy_descriptors(gser_fs_function); @@ -197,6 +628,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) f->descriptors, &gser_fs_in_desc); gser->fs.out = usb_find_endpoint(gser_fs_function, f->descriptors, &gser_fs_out_desc); +#ifdef CONFIG_MODEM_SUPPORT + gser->fs.notify = usb_find_endpoint(gser_fs_function, + f->descriptors, &gser_fs_notify_desc); +#endif /* support all relevant hardware speeds... we expect that when @@ -208,6 +643,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) gser_fs_in_desc.bEndpointAddress; gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; +#ifdef CONFIG_MODEM_SUPPORT + gser_hs_notify_desc.bEndpointAddress = + gser_fs_notify_desc.bEndpointAddress; +#endif /* copy descriptors, and track endpoint copies */ f->hs_descriptors = usb_copy_descriptors(gser_hs_function); @@ -216,6 +655,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors, &gser_hs_in_desc); gser->hs.out = usb_find_endpoint(gser_hs_function, f->hs_descriptors, &gser_hs_out_desc); +#ifdef CONFIG_MODEM_SUPPORT + gser->hs.notify = usb_find_endpoint(gser_hs_function, + f->hs_descriptors, &gser_hs_notify_desc); +#endif } DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", @@ -225,6 +668,14 @@ gser_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: +#ifdef CONFIG_MODEM_SUPPORT + if (gser->notify_req) + gs_free_req(gser->notify, gser->notify_req); + + /* we might as well release our claims on endpoints */ + if (gser->notify) + gser->notify->driver_data = NULL; +#endif /* we might as well release our claims on endpoints */ if (gser->port.out) gser->port.out->driver_data = NULL; @@ -239,9 +690,15 @@ fail: static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { +#ifdef CONFIG_MODEM_SUPPORT + struct f_gser *gser = func_to_gser(f); +#endif if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); +#ifdef CONFIG_MODEM_SUPPORT + gs_free_req(gser->notify, gser->notify_req); +#endif kfree(func_to_gser(f)); } @@ -257,9 +714,9 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f) * handle all the ones it binds. Caller is also responsible * for calling @gserial_cleanup() before module unload. */ -int __init gser_bind_config(struct usb_configuration *c, u8 port_num) +int gser_bind_config(struct usb_configuration *c, u8 port_num) { - struct f_gser *gser; + struct f_gser *gser; int status; /* REVISIT might want instance-specific strings to help @@ -267,29 +724,129 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num) */ /* maybe allocate device-global string ID */ - if (gser_string_defs[0].id == 0) { + if (modem_string_defs[0].id == 0 && port_num == 0) { status = usb_string_id(c->cdev); - if (status < 0) + if (status < 0) { + printk(KERN_ERR "%s: return %d\n", __func__, status); return status; - gser_string_defs[0].id = status; + } + modem_string_defs[0].id = status; + } + if (serial_string_defs[0].id == 0 && port_num == 2) { + status = usb_string_id(c->cdev); + if (status < 0) { + printk(KERN_ERR "%s: return %d\n", __func__, status); + return status; + } + serial_string_defs[0].id = status; } - /* allocate and initialize one new instance */ gser = kzalloc(sizeof *gser, GFP_KERNEL); if (!gser) return -ENOMEM; +#ifdef CONFIG_MODEM_SUPPORT + spin_lock_init(&gser->lock); +#endif gser->port_num = port_num; - gser->port.func.name = "gser"; - gser->port.func.strings = gser_strings; + if (port_num == 0) { + gser->port.func.name = "modem"; + gser->port.func.strings = modem_strings; + modem_function = &gser->port.func; + } else if (port_num == 2) { + gser->port.func.name = "serial"; + gser->port.func.strings = serial_strings; + serial_function = &gser->port.func; + } gser->port.func.bind = gser_bind; gser->port.func.unbind = gser_unbind; gser->port.func.set_alt = gser_set_alt; gser->port.func.disable = gser_disable; +#ifdef CONFIG_MODEM_SUPPORT + gser->port.func.setup = gser_setup; + gser->port.connect = gser_connect; + gser->port.get_dtr = gser_get_dtr; + gser->port.get_rts = gser_get_rts; + gser->port.send_carrier_detect = gser_send_carrier_detect; + gser->port.send_ring_indicator = gser_send_ring_indicator; + gser->port.disconnect = gser_disconnect; + gser->port.send_break = gser_send_break; +#endif + gser->port.func.hidden = 1; + gser->disabled = 1; status = usb_add_function(c, &gser->port.func); if (status) kfree(gser); return status; } + +static int modem_set_enabled(const char *val, struct kernel_param *kp) +{ + struct f_gser *gser; + int enabled = simple_strtol(val, NULL, 0); + printk(KERN_INFO "%s: %d\n", __func__, enabled); + gser = func_to_gser(modem_function); + if (!gser) + return 0; + gser->disabled = !enabled; + android_enable_function(modem_function, enabled); + return 0; +} + +static int modem_get_enabled(char *buffer, struct kernel_param *kp) +{ + buffer[0] = '0' + !modem_function->hidden; + printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0'); + return 1; +} +module_param_call(modem_enabled, modem_set_enabled, modem_get_enabled, NULL, 0664); + +static int serial_set_enabled(const char *val, struct kernel_param *kp) +{ + struct f_gser *gser; + int enabled = simple_strtol(val, NULL, 0); + printk(KERN_INFO "%s: %d\n", __func__, enabled); + gser = func_to_gser(serial_function); + if (!gser) + return 0; + gser->disabled = !enabled; + android_enable_function(serial_function, enabled); + return 0; +} + +static int serial_get_enabled(char *buffer, struct kernel_param *kp) +{ + buffer[0] = '0' + !serial_function->hidden; + printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0'); + return 1; +} +module_param_call(serial_enabled, serial_set_enabled, serial_get_enabled, NULL, 0664); + +static int serial_bind_config(struct usb_configuration *c) +{ + int ret; + + printk(KERN_INFO "serial_bind_config\n"); + ret = gser_bind_config(c, 0); + if (ret) + return ret; + ret = gser_bind_config(c, 2); + if (ret == 0) + gserial_setup(c->cdev->gadget, 3); + return ret; +} + +static struct android_usb_function android_serial_function = { + .name = "serial", + .bind_config = serial_bind_config, +}; + +static int __init init(void) +{ + printk(KERN_INFO "serial init\n"); + android_register_function(&android_serial_function); + return 0; +} +module_init(init); diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c index 52b4ee2b..be1fd75f 100644 --- a/drivers/usb/gadget/msm72k_udc.c +++ b/drivers/usb/gadget/msm72k_udc.c @@ -49,7 +49,6 @@ #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC #include #endif -#include static const char driver_name[] = "msm72k_udc"; @@ -82,14 +81,11 @@ static struct usb_info *the_usb_info; static int vbus; static int use_mfg_serialno; static char mfg_df_serialno[16]; -static int disable_charger; -#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT) +#ifdef CONFIG_USB_ACCESSORY_DETECT #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC extern int htc_get_usb_accessory_adc_level(uint32_t *buffer); #endif - - static struct switch_dev dock_switch = { .name = "dock", }; @@ -99,12 +95,6 @@ static struct switch_dev dock_switch = { #define DOCK_STATE_CAR (1 << 1) #endif -#include -#include - -static struct wake_lock vbus_idle_wake_lock; -static struct perf_lock usb_perf_lock; - struct msm_request { struct usb_request req; @@ -152,10 +142,8 @@ static void check_charger(struct work_struct *w); #ifdef CONFIG_USB_ACCESSORY_DETECT static void accessory_detect_work(struct work_struct *w); #endif -#ifdef CONFIG_DOCK_ACCESSORY_DETECT -static void dock_detect_work(struct work_struct *w); -static void dock_detect_init(struct usb_info *ui); -#endif +extern int android_switch_function(unsigned func); +extern int android_show_function(char *buf); extern void android_set_serialno(char *serialno); #define USB_STATE_IDLE 0 @@ -212,10 +200,6 @@ struct usb_info { void (*phy_reset)(void); void (*hw_reset)(bool en); void (*usb_uart_switch)(int); - void (*serial_debug_gpios)(int); - void (*usb_hub_enable)(bool); - int (*china_ac_detect)(void); - void (*disable_usb_charger)(void); /* for notification when USB is connected or disconnected */ void (*usb_connected)(int); @@ -224,7 +208,6 @@ struct usb_info { struct work_struct work; struct delayed_work chg_work; struct work_struct detect_work; - struct work_struct dock_work; struct work_struct notifier_work; unsigned phy_status; unsigned phy_fail_count; @@ -249,13 +232,10 @@ struct usb_info { u8 in_lpm; /* for accessory detection */ - bool dock_detect; u8 accessory_detect; u8 mfg_usb_carkit_enable; int idpin_irq; - int dockpin_irq; int usb_id_pin_gpio; - int dock_pin_gpio; void (*config_usb_id_gpios)(bool output_enable); /* 0: none, 1: carkit, 2: usb headset */ u8 accessory_type; @@ -346,7 +326,7 @@ static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg) USB_ULPI_VIEWPORT); /* wait for completion */ - while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ; + while((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ; if (timeout == 0) { printk(KERN_ERR "ulpi_write: timeout\n"); @@ -533,8 +513,6 @@ static void usb_ept_start(struct msm_endpoint *ept) { struct usb_info *ui = ept->ui; struct msm_request *req = ept->req; - int i, cnt; - unsigned n = 1 << ept->bit; BUG_ON(req->live); @@ -542,36 +520,14 @@ static void usb_ept_start(struct msm_endpoint *ept) ept->head->next = req->item_dma; ept->head->info = 0; - /* during high throughput testing it is observed that - * ept stat bit is not set even thoguh all the data - * structures are updated properly and ept prime bit - * is set. To workaround the issue, try to check if - * ept stat bit otherwise try to re-prime the ept - */ - for (i = 0; i < 5; i++) { - writel(n, USB_ENDPTPRIME); - for (cnt = 0; cnt < 3000; cnt++) { - if (!(readl(USB_ENDPTPRIME) & n) && - (readl(USB_ENDPTSTAT) & n)) - goto DONE; - udelay(1); - } - } + /* start the endpoint */ + writel(1 << ept->bit, USB_ENDPTPRIME); - if (!(readl(USB_ENDPTSTAT) & n)) { - pr_err("Unable to prime the ept%d%s\n", - ept->num, - ept->flags & EPT_FLAG_IN ? "in" : "out"); - return; - } - -DONE: /* mark this chain of requests as live */ while (req) { req->live = 1; req = req->next; } - } int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req) @@ -801,6 +757,7 @@ static void handle_setup(struct usb_info *ui) { u16 temp = 0; + temp = 1 << USB_DEVICE_SELF_POWERED; temp |= (ui->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); memcpy(req->buf, &temp, 2); @@ -855,10 +812,6 @@ static void handle_setup(struct usb_info *ui) case J_TEST: case K_TEST: case SE0_NAK_TEST: - if (!ui->test_mode) { - disable_charger = 1; - queue_delayed_work(ui->usb_wq, &ui->chg_work, 0); - } case TST_PKT_TEST: ui->test_mode = ctl.wIndex; goto ack; @@ -1160,6 +1113,30 @@ static ssize_t show_usb_cable_connect(struct device *dev, static DEVICE_ATTR(usb_cable_connect, 0444, show_usb_cable_connect, NULL); +static ssize_t show_usb_function_switch(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return android_show_function(buf); +} + +static ssize_t store_usb_function_switch(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned u; + ssize_t ret; + + u = simple_strtoul(buf, NULL, 10); + ret = android_switch_function(u); + + if (ret == 0) + return count; + else + return 0; +} + +static DEVICE_ATTR(usb_function_switch, 0666, + show_usb_function_switch, store_usb_function_switch); + static ssize_t show_usb_serial_number(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1270,27 +1247,6 @@ static ssize_t show_USB_ID_status(struct device *dev, static DEVICE_ATTR(USB_ID_status, 0444, show_USB_ID_status, NULL); -static ssize_t show_usb_car_kit_enable(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_info *ui = the_usb_info; - int value = 1; - unsigned length; - - if (!ui) - return 0; - if (ui->accessory_detect == 0) { - value = 0; - } - printk(KERN_INFO "usb: USB_car_kit_enable %d\n", ui->accessory_detect); - length = sprintf(buf, "%d", value); - return length; -} - -static DEVICE_ATTR(usb_car_kit_enable, 0444, - show_usb_car_kit_enable, NULL);/*for kar kit AP check if car kit enable*/ - static ssize_t show_usb_phy_setting(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1370,17 +1326,13 @@ static ssize_t store_mfg_carkit_enable(struct device *dev, static DEVICE_ATTR(usb_mfg_carkit_enable, 0644, show_mfg_carkit_enable, store_mfg_carkit_enable); -#endif -#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT) static ssize_t dock_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_info *ui = the_usb_info; if (ui->accessory_type == 1) return sprintf(buf, "online\n"); - else if (ui->accessory_type == 3) /*desk dock*/ - return sprintf(buf, "online\n"); else return sprintf(buf, "offline\n"); } @@ -1417,13 +1369,6 @@ static void usb_prepare(struct usb_info *ui) #ifdef CONFIG_USB_ACCESSORY_DETECT INIT_WORK(&ui->detect_work, accessory_detect_work); #endif -#ifdef CONFIG_DOCK_ACCESSORY_DETECT - if (ui->dock_detect) { - INIT_WORK(&ui->dock_work, dock_detect_work); - dock_detect_init(ui); - } -#endif - INIT_WORK(&ui->notifier_work, send_usb_connect_notify); INIT_DELAYED_WORK(&ui->chg_work, check_charger); @@ -1432,6 +1377,11 @@ static void usb_prepare(struct usb_info *ui) if (ret != 0) printk(KERN_WARNING "dev_attr_usb_cable_connect failed\n"); + ret = device_create_file(&ui->pdev->dev, + &dev_attr_usb_function_switch); + if (ret != 0) + printk(KERN_WARNING "dev_attr_usb_function_switch failed\n"); + ret = device_create_file(&ui->pdev->dev, &dev_attr_usb_serial_number); if (ret != 0) @@ -1458,11 +1408,6 @@ static void usb_prepare(struct usb_info *ui) if (ret != 0) printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n"); #endif - ret = device_create_file(&ui->pdev->dev, - &dev_attr_usb_car_kit_enable);/*for kar kit AP check if car kit enable*/ - if (ret != 0) - printk(KERN_WARNING "dev_attr_usb_car_kit_enable failed\n"); - } static int usb_wakeup_phy(struct usb_info *ui) @@ -1605,18 +1550,6 @@ static void usb_start(struct usb_info *ui) spin_lock_irqsave(&ui->lock, flags); ui->flags |= USB_FLAG_START; -/*if msm_hsusb_set_vbus_state set 1, but usb did not init, the ui =NULL, */ -/*it would cause reboot with usb, it did not swith to USB and ADB fail*/ -/*So when USB start, check again*/ - if (vbus) { - ui->flags |= USB_FLAG_VBUS_ONLINE; - } else { - ui->flags |= USB_FLAG_VBUS_OFFLINE; - } - /* online->switch to USB, offline->switch to uart */ - if (ui->usb_uart_switch) - ui->usb_uart_switch(!vbus); - queue_work(ui->usb_wq, &ui->work); spin_unlock_irqrestore(&ui->lock, flags); } @@ -1681,13 +1614,6 @@ static void usb_lpm_enter(struct usb_info *ui) clk_set_rate(ui->ebi1clk, 0); ui->in_lpm = 1; spin_unlock_irqrestore(&ui->lock, iflags); - - if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/ - printk(KERN_INFO "usb: idle_wake_unlock and perf unlock\n"); - wake_unlock(&vbus_idle_wake_lock); - if (is_perf_lock_active(&usb_perf_lock)) - perf_unlock(&usb_perf_lock); - } } static void usb_lpm_exit(struct usb_info *ui) @@ -1705,86 +1631,8 @@ static void usb_lpm_exit(struct usb_info *ui) clk_enable(ui->otgclk); usb_wakeup_phy(ui); ui->in_lpm = 0; - - if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/ - printk(KERN_INFO "usb: idle_wake_lock and perf lock\n"); - wake_lock(&vbus_idle_wake_lock); - if (!is_perf_lock_active(&usb_perf_lock)) - perf_lock(&usb_perf_lock); - } } -#ifdef CONFIG_DOCK_ACCESSORY_DETECT -static irqreturn_t dock_interrupt(int irq, void *data) -{ - struct usb_info *ui = data; - disable_irq_nosync(ui->dockpin_irq); - queue_work(ui->usb_wq, &ui->dock_work); - return IRQ_HANDLED; -} -static void dock_detect_work(struct work_struct *w) -{ - struct usb_info *ui = container_of(w, struct usb_info, dock_work); - int value; - - value = gpio_get_value(ui->dock_pin_gpio); - - if (value == 0 && vbus) { - set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH); - switch_set_state(&dock_switch, DOCK_STATE_DESK); - ui->accessory_type = 3; - printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_DESK); - } else { - set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW); - switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); - ui->accessory_type = 0; - printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_UNDOCKED); - } - enable_irq(ui->dockpin_irq); - - -} -static void dock_detect_init(struct usb_info *ui) -{ - int ret; - - if (ui->dock_pin_gpio == 0) - return; - if (ui->dockpin_irq == 0) - ui->dockpin_irq = gpio_to_irq(ui->dock_pin_gpio); - - ret = request_irq(ui->dockpin_irq, dock_interrupt, - IRQF_TRIGGER_LOW, - "dock_irq", ui); - if (ret < 0) { - printk(KERN_ERR "%s: request_irq failed\n", __func__); - return; - } - printk(KERN_INFO "%s: dock irq %d\n", __func__, - ui->dockpin_irq); - ret = set_irq_wake(ui->dockpin_irq, 1); - if (ret < 0) { - printk(KERN_ERR "%s: set_irq_wake failed\n", __func__); - goto err; - } - - if (switch_dev_register(&dock_switch) < 0) { - printk(KERN_ERR "usb: fail to register dock switch!\n"); - goto err; - } - - ret = device_create_file(dock_switch.dev, &dev_attr_status); - if (ret != 0) - printk(KERN_WARNING "dev_attr_status failed\n"); - - return; - -err: - free_irq(ui->dockpin_irq, 0); -} -#endif - - #ifdef CONFIG_USB_ACCESSORY_DETECT static void carkit_detect(struct usb_info *ui) { @@ -1842,7 +1690,7 @@ static void accessory_detect_by_adc(struct usb_info *ui) if (adc_value >= 0x2112 && adc_value <= 0x3D53) { printk(KERN_INFO "usb: headset inserted\n"); ui->accessory_type = 2; - headset_ext_detect(USB_AUDIO_OUT); + headset_ext_detect(USB_HEADSET); } else if (adc_value >= 0x88A && adc_value <= 0x1E38) { printk(KERN_INFO "usb: carkit inserted\n"); ui->accessory_type = 1; @@ -1856,7 +1704,7 @@ static void accessory_detect_by_adc(struct usb_info *ui) } else { if (ui->accessory_type == 2) { printk(KERN_INFO "usb: headset removed\n"); - headset_ext_detect(USB_NO_HEADSET); + headset_ext_detect(NO_DEVICE); } else if (ui->accessory_type == 1) { printk(KERN_INFO "usb: carkit removed\n"); switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); @@ -1908,8 +1756,7 @@ static void accessory_detect_init(struct usb_info *ui) if (ui->usb_id_pin_gpio == 0) return; - if (ui->idpin_irq == 0) - ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio); + ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio); ret = request_irq(ui->idpin_irq, usbid_interrupt, IRQF_TRIGGER_LOW, @@ -1929,11 +1776,9 @@ static void accessory_detect_init(struct usb_info *ui) printk(KERN_ERR "usb: fail to register dock switch!\n"); goto err; } - ret = device_create_file(dock_switch.dev, &dev_attr_status); if (ret != 0) printk(KERN_WARNING "dev_attr_status failed\n"); - return; err: free_irq(ui->idpin_irq, 0); @@ -1942,44 +1787,6 @@ err: #endif #define DELAY_FOR_CHECK_CHG msecs_to_jiffies(300) - -static void charger_detect_by_uart(struct usb_info *ui) -{ - int is_china_ac; - - /*UART*/ - if (ui->usb_uart_switch) - ui->usb_uart_switch(1); - - is_china_ac = ui->china_ac_detect(); - - if (is_china_ac) { - ui->connect_type = CONNECT_TYPE_AC; - queue_work(ui->usb_wq, &ui->notifier_work); - usb_lpm_enter(ui); - printk(KERN_INFO "usb: AC charger\n"); - } else { - ui->connect_type = CONNECT_TYPE_UNKNOWN; - queue_delayed_work(ui->usb_wq, &ui->chg_work, - DELAY_FOR_CHECK_CHG); - printk(KERN_INFO "usb: not AC charger\n"); - - /*set uart to gpo*/ - if (ui->serial_debug_gpios) - ui->serial_debug_gpios(0); - /*turn on USB HUB*/ - if (ui->usb_hub_enable) - ui->usb_hub_enable(1); - - /*USB*/ - if (ui->usb_uart_switch) - ui->usb_uart_switch(0); - - usb_lpm_exit(ui); - usb_reset(ui); - } -} - static void charger_detect(struct usb_info *ui) { if (!vbus) @@ -2004,13 +1811,6 @@ static void charger_detect(struct usb_info *ui) static void check_charger(struct work_struct *w) { struct usb_info *ui = container_of(w, struct usb_info, chg_work.work); - if (disable_charger) { - printk(KERN_INFO "usb: disable charger\n"); - if (ui->disable_usb_charger) - ui->disable_usb_charger(); - disable_charger = 0; - return; - } /* unknown charger */ if (vbus && ui->connect_type == CONNECT_TYPE_UNKNOWN) queue_work(ui->usb_wq, &ui->notifier_work); @@ -2022,7 +1822,6 @@ static void usb_do_work(struct work_struct *w) unsigned long iflags; unsigned flags, _vbus; - for (;;) { spin_lock_irqsave(&ui->lock, iflags); flags = ui->flags; @@ -2037,15 +1836,9 @@ static void usb_do_work(struct work_struct *w) case USB_STATE_IDLE: if (flags & USB_FLAG_START) { pr_info("hsusb: IDLE -> ONLINE\n"); - - if (ui->china_ac_detect) - charger_detect_by_uart(ui); - else { - usb_lpm_exit(ui); - usb_reset(ui); - - charger_detect(ui); - } + usb_lpm_exit(ui); + usb_reset(ui); + charger_detect(ui); ui->state = USB_STATE_ONLINE; #ifdef CONFIG_USB_ACCESSORY_DETECT @@ -2117,14 +1910,9 @@ static void usb_do_work(struct work_struct *w) */ if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) { pr_info("hsusb: OFFLINE -> ONLINE\n"); - - if (ui->china_ac_detect) - charger_detect_by_uart(ui); - else { - usb_lpm_exit(ui); - usb_reset(ui); - charger_detect(ui); - } + usb_lpm_exit(ui); + usb_reset(ui); + charger_detect(ui); ui->state = USB_STATE_ONLINE; usb_do_work_check_vbus(ui); @@ -2154,33 +1942,9 @@ void msm_hsusb_set_vbus_state(int online) } else { ui->flags |= USB_FLAG_VBUS_OFFLINE; } - - if (online) { - /*USB*/ - if (ui->usb_uart_switch) - ui->usb_uart_switch(0); - } else { - /*turn off USB HUB*/ - if (ui->usb_hub_enable) - ui->usb_hub_enable(0); - - /*UART*/ - if (ui->usb_uart_switch) - ui->usb_uart_switch(1); - /*configure uart pin to alternate function*/ - if (ui->serial_debug_gpios) - ui->serial_debug_gpios(1); -#ifdef CONFIG_DOCK_ACCESSORY_DETECT - if (ui->accessory_type == 3) { - set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW); - switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); - ui->accessory_type = 0; - printk(KERN_INFO "usb:dock: vbus offline\n"); - enable_irq(ui->dockpin_irq); - } -#endif - } - + /* online->switch to USB, offline->switch to uart */ + if (ui->usb_uart_switch) + ui->usb_uart_switch(!online); queue_work(ui->usb_wq, &ui->work); } } @@ -2601,10 +2365,6 @@ static int msm72k_probe(struct platform_device *pdev) ui->phy_init_seq = pdata->phy_init_seq; ui->usb_connected = pdata->usb_connected; ui->usb_uart_switch = pdata->usb_uart_switch; - ui->serial_debug_gpios = pdata->serial_debug_gpios; - ui->usb_hub_enable = pdata->usb_hub_enable; - ui->china_ac_detect = pdata->china_ac_detect; - ui->disable_usb_charger = pdata->disable_usb_charger; ui->accessory_detect = pdata->accessory_detect; printk(KERN_INFO "usb: accessory detect %d\n", @@ -2612,15 +2372,6 @@ static int msm72k_probe(struct platform_device *pdev) ui->usb_id_pin_gpio = pdata->usb_id_pin_gpio; printk(KERN_INFO "usb: id_pin_gpio %d\n", pdata->usb_id_pin_gpio); - - ui->dock_detect = pdata->dock_detect; - printk(KERN_INFO "usb: dock detect %d\n", - ui->dock_detect); - ui->dock_pin_gpio = pdata->dock_pin_gpio; - printk(KERN_INFO "usb: dock pin gpio %d\n", - ui->dock_pin_gpio); - - ui->idpin_irq = pdata->id_pin_irq; if (pdata->config_usb_id_gpios) ui->config_usb_id_gpios = pdata->config_usb_id_gpios; } @@ -2706,11 +2457,9 @@ static int msm72k_probe(struct platform_device *pdev) /* initialize mfg serial number */ - if (board_mfg_mode() == 1) { + if (board_mfg_mode() == 1) use_mfg_serialno = 1; - wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "usb_idle_lock"); - perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb"); - } else + else use_mfg_serialno = 0; strncpy(mfg_df_serialno, "000000000000", strlen("000000000000")); diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 1043da1f..48267bc0 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -292,13 +291,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - if ( rndis_per_dev_params [configNr].vendorDescr ) { - length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy (outbuf, - rndis_per_dev_params [configNr].vendorDescr, length); - } else { - outbuf[0] = 0; - } + length = strlen (rndis_per_dev_params [configNr].vendorDescr); + memcpy (outbuf, + rndis_per_dev_params [configNr].vendorDescr, length); retval = 0; break; diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c deleted file mode 100644 index 869248b4..00000000 --- a/drivers/usb/gadget/storage_common.c +++ /dev/null @@ -1,784 +0,0 @@ -/* - * 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 - - -/* 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; - - -#ifndef CONFIG_USB_ANDROID_MASS_STORAGE - /* disabled in android because we need to allow closing the backing file - * if the media was removed - */ - if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { - LDBG(curlun, "eject attempt prevented\n"); - return -EBUSY; /* "Door is locked" */ - } -#endif - - /* 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 99e4aa3b..82b30b5d 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -93,6 +93,13 @@ static inline bool can_support_ecm(struct usb_gadget *gadget) if (!gadget_supports_altsettings(gadget)) return false; + /* SA1100 can do ECM, *without* status endpoint ... but we'll + * only use it in non-ECM mode for backwards compatibility + * (and since we currently require a status endpoint) + */ + if (gadget_is_sa1100(gadget)) + return false; + /* Everything else is *presumably* fine ... but this is a bit * chancy, so be **CERTAIN** there are no hardware issues with * your controller. Add it above if it can't handle CDC. @@ -105,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); -#if defined(USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS) +#if defined(CONFIG_USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS) int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); diff --git a/include/linux/slab.h b/include/linux/slab.h index 49d1247c..2da83725 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -70,11 +70,6 @@ #else # define SLAB_NOTRACK 0x00000000UL #endif -#ifdef CONFIG_FAILSLAB -# define SLAB_FAILSLAB 0x02000000UL /* Fault injection mark */ -#else -# define SLAB_FAILSLAB 0x00000000UL -#endif /* The following flags affect the page allocator grouping pages by mobility */ #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ @@ -106,7 +101,6 @@ int kmem_cache_shrink(struct kmem_cache *); void kmem_cache_free(struct kmem_cache *, void *); unsigned int kmem_cache_size(struct kmem_cache *); const char *kmem_cache_name(struct kmem_cache *); -int kern_ptr_validate(const void *ptr, unsigned long size); int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr); /* diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h index ac09dcb7..dc40ecca 100644 --- a/include/linux/usb/android_composite.h +++ b/include/linux/usb/android_composite.h @@ -27,6 +27,11 @@ struct android_usb_function { }; struct android_usb_product { + /* Vendor ID for this set of functions. + * Default vendor_id in platform data will be used if this is zero. + */ + __u16 vendor_id; + /* Default product ID. */ __u16 product_id; @@ -79,6 +84,9 @@ struct usb_mass_storage_platform_data { /* number of LUNS */ int nluns; + + /* bitmap of lun to indicate cdrom disk*/ + int cdrom_lun; }; /* Platform data for USB ethernet driver. */ @@ -88,9 +96,13 @@ struct usb_ether_platform_data { const char *vendorDescr; }; +extern void android_usb_set_connected(int on); + extern void android_register_function(struct android_usb_function *f); extern void android_enable_function(struct usb_function *f, int enable); +extern int android_get_model_id(void); + #endif /* __LINUX_USB_ANDROID_H */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index c8e62b35..66884030 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -36,10 +36,8 @@ #include #include -#include -struct usb_composite_dev; struct usb_configuration; /** @@ -102,9 +100,7 @@ struct usb_function { struct usb_descriptor_header **hs_descriptors; struct usb_configuration *config; - - /* disabled is zero if the function is enabled */ - int disabled; + int hidden; /* REVISIT: bind() functions can be marked __init, which * makes trouble for section mismatch analysis. See if @@ -132,7 +128,6 @@ struct usb_function { /* private: */ /* internals */ struct list_head list; - DECLARE_BITMAP(endpoints, 32); struct device *dev; }; @@ -143,9 +138,6 @@ int usb_function_activate(struct usb_function *); int usb_interface_id(struct usb_configuration *, struct usb_function *); -void usb_function_set_enabled(struct usb_function *, int); -void usb_composite_force_reset(struct usb_composite_dev *); - /** * ep_choose - select descriptor endpoint at current device speed * @g: gadget, connected and running at some speed @@ -340,7 +332,6 @@ struct usb_composite_dev { /* private: */ /* internals */ - unsigned int suspended:1; struct usb_device_descriptor desc; struct list_head configs; struct usb_composite_driver *driver; @@ -353,15 +344,6 @@ struct usb_composite_dev { /* protects at least deactivation count */ spinlock_t lock; - - /* switch indicating connected/disconnected state */ - struct switch_dev sw_connected; - /* switch indicating current configuration */ - struct switch_dev sw_config; - /* current connected state for sw_connected */ - bool connected; - - struct work_struct switch_work; }; extern int usb_string_id(struct usb_composite_dev *c); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index d3ef42d7..bbf45d50 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -15,8 +15,6 @@ #ifndef __LINUX_USB_GADGET_H #define __LINUX_USB_GADGET_H -#include - struct usb_ep; /** @@ -494,13 +492,9 @@ static inline void set_gadget_data(struct usb_gadget *gadget, void *data) { dev_set_drvdata(&gadget->dev, data); } static inline void *get_gadget_data(struct usb_gadget *gadget) { return dev_get_drvdata(&gadget->dev); } -static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) -{ - return container_of(dev, struct usb_gadget, dev); -} /* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ -#define gadget_for_each_ep(tmp, gadget) \ +#define gadget_for_each_ep(tmp,gadget) \ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)