USB: gadget: android: android USB gadget improvements:

USB: android gadget: add remote wakeup attribute to android function

Add remote wakeup attribute to configuration descriptor of android
function to advertise remote wakeup capability to host

Acked-by: Allam, Suresh Reddy <sallam@qualcomm.com>

Signed-off-by: Mike Lockwood <lockwood@android.com>

USB: gadget: android: Allow functions to handle setup requests.

Signed-off-by: Mike Lockwood <lockwood@android.com>

Support for specifying the list of USB functions from platform data.

The main android.c gadget driver no longer has hard coded references
to the mass_storage and adb functions.

Support for computing the product ID based on tables in platform data
and the currently enabled functions.

Moved the adb enable/disable logic from android.c to f_adb.c.

Change-Id: I6259d3fb1473ed973f700e55d17744956f3527bb
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index fd6f9c6..5eba8c3 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -851,13 +851,30 @@
 	  which includes sample code for accessing the device file.
 
 config USB_ANDROID
-	tristate "Android Gadget"
+	boolean "Android Gadget"
 	depends on SWITCH
 	help
-	  The Android gadget provides mass storage and adb transport.
+	  The Android gadget driver supports multiple USB functions.
+	  The functions can be configured via a board file and may be
+	  enabled and disabled dynamically.
 
-	  Say "y" to link the driver statically, or "m" to build a
-	  dynamically linked module called "g_android".
+config USB_ANDROID_ACM
+	boolean "Android gadget ACM function"
+	depends on USB_ANDROID
+	help
+	  Provides adb function for adb gadget driver.
+
+config USB_ANDROID_ADB
+	boolean "Android gadget adb function"
+	depends on USB_ANDROID
+	help
+	  Provides adb function for adb 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 adb gadget driver.
 
 config USB_CDC_COMPOSITE
 	tristate "CDC Composite Device (Ethernet and ACM)"
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 859287b..3e822d4 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -72,4 +72,5 @@
 obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
-obj-$(CONFIG_USB_ANDROID)	+= g_android.o
+obj-$(CONFIG_USB_ANDROID_ACM)	+= f_acm.o u_serial.o
+obj-$(CONFIG_USB_G_ANDROID)    += g_android.o  
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index d3c028d..d10568e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -25,17 +25,13 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/utsname.h>
-#include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 
-#include <linux/usb/android.h>
+#include <linux/usb/android_composite.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 
-#include "f_mass_storage.h"
-#include "f_adb.h"
-
 #include "gadget_chips.h"
 
 /*
@@ -60,20 +56,19 @@
 /* Default vendor and product IDs, overridden by platform data */
 #define VENDOR_ID		0x18D1
 #define PRODUCT_ID		0x0001
-#define ADB_PRODUCT_ID	0x0002
 
 struct android_dev {
 	struct usb_composite_dev *cdev;
+	struct usb_configuration *config;
+	int num_products;
+	struct android_usb_product *products;
+	int num_functions;
+	char **functions;
 
 	int product_id;
-	int adb_product_id;
 	int version;
-
-	int adb_enabled;
-	int nluns;
 };
 
-static atomic_t adb_enable_excl;
 static struct android_dev *_android_dev;
 
 /* string IDs are assigned dynamically */
@@ -112,6 +107,9 @@
 	.bNumConfigurations   = 1,
 };
 
+static struct list_head _functions = LIST_HEAD_INIT(_functions);
+static int _registered_function_count = 0;
+
 void android_usb_set_connected(int connected)
 {
 	if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) {
@@ -122,33 +120,121 @@
 	}
 }
 
+static struct android_usb_function *get_function(const char *name)
+{
+	struct android_usb_function	*f;
+	list_for_each_entry(f, &_functions, list) {
+		if (!strcmp(name, f->name))
+			return f;
+	}
+	return 0;
+}
+
+static void bind_functions(struct android_dev *dev)
+{
+	struct android_usb_function	*f;
+	char **functions = dev->functions;
+	int i;
+
+	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 __init android_bind_config(struct usb_configuration *c)
 {
 	struct android_dev *dev = _android_dev;
-	int ret;
-	printk(KERN_DEBUG "android_bind_config\n");
 
-	ret = mass_storage_function_add(dev->cdev, c, dev->nluns);
-	if (ret)
-		return ret;
-	return adb_function_add(dev->cdev, c);
+	printk(KERN_DEBUG "android_bind_config\n");
+	dev->config = c;
+
+	/* bind our functions if they have all registered */
+	if (_registered_function_count == dev->num_functions)
+		bind_functions(dev);
+
+	return 0;
 }
 
+static int android_setup_config(struct usb_configuration *c,
+		const struct usb_ctrlrequest *ctrl);
+
 static struct usb_configuration android_config_driver = {
 	.label		= "android",
 	.bind		= android_bind_config,
+	.setup		= android_setup_config,
 	.bConfigurationValue = 1,
 	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 	.bMaxPower	= 0xFA, /* 500ma */
 };
 
+static int android_setup_config(struct usb_configuration *c,
+		const struct usb_ctrlrequest *ctrl)
+{
+	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 ret;
+}
+
+static int product_has_function(struct android_usb_product *p,
+		struct usb_function *f)
+{
+	char **functions = p->functions;
+	int count = p->num_functions;
+	const char *name = f->name;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (!strcmp(name, *functions++))
+			return 1;
+	}
+	return 0;
+}
+
+static int product_matches_functions(struct android_usb_product *p)
+{
+	struct usb_function		*f;
+	list_for_each_entry(f, &android_config_driver.functions, list) {
+		if (product_has_function(p, f) == !!f->hidden)
+			return 0;
+	}
+	return 1;
+}
+
+static int get_product_id(struct android_dev *dev)
+{
+	struct android_usb_product *p = dev->products;
+	int count = dev->num_products;
+	int i;
+
+	if (p) {
+		for (i = 0; i < count; i++, p++) {
+			if (product_matches_functions(p))
+				return p->product_id;
+		}
+	}
+	/* use default product ID */
+	return dev->product_id;
+}
+
 static int __init android_bind(struct usb_composite_dev *cdev)
 {
 	struct android_dev *dev = _android_dev;
 	struct usb_gadget	*gadget = cdev->gadget;
-	int			gcnum;
-	int			id;
-	int			ret;
+	int			gcnum, id, product_id, ret;
 
 	printk(KERN_INFO "android_bind\n");
 
@@ -173,6 +259,9 @@
 	strings_dev[STRING_SERIAL_IDX].id = id;
 	device_desc.iSerialNumber = id;
 
+	if (gadget->ops->wakeup)
+		android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+
 	/* register our configuration */
 	ret = usb_add_config(cdev, &android_config_driver);
 	if (ret) {
@@ -198,6 +287,9 @@
 
 	usb_gadget_set_selfpowered(gadget);
 	dev->cdev = cdev;
+	product_id = get_product_id(dev);
+	device_desc.idProduct = __constant_cpu_to_le16(product_id);
+	cdev->desc.idProduct = device_desc.idProduct;
 
 	return 0;
 }
@@ -209,19 +301,31 @@
 	.bind		= android_bind,
 };
 
-static void enable_adb(struct android_dev *dev, int enable)
+void android_register_function(struct android_usb_function *f)
 {
-	if (enable != dev->adb_enabled) {
-		dev->adb_enabled = enable;
-		adb_function_enable(enable);
+	struct android_dev *dev = _android_dev;
 
-		/* set product ID to the appropriate value */
-		if (enable)
-			device_desc.idProduct =
-				__constant_cpu_to_le16(dev->adb_product_id);
-		else
-			device_desc.idProduct =
-				__constant_cpu_to_le16(dev->product_id);
+	printk(KERN_INFO "android_register_function\n");
+	list_add_tail(&f->list, &_functions);
+	_registered_function_count++;
+
+	/* bind our functions if they have all registered
+	 * and the main driver has bound.
+	 */
+	if (dev->config && _registered_function_count == dev->num_functions)
+		bind_functions(dev);
+}
+
+void android_enable_function(struct usb_function *f, int enable)
+{
+	struct android_dev *dev = _android_dev;
+	int disable = !enable;
+	int product_id;
+
+	if (!!f->hidden != disable) {
+		f->hidden = disable;
+		product_id = get_product_id(dev);
+		device_desc.idProduct = __constant_cpu_to_le16(product_id);
 		if (dev->cdev)
 			dev->cdev->desc.idProduct = device_desc.idProduct;
 
@@ -235,39 +339,6 @@
 	}
 }
 
-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");
-	enable_adb(_android_dev, 1);
-
-	return 0;
-}
-
-static int adb_enable_release(struct inode *ip, struct file *fp)
-{
-	printk(KERN_INFO "disabling adb\n");
-	enable_adb(_android_dev, 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 __init android_probe(struct platform_device *pdev)
 {
 	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
@@ -276,6 +347,10 @@
 	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)
 			device_desc.idVendor =
 				__constant_cpu_to_le16(pdata->vendor_id);
@@ -284,8 +359,6 @@
 			device_desc.idProduct =
 				__constant_cpu_to_le16(pdata->product_id);
 		}
-		if (pdata->adb_product_id)
-			dev->adb_product_id = pdata->adb_product_id;
 		if (pdata->version)
 			dev->version = pdata->version;
 
@@ -296,10 +369,9 @@
 					pdata->manufacturer_name;
 		if (pdata->serial_number)
 			strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number;
-		dev->nluns = pdata->nluns;
 	}
 
-	return 0;
+	return usb_composite_register(&android_usb_driver);
 }
 
 static struct platform_driver android_platform_driver = {
@@ -310,7 +382,6 @@
 static int __init init(void)
 {
 	struct android_dev *dev;
-	int ret;
 
 	printk(KERN_INFO "android init\n");
 
@@ -320,30 +391,15 @@
 
 	/* set default values, which should be overridden by platform data */
 	dev->product_id = PRODUCT_ID;
-	dev->adb_product_id = ADB_PRODUCT_ID;
 	_android_dev = dev;
 
-	ret = platform_driver_register(&android_platform_driver);
-	if (ret)
-		return ret;
-	ret = misc_register(&adb_enable_device);
-	if (ret) {
-		platform_driver_unregister(&android_platform_driver);
-		return ret;
-	}
-	ret = usb_composite_register(&android_usb_driver);
-	if (ret) {
-		misc_deregister(&adb_enable_device);
-		platform_driver_unregister(&android_platform_driver);
-	}
-	return ret;
+	return platform_driver_register(&android_platform_driver);
 }
 module_init(init);
 
 static void __exit cleanup(void)
 {
 	usb_composite_unregister(&android_usb_driver);
-	misc_deregister(&adb_enable_device);
 	platform_driver_unregister(&android_platform_driver);
 	kfree(_android_dev);
 	_android_dev = NULL;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 10860be..5148e96 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -20,6 +20,7 @@
 
 #include "u_serial.h"
 #include "gadget_chips.h"
+#include "linux/usb/android_composite.h"
 
 
 /*
@@ -763,11 +764,22 @@
 	return status;
 }
 
-int __init acm_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c)
+int acm_function_bind_config(struct usb_configuration *c)
 {
 	int ret = acm_bind_config(c, 0);
 	if (ret == 0)
 		gserial_setup(c->cdev->gadget, 1);
 	return ret;
 }
+
+static struct android_usb_function acm_function = {
+	.name = "acm",
+	.bind_config = acm_function_bind_config,
+};
+
+static int __init init(void)
+{
+	android_register_function(&acm_function);
+	return 0;
+}
+module_init(init);
diff --git a/drivers/usb/gadget/f_acm.h b/drivers/usb/gadget/f_acm.h
deleted file mode 100644
index 8e27b34..0000000
--- a/drivers/usb/gadget/f_acm.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Gadget Driver for Android ACM
- *
- * Copyright (C) 2009 Motorola, Inc.
- * Author:
- *
- * 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 __F_ACM_H
-#define __F_ACM_H
-
-int acm_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c);
-
-#endif /* __F_ACM_H */
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 63452ed..373e51f 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -30,11 +30,7 @@
 #include <linux/device.h>
 #include <linux/miscdevice.h>
 
-#include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
-#include <linux/usb/gadget.h>
-
-#include "f_adb.h"
+#include <linux/usb/android_composite.h>
 
 #define BULK_BUFFER_SIZE           4096
 
@@ -126,15 +122,12 @@
 	NULL,
 };
 
-/* used when adb function is disabled */
-static struct usb_descriptor_header *null_adb_descs[] = {
-	NULL,
-};
-
 
 /* 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)
 {
 	return container_of(f, struct adb_dev, function);
@@ -489,7 +482,40 @@
 	.fops = &adb_fops,
 };
 
-static int __init
+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;
@@ -544,6 +570,7 @@
 	spin_unlock_irq(&dev->lock);
 
 	misc_deregister(&adb_device);
+	misc_deregister(&adb_enable_device);
 	kfree(_adb_dev);
 	_adb_dev = NULL;
 }
@@ -588,13 +615,12 @@
 	VDBG(cdev, "%s disabled\n", dev->function.name);
 }
 
-int __init adb_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c)
+static int adb_bind_config(struct usb_configuration *c)
 {
 	struct adb_dev *dev;
 	int ret;
 
-	printk(KERN_INFO "adb_function_add\n");
+	printk(KERN_INFO "adb_bind_config\n");
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -613,27 +639,36 @@
 	INIT_LIST_HEAD(&dev->rx_done);
 	INIT_LIST_HEAD(&dev->tx_idle);
 
-	dev->cdev = cdev;
+	dev->cdev = c->cdev;
 	dev->function.name = "adb";
-	dev->function.descriptors = null_adb_descs;
-	dev->function.hs_descriptors = null_adb_descs;
+	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.hidden = 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 = usb_add_function(c, &dev->function);
+	ret = misc_register(&adb_enable_device);
 	if (ret)
 		goto err2;
 
+	ret = usb_add_function(c, &dev->function);
+	if (ret)
+		goto err3;
+
 	return 0;
 
+err3:
+	misc_deregister(&adb_enable_device);
 err2:
 	misc_deregister(&adb_device);
 err1:
@@ -642,21 +677,15 @@
 	return ret;
 }
 
-void adb_function_enable(int enable)
+static struct android_usb_function adb_function = {
+	.name = "adb",
+	.bind_config = adb_bind_config,
+};
+
+static int __init init(void)
 {
-	struct adb_dev *dev = _adb_dev;
-
-	if (dev) {
-		DBG(dev->cdev, "adb_function_enable(%s)\n",
-			enable ? "true" : "false");
-
-		if (enable) {
-			dev->function.descriptors = fs_adb_descs;
-			dev->function.hs_descriptors = hs_adb_descs;
-		} else {
-			dev->function.descriptors = null_adb_descs;
-			dev->function.hs_descriptors = null_adb_descs;
-		}
-	}
+	printk(KERN_INFO "f_adb init\n");
+	android_register_function(&adb_function);
+	return 0;
 }
-
+module_init(init);
diff --git a/drivers/usb/gadget/f_adb.h b/drivers/usb/gadget/f_adb.h
deleted file mode 100644
index 4854ff6..0000000
--- a/drivers/usb/gadget/f_adb.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Gadget Driver for Android ADB
- *
- * 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 __F_ADB_H
-#define __F_ADB_H
-
-int adb_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c);
-void adb_function_enable(int enable);
-
-#endif /* __F_ADB_H */
diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h
deleted file mode 100644
index 8e63ac0..0000000
--- a/drivers/usb/gadget/f_mass_storage.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * drivers/usb/gadget/f_mass_storage.h
- *
- * Function Driver for USB Mass Storage
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * Based heavily on the file_storage gadget driver in
- * drivers/usb/gadget/file_storage.c and licensed under the same terms:
- *
- * Copyright (C) 2003-2007 Alan Stern
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __F_MASS_STORAGE_H
-#define __F_MASS_STORAGE_H
-
-int mass_storage_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c, int nluns);
-
-#endif /* __F_MASS_STORAGE_H */
diff --git a/drivers/usb/gadget/f_mass_storage_tmp.c b/drivers/usb/gadget/f_mass_storage_tmp.c
index a0f7f9c..79044f7 100644
--- a/drivers/usb/gadget/f_mass_storage_tmp.c
+++ b/drivers/usb/gadget/f_mass_storage_tmp.c
@@ -73,9 +73,8 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
-#include <linux/usb/android.h>
+#include <linux/usb/android_composite.h>
 
-#include "f_mass_storage.h"
 #include "gadget_chips.h"
 
 
@@ -2711,7 +2710,7 @@
 	switch_dev_unregister(&fsg->sdev);
 }
 
-static int __init
+static int
 fsg_function_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -2902,6 +2901,7 @@
 
 		if (pdata->release)
 			fsg->release = pdata->release;
+		fsg->nluns = pdata->nluns;
 	}
 
 	return 0;
@@ -2912,18 +2912,16 @@
 	.probe = fsg_probe,
 };
 
-int __init mass_storage_function_add(struct usb_composite_dev *cdev,
-	struct usb_configuration *c, int nluns)
+int mass_storage_bind_config(struct usb_configuration *c)
 {
 	int		rc;
 	struct fsg_dev	*fsg;
 
-	printk(KERN_INFO "mass_storage_function_add\n");
+	printk(KERN_INFO "mass_storage_bind_config\n");
 	rc = fsg_alloc();
 	if (rc)
 		return rc;
 	fsg = the_fsg;
-	fsg->nluns = nluns;
 
 	spin_lock_init(&fsg->lock);
 	init_rwsem(&fsg->filesem);
@@ -2945,7 +2943,7 @@
 	wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND,
 			   "usb_mass_storage");
 
-	fsg->cdev = cdev;
+	fsg->cdev = c->cdev;
 	fsg->function.name = shortname;
 	fsg->function.descriptors = fs_function;
 	fsg->function.bind = fsg_function_bind;
@@ -2972,4 +2970,16 @@
 	return rc;
 }
 
+static struct android_usb_function mass_storage_function = {
+	.name = "usb_mass_storage",
+	.bind_config = mass_storage_bind_config,
+};
+
+static int __init init(void)
+{
+	printk(KERN_INFO "f_mass_storage init\n");
+	android_register_function(&mass_storage_function);
+	return 0;
+}
+module_init(init);
 
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
deleted file mode 100644
index 4e7f419..0000000
--- a/include/linux/usb/android.h
+++ /dev/null
@@ -1,50 +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
-
-struct android_usb_platform_data {
-	/* USB device descriptor fields */
-	__u16 vendor_id;
-
-	/* Default product ID. */
-	__u16 product_id;
-
-	/* Product ID when adb is enabled. */
-	__u16 adb_product_id;
-
-	__u16 version;
-
-	char *product_name;
-	char *manufacturer_name;
-	char *serial_number;
-
-	/* number of LUNS for mass storage function */
-	int nluns;
-};
-
-/* Platform data for "usb_mass_storage" driver.
- * Contains values for the SC_INQUIRY SCSI command. */
-struct usb_mass_storage_platform_data {
-	char *vendor;
-	char *product;
-	int release;
-};
-
-extern void android_usb_set_connected(int on);
-
-#endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h
new file mode 100644
index 0000000..3280168
--- /dev/null
+++ b/include/linux/usb/android_composite.h
@@ -0,0 +1,90 @@
+/*
+ * 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>
+
+struct android_usb_function {
+	struct list_head	list;
+	char			*name;
+	int 			(*bind_config)(struct usb_configuration *c);
+};
+
+struct android_usb_product {
+	/* Default product ID. */
+	__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;
+};
+
+extern void android_usb_set_connected(int on);
+
+extern void android_register_function(struct android_usb_function *f);
+
+extern void android_enable_function(struct usb_function *f, int enable);
+
+
+#endif	/* __LINUX_USB_ANDROID_H */