android_usb: Composite USB gadget driver for android.

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

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: link fixes for android composite gadget

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

usb gadget: Fix null pointer errors in android composite driver

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

usb: gadget: android: Allow usb charging to draw up to 500mA instead of 250.

Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>

usb gadget: android: Add helper function for usb_gadget_connect and disconnect.

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

drivers: usb: gadget: call switch_dev_unregister in mass storage unbind callback

This fixes a problem unloading the android gadget driver when built as a module

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

usb: gadget: android: Add dependency on switch driver.

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

USB: gadget: android: Fix USB WHQL Certification Issues

Submitted on behalf of RaviKumar Vembu <ravi.v@motorola.com>
Signed-off-by: Jared Suttles <jared.suttles@motorola.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>

drivers: usb: gadget: Add "usb_mass_storage" platform driver.

This will be used for configuring vendor, product and release from board file.

Submitted on behalf of RaviKumar Vembu <ravi.v@motorola.com>
Signed-off-by: Jared Suttles <jared.suttles@motorola.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>

drivers: usb: gadget: Use usb_mass_storage platform device as parent for lun

If a platform device is specified for the f_mass_storage function, use it as the
parent driver for the lun files in sysfs.
This allows a platform independent file path for controlling USB mass storage
from user space.

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

drivers: usb: gadget: Add platform data struct for usb_mass_storage device

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

usb: gadget: mass_storage: Fix Mass Storage Panic during PC reboot

Submitted on behalf of RaviKumar Vembu <ravi.v@motorola.com>
Signed-off-by: Jared Suttles <jared.suttles@motorola.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>

usb: gadget: f_mass_storage: Handle setup request correctly

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

usb: gadget: f_mass_storage: Clean up wakelocks on error paths

Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
new file mode 100644
index 0000000..d3c028d
--- /dev/null
+++ b/drivers/usb/gadget/android.c
@@ -0,0 +1,351 @@
+/*
+ * Gadget Driver for Android
+ *
+ * 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.
+ *
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#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/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"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "composite.c"
+
+MODULE_AUTHOR("Mike Lockwood");
+MODULE_DESCRIPTION("Android Composite USB Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+static const char longname[] = "Gadget Android";
+
+/* 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;
+
+	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 */
+
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+#define STRING_SERIAL_IDX		2
+
+/* 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",
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+	.bLength              = sizeof(device_desc),
+	.bDescriptorType      = USB_DT_DEVICE,
+	.bcdUSB               = __constant_cpu_to_le16(0x0200),
+	.bDeviceClass         = USB_CLASS_PER_INTERFACE,
+	.idVendor             = __constant_cpu_to_le16(VENDOR_ID),
+	.idProduct            = __constant_cpu_to_le16(PRODUCT_ID),
+	.bcdDevice            = __constant_cpu_to_le16(0xffff),
+	.bNumConfigurations   = 1,
+};
+
+void android_usb_set_connected(int connected)
+{
+	if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) {
+		if (connected)
+			usb_gadget_connect(_android_dev->cdev->gadget);
+		else
+			usb_gadget_disconnect(_android_dev->cdev->gadget);
+	}
+}
+
+static 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);
+}
+
+static struct usb_configuration android_config_driver = {
+	.label		= "android",
+	.bind		= android_bind_config,
+	.bConfigurationValue = 1,
+	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower	= 0xFA, /* 500ma */
+};
+
+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;
+
+	printk(KERN_INFO "android_bind\n");
+
+	/* Allocate string descriptor numbers ... note that string
+	 * contents can be overridden by the composite_dev glue.
+	 */
+	id = usb_string_id(cdev);
+	if (id < 0)
+		return id;
+	strings_dev[STRING_MANUFACTURER_IDX].id = id;
+	device_desc.iManufacturer = id;
+
+	id = usb_string_id(cdev);
+	if (id < 0)
+		return id;
+	strings_dev[STRING_PRODUCT_IDX].id = id;
+	device_desc.iProduct = id;
+
+	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);
+	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);
+	else {
+		/* gadget zero is so simple (for now, no altsettings) that
+		 * it SHOULD NOT have problems with bulk-capable hardware.
+		 * so just warn about unrcognized controllers -- don't panic.
+		 *
+		 * things like configuration and altsetting numbering
+		 * can need hardware-specific attention though.
+		 */
+		pr_warning("%s: controller '%s' not recognized\n",
+			longname, gadget->name);
+		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+	}
+
+	usb_gadget_set_selfpowered(gadget);
+	dev->cdev = cdev;
+
+	return 0;
+}
+
+static struct usb_composite_driver android_usb_driver = {
+	.name		= "android_usb",
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.bind		= android_bind,
+};
+
+static void enable_adb(struct android_dev *dev, int enable)
+{
+	if (enable != dev->adb_enabled) {
+		dev->adb_enabled = enable;
+		adb_function_enable(enable);
+
+		/* 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);
+		if (dev->cdev)
+			dev->cdev->desc.idProduct = device_desc.idProduct;
+
+		/* force reenumeration */
+		if (dev->cdev && dev->cdev->gadget &&
+				dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
+			usb_gadget_disconnect(dev->cdev->gadget);
+			msleep(10);
+			usb_gadget_connect(dev->cdev->gadget);
+		}
+	}
+}
+
+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;
+	struct android_dev *dev = _android_dev;
+
+	printk(KERN_INFO "android_probe pdata: %p\n", pdata);
+
+	if (pdata) {
+		if (pdata->vendor_id)
+			device_desc.idVendor =
+				__constant_cpu_to_le16(pdata->vendor_id);
+		if (pdata->product_id) {
+			dev->product_id = pdata->product_id;
+			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;
+
+		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;
+		dev->nluns = pdata->nluns;
+	}
+
+	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 ret;
+
+	printk(KERN_INFO "android init\n");
+
+	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->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;
+}
+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;
+}
+module_exit(cleanup);