diff options
author | Benoit Goby <benoit@android.com> | 2011-04-19 20:37:33 -0700 |
---|---|---|
committer | Benoit Goby <benoit@android.com> | 2011-06-17 16:02:37 -0700 |
commit | aab96815ae9a40e05600b8e351561b514233afca (patch) | |
tree | b96a69b2be5f648ee17581246acf97895f1c72bf /drivers | |
parent | 94df1bdfdca9be6d4bbe6cc56354b4ee536cb15a (diff) | |
download | kernel_samsung_aries-aab96815ae9a40e05600b8e351561b514233afca.zip kernel_samsung_aries-aab96815ae9a40e05600b8e351561b514233afca.tar.gz kernel_samsung_aries-aab96815ae9a40e05600b8e351561b514233afca.tar.bz2 |
usb: gadget: android: Update android gadget driver
* Functions and the device descriptor are configured from user space:
echo 0 > /sys/class/android_usb/android0/enable
echo adb,acm > /sys/class/android_usb/android0/functions
echo 2 > /sys/class/android_usb/android0/f_acm/instances
echo 1 > /sys/class/android_usb/android0/enable
* Driver does not require platform data anymore
* Moved function initialization to android.c instead of each
function file
* Replaced switches by uevents
Signed-off-by: Benoit Goby <benoit@android.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>
Change-Id: If5ad9267c111ad0a442f0d87a0d31082dc5381b6
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 49 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 9 | ||||
-rw-r--r-- | drivers/usb/gadget/android.c | 1151 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 221 | ||||
-rw-r--r-- | drivers/usb/gadget/f_accessory.c | 235 | ||||
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 53 | ||||
-rw-r--r-- | drivers/usb/gadget/f_adb.c | 207 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 82 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mtp.c | 208 | ||||
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 92 | ||||
-rw-r--r-- | drivers/usb/gadget/u_ether.h | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/u_serial.c | 4 |
12 files changed, 1199 insertions, 1120 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5b3c58e..144a8c8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -935,7 +935,7 @@ config USB_G_PRINTER For more information, see Documentation/usb/gadget_printer.txt which includes sample code for accessing the device file. -config USB_ANDROID +config USB_G_ANDROID boolean "Android Gadget" depends on SWITCH help @@ -943,53 +943,6 @@ config USB_ANDROID The functions can be configured via a board file and may be enabled and disabled dynamically. -config USB_ANDROID_ACM - boolean "Android gadget ACM serial function" - depends on USB_ANDROID - help - Provides ACM serial function for android gadget driver. - -config USB_ANDROID_ADB - boolean "Android gadget adb function" - depends on USB_ANDROID - help - Provides adb function for android gadget driver. - -config USB_ANDROID_MASS_STORAGE - boolean "Android gadget mass storage function" - depends on USB_ANDROID && SWITCH - help - Provides USB mass storage function for android gadget driver. - -config USB_ANDROID_MTP - boolean "Android MTP function" - depends on USB_ANDROID - help - Provides Media Transfer Protocol (MTP) support for android gadget driver. - -config USB_ANDROID_RNDIS - boolean "Android gadget RNDIS ethernet function" - depends on USB_ANDROID - help - Provides RNDIS ethernet function for android gadget driver. - -config USB_ANDROID_RNDIS_WCEIS - boolean "Use Windows Internet Sharing Class/SubClass/Protocol" - depends on USB_ANDROID_RNDIS - help - Causes the driver to look like a Windows-compatible Internet - Sharing device, so Windows auto-detects it. - - If you enable this option, the device is no longer CDC ethernet - compatible. - - -config USB_ANDROID_ACCESSORY - boolean "Android USB accessory function" - depends on USB_ANDROID - help - Provides Android USB Accessory support for android gadget driver. - config USB_CDC_COMPOSITE tristate "CDC Composite Device (Ethernet and ACM)" depends on NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index e9066b9..ab17a4c 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -49,6 +49,7 @@ g_dbgp-y := dbgp.o g_nokia-y := nokia.o g_webcam-y := webcam.o g_ncm-y := ncm.o +g_android-y := android.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -67,10 +68,4 @@ obj-$(CONFIG_USB_G_MULTI) += g_multi.o obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o -obj-$(CONFIG_USB_ANDROID) += android.o -obj-$(CONFIG_USB_ANDROID_ACM) += f_acm.o u_serial.o -obj-$(CONFIG_USB_ANDROID_ADB) += f_adb.o -obj-$(CONFIG_USB_ANDROID_MASS_STORAGE) += f_mass_storage.o -obj-$(CONFIG_USB_ANDROID_MTP) += f_mtp.o -obj-$(CONFIG_USB_ANDROID_RNDIS) += f_rndis.o u_ether.o -obj-$(CONFIG_USB_ANDROID_ACCESSORY) += f_accessory.o +obj-$(CONFIG_USB_G_ANDROID) += g_android.o diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 2ebc818..377df5b 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -27,7 +27,6 @@ #include <linux/utsname.h> #include <linux/platform_device.h> -#include <linux/usb/android_composite.h> #include <linux/usb/ch9.h> #include <linux/usb/composite.h> #include <linux/usb/gadget.h> @@ -46,6 +45,17 @@ #include "epautoconf.c" #include "composite.c" +#include "f_mass_storage.c" +#include "u_serial.c" +#include "f_acm.c" +#include "f_adb.c" +#include "f_mtp.c" +#include "f_accessory.c" +#define USB_ETH_RNDIS y +#include "f_rndis.c" +#include "rndis.c" +#include "u_ether.c" + MODULE_AUTHOR("Mike Lockwood"); MODULE_DESCRIPTION("Android Composite USB Driver"); MODULE_LICENSE("GPL"); @@ -53,37 +63,68 @@ MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; -/* Default vendor and product IDs, overridden by platform data */ +/* Default vendor and product IDs, overridden by userspace */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 +struct android_usb_function { + char *name; + void *config; + + struct device *dev; + char *dev_name; + struct device_attribute **attributes; + + /* for android_dev.enabled_functions */ + struct list_head enabled_list; + + /* Optional: initialization during gadget bind */ + int (*init)(struct android_usb_function *, struct usb_composite_dev *); + /* Optional: cleanup during gadget unbind */ + void (*cleanup)(struct android_usb_function *); + + int (*bind_config)(struct android_usb_function *, struct usb_configuration *); + + /* Optional: called when the configuration is removed */ + void (*unbind_config)(struct android_usb_function *, struct usb_configuration *); + /* Optional: handle ctrl requests before the device is configured + * and/or before the function is enabled */ + int (*ctrlrequest)(struct android_usb_function *, + struct usb_composite_dev *, + const struct usb_ctrlrequest *); +}; + struct android_dev { + struct android_usb_function **functions; + struct list_head enabled_functions; struct usb_composite_dev *cdev; - struct usb_configuration *config; - int num_products; - struct android_usb_product *products; - int num_functions; - char **functions; - - int vendor_id; - int product_id; - int version; + struct device *dev; + + bool enabled; + bool connected; + bool sw_connected; + struct work_struct work; }; +static struct class *android_class; static struct android_dev *_android_dev; +static int android_bind_config(struct usb_configuration *c); +static void android_unbind_config(struct usb_configuration *c); /* string IDs are assigned dynamically */ - #define STRING_MANUFACTURER_IDX 0 #define STRING_PRODUCT_IDX 1 #define STRING_SERIAL_IDX 2 +static char manufacturer_string[256]; +static char product_string[256]; +static char serial_string[256]; + /* String Table */ static struct usb_string strings_dev[] = { - /* These dummy values should be overridden by platform data */ - [STRING_MANUFACTURER_IDX].s = "Android", - [STRING_PRODUCT_IDX].s = "Android", - [STRING_SERIAL_IDX].s = "0123456789ABCDEF", + [STRING_MANUFACTURER_IDX].s = manufacturer_string, + [STRING_PRODUCT_IDX].s = product_string, + [STRING_SERIAL_IDX].s = serial_string, { } /* end of list */ }; @@ -108,183 +149,788 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct list_head _functions = LIST_HEAD_INIT(_functions); -static bool _are_functions_bound; +static struct usb_configuration android_config_driver = { + .label = "android", + .unbind = android_unbind_config, + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 0xFA, /* 500ma */ +}; -static struct android_usb_function *get_function(const char *name) +static void android_work(struct work_struct *data) { - struct android_usb_function *f; - list_for_each_entry(f, &_functions, list) { - if (!strcmp(name, f->name)) - return f; + struct android_dev *dev = container_of(data, struct android_dev, work); + struct usb_composite_dev *cdev = dev->cdev; + char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; + char *connected[2] = { "USB_STATE=CONNECTED", NULL }; + char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config) { + spin_unlock_irqrestore(&cdev->lock, flags); + kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, + configured); + return; } - return 0; + if (dev->connected != dev->sw_connected) { + dev->sw_connected = dev->connected; + spin_unlock_irqrestore(&cdev->lock, flags); + kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, + dev->sw_connected ? connected : disconnected); + } else { + spin_unlock_irqrestore(&cdev->lock, flags); + } +} + + +/*-------------------------------------------------------------------------*/ +/* Supported functions initialization */ + +static int adb_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) +{ + return adb_setup(); +} + +static void adb_function_cleanup(struct android_usb_function *f) +{ + adb_cleanup(); +} + +static int adb_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) +{ + return adb_bind_config(c); +} + +static struct android_usb_function adb_function = { + .name = "adb", + .init = adb_function_init, + .cleanup = adb_function_cleanup, + .bind_config = adb_function_bind_config, +}; + + +#define MAX_ACM_INSTANCES 4 +struct acm_function_config { + int instances; +}; + +static int acm_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) +{ + f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL); + if (!f->config) + return -ENOMEM; + + return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES); +} + +static void acm_function_cleanup(struct android_usb_function *f) +{ + gserial_cleanup(); + kfree(f->config); + f->config = NULL; } -static bool are_functions_registered(struct android_dev *dev) +static int acm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { - char **functions = dev->functions; int i; + int ret = 0; + struct acm_function_config *config = f->config; - /* Look only for functions required by the board config */ - for (i = 0; i < dev->num_functions; i++) { - char *name = *functions++; - bool is_match = false; - /* Could reuse get_function() here, but a reverse search - * should yield less comparisons overall */ - struct android_usb_function *f; - list_for_each_entry_reverse(f, &_functions, list) { - if (!strcmp(name, f->name)) { - is_match = true; - break; - } + for (i = 0; i < config->instances; i++) { + ret = acm_bind_config(c, i); + if (ret) { + pr_err("Could not bind acm%u config\n", i); + break; } - if (is_match) - continue; - else - return false; } - return true; + return ret; } -static bool should_bind_functions(struct android_dev *dev) +static ssize_t acm_instances_show(struct device *dev, + struct device_attribute *attr, char *buf) { - /* Don't waste time if the main driver hasn't bound */ - if (!dev->config) - return false; + struct android_usb_function *f = dev_get_drvdata(dev); + struct acm_function_config *config = f->config; + return sprintf(buf, "%d\n", config->instances); +} - /* Don't waste time if we've already bound the functions */ - if (_are_functions_bound) - return false; +static ssize_t acm_instances_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct acm_function_config *config = f->config; + int value; + + sscanf(buf, "%d", &value); + if (value > MAX_ACM_INSTANCES) + value = MAX_ACM_INSTANCES; + config->instances = value; + return size; +} - /* This call is the most costly, so call it last */ - if (!are_functions_registered(dev)) - return false; +static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, acm_instances_store); +static struct device_attribute *acm_function_attributes[] = { &dev_attr_instances, NULL }; + +static struct android_usb_function acm_function = { + .name = "acm", + .init = acm_function_init, + .cleanup = acm_function_cleanup, + .bind_config = acm_function_bind_config, + .attributes = acm_function_attributes, +}; - return true; + +static int mtp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) +{ + return mtp_setup(); } -static void bind_functions(struct android_dev *dev) +static void mtp_function_cleanup(struct android_usb_function *f) { - struct android_usb_function *f; - char **functions = dev->functions; - int i; + mtp_cleanup(); +} - for (i = 0; i < dev->num_functions; i++) { - char *name = *functions++; - f = get_function(name); - if (f) - f->bind_config(dev->config); - else - printk(KERN_ERR "function %s not found in bind_functions\n", name); +static int mtp_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) +{ + return mtp_bind_config(c); +} + +static int mtp_function_ctrlrequest(struct android_usb_function *f, + struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *c) +{ + return mtp_ctrlrequest(cdev, c); +} + +static struct android_usb_function mtp_function = { + .name = "mtp", + .init = mtp_function_init, + .cleanup = mtp_function_cleanup, + .bind_config = mtp_function_bind_config, + .ctrlrequest = mtp_function_ctrlrequest, +}; + + +struct rndis_function_config { + u8 ethaddr[ETH_ALEN]; + u32 vendorID; + char manufacturer[256]; + bool wceis; +}; + +static int rndis_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) +{ + f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL); + if (!f->config) + return -ENOMEM; + return 0; +} + +static void rndis_function_cleanup(struct android_usb_function *f) +{ + kfree(f->config); + f->config = NULL; +} + +static int rndis_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + int ret; + struct rndis_function_config *rndis = f->config; + + if (!rndis) { + pr_err("%s: rndis_pdata\n", __func__); + return -1; } - _are_functions_bound = true; + pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, + rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], + rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); + + ret = gether_setup(c->cdev->gadget, rndis->ethaddr); + if (ret) { + pr_err("%s: gether_setup failed\n", __func__); + return ret; + } + + if (rndis->wceis) { + /* "Wireless" RNDIS; auto-detected by Windows */ + rndis_iad_descriptor.bFunctionClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_iad_descriptor.bFunctionSubClass = 0x01; + rndis_iad_descriptor.bFunctionProtocol = 0x03; + rndis_control_intf.bInterfaceClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_control_intf.bInterfaceSubClass = 0x01; + rndis_control_intf.bInterfaceProtocol = 0x03; + } + + return rndis_bind_config(c, rndis->ethaddr, rndis->vendorID, + rndis->manufacturer); } -static int android_bind_config(struct usb_configuration *c) +static void rndis_function_unbind_config(struct android_usb_function *f, + struct usb_configuration *c) { - struct android_dev *dev = _android_dev; + gether_cleanup(); +} - printk(KERN_DEBUG "android_bind_config\n"); - dev->config = c; +static ssize_t rndis_manufacturer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%s\n", config->manufacturer); +} - if (should_bind_functions(dev)) - bind_functions(dev); +static ssize_t rndis_manufacturer_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + + if (size >= sizeof(config->manufacturer)) + return -EINVAL; + if (sscanf(buf, "%s", config->manufacturer) == 1) + return size; + return -1; +} + +static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show, + rndis_manufacturer_store); + +static ssize_t rndis_wceis_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%d\n", config->wceis); +} +static ssize_t rndis_wceis_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + int value; + + if (sscanf(buf, "%d", &value) == 1) { + config->wceis = value; + return size; + } + return -EINVAL; +} + +static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show, + rndis_wceis_store); + +static ssize_t rndis_ethaddr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *rndis = f->config; + return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], + rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); +} + +static ssize_t rndis_ethaddr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *rndis = f->config; + + if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + (int *)&rndis->ethaddr[0], (int *)&rndis->ethaddr[1], + (int *)&rndis->ethaddr[2], (int *)&rndis->ethaddr[3], + (int *)&rndis->ethaddr[4], (int *)&rndis->ethaddr[5]) == 6) + return size; + return -EINVAL; +} + +static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show, + rndis_ethaddr_store); + +static ssize_t rndis_vendorID_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%04x\n", config->vendorID); +} + +static ssize_t rndis_vendorID_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + int value; + + if (sscanf(buf, "%04x", &value) == 1) { + config->vendorID = value; + return size; + } + return -EINVAL; +} + +static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show, + rndis_vendorID_store); + +static struct device_attribute *rndis_function_attributes[] = { + &dev_attr_manufacturer, + &dev_attr_wceis, + &dev_attr_ethaddr, + &dev_attr_vendorID, + NULL +}; + +static struct android_usb_function rndis_function = { + .name = "rndis", + .init = rndis_function_init, + .cleanup = rndis_function_cleanup, + .bind_config = rndis_function_bind_config, + .unbind_config = rndis_function_unbind_config, + .attributes = rndis_function_attributes, +}; + + +struct mass_storage_function_config { + struct fsg_config fsg; + struct fsg_common *common; +}; + +static int mass_storage_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) +{ + struct mass_storage_function_config *config; + struct fsg_common *common; + int err; + + config = kzalloc(sizeof(struct mass_storage_function_config), + GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->fsg.nluns = 1; + config->fsg.luns[0].removable = 1; + + common = fsg_common_init(NULL, cdev, &config->fsg); + if (IS_ERR(common)) { + kfree(config); + return PTR_ERR(common); + } + + err = sysfs_create_link(&f->dev->kobj, + &common->luns[0].dev.kobj, + "lun"); + if (err) { + kfree(config); + return err; + } + + config->common = common; + f->config = config; return 0; } -static int android_setup_config(struct usb_configuration *c, - const struct usb_ctrlrequest *ctrl); +static void mass_storage_function_cleanup(struct android_usb_function *f) +{ + kfree(f->config); + f->config = NULL; +} -static struct usb_configuration android_config_driver = { - .label = "android", - .setup = android_setup_config, - .bConfigurationValue = 1, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 0xFA, /* 500ma */ +static int mass_storage_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + struct mass_storage_function_config *config = f->config; + return fsg_bind_config(c->cdev, c, config->common); +} + +static ssize_t mass_storage_inquiry_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct mass_storage_function_config *config = f->config; + return sprintf(buf, "%s\n", config->common->inquiry_string); +} + +static ssize_t mass_storage_inquiry_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct mass_storage_function_config *config = f->config; + if (size >= sizeof(config->common->inquiry_string)) + return -EINVAL; + if (sscanf(buf, "%s", config->common->inquiry_string) != 1) + return -EINVAL; + return size; +} + +static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR, + mass_storage_inquiry_show, + mass_storage_inquiry_store); + +static struct device_attribute *mass_storage_function_attributes[] = { + &dev_attr_inquiry_string, + NULL }; -static int android_setup_config(struct usb_configuration *c, - const struct usb_ctrlrequest *ctrl) +static struct android_usb_function mass_storage_function = { + .name = "mass_storage", + .init = mass_storage_function_init, + .cleanup = mass_storage_function_cleanup, + .bind_config = mass_storage_function_bind_config, + .attributes = mass_storage_function_attributes, +}; + + +static int accessory_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) { - int i; - int ret = -EOPNOTSUPP; - - 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( - android_config_driver.interface[i], ctrl); - if (ret >= 0) - return ret; + return acc_setup(); +} + +static void accessory_function_cleanup(struct android_usb_function *f) +{ + acc_cleanup(); +} + +static int accessory_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + return acc_bind_config(c); +} + +static int accessory_function_ctrlrequest(struct android_usb_function *f, + struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *c) +{ + return acc_ctrlrequest(cdev, c); +} + +static struct android_usb_function accessory_function = { + .name = "accessory", + .init = accessory_function_init, + .cleanup = accessory_function_cleanup, + .bind_config = accessory_function_bind_config, + .ctrlrequest = accessory_function_ctrlrequest, +}; + + +static struct android_usb_function *supported_functions[] = { + &adb_function, + &acm_function, + &mtp_function, + &rndis_function, + &mass_storage_function, + &accessory_function, + NULL +}; + + +static int android_init_functions(struct android_usb_function **functions, + struct usb_composite_dev *cdev) +{ + struct android_dev *dev = _android_dev; + struct android_usb_function *f; + struct device_attribute **attrs; + struct device_attribute *attr; + int err; + int index = 0; + + for (; (f = *functions++); index++) { + f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); + f->dev = device_create(android_class, dev->dev, + MKDEV(0, index), f, f->dev_name); + if (IS_ERR(f->dev)) { + pr_err("%s: Failed to create dev %s", __func__, + f->dev_name); + err = PTR_ERR(f->dev); + goto err_create; + } + + if (f->init) { + err = f->init(f, cdev); + if (err) { + pr_err("%s: Failed to init %s", __func__, + f->name); + goto err_out; + } + } + + attrs = f->attributes; + if (attrs) { + while ((attr = *attrs++) && !err) + err = device_create_file(f->dev, attr); + } + if (err) { + pr_err("%s: Failed to create function %s attributes", + __func__, f->name); + goto err_out; } } - return ret; + return 0; + +err_out: + device_destroy(android_class, f->dev->devt); +err_create: + kfree(f->dev_name); + return err; } -static int product_has_function(struct android_usb_product *p, - struct usb_function *f) +static void android_cleanup_functions(struct android_usb_function **functions) { - char **functions = p->functions; - int count = p->num_functions; - const char *name = f->name; - int i; + struct android_usb_function *f; - for (i = 0; i < count; i++) { - /* For functions with multiple instances, usb_function.name - * will have an index appended to the core name (ex: acm0), - * while android_usb_product.functions[i] will only have the - * core name (ex: acm). So, only compare up to the length of - * android_usb_product.functions[i]. - */ - if (!strncmp(name, functions[i], strlen(functions[i]))) - return 1; + while (*functions) { + f = *functions++; + + if (f->dev) { + device_destroy(android_class, f->dev->devt); + kfree(f->dev_name); + } + + if (f->cleanup) + f->cleanup(f); + } +} + +static int +android_bind_enabled_functions(struct android_dev *dev, + struct usb_configuration *c) +{ + struct android_usb_function *f; + int ret; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) { + ret = f->bind_config(f, c); + if (ret) { + pr_err("%s: %s failed", __func__, f->name); + return ret; + } } return 0; } -static int product_matches_functions(struct android_usb_product *p) +static void +android_unbind_enabled_functions(struct android_dev *dev, + struct usb_configuration *c) { - struct usb_function *f; - list_for_each_entry(f, &android_config_driver.functions, list) { - if (product_has_function(p, f) == !!f->disabled) + struct android_usb_function *f; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) { + if (f->unbind_config) + f->unbind_config(f, c); + } +} + +static int android_enable_function(struct android_dev *dev, char *name) +{ + struct android_usb_function **functions = dev->functions; + struct android_usb_function *f; + while ((f = *functions++)) { + if (!strcmp(name, f->name)) { + list_add_tail(&f->enabled_list, &dev->enabled_functions); return 0; + } } - return 1; + return -EINVAL; } -static int get_vendor_id(struct android_dev *dev) +/*-------------------------------------------------------------------------*/ +/* /sys/class/android_usb/android%d/ interface */ + +static ssize_t +functions_show(struct device *pdev, struct device_attribute *attr, char *buf) { - struct android_usb_product *p = dev->products; - int count = dev->num_products; - int i; + struct android_dev *dev = dev_get_drvdata(pdev); + struct android_usb_function *f; + char *buff = buf; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) + buff += sprintf(buff, "%s,", f->name); + if (buff != buf) + *(buff-1) = '\n'; + return buff - buf; +} - if (p) { - for (i = 0; i < count; i++, p++) { - if (p->vendor_id && product_matches_functions(p)) - return p->vendor_id; +static ssize_t +functions_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t size) +{ + struct android_dev *dev = dev_get_drvdata(pdev); + char *name; + char buf[256], *b; + int err; + + INIT_LIST_HEAD(&dev->enabled_functions); + + strncpy(buf, buff, sizeof(buf)); + b = strim(buf); + + while (b) { + name = strsep(&b, ","); + if (name) { + err = android_enable_function(dev, name); + if (err) + pr_err("android_usb: Cannot enable '%s'", name); } } - /* use default vendor ID */ - return dev->vendor_id; + + return size; } -static int get_product_id(struct android_dev *dev) +static ssize_t enable_show(struct device *pdev, struct device_attribute *attr, + char *buf) { - struct android_usb_product *p = dev->products; - int count = dev->num_products; - int i; + struct android_dev *dev = dev_get_drvdata(pdev); + return sprintf(buf, "%d\n", dev->enabled); +} - if (p) { - for (i = 0; i < count; i++, p++) { - if (product_matches_functions(p)) - return p->product_id; - } +static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t size) +{ + struct android_dev *dev = dev_get_drvdata(pdev); + struct usb_composite_dev *cdev = dev->cdev; + int enabled = 0; + + sscanf(buff, "%d", &enabled); + if (enabled && !dev->enabled) { + /* update values in composite driver's copy of device descriptor */ + cdev->desc.idVendor = device_desc.idVendor; + cdev->desc.idProduct = device_desc.idProduct; + cdev->desc.bcdDevice = device_desc.bcdDevice; + cdev->desc.bDeviceClass = device_desc.bDeviceClass; + cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass; + cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol; + usb_add_config(cdev, &android_config_driver, + android_bind_config); + usb_gadget_connect(cdev->gadget); + dev->enabled = true; + } else if (!enabled && dev->enabled) { + usb_gadget_disconnect(cdev->gadget); + usb_remove_config(cdev, &android_config_driver); + dev->enabled = false; + } else { + pr_err("android_usb: already %s\n", + dev->enabled ? "enabled" : "disabled"); } - /* use default product ID */ - return dev->product_id; + return size; +} + +static ssize_t state_show(struct device *pdev, struct device_attribute *attr, + char *buf) +{ + struct android_dev *dev = dev_get_drvdata(pdev); + struct usb_composite_dev *cdev = dev->cdev; + char *state = "DISCONNECTED"; + unsigned long flags; + + if (!cdev) + goto out; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config) + state = "CONFIGURED"; + else if (dev->connected) + state = "CONNECTED"; + spin_unlock_irqrestore(&cdev->lock, flags); +out: + return sprintf(buf, "%s\n", state); +} + +#define DESCRIPTOR_ATTR(field, format_string) \ +static ssize_t \ +field ## _show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, format_string, device_desc.field); \ +} \ +static ssize_t \ +field ## _store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + int value; \ + if (sscanf(buf, format_string, &value) == 1) { \ + device_desc.field = value; \ + return size; \ + } \ + return -1; \ +} \ +static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); + +#define DESCRIPTOR_STRING_ATTR(field, buffer) \ +static ssize_t \ +field ## _show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, "%s", buffer); \ +} \ +static ssize_t \ +field ## _store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + if (size >= sizeof(buffer)) return -EINVAL; \ + if (sscanf(buf, "%s", buffer) == 1) { \ + return size; \ + } \ + return -1; \ +} \ +static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); + + +DESCRIPTOR_ATTR(idVendor, "%04x\n") +DESCRIPTOR_ATTR(idProduct, "%04x\n") +DESCRIPTOR_ATTR(bcdDevice, "%04x\n") +DESCRIPTOR_ATTR(bDeviceClass, "%d\n") +DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n") +DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n") +DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string) +DESCRIPTOR_STRING_ATTR(iProduct, product_string) +DESCRIPTOR_STRING_ATTR(iSerial, serial_string) + +static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); +static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); + +static struct device_attribute *android_usb_attributes[] = { + &dev_attr_idVendor, + &dev_attr_idProduct, + &dev_attr_bcdDevice, + &dev_attr_bDeviceClass, + &dev_attr_bDeviceSubClass, + &dev_attr_bDeviceProtocol, + &dev_attr_iManufacturer, + &dev_attr_iProduct, + &dev_attr_iSerial, + &dev_attr_functions, + &dev_attr_enable, + &dev_attr_state, + NULL +}; + +/*-------------------------------------------------------------------------*/ +/* Composite driver */ + +static int android_bind_config(struct usb_configuration *c) +{ + struct android_dev *dev = _android_dev; + int ret = 0; + + ret = android_bind_enabled_functions(dev, c); + if (ret) + return ret; + + return 0; +} + +static void android_unbind_config(struct usb_configuration *c) +{ + struct android_dev *dev = _android_dev; + + android_unbind_enabled_functions(dev, c); } static int android_bind(struct usb_composite_dev *cdev) @@ -293,7 +939,11 @@ static int android_bind(struct usb_composite_dev *cdev) struct usb_gadget *gadget = cdev->gadget; int gcnum, id, ret; - printk(KERN_INFO "android_bind\n"); + usb_gadget_disconnect(gadget); + + ret = android_init_functions(dev->functions, cdev); + if (ret) + return ret; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -310,19 +960,17 @@ static int android_bind(struct usb_composite_dev *cdev) strings_dev[STRING_PRODUCT_IDX].id = id; device_desc.iProduct = id; + /* Default strings - should be updated by userspace */ + strncpy(manufacturer_string, "Android", sizeof(manufacturer_string) - 1); + strncpy(product_string, "Android", sizeof(product_string) - 1); + strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); + id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; - /* register our configuration */ - ret = usb_add_config(cdev, &android_config_driver, android_bind_config); - if (ret) { - printk(KERN_ERR "usb_add_config failed\n"); - return ret; - } - gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); @@ -341,185 +989,136 @@ static int android_bind(struct usb_composite_dev *cdev) usb_gadget_set_selfpowered(gadget); dev->cdev = cdev; - device_desc.idVendor = __constant_cpu_to_le16(get_vendor_id(dev)); - device_desc.idProduct = __constant_cpu_to_le16(get_product_id(dev)); - cdev->desc.idVendor = device_desc.idVendor; - cdev->desc.idProduct = device_desc.idProduct; return 0; } +static int android_usb_unbind(struct usb_composite_dev *cdev) +{ + struct android_dev *dev = _android_dev; + + cancel_work_sync(&dev->work); + android_cleanup_functions(dev->functions); + return 0; +} + static struct usb_composite_driver android_usb_driver = { .name = "android_usb", .dev = &device_desc, .strings = dev_strings, - .enable_function = android_enable_function, + .unbind = android_usb_unbind, }; -void android_register_function(struct android_usb_function *f) +static int +android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) { - struct android_dev *dev = _android_dev; - - printk(KERN_INFO "android_register_function %s\n", f->name); - list_add_tail(&f->list, &_functions); - - if (dev && should_bind_functions(dev)) - bind_functions(dev); -} - -void update_dev_desc(struct android_dev *dev) -{ - struct usb_function *f; - struct usb_function *last_enabled_f = NULL; - int num_enabled = 0; - int has_iad = 0; - - dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; - dev->cdev->desc.bDeviceSubClass = 0x00; - dev->cdev->desc.bDeviceProtocol = 0x00; - - list_for_each_entry(f, &android_config_driver.functions, list) { - if (!f->disabled) { - num_enabled++; - last_enabled_f = f; - if (f->descriptors[0]->bDescriptorType == - USB_DT_INTERFACE_ASSOCIATION) - has_iad = 1; - } - if (num_enabled > 1 && has_iad) { - dev->cdev->desc.bDeviceClass = USB_CLASS_MISC; - dev->cdev->desc.bDeviceSubClass = 0x02; - dev->cdev->desc.bDeviceProtocol = 0x01; - break; + struct android_dev *dev = _android_dev; + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_request *req = cdev->req; + struct android_usb_function **functions = dev->functions; + struct android_usb_function *f; + int value = -EOPNOTSUPP; + unsigned long flags; + + req->zero = 0; + req->complete = composite_setup_complete; + req->length = 0; + gadget->ep0->driver_data = cdev; + + while ((f = *functions++)) { + if (f->ctrlrequest) { + value = f->ctrlrequest(f, cdev, c); + if (value >= 0) + break; } } - if (num_enabled == 1) { -#ifdef CONFIG_USB_ANDROID_RNDIS - if (!strcmp(last_enabled_f->name, "rndis")) { -#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS - dev->cdev->desc.bDeviceClass = - USB_CLASS_WIRELESS_CONTROLLER; -#else - dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; -#endif - } -#endif + if (value < 0) + value = composite_setup(gadget, c); + + spin_lock_irqsave(&cdev->lock, flags); + if (!dev->connected) { + dev->connected = 1; + schedule_work(&dev->work); } + else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) { + schedule_work(&dev->work); + } + spin_unlock_irqrestore(&cdev->lock, flags); + + return value; } -void android_enable_function(struct usb_function *f, int enable) +static void android_disconnect(struct usb_gadget *gadget) { struct android_dev *dev = _android_dev; - int disable = !enable; - - if (!!f->disabled != disable) { - usb_function_set_enabled(f, !disable); - -#ifdef CONFIG_USB_ANDROID_RNDIS - if (!strcmp(f->name, "rndis")) { - struct usb_function *func; - /* Windows does not support other interfaces when RNDIS is enabled, - * so we disable UMS and MTP 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); - } - } - } -#endif -#ifdef CONFIG_USB_ANDROID_ACCESSORY - if (!strcmp(f->name, "accessory") && enable) { - struct usb_function *func; - - /* disable everything else (and keep adb for now) */ - list_for_each_entry(func, &android_config_driver.functions, list) { - if (strcmp(func->name, "accessory") - && strcmp(func->name, "adb")) { - usb_function_set_enabled(func, 0); - } - } - } -#endif - - update_dev_desc(dev); - - device_desc.idVendor = __constant_cpu_to_le16(get_vendor_id(dev)); - device_desc.idProduct = __constant_cpu_to_le16(get_product_id(dev)); - if (dev->cdev) { - dev->cdev->desc.idVendor = device_desc.idVendor; - dev->cdev->desc.idProduct = device_desc.idProduct; - } - usb_composite_force_reset(dev->cdev); - } + dev->connected = 0; + schedule_work(&dev->work); + composite_disconnect(gadget); } -static int android_probe(struct platform_device *pdev) +static int android_create_device(struct android_dev *dev) { - struct android_usb_platform_data *pdata = pdev->dev.platform_data; - struct android_dev *dev = _android_dev; - - printk(KERN_INFO "android_probe pdata: %p\n", pdata); - - if (pdata) { - dev->products = pdata->products; - dev->num_products = pdata->num_products; - dev->functions = pdata->functions; - dev->num_functions = pdata->num_functions; - if (pdata->vendor_id) { - dev->vendor_id = pdata->vendor_id; - device_desc.idVendor = - __constant_cpu_to_le16(pdata->vendor_id); + struct device_attribute **attrs = android_usb_attributes; + struct device_attribute *attr; + int err; + + dev->dev = device_create(android_class, NULL, + MKDEV(0, 0), NULL, "android0"); + if (IS_ERR(dev->dev)) + return PTR_ERR(dev->dev); + + dev_set_drvdata(dev->dev, dev); + + while ((attr = *attrs++)) { + err = device_create_file(dev->dev, attr); + if (err) { + device_destroy(android_class, dev->dev->devt); + return err; } - if (pdata->product_id) { - dev->product_id = pdata->product_id; - device_desc.idProduct = - __constant_cpu_to_le16(pdata->product_id); - } - if (pdata->version) - dev->version = pdata->version; - - if (pdata->product_name) - strings_dev[STRING_PRODUCT_IDX].s = pdata->product_name; - if (pdata->manufacturer_name) - strings_dev[STRING_MANUFACTURER_IDX].s = - pdata->manufacturer_name; - if (pdata->serial_number) - strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number; } - - return usb_composite_probe(&android_usb_driver, android_bind); + return 0; } -static struct platform_driver android_platform_driver = { - .driver = { .name = "android_usb", }, - .probe = android_probe, -}; static int __init init(void) { struct android_dev *dev; + int err; - printk(KERN_INFO "android init\n"); + android_class = class_create(THIS_MODULE, "android_usb"); + if (IS_ERR(android_class)) + return PTR_ERR(android_class); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - /* set default values, which should be overridden by platform data */ - dev->product_id = PRODUCT_ID; + dev->functions = supported_functions; + INIT_LIST_HEAD(&dev->enabled_functions); + INIT_WORK(&dev->work, android_work); + + err = android_create_device(dev); + if (err) { + class_destroy(android_class); + kfree(dev); + return err; + } + _android_dev = dev; - return platform_driver_register(&android_platform_driver); + /* Override composite driver functions */ + composite_driver.setup = android_setup; + composite_driver.disconnect = android_disconnect; + + return usb_composite_probe(&android_usb_driver, android_bind); } module_init(init); static void __exit cleanup(void) { usb_composite_unregister(&android_usb_driver); - platform_driver_unregister(&android_platform_driver); + class_destroy(android_class); kfree(_android_dev); _android_dev = NULL; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 6c8fbb1..dc06da6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -25,8 +25,7 @@ #include <linux/slab.h> #include <linux/device.h> #include <linux/utsname.h> -#include <linux/delay.h> -#include <linux/kdev_t.h> + #include <linux/usb/composite.h> @@ -76,56 +75,6 @@ static char composite_manufacturer[50]; /*-------------------------------------------------------------------------*/ -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); -} - -static ssize_t enable_store( - struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) -{ - struct usb_function *f = dev_get_drvdata(dev); - struct usb_composite_driver *driver = f->config->cdev->driver; - int value; - - sscanf(buf, "%d", &value); - if (driver->enable_function) - driver->enable_function(f, value); - else - usb_function_set_enabled(f, 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 * @config: the configuration @@ -143,30 +92,15 @@ void usb_composite_force_reset(struct usb_composite_dev *cdev) int usb_add_function(struct usb_configuration *config, struct usb_function *function) { - struct usb_composite_dev *cdev = config->cdev; int value = -EINVAL; - int index; - DBG(cdev, "adding '%s'/%p to config '%s'/%p\n", + DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", function->name, function, config->label, config); if (!function->set_alt || !function->disable) goto done; - index = atomic_inc_return(&cdev->driver->function_count); - function->dev = device_create(cdev->driver->class, NULL, - MKDEV(0, index), NULL, function->name); - if (IS_ERR(function->dev)) - return PTR_ERR(function->dev); - - value = device_create_file(function->dev, &dev_attr_enable); - if (value < 0) { - device_destroy(cdev->driver->class, MKDEV(0, index)); - return value; - } - dev_set_drvdata(function->dev, function); - function->config = config; list_add_tail(&function->list, &config->functions); @@ -192,7 +126,7 @@ int usb_add_function(struct usb_configuration *config, done: if (value) - DBG(cdev, "adding '%s'/%p --> %d\n", + DBG(config->cdev, "adding '%s'/%p --> %d\n", function->name, function, value); return value; } @@ -302,20 +236,17 @@ static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { struct usb_config_descriptor *c = buf; - struct usb_interface_descriptor *intf; - struct usb_interface_assoc_descriptor *iad = NULL; void *next = buf + USB_DT_CONFIG_SIZE; int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; struct usb_function *f; int status; - int interfaceCount = 0; - u8 *dest; /* write the config descriptor */ c = buf; c->bLength = USB_DT_CONFIG_SIZE; c->bDescriptorType = type; - /* wTotalLength and bNumInterfaces are written later */ + /* wTotalLength is written later */ + c->bNumInterfaces = config->next_interface_id; c->bConfigurationValue = config->bConfigurationValue; c->iConfiguration = config->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; @@ -334,54 +265,23 @@ static int config_buf(struct usb_configuration *config, /* add each function's descriptors */ list_for_each_entry(f, &config->functions, list) { struct usb_descriptor_header **descriptors; - struct usb_descriptor_header *descriptor; if (speed == USB_SPEED_HIGH) descriptors = f->hs_descriptors; else descriptors = f->descriptors; - if (f->disabled || !descriptors || descriptors[0] == NULL) + if (!descriptors) continue; status = usb_descriptor_fillbuf(next, len, (const struct usb_descriptor_header **) descriptors); if (status < 0) return status; - - /* set interface numbers dynamically */ - dest = next; - 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; - if (iad) { - iad->bFirstInterface = - intf->bInterfaceNumber; - iad = NULL; - } - } else if (intf->bDescriptorType == - USB_DT_INTERFACE_ASSOCIATION) { - /* This will be first if it exists. Save - * a pointer to it so we can properly set - * bFirstInterface when we process the first - * interface. - */ - iad = (struct usb_interface_assoc_descriptor *) - dest; - } - dest += intf->bLength; - } - len -= status; next += status; } len = next - buf; c->wTotalLength = cpu_to_le16(len); - c->bNumInterfaces = interfaceCount; return len; } @@ -528,8 +428,6 @@ static int set_config(struct usb_composite_dev *cdev, if (!f) break; - if (f->disabled) - continue; /* * Record which endpoints are used by the function. This is used @@ -579,8 +477,6 @@ static int set_config(struct usb_composite_dev *cdev, done: usb_gadget_vbus_draw(gadget, power); - schedule_work(&cdev->switch_work); - if (result >= 0 && cdev->delayed_status) result = USB_GADGET_DELAYED_STATUS; return result; @@ -628,6 +524,7 @@ int usb_add_config(struct usb_composite_dev *cdev, INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; + memset(config->interface, '\0', sizeof(config->interface)); status = bind(config); if (status < 0) { @@ -961,14 +858,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) 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 @@ -1012,21 +901,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; @@ -1140,25 +1014,6 @@ unknown: value = c->setup(c, ctrl); } - /* If the vendor request is not processed (value < 0), - * call all device registered configure setup callbacks - * to process it. - * This is used to handle the following cases: - * - vendor request is for the device and arrives before - * setconfiguration. - * - Some devices are required to handle vendor request before - * setconfiguration such as MTP, USBNET. - */ - - if (value < 0) { - struct usb_configuration *cfg; - - list_for_each_entry(cfg, &cdev->configs, list) { - if (cfg && cfg->setup) - value = cfg->setup(cfg, ctrl); - } - } - goto done; } @@ -1194,12 +1049,8 @@ static void composite_disconnect(struct usb_gadget *gadget) spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) reset_config(cdev); - if (composite->disconnect) composite->disconnect(cdev); - - cdev->connected = 0; - schedule_work(&cdev->switch_work); spin_unlock_irqrestore(&cdev->lock, flags); } @@ -1242,8 +1093,6 @@ 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); device_remove_file(&gadget->dev, &dev_attr_suspended); kfree(cdev); set_gadget_data(gadget, NULL); @@ -1263,30 +1112,6 @@ static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) return *desc; } -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) { struct usb_composite_dev *cdev; @@ -1336,16 +1161,6 @@ 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; @@ -1451,23 +1266,6 @@ composite_resume(struct usb_gadget *gadget) 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; -} - /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver composite_driver = { @@ -1520,11 +1318,6 @@ int usb_composite_probe(struct usb_composite_driver *driver, composite = driver; composite_gadget_bind = bind; - 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_probe_driver(&composite_driver, composite_bind); } diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c index ad3c173..873ab2e 100644 --- a/drivers/usb/gadget/f_accessory.c +++ b/drivers/usb/gadget/f_accessory.c @@ -35,7 +35,6 @@ #include <linux/usb.h> #include <linux/usb/ch9.h> -#include <linux/usb/android_composite.h> #include <linux/usb/f_accessory.h> #define BULK_BUFFER_SIZE 16384 @@ -249,12 +248,11 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req) static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) { struct acc_dev *dev = ep->driver_data; - struct usb_composite_dev *cdev = dev->cdev; char *string_dest = NULL; int length = req->actual; if (req->status != 0) { - DBG(cdev, "acc_complete_set_string, err %d\n", req->status); + pr_err("acc_complete_set_string, err %d\n", req->status); return; } @@ -285,12 +283,12 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) length = ACC_STRING_SIZE - 1; spin_lock_irqsave(&dev->lock, flags); - memcpy(string_dest, cdev->req->buf, length); + memcpy(string_dest, req->buf, length); /* ensure zero termination */ string_dest[length] = 0; spin_unlock_irqrestore(&dev->lock, flags); } else { - DBG(cdev, "unknown accessory string index %d\n", + pr_err("unknown accessory string index %d\n", dev->string_index); } } @@ -364,12 +362,11 @@ static ssize_t acc_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { struct acc_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, "acc_read(%d)\n", count); + pr_debug("acc_read(%d)\n", count); if (dev->disconnected) return -ENODEV; @@ -378,7 +375,7 @@ static ssize_t acc_read(struct file *fp, char __user *buf, count = BULK_BUFFER_SIZE; /* we will block until we're online */ - DBG(cdev, "acc_read: waiting for online\n"); + pr_debug("acc_read: waiting for online\n"); ret = wait_event_interruptible(dev->read_wq, dev->online); if (ret < 0) { r = ret; @@ -395,7 +392,7 @@ requeue_req: r = -EIO; goto done; } else { - DBG(cdev, "rx %p queue\n", req); + pr_debug("rx %p queue\n", req); } /* wait for a request to complete */ @@ -410,7 +407,7 @@ requeue_req: if (req->actual == 0) goto requeue_req; - DBG(cdev, "rx %p %d\n", req, req->actual); + pr_debug("rx %p %d\n", req, req->actual); xfer = (req->actual < count) ? req->actual : count; r = xfer; if (copy_to_user(buf, req->buf, xfer)) @@ -419,7 +416,7 @@ requeue_req: r = -EIO; done: - DBG(cdev, "acc_read returning %d\n", r); + pr_debug("acc_read returning %d\n", r); return r; } @@ -427,19 +424,18 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { struct acc_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req = 0; int r = count, xfer; int ret; - DBG(cdev, "acc_write(%d)\n", count); + pr_debug("acc_write(%d)\n", count); if (!dev->online || dev->disconnected) return -ENODEV; while (count > 0) { if (!dev->online) { - DBG(cdev, "acc_write dev->error\n"); + pr_debug("acc_write dev->error\n"); r = -EIO; break; } @@ -465,7 +461,7 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, req->length = xfer; ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); if (ret < 0) { - DBG(cdev, "acc_write: xfer error %d\n", ret); + pr_debug("acc_write: xfer error %d\n", ret); r = -EIO; break; } @@ -480,7 +476,7 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, if (req) req_put(dev, &dev->tx_idle, req); - DBG(cdev, "acc_write returning %d\n", r); + pr_debug("acc_write returning %d\n", r); return r; } @@ -490,9 +486,6 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value) char *src = NULL; int ret; - if (dev->function.disabled) - return -ENODEV; - switch (code) { case ACCESSORY_GET_STRING_MANUFACTURER: src = dev->manufacturer; @@ -558,6 +551,69 @@ static struct miscdevice acc_device = { .fops = &acc_fops, }; + +static int acc_ctrlrequest(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl) +{ + struct acc_dev *dev = _acc_dev; + int value = -EOPNOTSUPP; + u8 b_requestType = ctrl->bRequestType; + u8 b_request = ctrl->bRequest; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + +/* + printk(KERN_INFO "acc_ctrlrequest " + "%02x.%02x v%04x i%04x l%u\n", + b_requestType, b_request, + w_value, w_index, w_length); +*/ + + if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { + if (b_request == ACCESSORY_START) { + schedule_delayed_work( + &dev->work, msecs_to_jiffies(10)); + value = 0; + } else if (b_request == ACCESSORY_SEND_STRING) { + dev->string_index = w_index; + cdev->gadget->ep0->driver_data = dev; + cdev->req->complete = acc_complete_set_string; + value = w_length; + } + } else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { + if (b_request == ACCESSORY_GET_PROTOCOL) { + *((u16 *)cdev->req->buf) = PROTOCOL_VERSION; + value = sizeof(u16); + + /* clear any strings left over from a previous session */ + memset(dev->manufacturer, 0, sizeof(dev->manufacturer)); + memset(dev->model, 0, sizeof(dev->model)); + memset(dev->description, 0, sizeof(dev->description)); + memset(dev->version, 0, sizeof(dev->version)); + memset(dev->uri, 0, sizeof(dev->uri)); + memset(dev->serial, 0, sizeof(dev->serial)); + } + } + + if (value >= 0) { + cdev->req->zero = 0; + cdev->req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); + if (value < 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 acc_function_bind(struct usb_configuration *c, struct usb_function *f) { @@ -566,7 +622,6 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f) int id; int ret; - dev->cdev = cdev; DBG(cdev, "acc_function_bind dev: %p\n", dev); /* allocate interface ID(s) */ @@ -602,90 +657,16 @@ acc_function_unbind(struct usb_configuration *c, struct usb_function *f) struct usb_request *req; int i; - spin_lock_irq(&dev->lock); while ((req = req_get(dev, &dev->tx_idle))) acc_request_free(req, dev->ep_in); for (i = 0; i < RX_REQ_MAX; i++) acc_request_free(dev->rx_req[i], dev->ep_out); - dev->online = 0; - spin_unlock_irq(&dev->lock); - - misc_deregister(&acc_device); - kfree(_acc_dev); - _acc_dev = NULL; } static void acc_work(struct work_struct *data) { - struct delayed_work *delayed = to_delayed_work(data); - struct acc_dev *dev = - container_of(delayed, struct acc_dev, work); - android_enable_function(&dev->function, 1); -} - -static int acc_function_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct acc_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = dev->cdev; - int value = -EOPNOTSUPP; - u8 b_requestType = ctrl->bRequestType; - u8 b_request = ctrl->bRequest; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - -/* - printk(KERN_INFO "acc_function_setup " - "%02x.%02x v%04x i%04x l%u\n", - b_requestType, b_request, - w_value, w_index, w_length); -*/ - - if (dev->function.disabled) { - if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { - if (b_request == ACCESSORY_START) { - schedule_delayed_work( - &dev->work, msecs_to_jiffies(10)); - value = 0; - } else if (b_request == ACCESSORY_SEND_STRING) { - dev->string_index = w_index; - cdev->gadget->ep0->driver_data = dev; - cdev->req->complete = acc_complete_set_string; - value = w_length; - } - } else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { - if (b_request == ACCESSORY_GET_PROTOCOL) { - *((u16 *)cdev->req->buf) = PROTOCOL_VERSION; - value = sizeof(u16); - - /* clear any strings left over from a previous session */ - memset(dev->manufacturer, 0, sizeof(dev->manufacturer)); - memset(dev->model, 0, sizeof(dev->model)); - memset(dev->description, 0, sizeof(dev->description)); - memset(dev->version, 0, sizeof(dev->version)); - memset(dev->uri, 0, sizeof(dev->uri)); - memset(dev->serial, 0, sizeof(dev->serial)); - } - } - } - - if (value >= 0) { - cdev->req->zero = 0; - cdev->req->length = value; - value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); - if (value < 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; + char *envp[2] = { "ACCESSORY=START", NULL }; + kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp); } static int acc_function_set_alt(struct usb_function *f, @@ -710,8 +691,8 @@ static int acc_function_set_alt(struct usb_function *f, usb_ep_disable(dev->ep_in); return ret; } - if (!dev->function.disabled) - dev->online = 1; + + dev->online = 1; /* readers may be blocked waiting for us to go online */ wake_up(&dev->read_wq); @@ -736,15 +717,11 @@ static void acc_function_disable(struct usb_function *f) static int acc_bind_config(struct usb_configuration *c) { - struct acc_dev *dev; + struct acc_dev *dev = _acc_dev; int ret; printk(KERN_INFO "acc_bind_config\n"); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - /* allocate a string ID for our interface */ if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) { ret = usb_string_id(c->cdev); @@ -754,13 +731,6 @@ static int acc_bind_config(struct usb_configuration *c) acc_interface_desc.iInterface = ret; } - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_wq); - atomic_set(&dev->open_excl, 0); - INIT_LIST_HEAD(&dev->tx_idle); - INIT_DELAYED_WORK(&dev->work, acc_work); - dev->cdev = c->cdev; dev->function.name = "accessory"; dev->function.strings = acc_strings, @@ -768,41 +738,46 @@ static int acc_bind_config(struct usb_configuration *c) dev->function.hs_descriptors = hs_acc_descs; dev->function.bind = acc_function_bind; dev->function.unbind = acc_function_unbind; - dev->function.setup = acc_function_setup; dev->function.set_alt = acc_function_set_alt; dev->function.disable = acc_function_disable; - dev->function.disabled = 1; + + return usb_add_function(c, &dev->function); +} + +static int acc_setup(void) +{ + struct acc_dev *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->lock); + init_waitqueue_head(&dev->read_wq); + init_waitqueue_head(&dev->write_wq); + atomic_set(&dev->open_excl, 0); + INIT_LIST_HEAD(&dev->tx_idle); + INIT_DELAYED_WORK(&dev->work, acc_work); /* _acc_dev must be set before calling usb_gadget_register_driver */ _acc_dev = dev; ret = misc_register(&acc_device); if (ret) - goto err1; - - ret = usb_add_function(c, &dev->function); - if (ret) - goto err2; + goto err; return 0; -err2: - misc_deregister(&acc_device); -err1: +err: kfree(dev); printk(KERN_ERR "USB accessory gadget driver failed to initialize\n"); return ret; } -static struct android_usb_function acc_function = { - .name = "accessory", - .bind_config = acc_bind_config, -}; - -static int __init init(void) +static void acc_cleanup(void) { - printk(KERN_INFO "f_accessory init\n"); - android_register_function(&acc_function); - return 0; + misc_deregister(&acc_device); + kfree(_acc_dev); + _acc_dev = NULL; } -module_init(init); diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index cf2e7fc..68b1a8e 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/device.h> -#include <linux/usb/android_composite.h> #include "u_serial.h" #include "gadget_chips.h" @@ -788,55 +787,3 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num) kfree(acm); return status; } - -#ifdef CONFIG_USB_ANDROID_ACM -#include <linux/platform_device.h> - -static struct acm_platform_data *acm_pdata; - -static int acm_probe(struct platform_device *pdev) -{ - acm_pdata = pdev->dev.platform_data; - return 0; -} - -static struct platform_driver acm_platform_driver = { - .driver = { .name = "acm", }, - .probe = acm_probe, -}; - -int acm_function_bind_config(struct usb_configuration *c) -{ - int i; - u8 num_inst = acm_pdata ? acm_pdata->num_inst : 1; - int ret = gserial_setup(c->cdev->gadget, num_inst); - - if (ret) - return ret; - - for (i = 0; i < num_inst; i++) { - ret = acm_bind_config(c, i); - if (ret) { - pr_err("Could not bind acm%u config\n", i); - break; - } - } - - return ret; -} - -static struct android_usb_function acm_function = { - .name = "acm", - .bind_config = acm_function_bind_config, -}; - -static int __init init(void) -{ - printk(KERN_INFO "f_acm init\n"); - platform_driver_register(&acm_platform_driver); - android_register_function(&acm_function); - return 0; -} -module_init(init); - -#endif /* CONFIG_USB_ANDROID_ACM */ diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index 7cfa39c..fe4455e 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -15,9 +15,6 @@ * */ -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - #include <linux/module.h> #include <linux/init.h> #include <linux/poll.h> @@ -30,14 +27,12 @@ #include <linux/device.h> #include <linux/miscdevice.h> -#include <linux/usb/android_composite.h> - -#define BULK_BUFFER_SIZE 4096 +#define ADB_BULK_BUFFER_SIZE 4096 /* number of tx requests to allocate */ #define TX_REQ_MAX 4 -static const char shortname[] = "android_adb"; +static const char adb_shortname[] = "android_adb"; struct adb_dev { struct usb_function function; @@ -120,9 +115,7 @@ static struct usb_descriptor_header *hs_adb_descs[] = { /* temporary variable used between adb_open() and adb_gadget_bind() */ static struct adb_dev *_adb_dev; -static atomic_t adb_enable_excl; - -static inline struct adb_dev *func_to_dev(struct usb_function *f) +static inline struct adb_dev *func_to_adb(struct usb_function *f) { return container_of(f, struct adb_dev, function); } @@ -152,7 +145,7 @@ static void adb_request_free(struct usb_request *req, struct usb_ep *ep) } } -static inline int _lock(atomic_t *excl) +static inline int adb_lock(atomic_t *excl) { if (atomic_inc_return(excl) == 1) { return 0; @@ -162,13 +155,13 @@ static inline int _lock(atomic_t *excl) } } -static inline void _unlock(atomic_t *excl) +static inline void adb_unlock(atomic_t *excl) { atomic_dec(excl); } /* add a request to the tail of a list */ -void req_put(struct adb_dev *dev, struct list_head *head, +void adb_req_put(struct adb_dev *dev, struct list_head *head, struct usb_request *req) { unsigned long flags; @@ -179,7 +172,7 @@ void req_put(struct adb_dev *dev, struct list_head *head, } /* remove a request from the head of a list */ -struct usb_request *req_get(struct adb_dev *dev, struct list_head *head) +struct usb_request *adb_req_get(struct adb_dev *dev, struct list_head *head) { unsigned long flags; struct usb_request *req; @@ -202,7 +195,7 @@ static void adb_complete_in(struct usb_ep *ep, struct usb_request *req) if (req->status != 0) dev->error = 1; - req_put(dev, &dev->tx_idle, req); + adb_req_put(dev, &dev->tx_idle, req); wake_up(&dev->write_wq); } @@ -218,7 +211,7 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) wake_up(&dev->read_wq); } -static int __init create_bulk_endpoints(struct adb_dev *dev, +static int adb_create_bulk_endpoints(struct adb_dev *dev, struct usb_endpoint_descriptor *in_desc, struct usb_endpoint_descriptor *out_desc) { @@ -248,18 +241,18 @@ 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); + req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE); if (!req) goto fail; req->complete = adb_complete_out; dev->rx_req = req; for (i = 0; i < TX_REQ_MAX; i++) { - req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE); + req = adb_request_new(dev->ep_in, ADB_BULK_BUFFER_SIZE); if (!req) goto fail; req->complete = adb_complete_in; - req_put(dev, &dev->tx_idle, req); + adb_req_put(dev, &dev->tx_idle, req); } return 0; @@ -273,26 +266,27 @@ static ssize_t adb_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { struct adb_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req; int r = count, xfer; int ret; - DBG(cdev, "adb_read(%d)\n", count); + pr_debug("adb_read(%d)\n", count); + if (!_adb_dev) + return -ENODEV; - if (count > BULK_BUFFER_SIZE) + if (count > ADB_BULK_BUFFER_SIZE) return -EINVAL; - if (_lock(&dev->read_excl)) + if (adb_lock(&dev->read_excl)) return -EBUSY; /* we will block until we're online */ while (!(dev->online || dev->error)) { - DBG(cdev, "adb_read: waiting for online state\n"); + pr_debug("adb_read: waiting for online state\n"); ret = wait_event_interruptible(dev->read_wq, (dev->online || dev->error)); if (ret < 0) { - _unlock(&dev->read_excl); + adb_unlock(&dev->read_excl); return ret; } } @@ -308,12 +302,12 @@ requeue_req: 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); + pr_debug("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); + pr_debug("rx %p queue\n", req); } /* wait for a request to complete */ @@ -329,16 +323,17 @@ requeue_req: if (req->actual == 0) goto requeue_req; - DBG(cdev, "rx %p %d\n", req, req->actual); + pr_debug("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; done: - _unlock(&dev->read_excl); - DBG(cdev, "adb_read returning %d\n", r); + adb_unlock(&dev->read_excl); + pr_debug("adb_read returning %d\n", r); return r; } @@ -346,19 +341,20 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { struct adb_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; struct usb_request *req = 0; int r = count, xfer; int ret; - DBG(cdev, "adb_write(%d)\n", count); + if (!_adb_dev) + return -ENODEV; + pr_debug("adb_write(%d)\n", count); - if (_lock(&dev->write_excl)) + if (adb_lock(&dev->write_excl)) return -EBUSY; while (count > 0) { if (dev->error) { - DBG(cdev, "adb_write dev->error\n"); + pr_debug("adb_write dev->error\n"); r = -EIO; break; } @@ -366,7 +362,7 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, /* get an idle tx request to use */ req = 0; ret = wait_event_interruptible(dev->write_wq, - ((req = req_get(dev, &dev->tx_idle)) || dev->error)); + (req = adb_req_get(dev, &dev->tx_idle)) || dev->error); if (ret < 0) { r = ret; @@ -374,8 +370,8 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, } if (req != 0) { - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; + if (count > ADB_BULK_BUFFER_SIZE) + xfer = ADB_BULK_BUFFER_SIZE; else xfer = count; if (copy_from_user(req->buf, buf, xfer)) { @@ -386,7 +382,7 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, req->length = xfer; ret = usb_ep_queue(dev->ep_in, req, GFP_ATOMIC); if (ret < 0) { - DBG(cdev, "adb_write: xfer error %d\n", ret); + pr_debug("adb_write: xfer error %d\n", ret); dev->error = 1; r = -EIO; break; @@ -401,17 +397,20 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, } if (req) - req_put(dev, &dev->tx_idle, req); + adb_req_put(dev, &dev->tx_idle, req); - _unlock(&dev->write_excl); - DBG(cdev, "adb_write returning %d\n", r); + adb_unlock(&dev->write_excl); + pr_debug("adb_write returning %d\n", r); return r; } static int adb_open(struct inode *ip, struct file *fp) { printk(KERN_INFO "adb_open\n"); - if (_lock(&_adb_dev->open_excl)) + if (!_adb_dev) + return -ENODEV; + + if (adb_lock(&_adb_dev->open_excl)) return -EBUSY; fp->private_data = _adb_dev; @@ -425,7 +424,7 @@ static int adb_open(struct inode *ip, struct file *fp) static int adb_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "adb_release\n"); - _unlock(&_adb_dev->open_excl); + adb_unlock(&_adb_dev->open_excl); return 0; } @@ -440,48 +439,18 @@ static struct file_operations adb_fops = { static struct miscdevice adb_device = { .minor = MISC_DYNAMIC_MINOR, - .name = shortname, + .name = adb_shortname, .fops = &adb_fops, }; -static int adb_enable_open(struct inode *ip, struct file *fp) -{ - if (atomic_inc_return(&adb_enable_excl) != 1) { - atomic_dec(&adb_enable_excl); - return -EBUSY; - } - printk(KERN_INFO "enabling adb\n"); - android_enable_function(&_adb_dev->function, 1); - return 0; -} - -static int adb_enable_release(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "disabling adb\n"); - android_enable_function(&_adb_dev->function, 0); - atomic_dec(&adb_enable_excl); - return 0; -} - -static const struct file_operations adb_enable_fops = { - .owner = THIS_MODULE, - .open = adb_enable_open, - .release = adb_enable_release, -}; - -static struct miscdevice adb_enable_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "android_adb_enable", - .fops = &adb_enable_fops, -}; static int adb_function_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; - struct adb_dev *dev = func_to_dev(f); + struct adb_dev *dev = func_to_adb(f); int id; int ret; @@ -495,7 +464,7 @@ adb_function_bind(struct usb_configuration *c, struct usb_function *f) adb_interface_desc.bInterfaceNumber = id; /* allocate endpoints */ - ret = create_bulk_endpoints(dev, &adb_fullspeed_in_desc, + ret = adb_create_bulk_endpoints(dev, &adb_fullspeed_in_desc, &adb_fullspeed_out_desc); if (ret) return ret; @@ -517,29 +486,24 @@ adb_function_bind(struct usb_configuration *c, struct usb_function *f) static void adb_function_unbind(struct usb_configuration *c, struct usb_function *f) { - struct adb_dev *dev = func_to_dev(f); + struct adb_dev *dev = func_to_adb(f); struct usb_request *req; - spin_lock_irq(&dev->lock); - - adb_request_free(dev->rx_req, dev->ep_out); - while ((req = req_get(dev, &dev->tx_idle))) - adb_request_free(req, dev->ep_in); dev->online = 0; dev->error = 1; - spin_unlock_irq(&dev->lock); - misc_deregister(&adb_device); - misc_deregister(&adb_enable_device); - kfree(_adb_dev); - _adb_dev = NULL; + wake_up(&dev->read_wq); + + adb_request_free(dev->rx_req, dev->ep_out); + while ((req = adb_req_get(dev, &dev->tx_idle))) + adb_request_free(req, dev->ep_in); } static int adb_function_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { - struct adb_dev *dev = func_to_dev(f); + struct adb_dev *dev = func_to_adb(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; @@ -567,10 +531,10 @@ static int adb_function_set_alt(struct usb_function *f, static void adb_function_disable(struct usb_function *f) { - struct adb_dev *dev = func_to_dev(f); + struct adb_dev *dev = func_to_adb(f); struct usb_composite_dev *cdev = dev->cdev; - DBG(cdev, "adb_function_disable\n"); + DBG(cdev, "adb_function_disable cdev %p\n", cdev); dev->online = 0; dev->error = 1; usb_ep_disable(dev->ep_in); @@ -584,11 +548,27 @@ static void adb_function_disable(struct usb_function *f) static int adb_bind_config(struct usb_configuration *c) { - struct adb_dev *dev; - int ret; + struct adb_dev *dev = _adb_dev; printk(KERN_INFO "adb_bind_config\n"); + dev->cdev = c->cdev; + dev->function.name = "adb"; + 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; + + return usb_add_function(c, &dev->function); +} + +static int adb_setup(void) +{ + struct adb_dev *dev; + int ret; + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -604,53 +584,24 @@ static int adb_bind_config(struct usb_configuration *c) INIT_LIST_HEAD(&dev->tx_idle); - dev->cdev = c->cdev; - dev->function.name = "adb"; - 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; - - /* start disabled */ - dev->function.disabled = 1; - - /* _adb_dev must be set before calling usb_gadget_register_driver */ _adb_dev = dev; ret = misc_register(&adb_device); if (ret) - goto err1; - ret = misc_register(&adb_enable_device); - if (ret) - goto err2; - - ret = usb_add_function(c, &dev->function); - if (ret) - goto err3; + goto err; return 0; -err3: - misc_deregister(&adb_enable_device); -err2: - misc_deregister(&adb_device); -err1: +err: kfree(dev); printk(KERN_ERR "adb gadget driver failed to initialize\n"); return ret; } -static struct android_usb_function adb_function = { - .name = "adb", - .bind_config = adb_bind_config, -}; - -static int __init init(void) +static void adb_cleanup(void) { - printk(KERN_INFO "f_adb init\n"); - android_register_function(&adb_function); - return 0; + misc_deregister(&adb_device); + + kfree(_adb_dev); + _adb_dev = NULL; } -module_init(init); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index a296cd8..5440c6d 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -297,12 +297,6 @@ #include "gadget_chips.h" -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE -#include <linux/usb/android_composite.h> -#include <linux/platform_device.h> - -#define FUNCTION_NAME "usb_mass_storage" -#endif /*------------------------------------------------------------------------*/ @@ -438,10 +432,6 @@ struct fsg_config { u16 release; char can_stall; - -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - struct platform_device *pdev; -#endif }; struct fsg_dev { @@ -2790,13 +2780,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, curlun->initially_ro = curlun->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, @@ -3068,11 +3052,7 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, if (unlikely(!fsg)) return -ENOMEM; -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - fsg->function.name = FUNCTION_NAME; -#else - fsg->function.name = FSG_DRIVER_DESC; -#endif + fsg->function.name = "mass_storage"; fsg->function.strings = fsg_strings_array; fsg->function.bind = fsg_bind; fsg->function.unbind = fsg_unbind; @@ -3198,63 +3178,3 @@ fsg_common_from_params(struct fsg_common *common, return fsg_common_init(common, cdev, &cfg); } -#ifdef CONFIG_USB_ANDROID_MASS_STORAGE - -static struct fsg_config fsg_cfg; - -static int fsg_probe(struct platform_device *pdev) -{ - struct usb_mass_storage_platform_data *pdata = pdev->dev.platform_data; - int i, nluns; - - printk(KERN_INFO "fsg_probe pdev: %p, pdata: %p\n", pdev, pdata); - if (!pdata) - return -1; - - 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; - - 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; - - return 0; -} - -static struct platform_driver fsg_platform_driver = { - .driver = { .name = FUNCTION_NAME, }, - .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); -} - -static struct android_usb_function mass_storage_function = { - .name = FUNCTION_NAME, - .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 */ - diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c index 92dd89b..c892ec8 100644 --- a/drivers/usb/gadget/f_mtp.c +++ b/drivers/usb/gadget/f_mtp.c @@ -34,10 +34,9 @@ #include <linux/usb.h> #include <linux/usb_usual.h> #include <linux/usb/ch9.h> -#include <linux/usb/android_composite.h> #include <linux/usb/f_mtp.h> -#define BULK_BUFFER_SIZE 16384 +#define MTP_BULK_BUFFER_SIZE 16384 #define INTR_BUFFER_SIZE 28 /* String IDs */ @@ -67,7 +66,7 @@ #define MTP_RESPONSE_OK 0x2001 #define MTP_RESPONSE_DEVICE_BUSY 0x2019 -static const char shortname[] = "mtp_usb"; +static const char mtp_shortname[] = "mtp_usb"; struct mtp_dev { struct usb_function function; @@ -273,7 +272,7 @@ struct mtp_device_status { /* 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) +static inline struct mtp_dev *func_to_mtp(struct usb_function *f) { return container_of(f, struct mtp_dev, function); } @@ -302,7 +301,7 @@ static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) } } -static inline int _lock(atomic_t *excl) +static inline int mtp_lock(atomic_t *excl) { if (atomic_inc_return(excl) == 1) { return 0; @@ -312,13 +311,13 @@ static inline int _lock(atomic_t *excl) } } -static inline void _unlock(atomic_t *excl) +static inline void mtp_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, +static void mtp_req_put(struct mtp_dev *dev, struct list_head *head, struct usb_request *req) { unsigned long flags; @@ -329,7 +328,8 @@ static void req_put(struct mtp_dev *dev, struct list_head *head, } /* remove a request from the head of a list */ -static struct usb_request *req_get(struct mtp_dev *dev, struct list_head *head) +static struct usb_request +*mtp_req_get(struct mtp_dev *dev, struct list_head *head) { unsigned long flags; struct usb_request *req; @@ -352,7 +352,7 @@ static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) if (req->status != 0) dev->state = STATE_ERROR; - req_put(dev, &dev->tx_idle, req); + mtp_req_put(dev, &dev->tx_idle, req); wake_up(&dev->write_wq); } @@ -379,7 +379,7 @@ static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) dev->state = STATE_ERROR; } -static int __init create_bulk_endpoints(struct mtp_dev *dev, +static int mtp_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) @@ -429,14 +429,14 @@ static int __init create_bulk_endpoints(struct mtp_dev *dev, /* now allocate requests for our endpoints */ for (i = 0; i < TX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_in, BULK_BUFFER_SIZE); + req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE); if (!req) goto fail; req->complete = mtp_complete_in; - req_put(dev, &dev->tx_idle, req); + mtp_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); + req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE); if (!req) goto fail; req->complete = mtp_complete_out; @@ -466,7 +466,7 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, DBG(cdev, "mtp_read(%d)\n", count); - if (count > BULK_BUFFER_SIZE) + if (count > MTP_BULK_BUFFER_SIZE) return -EINVAL; /* we will block until we're online */ @@ -579,15 +579,15 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, /* get an idle tx request to use */ req = 0; ret = wait_event_interruptible(dev->write_wq, - ((req = req_get(dev, &dev->tx_idle)) + ((req = mtp_req_get(dev, &dev->tx_idle)) || dev->state != STATE_BUSY)); if (!req) { r = ret; break; } - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; + if (count > MTP_BULK_BUFFER_SIZE) + xfer = MTP_BULK_BUFFER_SIZE; else xfer = count; if (xfer && copy_from_user(req->buf, buf, xfer)) { @@ -611,7 +611,7 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf, } if (req) - req_put(dev, &dev->tx_idle, req); + mtp_req_put(dev, &dev->tx_idle, req); spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) @@ -659,7 +659,7 @@ static void send_file_work(struct work_struct *data) { /* get an idle tx request to use */ req = 0; ret = wait_event_interruptible(dev->write_wq, - (req = req_get(dev, &dev->tx_idle)) + (req = mtp_req_get(dev, &dev->tx_idle)) || dev->state != STATE_BUSY); if (dev->state == STATE_CANCELED) { r = -ECANCELED; @@ -670,8 +670,8 @@ static void send_file_work(struct work_struct *data) { break; } - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; + if (count > MTP_BULK_BUFFER_SIZE) + xfer = MTP_BULK_BUFFER_SIZE; else xfer = count; ret = vfs_read(filp, req->buf, xfer, &offset); @@ -697,7 +697,7 @@ static void send_file_work(struct work_struct *data) { } if (req) - req_put(dev, &dev->tx_idle, req); + mtp_req_put(dev, &dev->tx_idle, req); DBG(cdev, "send_file_work returning %d\n", r); /* write the result */ @@ -731,8 +731,8 @@ static void receive_file_work(struct work_struct *data) 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); + read_req->length = (count > MTP_BULK_BUFFER_SIZE + ? MTP_BULK_BUFFER_SIZE : count); dev->rx_done = 0; ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); if (ret < 0) { @@ -824,7 +824,7 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) struct file *filp = NULL; int ret = -EINVAL; - if (_lock(&dev->ioctl_excl)) + if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; switch (code) { @@ -922,7 +922,7 @@ fail: dev->state = STATE_READY; spin_unlock_irq(&dev->lock); out: - _unlock(&dev->ioctl_excl); + mtp_unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); return ret; } @@ -930,7 +930,7 @@ out: static int mtp_open(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_open\n"); - if (_lock(&_mtp_dev->open_excl)) + if (mtp_lock(&_mtp_dev->open_excl)) return -EBUSY; /* clear any error condition */ @@ -945,7 +945,7 @@ static int mtp_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_release\n"); - _unlock(&_mtp_dev->open_excl); + mtp_unlock(&_mtp_dev->open_excl); return 0; } @@ -961,15 +961,52 @@ static const struct file_operations mtp_fops = { static struct miscdevice mtp_device = { .minor = MISC_DYNAMIC_MINOR, - .name = shortname, + .name = mtp_shortname, .fops = &mtp_fops, }; +static int mtp_ctrlrequest(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl) +{ + struct mtp_dev *dev = _mtp_dev; + 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); + + VDBG(cdev, "mtp_ctrlrequest " + "%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); + } + /* 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__); + } + return value; +} + 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); + struct mtp_dev *dev = func_to_mtp(f); int id; int ret; @@ -983,7 +1020,7 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f) mtp_interface_desc.bInterfaceNumber = id; /* allocate endpoints */ - ret = create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, + ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, &mtp_fullspeed_out_desc, &mtp_intr_desc); if (ret) return ret; @@ -1005,28 +1042,22 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f) static void mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) { - struct mtp_dev *dev = func_to_dev(f); + struct mtp_dev *dev = func_to_mtp(f); struct usb_request *req; int i; - spin_lock_irq(&dev->lock); - while ((req = req_get(dev, &dev->tx_idle))) + while ((req = mtp_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); - - 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 mtp_dev *dev = func_to_mtp(f); struct usb_composite_dev *cdev = dev->cdev; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); @@ -1034,28 +1065,11 @@ static int mtp_function_setup(struct usb_function *f, 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", @@ -1135,7 +1149,7 @@ static int mtp_function_setup(struct usb_function *f, static int mtp_function_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { - struct mtp_dev *dev = func_to_dev(f); + struct mtp_dev *dev = func_to_mtp(f); struct usb_composite_dev *cdev = f->config->cdev; int ret; @@ -1169,7 +1183,7 @@ static int mtp_function_set_alt(struct usb_function *f, static void mtp_function_disable(struct usb_function *f) { - struct mtp_dev *dev = func_to_dev(f); + struct mtp_dev *dev = func_to_mtp(f); struct usb_composite_dev *cdev = dev->cdev; DBG(cdev, "mtp_function_disable\n"); @@ -1186,15 +1200,11 @@ static void mtp_function_disable(struct usb_function *f) static int mtp_bind_config(struct usb_configuration *c) { - struct mtp_dev *dev; + struct mtp_dev *dev = _mtp_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); @@ -1204,19 +1214,6 @@ static int mtp_bind_config(struct usb_configuration *c) mtp_interface_desc.iInterface = ret; } - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_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, @@ -1231,38 +1228,59 @@ static int mtp_bind_config(struct usb_configuration *c) /* 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; + return usb_add_function(c, &dev->function); +} - ret = misc_register(&mtp_device); - if (ret) +static int mtp_setup(void) +{ + struct mtp_dev *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->lock); + init_waitqueue_head(&dev->read_wq); + init_waitqueue_head(&dev->write_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) { + ret = -ENOMEM; goto err1; + } + INIT_WORK(&dev->send_file_work, send_file_work); + INIT_WORK(&dev->receive_file_work, receive_file_work); + + _mtp_dev = dev; - ret = usb_add_function(c, &dev->function); + ret = misc_register(&mtp_device); if (ret) goto err2; return 0; err2: - misc_deregister(&mtp_device); + destroy_workqueue(dev->wq); err1: - if (dev->wq) - destroy_workqueue(dev->wq); + _mtp_dev = NULL; 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) +static void mtp_cleanup(void) { - printk(KERN_INFO "f_mtp init\n"); - android_register_function(&mtp_function); - return 0; + struct mtp_dev *dev = _mtp_dev; + + if (!dev) + return; + + misc_deregister(&mtp_device); + destroy_workqueue(dev->wq); + _mtp_dev = NULL; + kfree(dev); } -module_init(init); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 761a789..d03b11b 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -28,7 +28,6 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/etherdevice.h> -#include <linux/usb/android_composite.h> #include <asm/atomic.h> @@ -87,8 +86,11 @@ struct f_rndis { struct gether port; u8 ctrl_id, data_id; u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *manufacturer; int config; + struct rndis_ep_descs fs; struct rndis_ep_descs hs; @@ -130,16 +132,9 @@ static struct usb_interface_descriptor rndis_control_intf = { /* .bInterfaceNumber = DYNAMIC */ /* status endpoint is optional; this could be patched later */ .bNumEndpoints = 1, -#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS - /* "Wireless" RNDIS; auto-detected by Windows */ - .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER, - .bInterfaceSubClass = 0x01, - .bInterfaceProtocol = 0x03, -#else .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, -#endif /* .iInterface = DYNAMIC */ }; @@ -195,19 +190,11 @@ 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 -#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS - /* "Wireless" RNDIS; auto-detected by Windows */ - .bFunctionClass = USB_CLASS_WIRELESS_CONTROLLER, - .bFunctionSubClass = 0x01, - .bFunctionProtocol = 0x03, -#else .bFunctionClass = USB_CLASS_COMM, .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, .bFunctionProtocol = USB_CDC_ACM_PROTO_VENDOR, -#endif /* .iFunction = DYNAMIC */ }; @@ -319,10 +306,6 @@ static struct usb_gadget_strings *rndis_strings[] = { NULL, }; -#ifdef CONFIG_USB_ANDROID_RNDIS -static struct usb_ether_platform_data *rndis_pdata; -#endif - /*-------------------------------------------------------------------------*/ static struct sk_buff *rndis_add_header(struct gether *port, @@ -725,13 +708,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); -#ifdef CONFIG_USB_ANDROID_RNDIS - if (rndis_pdata) { - if (rndis_set_param_vendor(rndis->config, rndis_pdata->vendorID, - rndis_pdata->vendorDescr)) + if (rndis_set_param_vendor(rndis->config, rndis->vendorID, + rndis->manufacturer)) goto fail; - } -#endif /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -808,7 +787,8 @@ static inline bool can_support_rndis(struct usb_configuration *c) * for calling @gether_cleanup() before module unload. */ int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { struct f_rndis *rndis; int status; @@ -853,6 +833,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) goto fail; memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); + rndis->vendorID = vendorID; + rndis->manufacturer = manufacturer; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; @@ -871,11 +853,6 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) rndis->port.func.setup = rndis_setup; rndis->port.func.disable = rndis_disable; -#ifdef CONFIG_USB_ANDROID_RNDIS - /* start disabled */ - rndis->port.func.disabled = 1; -#endif - status = usb_add_function(c, &rndis->port.func); if (status) { kfree(rndis); @@ -884,54 +861,3 @@ fail: } return status; } - -#ifdef CONFIG_USB_ANDROID_RNDIS -#include "rndis.c" - -static int rndis_probe(struct platform_device *pdev) -{ - rndis_pdata = pdev->dev.platform_data; - return 0; -} - -static struct platform_driver rndis_platform_driver = { - .driver = { .name = "rndis", }, - .probe = rndis_probe, -}; - -int rndis_function_bind_config(struct usb_configuration *c) -{ - int ret; - - if (!rndis_pdata) { - printk(KERN_ERR "rndis_pdata null in rndis_function_bind_config\n"); - return -1; - } - - printk(KERN_INFO - "rndis_function_bind_config MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - rndis_pdata->ethaddr[0], rndis_pdata->ethaddr[1], - rndis_pdata->ethaddr[2], rndis_pdata->ethaddr[3], - rndis_pdata->ethaddr[4], rndis_pdata->ethaddr[5]); - - ret = gether_setup(c->cdev->gadget, rndis_pdata->ethaddr); - if (ret == 0) - ret = rndis_bind_config(c, rndis_pdata->ethaddr); - return ret; -} - -static struct android_usb_function rndis_function = { - .name = "rndis", - .bind_config = rndis_function_bind_config, -}; - -static int __init init(void) -{ - printk(KERN_INFO "f_rndis init\n"); - platform_driver_register(&rndis_platform_driver); - android_register_function(&rndis_function); - return 0; -} -module_init(init); - -#endif /* CONFIG_USB_ANDROID_RNDIS */ diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 2779865..5bb1021 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -110,14 +110,16 @@ int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); int ncm_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) +#ifdef USB_ETH_RNDIS -int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer); #else static inline int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { return 0; } diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 3dcbeca..3fdcc9a 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1028,7 +1028,7 @@ static const struct tty_operations gs_tty_ops = { static struct tty_driver *gs_tty_driver; -static int __init +static int gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) { struct gs_port *port; @@ -1074,7 +1074,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) * * Returns negative errno or zero. */ -int __init gserial_setup(struct usb_gadget *g, unsigned count) +int gserial_setup(struct usb_gadget *g, unsigned count) { unsigned i; struct usb_cdc_line_coding coding; |