usb: gadget: android: Update android gadget driver
authorBenoit Goby <benoit@android.com>
Wed, 20 Apr 2011 03:37:33 +0000 (20:37 -0700)
committermgross <mark.gross@intel.com>
Wed, 9 Nov 2011 20:09:01 +0000 (12:09 -0800)
* 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

14 files changed:
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/android.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/f_accessory.c
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/f_adb.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_mtp.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/u_ether.h
drivers/usb/gadget/u_serial.c
include/linux/usb/android_composite.h [deleted file]
include/linux/usb/composite.h

index 5b3c58e..144a8c8 100644 (file)
@@ -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
index e9066b9..ab17a4c 100644 (file)
@@ -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
index 2ebc818..377df5b 100644 (file)
@@ -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>
 #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;
 }
index 6c8fbb1..dc06da6 100644 (file)
@@ -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);
 }
 
index ad3c173..873ab2e 100644 (file)
@@ -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);
index cf2e7fc..68b1a8e 100644 (file)
@@ -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 */
index 7cfa39c..fe4455e 100644 (file)
@@ -15,9 +15,6 @@
  *
  */
 
-/* #define DEBUG */
-/* #define VERBOSE_DEBUG */
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #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);
index a296cd8..5440c6d 100644 (file)
 
 #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 */
-
index 92dd89b..c892ec8 100644 (file)
 #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);
index 761a789..d03b11b 100644 (file)
@@ -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 */
index 2779865..5bb1021 100644 (file)
@@ -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;
 }
index 3dcbeca..3fdcc9a 100644 (file)
@@ -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;
diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h
deleted file mode 100644 (file)
index 7f90007..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Platform data for Android USB
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef        __LINUX_USB_ANDROID_H
-#define        __LINUX_USB_ANDROID_H
-
-#include <linux/usb/composite.h>
-#include <linux/if_ether.h>
-
-struct android_usb_function {
-       struct list_head        list;
-       char                    *name;
-       int                     (*bind_config)(struct usb_configuration *c);
-};
-
-struct android_usb_product {
-       /* Vendor ID for this set of functions.
-        * Default vendor_id in platform data will be used if this is zero.
-        */
-       __u16 vendor_id;
-
-       /* Product ID for this set of functions. */
-       __u16 product_id;
-
-       /* List of function names associated with this product.
-        * This is used to compute the USB product ID dynamically
-        * based on which functions are enabled.
-        */
-       int num_functions;
-       char **functions;
-};
-
-struct android_usb_platform_data {
-       /* USB device descriptor fields */
-       __u16 vendor_id;
-
-       /* Default product ID. */
-       __u16 product_id;
-
-       __u16 version;
-
-       char *product_name;
-       char *manufacturer_name;
-       char *serial_number;
-
-       /* List of available USB products.
-        * This is used to compute the USB product ID dynamically
-        * based on which functions are enabled.
-        * if num_products is zero or no match can be found,
-        * we use the default product ID
-        */
-       int num_products;
-       struct android_usb_product *products;
-
-       /* List of all supported USB functions.
-        * This list is used to define the order in which
-        * the functions appear in the configuration's list of USB interfaces.
-        * This is necessary to avoid depending upon the order in which
-        * the individual function drivers are initialized.
-        */
-       int num_functions;
-       char **functions;
-};
-
-/* Platform data for "usb_mass_storage" driver. */
-struct usb_mass_storage_platform_data {
-       /* Contains values for the SC_INQUIRY SCSI command. */
-       char *vendor;
-       char *product;
-       int release;
-
-       /* number of LUNS */
-       int nluns;
-};
-
-/* Platform data for USB ethernet driver. */
-struct usb_ether_platform_data {
-       u8      ethaddr[ETH_ALEN];
-       u32     vendorID;
-       const char *vendorDescr;
-};
-
-/* Platform data for ACM driver. */
-struct acm_platform_data {
-       u8      num_inst;
-};
-
-extern void android_register_function(struct android_usb_function *f);
-
-extern void android_enable_function(struct usb_function *f, int enable);
-
-
-#endif /* __LINUX_USB_ANDROID_H */
index d00ab95..66a29a9 100644 (file)
@@ -36,7 +36,6 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/switch.h>
 
 /*
  * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
@@ -47,7 +46,6 @@
  */
 #define USB_GADGET_DELAYED_STATUS       0x7fff /* Impossibly large value */
 
-struct usb_composite_dev;
 struct usb_configuration;
 
 /**
@@ -111,9 +109,6 @@ struct usb_function {
 
        struct usb_configuration        *config;
 
-       /* disabled is zero if the function is enabled */
-       int                             disabled;
-
        /* REVISIT:  bind() functions can be marked __init, which
         * makes trouble for section mismatch analysis.  See if
         * we can't restructure things to avoid mismatching.
@@ -141,7 +136,6 @@ struct usb_function {
        /* internals */
        struct list_head                list;
        DECLARE_BITMAP(endpoints, 32);
-       struct device                   *dev;
 };
 
 int usb_add_function(struct usb_configuration *, struct usb_function *);
@@ -151,9 +145,6 @@ int usb_function_activate(struct usb_function *);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
 
-void usb_function_set_enabled(struct usb_function *, int);
-void usb_composite_force_reset(struct usb_composite_dev *);
-
 /**
  * ep_choose - select descriptor endpoint at current device speed
  * @g: gadget, connected and running at some speed
@@ -293,9 +284,6 @@ struct usb_composite_driver {
        struct usb_gadget_strings               **strings;
        unsigned                needs_serial:1;
 
-       struct class            *class;
-       atomic_t                function_count;
-
        int                     (*unbind)(struct usb_composite_dev *);
 
        void                    (*disconnect)(struct usb_composite_dev *);
@@ -303,8 +291,6 @@ struct usb_composite_driver {
        /* global suspend hooks */
        void                    (*suspend)(struct usb_composite_dev *);
        void                    (*resume)(struct usb_composite_dev *);
-
-       void                    (*enable_function)(struct usb_function *f, int enable);
 };
 
 extern int usb_composite_probe(struct usb_composite_driver *driver,
@@ -375,15 +361,6 @@ struct usb_composite_dev {
 
        /* protects deactivations and delayed_status counts*/
        spinlock_t                      lock;
-
-       /* switch indicating connected/disconnected state */
-       struct switch_dev               sw_connected;
-       /* switch indicating current configuration */
-       struct switch_dev               sw_config;
-       /* current connected state for sw_connected */
-       bool                            connected;
-
-       struct work_struct switch_work;
 };
 
 extern int usb_string_id(struct usb_composite_dev *c);