aboutsummaryrefslogtreecommitdiffstats
diff options
-rw-r--r--bus_id-arm.patch160
-rw-r--r--driver-core-provide-a-dev_set_name-that-handles-names-longer-than-20-chars.patch21
-rw-r--r--driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch2
-rw-r--r--driver-core/class-change-internal-semaphore-to-a-mutex.patch8
-rw-r--r--driver-core/class-move-driver-core-specific-parts-to-a-private-structure.patch6
-rw-r--r--driver-core/class-rename-devices-to-class_devices-in-internal-class-structure.patch2
-rw-r--r--driver-core/class-rename-interfaces-to-class_interfaces-in-internal-class-structure.patch4
-rw-r--r--driver-core/class-rename-sem-to-class_sem-in-internal-class-structure.patch8
-rw-r--r--driver-core/class-rename-subsys-to-class_subsys-in-internal-class-structure.patch2
-rw-r--r--driver-core/driver-core-add-ability-for-class_find_device-to-start-in-middle-of-list.patch2
-rw-r--r--driver-core/driver-core-add-init_name-to-struct-device.patch6
-rw-r--r--driver-core/driver-core-prepare-for-removal-of-20-char-limit-from-struct-device.patch16
-rw-r--r--driver-core/driver-core-remove-device_create.patch2
-rw-r--r--driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch35
-rw-r--r--driver-core/sysfs-add-sys-dev-char-block-to-lookup-sysfs-path-by-major-minor.patch12
-rw-r--r--driver-core/uio-add-generic-uio-platform-driver.patch168
-rw-r--r--driver-core/uio-add-write-function-to-allow-irq-masking.patch155
-rw-r--r--driver-core/uio-fix-uio-kconfig-dependancies.patch39
-rw-r--r--series32
-rw-r--r--usb.current/usb-isp1760-assign-resource-fields-before-adding-hcd.patch42
-rw-r--r--usb/ohci-fix-toggle-bit-desynchronization-when-canceling-urbs.patch58
-rw-r--r--usb/usb-at91_udc-updated-fifo-sizes.patch44
-rw-r--r--usb/usb-auerwald-push-down-the-bkl-into-the-driver.patch59
-rw-r--r--usb/usb-composite-support-16-interfaces-by-default.patch31
-rw-r--r--usb/usb-cp2101.c-fix-sparse-signedness-mismatch-warnings.patch128
-rw-r--r--usb/usb-digi_accelport.c-trivial-sparse-lock-annotation.patch26
-rw-r--r--usb/usb-ftdi_usb-eliminate-ioctl-and-bkl-ioctl-use.patch57
-rw-r--r--usb/usb-gadget-composite-gadget-framework.patch1477
-rw-r--r--usb/usb-gadget-push-bkl-down-into-drivers.patch113
-rw-r--r--usb/usb-gadget-support-descriptor-copying.patch171
-rw-r--r--usb/usb-gadget-zero-loopback-function-driver.patch426
-rw-r--r--usb/usb-gadget-zero-sourcesink-config-driver.patch645
-rw-r--r--usb/usb-gadget-zero-use-updated-framework.patch1346
-rw-r--r--usb/usb-hiddev-switch-to-unlocked_ioctl.patch74
-rw-r--r--usb/usb-iowarrior-push-down-bkl.patch57
-rw-r--r--usb/usb-make-sa1111-ohci-driver-sa11x0-specific.patch35
-rw-r--r--usb/usb-missing-usb_put_hcd-to-ohci-at91.patch65
-rw-r--r--usb/usb-ohci-ppc-of-use-linux-of_platform.h-instead-of-asm.patch29
-rw-r--r--usb/usb-ohci_hcd-hang-submit-vs.-rmmod-race.patch49
-rw-r--r--usb/usb-rio100-push-down-the-bkl.patch56
-rw-r--r--usb/usb-serial-gadget-cdc-acm-function-driver.patch681
-rw-r--r--usb/usb-serial-gadget-generic-serial-function-driver.patch354
-rw-r--r--usb/usb-serial-gadget-use-updated-framework.patch1205
-rw-r--r--usb/usb-sisusb-push-down-the-bkl.patch68
-rw-r--r--usb/usb-speedtch.c-fix-sparse-shadowed-variable-warning.patch30
-rw-r--r--usb/usb-usblcd-push-down-bkl-into-driver.patch55
-rw-r--r--usb/wusb-drivers-uwb-wlp-sysfs.c-move-misplaced-debug-statement.patch33
47 files changed, 7889 insertions, 205 deletions
diff --git a/bus_id-arm.patch b/bus_id-arm.patch
deleted file mode 100644
index f5b876f8fd8599..00000000000000
--- a/bus_id-arm.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-From kay.sievers@vrfy.org Fri May 30 10:26:49 2008
-From: Kay Sievers <kay.sievers@vrfy.org>
-Subject: arm: convert to new driver core device name api
-Date: Fri, 30 May 2008 17:42:11 +0200
-Message-Id: <1212162131.2418.5.camel@linux.site>
-Mime-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Status: RO
-Content-Length: 8395
-
-Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
----
-
----
- arch/arm/mach-aaec2000/core.c | 2 +-
- arch/arm/mach-ep93xx/core.c | 6 +++---
- arch/arm/mach-integrator/core.c | 10 +++++-----
- arch/arm/mach-integrator/integrator_cp.c | 6 +++---
- arch/arm/mach-lh7a40x/clcd.c | 2 +-
- arch/arm/mach-netx/fb.c | 2 +-
- 6 files changed, 14 insertions(+), 14 deletions(-)
-
---- a/arch/arm/mach-aaec2000/core.c
-+++ b/arch/arm/mach-aaec2000/core.c
-@@ -212,7 +212,7 @@ static struct clcd_board clcd_plat_data
-
- static struct amba_device clcd_device = {
- .dev = {
-- .bus_id = "mb:16",
-+ .init_name = "mb:16",
- .coherent_dma_mask = ~0,
- .platform_data = &clcd_plat_data,
- },
---- a/arch/arm/mach-ep93xx/core.c
-+++ b/arch/arm/mach-ep93xx/core.c
-@@ -389,7 +389,7 @@ static struct amba_pl010_data ep93xx_uar
-
- static struct amba_device uart1_device = {
- .dev = {
-- .bus_id = "apb:uart1",
-+ .init_name = "apb:uart1",
- .platform_data = &ep93xx_uart_data,
- },
- .res = {
-@@ -403,7 +403,7 @@ static struct amba_device uart1_device =
-
- static struct amba_device uart2_device = {
- .dev = {
-- .bus_id = "apb:uart2",
-+ .init_name = "apb:uart2",
- .platform_data = &ep93xx_uart_data,
- },
- .res = {
-@@ -417,7 +417,7 @@ static struct amba_device uart2_device =
-
- static struct amba_device uart3_device = {
- .dev = {
-- .bus_id = "apb:uart3",
-+ .init_name = "apb:uart3",
- .platform_data = &ep93xx_uart_data,
- },
- .res = {
---- a/arch/arm/mach-integrator/core.c
-+++ b/arch/arm/mach-integrator/core.c
-@@ -35,7 +35,7 @@ static struct amba_pl010_data integrator
-
- static struct amba_device rtc_device = {
- .dev = {
-- .bus_id = "mb:15",
-+ .init_name = "mb:15",
- },
- .res = {
- .start = INTEGRATOR_RTC_BASE,
-@@ -48,7 +48,7 @@ static struct amba_device rtc_device = {
-
- static struct amba_device uart0_device = {
- .dev = {
-- .bus_id = "mb:16",
-+ .init_name = "mb:16",
- .platform_data = &integrator_uart_data,
- },
- .res = {
-@@ -62,7 +62,7 @@ static struct amba_device uart0_device =
-
- static struct amba_device uart1_device = {
- .dev = {
-- .bus_id = "mb:17",
-+ .init_name = "mb:17",
- .platform_data = &integrator_uart_data,
- },
- .res = {
-@@ -76,7 +76,7 @@ static struct amba_device uart1_device =
-
- static struct amba_device kmi0_device = {
- .dev = {
-- .bus_id = "mb:18",
-+ .init_name = "mb:18",
- },
- .res = {
- .start = KMI0_BASE,
-@@ -89,7 +89,7 @@ static struct amba_device kmi0_device =
-
- static struct amba_device kmi1_device = {
- .dev = {
-- .bus_id = "mb:19",
-+ .init_name = "mb:19",
- },
- .res = {
- .start = KMI1_BASE,
---- a/arch/arm/mach-integrator/integrator_cp.c
-+++ b/arch/arm/mach-integrator/integrator_cp.c
-@@ -406,7 +406,7 @@ static struct mmc_platform_data mmc_data
-
- static struct amba_device mmc_device = {
- .dev = {
-- .bus_id = "mb:1c",
-+ .init_name = "mb:1c",
- .platform_data = &mmc_data,
- },
- .res = {
-@@ -420,7 +420,7 @@ static struct amba_device mmc_device = {
-
- static struct amba_device aaci_device = {
- .dev = {
-- .bus_id = "mb:1d",
-+ .init_name = "mb:1d",
- },
- .res = {
- .start = INTCP_PA_AACI_BASE,
-@@ -531,7 +531,7 @@ static struct clcd_board clcd_data = {
-
- static struct amba_device clcd_device = {
- .dev = {
-- .bus_id = "mb:c0",
-+ .init_name = "mb:c0",
- .coherent_dma_mask = ~0,
- .platform_data = &clcd_data,
- },
---- a/arch/arm/mach-lh7a40x/clcd.c
-+++ b/arch/arm/mach-lh7a40x/clcd.c
-@@ -208,7 +208,7 @@ static struct clcd_board clcd_platform_d
- static struct amba_device name##_device = { \
- .dev = { \
- .coherent_dma_mask = ~0, \
-- .bus_id = busid, \
-+ .init_name = busid, \
- .platform_data = plat, \
- }, \
- .res = { \
---- a/arch/arm/mach-netx/fb.c
-+++ b/arch/arm/mach-netx/fb.c
-@@ -94,7 +94,7 @@ void clk_put(struct clk *clk)
-
- static struct amba_device fb_device = {
- .dev = {
-- .bus_id = "fb",
-+ .init_name = "fb",
- .coherent_dma_mask = ~0,
- },
- .res = {
diff --git a/driver-core-provide-a-dev_set_name-that-handles-names-longer-than-20-chars.patch b/driver-core-provide-a-dev_set_name-that-handles-names-longer-than-20-chars.patch
index c660648061e67e..67ef1e909b5f6c 100644
--- a/driver-core-provide-a-dev_set_name-that-handles-names-longer-than-20-chars.patch
+++ b/driver-core-provide-a-dev_set_name-that-handles-names-longer-than-20-chars.patch
@@ -13,9 +13,9 @@ Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
- drivers/base/core.c | 89 +++++++++++++++++++++++++++++++------------------
+ drivers/base/core.c | 90 +++++++++++++++++++++++++++++++------------------
include/linux/device.h | 10 +++--
- 2 files changed, 64 insertions(+), 35 deletions(-)
+ 2 files changed, 64 insertions(+), 36 deletions(-)
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -29,12 +29,13 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (dev->release)
dev->release(dev);
else if (dev->type && dev->type->release)
-@@ -767,21 +770,6 @@ static void device_remove_class_symlinks
+@@ -767,22 +770,6 @@ static void device_remove_class_symlinks
}
/**
- * dev_set_name - set a device name
- * @dev: device
+- * @fmt: format string for the device's name
- */
-int dev_set_name(struct device *dev, const char *fmt, ...)
-{
@@ -51,7 +52,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
* device_to_dev_kobj - select a /sys/dev/ directory for the device
* @dev: device
*
-@@ -829,6 +817,47 @@ static void device_remove_sys_dev_entry(
+@@ -830,6 +817,47 @@ static void device_remove_sys_dev_entry(
}
}
@@ -99,7 +100,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/**
* device_add - add device to device hierarchy.
* @dev: device.
-@@ -850,12 +879,7 @@ int device_add(struct device *dev)
+@@ -851,12 +879,7 @@ int device_add(struct device *dev)
if (!dev)
goto done;
@@ -113,7 +114,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
goto done;
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
-@@ -867,12 +891,15 @@ int device_add(struct device *dev)
+@@ -868,12 +891,15 @@ int device_add(struct device *dev)
if (parent)
set_dev_node(dev, dev_to_node(parent));
@@ -132,7 +133,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (platform_notify)
platform_notify(dev);
-@@ -927,6 +954,7 @@ int device_add(struct device *dev)
+@@ -928,6 +954,7 @@ int device_add(struct device *dev)
done:
put_device(dev);
return error;
@@ -140,7 +141,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
PMError:
bus_remove_device(dev);
BusError:
-@@ -1233,7 +1261,9 @@ struct device *device_create_vargs(struc
+@@ -1234,7 +1261,9 @@ struct device *device_create_vargs(struc
dev->release = device_create_release;
dev_set_drvdata(dev, drvdata);
@@ -151,7 +152,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
retval = device_register(dev);
if (retval)
goto error;
-@@ -1241,6 +1271,7 @@ struct device *device_create_vargs(struc
+@@ -1242,6 +1271,7 @@ struct device *device_create_vargs(struc
return dev;
error:
@@ -159,7 +160,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
kfree(dev);
return ERR_PTR(retval);
}
-@@ -1340,19 +1371,15 @@ int device_rename(struct device *dev, ch
+@@ -1341,19 +1371,15 @@ int device_rename(struct device *dev, ch
old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif
diff --git a/driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch b/driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch
index ed37ca3b705902..bad0705f2c2096 100644
--- a/driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch
+++ b/driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch
@@ -67,7 +67,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
incorrect and needs to be fixed.
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -1259,6 +1259,11 @@ EXPORT_SYMBOL_GPL(device_destroy);
+@@ -1260,6 +1260,11 @@ EXPORT_SYMBOL_GPL(device_destroy);
* device_rename - renames a device
* @dev: the pointer to the struct device to be renamed
* @new_name: the new name of the device
diff --git a/driver-core/class-change-internal-semaphore-to-a-mutex.patch b/driver-core/class-change-internal-semaphore-to-a-mutex.patch
index 7fc9e1b79a3df2..27d7c0d8d2455e 100644
--- a/driver-core/class-change-internal-semaphore-to-a-mutex.patch
+++ b/driver-core/class-change-internal-semaphore-to-a-mutex.patch
@@ -160,7 +160,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#include "base.h"
#include "power/power.h"
-@@ -906,7 +907,7 @@ int device_add(struct device *dev)
+@@ -907,7 +908,7 @@ int device_add(struct device *dev)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
@@ -169,7 +169,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* tie the class to the device */
list_add_tail(&dev->node, &dev->class->p->class_devices);
-@@ -915,7 +916,7 @@ int device_add(struct device *dev)
+@@ -916,7 +917,7 @@ int device_add(struct device *dev)
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
@@ -178,7 +178,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
Done:
put_device(dev);
-@@ -1016,7 +1017,7 @@ void device_del(struct device *dev)
+@@ -1017,7 +1018,7 @@ void device_del(struct device *dev)
if (dev->class) {
device_remove_class_symlinks(dev);
@@ -187,7 +187,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* notify any interfaces that the device is now gone */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
-@@ -1024,7 +1025,7 @@ void device_del(struct device *dev)
+@@ -1025,7 +1026,7 @@ void device_del(struct device *dev)
class_intf->remove_dev(dev, class_intf);
/* remove the device from the class list */
list_del_init(&dev->node);
diff --git a/driver-core/class-move-driver-core-specific-parts-to-a-private-structure.patch b/driver-core/class-move-driver-core-specific-parts-to-a-private-structure.patch
index 79ea9af6875299..4d2d549cded627 100644
--- a/driver-core/class-move-driver-core-specific-parts-to-a-private-structure.patch
+++ b/driver-core/class-move-driver-core-specific-parts-to-a-private-structure.patch
@@ -389,7 +389,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#endif
sysfs_remove_link(&dev->kobj, "subsystem");
-@@ -903,15 +903,16 @@ int device_add(struct device *dev)
+@@ -904,15 +904,16 @@ int device_add(struct device *dev)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
@@ -410,7 +410,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
Done:
put_device(dev);
-@@ -1012,14 +1013,15 @@ void device_del(struct device *dev)
+@@ -1013,14 +1014,15 @@ void device_del(struct device *dev)
if (dev->class) {
device_remove_class_symlinks(dev);
@@ -429,7 +429,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
-@@ -1355,11 +1357,12 @@ int device_rename(struct device *dev, ch
+@@ -1356,11 +1358,12 @@ int device_rename(struct device *dev, ch
}
#else
if (dev->class) {
diff --git a/driver-core/class-rename-devices-to-class_devices-in-internal-class-structure.patch b/driver-core/class-rename-devices-to-class_devices-in-internal-class-structure.patch
index 8cc09659207848..e11b765b780f34 100644
--- a/driver-core/class-rename-devices-to-class_devices-in-internal-class-structure.patch
+++ b/driver-core/class-rename-devices-to-class_devices-in-internal-class-structure.patch
@@ -87,7 +87,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
up(&parent->p->sem);
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -905,7 +905,7 @@ int device_add(struct device *dev)
+@@ -906,7 +906,7 @@ int device_add(struct device *dev)
if (dev->class) {
down(&dev->class->p->sem);
/* tie the class to the device */
diff --git a/driver-core/class-rename-interfaces-to-class_interfaces-in-internal-class-structure.patch b/driver-core/class-rename-interfaces-to-class_interfaces-in-internal-class-structure.patch
index 92492131b8d9f7..40ebaf6f5b57ca 100644
--- a/driver-core/class-rename-interfaces-to-class_interfaces-in-internal-class-structure.patch
+++ b/driver-core/class-rename-interfaces-to-class_interfaces-in-internal-class-structure.patch
@@ -61,7 +61,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
class_intf->add_dev(dev, class_intf);
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -908,8 +908,8 @@ int device_add(struct device *dev)
+@@ -909,8 +909,8 @@ int device_add(struct device *dev)
list_add_tail(&dev->node, &dev->class->p->class_devices);
/* notify any interfaces that the device is here */
@@ -72,7 +72,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->p->sem);
-@@ -1015,8 +1015,8 @@ void device_del(struct device *dev)
+@@ -1016,8 +1016,8 @@ void device_del(struct device *dev)
down(&dev->class->p->sem);
/* notify any interfaces that the device is now gone */
diff --git a/driver-core/class-rename-sem-to-class_sem-in-internal-class-structure.patch b/driver-core/class-rename-sem-to-class_sem-in-internal-class-structure.patch
index cf1fb7164c8b29..b1804938f47d8e 100644
--- a/driver-core/class-rename-sem-to-class_sem-in-internal-class-structure.patch
+++ b/driver-core/class-rename-sem-to-class_sem-in-internal-class-structure.patch
@@ -137,7 +137,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -906,7 +906,7 @@ int device_add(struct device *dev)
+@@ -907,7 +907,7 @@ int device_add(struct device *dev)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
@@ -146,7 +146,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* tie the class to the device */
list_add_tail(&dev->node, &dev->class->p->class_devices);
-@@ -915,7 +915,7 @@ int device_add(struct device *dev)
+@@ -916,7 +916,7 @@ int device_add(struct device *dev)
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
@@ -155,7 +155,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
Done:
put_device(dev);
-@@ -1016,7 +1016,7 @@ void device_del(struct device *dev)
+@@ -1017,7 +1017,7 @@ void device_del(struct device *dev)
if (dev->class) {
device_remove_class_symlinks(dev);
@@ -164,7 +164,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* notify any interfaces that the device is now gone */
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
-@@ -1024,7 +1024,7 @@ void device_del(struct device *dev)
+@@ -1025,7 +1025,7 @@ void device_del(struct device *dev)
class_intf->remove_dev(dev, class_intf);
/* remove the device from the class list */
list_del_init(&dev->node);
diff --git a/driver-core/class-rename-subsys-to-class_subsys-in-internal-class-structure.patch b/driver-core/class-rename-subsys-to-class_subsys-in-internal-class-structure.patch
index b492ceca1b931e..e397de2e7f13a7 100644
--- a/driver-core/class-rename-subsys-to-class_subsys-in-internal-class-structure.patch
+++ b/driver-core/class-rename-subsys-to-class_subsys-in-internal-class-structure.patch
@@ -209,7 +209,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#endif
sysfs_remove_link(&dev->kobj, "subsystem");
-@@ -1357,11 +1360,11 @@ int device_rename(struct device *dev, ch
+@@ -1358,11 +1361,11 @@ int device_rename(struct device *dev, ch
}
#else
if (dev->class) {
diff --git a/driver-core/driver-core-add-ability-for-class_find_device-to-start-in-middle-of-list.patch b/driver-core/driver-core-add-ability-for-class_find_device-to-start-in-middle-of-list.patch
index 0df91b0a195741..2c71eb7414af7c 100644
--- a/driver-core/driver-core-add-ability-for-class_find_device-to-start-in-middle-of-list.patch
+++ b/driver-core/driver-core-add-ability-for-class_find_device-to-start-in-middle-of-list.patch
@@ -75,7 +75,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -1291,7 +1291,7 @@ void device_destroy(struct class *class,
+@@ -1292,7 +1292,7 @@ void device_destroy(struct class *class,
{
struct device *dev;
diff --git a/driver-core/driver-core-add-init_name-to-struct-device.patch b/driver-core/driver-core-add-init_name-to-struct-device.patch
index 6924da0d6ef07a..0f8d1718c40e59 100644
--- a/driver-core/driver-core-add-init_name-to-struct-device.patch
+++ b/driver-core/driver-core-add-init_name-to-struct-device.patch
@@ -17,7 +17,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -843,13 +843,19 @@ int device_add(struct device *dev)
+@@ -844,13 +844,19 @@ int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
@@ -42,7 +42,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
-@@ -917,7 +923,7 @@ int device_add(struct device *dev)
+@@ -918,7 +924,7 @@ int device_add(struct device *dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_mutex);
}
@@ -51,7 +51,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
put_device(dev);
return error;
PMError:
-@@ -944,7 +950,7 @@ int device_add(struct device *dev)
+@@ -945,7 +951,7 @@ int device_add(struct device *dev)
cleanup_device_parent(dev);
if (parent)
put_device(parent);
diff --git a/driver-core/driver-core-prepare-for-removal-of-20-char-limit-from-struct-device.patch b/driver-core/driver-core-prepare-for-removal-of-20-char-limit-from-struct-device.patch
index 5152db7e2ffc72..455245051a6f57 100644
--- a/driver-core/driver-core-prepare-for-removal-of-20-char-limit-from-struct-device.patch
+++ b/driver-core/driver-core-prepare-for-removal-of-20-char-limit-from-struct-device.patch
@@ -749,7 +749,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#endif
sysfs_remove_link(&dev->kobj, "subsystem");
-@@ -852,7 +851,7 @@ int device_add(struct device *dev)
+@@ -853,7 +852,7 @@ int device_add(struct device *dev)
goto Done;
}
@@ -758,7 +758,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
parent = get_device(dev->parent);
setup_parent(dev, parent);
-@@ -862,7 +861,7 @@ int device_add(struct device *dev)
+@@ -863,7 +862,7 @@ int device_add(struct device *dev)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
@@ -767,7 +767,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (error)
goto Error;
-@@ -1065,7 +1064,7 @@ void device_del(struct device *dev)
+@@ -1066,7 +1065,7 @@ void device_del(struct device *dev)
*/
void device_unregister(struct device *dev)
{
@@ -776,7 +776,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
device_del(dev);
put_device(dev);
}
-@@ -1178,7 +1177,7 @@ EXPORT_SYMBOL_GPL(device_remove_file);
+@@ -1179,7 +1178,7 @@ EXPORT_SYMBOL_GPL(device_remove_file);
static void device_create_release(struct device *dev)
{
@@ -785,7 +785,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
kfree(dev);
}
-@@ -1326,7 +1325,7 @@ int device_rename(struct device *dev, ch
+@@ -1327,7 +1326,7 @@ int device_rename(struct device *dev, ch
if (!dev)
return -EINVAL;
@@ -794,7 +794,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
__func__, new_name);
#ifdef CONFIG_SYSFS_DEPRECATED
-@@ -1339,7 +1338,7 @@ int device_rename(struct device *dev, ch
+@@ -1340,7 +1339,7 @@ int device_rename(struct device *dev, ch
error = -ENOMEM;
goto out;
}
@@ -803,7 +803,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name);
-@@ -1362,7 +1361,7 @@ int device_rename(struct device *dev, ch
+@@ -1363,7 +1362,7 @@ int device_rename(struct device *dev, ch
#else
if (dev->class) {
error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
@@ -812,7 +812,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (error)
goto out;
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
-@@ -1440,8 +1439,8 @@ int device_move(struct device *dev, stru
+@@ -1441,8 +1440,8 @@ int device_move(struct device *dev, stru
new_parent = get_device(new_parent);
new_parent_kobj = get_device_parent(dev, new_parent);
diff --git a/driver-core/driver-core-remove-device_create.patch b/driver-core/driver-core-remove-device_create.patch
index 222f1f96b5f862..9b40ea46ddf84d 100644
--- a/driver-core/driver-core-remove-device_create.patch
+++ b/driver-core/driver-core-remove-device_create.patch
@@ -16,7 +16,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
-@@ -1272,40 +1272,6 @@ struct device *device_create_drvdata(str
+@@ -1273,40 +1273,6 @@ struct device *device_create_drvdata(str
}
EXPORT_SYMBOL_GPL(device_create_drvdata);
diff --git a/driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch b/driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch
new file mode 100644
index 00000000000000..3888347a92376d
--- /dev/null
+++ b/driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch
@@ -0,0 +1,35 @@
+From richard@rsk.demon.co.uk Fri Jun 6 15:22:07 2008
+From: Richard Kennedy <richard@rsk.demon.co.uk>
+Date: Mon, 02 Jun 2008 11:07:25 +0100
+Subject: kobject: reorder kobject to save space on 64 bit builds
+To: gregkh <gregkh@suse.de>
+Message-ID: <1212401245.2966.8.camel@castor.localdomain>
+
+
+reorder kobject to save space on 64 bit builds.
+shrinks from 72 to 64 bytes & moves allocated kobject to a smaller
+slab.
+
+Signed-off-by: Richard Kennedy <richard@rsk.demon.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/kobject.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -58,12 +58,12 @@ enum kobject_action {
+
+ struct kobject {
+ const char *name;
+- struct kref kref;
+ struct list_head entry;
+ struct kobject *parent;
+ struct kset *kset;
+ struct kobj_type *ktype;
+ struct sysfs_dirent *sd;
++ struct kref kref;
+ unsigned int state_initialized:1;
+ unsigned int state_in_sysfs:1;
+ unsigned int state_add_uevent_sent:1;
diff --git a/driver-core/sysfs-add-sys-dev-char-block-to-lookup-sysfs-path-by-major-minor.patch b/driver-core/sysfs-add-sys-dev-char-block-to-lookup-sysfs-path-by-major-minor.patch
index ed9a41a564f73d..dada3dd9cf7d04 100644
--- a/driver-core/sysfs-add-sys-dev-char-block-to-lookup-sysfs-path-by-major-minor.patch
+++ b/driver-core/sysfs-add-sys-dev-char-block-to-lookup-sysfs-path-by-major-minor.patch
@@ -134,7 +134,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#ifdef CONFIG_BLOCK
static inline int device_is_not_partition(struct device *dev)
-@@ -775,6 +778,54 @@ int dev_set_name(struct device *dev, con
+@@ -776,6 +779,54 @@ int dev_set_name(struct device *dev, con
EXPORT_SYMBOL_GPL(dev_set_name);
/**
@@ -189,7 +189,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
* device_add - add device to device hierarchy.
* @dev: device.
*
-@@ -828,6 +879,10 @@ int device_add(struct device *dev)
+@@ -829,6 +880,10 @@ int device_add(struct device *dev)
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
@@ -200,7 +200,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
error = device_add_class_symlinks(dev);
-@@ -872,6 +927,9 @@ int device_add(struct device *dev)
+@@ -873,6 +928,9 @@ int device_add(struct device *dev)
device_remove_class_symlinks(dev);
SymlinkError:
if (MAJOR(dev->devt))
@@ -210,7 +210,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
device_remove_file(dev, &devt_attr);
ueventattrError:
device_remove_file(dev, &uevent_attr);
-@@ -947,8 +1005,10 @@ void device_del(struct device *dev)
+@@ -948,8 +1006,10 @@ void device_del(struct device *dev)
device_pm_remove(dev);
if (parent)
klist_del(&dev->knode_parent);
@@ -222,7 +222,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
if (dev->class) {
device_remove_class_symlinks(dev);
-@@ -1073,7 +1133,25 @@ int __init devices_init(void)
+@@ -1074,7 +1134,25 @@ int __init devices_init(void)
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
@@ -248,7 +248,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
}
EXPORT_SYMBOL_GPL(device_for_each_child);
-@@ -1451,4 +1529,7 @@ void device_shutdown(void)
+@@ -1452,4 +1530,7 @@ void device_shutdown(void)
dev->driver->shutdown(dev);
}
}
diff --git a/driver-core/uio-add-generic-uio-platform-driver.patch b/driver-core/uio-add-generic-uio-platform-driver.patch
new file mode 100644
index 00000000000000..2d487467b6eeaa
--- /dev/null
+++ b/driver-core/uio-add-generic-uio-platform-driver.patch
@@ -0,0 +1,168 @@
+From hjk@linutronix.de Sat May 31 02:37:42 2008
+From: Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>
+Date: Sat, 31 May 2008 11:37:27 +0200
+Subject: UIO: add generic UIO platform driver
+To: linux-kernel@vger.kernel.org
+Cc: Hans J. Koch <hjk@linutronix.de>, Greg Kroah-Hartman <gregkh@suse.de>
+
+
+This patch adds a generic UIO platform driver. It eliminates the need for a
+dedicated kernel module for simple platform devices. Users only need to
+implement their irq handler in platform code and fill a struct uio_info
+there. This helps avoiding code duplication as UIO platform drivers often
+share a lot of common code.
+
+Signed-off-by: Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>
+Signed-off-by: Hans J. Koch <hjk@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/uio/Kconfig | 7 ++
+ drivers/uio/Makefile | 1
+ drivers/uio/uio_pdrv.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 126 insertions(+)
+
+--- a/drivers/uio/Kconfig
++++ b/drivers/uio/Kconfig
+@@ -26,6 +26,13 @@ config UIO_CIF
+ To compile this driver as a module, choose M here: the module
+ will be called uio_cif.
+
++config UIO_PDRV
++ tristate "Userspace I/O platform driver"
++ help
++ Generic platform driver for Userspace I/O devices.
++
++ If you don't know what to do here, say N.
++
+ config UIO_SMX
+ tristate "SMX cryptengine UIO interface"
+ default n
+--- a/drivers/uio/Makefile
++++ b/drivers/uio/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_UIO) += uio.o
+ obj-$(CONFIG_UIO_CIF) += uio_cif.o
++obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
+ obj-$(CONFIG_UIO_SMX) += uio_smx.o
+--- /dev/null
++++ b/drivers/uio/uio_pdrv.c
+@@ -0,0 +1,118 @@
++/*
++ * drivers/uio/uio_pdrv.c
++ *
++ * Copyright (C) 2008 by Digi International Inc.
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ */
++#include <linux/platform_device.h>
++#include <linux/uio_driver.h>
++#include <linux/stringify.h>
++
++#define DRIVER_NAME "uio"
++
++struct uio_platdata {
++ struct uio_info *uioinfo;
++};
++
++static int uio_pdrv_probe(struct platform_device *pdev)
++{
++ struct uio_info *uioinfo = pdev->dev.platform_data;
++ struct uio_platdata *pdata;
++ struct uio_mem *uiomem;
++ int ret = -ENODEV;
++ int i;
++
++ if (!uioinfo || !uioinfo->name || !uioinfo->version) {
++ dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__);
++ goto err_uioinfo;
++ }
++
++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ ret = -ENOMEM;
++ dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__);
++ goto err_alloc_pdata;
++ }
++
++ pdata->uioinfo = uioinfo;
++
++ uiomem = &uioinfo->mem[0];
++
++ for (i = 0; i < pdev->num_resources; ++i) {
++ struct resource *r = &pdev->resource[i];
++
++ if (r->flags != IORESOURCE_MEM)
++ continue;
++
++ if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
++ dev_warn(&pdev->dev, "device has more than "
++ __stringify(MAX_UIO_MAPS)
++ " I/O memory resources.\n");
++ break;
++ }
++
++ uiomem->memtype = UIO_MEM_PHYS;
++ uiomem->addr = r->start;
++ uiomem->size = r->end - r->start + 1;
++ ++uiomem;
++ }
++
++ while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
++ uiomem->size = 0;
++ ++uiomem;
++ }
++
++ pdata->uioinfo->priv = pdata;
++
++ ret = uio_register_device(&pdev->dev, pdata->uioinfo);
++
++ if (ret) {
++ kfree(pdata);
++err_alloc_pdata:
++err_uioinfo:
++ return ret;
++ }
++
++ platform_set_drvdata(pdev, pdata);
++
++ return 0;
++}
++
++static int uio_pdrv_remove(struct platform_device *pdev)
++{
++ struct uio_platdata *pdata = platform_get_drvdata(pdev);
++
++ uio_unregister_device(pdata->uioinfo);
++
++ return 0;
++}
++
++static struct platform_driver uio_pdrv = {
++ .probe = uio_pdrv_probe,
++ .remove = uio_pdrv_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init uio_pdrv_init(void)
++{
++ return platform_driver_register(&uio_pdrv);
++}
++
++static void __exit uio_pdrv_exit(void)
++{
++ platform_driver_unregister(&uio_pdrv);
++}
++module_init(uio_pdrv_init);
++module_exit(uio_pdrv_exit);
++
++MODULE_AUTHOR("Uwe Kleine-Koenig");
++MODULE_DESCRIPTION("Userspace I/O platform driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/driver-core/uio-add-write-function-to-allow-irq-masking.patch b/driver-core/uio-add-write-function-to-allow-irq-masking.patch
new file mode 100644
index 00000000000000..bf3f1f446c1604
--- /dev/null
+++ b/driver-core/uio-add-write-function-to-allow-irq-masking.patch
@@ -0,0 +1,155 @@
+From hjk@linutronix.de Sat May 31 02:37:42 2008
+From: Hans J. Koch <hjk@linutronix.de>
+Date: Sat, 31 May 2008 11:37:27 +0200
+Date: Thu, Fri, 23 May 2008 13:50:14 +0200
+Subject: UIO: Add write function to allow irq masking
+To: linux-kernel@vger.kernel.org
+Cc: Greg Kroah-Hartman <gregkh@suse.de>, Jan Altenberg <jan.altenberg@linutronix.de>, Thomas Gleixner <tglx@linutronix.de>, Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>, Magnus Damm <magnus.damm@gmail.com>
+
+
+Sometimes it is necessary to enable/disable the interrupt of a UIO device
+from the userspace part of the driver. With this patch, the UIO kernel driver
+can implement an "irqcontrol()" function that does this. Userspace can write
+an s32 value to /dev/uioX (usually 0 or 1 to turn the irq off or on). The
+UIO core will then call the driver's irqcontrol function.
+
+Signed-off-by: Hans J. Koch <hjk@linutronix.de>
+Acked-by: Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/uio-howto.tmpl | 40 ++++++++++++++++++++++++++++++++++-
+ drivers/uio/uio.c | 26 ++++++++++++++++++++++
+ include/linux/uio_driver.h | 2 +
+ 3 files changed, 67 insertions(+), 1 deletion(-)
+
+--- a/Documentation/DocBook/uio-howto.tmpl
++++ b/Documentation/DocBook/uio-howto.tmpl
+@@ -30,6 +30,12 @@
+
+ <revhistory>
+ <revision>
++ <revnumber>0.5</revnumber>
++ <date>2008-05-22</date>
++ <authorinitials>hjk</authorinitials>
++ <revremark>Added description of write() function.</revremark>
++ </revision>
++ <revision>
+ <revnumber>0.4</revnumber>
+ <date>2007-11-26</date>
+ <authorinitials>hjk</authorinitials>
+@@ -64,7 +70,7 @@
+ <?dbhtml filename="copyright.html"?>
+ <title>Copyright and License</title>
+ <para>
+- Copyright (c) 2006 by Hans-Jürgen Koch.</para>
++ Copyright (c) 2006-2008 by Hans-Jürgen Koch.</para>
+ <para>
+ This documentation is Free Software licensed under the terms of the
+ GPL version 2.
+@@ -189,6 +195,30 @@ interested in translating it, please ema
+ represents the total interrupt count. You can use this number
+ to figure out if you missed some interrupts.
+ </para>
++ <para>
++ For some hardware that has more than one interrupt source internally,
++ but not separate IRQ mask and status registers, there might be
++ situations where userspace cannot determine what the interrupt source
++ was if the kernel handler disables them by writing to the chip's IRQ
++ register. In such a case, the kernel has to disable the IRQ completely
++ to leave the chip's register untouched. Now the userspace part can
++ determine the cause of the interrupt, but it cannot re-enable
++ interrupts. Another cornercase is chips where re-enabling interrupts
++ is a read-modify-write operation to a combined IRQ status/acknowledge
++ register. This would be racy if a new interrupt occurred
++ simultaneously.
++ </para>
++ <para>
++ To address these problems, UIO also implements a write() function. It
++ is normally not used and can be ignored for hardware that has only a
++ single interrupt source or has separate IRQ mask and status registers.
++ If you need it, however, a write to <filename>/dev/uioX</filename>
++ will call the <function>irqcontrol()</function> function implemented
++ by the driver. You have to write a 32-bit value that is usually either
++ 0 or 1 to disable or enable interrupts. If a driver does not implement
++ <function>irqcontrol()</function>, <function>write()</function> will
++ return with <varname>-ENOSYS</varname>.
++ </para>
+
+ <para>
+ To handle interrupts properly, your custom kernel module can
+@@ -362,6 +392,14 @@ device is actually used.
+ <function>open()</function>, you will probably also want a custom
+ <function>release()</function> function.
+ </para></listitem>
++
++<listitem><para>
++<varname>int (*irqcontrol)(struct uio_info *info, s32 irq_on)
++</varname>: Optional. If you need to be able to enable or disable
++interrupts from userspace by writing to <filename>/dev/uioX</filename>,
++you can implement this function. The parameter <varname>irq_on</varname>
++will be 0 to disable interrupts and 1 to enable them.
++</para></listitem>
+ </itemizedlist>
+
+ <para>
+--- a/drivers/uio/uio.c
++++ b/drivers/uio/uio.c
+@@ -420,6 +420,31 @@ static ssize_t uio_read(struct file *fil
+ return retval;
+ }
+
++static ssize_t uio_write(struct file *filep, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct uio_listener *listener = filep->private_data;
++ struct uio_device *idev = listener->dev;
++ ssize_t retval;
++ s32 irq_on;
++
++ if (idev->info->irq == UIO_IRQ_NONE)
++ return -EIO;
++
++ if (count != sizeof(s32))
++ return -EINVAL;
++
++ if (!idev->info->irqcontrol)
++ return -ENOSYS;
++
++ if (copy_from_user(&irq_on, buf, count))
++ return -EFAULT;
++
++ retval = idev->info->irqcontrol(idev->info, irq_on);
++
++ return retval ? retval : sizeof(s32);
++}
++
+ static int uio_find_mem_index(struct vm_area_struct *vma)
+ {
+ int mi;
+@@ -539,6 +564,7 @@ static const struct file_operations uio_
+ .open = uio_open,
+ .release = uio_release,
+ .read = uio_read,
++ .write = uio_write,
+ .mmap = uio_mmap,
+ .poll = uio_poll,
+ .fasync = uio_fasync,
+--- a/include/linux/uio_driver.h
++++ b/include/linux/uio_driver.h
+@@ -53,6 +53,7 @@ struct uio_device;
+ * @mmap: mmap operation for this uio device
+ * @open: open operation for this uio device
+ * @release: release operation for this uio device
++ * @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX
+ */
+ struct uio_info {
+ struct uio_device *uio_dev;
+@@ -66,6 +67,7 @@ struct uio_info {
+ int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
+ int (*open)(struct uio_info *info, struct inode *inode);
+ int (*release)(struct uio_info *info, struct inode *inode);
++ int (*irqcontrol)(struct uio_info *info, s32 irq_on);
+ };
+
+ extern int __must_check
diff --git a/driver-core/uio-fix-uio-kconfig-dependancies.patch b/driver-core/uio-fix-uio-kconfig-dependancies.patch
new file mode 100644
index 00000000000000..6c0772aa11f954
--- /dev/null
+++ b/driver-core/uio-fix-uio-kconfig-dependancies.patch
@@ -0,0 +1,39 @@
+From hjk@linutronix.de Sat May 31 02:37:42 2008
+From: Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>
+Date: Sat, 31 May 2008 11:37:27 +0200
+Subject: UIO: fix UIO Kconfig dependancies
+To: linux-kernel@vger.kernel.org
+Cc: Hans J. Koch <hjk@linutronix.de>, Greg Kroah-Hartman <gregkh@suse.de>
+
+
+ae210f188614bb3d1ee3f19c64e28e3cdd44877c introduced a big "if UIO"/"endif"
+where all uio drivers are defined. So know there is no need for them to
+depend explicitly on UIO.
+
+Signed-off-by: Uwe Kleine-K�nig <Uwe.Kleine-Koenig@digi.com>
+Signed-off-by: Hans J. Koch <hjk@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/uio/Kconfig | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/uio/Kconfig
++++ b/drivers/uio/Kconfig
+@@ -15,7 +15,7 @@ if UIO
+
+ config UIO_CIF
+ tristate "generic Hilscher CIF Card driver"
+- depends on UIO && PCI
++ depends on PCI
+ default n
+ help
+ Driver for Hilscher CIF DeviceNet and Profibus cards. This
+@@ -28,7 +28,6 @@ config UIO_CIF
+
+ config UIO_SMX
+ tristate "SMX cryptengine UIO interface"
+- depends on UIO
+ default n
+ help
+ Userspace IO interface to the Cryptography engine found on the
diff --git a/series b/series
index 6e069128761f98..1434cba166cfbc 100644
--- a/series
+++ b/series
@@ -21,6 +21,7 @@ driver-core.current/kobject-fix-kobject_rename-and-config_sysfs.patch
#################################
usb.current/usb-fix-build-bug-in-usb_isightfw.patch
usb.current/isight_firmware-avoid-crash-on-loading-invalid-firmware.patch
+usb.current/usb-isp1760-assign-resource-fields-before-adding-hcd.patch
#####################################################################
# Stuff to be merged after 2.6.26 is out
@@ -91,6 +92,10 @@ driver-core/driver-core-remove-device_id_size-define.patch
driver-core/driver-core-fix-a-lot-of-printk-usages-of-bus_id.patch
driver-core/pnp-add-acpi-modalias-entries.patch
+driver-core/uio-fix-uio-kconfig-dependancies.patch
+driver-core/uio-add-write-function-to-allow-irq-masking.patch
+driver-core/uio-add-generic-uio-platform-driver.patch
+driver-core/kobject-reorder-kobject-to-save-space-on-64-bit-builds.patch
# bus_id fun
driver-core/pci-make-pci_name-use-dev_name.patch
@@ -171,6 +176,32 @@ usb/usb-remove-documentation-usb-uhci.txt.patch
usb/usb-serial-gadget-modular-tty-glue.patch
usb/usb-serial-gadget-use-new-tty-glue.patch
usb/usb-rndis-switch-to-seq_files.patch
+usb/usb-at91_udc-updated-fifo-sizes.patch
+usb/usb-gadget-support-descriptor-copying.patch
+usb/usb-gadget-composite-gadget-framework.patch
+usb/usb-gadget-zero-sourcesink-config-driver.patch
+usb/usb-gadget-zero-loopback-function-driver.patch
+usb/usb-gadget-zero-use-updated-framework.patch
+usb/usb-serial-gadget-cdc-acm-function-driver.patch
+usb/usb-serial-gadget-generic-serial-function-driver.patch
+usb/usb-serial-gadget-use-updated-framework.patch
+usb/usb-composite-support-16-interfaces-by-default.patch
+usb/usb-gadget-push-bkl-down-into-drivers.patch
+usb/usb-ftdi_usb-eliminate-ioctl-and-bkl-ioctl-use.patch
+usb/usb-usblcd-push-down-bkl-into-driver.patch
+usb/usb-iowarrior-push-down-bkl.patch
+usb/usb-hiddev-switch-to-unlocked_ioctl.patch
+usb/usb-auerwald-push-down-the-bkl-into-the-driver.patch
+usb/usb-rio100-push-down-the-bkl.patch
+usb/usb-sisusb-push-down-the-bkl.patch
+usb/usb-ohci-ppc-of-use-linux-of_platform.h-instead-of-asm.patch
+usb/usb-digi_accelport.c-trivial-sparse-lock-annotation.patch
+usb/usb-cp2101.c-fix-sparse-signedness-mismatch-warnings.patch
+usb/usb-speedtch.c-fix-sparse-shadowed-variable-warning.patch
+usb/ohci-fix-toggle-bit-desynchronization-when-canceling-urbs.patch
+usb/usb-missing-usb_put_hcd-to-ohci-at91.patch
+usb/usb-make-sa1111-ohci-driver-sa11x0-specific.patch
+usb/usb-ohci_hcd-hang-submit-vs.-rmmod-race.patch
# wireless usb, still a work in progress
usb/bitmap-add-bitmap_copy_le.patch
@@ -207,6 +238,7 @@ usb/wusb-add-the-wire-adapter-core.patch
usb/wusb-add-hwa-hc-wireless-host-controller-driver.patch
usb/wusb-fix-error-path-for-wusb_set_dev_addr.patch
usb/uwb-disable-command-event-filtering-for-DUB-1210.patch
+usb/wusb-drivers-uwb-wlp-sysfs.c-move-misplaced-debug-statement.patch
# my ols tutorial driver, never in mainline
usb/usb-gotemp.patch
diff --git a/usb.current/usb-isp1760-assign-resource-fields-before-adding-hcd.patch b/usb.current/usb-isp1760-assign-resource-fields-before-adding-hcd.patch
new file mode 100644
index 00000000000000..d99624262e7287
--- /dev/null
+++ b/usb.current/usb-isp1760-assign-resource-fields-before-adding-hcd.patch
@@ -0,0 +1,42 @@
+From ncase@xes-inc.com Fri Jun 6 15:07:08 2008
+From: Nate Case <ncase@xes-inc.com>
+Date: Wed, 21 May 2008 16:28:20 -0500
+Subject: USB: isp1760: Assign resource fields before adding hcd
+To: Sebastian Siewior <bigeasy@linutronix.de>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>, linux-usb@vger.kernel.org, linuxppc-dev <linuxppc-dev@ozlabs.org>
+Message-ID: <1211405300.13845.627.camel@localhost.localdomain>
+
+
+This fixes the bogus "io mem 0x00000000" message printed
+during driver init due to hcd->rsrc_start being assigned after
+the call to usb_add_hcd().
+
+Signed-off-by: Nate Case <ncase@xes-inc.com>
+Acked-by: Sebastian Siewior <bigeasy@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/isp1760-hcd.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/isp1760-hcd.c
++++ b/drivers/usb/host/isp1760-hcd.c
+@@ -2207,14 +2207,14 @@ struct usb_hcd *isp1760_register(u64 res
+ goto err_put;
+ }
+
+- ret = usb_add_hcd(hcd, irq, irqflags);
+- if (ret)
+- goto err_unmap;
+-
+ hcd->irq = irq;
+ hcd->rsrc_start = res_start;
+ hcd->rsrc_len = res_len;
+
++ ret = usb_add_hcd(hcd, irq, irqflags);
++ if (ret)
++ goto err_unmap;
++
+ return hcd;
+
+ err_unmap:
diff --git a/usb/ohci-fix-toggle-bit-desynchronization-when-canceling-urbs.patch b/usb/ohci-fix-toggle-bit-desynchronization-when-canceling-urbs.patch
new file mode 100644
index 00000000000000..42a59cd13d9cf5
--- /dev/null
+++ b/usb/ohci-fix-toggle-bit-desynchronization-when-canceling-urbs.patch
@@ -0,0 +1,58 @@
+From leonidv11@gmail.com Fri Jun 6 15:17:55 2008
+From: Leonid <leonidv11@gmail.com>
+Date: Fri, 30 May 2008 11:59:01 -0700
+Subject: OHCI: fix toggle bit desynchronization when canceling URBs
+To: "USB list" <linux-usb@vger.kernel.org>
+Cc: "Greg KH" <greg@kroah.com>, "David Brownell" <david-b@pacbell.net>
+Message-ID: <efc7ee340805301159k30108141h6ceec6f4cefe840c@mail.gmail.com>
+Content-Disposition: inline
+
+
+This patch fixes a problem where canceling (bulk or interrupts) URBs
+through the OHCI controller can result in a desynchronization of the
+toggle bits between the HC and the peripheral. The reason for this
+issue stems from the fact that during the cancellation process the TD
+is never officially "retired" by the HC and, therefore, as per the
+OHCI specification, the TD's internal toggle state does not get passed
+to the ED's toggle state. Future TDs that obtain their toggle state
+from the ED would then be using an incorrect toggle state.
+
+The fix is simple: the toggle state of any canceled TDs are
+propagated back to the ED in the finish_unlinks function.
+
+Signed-off-by: Leonid <leonidv11@gmail.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-q.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/usb/host/ohci-q.c
++++ b/drivers/usb/host/ohci-q.c
+@@ -952,6 +952,7 @@ rescan_this:
+ struct urb *urb;
+ urb_priv_t *urb_priv;
+ __hc32 savebits;
++ u32 tdINFO;
+
+ td = list_entry (entry, struct td, td_list);
+ urb = td->urb;
+@@ -966,6 +967,17 @@ rescan_this:
+ savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
+ *prev = td->hwNextTD | savebits;
+
++ /* If this was unlinked, the TD may not have been
++ * retired ... so manually save the data toggle.
++ * When this is ISO (no toggle), the value we save
++ * will be ignored by the controller.
++ */
++ tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
++ if ((tdINFO & TD_T) == TD_T_DATA0)
++ ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C);
++ else if ((tdINFO & TD_T) == TD_T_DATA1)
++ ed->hwHeadP |= cpu_to_hc32(ohci, ED_C);
++
+ /* HC may have partly processed this TD */
+ td_done (ohci, urb, td);
+ urb_priv->td_cnt++;
diff --git a/usb/usb-at91_udc-updated-fifo-sizes.patch b/usb/usb-at91_udc-updated-fifo-sizes.patch
new file mode 100644
index 00000000000000..cd1a477417e5ef
--- /dev/null
+++ b/usb/usb-at91_udc-updated-fifo-sizes.patch
@@ -0,0 +1,44 @@
+From david-b@pacbell.net Fri Jun 6 15:06:20 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 27 May 2008 19:24:20 -0700
+Subject: USB: at91_udc: updated fifo sizes
+To: linux-usb@vger.kernel.org
+Cc: Greg KH <greg@kroah.com>, Andrew Victor <linux@maxim.org.za>
+Message-ID: <200805271924.21005.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+From: David Brownell <dbrownell@users.sourceforge.net>
+
+It turns out newer versions of the AT91 UDC hardware have increased
+sizes of some of the FIFOs. Reporting that is a Good Thing.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/at91_udc.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -1687,6 +1687,19 @@ static int __init at91udc_probe(struct p
+ udc->board.pullup_active_low);
+ }
+
++ /* newer chips have more FIFO memory than rm9200 */
++ if (cpu_is_at91sam9260()) {
++ udc->ep[0].maxpacket = 64;
++ udc->ep[3].maxpacket = 64;
++ udc->ep[4].maxpacket = 512;
++ udc->ep[5].maxpacket = 512;
++ } else if (cpu_is_at91sam9261()) {
++ udc->ep[3].maxpacket = 64;
++ } else if (cpu_is_at91sam9263()) {
++ udc->ep[0].maxpacket = 64;
++ udc->ep[3].maxpacket = 64;
++ }
++
+ udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+ if (!udc->udp_baseaddr) {
+ retval = -ENOMEM;
diff --git a/usb/usb-auerwald-push-down-the-bkl-into-the-driver.patch b/usb/usb-auerwald-push-down-the-bkl-into-the-driver.patch
new file mode 100644
index 00000000000000..cd09705f3286dc
--- /dev/null
+++ b/usb/usb-auerwald-push-down-the-bkl-into-the-driver.patch
@@ -0,0 +1,59 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:15:02 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:46:25 +0100
+Subject: USB: auerwald: Push down the BKL into the driver
+To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20080522224625.6fe88245@core>
+
+
+Also fix the unknown ioctl return code
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/auerswald.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/misc/auerswald.c
++++ b/drivers/usb/misc/auerswald.c
+@@ -1421,7 +1421,8 @@ ofail: mutex_unlock(&cp->mutex);
+
+
+ /* IOCTL functions */
+-static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long auerchar_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
+ {
+ pauerchar_t ccp = (pauerchar_t) file->private_data;
+ int ret = 0;
+@@ -1452,7 +1453,7 @@ static int auerchar_ioctl (struct inode
+ mutex_unlock(&ccp->mutex);
+ return -ENODEV;
+ }
+-
++ lock_kernel();
+ switch (cmd) {
+
+ /* return != 0 if Transmitt channel ready to send */
+@@ -1547,9 +1548,10 @@ static int auerchar_ioctl (struct inode
+
+ default:
+ dbg ("IOCTL_AU_UNKNOWN");
+- ret = -ENOIOCTLCMD;
++ ret = -ENOTTY;
+ break;
+ }
++ unlock_kernel();
+ /* release the mutexes */
+ mutex_unlock(&cp->mutex);
+ mutex_unlock(&ccp->mutex);
+@@ -1860,7 +1862,7 @@ static const struct file_operations auer
+ .llseek = no_llseek,
+ .read = auerchar_read,
+ .write = auerchar_write,
+- .ioctl = auerchar_ioctl,
++ .unlocked_ioctl = auerchar_ioctl,
+ .open = auerchar_open,
+ .release = auerchar_release,
+ };
diff --git a/usb/usb-composite-support-16-interfaces-by-default.patch b/usb/usb-composite-support-16-interfaces-by-default.patch
new file mode 100644
index 00000000000000..30070e710c8891
--- /dev/null
+++ b/usb/usb-composite-support-16-interfaces-by-default.patch
@@ -0,0 +1,31 @@
+From felipe.balbi@nokia.com Fri Jun 6 15:12:15 2008
+From: Felipe Balbi <felipe.balbi@nokia.com>
+Date: Thu, 22 May 2008 02:45:11 +0300
+Subject: USB: COMPOSITE: Support 16 interfaces by default
+To: linux-usb@vger.kernel.org
+Cc: David Brownell <dbrownell@sourceforge.users.net>, Felipe Balbi <felipe.balbi@nokia.com>
+Message-ID: <1211413513-1320-2-git-send-email-felipe.balbi@nokia.com>
+
+
+8 interfaces is not enough if we try to use
+3 instances of obex function driver.
+
+Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/usb/composite.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/usb/composite.h
++++ b/include/linux/usb/composite.h
+@@ -147,7 +147,7 @@ ep_choose(struct usb_gadget *g, struct u
+ return fs;
+ }
+
+-#define MAX_CONFIG_INTERFACES 8 /* arbitrary; max 255 */
++#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
+
+ /**
+ * struct usb_configuration - represents one gadget configuration
diff --git a/usb/usb-cp2101.c-fix-sparse-signedness-mismatch-warnings.patch b/usb/usb-cp2101.c-fix-sparse-signedness-mismatch-warnings.patch
new file mode 100644
index 00000000000000..04281707dffc02
--- /dev/null
+++ b/usb/usb-cp2101.c-fix-sparse-signedness-mismatch-warnings.patch
@@ -0,0 +1,128 @@
+From harvey.harrison@gmail.com Fri Jun 6 15:17:09 2008
+From: Harvey Harrison <harvey.harrison@gmail.com>
+Date: Fri, 30 May 2008 10:29:55 -0700
+Subject: USB: cp2101.c fix sparse signedness mismatch warnings
+To: Greg KH <gregkh@suse.de>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Message-ID: <1212168595.28403.198.camel@brick>
+
+
+The get/set 2101_config helpers take an unsigned int rather than an
+int. It is safe to change these in each case and may even produce
+better code as it will be an unsigned divide rather than a signed
+divide in places. All other manipulation was setting/masking bits
+which will not be affected by the sign change.
+
+Fixes the following sparse warnings:
+drivers/usb/serial/cp2101.c:378:44: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:378:44: expected unsigned int *data
+drivers/usb/serial/cp2101.c:378:44: got int *<noident>
+drivers/usb/serial/cp2101.c:388:40: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:388:40: expected unsigned int *data
+drivers/usb/serial/cp2101.c:388:40: got int *<noident>
+drivers/usb/serial/cp2101.c:413:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:413:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:413:42: got int *<noident>
+drivers/usb/serial/cp2101.c:421:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:421:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:421:42: got int *<noident>
+drivers/usb/serial/cp2101.c:444:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:444:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:444:42: got int *<noident>
+drivers/usb/serial/cp2101.c:451:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:451:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:451:42: got int *<noident>
+drivers/usb/serial/cp2101.c:458:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:458:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:458:42: got int *<noident>
+drivers/usb/serial/cp2101.c:471:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:471:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:471:42: got int *<noident>
+drivers/usb/serial/cp2101.c:481:42: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:481:42: expected unsigned int *data
+drivers/usb/serial/cp2101.c:481:42: got int *<noident>
+drivers/usb/serial/cp2101.c:561:41: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:561:41: expected unsigned int *data
+drivers/usb/serial/cp2101.c:561:41: got int *<noident>
+drivers/usb/serial/cp2101.c:591:45: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:591:45: expected unsigned int *data
+drivers/usb/serial/cp2101.c:591:45: got int *<noident>
+drivers/usb/serial/cp2101.c:597:41: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:597:41: expected unsigned int *data
+drivers/usb/serial/cp2101.c:597:41: got int *<noident>
+drivers/usb/serial/cp2101.c:608:45: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:608:45: expected unsigned int *data
+drivers/usb/serial/cp2101.c:608:45: got int *<noident>
+drivers/usb/serial/cp2101.c:614:41: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:614:41: expected unsigned int *data
+drivers/usb/serial/cp2101.c:614:41: got int *<noident>
+drivers/usb/serial/cp2101.c:623:45: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:623:45: expected unsigned int *data
+drivers/usb/serial/cp2101.c:623:45: got int *<noident>
+drivers/usb/serial/cp2101.c:680:50: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:680:50: expected unsigned int *data
+drivers/usb/serial/cp2101.c:680:50: got int *<noident>
+drivers/usb/serial/cp2101.c:690:43: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:690:43: expected unsigned int *data
+drivers/usb/serial/cp2101.c:690:43: got int *<noident>
+drivers/usb/serial/cp2101.c:715:41: warning: incorrect type in argument 3 (different signedness)
+drivers/usb/serial/cp2101.c:715:41: expected unsigned int *data
+drivers/usb/serial/cp2101.c:715:41: got int *<noident>
+
+Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/cp2101.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/serial/cp2101.c
++++ b/drivers/usb/serial/cp2101.c
+@@ -365,8 +365,8 @@ static void cp2101_close (struct usb_ser
+ static void cp2101_get_termios (struct usb_serial_port *port)
+ {
+ unsigned int cflag, modem_ctl[4];
+- int baud;
+- int bits;
++ unsigned int baud;
++ unsigned int bits;
+
+ dbg("%s - port %d", __func__, port->number);
+
+@@ -498,7 +498,7 @@ static void cp2101_set_termios (struct u
+ struct ktermios *old_termios)
+ {
+ unsigned int cflag, old_cflag;
+- int baud=0, bits;
++ unsigned int baud = 0, bits;
+ unsigned int modem_ctl[4];
+
+ dbg("%s - port %d", __func__, port->number);
+@@ -654,7 +654,7 @@ static void cp2101_set_termios (struct u
+ static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+ {
+- int control = 0;
++ unsigned int control = 0;
+
+ dbg("%s - port %d", __func__, port->number);
+
+@@ -683,7 +683,8 @@ static int cp2101_tiocmset (struct usb_s
+
+ static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
+ {
+- int control, result;
++ unsigned int control;
++ int result;
+
+ dbg("%s - port %d", __func__, port->number);
+
+@@ -703,7 +704,7 @@ static int cp2101_tiocmget (struct usb_s
+
+ static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
+ {
+- int state;
++ unsigned int state;
+
+ dbg("%s - port %d", __func__, port->number);
+ if (break_state == 0)
diff --git a/usb/usb-digi_accelport.c-trivial-sparse-lock-annotation.patch b/usb/usb-digi_accelport.c-trivial-sparse-lock-annotation.patch
new file mode 100644
index 00000000000000..7c37e2cfda7a6b
--- /dev/null
+++ b/usb/usb-digi_accelport.c-trivial-sparse-lock-annotation.patch
@@ -0,0 +1,26 @@
+From harvey.harrison@gmail.com Fri Jun 6 15:16:54 2008
+From: Harvey Harrison <harvey.harrison@gmail.com>
+Date: Fri, 30 May 2008 10:18:53 -0700
+Subject: USB: digi_accelport.c trivial sparse lock annotation
+To: Greg KH <gregkh@suse.de>
+Cc: LKML <linux-kernel@vger.kernel.org>, Al Viro <viro@ZenIV.linux.org.uk>
+Message-ID: <1212167934.28403.196.camel@brick>
+
+
+Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/serial/digi_acceleport.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -571,6 +571,7 @@ static struct usb_serial_driver digi_acc
+ static long cond_wait_interruptible_timeout_irqrestore(
+ wait_queue_head_t *q, long timeout,
+ spinlock_t *lock, unsigned long flags)
++__releases(lock)
+ {
+ DEFINE_WAIT(wait);
+
diff --git a/usb/usb-ftdi_usb-eliminate-ioctl-and-bkl-ioctl-use.patch b/usb/usb-ftdi_usb-eliminate-ioctl-and-bkl-ioctl-use.patch
new file mode 100644
index 00000000000000..1cf45ee232bbc9
--- /dev/null
+++ b/usb/usb-ftdi_usb-eliminate-ioctl-and-bkl-ioctl-use.patch
@@ -0,0 +1,57 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:13:59 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:04:48 +0100
+Subject: USB: ftdi_usb: Eliminate ioctl and BKL ioctl use
+To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20080522220448.7d77a7db@core>
+
+
+ftdi has one ioctl, which is buggy and for debugging. Kill it off
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/ftdi-elan.c | 24 ------------------------
+ 1 file changed, 24 deletions(-)
+
+--- a/drivers/usb/misc/ftdi-elan.c
++++ b/drivers/usb/misc/ftdi-elan.c
+@@ -656,29 +656,6 @@ static int ftdi_elan_release(struct inod
+ }
+
+
+-#define FTDI_ELAN_IOC_MAGIC 0xA1
+-#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)
+-static int ftdi_elan_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- switch (cmd) {
+- case FTDI_ELAN_IOCDEBUG:{
+- char line[132];
+- int size = strncpy_from_user(line,
+- (const char __user *)arg, sizeof(line));
+- if (size < 0) {
+- return -EINVAL;
+- } else {
+- printk(KERN_ERR "TODO: ioctl %s\n", line);
+- return 0;
+- }
+- }
+- default:
+- return -EFAULT;
+- }
+-}
+-
+-
+ /*
+ *
+ * blocking bulk reads are used to get data from the device
+@@ -1222,7 +1199,6 @@ error_1:
+ static const struct file_operations ftdi_elan_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+- .ioctl = ftdi_elan_ioctl,
+ .read = ftdi_elan_read,
+ .write = ftdi_elan_write,
+ .open = ftdi_elan_open,
diff --git a/usb/usb-gadget-composite-gadget-framework.patch b/usb/usb-gadget-composite-gadget-framework.patch
new file mode 100644
index 00000000000000..51a992806b9803
--- /dev/null
+++ b/usb/usb-gadget-composite-gadget-framework.patch
@@ -0,0 +1,1477 @@
+From david-b@pacbell.net Fri Jun 6 15:10:24 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:04:46 -0700
+Subject: usb gadget: composite gadget framework
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201104.46710.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+Add <linux/usb/composite.h> interfaces for composite gadget drivers, and
+basic implementation support behind it:
+
+ - struct usb_function ... groups one or more interfaces into a function
+ managed as one unit within a configuration, to which it's added by
+ usb_add_function().
+
+ - struct usb_configuration ... groups one or more such functions into
+ a configuration managed as one unit by a driver, to which it's added
+ by usb_add_config(). These operate at either high or full/low speeds
+ and at a given bMaxPower.
+
+ - struct usb_composite_driver ... groups one or more such configurations
+ into a gadget driver, which may be registered or unregistered.
+
+ - struct usb_composite_dev ... a usb_composite_driver manages this; it
+ wraps the usb_gadget exposed by the controller driver.
+
+This also includes some basic kerneldoc.
+
+How to use it (the short version): provide a usb_composite_driver with a
+bind() that calls usb_add_config() for each of the needed configurations.
+The configurations in turn have bind() calls, which will usb_add_function()
+for each function required. Each function's bind() allocates resources
+needed to perform its tasks, like endpoints; sometimes configurations will
+allocate resources too.
+
+Separate patches will convert most gadget drivers to this infrastructure.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/gadget.tmpl | 35 +
+ drivers/usb/gadget/composite.c | 1041 ++++++++++++++++++++++++++++++++++++++
+ include/linux/usb/composite.h | 338 ++++++++++++
+ 3 files changed, 1414 insertions(+)
+
+--- a/Documentation/DocBook/gadget.tmpl
++++ b/Documentation/DocBook/gadget.tmpl
+@@ -524,6 +524,41 @@ These utilities include endpoint autocon
+ <!-- !Edrivers/usb/gadget/epautoconf.c -->
+ </sect1>
+
++<sect1 id="composite"><title>Composite Device Framework</title>
++
++<para>The core API is sufficient for writing drivers for composite
++USB devices (with more than one function in a given configuration),
++and also multi-configuration devices (also more than one function,
++but not necessarily sharing a given configuration).
++There is however an optional framework which makes it easier to
++reuse and combine functions.
++</para>
++
++<para>Devices using this framework provide a <emphasis>struct
++usb_composite_driver</emphasis>, which in turn provides one or
++more <emphasis>struct usb_configuration</emphasis> instances.
++Each such configuration includes at least one
++<emphasis>struct usb_function</emphasis>, which packages a user
++visible role such as "network link" or "mass storage device".
++Management functions may also exist, such as "Device Firmware
++Upgrade".
++</para>
++
++!Iinclude/linux/usb/composite.h
++!Edrivers/usb/gadget/composite.c
++
++</sect1>
++
++<sect1 id="functions"><title>Composite Device Functions</title>
++
++<para>At this writing, a few of the current gadget drivers have
++been converted to this framework.
++Near-term plans include converting all of them, except for "gadgetfs".
++</para>
++
++</sect1>
++
++
+ </chapter>
+
+ <chapter id="controllers"><title>Peripheral Controller Drivers</title>
+--- /dev/null
++++ b/drivers/usb/gadget/composite.c
+@@ -0,0 +1,1041 @@
++/*
++ * composite.c - infrastructure for Composite USB Gadgets
++ *
++ * Copyright (C) 2006-2008 David Brownell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kallsyms.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++
++#include <linux/usb/composite.h>
++
++
++/*
++ * The code in this file is utility code, used to build a gadget driver
++ * from one or more "function" drivers, one or more "configuration"
++ * objects, and a "usb_composite_driver" by gluing them together along
++ * with the relevant device-wide data.
++ */
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ 512
++
++static struct usb_composite_driver *composite;
++
++/* Some systems will need runtime overrides for the product identifers
++ * published in the device descriptor, either numbers or strings or both.
++ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
++ */
++
++static ushort idVendor;
++module_param(idVendor, ushort, 0);
++MODULE_PARM_DESC(idVendor, "USB Vendor ID");
++
++static ushort idProduct;
++module_param(idProduct, ushort, 0);
++MODULE_PARM_DESC(idProduct, "USB Product ID");
++
++static ushort bcdDevice;
++module_param(bcdDevice, ushort, 0);
++MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
++
++static char *iManufacturer;
++module_param(iManufacturer, charp, 0);
++MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
++
++static char *iProduct;
++module_param(iProduct, charp, 0);
++MODULE_PARM_DESC(iProduct, "USB Product string");
++
++static char *iSerialNumber;
++module_param(iSerialNumber, charp, 0);
++MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
++
++/*-------------------------------------------------------------------------*/
++
++/**
++ * usb_add_function() - add a function to a configuration
++ * @config: the configuration
++ * @function: the function being added
++ * Context: single threaded during gadget setup
++ *
++ * After initialization, each configuration must have one or more
++ * functions added to it. Adding a function involves calling its @bind()
++ * method to allocate resources such as interface and string identifiers
++ * and endpoints.
++ *
++ * This function returns the value of the function's bind(), which is
++ * zero for success else a negative errno value.
++ */
++int __init usb_add_function(struct usb_configuration *config,
++ struct usb_function *function)
++{
++ int value = -EINVAL;
++
++ 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;
++
++ function->config = config;
++ list_add_tail(&function->list, &config->functions);
++
++ /* REVISIT *require* function->bind? */
++ if (function->bind) {
++ value = function->bind(config, function);
++ if (value < 0) {
++ list_del(&function->list);
++ function->config = NULL;
++ }
++ } else
++ value = 0;
++
++ /* We allow configurations that don't work at both speeds.
++ * If we run into a lowspeed Linux system, treat it the same
++ * as full speed ... it's the function drivers that will need
++ * to avoid bulk and ISO transfers.
++ */
++ if (!config->fullspeed && function->descriptors)
++ config->fullspeed = true;
++ if (!config->highspeed && function->hs_descriptors)
++ config->highspeed = true;
++
++done:
++ if (value)
++ DBG(config->cdev, "adding '%s'/%p --> %d\n",
++ function->name, function, value);
++ return value;
++}
++
++/**
++ * usb_interface_id() - allocate an unused interface ID
++ * @config: configuration associated with the interface
++ * @function: function handling the interface
++ * Context: single threaded during gadget setup
++ *
++ * usb_interface_id() is called from usb_function.bind() callbacks to
++ * allocate new interface IDs. The function driver will then store that
++ * ID in interface, association, CDC union, and other descriptors. It
++ * will also handle any control requests targetted at that interface,
++ * particularly changing its altsetting via set_alt(). There may
++ * also be class-specific or vendor-specific requests to handle.
++ *
++ * All interface identifier should be allocated using this routine, to
++ * ensure that for example different functions don't wrongly assign
++ * different meanings to the same identifier. Note that since interface
++ * identifers are configuration-specific, functions used in more than
++ * one configuration (or more than once in a given configuration) need
++ * multiple versions of the relevant descriptors.
++ *
++ * Returns the interface ID which was allocated; or -ENODEV if no
++ * more interface IDs can be allocated.
++ */
++int __init usb_interface_id(struct usb_configuration *config,
++ struct usb_function *function)
++{
++ unsigned id = config->next_interface_id;
++
++ if (id < MAX_CONFIG_INTERFACES) {
++ config->interface[id] = function;
++ config->next_interface_id = id + 1;
++ return id;
++ }
++ return -ENODEV;
++}
++
++static int config_buf(struct usb_configuration *config,
++ enum usb_device_speed speed, void *buf, u8 type)
++{
++ struct usb_config_descriptor *c = buf;
++ void *next = buf + USB_DT_CONFIG_SIZE;
++ int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
++ struct usb_function *f;
++ int status;
++
++ /* write the config descriptor */
++ c = buf;
++ c->bLength = USB_DT_CONFIG_SIZE;
++ c->bDescriptorType = type;
++ /* 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;
++ c->bMaxPower = config->bMaxPower;
++
++ /* There may be e.g. OTG descriptors */
++ if (config->descriptors) {
++ status = usb_descriptor_fillbuf(next, len,
++ config->descriptors);
++ if (status < 0)
++ return status;
++ len -= status;
++ next += status;
++ }
++
++ /* add each function's descriptors */
++ list_for_each_entry(f, &config->functions, list) {
++ struct usb_descriptor_header **descriptors;
++
++ if (speed == USB_SPEED_HIGH)
++ descriptors = f->hs_descriptors;
++ else
++ descriptors = f->descriptors;
++ if (!descriptors)
++ continue;
++ status = usb_descriptor_fillbuf(next, len,
++ (const struct usb_descriptor_header **) descriptors);
++ if (status < 0)
++ return status;
++ len -= status;
++ next += status;
++ }
++
++ len = next - buf;
++ c->wTotalLength = cpu_to_le16(len);
++ return len;
++}
++
++static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c;
++ u8 type = w_value >> 8;
++ enum usb_device_speed speed = USB_SPEED_UNKNOWN;
++
++ if (gadget_is_dualspeed(gadget)) {
++ int hs = 0;
++
++ if (gadget->speed == USB_SPEED_HIGH)
++ hs = 1;
++ if (type == USB_DT_OTHER_SPEED_CONFIG)
++ hs = !hs;
++ if (hs)
++ speed = USB_SPEED_HIGH;
++
++ }
++
++ /* This is a lookup by config *INDEX* */
++ w_value &= 0xff;
++ list_for_each_entry(c, &cdev->configs, list) {
++ /* ignore configs that won't work at this speed */
++ if (speed == USB_SPEED_HIGH) {
++ if (!c->highspeed)
++ continue;
++ } else {
++ if (!c->fullspeed)
++ continue;
++ }
++ if (w_value == 0)
++ return config_buf(c, speed, cdev->req->buf, type);
++ w_value--;
++ }
++ return -EINVAL;
++}
++
++static int count_configs(struct usb_composite_dev *cdev, unsigned type)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c;
++ unsigned count = 0;
++ int hs = 0;
++
++ if (gadget_is_dualspeed(gadget)) {
++ if (gadget->speed == USB_SPEED_HIGH)
++ hs = 1;
++ if (type == USB_DT_DEVICE_QUALIFIER)
++ hs = !hs;
++ }
++ list_for_each_entry(c, &cdev->configs, list) {
++ /* ignore configs that won't work at this speed */
++ if (hs) {
++ if (!c->highspeed)
++ continue;
++ } else {
++ if (!c->fullspeed)
++ continue;
++ }
++ count++;
++ }
++ return count;
++}
++
++static void device_qual(struct usb_composite_dev *cdev)
++{
++ struct usb_qualifier_descriptor *qual = cdev->req->buf;
++
++ qual->bLength = sizeof(*qual);
++ qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
++ /* POLICY: same bcdUSB and device type info at both speeds */
++ qual->bcdUSB = cdev->desc.bcdUSB;
++ qual->bDeviceClass = cdev->desc.bDeviceClass;
++ qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
++ qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
++ /* ASSUME same EP0 fifo size at both speeds */
++ qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
++ qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void reset_config(struct usb_composite_dev *cdev)
++{
++ struct usb_function *f;
++
++ DBG(cdev, "reset config\n");
++
++ list_for_each_entry(f, &cdev->config->functions, list) {
++ if (f->disable)
++ f->disable(f);
++ }
++ cdev->config = NULL;
++}
++
++static int set_config(struct usb_composite_dev *cdev,
++ const struct usb_ctrlrequest *ctrl, unsigned number)
++{
++ struct usb_gadget *gadget = cdev->gadget;
++ struct usb_configuration *c = NULL;
++ int result = -EINVAL;
++ unsigned power = gadget_is_otg(gadget) ? 8 : 100;
++ int tmp;
++
++ if (cdev->config)
++ reset_config(cdev);
++
++ if (number) {
++ list_for_each_entry(c, &cdev->configs, list) {
++ if (c->bConfigurationValue == number) {
++ result = 0;
++ break;
++ }
++ }
++ if (result < 0)
++ goto done;
++ } else
++ result = 0;
++
++ INFO(cdev, "%s speed config #%d: %s\n",
++ ({ char *speed;
++ switch (gadget->speed) {
++ case USB_SPEED_LOW: speed = "low"; break;
++ case USB_SPEED_FULL: speed = "full"; break;
++ case USB_SPEED_HIGH: speed = "high"; break;
++ default: speed = "?"; break;
++ } ; speed; }), number, c ? c->label : "");
++
++ if (!c)
++ goto done;
++
++ cdev->config = c;
++
++ /* Initialize all interfaces by setting them to altsetting zero. */
++ for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
++ struct usb_function *f = c->interface[tmp];
++
++ if (!f)
++ break;
++
++ result = f->set_alt(f, tmp, 0);
++ if (result < 0) {
++ DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
++ tmp, f->name, f, result);
++
++ reset_config(cdev);
++ goto done;
++ }
++ }
++
++ /* when we return, be sure our power usage is valid */
++ power = 2 * c->bMaxPower;
++done:
++ usb_gadget_vbus_draw(gadget, power);
++ return result;
++}
++
++/**
++ * usb_add_config() - add a configuration to a device.
++ * @cdev: wraps the USB gadget
++ * @config: the configuration, with bConfigurationValue assigned
++ * Context: single threaded during gadget setup
++ *
++ * One of the main tasks of a composite driver's bind() routine is to
++ * add each of the configurations it supports, using this routine.
++ *
++ * This function returns the value of the configuration's bind(), which
++ * is zero for success else a negative errno value. Binding configurations
++ * assigns global resources including string IDs, and per-configuration
++ * resources such as interface IDs and endpoints.
++ */
++int __init usb_add_config(struct usb_composite_dev *cdev,
++ struct usb_configuration *config)
++{
++ int status = -EINVAL;
++ struct usb_configuration *c;
++
++ DBG(cdev, "adding config #%u '%s'/%p\n",
++ config->bConfigurationValue,
++ config->label, config);
++
++ if (!config->bConfigurationValue || !config->bind)
++ goto done;
++
++ /* Prevent duplicate configuration identifiers */
++ list_for_each_entry(c, &cdev->configs, list) {
++ if (c->bConfigurationValue == config->bConfigurationValue) {
++ status = -EBUSY;
++ goto done;
++ }
++ }
++
++ config->cdev = cdev;
++ list_add_tail(&config->list, &cdev->configs);
++
++ INIT_LIST_HEAD(&config->functions);
++ config->next_interface_id = 0;
++
++ status = config->bind(config);
++ if (status < 0) {
++ list_del(&config->list);
++ config->cdev = NULL;
++ } else {
++ unsigned i;
++
++ DBG(cdev, "cfg %d/%p speeds:%s%s\n",
++ config->bConfigurationValue, config,
++ config->highspeed ? " high" : "",
++ config->fullspeed
++ ? (gadget_is_dualspeed(cdev->gadget)
++ ? " full"
++ : " full/low")
++ : "");
++
++ for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
++ struct usb_function *f = config->interface[i];
++
++ if (!f)
++ continue;
++ DBG(cdev, " interface %d = %s/%p\n",
++ i, f->name, f);
++ }
++ }
++
++ /* set_alt(), or next config->bind(), sets up
++ * ep->driver_data as needed.
++ */
++ usb_ep_autoconfig_reset(cdev->gadget);
++
++done:
++ if (status)
++ DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
++ config->bConfigurationValue, status);
++ return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* We support strings in multiple languages ... string descriptor zero
++ * says which languages are supported. The typical case will be that
++ * only one language (probably English) is used, with I18N handled on
++ * the host side.
++ */
++
++static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
++{
++ const struct usb_gadget_strings *s;
++ u16 language;
++ __le16 *tmp;
++
++ while (*sp) {
++ s = *sp;
++ language = cpu_to_le16(s->language);
++ for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) {
++ if (*tmp == language)
++ goto repeat;
++ }
++ *tmp++ = language;
++repeat:
++ sp++;
++ }
++}
++
++static int lookup_string(
++ struct usb_gadget_strings **sp,
++ void *buf,
++ u16 language,
++ int id
++)
++{
++ struct usb_gadget_strings *s;
++ int value;
++
++ while (*sp) {
++ s = *sp++;
++ if (s->language != language)
++ continue;
++ value = usb_gadget_get_string(s, id, buf);
++ if (value > 0)
++ return value;
++ }
++ return -EINVAL;
++}
++
++static int get_string(struct usb_composite_dev *cdev,
++ void *buf, u16 language, int id)
++{
++ struct usb_configuration *c;
++ struct usb_function *f;
++ int len;
++
++ /* Yes, not only is USB's I18N support probably more than most
++ * folk will ever care about ... also, it's all supported here.
++ * (Except for UTF8 support for Unicode's "Astral Planes".)
++ */
++
++ /* 0 == report all available language codes */
++ if (id == 0) {
++ struct usb_string_descriptor *s = buf;
++ struct usb_gadget_strings **sp;
++
++ memset(s, 0, 256);
++ s->bDescriptorType = USB_DT_STRING;
++
++ sp = composite->strings;
++ if (sp)
++ collect_langs(sp, s->wData);
++
++ list_for_each_entry(c, &cdev->configs, list) {
++ sp = c->strings;
++ if (sp)
++ collect_langs(sp, s->wData);
++
++ list_for_each_entry(f, &c->functions, list) {
++ sp = f->strings;
++ if (sp)
++ collect_langs(sp, s->wData);
++ }
++ }
++
++ for (len = 0; s->wData[len] && len <= 126; len++)
++ continue;
++ if (!len)
++ return -EINVAL;
++
++ s->bLength = 2 * (len + 1);
++ return s->bLength;
++ }
++
++ /* Otherwise, look up and return a specified string. String IDs
++ * are device-scoped, so we look up each string table we're told
++ * about. These lookups are infrequent; simpler-is-better here.
++ */
++ if (composite->strings) {
++ len = lookup_string(composite->strings, buf, language, id);
++ if (len > 0)
++ return len;
++ }
++ list_for_each_entry(c, &cdev->configs, list) {
++ if (c->strings) {
++ len = lookup_string(c->strings, buf, language, id);
++ if (len > 0)
++ return len;
++ }
++ list_for_each_entry(f, &c->functions, list) {
++ if (!f->strings)
++ continue;
++ len = lookup_string(f->strings, buf, language, id);
++ if (len > 0)
++ return len;
++ }
++ }
++ return -EINVAL;
++}
++
++/**
++ * usb_string_id() - allocate an unused string ID
++ * @cdev: the device whose string descriptor IDs are being allocated
++ * Context: single threaded during gadget setup
++ *
++ * @usb_string_id() is called from bind() callbacks to allocate
++ * string IDs. Drivers for functions, configurations, or gadgets will
++ * then store that ID in the appropriate descriptors and string table.
++ *
++ * All string identifier should be allocated using this routine, to
++ * ensure that for example different functions don't wrongly assign
++ * different meanings to the same identifier.
++ */
++int __init usb_string_id(struct usb_composite_dev *cdev)
++{
++ if (cdev->next_string_id < 254) {
++ /* string id 0 is reserved */
++ cdev->next_string_id++;
++ return cdev->next_string_id;
++ }
++ return -ENODEV;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ if (req->status || req->actual != req->length)
++ DBG((struct usb_composite_dev *) ep->driver_data,
++ "setup complete --> %d, %d/%d\n",
++ req->status, req->actual, req->length);
++}
++
++/*
++ * The setup() callback implements all the ep0 functionality that's
++ * not handled lower down, in hardware or the hardware driver(like
++ * device and endpoint feature flags, and their status). It's all
++ * housekeeping for the gadget function we're implementing. Most of
++ * the work is in config and function specific setup.
++ */
++static int
++composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_composite_dev *cdev = get_gadget_data(gadget);
++ struct usb_request *req = cdev->req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++ struct usb_function *f = NULL;
++
++ /* partial re-init of the response message; the function or the
++ * gadget might need to intercept e.g. a control-OUT completion
++ * when we delegate to it.
++ */
++ req->zero = 0;
++ req->complete = composite_setup_complete;
++ req->length = USB_BUFSIZ;
++ gadget->ep0->driver_data = cdev;
++
++ switch (ctrl->bRequest) {
++
++ /* we handle all standard USB descriptors */
++ case USB_REQ_GET_DESCRIPTOR:
++ if (ctrl->bRequestType != USB_DIR_IN)
++ goto unknown;
++ switch (w_value >> 8) {
++
++ case USB_DT_DEVICE:
++ cdev->desc.bNumConfigurations =
++ count_configs(cdev, USB_DT_DEVICE);
++ value = min(w_length, (u16) sizeof cdev->desc);
++ memcpy(req->buf, &cdev->desc, value);
++ break;
++ case USB_DT_DEVICE_QUALIFIER:
++ if (!gadget_is_dualspeed(gadget))
++ break;
++ device_qual(cdev);
++ value = min_t(int, w_length,
++ sizeof(struct usb_qualifier_descriptor));
++ break;
++ case USB_DT_OTHER_SPEED_CONFIG:
++ if (!gadget_is_dualspeed(gadget))
++ break;
++ /* FALLTHROUGH */
++ case USB_DT_CONFIG:
++ value = config_desc(cdev, w_value);
++ if (value >= 0)
++ value = min(w_length, (u16) value);
++ break;
++ case USB_DT_STRING:
++ value = get_string(cdev, req->buf,
++ w_index, w_value & 0xff);
++ if (value >= 0)
++ value = min(w_length, (u16) value);
++ break;
++ }
++ break;
++
++ /* any number of configs can work */
++ case USB_REQ_SET_CONFIGURATION:
++ if (ctrl->bRequestType != 0)
++ goto unknown;
++ if (gadget_is_otg(gadget)) {
++ if (gadget->a_hnp_support)
++ DBG(cdev, "HNP available\n");
++ else if (gadget->a_alt_hnp_support)
++ DBG(cdev, "HNP on another port\n");
++ else
++ VDBG(cdev, "HNP inactive\n");
++ }
++ spin_lock(&cdev->lock);
++ value = set_config(cdev, ctrl, w_value);
++ spin_unlock(&cdev->lock);
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ if (ctrl->bRequestType != USB_DIR_IN)
++ goto unknown;
++ if (cdev->config)
++ *(u8 *)req->buf = cdev->config->bConfigurationValue;
++ else
++ *(u8 *)req->buf = 0;
++ value = min(w_length, (u16) 1);
++ break;
++
++ /* function drivers must handle get/set altsetting; if there's
++ * no get() method, we know only altsetting zero works.
++ */
++ case USB_REQ_SET_INTERFACE:
++ if (ctrl->bRequestType != USB_RECIP_INTERFACE)
++ goto unknown;
++ if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
++ break;
++ f = cdev->config->interface[w_index];
++ if (!f)
++ break;
++ if (w_value && !f->get_alt)
++ break;
++ value = f->set_alt(f, w_index, w_value);
++ break;
++ case USB_REQ_GET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
++ goto unknown;
++ if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
++ break;
++ f = cdev->config->interface[w_index];
++ if (!f)
++ break;
++ /* lots of interfaces only need altsetting zero... */
++ value = f->get_alt ? f->get_alt(f, w_index) : 0;
++ if (value < 0)
++ break;
++ *((u8 *)req->buf) = value;
++ value = min(w_length, (u16) 1);
++ break;
++ default:
++unknown:
++ VDBG(cdev,
++ "non-core control req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++
++ /* functions always handle their interfaces ... punt other
++ * recipients (endpoint, other, WUSB, ...) to the current
++ * configuration code.
++ *
++ * REVISIT it could make sense to let the composite device
++ * take such requests too, if that's ever needed: to work
++ * in config 0, etc.
++ */
++ if ((ctrl->bRequestType & USB_RECIP_MASK)
++ == USB_RECIP_INTERFACE) {
++ f = cdev->config->interface[w_index];
++ if (f && f->setup)
++ value = f->setup(f, ctrl);
++ else
++ f = NULL;
++ }
++ if (value < 0 && !f) {
++ struct usb_configuration *c;
++
++ c = cdev->config;
++ if (c && c->setup)
++ value = c->setup(c, ctrl);
++ }
++
++ goto done;
++ }
++
++ /* respond with data transfer before status phase? */
++ if (value >= 0) {
++ req->length = value;
++ req->zero = value < w_length;
++ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
++ if (value < 0) {
++ DBG(cdev, "ep_queue --> %d\n", value);
++ req->status = 0;
++ composite_setup_complete(gadget->ep0, req);
++ }
++ }
++
++done:
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static void composite_disconnect(struct usb_gadget *gadget)
++{
++ struct usb_composite_dev *cdev = get_gadget_data(gadget);
++ unsigned long flags;
++
++ /* REVISIT: should we have config and device level
++ * disconnect callbacks?
++ */
++ spin_lock_irqsave(&cdev->lock, flags);
++ if (cdev->config)
++ reset_config(cdev);
++ spin_unlock_irqrestore(&cdev->lock, flags);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void /* __init_or_exit */
++composite_unbind(struct usb_gadget *gadget)
++{
++ struct usb_composite_dev *cdev = get_gadget_data(gadget);
++ unsigned long flags;
++
++ /* composite_disconnect() must already have been called
++ * by the underlying peripheral controller driver!
++ */
++ WARN_ON(cdev->config);
++
++ spin_lock_irqsave(&cdev->lock, flags);
++ while (!list_empty(&cdev->configs)) {
++ struct usb_configuration *c;
++
++ c = list_first_entry(&cdev->configs,
++ struct usb_configuration, list);
++ while (!list_empty(&c->functions)) {
++ struct usb_function *f;
++
++ f = list_first_entry(&c->functions,
++ struct usb_function, list);
++ list_del(&f->list);
++ if (f->unbind) {
++ DBG(cdev, "unbind function '%s'/%p\n",
++ f->name, f);
++ f->unbind(c, f);
++ /* may free memory for "f" */
++ }
++ }
++ list_del(&c->list);
++ if (c->unbind) {
++ DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
++ c->unbind(c);
++ /* may free memory for "c" */
++ }
++ }
++ if (composite->unbind)
++ composite->unbind(cdev);
++ spin_unlock_irqrestore(&cdev->lock, flags);
++
++ if (cdev->req) {
++ kfree(cdev->req->buf);
++ usb_ep_free_request(gadget->ep0, cdev->req);
++ }
++ kfree(cdev);
++ set_gadget_data(gadget, NULL);
++ composite = NULL;
++}
++
++static void __init
++string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
++{
++ struct usb_string *str = tab->strings;
++
++ for (str = tab->strings; str->s; str++) {
++ if (str->id == id) {
++ str->s = s;
++ return;
++ }
++ }
++}
++
++static void __init
++string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
++{
++ while (*tab) {
++ string_override_one(*tab, id, s);
++ tab++;
++ }
++}
++
++static int __init composite_bind(struct usb_gadget *gadget)
++{
++ struct usb_composite_dev *cdev;
++ int status = -ENOMEM;
++
++ cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
++ if (!cdev)
++ return status;
++
++ spin_lock_init(&cdev->lock);
++ cdev->gadget = gadget;
++ set_gadget_data(gadget, cdev);
++ INIT_LIST_HEAD(&cdev->configs);
++
++ /* preallocate control response and buffer */
++ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
++ if (!cdev->req)
++ goto fail;
++ cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
++ if (!cdev->req->buf)
++ goto fail;
++ cdev->req->complete = composite_setup_complete;
++ gadget->ep0->driver_data = cdev;
++
++ cdev->bufsiz = USB_BUFSIZ;
++ cdev->driver = composite;
++
++ usb_gadget_set_selfpowered(gadget);
++
++ /* interface and string IDs start at zero via kzalloc.
++ * we force endpoints to start unassigned; few controller
++ * drivers will zero ep->driver_data.
++ */
++ usb_ep_autoconfig_reset(cdev->gadget);
++
++ /* composite gadget needs to assign strings for whole device (like
++ * serial number), register function drivers, potentially update
++ * power state and consumption, etc
++ */
++ status = composite->bind(cdev);
++ if (status < 0)
++ goto fail;
++
++ cdev->desc = *composite->dev;
++ cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++
++ /* standardized runtime overrides for device ID data */
++ if (idVendor)
++ cdev->desc.idVendor = cpu_to_le16(idVendor);
++ if (idProduct)
++ cdev->desc.idProduct = cpu_to_le16(idProduct);
++ if (bcdDevice)
++ cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
++
++ /* strings can't be assigned before bind() allocates the
++ * releavnt identifiers
++ */
++ if (cdev->desc.iManufacturer && iManufacturer)
++ string_override(composite->strings,
++ cdev->desc.iManufacturer, iManufacturer);
++ if (cdev->desc.iProduct && iProduct)
++ string_override(composite->strings,
++ cdev->desc.iProduct, iProduct);
++ if (cdev->desc.iSerialNumber && iSerialNumber)
++ string_override(composite->strings,
++ cdev->desc.iSerialNumber, iSerialNumber);
++
++ INFO(cdev, "%s ready\n", composite->name);
++ return 0;
++
++fail:
++ composite_unbind(gadget);
++ return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++composite_suspend(struct usb_gadget *gadget)
++{
++ struct usb_composite_dev *cdev = get_gadget_data(gadget);
++ struct usb_function *f;
++
++ /* REVISIT: should we have config and device level
++ * suspend/resume callbacks?
++ */
++ DBG(cdev, "suspend\n");
++ if (cdev->config) {
++ list_for_each_entry(f, &cdev->config->functions, list) {
++ if (f->suspend)
++ f->suspend(f);
++ }
++ }
++}
++
++static void
++composite_resume(struct usb_gadget *gadget)
++{
++ struct usb_composite_dev *cdev = get_gadget_data(gadget);
++ struct usb_function *f;
++
++ /* REVISIT: should we have config and device level
++ * suspend/resume callbacks?
++ */
++ DBG(cdev, "resume\n");
++ if (cdev->config) {
++ list_for_each_entry(f, &cdev->config->functions, list) {
++ if (f->resume)
++ f->resume(f);
++ }
++ }
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver composite_driver = {
++ .speed = USB_SPEED_HIGH,
++
++ .bind = composite_bind,
++ .unbind = __exit_p(composite_unbind),
++
++ .setup = composite_setup,
++ .disconnect = composite_disconnect,
++
++ .suspend = composite_suspend,
++ .resume = composite_resume,
++
++ .driver = {
++ .owner = THIS_MODULE,
++ },
++};
++
++/**
++ * usb_composite_register() - register a composite driver
++ * @driver: the driver to register
++ * Context: single threaded during gadget setup
++ *
++ * This function is used to register drivers using the composite driver
++ * framework. The return value is zero, or a negative errno value.
++ * Those values normally come from the driver's @bind method, which does
++ * all the work of setting up the driver to match the hardware.
++ *
++ * On successful return, the gadget is ready to respond to requests from
++ * the host, unless one of its components invokes usb_gadget_disconnect()
++ * while it was binding. That would usually be done in order to wait for
++ * some userspace participation.
++ */
++int __init usb_composite_register(struct usb_composite_driver *driver)
++{
++ if (!driver || !driver->dev || !driver->bind || composite)
++ return -EINVAL;
++
++ if (!driver->name)
++ driver->name = "composite";
++ composite_driver.function = (char *) driver->name;
++ composite_driver.driver.name = driver->name;
++ composite = driver;
++
++ return usb_gadget_register_driver(&composite_driver);
++}
++
++/**
++ * usb_composite_unregister() - unregister a composite driver
++ * @driver: the driver to unregister
++ *
++ * This function is used to unregister drivers using the composite
++ * driver framework.
++ */
++void __exit usb_composite_unregister(struct usb_composite_driver *driver)
++{
++ if (composite != driver)
++ return;
++ usb_gadget_unregister_driver(&composite_driver);
++}
+--- /dev/null
++++ b/include/linux/usb/composite.h
+@@ -0,0 +1,338 @@
++/*
++ * composite.h -- framework for usb gadgets which are composite devices
++ *
++ * Copyright (C) 2006-2008 David Brownell
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef __LINUX_USB_COMPOSITE_H
++#define __LINUX_USB_COMPOSITE_H
++
++/*
++ * This framework is an optional layer on top of the USB Gadget interface,
++ * making it easier to build (a) Composite devices, supporting multiple
++ * functions within any single configuration, and (b) Multi-configuration
++ * devices, also supporting multiple functions but without necessarily
++ * having more than one function per configuration.
++ *
++ * Example: a device with a single configuration supporting both network
++ * link and mass storage functions is a composite device. Those functions
++ * might alternatively be packaged in individual configurations, but in
++ * the composite model the host can use both functions at the same time.
++ */
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++
++struct usb_configuration;
++
++/**
++ * struct usb_function - describes one function of a configuration
++ * @name: For diagnostics, identifies the function.
++ * @strings: tables of strings, keyed by identifiers assigned during bind()
++ * and by language IDs provided in control requests
++ * @descriptors: Table of full (or low) speed descriptors, using interface and
++ * string identifiers assigned during @bind(). If this pointer is null,
++ * the function will not be available at full speed (or at low speed).
++ * @hs_descriptors: Table of high speed descriptors, using interface and
++ * string identifiers assigned during @bind(). If this pointer is null,
++ * the function will not be available at high speed.
++ * @config: assigned when @usb_add_function() is called; this is the
++ * configuration with which this function is associated.
++ * @bind: Before the gadget can register, all of its functions bind() to the
++ * available resources including string and interface identifiers used
++ * in interface or class descriptors; endpoints; I/O buffers; and so on.
++ * @unbind: Reverses @bind; called as a side effect of unregistering the
++ * driver which added this function.
++ * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
++ * initialize usb_ep.driver data at this time (when it is used).
++ * Note that setting an interface to its current altsetting resets
++ * interface state, and that all interfaces have a disabled state.
++ * @get_alt: Returns the active altsetting. If this is not provided,
++ * then only altsetting zero is supported.
++ * @disable: (REQUIRED) Indicates the function should be disabled. Reasons
++ * include host resetting or reconfiguring the gadget, and disconnection.
++ * @setup: Used for interface-specific control requests.
++ * @suspend: Notifies functions when the host stops sending USB traffic.
++ * @resume: Notifies functions when the host restarts USB traffic.
++ *
++ * A single USB function uses one or more interfaces, and should in most
++ * cases support operation at both full and high speeds. Each function is
++ * associated by @usb_add_function() with a one configuration; that function
++ * causes @bind() to be called so resources can be allocated as part of
++ * setting up a gadget driver. Those resources include endpoints, which
++ * should be allocated using @usb_ep_autoconfig().
++ *
++ * To support dual speed operation, a function driver provides descriptors
++ * for both high and full speed operation. Except in rare cases that don't
++ * involve bulk endpoints, each speed needs different endpoint descriptors.
++ *
++ * Function drivers choose their own strategies for managing instance data.
++ * The simplest strategy just declares it "static', which means the function
++ * can only be activated once. If the function needs to be exposed in more
++ * than one configuration at a given speed, it needs to support multiple
++ * usb_function structures (one for each configuration).
++ *
++ * A more complex strategy might encapsulate a @usb_function structure inside
++ * a driver-specific instance structure to allows multiple activations. An
++ * example of multiple activations might be a CDC ACM function that supports
++ * two or more distinct instances within the same configuration, providing
++ * several independent logical data links to a USB host.
++ */
++struct usb_function {
++ const char *name;
++ struct usb_gadget_strings **strings;
++ struct usb_descriptor_header **descriptors;
++ struct usb_descriptor_header **hs_descriptors;
++
++ struct usb_configuration *config;
++
++ /* REVISIT: bind() functions can be marked __init, which
++ * makes trouble for section mismatch analysis. See if
++ * we can't restructure things to avoid mismatching.
++ * Related: unbind() may kfree() but bind() won't...
++ */
++
++ /* configuration management: bind/unbind */
++ int (*bind)(struct usb_configuration *,
++ struct usb_function *);
++ void (*unbind)(struct usb_configuration *,
++ struct usb_function *);
++
++ /* runtime state management */
++ int (*set_alt)(struct usb_function *,
++ unsigned interface, unsigned alt);
++ int (*get_alt)(struct usb_function *,
++ unsigned interface);
++ void (*disable)(struct usb_function *);
++ int (*setup)(struct usb_function *,
++ const struct usb_ctrlrequest *);
++ void (*suspend)(struct usb_function *);
++ void (*resume)(struct usb_function *);
++
++ /* internals */
++ struct list_head list;
++};
++
++int usb_add_function(struct usb_configuration *, struct usb_function *);
++
++int usb_interface_id(struct usb_configuration *, struct usb_function *);
++
++/**
++ * ep_choose - select descriptor endpoint at current device speed
++ * @g: gadget, connected and running at some speed
++ * @hs: descriptor to use for high speed operation
++ * @fs: descriptor to use for full or low speed operation
++ */
++static inline struct usb_endpoint_descriptor *
++ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
++ struct usb_endpoint_descriptor *fs)
++{
++ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
++ return hs;
++ return fs;
++}
++
++#define MAX_CONFIG_INTERFACES 8 /* arbitrary; max 255 */
++
++/**
++ * struct usb_configuration - represents one gadget configuration
++ * @label: For diagnostics, describes the configuration.
++ * @strings: Tables of strings, keyed by identifiers assigned during @bind()
++ * and by language IDs provided in control requests.
++ * @descriptors: Table of descriptors preceding all function descriptors.
++ * Examples include OTG and vendor-specific descriptors.
++ * @bind: Called from @usb_add_config() to allocate resources unique to this
++ * configuration and to call @usb_add_function() for each function used.
++ * @unbind: Reverses @bind; called as a side effect of unregistering the
++ * driver which added this configuration.
++ * @setup: Used to delegate control requests that aren't handled by standard
++ * device infrastructure or directed at a specific interface.
++ * @bConfigurationValue: Copied into configuration descriptor.
++ * @iConfiguration: Copied into configuration descriptor.
++ * @bmAttributes: Copied into configuration descriptor.
++ * @bMaxPower: Copied into configuration descriptor.
++ * @cdev: assigned by @usb_add_config() before calling @bind(); this is
++ * the device associated with this configuration.
++ *
++ * Configurations are building blocks for gadget drivers structured around
++ * function drivers. Simple USB gadgets require only one function and one
++ * configuration, and handle dual-speed hardware by always providing the same
++ * functionality. Slightly more complex gadgets may have more than one
++ * single-function configuration at a given speed; or have configurations
++ * that only work at one speed.
++ *
++ * Composite devices are, by definition, ones with configurations which
++ * include more than one function.
++ *
++ * The lifecycle of a usb_configuration includes allocation, initialization
++ * of the fields described above, and calling @usb_add_config() to set up
++ * internal data and bind it to a specific device. The configuration's
++ * @bind() method is then used to initialize all the functions and then
++ * call @usb_add_function() for them.
++ *
++ * Those functions would normally be independant of each other, but that's
++ * not mandatory. CDC WMC devices are an example where functions often
++ * depend on other functions, with some functions subsidiary to others.
++ * Such interdependency may be managed in any way, so long as all of the
++ * descriptors complete by the time the composite driver returns from
++ * its bind() routine.
++ */
++struct usb_configuration {
++ const char *label;
++ struct usb_gadget_strings **strings;
++ const struct usb_descriptor_header **descriptors;
++
++ /* REVISIT: bind() functions can be marked __init, which
++ * makes trouble for section mismatch analysis. See if
++ * we can't restructure things to avoid mismatching...
++ */
++
++ /* configuration management: bind/unbind */
++ int (*bind)(struct usb_configuration *);
++ void (*unbind)(struct usb_configuration *);
++ int (*setup)(struct usb_configuration *,
++ const struct usb_ctrlrequest *);
++
++ /* fields in the config descriptor */
++ u8 bConfigurationValue;
++ u8 iConfiguration;
++ u8 bmAttributes;
++ u8 bMaxPower;
++
++ struct usb_composite_dev *cdev;
++
++ /* internals */
++ struct list_head list;
++ struct list_head functions;
++ u8 next_interface_id;
++ unsigned highspeed:1;
++ unsigned fullspeed:1;
++ struct usb_function *interface[MAX_CONFIG_INTERFACES];
++};
++
++int usb_add_config(struct usb_composite_dev *,
++ struct usb_configuration *);
++
++/**
++ * struct usb_composite_driver - groups configurations into a gadget
++ * @name: For diagnostics, identifies the driver.
++ * @dev: Template descriptor for the device, including default device
++ * identifiers.
++ * @strings: tables of strings, keyed by identifiers assigned during bind()
++ * and language IDs provided in control requests
++ * @bind: (REQUIRED) Used to allocate resources that are shared across the
++ * whole device, such as string IDs, and add its configurations using
++ * @usb_add_config(). This may fail by returning a negative errno
++ * value; it should return zero on successful initialization.
++ * @unbind: Reverses @bind(); called as a side effect of unregistering
++ * this driver.
++ *
++ * Devices default to reporting self powered operation. Devices which rely
++ * on bus powered operation should report this in their @bind() method.
++ *
++ * Before returning from @bind, various fields in the template descriptor
++ * may be overridden. These include the idVendor/idProduct/bcdDevice values
++ * normally to bind the appropriate host side driver, and the three strings
++ * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
++ * meaningful device identifiers. (The strings will not be defined unless
++ * they are defined in @dev and @strings.) The correct ep0 maxpacket size
++ * is also reported, as defined by the underlying controller driver.
++ */
++struct usb_composite_driver {
++ const char *name;
++ const struct usb_device_descriptor *dev;
++ struct usb_gadget_strings **strings;
++
++ /* REVISIT: bind() functions can be marked __init, which
++ * makes trouble for section mismatch analysis. See if
++ * we can't restructure things to avoid mismatching...
++ */
++
++ int (*bind)(struct usb_composite_dev *);
++ int (*unbind)(struct usb_composite_dev *);
++};
++
++extern int usb_composite_register(struct usb_composite_driver *);
++extern void usb_composite_unregister(struct usb_composite_driver *);
++
++
++/**
++ * struct usb_composite_device - represents one composite usb gadget
++ * @gadget: read-only, abstracts the gadget's usb peripheral controller
++ * @req: used for control responses; buffer is pre-allocated
++ * @bufsiz: size of buffer pre-allocated in @req
++ * @config: the currently active configuration
++ *
++ * One of these devices is allocated and initialized before the
++ * associated device driver's bind() is called.
++ *
++ * OPEN ISSUE: it appears that some WUSB devices will need to be
++ * built by combining a normal (wired) gadget with a wireless one.
++ * This revision of the gadget framework should probably try to make
++ * sure doing that won't hurt too much.
++ *
++ * One notion for how to handle Wireless USB devices involves:
++ * (a) a second gadget here, discovery mechanism TBD, but likely
++ * needing separate "register/unregister WUSB gadget" calls;
++ * (b) updates to usb_gadget to include flags "is it wireless",
++ * "is it wired", plus (presumably in a wrapper structure)
++ * bandgroup and PHY info;
++ * (c) presumably a wireless_ep wrapping a usb_ep, and reporting
++ * wireless-specific parameters like maxburst and maxsequence;
++ * (d) configurations that are specific to wireless links;
++ * (e) function drivers that understand wireless configs and will
++ * support wireless for (additional) function instances;
++ * (f) a function to support association setup (like CBAF), not
++ * necessarily requiring a wireless adapter;
++ * (g) composite device setup that can create one or more wireless
++ * configs, including appropriate association setup support;
++ * (h) more, TBD.
++ */
++struct usb_composite_dev {
++ struct usb_gadget *gadget;
++ struct usb_request *req;
++ unsigned bufsiz;
++
++ struct usb_configuration *config;
++
++ /* internals */
++ struct usb_device_descriptor desc;
++ struct list_head configs;
++ struct usb_composite_driver *driver;
++ u8 next_string_id;
++
++ spinlock_t lock;
++
++ /* REVISIT use and existence of lock ... */
++};
++
++extern int usb_string_id(struct usb_composite_dev *c);
++
++/* messaging utils */
++#define DBG(d, fmt, args...) \
++ dev_dbg(&(d)->gadget->dev , fmt , ## args)
++#define VDBG(d, fmt, args...) \
++ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
++#define ERROR(d, fmt, args...) \
++ dev_err(&(d)->gadget->dev , fmt , ## args)
++#define WARN(d, fmt, args...) \
++ dev_warn(&(d)->gadget->dev , fmt , ## args)
++#define INFO(d, fmt, args...) \
++ dev_info(&(d)->gadget->dev , fmt , ## args)
++
++#endif /* __LINUX_USB_COMPOSITE_H */
diff --git a/usb/usb-gadget-push-bkl-down-into-drivers.patch b/usb/usb-gadget-push-bkl-down-into-drivers.patch
new file mode 100644
index 00000000000000..3b29204bd98237
--- /dev/null
+++ b/usb/usb-gadget-push-bkl-down-into-drivers.patch
@@ -0,0 +1,113 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:13:46 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:03:27 +0100
+Subject: USB: gadget: Push BKL down into drivers
+To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20080522220327.38e2347d@core>
+
+
+This keeps the gadget ioctl method wrapped but pushes the BKL down into
+the gadget code so we can use unlocked_ioctl().
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/inode.c | 23 +++++++++++++----------
+ drivers/usb/gadget/printer.c | 7 +++----
+ 2 files changed, 16 insertions(+), 14 deletions(-)
+
+--- a/drivers/usb/gadget/inode.c
++++ b/drivers/usb/gadget/inode.c
+@@ -32,6 +32,7 @@
+ #include <asm/uaccess.h>
+ #include <linux/slab.h>
+ #include <linux/poll.h>
++#include <linux/smp_lock.h>
+
+ #include <linux/device.h>
+ #include <linux/moduleparam.h>
+@@ -483,8 +484,7 @@ ep_release (struct inode *inode, struct
+ return 0;
+ }
+
+-static int ep_ioctl (struct inode *inode, struct file *fd,
+- unsigned code, unsigned long value)
++static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
+ {
+ struct ep_data *data = fd->private_data;
+ int status;
+@@ -740,7 +740,7 @@ static const struct file_operations ep_i
+
+ .read = ep_read,
+ .write = ep_write,
+- .ioctl = ep_ioctl,
++ .unlocked_ioctl = ep_ioctl,
+ .release = ep_release,
+
+ .aio_read = ep_aio_read,
+@@ -1294,15 +1294,18 @@ out:
+ return mask;
+ }
+
+-static int dev_ioctl (struct inode *inode, struct file *fd,
+- unsigned code, unsigned long value)
++static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
+ {
+ struct dev_data *dev = fd->private_data;
+ struct usb_gadget *gadget = dev->gadget;
++ long ret = -ENOTTY;
+
+- if (gadget->ops->ioctl)
+- return gadget->ops->ioctl (gadget, code, value);
+- return -ENOTTY;
++ if (gadget->ops->ioctl) {
++ lock_kernel();
++ ret = gadget->ops->ioctl (gadget, code, value);
++ unlock_kernel();
++ }
++ return ret;
+ }
+
+ /* used after device configuration */
+@@ -1314,7 +1317,7 @@ static const struct file_operations ep0_
+ .write = ep0_write,
+ .fasync = ep0_fasync,
+ .poll = ep0_poll,
+- .ioctl = dev_ioctl,
++ .unlocked_ioctl = dev_ioctl,
+ .release = dev_release,
+ };
+
+@@ -1964,7 +1967,7 @@ static const struct file_operations dev_
+ .open = dev_open,
+ .write = dev_config,
+ .fasync = ep0_fasync,
+- .ioctl = dev_ioctl,
++ .unlocked_ioctl = dev_ioctl,
+ .release = dev_release,
+ };
+
+--- a/drivers/usb/gadget/printer.c
++++ b/drivers/usb/gadget/printer.c
+@@ -827,9 +827,8 @@ printer_poll(struct file *fd, poll_table
+ return status;
+ }
+
+-static int
+-printer_ioctl(struct inode *inode, struct file *fd, unsigned int code,
+- unsigned long arg)
++static long
++printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
+ {
+ struct printer_dev *dev = fd->private_data;
+ unsigned long flags;
+@@ -868,7 +867,7 @@ static struct file_operations printer_io
+ .write = printer_write,
+ .fsync = printer_fsync,
+ .poll = printer_poll,
+- .ioctl = printer_ioctl,
++ .unlocked_ioctl = printer_ioctl,
+ .release = printer_close
+ };
+
diff --git a/usb/usb-gadget-support-descriptor-copying.patch b/usb/usb-gadget-support-descriptor-copying.patch
new file mode 100644
index 00000000000000..996eac0c45d9ec
--- /dev/null
+++ b/usb/usb-gadget-support-descriptor-copying.patch
@@ -0,0 +1,171 @@
+From david-b@pacbell.net Fri Jun 6 15:10:05 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:02:47 -0700
+Subject: USB: gadget support descriptor copying
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201102.47771.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+Define three new descriptor manipulation utilities, for use when
+setting up functions that may have multiple instances:
+
+ usb_copy_descriptors() to copy a vector of descriptors
+ usb_free_descriptors() to free the copy
+ usb_find_endpoint() to find a copied version
+
+These will be used as follows. Functions will continue to have static
+tables of descriptors they update, now used as __initdata templates.
+
+When a function creates a new instance, it patches those tables with
+relevant interface and string IDs, plus endpoint assignments. Then it
+makes a copy of those morphed descriptors and associates that with the
+new function instance, and records the endpoint descriptors to use when
+activating the endpoints. When initialization is done, only the copies
+remain in memory. The copies are freed on driver removal.
+
+This ensures that each instances has descriptors which hold the right
+instance-specific data. Two instances in the same configuration will
+obviously never share the same interface IDs or use the same endpoints,
+and instances in different configuration mostly wouldn't do so either.
+
+This also includes a bugfix to the epautoconf code that shows up with
+this usage model. It must replace the previous endpoint number when
+it updates descriptors, not just mask in a few more bits.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/config.c | 75 +++++++++++++++++++++++++++++++++++++++-
+ drivers/usb/gadget/epautoconf.c | 1
+ include/linux/usb/gadget.h | 19 ++++++++++
+ 3 files changed, 94 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/config.c
++++ b/drivers/usb/gadget/config.c
+@@ -96,7 +96,7 @@ int usb_gadget_config_buf(
+ /* config descriptor first */
+ if (length < USB_DT_CONFIG_SIZE || !desc)
+ return -EINVAL;
+- *cp = *config;
++ *cp = *config;
+
+ /* then interface/endpoint/class/vendor/... */
+ len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+@@ -115,3 +115,76 @@ int usb_gadget_config_buf(
+ return len;
+ }
+
++/**
++ * usb_copy_descriptors - copy a vector of USB descriptors
++ * @src: null-terminated vector to copy
++ * Context: initialization code, which may sleep
++ *
++ * This makes a copy of a vector of USB descriptors. Its primary use
++ * is to support usb_function objects which can have multiple copies,
++ * each needing different descriptors. Functions may have static
++ * tables of descriptors, which are used as templates and customized
++ * with identifiers (for interfaces, strings, endpoints, and more)
++ * as needed by a given function instance.
++ */
++struct usb_descriptor_header **__init
++usb_copy_descriptors(struct usb_descriptor_header **src)
++{
++ struct usb_descriptor_header **tmp;
++ unsigned bytes;
++ unsigned n_desc;
++ void *mem;
++ struct usb_descriptor_header **ret;
++
++ /* count descriptors and their sizes; then add vector size */
++ for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
++ bytes += (*tmp)->bLength;
++ bytes += (n_desc + 1) * sizeof(*tmp);
++
++ mem = kmalloc(bytes, GFP_KERNEL);
++ if (!mem)
++ return NULL;
++
++ /* fill in pointers starting at "tmp",
++ * to descriptors copied starting at "mem";
++ * and return "ret"
++ */
++ ret = tmp = mem;
++ mem += (n_desc + 1) * sizeof(*tmp);
++ while (*src) {
++ memcpy(mem, *src, (*src)->bLength);
++ *tmp = mem;
++ tmp++;
++ mem += (*src)->bLength;
++ src++;
++ }
++ *tmp = NULL;
++
++ return ret;
++}
++
++/**
++ * usb_find_endpoint - find a copy of an endpoint descriptor
++ * @src: original vector of descriptors
++ * @copy: copy of @src
++ * @ep: endpoint descriptor found in @src
++ *
++ * This returns the copy of the @match descriptor made for @copy. Its
++ * intended use is to help remembering the endpoint descriptor to use
++ * when enabling a given endpoint.
++ */
++struct usb_endpoint_descriptor *__init
++usb_find_endpoint(
++ struct usb_descriptor_header **src,
++ struct usb_descriptor_header **copy,
++ struct usb_endpoint_descriptor *match
++)
++{
++ while (*src) {
++ if (*src == (void *) match)
++ return (void *)*copy;
++ src++;
++ copy++;
++ }
++ return NULL;
++}
+--- a/drivers/usb/gadget/epautoconf.c
++++ b/drivers/usb/gadget/epautoconf.c
+@@ -159,6 +159,7 @@ ep_matches (
+ /* MATCH!! */
+
+ /* report address */
++ desc->bEndpointAddress &= USB_DIR_IN;
+ if (isdigit (ep->name [2])) {
+ u8 num = simple_strtol (&ep->name [2], NULL, 10);
+ desc->bEndpointAddress |= num;
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -858,6 +858,25 @@ int usb_descriptor_fillbuf(void *, unsig
+ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
+ void *buf, unsigned buflen, const struct usb_descriptor_header **desc);
+
++/* copy a NULL-terminated vector of descriptors */
++struct usb_descriptor_header **usb_copy_descriptors(
++ struct usb_descriptor_header **);
++
++/* return copy of endpoint descriptor given original descriptor set */
++struct usb_endpoint_descriptor *usb_find_endpoint(
++ struct usb_descriptor_header **src,
++ struct usb_descriptor_header **copy,
++ struct usb_endpoint_descriptor *match);
++
++/**
++ * usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
++ * @v: vector of descriptors
++ */
++static inline void usb_free_descriptors(struct usb_descriptor_header **v)
++{
++ kfree(v);
++}
++
+ /*-------------------------------------------------------------------------*/
+
+ /* utility wrapping a simple endpoint selection policy */
diff --git a/usb/usb-gadget-zero-loopback-function-driver.patch b/usb/usb-gadget-zero-loopback-function-driver.patch
new file mode 100644
index 00000000000000..ee2af7a0a1d4a4
--- /dev/null
+++ b/usb/usb-gadget-zero-loopback-function-driver.patch
@@ -0,0 +1,426 @@
+From david-b@pacbell.net Fri Jun 6 15:10:56 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:07:08 -0700
+Subject: usb gadget zero: loopback function driver
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201107.08935.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+This splits the gadget zero "loopback" configuration into a standalone
+"configuration driver", building on the composite gadget framework code.
+It doesn't yet pull the original code out of gadget zero or update how
+that driver is built.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_loopback.c | 383 ++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/gadget/g_zero.h | 2
+ 2 files changed, 385 insertions(+)
+
+--- /dev/null
++++ b/drivers/usb/gadget/f_loopback.c
+@@ -0,0 +1,383 @@
++/*
++ * f_loopback.c - USB peripheral loopback configuration driver
++ *
++ * Copyright (C) 2003-2008 David Brownell
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++
++#include "g_zero.h"
++#include "gadget_chips.h"
++
++
++/*
++ * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
++ *
++ * This takes messages of various sizes written OUT to a device, and loops
++ * them back so they can be read IN from it. It has been used by certain
++ * test applications. It supports limited testing of data queueing logic.
++ *
++ *
++ * This is currently packaged as a configuration driver, which can't be
++ * combined with other functions to make composite devices. However, it
++ * can be combined with other independent configurations.
++ */
++struct f_loopback {
++ struct usb_function function;
++
++ struct usb_ep *in_ep;
++ struct usb_ep *out_ep;
++};
++
++static inline struct f_loopback *func_to_loop(struct usb_function *f)
++{
++ return container_of(f, struct f_loopback, function);
++}
++
++static unsigned qlen = 32;
++module_param(qlen, uint, 0);
++MODULE_PARM_DESC(qlenn, "depth of loopback queue");
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_interface_descriptor loopback_intf = {
++ .bLength = sizeof loopback_intf,
++ .bDescriptorType = USB_DT_INTERFACE,
++
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
++ /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_source_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_sink_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_loopback_descs[] = {
++ (struct usb_descriptor_header *) &loopback_intf,
++ (struct usb_descriptor_header *) &fs_sink_desc,
++ (struct usb_descriptor_header *) &fs_source_desc,
++ NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_source_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_sink_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *hs_loopback_descs[] = {
++ (struct usb_descriptor_header *) &loopback_intf,
++ (struct usb_descriptor_header *) &hs_source_desc,
++ (struct usb_descriptor_header *) &hs_sink_desc,
++ NULL,
++};
++
++/* function-specific strings: */
++
++static struct usb_string strings_loopback[] = {
++ [0].s = "loop input to output",
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_loop = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_loopback,
++};
++
++static struct usb_gadget_strings *loopback_strings[] = {
++ &stringtab_loop,
++ NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int __init
++loopback_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct f_loopback *loop = func_to_loop(f);
++ int id;
++
++ /* allocate interface ID(s) */
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ loopback_intf.bInterfaceNumber = id;
++
++ /* allocate endpoints */
++
++ loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
++ if (!loop->in_ep) {
++autoconf_fail:
++ ERROR(cdev, "%s: can't autoconfigure on %s\n",
++ f->name, cdev->gadget->name);
++ return -ENODEV;
++ }
++ loop->in_ep->driver_data = cdev; /* claim */
++
++ loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
++ if (!loop->out_ep)
++ goto autoconf_fail;
++ loop->out_ep->driver_data = cdev; /* claim */
++
++ /* support high speed hardware */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ hs_source_desc.bEndpointAddress =
++ fs_source_desc.bEndpointAddress;
++ hs_sink_desc.bEndpointAddress =
++ fs_sink_desc.bEndpointAddress;
++ f->hs_descriptors = hs_loopback_descs;
++ }
++
++ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ f->name, loop->in_ep->name, loop->out_ep->name);
++ return 0;
++}
++
++static void
++loopback_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ kfree(func_to_loop(f));
++}
++
++static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct f_loopback *loop = ep->driver_data;
++ struct usb_composite_dev *cdev = loop->function.config->cdev;
++ int status = req->status;
++
++ switch (status) {
++
++ case 0: /* normal completion? */
++ if (ep == loop->out_ep) {
++ /* loop this OUT packet back IN to the host */
++ req->zero = (req->actual < req->length);
++ req->length = req->actual;
++ status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
++ if (status == 0)
++ return;
++
++ /* "should never get here" */
++ ERROR(cdev, "can't loop %s to %s: %d\n",
++ ep->name, loop->in_ep->name,
++ status);
++ }
++
++ /* queue the buffer for some later OUT packet */
++ req->length = buflen;
++ status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
++ if (status == 0)
++ return;
++
++ /* "should never get here" */
++ /* FALLTHROUGH */
++
++ default:
++ ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
++ status, req->actual, req->length);
++ /* FALLTHROUGH */
++
++ /* NOTE: since this driver doesn't maintain an explicit record
++ * of requests it submitted (just maintains qlen count), we
++ * rely on the hardware driver to clean up on disconnect or
++ * endpoint disable.
++ */
++ case -ECONNABORTED: /* hardware forced ep reset */
++ case -ECONNRESET: /* request dequeued */
++ case -ESHUTDOWN: /* disconnect from host */
++ free_ep_req(ep, req);
++ return;
++ }
++}
++
++static void disable_loopback(struct f_loopback *loop)
++{
++ struct usb_composite_dev *cdev;
++
++ cdev = loop->function.config->cdev;
++ disable_endpoints(cdev, loop->in_ep, loop->out_ep);
++ VDBG(cdev, "%s disabled\n", loop->function.name);
++}
++
++static int
++enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
++{
++ int result = 0;
++ const struct usb_endpoint_descriptor *src, *sink;
++ struct usb_ep *ep;
++ struct usb_request *req;
++ unsigned i;
++
++ src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
++ sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
++
++ /* one endpoint writes data back IN to the host */
++ ep = loop->in_ep;
++ result = usb_ep_enable(ep, src);
++ if (result < 0)
++ return result;
++ ep->driver_data = loop;
++
++ /* one endpoint just reads OUT packets */
++ ep = loop->out_ep;
++ result = usb_ep_enable(ep, sink);
++ if (result < 0) {
++fail0:
++ ep = loop->in_ep;
++ usb_ep_disable(ep);
++ ep->driver_data = NULL;
++ return result;
++ }
++ ep->driver_data = loop;
++
++ /* allocate a bunch of read buffers and queue them all at once.
++ * we buffer at most 'qlen' transfers; fewer if any need more
++ * than 'buflen' bytes each.
++ */
++ for (i = 0; i < qlen && result == 0; i++) {
++ req = alloc_ep_req(ep);
++ if (req) {
++ req->complete = loopback_complete;
++ result = usb_ep_queue(ep, req, GFP_ATOMIC);
++ if (result)
++ ERROR(cdev, "%s queue req --> %d\n",
++ ep->name, result);
++ } else {
++ usb_ep_disable(ep);
++ ep->driver_data = NULL;
++ result = -ENOMEM;
++ goto fail0;
++ }
++ }
++
++ DBG(cdev, "%s enabled\n", loop->function.name);
++ return result;
++}
++
++static int loopback_set_alt(struct usb_function *f,
++ unsigned intf, unsigned alt)
++{
++ struct f_loopback *loop = func_to_loop(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ /* we know alt is zero */
++ if (loop->in_ep->driver_data)
++ disable_loopback(loop);
++ return enable_loopback(cdev, loop);
++}
++
++static void loopback_disable(struct usb_function *f)
++{
++ struct f_loopback *loop = func_to_loop(f);
++
++ disable_loopback(loop);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __init loopback_bind_config(struct usb_configuration *c)
++{
++ struct f_loopback *loop;
++ int status;
++
++ loop = kzalloc(sizeof *loop, GFP_KERNEL);
++ if (!loop)
++ return -ENOMEM;
++
++ loop->function.name = "loopback";
++ loop->function.descriptors = fs_loopback_descs;
++ loop->function.bind = loopback_bind;
++ loop->function.unbind = loopback_unbind;
++ loop->function.set_alt = loopback_set_alt;
++ loop->function.disable = loopback_disable;
++
++ status = usb_add_function(c, &loop->function);
++ if (status)
++ kfree(loop);
++ return status;
++}
++
++static struct usb_configuration loopback_driver = {
++ .label = "loopback",
++ .strings = loopback_strings,
++ .bind = loopback_bind_config,
++ .bConfigurationValue = 2,
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = 1, /* 2 mA, minimal */
++ /* .iConfiguration = DYNAMIC */
++};
++
++/**
++ * loopback_add - add a loopback testing configuration to a device
++ * @cdev: the device to support the loopback configuration
++ */
++int __init loopback_add(struct usb_composite_dev *cdev)
++{
++ int id;
++
++ /* allocate string ID(s) */
++ id = usb_string_id(cdev);
++ if (id < 0)
++ return id;
++ strings_loopback[0].id = id;
++
++ loopback_intf.iInterface = id;
++ loopback_driver.iConfiguration = id;
++
++ /* FIXME pass in bConfigurationValue and OTG stuff */
++
++ /* support OTG systems */
++ if (gadget_is_otg(cdev->gadget)) {
++ loopback_driver.descriptors = otg_desc;
++ loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ return usb_add_config(cdev, &loopback_driver);
++}
+--- a/drivers/usb/gadget/g_zero.h
++++ b/drivers/usb/gadget/g_zero.h
+@@ -9,6 +9,7 @@
+ #include <linux/usb/composite.h>
+
+ /* global state */
++extern unsigned buflen;
+ extern const struct usb_descriptor_header **otg_desc;
+
+ /* common utilities */
+@@ -19,5 +20,6 @@ void disable_endpoints(struct usb_compos
+
+ /* configuration-specific linkup */
+ int sourcesink_add(struct usb_composite_dev *cdev);
++int loopback_add(struct usb_composite_dev *cdev);
+
+ #endif /* __G_ZERO_H */
diff --git a/usb/usb-gadget-zero-sourcesink-config-driver.patch b/usb/usb-gadget-zero-sourcesink-config-driver.patch
new file mode 100644
index 00000000000000..970deb13e6df92
--- /dev/null
+++ b/usb/usb-gadget-zero-sourcesink-config-driver.patch
@@ -0,0 +1,645 @@
+From david-b@pacbell.net Fri Jun 6 15:10:42 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:06:24 -0700
+Subject: usb gadget zero: sourcesink config driver
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201106.24630.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+This splits the gadget zero "source/sink" configuration into a standalone
+"configuration driver", building on the composite gadget framework code.
+It doesn't yet pull the original code out of gadget zero or update how
+that driver is built.
+
+Neither this, nor its sibling "loopback" configuration, is a function
+driver that can be combined with other functions. However the code does
+become simpler because of this conversion, so it's a net win.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/f_sourcesink.c | 589 ++++++++++++++++++++++++++++++++++++++
+ drivers/usb/gadget/g_zero.h | 23 +
+ 2 files changed, 612 insertions(+)
+
+--- /dev/null
++++ b/drivers/usb/gadget/f_sourcesink.c
+@@ -0,0 +1,589 @@
++/*
++ * f_sourcesink.c - USB peripheral source/sink configuration driver
++ *
++ * Copyright (C) 2003-2008 David Brownell
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++
++#include "g_zero.h"
++#include "gadget_chips.h"
++
++
++/*
++ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
++ * controller drivers.
++ *
++ * This just sinks bulk packets OUT to the peripheral and sources them IN
++ * to the host, optionally with specific data patterns for integrity tests.
++ * As such it supports basic functionality and load tests.
++ *
++ * In terms of control messaging, this supports all the standard requests
++ * plus two that support control-OUT tests. If the optional "autoresume"
++ * mode is enabled, it provides good functional coverage for the "USBCV"
++ * test harness from USB-IF.
++ *
++ * Note that because this doesn't queue more than one request at a time,
++ * some other function must be used to test queueing logic. The network
++ * link (g_ether) is the best overall option for that, since its TX and RX
++ * queues are relatively independent, will receive a range of packet sizes,
++ * and can often be made to run out completely. Those issues are important
++ * when stress testing peripheral controller drivers.
++ *
++ *
++ * This is currently packaged as a configuration driver, which can't be
++ * combined with other functions to make composite devices. However, it
++ * can be combined with other independent configurations.
++ */
++struct f_sourcesink {
++ struct usb_function function;
++
++ struct usb_ep *in_ep;
++ struct usb_ep *out_ep;
++ struct timer_list resume;
++};
++
++static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
++{
++ return container_of(f, struct f_sourcesink, function);
++}
++
++static unsigned autoresume;
++module_param(autoresume, uint, 0);
++MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
++
++static unsigned pattern;
++module_param(pattern, uint, 0);
++MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_interface_descriptor source_sink_intf = {
++ .bLength = sizeof source_sink_intf,
++ .bDescriptorType = USB_DT_INTERFACE,
++
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
++ /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor fs_source_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor fs_sink_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *fs_source_sink_descs[] = {
++ (struct usb_descriptor_header *) &source_sink_intf,
++ (struct usb_descriptor_header *) &fs_sink_desc,
++ (struct usb_descriptor_header *) &fs_source_desc,
++ NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor hs_source_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor hs_sink_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *hs_source_sink_descs[] = {
++ (struct usb_descriptor_header *) &source_sink_intf,
++ (struct usb_descriptor_header *) &hs_source_desc,
++ (struct usb_descriptor_header *) &hs_sink_desc,
++ NULL,
++};
++
++/* function-specific strings: */
++
++static struct usb_string strings_sourcesink[] = {
++ [0].s = "source and sink data",
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab_sourcesink = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_sourcesink,
++};
++
++static struct usb_gadget_strings *sourcesink_strings[] = {
++ &stringtab_sourcesink,
++ NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static void sourcesink_autoresume(unsigned long _c)
++{
++ struct usb_composite_dev *cdev = (void *)_c;
++ struct usb_gadget *g = cdev->gadget;
++
++ /* Normally the host would be woken up for something
++ * more significant than just a timer firing; likely
++ * because of some direct user request.
++ */
++ if (g->speed != USB_SPEED_UNKNOWN) {
++ int status = usb_gadget_wakeup(g);
++ DBG(cdev, "%s --> %d\n", __func__, status);
++ }
++}
++
++static int __init
++sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct f_sourcesink *ss = func_to_ss(f);
++ int id;
++
++ /* allocate interface ID(s) */
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ source_sink_intf.bInterfaceNumber = id;
++
++ /* allocate endpoints */
++ ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
++ if (!ss->in_ep) {
++autoconf_fail:
++ ERROR(cdev, "%s: can't autoconfigure on %s\n",
++ f->name, cdev->gadget->name);
++ return -ENODEV;
++ }
++ ss->in_ep->driver_data = cdev; /* claim */
++
++ ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
++ if (!ss->out_ep)
++ goto autoconf_fail;
++ ss->out_ep->driver_data = cdev; /* claim */
++
++ setup_timer(&ss->resume, sourcesink_autoresume,
++ (unsigned long) c->cdev);
++
++ /* support high speed hardware */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ hs_source_desc.bEndpointAddress =
++ fs_source_desc.bEndpointAddress;
++ hs_sink_desc.bEndpointAddress =
++ fs_sink_desc.bEndpointAddress;
++ f->hs_descriptors = hs_source_sink_descs;
++ }
++
++ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ f->name, ss->in_ep->name, ss->out_ep->name);
++ return 0;
++}
++
++static void
++sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ kfree(func_to_ss(f));
++}
++
++/* optionally require specific source/sink data patterns */
++static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
++{
++ unsigned i;
++ u8 *buf = req->buf;
++ struct usb_composite_dev *cdev = ss->function.config->cdev;
++
++ for (i = 0; i < req->actual; i++, buf++) {
++ switch (pattern) {
++
++ /* all-zeroes has no synchronization issues */
++ case 0:
++ if (*buf == 0)
++ continue;
++ break;
++
++ /* "mod63" stays in sync with short-terminated transfers,
++ * OR otherwise when host and gadget agree on how large
++ * each usb transfer request should be. Resync is done
++ * with set_interface or set_config. (We *WANT* it to
++ * get quickly out of sync if controllers or their drivers
++ * stutter for any reason, including buffer duplcation...)
++ */
++ case 1:
++ if (*buf == (u8)(i % 63))
++ continue;
++ break;
++ }
++ ERROR(cdev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
++ usb_ep_set_halt(ss->out_ep);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
++{
++ unsigned i;
++ u8 *buf = req->buf;
++
++ switch (pattern) {
++ case 0:
++ memset(req->buf, 0, req->length);
++ break;
++ case 1:
++ for (i = 0; i < req->length; i++)
++ *buf++ = (u8) (i % 63);
++ break;
++ }
++}
++
++static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct f_sourcesink *ss = ep->driver_data;
++ struct usb_composite_dev *cdev = ss->function.config->cdev;
++ int status = req->status;
++
++ switch (status) {
++
++ case 0: /* normal completion? */
++ if (ep == ss->out_ep) {
++ check_read_data(ss, req);
++ memset(req->buf, 0x55, req->length);
++ } else
++ reinit_write_data(ep, req);
++ break;
++
++ /* this endpoint is normally active while we're configured */
++ case -ECONNABORTED: /* hardware forced ep reset */
++ case -ECONNRESET: /* request dequeued */
++ case -ESHUTDOWN: /* disconnect from host */
++ VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
++ req->actual, req->length);
++ if (ep == ss->out_ep)
++ check_read_data(ss, req);
++ free_ep_req(ep, req);
++ return;
++
++ case -EOVERFLOW: /* buffer overrun on read means that
++ * we didn't provide a big enough
++ * buffer.
++ */
++ default:
++#if 1
++ DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
++ status, req->actual, req->length);
++#endif
++ case -EREMOTEIO: /* short read */
++ break;
++ }
++
++ status = usb_ep_queue(ep, req, GFP_ATOMIC);
++ if (status) {
++ ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n",
++ ep->name, req->length, status);
++ usb_ep_set_halt(ep);
++ /* FIXME recover later ... somehow */
++ }
++}
++
++static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
++{
++ struct usb_ep *ep;
++ struct usb_request *req;
++ int status;
++
++ ep = is_in ? ss->in_ep : ss->out_ep;
++ req = alloc_ep_req(ep);
++ if (!req)
++ return -ENOMEM;
++
++ req->complete = source_sink_complete;
++ if (is_in)
++ reinit_write_data(ep, req);
++ else
++ memset(req->buf, 0x55, req->length);
++
++ status = usb_ep_queue(ep, req, GFP_ATOMIC);
++ if (status) {
++ struct usb_composite_dev *cdev;
++
++ cdev = ss->function.config->cdev;
++ ERROR(cdev, "start %s %s --> %d\n",
++ is_in ? "IN" : "OUT",
++ ep->name, status);
++ free_ep_req(ep, req);
++ }
++
++ return status;
++}
++
++static void disable_source_sink(struct f_sourcesink *ss)
++{
++ struct usb_composite_dev *cdev;
++
++ cdev = ss->function.config->cdev;
++ disable_endpoints(cdev, ss->in_ep, ss->out_ep);
++ del_timer(&ss->resume);
++ VDBG(cdev, "%s disabled\n", ss->function.name);
++}
++
++static int
++enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
++{
++ int result = 0;
++ const struct usb_endpoint_descriptor *src, *sink;
++ struct usb_ep *ep;
++
++ src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
++ sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
++
++ /* one endpoint writes (sources) zeroes IN (to the host) */
++ ep = ss->in_ep;
++ result = usb_ep_enable(ep, src);
++ if (result < 0)
++ return result;
++ ep->driver_data = ss;
++
++ result = source_sink_start_ep(ss, true);
++ if (result < 0) {
++fail:
++ ep = ss->in_ep;
++ usb_ep_disable(ep);
++ ep->driver_data = NULL;
++ return result;
++ }
++
++ /* one endpoint reads (sinks) anything OUT (from the host) */
++ ep = ss->out_ep;
++ result = usb_ep_enable(ep, sink);
++ if (result < 0)
++ goto fail;
++ ep->driver_data = ss;
++
++ result = source_sink_start_ep(ss, false);
++ if (result < 0) {
++ usb_ep_disable(ep);
++ ep->driver_data = NULL;
++ goto fail;
++ }
++
++ DBG(cdev, "%s enabled\n", ss->function.name);
++ return result;
++}
++
++static int sourcesink_set_alt(struct usb_function *f,
++ unsigned intf, unsigned alt)
++{
++ struct f_sourcesink *ss = func_to_ss(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ /* we know alt is zero */
++ if (ss->in_ep->driver_data)
++ disable_source_sink(ss);
++ return enable_source_sink(cdev, ss);
++}
++
++static void sourcesink_disable(struct usb_function *f)
++{
++ struct f_sourcesink *ss = func_to_ss(f);
++
++ disable_source_sink(ss);
++}
++
++static void sourcesink_suspend(struct usb_function *f)
++{
++ struct f_sourcesink *ss = func_to_ss(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
++ return;
++
++ if (autoresume) {
++ mod_timer(&ss->resume, jiffies + (HZ * autoresume));
++ DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
++ } else
++ DBG(cdev, "%s\n", __func__);
++}
++
++static void sourcesink_resume(struct usb_function *f)
++{
++ struct f_sourcesink *ss = func_to_ss(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ DBG(cdev, "%s\n", __func__);
++ del_timer(&ss->resume);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __init sourcesink_bind_config(struct usb_configuration *c)
++{
++ struct f_sourcesink *ss;
++ int status;
++
++ ss = kzalloc(sizeof *ss, GFP_KERNEL);
++ if (!ss)
++ return -ENOMEM;
++
++ ss->function.name = "source/sink";
++ ss->function.descriptors = fs_source_sink_descs;
++ ss->function.bind = sourcesink_bind;
++ ss->function.unbind = sourcesink_unbind;
++ ss->function.set_alt = sourcesink_set_alt;
++ ss->function.disable = sourcesink_disable;
++ ss->function.suspend = sourcesink_suspend;
++ ss->function.resume = sourcesink_resume;
++
++ status = usb_add_function(c, &ss->function);
++ if (status)
++ kfree(ss);
++ return status;
++}
++
++static int sourcesink_setup(struct usb_configuration *c,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_request *req = c->cdev->req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ /* composite driver infrastructure handles everything except
++ * the two control test requests.
++ */
++ switch (ctrl->bRequest) {
++
++ /*
++ * These are the same vendor-specific requests supported by
++ * Intel's USB 2.0 compliance test devices. We exceed that
++ * device spec by allowing multiple-packet requests.
++ *
++ * NOTE: the Control-OUT data stays in req->buf ... better
++ * would be copying it into a scratch buffer, so that other
++ * requests may safely intervene.
++ */
++ case 0x5b: /* control WRITE test -- fill the buffer */
++ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
++ goto unknown;
++ if (w_value || w_index)
++ break;
++ /* just read that many bytes into the buffer */
++ if (w_length > req->length)
++ break;
++ value = w_length;
++ break;
++ case 0x5c: /* control READ test -- return the buffer */
++ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
++ goto unknown;
++ if (w_value || w_index)
++ break;
++ /* expect those bytes are still in the buffer; send back */
++ if (w_length > req->length)
++ break;
++ value = w_length;
++ break;
++
++ default:
++unknown:
++ VDBG(c->cdev,
++ "unknown control req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ }
++
++ /* respond with data transfer or status phase? */
++ if (value >= 0) {
++ VDBG(c->cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ req->zero = 0;
++ req->length = value;
++ value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
++ if (value < 0)
++ ERROR(c->cdev, "source/sinkc response, err %d\n",
++ value);
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static struct usb_configuration sourcesink_driver = {
++ .label = "source/sink",
++ .strings = sourcesink_strings,
++ .bind = sourcesink_bind_config,
++ .setup = sourcesink_setup,
++ .bConfigurationValue = 3,
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = 1, /* 2 mA, minimal */
++ /* .iConfiguration = DYNAMIC */
++};
++
++/**
++ * sourcesink_add - add a source/sink testing configuration to a device
++ * @cdev: the device to support the configuration
++ */
++int __init sourcesink_add(struct usb_composite_dev *cdev)
++{
++ int id;
++
++ /* allocate string ID(s) */
++ id = usb_string_id(cdev);
++ if (id < 0)
++ return id;
++ strings_sourcesink[0].id = id;
++
++ source_sink_intf.iInterface = id;
++ sourcesink_driver.iConfiguration = id;
++
++ /* FIXME pass in bConfigurationValue and OTG stuff */
++
++ /* support autoresume for remote wakeup testing */
++ if (autoresume)
++ sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++
++ /* support OTG systems */
++ if (gadget_is_otg(cdev->gadget)) {
++ sourcesink_driver.descriptors = otg_desc;
++ sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
++
++ return usb_add_config(cdev, &sourcesink_driver);
++}
+--- /dev/null
++++ b/drivers/usb/gadget/g_zero.h
+@@ -0,0 +1,23 @@
++/*
++ * This header declares the utility functions used by "Gadget Zero", plus
++ * interfaces to its two single-configuration function drivers.
++ */
++
++#ifndef __G_ZERO_H
++#define __G_ZERO_H
++
++#include <linux/usb/composite.h>
++
++/* global state */
++extern const struct usb_descriptor_header **otg_desc;
++
++/* common utilities */
++struct usb_request *alloc_ep_req(struct usb_ep *ep);
++void free_ep_req(struct usb_ep *ep, struct usb_request *req);
++void disable_endpoints(struct usb_composite_dev *cdev,
++ struct usb_ep *in, struct usb_ep *out);
++
++/* configuration-specific linkup */
++int sourcesink_add(struct usb_composite_dev *cdev);
++
++#endif /* __G_ZERO_H */
diff --git a/usb/usb-gadget-zero-use-updated-framework.patch b/usb/usb-gadget-zero-use-updated-framework.patch
new file mode 100644
index 00000000000000..f0bbcc562c2f05
--- /dev/null
+++ b/usb/usb-gadget-zero-use-updated-framework.patch
@@ -0,0 +1,1346 @@
+From david-b@pacbell.net Fri Jun 6 15:11:08 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:07:49 -0700
+Subject: usb gadget zero: use updated framework
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201107.49807.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+Update Gadget Zero to use the more modular versions of the loopback
+and source/sink configuration drivers which build on the new gadget
+framework code.
+
+The core code is a LOT simpler, and it should be much easier now to
+understand how the parts fit together. The conversion is an overall
+source shrink in terms of this gadget, since it uses more midlayer
+support. However, it's an overall increase in object size because
+there's less sharing between the two configurations (improves code
+clarity) and because the midlayer is a bit more functional than this
+driver actually needs.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/Makefile | 4
+ drivers/usb/gadget/zero.c | 1158 +++-----------------------------------------
+ 2 files changed, 95 insertions(+), 1067 deletions(-)
+
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -22,7 +22,9 @@ obj-$(CONFIG_USB_M66592) += m66592-udc.o
+ #
+ # USB gadget drivers
+ #
+-g_zero-objs := zero.o usbstring.o config.o epautoconf.o
++C_UTILS = composite.o usbstring.o config.o epautoconf.o
++
++g_zero-objs := zero.o f_sourcesink.o f_loopback.o $(C_UTILS)
+ g_ether-objs := ether.o usbstring.o config.o epautoconf.o
+ g_serial-objs := serial.o u_serial.o usbstring.o config.o epautoconf.o
+ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
+--- a/drivers/usb/gadget/zero.c
++++ b/drivers/usb/gadget/zero.c
+@@ -30,12 +30,7 @@
+ *
+ * It supports two similar configurations. One sinks whatever the usb host
+ * writes, and in return sources zeroes. The other loops whatever the host
+- * writes back, so the host can read it. Module options include:
+- *
+- * buflen=N default N=4096, buffer size used
+- * qlen=N default N=32, how many buffers in the loopback queue
+- * loopdefault default false, list loopback config first
+- * autoresume=N default N=0, seconds before triggering remote wakeup
++ * writes back, so the host can read it.
+ *
+ * Many drivers will only have one configuration, letting them be much
+ * simpler if they also don't support high speed operation (like this
+@@ -47,94 +42,35 @@
+ * work with low capability USB controllers without four bulk endpoints.
+ */
+
++/*
++ * driver assumes self-powered hardware, and
++ * has no way for users to trigger remote wakeup.
++ */
++
+ /* #define VERBOSE_DEBUG */
+
+ #include <linux/kernel.h>
+ #include <linux/utsname.h>
+ #include <linux/device.h>
+
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/gadget.h>
+-
++#include "g_zero.h"
+ #include "gadget_chips.h"
+
+
+ /*-------------------------------------------------------------------------*/
+
+-#define DRIVER_VERSION "Earth Day 2008"
++#define DRIVER_VERSION "Cinco de Mayo 2008"
+
+-static const char shortname[] = "zero";
+ static const char longname[] = "Gadget Zero";
+
+-static const char source_sink[] = "source and sink data";
+-static const char loopback[] = "loop input to output";
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * driver assumes self-powered hardware, and
+- * has no way for users to trigger remote wakeup.
+- *
+- * this version autoconfigures as much as possible,
+- * which is reasonable for most "bulk-only" drivers.
+- */
+-static const char *EP_IN_NAME; /* source */
+-static const char *EP_OUT_NAME; /* sink */
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* big enough to hold our biggest descriptor */
+-#define USB_BUFSIZ 256
+-
+-struct zero_dev {
+- spinlock_t lock;
+- struct usb_gadget *gadget;
+- struct usb_request *req; /* for control responses */
+-
+- /* when configured, we have one of two configs:
+- * - source data (in to host) and sink it (out from host)
+- * - or loop it back (out from host back in to host)
+- */
+- u8 config;
+- struct usb_ep *in_ep, *out_ep;
+-
+- /* autoresume timer */
+- struct timer_list resume;
+-};
+-
+-#define DBG(d, fmt, args...) \
+- dev_dbg(&(d)->gadget->dev , fmt , ## args)
+-#define VDBG(d, fmt, args...) \
+- dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+-#define ERROR(d, fmt, args...) \
+- dev_err(&(d)->gadget->dev , fmt , ## args)
+-#define WARN(d, fmt, args...) \
+- dev_warn(&(d)->gadget->dev , fmt , ## args)
+-#define INFO(d, fmt, args...) \
+- dev_info(&(d)->gadget->dev , fmt , ## args)
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static unsigned buflen = 4096;
+-static unsigned qlen = 32;
+-static unsigned pattern = 0;
+-
+-module_param(buflen, uint, S_IRUGO);
+-module_param(qlen, uint, S_IRUGO);
+-module_param(pattern, uint, S_IRUGO|S_IWUSR);
+-
+-/*
+- * if it's nonzero, autoresume says how many seconds to wait
+- * before trying to wake up the host after suspend.
+- */
+-static unsigned autoresume = 0;
+-module_param(autoresume, uint, 0);
++unsigned buflen = 4096;
++module_param(buflen, uint, 0);
+
+ /*
+ * Normally the "loopback" configuration is second (index 1) so
+ * it's not the default. Here's where to change that order, to
+- * work better with hosts where config changes are problematic.
+- * Or controllers (like superh) that only support one config.
++ * work better with hosts where config changes are problematic or
++ * controllers (like original superh) that only support one config.
+ */
+ static int loopdefault = 0;
+ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
+@@ -156,24 +92,6 @@ module_param(loopdefault, bool, S_IRUGO|
+
+ /*-------------------------------------------------------------------------*/
+
+-/*
+- * DESCRIPTORS ... most are static, but strings and (full)
+- * configuration descriptors are built on demand.
+- */
+-
+-#define STRING_MANUFACTURER 25
+-#define STRING_PRODUCT 42
+-#define STRING_SERIAL 101
+-#define STRING_SOURCE_SINK 250
+-#define STRING_LOOPBACK 251
+-
+-/*
+- * This device advertises two configurations; these numbers work
+- * on a pxa250 as well as more flexible hardware.
+- */
+-#define CONFIG_SOURCE_SINK 3
+-#define CONFIG_LOOPBACK 2
+-
+ static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+@@ -183,248 +101,64 @@ static struct usb_device_descriptor devi
+
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+- .iManufacturer = STRING_MANUFACTURER,
+- .iProduct = STRING_PRODUCT,
+- .iSerialNumber = STRING_SERIAL,
+ .bNumConfigurations = 2,
+ };
+
+-static struct usb_config_descriptor source_sink_config = {
+- .bLength = sizeof source_sink_config,
+- .bDescriptorType = USB_DT_CONFIG,
+-
+- /* compute wTotalLength on the fly */
+- .bNumInterfaces = 1,
+- .bConfigurationValue = CONFIG_SOURCE_SINK,
+- .iConfiguration = STRING_SOURCE_SINK,
+- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+- .bMaxPower = 1, /* self-powered */
+-};
+-
+-static struct usb_config_descriptor loopback_config = {
+- .bLength = sizeof loopback_config,
+- .bDescriptorType = USB_DT_CONFIG,
+-
+- /* compute wTotalLength on the fly */
+- .bNumInterfaces = 1,
+- .bConfigurationValue = CONFIG_LOOPBACK,
+- .iConfiguration = STRING_LOOPBACK,
+- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+- .bMaxPower = 1, /* self-powered */
+-};
+-
++#ifdef CONFIG_USB_OTG
+ static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+
+- .bmAttributes = USB_OTG_SRP,
+-};
+-
+-/* one interface in each configuration */
+-
+-static const struct usb_interface_descriptor source_sink_intf = {
+- .bLength = sizeof source_sink_intf,
+- .bDescriptorType = USB_DT_INTERFACE,
+-
+- .bNumEndpoints = 2,
+- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+- .iInterface = STRING_SOURCE_SINK,
+-};
+-
+-static const struct usb_interface_descriptor loopback_intf = {
+- .bLength = sizeof loopback_intf,
+- .bDescriptorType = USB_DT_INTERFACE,
+-
+- .bNumEndpoints = 2,
+- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+- .iInterface = STRING_LOOPBACK,
+-};
+-
+-/* two full speed bulk endpoints; their use is config-dependent */
+-
+-static struct usb_endpoint_descriptor fs_source_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+-
+- .bEndpointAddress = USB_DIR_IN,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static struct usb_endpoint_descriptor fs_sink_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+-
+- .bEndpointAddress = USB_DIR_OUT,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static const struct usb_descriptor_header *fs_source_sink_function[] = {
+- (struct usb_descriptor_header *) &otg_descriptor,
+- (struct usb_descriptor_header *) &source_sink_intf,
+- (struct usb_descriptor_header *) &fs_sink_desc,
+- (struct usb_descriptor_header *) &fs_source_desc,
+- NULL,
+-};
+-
+-static const struct usb_descriptor_header *fs_loopback_function[] = {
+- (struct usb_descriptor_header *) &otg_descriptor,
+- (struct usb_descriptor_header *) &loopback_intf,
+- (struct usb_descriptor_header *) &fs_sink_desc,
+- (struct usb_descriptor_header *) &fs_source_desc,
+- NULL,
+-};
+-
+-/*
+- * usb 2.0 devices need to expose both high speed and full speed
+- * descriptors, unless they only run at full speed.
+- *
+- * that means alternate endpoint descriptors (bigger packets)
+- * and a "device qualifier" ... plus more construction options
+- * for the config descriptor.
+- */
+-
+-static struct usb_endpoint_descriptor hs_source_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+-
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+- .wMaxPacketSize = __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_endpoint_descriptor hs_sink_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+-
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+- .wMaxPacketSize = __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_qualifier_descriptor dev_qualifier = {
+- .bLength = sizeof dev_qualifier,
+- .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+-
+- .bcdUSB = __constant_cpu_to_le16(0x0200),
+- .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+-
+- .bNumConfigurations = 2,
++ /* REVISIT SRP-only hardware is possible, although
++ * it would not be called "OTG" ...
++ */
++ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+ };
+
+-static const struct usb_descriptor_header *hs_source_sink_function[] = {
++const struct usb_descriptor_header **otg_desc = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+- (struct usb_descriptor_header *) &source_sink_intf,
+- (struct usb_descriptor_header *) &hs_source_desc,
+- (struct usb_descriptor_header *) &hs_sink_desc,
+ NULL,
+ };
++#endif
+
+-static const struct usb_descriptor_header *hs_loopback_function[] = {
+- (struct usb_descriptor_header *) &otg_descriptor,
+- (struct usb_descriptor_header *) &loopback_intf,
+- (struct usb_descriptor_header *) &hs_source_desc,
+- (struct usb_descriptor_header *) &hs_sink_desc,
+- NULL,
+-};
++/* string IDs are assigned dynamically */
+
+-/* maxpacket and other transfer characteristics vary by speed. */
+-static inline struct usb_endpoint_descriptor *
+-ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+- struct usb_endpoint_descriptor *fs)
+-{
+- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+- return hs;
+- return fs;
+-}
++#define STRING_MANUFACTURER_IDX 0
++#define STRING_PRODUCT_IDX 1
++#define STRING_SERIAL_IDX 2
+
+ static char manufacturer[50];
+
+ /* default serial number takes at least two packets */
+ static char serial[] = "0123456789.0123456789.0123456789";
+
+-
+-/* static strings, in UTF-8 */
+-static struct usb_string strings[] = {
+- { STRING_MANUFACTURER, manufacturer, },
+- { STRING_PRODUCT, longname, },
+- { STRING_SERIAL, serial, },
+- { STRING_LOOPBACK, loopback, },
+- { STRING_SOURCE_SINK, source_sink, },
++static struct usb_string strings_dev[] = {
++ [STRING_MANUFACTURER_IDX].s = manufacturer,
++ [STRING_PRODUCT_IDX].s = longname,
++ [STRING_SERIAL_IDX].s = serial,
+ { } /* end of list */
+ };
+
+-static struct usb_gadget_strings stringtab = {
++static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+- .strings = strings,
++ .strings = strings_dev,
+ };
+
+-/*
+- * config descriptors are also handcrafted. these must agree with code
+- * that sets configurations, and with code managing interfaces and their
+- * altsettings. other complexity may come from:
+- *
+- * - high speed support, including "other speed config" rules
+- * - multiple configurations
+- * - interfaces with alternate settings
+- * - embedded class or vendor-specific descriptors
+- *
+- * this handles high speed, and has a second config that could as easily
+- * have been an alternate interface setting (on most hardware).
+- *
+- * NOTE: to demonstrate (and test) more USB capabilities, this driver
+- * should include an altsetting to test interrupt transfers, including
+- * high bandwidth modes at high speed. (Maybe work like Intel's test
+- * device?)
+- */
+-static int config_buf(struct usb_gadget *gadget,
+- u8 *buf, u8 type, unsigned index)
+-{
+- int is_source_sink;
+- int len;
+- const struct usb_descriptor_header **function;
+- int hs = 0;
+-
+- /* two configurations will always be index 0 and index 1 */
+- if (index > 1)
+- return -EINVAL;
+- is_source_sink = loopdefault ? (index == 1) : (index == 0);
+-
+- if (gadget_is_dualspeed(gadget)) {
+- hs = (gadget->speed == USB_SPEED_HIGH);
+- if (type == USB_DT_OTHER_SPEED_CONFIG)
+- hs = !hs;
+- }
+- if (hs)
+- function = is_source_sink
+- ? hs_source_sink_function
+- : hs_loopback_function;
+- else
+- function = is_source_sink
+- ? fs_source_sink_function
+- : fs_loopback_function;
+-
+- /* for now, don't advertise srp-only devices */
+- if (!gadget_is_otg(gadget))
+- function++;
+-
+- len = usb_gadget_config_buf(is_source_sink
+- ? &source_sink_config
+- : &loopback_config,
+- buf, USB_BUFSIZ, function);
+- if (len < 0)
+- return len;
+- ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+- return len;
+-}
++static struct usb_gadget_strings *dev_strings[] = {
++ &stringtab_dev,
++ NULL,
++};
+
+ /*-------------------------------------------------------------------------*/
+
+-static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
++struct usb_request *alloc_ep_req(struct usb_ep *ep)
+ {
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (req) {
+- req->length = length;
+- req->buf = kmalloc(length, GFP_ATOMIC);
++ req->length = buflen;
++ req->buf = kmalloc(buflen, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ req = NULL;
+@@ -433,681 +167,73 @@ static struct usb_request *alloc_ep_req(
+ return req;
+ }
+
+-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
++void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+ {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+- * this just sinks bulk packets OUT to the peripheral and sources them IN
+- * to the host, optionally with specific data patterns.
+- *
+- * In terms of control messaging, this supports all the standard requests
+- * plus two that support control-OUT tests.
+- *
+- * Note that because this doesn't queue more than one request at a time,
+- * some other function must be used to test queueing logic. The network
+- * link (g_ether) is probably the best option for that.
+- */
+-
+-/* optionally require specific source/sink data patterns */
+-
+-static int
+-check_read_data(
+- struct zero_dev *dev,
+- struct usb_ep *ep,
+- struct usb_request *req
+-)
+-{
+- unsigned i;
+- u8 *buf = req->buf;
+-
+- for (i = 0; i < req->actual; i++, buf++) {
+- switch (pattern) {
+- /* all-zeroes has no synchronization issues */
+- case 0:
+- if (*buf == 0)
+- continue;
+- break;
+- /* mod63 stays in sync with short-terminated transfers,
+- * or otherwise when host and gadget agree on how large
+- * each usb transfer request should be. resync is done
+- * with set_interface or set_config.
+- */
+- case 1:
+- if (*buf == (u8)(i % 63))
+- continue;
+- break;
+- }
+- ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+- usb_ep_set_halt(ep);
+- return -EINVAL;
+- }
+- return 0;
+-}
+-
+-static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
+-{
+- unsigned i;
+- u8 *buf = req->buf;
+-
+- switch (pattern) {
+- case 0:
+- memset(req->buf, 0, req->length);
+- break;
+- case 1:
+- for (i = 0; i < req->length; i++)
+- *buf++ = (u8) (i % 63);
+- break;
+- }
+-}
+-
+-/* if there is only one request in the queue, there'll always be an
+- * irq delay between end of one request and start of the next.
+- * that prevents using hardware dma queues.
+- */
+-static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
++static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
+ {
+- struct zero_dev *dev = ep->driver_data;
+- int status = req->status;
+-
+- switch (status) {
+-
+- case 0: /* normal completion? */
+- if (ep == dev->out_ep) {
+- check_read_data(dev, ep, req);
+- memset(req->buf, 0x55, req->length);
+- } else
+- reinit_write_data(ep, req);
+- break;
+-
+- /* this endpoint is normally active while we're configured */
+- case -ECONNABORTED: /* hardware forced ep reset */
+- case -ECONNRESET: /* request dequeued */
+- case -ESHUTDOWN: /* disconnect from host */
+- VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
+- req->actual, req->length);
+- if (ep == dev->out_ep)
+- check_read_data(dev, ep, req);
+- free_ep_req(ep, req);
+- return;
+-
+- case -EOVERFLOW: /* buffer overrun on read means that
+- * we didn't provide a big enough
+- * buffer.
+- */
+- default:
+-#if 1
+- DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
+- status, req->actual, req->length);
+-#endif
+- case -EREMOTEIO: /* short read */
+- break;
+- }
++ int value;
+
+- status = usb_ep_queue(ep, req, GFP_ATOMIC);
+- if (status) {
+- ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
+- ep->name, req->length, status);
+- usb_ep_set_halt(ep);
+- /* FIXME recover later ... somehow */
++ if (ep->driver_data) {
++ value = usb_ep_disable(ep);
++ if (value < 0)
++ DBG(cdev, "disable %s --> %d\n",
++ ep->name, value);
++ ep->driver_data = NULL;
+ }
+ }
+
+-static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
++void disable_endpoints(struct usb_composite_dev *cdev,
++ struct usb_ep *in, struct usb_ep *out)
+ {
+- struct usb_request *req;
+- int status;
+-
+- req = alloc_ep_req(ep, buflen);
+- if (!req)
+- return NULL;
+-
+- memset(req->buf, 0, req->length);
+- req->complete = source_sink_complete;
+-
+- if (strcmp(ep->name, EP_IN_NAME) == 0)
+- reinit_write_data(ep, req);
+- else
+- memset(req->buf, 0x55, req->length);
+-
+- status = usb_ep_queue(ep, req, GFP_ATOMIC);
+- if (status) {
+- struct zero_dev *dev = ep->driver_data;
+-
+- ERROR(dev, "start %s --> %d\n", ep->name, status);
+- free_ep_req(ep, req);
+- req = NULL;
+- }
+-
+- return req;
+-}
+-
+-static int set_source_sink_config(struct zero_dev *dev)
+-{
+- int result = 0;
+- struct usb_ep *ep;
+- struct usb_gadget *gadget = dev->gadget;
+-
+- gadget_for_each_ep(ep, gadget) {
+- const struct usb_endpoint_descriptor *d;
+-
+- /* one endpoint writes (sources) zeroes in (to the host) */
+- if (strcmp(ep->name, EP_IN_NAME) == 0) {
+- d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+- result = usb_ep_enable(ep, d);
+- if (result == 0) {
+- ep->driver_data = dev;
+- if (source_sink_start_ep(ep) != NULL) {
+- dev->in_ep = ep;
+- continue;
+- }
+- usb_ep_disable(ep);
+- result = -EIO;
+- }
+-
+- /* one endpoint reads (sinks) anything out (from the host) */
+- } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+- d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+- result = usb_ep_enable(ep, d);
+- if (result == 0) {
+- ep->driver_data = dev;
+- if (source_sink_start_ep(ep) != NULL) {
+- dev->out_ep = ep;
+- continue;
+- }
+- usb_ep_disable(ep);
+- result = -EIO;
+- }
+-
+- /* ignore any other endpoints */
+- } else
+- continue;
+-
+- /* stop on error */
+- ERROR(dev, "can't start %s, result %d\n", ep->name, result);
+- break;
+- }
+- if (result == 0)
+- DBG(dev, "buflen %d\n", buflen);
+-
+- /* caller is responsible for cleanup on error */
+- return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+- struct zero_dev *dev = ep->driver_data;
+- int status = req->status;
+-
+- switch (status) {
+-
+- case 0: /* normal completion? */
+- if (ep == dev->out_ep) {
+- /* loop this OUT packet back IN to the host */
+- req->zero = (req->actual < req->length);
+- req->length = req->actual;
+- status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
+- if (status == 0)
+- return;
+-
+- /* "should never get here" */
+- ERROR(dev, "can't loop %s to %s: %d\n",
+- ep->name, dev->in_ep->name,
+- status);
+- }
+-
+- /* queue the buffer for some later OUT packet */
+- req->length = buflen;
+- status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+- if (status == 0)
+- return;
+-
+- /* "should never get here" */
+- /* FALLTHROUGH */
+-
+- default:
+- ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+- status, req->actual, req->length);
+- /* FALLTHROUGH */
+-
+- /* NOTE: since this driver doesn't maintain an explicit record
+- * of requests it submitted (just maintains qlen count), we
+- * rely on the hardware driver to clean up on disconnect or
+- * endpoint disable.
+- */
+- case -ECONNABORTED: /* hardware forced ep reset */
+- case -ECONNRESET: /* request dequeued */
+- case -ESHUTDOWN: /* disconnect from host */
+- free_ep_req(ep, req);
+- return;
+- }
+-}
+-
+-static int set_loopback_config(struct zero_dev *dev)
+-{
+- int result = 0;
+- struct usb_ep *ep;
+- struct usb_gadget *gadget = dev->gadget;
+-
+- gadget_for_each_ep(ep, gadget) {
+- const struct usb_endpoint_descriptor *d;
+-
+- /* one endpoint writes data back IN to the host */
+- if (strcmp(ep->name, EP_IN_NAME) == 0) {
+- d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+- result = usb_ep_enable(ep, d);
+- if (result == 0) {
+- ep->driver_data = dev;
+- dev->in_ep = ep;
+- continue;
+- }
+-
+- /* one endpoint just reads OUT packets */
+- } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+- d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+- result = usb_ep_enable(ep, d);
+- if (result == 0) {
+- ep->driver_data = dev;
+- dev->out_ep = ep;
+- continue;
+- }
+-
+- /* ignore any other endpoints */
+- } else
+- continue;
+-
+- /* stop on error */
+- ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
+- break;
+- }
+-
+- /* allocate a bunch of read buffers and queue them all at once.
+- * we buffer at most 'qlen' transfers; fewer if any need more
+- * than 'buflen' bytes each.
+- */
+- if (result == 0) {
+- struct usb_request *req;
+- unsigned i;
+-
+- ep = dev->out_ep;
+- for (i = 0; i < qlen && result == 0; i++) {
+- req = alloc_ep_req(ep, buflen);
+- if (req) {
+- req->complete = loopback_complete;
+- result = usb_ep_queue(ep, req, GFP_ATOMIC);
+- if (result)
+- DBG(dev, "%s queue req --> %d\n",
+- ep->name, result);
+- } else
+- result = -ENOMEM;
+- }
+- }
+- if (result == 0)
+- DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
+-
+- /* caller is responsible for cleanup on error */
+- return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_reset_config(struct zero_dev *dev)
+-{
+- if (dev->config == 0)
+- return;
+-
+- DBG(dev, "reset config\n");
+-
+- /* just disable endpoints, forcing completion of pending i/o.
+- * all our completion handlers free their requests in this case.
+- */
+- if (dev->in_ep) {
+- usb_ep_disable(dev->in_ep);
+- dev->in_ep = NULL;
+- }
+- if (dev->out_ep) {
+- usb_ep_disable(dev->out_ep);
+- dev->out_ep = NULL;
+- }
+- dev->config = 0;
+- del_timer(&dev->resume);
+-}
+-
+-/* change our operational config. this code must agree with the code
+- * that returns config descriptors, and altsetting code.
+- *
+- * it's also responsible for power management interactions. some
+- * configurations might not work with our current power sources.
+- *
+- * note that some device controller hardware will constrain what this
+- * code can do, perhaps by disallowing more than one configuration or
+- * by limiting configuration choices (like the pxa2xx).
+- */
+-static int zero_set_config(struct zero_dev *dev, unsigned number)
+-{
+- int result = 0;
+- struct usb_gadget *gadget = dev->gadget;
+-
+- if (number == dev->config)
+- return 0;
+-
+- if (gadget_is_sa1100(gadget) && dev->config) {
+- /* tx fifo is full, but we can't clear it...*/
+- ERROR(dev, "can't change configurations\n");
+- return -ESPIPE;
+- }
+- zero_reset_config(dev);
+-
+- switch (number) {
+- case CONFIG_SOURCE_SINK:
+- result = set_source_sink_config(dev);
+- break;
+- case CONFIG_LOOPBACK:
+- result = set_loopback_config(dev);
+- break;
+- default:
+- result = -EINVAL;
+- /* FALL THROUGH */
+- case 0:
+- return result;
+- }
+-
+- if (!result && (!dev->in_ep || !dev->out_ep))
+- result = -ENODEV;
+- if (result)
+- zero_reset_config(dev);
+- else {
+- char *speed;
+-
+- switch (gadget->speed) {
+- case USB_SPEED_LOW: speed = "low"; break;
+- case USB_SPEED_FULL: speed = "full"; break;
+- case USB_SPEED_HIGH: speed = "high"; break;
+- default: speed = "?"; break;
+- }
+-
+- dev->config = number;
+- INFO(dev, "%s speed config #%d: %s\n", speed, number,
+- (number == CONFIG_SOURCE_SINK)
+- ? source_sink : loopback);
+- }
+- return result;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+- if (req->status || req->actual != req->length)
+- DBG((struct zero_dev *) ep->driver_data,
+- "setup complete --> %d, %d/%d\n",
+- req->status, req->actual, req->length);
+-}
+-
+-/*
+- * The setup() callback implements all the ep0 functionality that's
+- * not handled lower down, in hardware or the hardware driver (like
+- * device and endpoint feature flags, and their status). It's all
+- * housekeeping for the gadget function we're implementing. Most of
+- * the work is in config-specific setup.
+- */
+-static int
+-zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+-{
+- struct zero_dev *dev = get_gadget_data(gadget);
+- struct usb_request *req = dev->req;
+- int value = -EOPNOTSUPP;
+- u16 w_index = le16_to_cpu(ctrl->wIndex);
+- u16 w_value = le16_to_cpu(ctrl->wValue);
+- u16 w_length = le16_to_cpu(ctrl->wLength);
+-
+- /* usually this stores reply data in the pre-allocated ep0 buffer,
+- * but config change events will reconfigure hardware.
+- */
+- req->zero = 0;
+- switch (ctrl->bRequest) {
+-
+- case USB_REQ_GET_DESCRIPTOR:
+- if (ctrl->bRequestType != USB_DIR_IN)
+- goto unknown;
+- switch (w_value >> 8) {
+-
+- case USB_DT_DEVICE:
+- value = min(w_length, (u16) sizeof device_desc);
+- memcpy(req->buf, &device_desc, value);
+- break;
+- case USB_DT_DEVICE_QUALIFIER:
+- if (!gadget_is_dualspeed(gadget))
+- break;
+- value = min(w_length, (u16) sizeof dev_qualifier);
+- memcpy(req->buf, &dev_qualifier, value);
+- break;
+-
+- case USB_DT_OTHER_SPEED_CONFIG:
+- if (!gadget_is_dualspeed(gadget))
+- break;
+- // FALLTHROUGH
+- case USB_DT_CONFIG:
+- value = config_buf(gadget, req->buf,
+- w_value >> 8,
+- w_value & 0xff);
+- if (value >= 0)
+- value = min(w_length, (u16) value);
+- break;
+-
+- case USB_DT_STRING:
+- /* wIndex == language code.
+- * this driver only handles one language, you can
+- * add string tables for other languages, using
+- * any UTF-8 characters
+- */
+- value = usb_gadget_get_string(&stringtab,
+- w_value & 0xff, req->buf);
+- if (value >= 0)
+- value = min(w_length, (u16) value);
+- break;
+- }
+- break;
+-
+- /* currently two configs, two speeds */
+- case USB_REQ_SET_CONFIGURATION:
+- if (ctrl->bRequestType != 0)
+- goto unknown;
+- if (gadget->a_hnp_support)
+- DBG(dev, "HNP available\n");
+- else if (gadget->a_alt_hnp_support)
+- DBG(dev, "HNP needs a different root port\n");
+- else
+- VDBG(dev, "HNP inactive\n");
+- spin_lock(&dev->lock);
+- value = zero_set_config(dev, w_value);
+- spin_unlock(&dev->lock);
+- break;
+- case USB_REQ_GET_CONFIGURATION:
+- if (ctrl->bRequestType != USB_DIR_IN)
+- goto unknown;
+- *(u8 *)req->buf = dev->config;
+- value = min(w_length, (u16) 1);
+- break;
+-
+- /* until we add altsetting support, or other interfaces,
+- * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
+- * and already killed pending endpoint I/O.
+- */
+- case USB_REQ_SET_INTERFACE:
+- if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+- goto unknown;
+- spin_lock(&dev->lock);
+- if (dev->config && w_index == 0 && w_value == 0) {
+- u8 config = dev->config;
+-
+- /* resets interface configuration, forgets about
+- * previous transaction state (queued bufs, etc)
+- * and re-inits endpoint state (toggle etc)
+- * no response queued, just zero status == success.
+- * if we had more than one interface we couldn't
+- * use this "reset the config" shortcut.
+- */
+- zero_reset_config(dev);
+- zero_set_config(dev, config);
+- value = 0;
+- }
+- spin_unlock(&dev->lock);
+- break;
+- case USB_REQ_GET_INTERFACE:
+- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+- goto unknown;
+- if (!dev->config)
+- break;
+- if (w_index != 0) {
+- value = -EDOM;
+- break;
+- }
+- *(u8 *)req->buf = 0;
+- value = min(w_length, (u16) 1);
+- break;
+-
+- /*
+- * These are the same vendor-specific requests supported by
+- * Intel's USB 2.0 compliance test devices. We exceed that
+- * device spec by allowing multiple-packet requests.
+- */
+- case 0x5b: /* control WRITE test -- fill the buffer */
+- if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
+- goto unknown;
+- if (w_value || w_index)
+- break;
+- /* just read that many bytes into the buffer */
+- if (w_length > USB_BUFSIZ)
+- break;
+- value = w_length;
+- break;
+- case 0x5c: /* control READ test -- return the buffer */
+- if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
+- goto unknown;
+- if (w_value || w_index)
+- break;
+- /* expect those bytes are still in the buffer; send back */
+- if (w_length > USB_BUFSIZ
+- || w_length != req->length)
+- break;
+- value = w_length;
+- break;
+-
+- default:
+-unknown:
+- VDBG(dev,
+- "unknown control req%02x.%02x v%04x i%04x l%d\n",
+- ctrl->bRequestType, ctrl->bRequest,
+- w_value, w_index, w_length);
+- }
+-
+- /* respond with data transfer before status phase? */
+- if (value >= 0) {
+- req->length = value;
+- req->zero = value < w_length;
+- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+- if (value < 0) {
+- DBG(dev, "ep_queue --> %d\n", value);
+- req->status = 0;
+- zero_setup_complete(gadget->ep0, req);
+- }
+- }
+-
+- /* device either stalls (value < 0) or reports success */
+- return value;
+-}
+-
+-static void zero_disconnect(struct usb_gadget *gadget)
+-{
+- struct zero_dev *dev = get_gadget_data(gadget);
+- unsigned long flags;
+-
+- spin_lock_irqsave(&dev->lock, flags);
+- zero_reset_config(dev);
+-
+- /* a more significant application might have some non-usb
+- * activities to quiesce here, saving resources like power
+- * or pushing the notification up a network stack.
+- */
+- spin_unlock_irqrestore(&dev->lock, flags);
+-
+- /* next we may get setup() calls to enumerate new connections;
+- * or an unbind() during shutdown (including removing module).
+- */
+-}
+-
+-static void zero_autoresume(unsigned long _dev)
+-{
+- struct zero_dev *dev = (struct zero_dev *) _dev;
+- int status;
+-
+- /* normally the host would be woken up for something
+- * more significant than just a timer firing...
+- */
+- if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+- status = usb_gadget_wakeup(dev->gadget);
+- DBG(dev, "wakeup --> %d\n", status);
+- }
++ disable_ep(cdev, in);
++ disable_ep(cdev, out);
+ }
+
+ /*-------------------------------------------------------------------------*/
+
+-static void zero_unbind(struct usb_gadget *gadget)
+-{
+- struct zero_dev *dev = get_gadget_data(gadget);
+-
+- DBG(dev, "unbind\n");
+-
+- /* we've already been disconnected ... no i/o is active */
+- if (dev->req) {
+- dev->req->length = USB_BUFSIZ;
+- free_ep_req(gadget->ep0, dev->req);
+- }
+- del_timer_sync(&dev->resume);
+- kfree(dev);
+- set_gadget_data(gadget, NULL);
+-}
+-
+-static int __init zero_bind(struct usb_gadget *gadget)
++static int __init zero_bind(struct usb_composite_dev *cdev)
+ {
+- struct zero_dev *dev;
+- struct usb_ep *ep;
+ int gcnum;
++ struct usb_gadget *gadget = cdev->gadget;
++ int id;
+
+- /* FIXME this can't yet work right with SH ... it has only
+- * one configuration, numbered one.
+- */
+- if (gadget_is_sh(gadget))
+- return -ENODEV;
+-
+- /* Bulk-only drivers like this one SHOULD be able to
+- * autoconfigure on any sane usb controller driver,
+- * but there may also be important quirks to address.
++ /* Allocate string descriptor numbers ... note that string
++ * contents can be overridden by the composite_dev glue.
+ */
+- usb_ep_autoconfig_reset(gadget);
+- ep = usb_ep_autoconfig(gadget, &fs_source_desc);
+- if (!ep) {
+-autoconf_fail:
+- pr_err("%s: can't autoconfigure on %s\n",
+- shortname, gadget->name);
+- return -ENODEV;
++ 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 primary, then secondary configuration. Note that
++ * SH3 only allows one config...
++ */
++ if (loopdefault) {
++ loopback_add(cdev);
++ if (!gadget_is_sh(gadget))
++ sourcesink_add(cdev);
++ } else {
++ sourcesink_add(cdev);
++ if (!gadget_is_sh(gadget))
++ loopback_add(cdev);
+ }
+- EP_IN_NAME = ep->name;
+- ep->driver_data = ep; /* claim */
+-
+- ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
+- if (!ep)
+- goto autoconf_fail;
+- EP_OUT_NAME = ep->name;
+- ep->driver_data = ep; /* claim */
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+@@ -1115,144 +241,44 @@ autoconf_fail:
+ else {
+ /* gadget zero is so simple (for now, no altsettings) that
+ * it SHOULD NOT have problems with bulk-capable hardware.
+- * so warn about unrcognized controllers, don't panic.
++ * 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",
+- shortname, gadget->name);
++ longname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ }
+
+
+- /* ok, we made sense of the hardware ... */
+- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (!dev)
+- return -ENOMEM;
+- spin_lock_init(&dev->lock);
+- dev->gadget = gadget;
+- set_gadget_data(gadget, dev);
+-
+- init_timer(&dev->resume);
+- dev->resume.function = zero_autoresume;
+- dev->resume.data = (unsigned long) dev;
+-
+- /* preallocate control response and buffer */
+- dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+- if (!dev->req)
+- goto enomem;
+- dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+- if (!dev->req->buf)
+- goto enomem;
+-
+- dev->req->complete = zero_setup_complete;
+-
+- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+-
+- if (gadget_is_dualspeed(gadget)) {
+- /* assume ep0 uses the same value for both speeds ... */
+- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+-
+- /* and that all endpoints are dual-speed */
+- hs_source_desc.bEndpointAddress =
+- fs_source_desc.bEndpointAddress;
+- hs_sink_desc.bEndpointAddress =
+- fs_sink_desc.bEndpointAddress;
+- }
+-
+- if (gadget_is_otg(gadget)) {
+- otg_descriptor.bmAttributes |= USB_OTG_HNP,
+- source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- }
+-
+- usb_gadget_set_selfpowered(gadget);
+-
+- if (autoresume) {
+- source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- }
+-
+- gadget->ep0->driver_data = dev;
+-
+- INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+- INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
+- EP_OUT_NAME, EP_IN_NAME);
++ INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
+
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+
+ return 0;
+-
+-enomem:
+- zero_unbind(gadget);
+- return -ENOMEM;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void zero_suspend(struct usb_gadget *gadget)
+-{
+- struct zero_dev *dev = get_gadget_data(gadget);
+-
+- if (gadget->speed == USB_SPEED_UNKNOWN)
+- return;
+-
+- if (autoresume) {
+- mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+- DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
+- } else
+- DBG(dev, "suspend\n");
+-}
+-
+-static void zero_resume(struct usb_gadget *gadget)
+-{
+- struct zero_dev *dev = get_gadget_data(gadget);
+-
+- DBG(dev, "resume\n");
+- del_timer(&dev->resume);
+ }
+
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static struct usb_gadget_driver zero_driver = {
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+- .speed = USB_SPEED_HIGH,
+-#else
+- .speed = USB_SPEED_FULL,
+-#endif
+- .function = (char *) longname,
++static struct usb_composite_driver zero_driver = {
++ .name = "zero",
++ .dev = &device_desc,
++ .strings = dev_strings,
+ .bind = zero_bind,
+- .unbind = __exit_p(zero_unbind),
+-
+- .setup = zero_setup,
+- .disconnect = zero_disconnect,
+-
+- .suspend = zero_suspend,
+- .resume = zero_resume,
+-
+- .driver = {
+- .name = (char *) shortname,
+- .owner = THIS_MODULE,
+- },
+ };
+
+ MODULE_AUTHOR("David Brownell");
+ MODULE_LICENSE("GPL");
+
+-
+ static int __init init(void)
+ {
+- return usb_gadget_register_driver(&zero_driver);
++ return usb_composite_register(&zero_driver);
+ }
+ module_init(init);
+
+ static void __exit cleanup(void)
+ {
+- usb_gadget_unregister_driver(&zero_driver);
++ usb_composite_unregister(&zero_driver);
+ }
+ module_exit(cleanup);
+-
diff --git a/usb/usb-hiddev-switch-to-unlocked_ioctl.patch b/usb/usb-hiddev-switch-to-unlocked_ioctl.patch
new file mode 100644
index 00000000000000..e9bcea751f06e6
--- /dev/null
+++ b/usb/usb-hiddev-switch-to-unlocked_ioctl.patch
@@ -0,0 +1,74 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:14:50 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:22:17 +0100
+Subject: USB: hiddev: Switch to unlocked_ioctl
+To: linux-kernel@vger.kernel.org, dmitry.torokhov@gmail.com, linux-usb@vger.kernel.org
+Message-ID: <20080522222217.3a785487@core>
+
+
+Push down the BKL. In some cases compat_ioctl already doesn't take the
+BKL so we don't either. Some of the locking here seems already dubious
+and object lifetimes want documenting
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hid/usbhid/hiddev.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/hid/usbhid/hiddev.c
++++ b/drivers/hid/usbhid/hiddev.c
+@@ -406,6 +406,7 @@ static noinline int hiddev_ioctl_usage(s
+ uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+ if (!uref_multi)
+ return -ENOMEM;
++ lock_kernel();
+ uref = &uref_multi->uref;
+ if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+ if (copy_from_user(uref_multi, user_arg,
+@@ -501,12 +502,15 @@ static noinline int hiddev_ioctl_usage(s
+ }
+
+ goodreturn:
++ unlock_kernel();
+ kfree(uref_multi);
+ return 0;
+ fault:
++ unlock_kernel();
+ kfree(uref_multi);
+ return -EFAULT;
+ inval:
++ unlock_kernel();
+ kfree(uref_multi);
+ return -EINVAL;
+ }
+@@ -540,7 +544,7 @@ static noinline int hiddev_ioctl_string(
+ return len;
+ }
+
+-static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct hiddev_list *list = file->private_data;
+ struct hiddev *hiddev = list->hiddev;
+@@ -555,7 +559,10 @@ static int hiddev_ioctl(struct inode *in
+ struct usbhid_device *usbhid = hid->driver_data;
+ void __user *user_arg = (void __user *)arg;
+ int i;
++
++ /* Called without BKL by compat methods so no BKL taken */
+
++ /* FIXME: Who or what stop this racing with a disconnect ?? */
+ if (!hiddev->exist)
+ return -EIO;
+
+@@ -768,7 +775,7 @@ static const struct file_operations hidd
+ .poll = hiddev_poll,
+ .open = hiddev_open,
+ .release = hiddev_release,
+- .ioctl = hiddev_ioctl,
++ .unlocked_ioctl = hiddev_ioctl,
+ .fasync = hiddev_fasync,
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = hiddev_compat_ioctl,
diff --git a/usb/usb-iowarrior-push-down-bkl.patch b/usb/usb-iowarrior-push-down-bkl.patch
new file mode 100644
index 00000000000000..d98ecba9b12531
--- /dev/null
+++ b/usb/usb-iowarrior-push-down-bkl.patch
@@ -0,0 +1,57 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:14:34 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:06:02 +0100
+Subject: USB: iowarrior: Push down BKL
+To: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
+Message-ID: <20080522220602.31397da8@core>
+
+
+I'm pretty sure the mutex is sufficient for all locking but will come
+back to that later if the USB folks don't beat me to it. For now get rid
+of the old BKL ioctl method and wrap the ioctl handler
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/iowarrior.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/misc/iowarrior.c
++++ b/drivers/usb/misc/iowarrior.c
+@@ -474,8 +474,8 @@ exit:
+ /**
+ * iowarrior_ioctl
+ */
+-static int iowarrior_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
++static long iowarrior_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
+ {
+ struct iowarrior *dev = NULL;
+ __u8 *buffer;
+@@ -493,6 +493,7 @@ static int iowarrior_ioctl(struct inode
+ return -ENOMEM;
+
+ /* lock this object */
++ lock_kernel();
+ mutex_lock(&dev->mutex);
+
+ /* verify that the device wasn't unplugged */
+@@ -584,6 +585,7 @@ static int iowarrior_ioctl(struct inode
+ error_out:
+ /* unlock the device */
+ mutex_unlock(&dev->mutex);
++ unlock_kernel();
+ kfree(buffer);
+ return retval;
+ }
+@@ -719,7 +721,7 @@ static const struct file_operations iowa
+ .owner = THIS_MODULE,
+ .write = iowarrior_write,
+ .read = iowarrior_read,
+- .ioctl = iowarrior_ioctl,
++ .unlocked_ioctl = iowarrior_ioctl,
+ .open = iowarrior_open,
+ .release = iowarrior_release,
+ .poll = iowarrior_poll,
diff --git a/usb/usb-make-sa1111-ohci-driver-sa11x0-specific.patch b/usb/usb-make-sa1111-ohci-driver-sa11x0-specific.patch
new file mode 100644
index 00000000000000..9d317c1ddc4713
--- /dev/null
+++ b/usb/usb-make-sa1111-ohci-driver-sa11x0-specific.patch
@@ -0,0 +1,35 @@
+From eric.y.miao@gmail.com Fri Jun 6 15:19:15 2008
+From: Eric Miao <eric.y.miao@gmail.com>
+Date: Mon, 02 Jun 2008 10:05:30 +0800
+Subject: USB: make SA1111 OHCI driver SA11x0 specific
+To: linux-usb@vger.kernel.org
+Cc: David Brownell <david-b@pacbell.net>, Russell King - ARM Linux <linux@arm.linux.org.uk>
+Message-ID: <4843556A.5080905@gmail.com>
+
+
+
+As RMK pointed out, considering the fact that the _only_ platform with
+a PXA and SA1111 is the Lubbock, and that SA1111 DMA doesn't work there,
+(i.e. the SA1111 OHCI doesn't work there) the SA1111 OHCI driver should
+really be made SA11x0 specific.
+
+Signed-off-by: Eric Miao <eric.miao@marvell.com>
+Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-hcd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -974,7 +974,7 @@ MODULE_LICENSE ("GPL");
+ #define PCI_DRIVER ohci_pci_driver
+ #endif
+
+-#ifdef CONFIG_SA1111
++#if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111)
+ #include "ohci-sa1111.c"
+ #define SA1111_DRIVER ohci_hcd_sa1111_driver
+ #endif
diff --git a/usb/usb-missing-usb_put_hcd-to-ohci-at91.patch b/usb/usb-missing-usb_put_hcd-to-ohci-at91.patch
new file mode 100644
index 00000000000000..1cbcbb251ad28e
--- /dev/null
+++ b/usb/usb-missing-usb_put_hcd-to-ohci-at91.patch
@@ -0,0 +1,65 @@
+From zaitcev@redhat.com Fri Jun 6 15:18:50 2008
+From: Pete Zaitcev <zaitcev@redhat.com>
+Date: Sun, 1 Jun 2008 14:38:43 -0700
+Subject: USB: missing usb_put_hcd to ohci-at91
+To: linux-usb@vger.kernel.org
+Cc: linux@maxim.org.za, zaitcev@redhat.com
+Message-ID: <20080601143843.5ba394db.zaitcev@redhat.com>
+
+
+Looks like usb_put_hcd was missing. Also, make an always-zero function
+return void.
+
+Signed-off-by: Pete Zaitcev <zaitcev@yahoo.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-at91.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -91,7 +91,7 @@ static void at91_stop_hc(struct platform
+
+ /*-------------------------------------------------------------------------*/
+
+-static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
++static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
+
+ /* configure so an HC device and id are always provided */
+ /* always called with process context; sleeping is OK */
+@@ -184,13 +184,14 @@ static int usb_hcd_at91_probe(const stru
+ * context, "rmmod" or something similar.
+ *
+ */
+-static int usb_hcd_at91_remove(struct usb_hcd *hcd,
++static void usb_hcd_at91_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
+ {
+ usb_remove_hcd(hcd);
+ at91_stop_hc(pdev);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
+
+ if (cpu_is_at91sam9261())
+ clk_put(hclk);
+@@ -199,7 +200,6 @@ static int usb_hcd_at91_remove(struct us
+ fclk = iclk = hclk = NULL;
+
+ dev_set_drvdata(&pdev->dev, NULL);
+- return 0;
+ }
+
+ /*-------------------------------------------------------------------------*/
+@@ -308,7 +308,8 @@ static int ohci_hcd_at91_drv_remove(stru
+ }
+
+ device_init_wakeup(&pdev->dev, 0);
+- return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
++ usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
++ return 0;
+ }
+
+ #ifdef CONFIG_PM
diff --git a/usb/usb-ohci-ppc-of-use-linux-of_platform.h-instead-of-asm.patch b/usb/usb-ohci-ppc-of-use-linux-of_platform.h-instead-of-asm.patch
new file mode 100644
index 00000000000000..b182fb85b74d3b
--- /dev/null
+++ b/usb/usb-ohci-ppc-of-use-linux-of_platform.h-instead-of-asm.patch
@@ -0,0 +1,29 @@
+From sfr@canb.auug.org.au Fri Jun 6 15:16:28 2008
+From: Stephen Rothwell <sfr@canb.auug.org.au>
+Date: Fri, 23 May 2008 16:37:58 +1000
+Subject: USB: ohci-ppc-of: use linux/of_platform.h instead of asm
+To: Sylvain Munaut <tnt@246tNt.com>
+Cc: ppc-dev <linuxppc-dev@ozlabs.org>, Greg KH <greg@kroah.com>
+Message-ID: <20080523163758.4edcdef4.sfr@canb.auug.org.au>
+
+
+
+Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-ppc-of.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/ohci-ppc-of.c
++++ b/drivers/usb/host/ohci-ppc-of.c
+@@ -14,8 +14,8 @@
+ */
+
+ #include <linux/signal.h>
++#include <linux/of_platform.h>
+
+-#include <asm/of_platform.h>
+ #include <asm/prom.h>
+
+
diff --git a/usb/usb-ohci_hcd-hang-submit-vs.-rmmod-race.patch b/usb/usb-ohci_hcd-hang-submit-vs.-rmmod-race.patch
new file mode 100644
index 00000000000000..53adab2165ee65
--- /dev/null
+++ b/usb/usb-ohci_hcd-hang-submit-vs.-rmmod-race.patch
@@ -0,0 +1,49 @@
+From zaitcev@redhat.com Fri Jun 6 15:19:36 2008
+From: Pete Zaitcev <zaitcev@redhat.com>
+Date: Sun, 1 Jun 2008 21:23:07 -0700
+Subject: USB: ohci_hcd hang: submit vs. rmmod race
+To: greg@kroah.com
+Cc: linux-usb@vger.kernel.org, zaitcev@redhat.com
+Message-ID: <20080601212307.f01b8089.zaitcev@redhat.com>
+
+
+If we do rmmod ohci_hcd while an application is doing something, the
+following may happen:
+
+- a control URB completes (in finish_urb) and the ohci's endpoint is
+ set into ED_UNLINK in ed_deschedule
+- same URB is (re)submitted because of the open/close loop or other
+ such application behaviour
+- rmmod sets the state to HC_STATE_QUESCING
+- finish_unlinks happens at next SOF; normally it would set ed into
+ ED_IDLE and immediately call ed_schedule (since URB had extra TDs
+ queued), which sets it into ED_OPER. But the check in ed_schedule
+ makes it fail with -EAGAIN (which is ignored)
+- from now on we have a dead URB stuck; it cannot even be unlinked
+ because the ed status is not ED_OPER, and thus start_ed_unlink is
+ not invoked.
+
+This patch removes the check. In 2.6.25, all callers check for
+__ACTIVE bit before invoking ed_schedule, which is more appropriate.
+
+Alan Stern and David Brownell approved of this (cautiously).
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ohci-q.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/usb/host/ohci-q.c
++++ b/drivers/usb/host/ohci-q.c
+@@ -159,9 +159,6 @@ static int ed_schedule (struct ohci_hcd
+ {
+ int branch;
+
+- if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
+- return -EAGAIN;
+-
+ ed->state = ED_OPER;
+ ed->ed_prev = NULL;
+ ed->ed_next = NULL;
diff --git a/usb/usb-rio100-push-down-the-bkl.patch b/usb/usb-rio100-push-down-the-bkl.patch
new file mode 100644
index 00000000000000..941e20ed384b79
--- /dev/null
+++ b/usb/usb-rio100-push-down-the-bkl.patch
@@ -0,0 +1,56 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:15:16 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:47:31 +0100
+Subject: USB: rio100: Push down the BKL
+To: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
+Message-ID: <20080522224731.10cdac01@core>
+
+
+The BKL is actually probably not needed as the mutex seems sufficient. If
+so then a further patch to drop it would be a good followup.
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/rio500.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/misc/rio500.c
++++ b/drivers/usb/misc/rio500.c
+@@ -104,9 +104,7 @@ static int close_rio(struct inode *inode
+ return 0;
+ }
+
+-static int
+-ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
+- unsigned long arg)
++static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct RioCommand rio_cmd;
+ struct rio_usb_data *rio = &rio_instance;
+@@ -116,6 +114,7 @@ ioctl_rio(struct inode *inode, struct fi
+ int retries;
+ int retval=0;
+
++ lock_kernel();
+ mutex_lock(&(rio->lock));
+ /* Sanity check to make sure rio is connected, powered, etc */
+ if (rio->present == 0 || rio->rio_dev == NULL) {
+@@ -254,6 +253,7 @@ ioctl_rio(struct inode *inode, struct fi
+
+ err_out:
+ mutex_unlock(&(rio->lock));
++ unlock_kernel();
+ return retval;
+ }
+
+@@ -433,7 +433,7 @@ file_operations usb_rio_fops = {
+ .owner = THIS_MODULE,
+ .read = read_rio,
+ .write = write_rio,
+- .ioctl = ioctl_rio,
++ .unlocked_ioctl = ioctl_rio,
+ .open = open_rio,
+ .release = close_rio,
+ };
diff --git a/usb/usb-serial-gadget-cdc-acm-function-driver.patch b/usb/usb-serial-gadget-cdc-acm-function-driver.patch
new file mode 100644
index 00000000000000..f9b59ca1746408
--- /dev/null
+++ b/usb/usb-serial-gadget-cdc-acm-function-driver.patch
@@ -0,0 +1,681 @@
+From david-b@pacbell.net Fri Jun 6 15:11:23 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:10:52 -0700
+Subject: usb serial gadget: cdc acm function driver
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201110.52928.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+Split out CDC ACM parts of "gadget serial" to a "function driver".
+Some key structural differences from the previous ACM support, shared
+with with the generic serial function (next patch):
+
+ - As a function driver, it can be combined with other functions.
+ One gadget configuration could offer both serial and network
+ links, as an example.
+
+ - One serial port can be exposed in multiple configurations;
+ the /dev/ttyGS0 node could be exposed regardless of which
+ config the host selected.
+
+ - One configuration can expose multiple serial ports, such as
+ ttyGS0, ttyGS1, ttyGS2, and ttyGS3.
+
+This code should be a lot easier to understand than the previous
+all-in-one-big-file version of the driver.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/gadget.tmpl | 2
+ drivers/usb/gadget/Makefile | 2
+ drivers/usb/gadget/f_acm.c | 587 ++++++++++++++++++++++++++++++++++++++
+ drivers/usb/gadget/u_serial.h | 10
+ 4 files changed, 595 insertions(+), 6 deletions(-)
+
+--- a/Documentation/DocBook/gadget.tmpl
++++ b/Documentation/DocBook/gadget.tmpl
+@@ -556,6 +556,8 @@ been converted to this framework.
+ Near-term plans include converting all of them, except for "gadgetfs".
+ </para>
+
++!Edrivers/usb/gadget/f_acm.c
++
+ </sect1>
+
+
+--- /dev/null
++++ b/drivers/usb/gadget/f_acm.c
+@@ -0,0 +1,587 @@
++/*
++ * f_acm.c -- USB CDC ACM function driver
++ *
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 by David Brownell
++ *
++ * This software is 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.
++ */
++
++/* #define VERBOSE_DEBUG */
++
++#include <linux/kernel.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++
++#include "u_serial.h"
++#include "gadget_chips.h"
++
++
++/*
++ * This CDC ACM function support just wraps control functions and
++ * notifications around the generic serial-over-usb code.
++ *
++ * Because CDC ACM is standardized by the USB-IF, many host operating
++ * systems have drivers for it. Accordingly, ACM is the preferred
++ * interop solution for serial-port type connections. The control
++ * models are often not necessary, and in any case don't do much in
++ * this bare-bones implementation.
++ */
++
++struct acm_ep_descs {
++ struct usb_endpoint_descriptor *in;
++ struct usb_endpoint_descriptor *out;
++ struct usb_endpoint_descriptor *notify;
++};
++
++struct f_acm {
++ struct gserial port;
++ u8 ctrl_id, data_id;
++ u8 port_num;
++
++ struct usb_descriptor_header **fs_function;
++ struct acm_ep_descs fs;
++ struct usb_descriptor_header **hs_function;
++ struct acm_ep_descs hs;
++
++ struct usb_ep *notify;
++ struct usb_endpoint_descriptor *notify_desc;
++
++ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
++ u16 port_handshake_bits;
++#define RS232_RTS (1 << 1) /* unused with full duplex */
++#define RS232_DTR (1 << 0) /* host is ready for data r/w */
++};
++
++static inline struct f_acm *func_to_acm(struct usb_function *f)
++{
++ return container_of(f, struct f_acm, port.func);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* notification endpoint uses smallish and infrequent fixed-size messages */
++
++#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
++#define GS_NOTIFY_MAXPACKET 8
++
++/* interface and class descriptors: */
++
++static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ /* .bInterfaceNumber = DYNAMIC */
++ .bNumEndpoints = 1,
++ .bInterfaceClass = USB_CLASS_COMM,
++ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
++ .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
++ /* .iInterface = DYNAMIC */
++};
++
++static struct usb_interface_descriptor acm_data_interface_desc __initdata = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ /* .bInterfaceNumber = DYNAMIC */
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_CDC_DATA,
++ .bInterfaceSubClass = 0,
++ .bInterfaceProtocol = 0,
++ /* .iInterface = DYNAMIC */
++};
++
++static struct usb_cdc_header_desc acm_header_desc __initdata = {
++ .bLength = sizeof(acm_header_desc),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
++ .bcdCDC = __constant_cpu_to_le16(0x0110),
++};
++
++static struct usb_cdc_call_mgmt_descriptor
++acm_call_mgmt_descriptor __initdata = {
++ .bLength = sizeof(acm_call_mgmt_descriptor),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
++ .bmCapabilities = 0,
++ /* .bDataInterface = DYNAMIC */
++};
++
++static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
++ .bLength = sizeof(acm_descriptor),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubType = USB_CDC_ACM_TYPE,
++ .bmCapabilities = (1 << 1),
++};
++
++static struct usb_cdc_union_desc acm_union_desc __initdata = {
++ .bLength = sizeof(acm_union_desc),
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubType = USB_CDC_UNION_TYPE,
++ /* .bMasterInterface0 = DYNAMIC */
++ /* .bSlaveInterface0 = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_INT,
++ .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
++ .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
++};
++
++static struct usb_endpoint_descriptor acm_fs_in_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *acm_fs_function[] __initdata = {
++ (struct usb_descriptor_header *) &acm_control_interface_desc,
++ (struct usb_descriptor_header *) &acm_header_desc,
++ (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
++ (struct usb_descriptor_header *) &acm_descriptor,
++ (struct usb_descriptor_header *) &acm_union_desc,
++ (struct usb_descriptor_header *) &acm_fs_notify_desc,
++ (struct usb_descriptor_header *) &acm_data_interface_desc,
++ (struct usb_descriptor_header *) &acm_fs_in_desc,
++ (struct usb_descriptor_header *) &acm_fs_out_desc,
++ NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_INT,
++ .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
++ .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
++};
++
++static struct usb_endpoint_descriptor acm_hs_in_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *acm_hs_function[] __initdata = {
++ (struct usb_descriptor_header *) &acm_control_interface_desc,
++ (struct usb_descriptor_header *) &acm_header_desc,
++ (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
++ (struct usb_descriptor_header *) &acm_descriptor,
++ (struct usb_descriptor_header *) &acm_union_desc,
++ (struct usb_descriptor_header *) &acm_hs_notify_desc,
++ (struct usb_descriptor_header *) &acm_data_interface_desc,
++ (struct usb_descriptor_header *) &acm_hs_in_desc,
++ (struct usb_descriptor_header *) &acm_hs_out_desc,
++ NULL,
++};
++
++/* string descriptors: */
++
++#define ACM_CTRL_IDX 0
++#define ACM_DATA_IDX 1
++
++/* static strings, in UTF-8 */
++static struct usb_string acm_string_defs[] = {
++ [ACM_CTRL_IDX].s = "CDC ACM Control",
++ [ACM_DATA_IDX].s = "CDC ACM Data",
++ { /* ZEROES END LIST */ },
++};
++
++static struct usb_gadget_strings acm_string_table = {
++ .language = 0x0409, /* en-us */
++ .strings = acm_string_defs,
++};
++
++static struct usb_gadget_strings *acm_strings[] = {
++ &acm_string_table,
++ NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* ACM control ... data handling is delegated to tty library code.
++ * The main task of this function is to activate and deactivate
++ * that code based on device state; track parameters like line
++ * speed, handshake state, and so on; and issue notifications.
++ */
++
++static void acm_complete_set_line_coding(struct usb_ep *ep,
++ struct usb_request *req)
++{
++ struct f_acm *acm = ep->driver_data;
++ struct usb_composite_dev *cdev = acm->port.func.config->cdev;
++
++ if (req->status != 0) {
++ DBG(cdev, "acm ttyGS%d completion, err %d\n",
++ acm->port_num, req->status);
++ return;
++ }
++
++ /* normal completion */
++ if (req->actual != sizeof(acm->port_line_coding)) {
++ DBG(cdev, "acm ttyGS%d short resp, len %d\n",
++ acm->port_num, req->actual);
++ usb_ep_set_halt(ep);
++ } else {
++ struct usb_cdc_line_coding *value = req->buf;
++
++ /* REVISIT: we currently just remember this data.
++ * If we change that, (a) validate it first, then
++ * (b) update whatever hardware needs updating,
++ * (c) worry about locking. This is information on
++ * the order of 9600-8-N-1 ... most of which means
++ * nothing unless we control a real RS232 line.
++ */
++ acm->port_line_coding = *value;
++ }
++}
++
++static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
++{
++ struct f_acm *acm = func_to_acm(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++ struct usb_request *req = cdev->req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ /* composite driver infrastructure handles everything except
++ * CDC class messages; interface activation uses set_alt().
++ */
++ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++
++ /* SET_LINE_CODING ... just read and save what the host sends */
++ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | USB_CDC_REQ_SET_LINE_CODING:
++ if (w_length != sizeof(struct usb_cdc_line_coding)
++ || w_index != acm->ctrl_id)
++ goto invalid;
++
++ value = w_length;
++ cdev->gadget->ep0->driver_data = acm;
++ req->complete = acm_complete_set_line_coding;
++ break;
++
++ /* GET_LINE_CODING ... return what host sent, or initial value */
++ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | USB_CDC_REQ_GET_LINE_CODING:
++ if (w_index != acm->ctrl_id)
++ goto invalid;
++
++ value = min_t(unsigned, w_length,
++ sizeof(struct usb_cdc_line_coding));
++ memcpy(req->buf, &acm->port_line_coding, value);
++ break;
++
++ /* SET_CONTROL_LINE_STATE ... save what the host sent */
++ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | USB_CDC_REQ_SET_CONTROL_LINE_STATE:
++ if (w_index != acm->ctrl_id)
++ goto invalid;
++
++ value = 0;
++
++ /* FIXME we should not allow data to flow until the
++ * host sets the RS232_DTR bit; and when it clears
++ * that bit, we should return to that no-flow state.
++ */
++ acm->port_handshake_bits = w_value;
++ break;
++
++ default:
++invalid:
++ VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ }
++
++ /* respond with data transfer or status phase? */
++ if (value >= 0) {
++ DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
++ acm->port_num, ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ req->zero = 0;
++ req->length = value;
++ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
++ if (value < 0)
++ ERROR(cdev, "acm response on ttyGS%d, err %d\n",
++ acm->port_num, value);
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++ struct f_acm *acm = func_to_acm(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ /* we know alt == 0, so this is an activation or a reset */
++
++ /* REVISIT hardware on PXA handles SET_INTERFACE;
++ * this is probably doing resets wrong ...
++ */
++
++ if (intf == acm->ctrl_id) {
++ /* REVISIT this may need more work when we start to
++ * send notifications ...
++ */
++ if (acm->notify->driver_data) {
++ VDBG(cdev, "reset acm control interface %d\n", intf);
++ usb_ep_disable(acm->notify);
++ } else {
++ VDBG(cdev, "init acm ctrl interface %d\n", intf);
++ acm->notify_desc = ep_choose(cdev->gadget,
++ acm->hs.notify,
++ acm->fs.notify);
++ }
++ usb_ep_enable(acm->notify, acm->notify_desc);
++ acm->notify->driver_data = acm;
++
++ } else if (intf == acm->data_id) {
++ if (acm->port.in->driver_data) {
++ DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
++ gserial_disconnect(&acm->port);
++ } else {
++ DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
++ acm->port.in_desc = ep_choose(cdev->gadget,
++ acm->hs.in, acm->fs.in);
++ acm->port.out_desc = ep_choose(cdev->gadget,
++ acm->hs.out, acm->fs.out);
++ }
++ gserial_connect(&acm->port, acm->port_num);
++
++ } else
++ return -EINVAL;
++
++ return 0;
++}
++
++static void acm_disable(struct usb_function *f)
++{
++ struct f_acm *acm = func_to_acm(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
++ gserial_disconnect(&acm->port);
++ usb_ep_disable(acm->notify);
++ acm->notify->driver_data = NULL;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* ACM function driver setup/binding */
++static int __init
++acm_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct f_acm *acm = func_to_acm(f);
++ int status;
++ struct usb_ep *ep;
++
++ /* allocate instance-specific interface IDs, and patch descriptors */
++ status = usb_interface_id(c, f);
++ if (status < 0)
++ goto fail;
++ acm->ctrl_id = status;
++
++ acm_control_interface_desc.bInterfaceNumber = status;
++ acm_union_desc .bMasterInterface0 = status;
++
++ status = usb_interface_id(c, f);
++ if (status < 0)
++ goto fail;
++ acm->data_id = status;
++
++ acm_data_interface_desc.bInterfaceNumber = status;
++ acm_union_desc.bSlaveInterface0 = status;
++ acm_call_mgmt_descriptor.bDataInterface = status;
++
++ status = -ENODEV;
++
++ /* allocate instance-specific endpoints */
++ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
++ if (!ep)
++ goto fail;
++ acm->port.in = ep;
++ ep->driver_data = cdev; /* claim */
++
++ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
++ if (!ep)
++ goto fail;
++ acm->port.out = ep;
++ ep->driver_data = cdev; /* claim */
++
++ ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
++ if (!ep)
++ goto fail;
++ acm->notify = ep;
++ ep->driver_data = cdev; /* claim */
++
++ /* copy descriptors, and track endpoint copies */
++ f->descriptors = usb_copy_descriptors(acm_fs_function);
++
++ acm->fs.in = usb_find_endpoint(acm_fs_function,
++ f->descriptors, &acm_fs_in_desc);
++ acm->fs.out = usb_find_endpoint(acm_fs_function,
++ f->descriptors, &acm_fs_out_desc);
++ acm->fs.notify = usb_find_endpoint(acm_fs_function,
++ f->descriptors, &acm_fs_notify_desc);
++
++ /* support all relevant hardware speeds... we expect that when
++ * hardware is dual speed, all bulk-capable endpoints work at
++ * both speeds
++ */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ acm_hs_in_desc.bEndpointAddress =
++ acm_fs_in_desc.bEndpointAddress;
++ acm_hs_out_desc.bEndpointAddress =
++ acm_fs_out_desc.bEndpointAddress;
++ acm_hs_notify_desc.bEndpointAddress =
++ acm_fs_notify_desc.bEndpointAddress;
++
++ /* copy descriptors, and track endpoint copies */
++ f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
++
++ acm->hs.in = usb_find_endpoint(acm_hs_function,
++ f->hs_descriptors, &acm_hs_in_desc);
++ acm->hs.out = usb_find_endpoint(acm_hs_function,
++ f->hs_descriptors, &acm_hs_out_desc);
++ acm->hs.notify = usb_find_endpoint(acm_hs_function,
++ f->hs_descriptors, &acm_hs_notify_desc);
++ }
++
++ /* FIXME provide a callback for triggering notifications */
++
++ DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
++ acm->port_num,
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ acm->port.in->name, acm->port.out->name,
++ acm->notify->name);
++ return 0;
++
++fail:
++ /* we might as well release our claims on endpoints */
++ if (acm->notify)
++ acm->notify->driver_data = NULL;
++ if (acm->port.out)
++ acm->port.out->driver_data = NULL;
++ if (acm->port.in)
++ acm->port.in->driver_data = NULL;
++
++ ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
++
++ return status;
++}
++
++static void
++acm_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ if (gadget_is_dualspeed(c->cdev->gadget))
++ usb_free_descriptors(f->hs_descriptors);
++ usb_free_descriptors(f->descriptors);
++ kfree(func_to_acm(f));
++}
++
++/* Some controllers can't support CDC ACM ... */
++static inline bool can_support_cdc(struct usb_configuration *c)
++{
++ /* SH3 doesn't support multiple interfaces */
++ if (gadget_is_sh(c->cdev->gadget))
++ return false;
++
++ /* sa1100 doesn't have a third interrupt endpoint */
++ if (gadget_is_sa1100(c->cdev->gadget))
++ return false;
++
++ /* everything else is *probably* fine ... */
++ return true;
++}
++
++/**
++ * acm_bind_config - add a CDC ACM function to a configuration
++ * @c: the configuration to support the CDC ACM instance
++ * @port_num: /dev/ttyGS* port this interface will use
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gserial_setup() with enough ports to
++ * handle all the ones it binds. Caller is also responsible
++ * for calling @gserial_cleanup() before module unload.
++ */
++int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
++{
++ struct f_acm *acm;
++ int status;
++
++ if (!can_support_cdc(c))
++ return -EINVAL;
++
++ /* REVISIT might want instance-specific strings to help
++ * distinguish instances ...
++ */
++
++ /* maybe allocate device-global string IDs, and patch descriptors */
++ if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ acm_string_defs[ACM_CTRL_IDX].id = status;
++
++ acm_control_interface_desc.iInterface = status;
++
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ acm_string_defs[ACM_DATA_IDX].id = status;
++
++ acm_data_interface_desc.iInterface = status;
++ }
++
++ /* allocate and initialize one new instance */
++ acm = kzalloc(sizeof *acm, GFP_KERNEL);
++ if (!acm)
++ return -ENOMEM;
++
++ acm->port_num = port_num;
++
++ acm->port.func.name = "acm";
++ acm->port.func.strings = acm_strings;
++ /* descriptors are per-instance copies */
++ acm->port.func.bind = acm_bind;
++ acm->port.func.unbind = acm_unbind;
++ acm->port.func.set_alt = acm_set_alt;
++ acm->port.func.setup = acm_setup;
++ acm->port.func.disable = acm_disable;
++
++ status = usb_add_function(c, &acm->port.func);
++ if (status)
++ kfree(acm);
++ return status;
++}
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -26,7 +26,7 @@ C_UTILS = composite.o usbstring.o config
+
+ g_zero-objs := zero.o f_sourcesink.o f_loopback.o $(C_UTILS)
+ g_ether-objs := ether.o usbstring.o config.o epautoconf.o
+-g_serial-objs := serial.o u_serial.o usbstring.o config.o epautoconf.o
++g_serial-objs := serial.o u_serial.o f_acm.o $(C_UTILS)
+ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs := inode.o
+ g_file_storage-objs := file_storage.o usbstring.o config.o \
+--- a/drivers/usb/gadget/u_serial.h
++++ b/drivers/usb/gadget/u_serial.h
+@@ -1,10 +1,7 @@
+ #ifndef __U_SERIAL_H
+ #define __U_SERIAL_H
+
+-/* #include <linux/usb/composite.h> */
+-#include <linux/usb/ch9.h>
+-#include <linux/usb/gadget.h>
+-
++#include <linux/usb/composite.h>
+ #include <linux/usb/cdc.h>
+
+ /*
+@@ -21,7 +18,7 @@
+ * REVISIT someday, allow multiplexing several TTYs over these endpoints.
+ */
+ struct gserial {
+- /* struct usb_function func; */
++ struct usb_function func;
+
+ /* port is managed by gserial_{connect,disconnect} */
+ struct gs_port *ioport;
+@@ -48,4 +45,7 @@ void gserial_cleanup(void);
+ int gserial_connect(struct gserial *, u8 port_num);
+ void gserial_disconnect(struct gserial *);
+
++/* functions are bound to configurations by a config or gadget driver */
++int acm_bind_config(struct usb_configuration *c, u8 port_num);
++
+ #endif /* __U_SERIAL_H */
diff --git a/usb/usb-serial-gadget-generic-serial-function-driver.patch b/usb/usb-serial-gadget-generic-serial-function-driver.patch
new file mode 100644
index 00000000000000..3aa638262d159e
--- /dev/null
+++ b/usb/usb-serial-gadget-generic-serial-function-driver.patch
@@ -0,0 +1,354 @@
+From david-b@pacbell.net Fri Jun 6 15:11:41 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:11:31 -0700
+Subject: usb serial gadget: generic serial function driver
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201111.31815.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+Split out the generic serial support into a "function driver". This
+closely mimics the ACM support, but with a MUCH simpler control model.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/DocBook/gadget.tmpl | 1
+ drivers/usb/gadget/Makefile | 2
+ drivers/usb/gadget/f_serial.c | 298 ++++++++++++++++++++++++++++++++++++++
+ drivers/usb/gadget/u_serial.h | 1
+ 4 files changed, 301 insertions(+), 1 deletion(-)
+
+--- a/Documentation/DocBook/gadget.tmpl
++++ b/Documentation/DocBook/gadget.tmpl
+@@ -557,6 +557,7 @@ Near-term plans include converting all o
+ </para>
+
+ !Edrivers/usb/gadget/f_acm.c
++!Edrivers/usb/gadget/f_serial.c
+
+ </sect1>
+
+--- /dev/null
++++ b/drivers/usb/gadget/f_serial.c
+@@ -0,0 +1,298 @@
++/*
++ * f_serial.c - generic USB serial function
++ *
++ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
++ * Copyright (C) 2008 by David Brownell
++ *
++ * This software is 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.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++
++#include "u_serial.h"
++#include "gadget_chips.h"
++
++
++/*
++ * This function packages a simple "generic serial" port with no real
++ * control mechanisms, just raw data transfer over two bulk endpoints.
++ *
++ * Because it's not standardized, this isn't as interoperable as the
++ * CDC ACM driver. However, for many purposes it's just as functional
++ * if you can arrange appropriate host side drivers.
++ */
++
++struct gser_descs {
++ struct usb_endpoint_descriptor *in;
++ struct usb_endpoint_descriptor *out;
++};
++
++struct f_gser {
++ struct gserial port;
++ u8 data_id;
++ u8 port_num;
++
++ struct usb_descriptor_header **fs_function;
++ struct gser_descs fs;
++ struct usb_descriptor_header **hs_function;
++ struct gser_descs hs;
++};
++
++static inline struct f_gser *func_to_gser(struct usb_function *f)
++{
++ return container_of(f, struct f_gser, port.func);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* interface descriptor: */
++
++static struct usb_interface_descriptor gser_interface_desc __initdata = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ /* .bInterfaceNumber = DYNAMIC */
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
++ .bInterfaceSubClass = 0,
++ .bInterfaceProtocol = 0,
++ /* .iInterface = DYNAMIC */
++};
++
++/* full speed support: */
++
++static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_descriptor_header *gser_fs_function[] __initdata = {
++ (struct usb_descriptor_header *) &gser_interface_desc,
++ (struct usb_descriptor_header *) &gser_fs_in_desc,
++ (struct usb_descriptor_header *) &gser_fs_out_desc,
++ NULL,
++};
++
++/* high speed support: */
++
++static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_descriptor_header *gser_hs_function[] __initdata = {
++ (struct usb_descriptor_header *) &gser_interface_desc,
++ (struct usb_descriptor_header *) &gser_hs_in_desc,
++ (struct usb_descriptor_header *) &gser_hs_out_desc,
++ NULL,
++};
++
++/* string descriptors: */
++
++static struct usb_string gser_string_defs[] = {
++ [0].s = "Generic Serial",
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings gser_string_table = {
++ .language = 0x0409, /* en-us */
++ .strings = gser_string_defs,
++};
++
++static struct usb_gadget_strings *gser_strings[] = {
++ &gser_string_table,
++ NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
++{
++ struct f_gser *gser = func_to_gser(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ /* we know alt == 0, so this is an activation or a reset */
++
++ /* REVISIT hardware on PXA handles SET_INTERFACE;
++ * this is probably doing resets wrong ...
++ */
++ if (gser->port.in->driver_data) {
++ DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
++ gserial_disconnect(&gser->port);
++ } else {
++ DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
++ gser->port.in_desc = ep_choose(cdev->gadget,
++ gser->hs.in, gser->fs.in);
++ gser->port.out_desc = ep_choose(cdev->gadget,
++ gser->hs.out, gser->fs.out);
++ }
++ gserial_connect(&gser->port, gser->port_num);
++ return 0;
++}
++
++static void gser_disable(struct usb_function *f)
++{
++ struct f_gser *gser = func_to_gser(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++
++ DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
++ gserial_disconnect(&gser->port);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* serial function driver setup/binding */
++
++static int __init
++gser_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct f_gser *gser = func_to_gser(f);
++ int status;
++ struct usb_ep *ep;
++
++ /* allocate instance-specific interface IDs */
++ status = usb_interface_id(c, f);
++ if (status < 0)
++ goto fail;
++ gser->data_id = status;
++ gser_interface_desc.bInterfaceNumber = status;
++
++ status = -ENODEV;
++
++ /* allocate instance-specific endpoints */
++ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
++ if (!ep)
++ goto fail;
++ gser->port.in = ep;
++ ep->driver_data = cdev; /* claim */
++
++ ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
++ if (!ep)
++ goto fail;
++ gser->port.out = ep;
++ ep->driver_data = cdev; /* claim */
++
++ /* copy descriptors, and track endpoint copies */
++ f->descriptors = usb_copy_descriptors(gser_fs_function);
++
++ gser->fs.in = usb_find_endpoint(gser_fs_function,
++ f->descriptors, &gser_fs_in_desc);
++ gser->fs.out = usb_find_endpoint(gser_fs_function,
++ f->descriptors, &gser_fs_out_desc);
++
++
++ /* support all relevant hardware speeds... we expect that when
++ * hardware is dual speed, all bulk-capable endpoints work at
++ * both speeds
++ */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ gser_hs_in_desc.bEndpointAddress =
++ gser_fs_in_desc.bEndpointAddress;
++ gser_hs_out_desc.bEndpointAddress =
++ gser_fs_out_desc.bEndpointAddress;
++
++ /* copy descriptors, and track endpoint copies */
++ f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
++
++ gser->hs.in = usb_find_endpoint(gser_hs_function,
++ f->hs_descriptors, &gser_hs_in_desc);
++ gser->hs.out = usb_find_endpoint(gser_hs_function,
++ f->hs_descriptors, &gser_hs_out_desc);
++ }
++
++ DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
++ gser->port_num,
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ gser->port.in->name, gser->port.out->name);
++ return 0;
++
++fail:
++ /* we might as well release our claims on endpoints */
++ if (gser->port.out)
++ gser->port.out->driver_data = NULL;
++ if (gser->port.in)
++ gser->port.in->driver_data = NULL;
++
++ ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
++
++ return status;
++}
++
++static void
++gser_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ if (gadget_is_dualspeed(c->cdev->gadget))
++ usb_free_descriptors(f->hs_descriptors);
++ usb_free_descriptors(f->descriptors);
++ kfree(func_to_gser(f));
++}
++
++/**
++ * gser_bind_config - add a generic serial function to a configuration
++ * @c: the configuration to support the serial instance
++ * @port_num: /dev/ttyGS* port this interface will use
++ * Context: single threaded during gadget setup
++ *
++ * Returns zero on success, else negative errno.
++ *
++ * Caller must have called @gserial_setup() with enough ports to
++ * handle all the ones it binds. Caller is also responsible
++ * for calling @gserial_cleanup() before module unload.
++ */
++int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
++{
++ struct f_gser *gser;
++ int status;
++
++ /* REVISIT might want instance-specific strings to help
++ * distinguish instances ...
++ */
++
++ /* maybe allocate device-global string ID */
++ if (gser_string_defs[0].id == 0) {
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ gser_string_defs[0].id = status;
++ }
++
++ /* allocate and initialize one new instance */
++ gser = kzalloc(sizeof *gser, GFP_KERNEL);
++ if (!gser)
++ return -ENOMEM;
++
++ gser->port_num = port_num;
++
++ gser->port.func.name = "gser";
++ gser->port.func.strings = gser_strings;
++ gser->port.func.bind = gser_bind;
++ gser->port.func.unbind = gser_unbind;
++ gser->port.func.set_alt = gser_set_alt;
++ gser->port.func.disable = gser_disable;
++
++ status = usb_add_function(c, &gser->port.func);
++ if (status)
++ kfree(gser);
++ return status;
++}
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -26,7 +26,7 @@ C_UTILS = composite.o usbstring.o config
+
+ g_zero-objs := zero.o f_sourcesink.o f_loopback.o $(C_UTILS)
+ g_ether-objs := ether.o usbstring.o config.o epautoconf.o
+-g_serial-objs := serial.o u_serial.o f_acm.o $(C_UTILS)
++g_serial-objs := serial.o u_serial.o f_acm.o f_serial.o $(C_UTILS)
+ g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs := inode.o
+ g_file_storage-objs := file_storage.o usbstring.o config.o \
+--- a/drivers/usb/gadget/u_serial.h
++++ b/drivers/usb/gadget/u_serial.h
+@@ -47,5 +47,6 @@ void gserial_disconnect(struct gserial *
+
+ /* functions are bound to configurations by a config or gadget driver */
+ int acm_bind_config(struct usb_configuration *c, u8 port_num);
++int gser_bind_config(struct usb_configuration *c, u8 port_num);
+
+ #endif /* __U_SERIAL_H */
diff --git a/usb/usb-serial-gadget-use-updated-framework.patch b/usb/usb-serial-gadget-use-updated-framework.patch
new file mode 100644
index 00000000000000..e92e015abf1e6e
--- /dev/null
+++ b/usb/usb-serial-gadget-use-updated-framework.patch
@@ -0,0 +1,1205 @@
+From david-b@pacbell.net Fri Jun 6 15:11:53 2008
+From: David Brownell <david-b@pacbell.net>
+Date: Tue, 20 May 2008 11:21:06 -0700
+Subject: usb serial gadget: use updated framework
+To: linux-usb@vger.kernel.org
+Cc: Tony Lindgren <tony@atomide.com>, Felipe Balbi <felipebalbi@users.sourceforge.net>, Al Borchers <alborchers@steinerpoint.com>
+Message-ID: <200805201121.06576.david-b@pacbell.net>
+Content-Disposition: inline
+
+
+This switches the serial gadget over to using the new "function"
+versions of the serial port interfacing code. The remaining code
+in this module is quite small...
+
+Note one new feature added by this patch: a new module parameter
+saying how many instances to create, defaulting to "one". So for
+hardware which allows it, you can "modprobe g_serial n_ports=2"
+(or more) to get two ACM ports.
+
+Also, ACM is the (more interoperable) default now, with the use_acm
+parameter switched to be a boolean.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/serial.c | 1073 +++++-------------------------------------
+ drivers/usb/gadget/u_serial.h | 5
+ 2 files changed, 144 insertions(+), 934 deletions(-)
+
+--- a/drivers/usb/gadget/serial.c
++++ b/drivers/usb/gadget/serial.c
+@@ -21,314 +21,78 @@
+
+ /* Defines */
+
+-#define GS_VERSION_STR "v2.3"
+-#define GS_VERSION_NUM 0x2300
++#define GS_VERSION_STR "v2.4"
++#define GS_VERSION_NUM 0x2400
+
+ #define GS_LONG_NAME "Gadget Serial"
+-#define GS_SHORT_NAME "g_serial"
+-
+ #define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
+
+-
+-/* REVISIT only one port is supported for now;
+- * see gs_{send,recv}_packet() ... no multiplexing,
+- * and no support for multiple ACM devices.
+- */
+-#define GS_NUM_PORTS 1
+-
+-#define GS_NUM_CONFIGS 1
+-#define GS_NO_CONFIG_ID 0
+-#define GS_BULK_CONFIG_ID 1
+-#define GS_ACM_CONFIG_ID 2
+-
+-#define GS_MAX_NUM_INTERFACES 2
+-#define GS_BULK_INTERFACE_ID 0
+-#define GS_CONTROL_INTERFACE_ID 0
+-#define GS_DATA_INTERFACE_ID 1
+-
+-#define GS_MAX_DESC_LEN 256
+-
+-#define GS_DEFAULT_USE_ACM 0
+-
+-
+-/* maxpacket and other transfer characteristics vary by speed. */
+-static inline struct usb_endpoint_descriptor *
+-choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+- struct usb_endpoint_descriptor *fs)
+-{
+- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+- return hs;
+- return fs;
+-}
+-
++/*-------------------------------------------------------------------------*/
+
+ /* Thanks to NetChip Technologies for donating this product ID.
+- *
+- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+- * Instead: allocate your own, using normal USB-IF procedures.
+- */
++*
++* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
++* Instead: allocate your own, using normal USB-IF procedures.
++*/
+ #define GS_VENDOR_ID 0x0525 /* NetChip */
+ #define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
+ #define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */
+
+-#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
+-#define GS_NOTIFY_MAXPACKET 8
+-
+-/* the device structure holds info for the USB device */
+-struct gs_dev {
+- struct usb_gadget *dev_gadget; /* gadget device pointer */
+- spinlock_t dev_lock; /* lock for set/reset config */
+- int dev_config; /* configuration number */
+- struct usb_request *dev_ctrl_req; /* control request */
+-
+- struct gserial gser; /* serial/tty port */
+-};
+-
+-
+-/* Functions */
++/* string IDs are assigned dynamically */
+
+-/* gadget driver internals */
+-static int gs_set_config(struct gs_dev *dev, unsigned config);
+-static void gs_reset_config(struct gs_dev *dev);
+-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
+- u8 type, unsigned int index, int is_otg);
+-
+-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
+- gfp_t kmalloc_flags);
+-static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
++#define STRING_MANUFACTURER_IDX 0
++#define STRING_PRODUCT_IDX 1
++#define STRING_DESCRIPTION_IDX 2
+
+-/*-------------------------------------------------------------------------*/
+-
+-/* USB descriptors */
+-
+-#define GS_MANUFACTURER_STR_ID 1
+-#define GS_PRODUCT_STR_ID 2
+-#define GS_SERIAL_STR_ID 3
+-#define GS_BULK_CONFIG_STR_ID 4
+-#define GS_ACM_CONFIG_STR_ID 5
+-#define GS_CONTROL_STR_ID 6
+-#define GS_DATA_STR_ID 7
+-
+-/* static strings, in UTF-8 */
+ static char manufacturer[50];
+-static struct usb_string gs_strings[] = {
+- { GS_MANUFACTURER_STR_ID, manufacturer },
+- { GS_PRODUCT_STR_ID, GS_VERSION_NAME },
+- { GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
+- { GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
+- { GS_CONTROL_STR_ID, "Gadget Serial Control" },
+- { GS_DATA_STR_ID, "Gadget Serial Data" },
++
++static struct usb_string strings_dev[] = {
++ [STRING_MANUFACTURER_IDX].s = manufacturer,
++ [STRING_PRODUCT_IDX].s = GS_VERSION_NAME,
++ [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
+ { } /* end of list */
+ };
+
+-static struct usb_gadget_strings gs_string_table = {
+- .language = 0x0409, /* en-us */
+- .strings = gs_strings,
++static struct usb_gadget_strings stringtab_dev = {
++ .language = 0x0409, /* en-us */
++ .strings = strings_dev,
+ };
+
+-static struct usb_device_descriptor gs_device_desc = {
++static struct usb_gadget_strings *dev_strings[] = {
++ &stringtab_dev,
++ NULL,
++};
++
++static struct usb_device_descriptor device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
++ /* .bDeviceClass = f(use_acm) */
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
++ /* .bMaxPacketSize0 = f(hardware) */
+ .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID),
+- .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID),
+- .iManufacturer = GS_MANUFACTURER_STR_ID,
+- .iProduct = GS_PRODUCT_STR_ID,
+- .bNumConfigurations = GS_NUM_CONFIGS,
++ /* .idProduct = f(use_acm) */
++ /* .iManufacturer = DYNAMIC */
++ /* .iProduct = DYNAMIC */
++ .bNumConfigurations = 1,
+ };
+
+-static struct usb_otg_descriptor gs_otg_descriptor = {
+- .bLength = sizeof(gs_otg_descriptor),
++static struct usb_otg_descriptor otg_descriptor = {
++ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+- .bmAttributes = USB_OTG_SRP,
+-};
+-
+-static struct usb_config_descriptor gs_bulk_config_desc = {
+- .bLength = USB_DT_CONFIG_SIZE,
+- .bDescriptorType = USB_DT_CONFIG,
+- /* .wTotalLength computed dynamically */
+- .bNumInterfaces = 1,
+- .bConfigurationValue = GS_BULK_CONFIG_ID,
+- .iConfiguration = GS_BULK_CONFIG_STR_ID,
+- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+- .bMaxPower = 1,
+-};
+-
+-static struct usb_config_descriptor gs_acm_config_desc = {
+- .bLength = USB_DT_CONFIG_SIZE,
+- .bDescriptorType = USB_DT_CONFIG,
+- /* .wTotalLength computed dynamically */
+- .bNumInterfaces = 2,
+- .bConfigurationValue = GS_ACM_CONFIG_ID,
+- .iConfiguration = GS_ACM_CONFIG_STR_ID,
+- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+- .bMaxPower = 1,
+-};
+-
+-static const struct usb_interface_descriptor gs_bulk_interface_desc = {
+- .bLength = USB_DT_INTERFACE_SIZE,
+- .bDescriptorType = USB_DT_INTERFACE,
+- .bInterfaceNumber = GS_BULK_INTERFACE_ID,
+- .bNumEndpoints = 2,
+- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+- .bInterfaceSubClass = 0,
+- .bInterfaceProtocol = 0,
+- .iInterface = GS_DATA_STR_ID,
+-};
+-
+-static const struct usb_interface_descriptor gs_control_interface_desc = {
+- .bLength = USB_DT_INTERFACE_SIZE,
+- .bDescriptorType = USB_DT_INTERFACE,
+- .bInterfaceNumber = GS_CONTROL_INTERFACE_ID,
+- .bNumEndpoints = 1,
+- .bInterfaceClass = USB_CLASS_COMM,
+- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+- .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
+- .iInterface = GS_CONTROL_STR_ID,
+-};
+-
+-static const struct usb_interface_descriptor gs_data_interface_desc = {
+- .bLength = USB_DT_INTERFACE_SIZE,
+- .bDescriptorType = USB_DT_INTERFACE,
+- .bInterfaceNumber = GS_DATA_INTERFACE_ID,
+- .bNumEndpoints = 2,
+- .bInterfaceClass = USB_CLASS_CDC_DATA,
+- .bInterfaceSubClass = 0,
+- .bInterfaceProtocol = 0,
+- .iInterface = GS_DATA_STR_ID,
+-};
+-
+-static const struct usb_cdc_header_desc gs_header_desc = {
+- .bLength = sizeof(gs_header_desc),
+- .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+- .bcdCDC = __constant_cpu_to_le16(0x0110),
+-};
+-
+-static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
+- .bLength = sizeof(gs_call_mgmt_descriptor),
+- .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
+- .bmCapabilities = 0,
+- .bDataInterface = 1, /* index of data interface */
+-};
+-
+-static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
+- .bLength = sizeof(gs_acm_descriptor),
+- .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = USB_CDC_ACM_TYPE,
+- .bmCapabilities = (1 << 1),
+-};
+-
+-static const struct usb_cdc_union_desc gs_union_desc = {
+- .bLength = sizeof(gs_union_desc),
+- .bDescriptorType = USB_DT_CS_INTERFACE,
+- .bDescriptorSubType = USB_CDC_UNION_TYPE,
+- .bMasterInterface0 = 0, /* index of control interface */
+- .bSlaveInterface0 = 1, /* index of data interface */
+-};
+-
+-static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bEndpointAddress = USB_DIR_IN,
+- .bmAttributes = USB_ENDPOINT_XFER_INT,
+- .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+- .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
+-};
+-
+-static struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bEndpointAddress = USB_DIR_IN,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+-};
+
+-static struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bEndpointAddress = USB_DIR_OUT,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+-};
+-
+-static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = {
+- (struct usb_descriptor_header *) &gs_otg_descriptor,
+- (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+- (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+- (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+- NULL,
+-};
+-
+-static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
+- (struct usb_descriptor_header *) &gs_otg_descriptor,
+- (struct usb_descriptor_header *) &gs_control_interface_desc,
+- (struct usb_descriptor_header *) &gs_header_desc,
+- (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+- (struct usb_descriptor_header *) &gs_acm_descriptor,
+- (struct usb_descriptor_header *) &gs_union_desc,
+- (struct usb_descriptor_header *) &gs_fullspeed_notify_desc,
+- (struct usb_descriptor_header *) &gs_data_interface_desc,
+- (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
+- (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
+- NULL,
+-};
+-
+-static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bEndpointAddress = USB_DIR_IN,
+- .bmAttributes = USB_ENDPOINT_XFER_INT,
+- .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
+- .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
+-};
+-
+-static struct usb_endpoint_descriptor gs_highspeed_in_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+- .wMaxPacketSize = __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_endpoint_descriptor gs_highspeed_out_desc = {
+- .bLength = USB_DT_ENDPOINT_SIZE,
+- .bDescriptorType = USB_DT_ENDPOINT,
+- .bmAttributes = USB_ENDPOINT_XFER_BULK,
+- .wMaxPacketSize = __constant_cpu_to_le16(512),
+-};
+-
+-static struct usb_qualifier_descriptor gs_qualifier_desc = {
+- .bLength = sizeof(struct usb_qualifier_descriptor),
+- .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+- /* assumes ep0 uses the same value for both speeds ... */
+- .bNumConfigurations = GS_NUM_CONFIGS,
+-};
+-
+-static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = {
+- (struct usb_descriptor_header *) &gs_otg_descriptor,
+- (struct usb_descriptor_header *) &gs_bulk_interface_desc,
+- (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+- (struct usb_descriptor_header *) &gs_highspeed_out_desc,
+- NULL,
++ /* REVISIT SRP-only hardware is possible, although
++ * it would not be called "OTG" ...
++ */
++ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+ };
+
+-static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
+- (struct usb_descriptor_header *) &gs_otg_descriptor,
+- (struct usb_descriptor_header *) &gs_control_interface_desc,
+- (struct usb_descriptor_header *) &gs_header_desc,
+- (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
+- (struct usb_descriptor_header *) &gs_acm_descriptor,
+- (struct usb_descriptor_header *) &gs_union_desc,
+- (struct usb_descriptor_header *) &gs_highspeed_notify_desc,
+- (struct usb_descriptor_header *) &gs_data_interface_desc,
+- (struct usb_descriptor_header *) &gs_highspeed_in_desc,
+- (struct usb_descriptor_header *) &gs_highspeed_out_desc,
++static const struct usb_descriptor_header *otg_desc[] = {
++ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+ };
+
+-
+ /*-------------------------------------------------------------------------*/
+
+ /* Module */
+@@ -337,699 +101,150 @@ MODULE_AUTHOR("Al Borchers");
+ MODULE_AUTHOR("David Brownell");
+ MODULE_LICENSE("GPL");
+
+-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
+-module_param(use_acm, uint, S_IRUGO);
+-MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
++static int use_acm = true;
++module_param(use_acm, bool, 0);
++MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
++
++static unsigned n_ports = 1;
++module_param(n_ports, uint, 0);
++MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
+
+ /*-------------------------------------------------------------------------*/
+
+-/* Gadget Driver */
+-
+-/*
+- * gs_unbind
+- *
+- * Called on module unload. Frees the control request and device
+- * structure.
+- */
+-static void __exit gs_unbind(struct usb_gadget *gadget)
++static int __init serial_bind_config(struct usb_configuration *c)
+ {
+- struct gs_dev *dev = get_gadget_data(gadget);
++ unsigned i;
++ int status = 0;
+
+- /* read/write requests already freed, only control request remains */
+- if (dev != NULL) {
+- if (dev->dev_ctrl_req != NULL) {
+- gs_free_req(gadget->ep0, dev->dev_ctrl_req);
+- dev->dev_ctrl_req = NULL;
+- }
+- gs_reset_config(dev);
+- kfree(dev);
+- set_gadget_data(gadget, NULL);
++ for (i = 0; i < n_ports && status == 0; i++) {
++ if (use_acm)
++ status = acm_bind_config(c, i);
++ else
++ status = gser_bind_config(c, i);
+ }
+-
+- pr_info("gs_unbind: %s unbound\n", GS_VERSION_NAME);
+-
+- gserial_cleanup();
++ return status;
+ }
+
+-/*
+- * gs_bind
+- *
+- * Called on module load. Allocates and initializes the device
+- * structure and a control request.
+- */
+-static int __init gs_bind(struct usb_gadget *gadget)
+-{
+- int ret;
+- struct usb_ep *ep;
+- struct gs_dev *dev;
+- int gcnum;
+-
+- ret = gserial_setup(gadget, GS_NUM_PORTS);
+- if (ret < 0)
+- return ret;
+-
+- /* Some controllers can't support CDC ACM:
+- * - sh doesn't support multiple interfaces or configs;
+- * - sa1100 doesn't have a third interrupt endpoint
+- */
+- if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
+- use_acm = 0;
+-
+- gcnum = usb_gadget_controller_number(gadget);
+- if (gcnum >= 0)
+- gs_device_desc.bcdDevice =
+- cpu_to_le16(GS_VERSION_NUM | gcnum);
+- else {
+- pr_warning("gs_bind: controller '%s' not recognized\n",
+- gadget->name);
+- /* unrecognized, but safe unless bulk is REALLY quirky */
+- gs_device_desc.bcdDevice =
+- __constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
+- }
+-
+- dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
+- if (dev == NULL) {
+- ret = -ENOMEM;
+- goto autoconf_fail;
+- }
+-
+- usb_ep_autoconfig_reset(gadget);
+- ret = -ENXIO;
+-
+- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
+- if (!ep)
+- goto autoconf_fail;
+- dev->gser.in = ep;
+- ep->driver_data = dev; /* claim the endpoint */
+-
+- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
+- if (!ep)
+- goto autoconf_fail;
+- dev->gser.out = ep;
+- ep->driver_data = dev; /* claim the endpoint */
+-
+- if (use_acm) {
+- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
+- if (!ep) {
+- pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
+- goto autoconf_fail;
+- }
+- gs_device_desc.idProduct = __constant_cpu_to_le16(
+- GS_CDC_PRODUCT_ID),
+- dev->gser.notify = ep;
+- ep->driver_data = dev; /* claim the endpoint */
+- }
++static struct usb_configuration serial_config_driver = {
++ /* .label = f(use_acm) */
++ .bind = serial_bind_config,
++ /* .bConfigurationValue = f(use_acm) */
++ /* .iConfiguration = DYNAMIC */
++ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = 1, /* 2 mA, minimal */
++};
+
+- gs_device_desc.bDeviceClass = use_acm
+- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+- gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+-
+- if (gadget_is_dualspeed(gadget)) {
+- gs_qualifier_desc.bDeviceClass = use_acm
+- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+- /* assume ep0 uses the same packet size for both speeds */
+- gs_qualifier_desc.bMaxPacketSize0 =
+- gs_device_desc.bMaxPacketSize0;
+- /* assume endpoints are dual-speed */
+- gs_highspeed_notify_desc.bEndpointAddress =
+- gs_fullspeed_notify_desc.bEndpointAddress;
+- gs_highspeed_in_desc.bEndpointAddress =
+- gs_fullspeed_in_desc.bEndpointAddress;
+- gs_highspeed_out_desc.bEndpointAddress =
+- gs_fullspeed_out_desc.bEndpointAddress;
+- }
++static int __init gs_bind(struct usb_composite_dev *cdev)
++{
++ int gcnum;
++ struct usb_gadget *gadget = cdev->gadget;
++ int status;
+
+- usb_gadget_set_selfpowered(gadget);
++ status = gserial_setup(cdev->gadget, n_ports);
++ if (status < 0)
++ return status;
+
+- if (gadget_is_otg(gadget)) {
+- gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
+- gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+- }
++ /* Allocate string descriptor numbers ... note that string
++ * contents can be overridden by the composite_dev glue.
++ */
+
+- snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
++ /* device description: manufacturer, product */
++ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail;
++ strings_dev[STRING_MANUFACTURER_IDX].id = status;
+
+- dev->dev_gadget = gadget;
+- spin_lock_init(&dev->dev_lock);
+- set_gadget_data(gadget, dev);
+-
+- /* preallocate control response and buffer */
+- dev->dev_ctrl_req = gs_alloc_req(gadget->ep0, GS_MAX_DESC_LEN,
+- GFP_KERNEL);
+- if (dev->dev_ctrl_req == NULL) {
+- ret = -ENOMEM;
+- goto autoconf_fail;
+- }
+- gadget->ep0->driver_data = dev;
++ device_desc.iManufacturer = status;
+
+- pr_info("gs_bind: %s bound\n", GS_VERSION_NAME);
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail;
++ strings_dev[STRING_PRODUCT_IDX].id = status;
+
+- return 0;
++ device_desc.iProduct = status;
+
+-autoconf_fail:
+- kfree(dev);
+- gserial_cleanup();
+- pr_err("gs_bind: to %s, err %d\n", gadget->name, ret);
+- return ret;
+-}
++ /* config description */
++ status = usb_string_id(cdev);
++ if (status < 0)
++ goto fail;
++ strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+-static int gs_setup_standard(struct usb_gadget *gadget,
+- const struct usb_ctrlrequest *ctrl)
+-{
+- int ret = -EOPNOTSUPP;
+- struct gs_dev *dev = get_gadget_data(gadget);
+- struct usb_request *req = dev->dev_ctrl_req;
+- u16 wIndex = le16_to_cpu(ctrl->wIndex);
+- u16 wValue = le16_to_cpu(ctrl->wValue);
+- u16 wLength = le16_to_cpu(ctrl->wLength);
+-
+- switch (ctrl->bRequest) {
+- case USB_REQ_GET_DESCRIPTOR:
+- if (ctrl->bRequestType != USB_DIR_IN)
+- break;
+-
+- switch (wValue >> 8) {
+- case USB_DT_DEVICE:
+- ret = min(wLength,
+- (u16)sizeof(struct usb_device_descriptor));
+- memcpy(req->buf, &gs_device_desc, ret);
+- break;
+-
+- case USB_DT_DEVICE_QUALIFIER:
+- if (!gadget_is_dualspeed(gadget))
+- break;
+- ret = min(wLength,
+- (u16)sizeof(struct usb_qualifier_descriptor));
+- memcpy(req->buf, &gs_qualifier_desc, ret);
+- break;
+-
+- case USB_DT_OTHER_SPEED_CONFIG:
+- if (!gadget_is_dualspeed(gadget))
+- break;
+- /* fall through */
+- case USB_DT_CONFIG:
+- ret = gs_build_config_buf(req->buf, gadget,
+- wValue >> 8, wValue & 0xff,
+- gadget_is_otg(gadget));
+- if (ret >= 0)
+- ret = min(wLength, (u16)ret);
+- break;
+-
+- case USB_DT_STRING:
+- /* wIndex == language code. */
+- ret = usb_gadget_get_string(&gs_string_table,
+- wValue & 0xff, req->buf);
+- if (ret >= 0)
+- ret = min(wLength, (u16)ret);
+- break;
+- }
+- break;
+-
+- case USB_REQ_SET_CONFIGURATION:
+- if (ctrl->bRequestType != 0)
+- break;
+- spin_lock(&dev->dev_lock);
+- ret = gs_set_config(dev, wValue);
+- spin_unlock(&dev->dev_lock);
+- break;
+-
+- case USB_REQ_GET_CONFIGURATION:
+- if (ctrl->bRequestType != USB_DIR_IN)
+- break;
+- *(u8 *)req->buf = dev->dev_config;
+- ret = min(wLength, (u16)1);
+- break;
+-
+- case USB_REQ_SET_INTERFACE:
+- if (ctrl->bRequestType != USB_RECIP_INTERFACE
+- || !dev->dev_config
+- || wIndex >= GS_MAX_NUM_INTERFACES)
+- break;
+- if (dev->dev_config == GS_BULK_CONFIG_ID
+- && wIndex != GS_BULK_INTERFACE_ID)
+- break;
+- /* no alternate interface settings */
+- if (wValue != 0)
+- break;
+- spin_lock(&dev->dev_lock);
+- /* PXA hardware partially handles SET_INTERFACE;
+- * we need to kluge around that interference. */
+- if (gadget_is_pxa(gadget)) {
+- ret = gs_set_config(dev, use_acm ?
+- GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID);
+- goto set_interface_done;
+- }
+- if (dev->dev_config != GS_BULK_CONFIG_ID
+- && wIndex == GS_CONTROL_INTERFACE_ID) {
+- if (dev->gser.notify) {
+- usb_ep_disable(dev->gser.notify);
+- usb_ep_enable(dev->gser.notify,
+- dev->gser.notify_desc);
+- }
+- } else {
+- gserial_connect(&dev->gser, 0);
+- gserial_disconnect(&dev->gser);
+- }
+- ret = 0;
+-set_interface_done:
+- spin_unlock(&dev->dev_lock);
+- break;
+-
+- case USB_REQ_GET_INTERFACE:
+- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+- || dev->dev_config == GS_NO_CONFIG_ID)
+- break;
+- if (wIndex >= GS_MAX_NUM_INTERFACES
+- || (dev->dev_config == GS_BULK_CONFIG_ID
+- && wIndex != GS_BULK_INTERFACE_ID)) {
+- ret = -EDOM;
+- break;
+- }
+- /* no alternate interface settings */
+- *(u8 *)req->buf = 0;
+- ret = min(wLength, (u16)1);
+- break;
+-
+- default:
+- pr_err("gs_setup: unknown standard request, type=%02x, "
+- "request=%02x, value=%04x, index=%04x, length=%d\n",
+- ctrl->bRequestType, ctrl->bRequest,
+- wValue, wIndex, wLength);
+- break;
+- }
++ serial_config_driver.iConfiguration = status;
+
+- return ret;
+-}
+-
+-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+- struct usb_request *req)
+-{
+- struct gs_dev *dev = ep->driver_data;
+-
+- switch (req->status) {
+- case 0:
+- /* normal completion */
+- if (req->actual != sizeof(dev->gser.port_line_coding))
+- usb_ep_set_halt(ep);
+- else {
+- struct usb_cdc_line_coding *value = req->buf;
+-
+- /* REVISIT: we currently just remember this data.
+- * If we change that, (a) validate it first, then
+- * (b) update whatever hardware needs updating.
+- */
+- spin_lock(&dev->dev_lock);
+- dev->gser.port_line_coding = *value;
+- spin_unlock(&dev->dev_lock);
+- }
+- break;
+-
+- case -ESHUTDOWN:
+- /* disconnect */
+- gs_free_req(ep, req);
+- break;
+-
+- default:
+- /* unexpected */
+- break;
+- }
+- return;
+-}
+-
+-static int gs_setup_class(struct usb_gadget *gadget,
+- const struct usb_ctrlrequest *ctrl)
+-{
+- int ret = -EOPNOTSUPP;
+- struct gs_dev *dev = get_gadget_data(gadget);
+- struct usb_request *req = dev->dev_ctrl_req;
+- u16 wIndex = le16_to_cpu(ctrl->wIndex);
+- u16 wValue = le16_to_cpu(ctrl->wValue);
+- u16 wLength = le16_to_cpu(ctrl->wLength);
+-
+- switch (ctrl->bRequest) {
+- case USB_CDC_REQ_SET_LINE_CODING:
+- if (wLength != sizeof(struct usb_cdc_line_coding))
+- break;
+- ret = wLength;
+- req->complete = gs_setup_complete_set_line_coding;
+- break;
+-
+- case USB_CDC_REQ_GET_LINE_CODING:
+- ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
+- spin_lock(&dev->dev_lock);
+- memcpy(req->buf, &dev->gser.port_line_coding, ret);
+- spin_unlock(&dev->dev_lock);
+- break;
+-
+- case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+- if (wLength != 0)
+- break;
+- ret = 0;
+- /* REVISIT: we currently just remember this data.
+- * If we change that, update whatever hardware needs
+- * updating.
+- */
+- spin_lock(&dev->dev_lock);
+- dev->gser.port_handshake_bits = wValue;
+- spin_unlock(&dev->dev_lock);
+- break;
+-
+- default:
+- /* NOTE: strictly speaking, we should accept AT-commands
+- * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+- * But our call management descriptor says we don't handle
+- * call management, so we should be able to get by without
+- * handling those "required" commands (except by stalling).
++ /* set up other descriptors */
++ gcnum = usb_gadget_controller_number(gadget);
++ if (gcnum >= 0)
++ device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum);
++ else {
++ /* this is so simple (for now, no altsettings) that it
++ * SHOULD NOT have problems with bulk-capable hardware.
++ * so warn about unrcognized controllers -- don't panic.
++ *
++ * things like configuration and altsetting numbering
++ * can need hardware-specific attention though.
+ */
+- pr_err("gs_setup: unknown class request, "
+- "type=%02x, request=%02x, value=%04x, "
+- "index=%04x, length=%d\n",
+- ctrl->bRequestType, ctrl->bRequest,
+- wValue, wIndex, wLength);
+- break;
+- }
+-
+- return ret;
+-}
+-
+-/*
+- * gs_setup_complete
+- */
+-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
+-{
+- if (req->status || req->actual != req->length) {
+- pr_err("gs_setup_complete: status error, status=%d, "
+- "actual=%d, length=%d\n",
+- req->status, req->actual, req->length);
+- }
+-}
+-
+-/*
+- * gs_setup
+- *
+- * Implements all the control endpoint functionality that's not
+- * handled in hardware or the hardware driver.
+- *
+- * Returns the size of the data sent to the host, or a negative
+- * error number.
+- */
+-static int gs_setup(struct usb_gadget *gadget,
+- const struct usb_ctrlrequest *ctrl)
+-{
+- int ret = -EOPNOTSUPP;
+- struct gs_dev *dev = get_gadget_data(gadget);
+- struct usb_request *req = dev->dev_ctrl_req;
+- u16 wIndex = le16_to_cpu(ctrl->wIndex);
+- u16 wValue = le16_to_cpu(ctrl->wValue);
+- u16 wLength = le16_to_cpu(ctrl->wLength);
+-
+- req->complete = gs_setup_complete;
+-
+- switch (ctrl->bRequestType & USB_TYPE_MASK) {
+- case USB_TYPE_STANDARD:
+- ret = gs_setup_standard(gadget, ctrl);
+- break;
+-
+- case USB_TYPE_CLASS:
+- ret = gs_setup_class(gadget, ctrl);
+- break;
+-
+- default:
+- pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+- "value=%04x, index=%04x, length=%d\n",
+- ctrl->bRequestType, ctrl->bRequest,
+- wValue, wIndex, wLength);
+- break;
++ pr_warning("gs_bind: controller '%s' not recognized\n",
++ gadget->name);
++ device_desc.bcdDevice =
++ __constant_cpu_to_le16(GS_VERSION_NUM | 0x0099);
+ }
+
+- /* respond with data transfer before status phase? */
+- if (ret >= 0) {
+- req->length = ret;
+- req->zero = ret < wLength
+- && (ret % gadget->ep0->maxpacket) == 0;
+- ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+- if (ret < 0) {
+- pr_err("gs_setup: cannot queue response, ret=%d\n",
+- ret);
+- req->status = 0;
+- gs_setup_complete(gadget->ep0, req);
+- }
++ if (gadget_is_otg(cdev->gadget)) {
++ serial_config_driver.descriptors = otg_desc;
++ serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+- /* device either stalls (ret < 0) or reports success */
+- return ret;
+-}
++ /* register our configuration */
++ status = usb_add_config(cdev, &serial_config_driver);
++ if (status < 0)
++ goto fail;
+
+-/*
+- * gs_disconnect
+- *
+- * Called when the device is disconnected. Frees the closed
+- * ports and disconnects open ports. Open ports will be freed
+- * on close. Then reallocates the ports for the next connection.
+- */
+-static void gs_disconnect(struct usb_gadget *gadget)
+-{
+- unsigned long flags;
+- struct gs_dev *dev = get_gadget_data(gadget);
++ INFO(cdev, "%s\n", GS_VERSION_NAME);
+
+- spin_lock_irqsave(&dev->dev_lock, flags);
+- gs_reset_config(dev);
+- spin_unlock_irqrestore(&dev->dev_lock, flags);
++ return 0;
+
+- pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
++fail:
++ gserial_cleanup();
++ return status;
+ }
+
+-static struct usb_gadget_driver gs_gadget_driver = {
+-#ifdef CONFIG_USB_GADGET_DUALSPEED
+- .speed = USB_SPEED_HIGH,
+-#else
+- .speed = USB_SPEED_FULL,
+-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+- .function = GS_LONG_NAME,
+- .bind = gs_bind,
+- .unbind = gs_unbind,
+- .setup = gs_setup,
+- .disconnect = gs_disconnect,
+- .driver = {
+- .name = GS_SHORT_NAME,
+- .owner = THIS_MODULE,
+- },
++static struct usb_composite_driver gserial_driver = {
++ .name = "g_serial",
++ .dev = &device_desc,
++ .strings = dev_strings,
++ .bind = gs_bind,
+ };
+
+-/*
+- * gs_set_config
+- *
+- * Configures the device by enabling device specific
+- * optimizations, setting up the endpoints, allocating
+- * read and write requests and queuing read requests.
+- *
+- * The device lock must be held when calling this function.
+- */
+-static int gs_set_config(struct gs_dev *dev, unsigned config)
++static int __init init(void)
+ {
+- int ret = 0;
+- struct usb_gadget *gadget = dev->dev_gadget;
+-
+- if (config == dev->dev_config)
+- return 0;
+-
+- gs_reset_config(dev);
+-
+- switch (config) {
+- case GS_NO_CONFIG_ID:
+- return 0;
+- case GS_BULK_CONFIG_ID:
+- if (use_acm)
+- return -EINVAL;
+- break;
+- case GS_ACM_CONFIG_ID:
+- if (!use_acm)
+- return -EINVAL;
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- dev->gser.in_desc = choose_ep_desc(gadget,
+- &gs_highspeed_in_desc,
+- &gs_fullspeed_in_desc);
+- dev->gser.out_desc = choose_ep_desc(gadget,
+- &gs_highspeed_out_desc,
+- &gs_fullspeed_out_desc);
+- dev->gser.notify_desc = dev->gser.notify
+- ? choose_ep_desc(gadget,
+- &gs_highspeed_notify_desc,
+- &gs_fullspeed_notify_desc)
+- : NULL;
+-
+- /* only support one "serial" port for now */
+- if (dev->gser.notify) {
+- ret = usb_ep_enable(dev->gser.notify, dev->gser.notify_desc);
+- if (ret < 0)
+- return ret;
+- dev->gser.notify->driver_data = dev;
+- }
+-
+- ret = gserial_connect(&dev->gser, 0);
+- if (ret < 0) {
+- if (dev->gser.notify) {
+- usb_ep_disable(dev->gser.notify);
+- dev->gser.notify->driver_data = NULL;
+- }
+- return ret;
+- }
+-
+- dev->dev_config = config;
+-
+- /* REVISIT the ACM mode should be able to actually *issue* some
+- * notifications, for at least serial state change events if
+- * not also for network connection; say so in bmCapabilities.
++ /* We *could* export two configs; that'd be much cleaner...
++ * but neither of these product IDs was defined that way.
+ */
+-
+- pr_info("gs_set_config: %s configured, %s speed %s config\n",
+- GS_LONG_NAME,
+- gadget->speed == USB_SPEED_HIGH ? "high" : "full",
+- config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
+-
+- return 0;
+-}
+-
+-/*
+- * gs_reset_config
+- *
+- * Mark the device as not configured, disable all endpoints,
+- * which forces completion of pending I/O and frees queued
+- * requests, and free the remaining write requests on the
+- * free list.
+- *
+- * The device lock must be held when calling this function.
+- */
+-static void gs_reset_config(struct gs_dev *dev)
+-{
+- if (dev->dev_config == GS_NO_CONFIG_ID)
+- return;
+-
+- dev->dev_config = GS_NO_CONFIG_ID;
+-
+- gserial_disconnect(&dev->gser);
+- if (dev->gser.notify) {
+- usb_ep_disable(dev->gser.notify);
+- dev->gser.notify->driver_data = NULL;
+- }
+-}
+-
+-/*
+- * gs_build_config_buf
+- *
+- * Builds the config descriptors in the given buffer and returns the
+- * length, or a negative error number.
+- */
+-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
+- u8 type, unsigned int index, int is_otg)
+-{
+- int len;
+- int high_speed = 0;
+- const struct usb_config_descriptor *config_desc;
+- const struct usb_descriptor_header **function;
+-
+- if (index >= gs_device_desc.bNumConfigurations)
+- return -EINVAL;
+-
+- /* other speed switches high and full speed */
+- if (gadget_is_dualspeed(g)) {
+- high_speed = (g->speed == USB_SPEED_HIGH);
+- if (type == USB_DT_OTHER_SPEED_CONFIG)
+- high_speed = !high_speed;
+- }
+-
+ if (use_acm) {
+- config_desc = &gs_acm_config_desc;
+- function = high_speed
+- ? gs_acm_highspeed_function
+- : gs_acm_fullspeed_function;
++ serial_config_driver.label = "CDC ACM config";
++ serial_config_driver.bConfigurationValue = 2;
++ device_desc.bDeviceClass = USB_CLASS_COMM;
++ device_desc.idProduct =
++ __constant_cpu_to_le16(GS_CDC_PRODUCT_ID);
+ } else {
+- config_desc = &gs_bulk_config_desc;
+- function = high_speed
+- ? gs_bulk_highspeed_function
+- : gs_bulk_fullspeed_function;
++ serial_config_driver.label = "Generic Serial config";
++ serial_config_driver.bConfigurationValue = 1;
++ device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
++ device_desc.idProduct =
++ __constant_cpu_to_le16(GS_PRODUCT_ID);
+ }
++ strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
+
+- /* for now, don't advertise srp-only devices */
+- if (!is_otg)
+- function++;
+-
+- len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
+- if (len < 0)
+- return len;
+-
+- ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+-
+- return len;
+-}
+-
+-/*
+- * gs_alloc_req
+- *
+- * Allocate a usb_request and its buffer. Returns a pointer to the
+- * usb_request or NULL if there is an error.
+- */
+-static struct usb_request *
+-gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags)
+-{
+- struct usb_request *req;
+-
+- if (ep == NULL)
+- return NULL;
+-
+- req = usb_ep_alloc_request(ep, kmalloc_flags);
+-
+- if (req != NULL) {
+- req->length = len;
+- req->buf = kmalloc(len, kmalloc_flags);
+- if (req->buf == NULL) {
+- usb_ep_free_request(ep, req);
+- return NULL;
+- }
+- }
+-
+- return req;
++ return usb_composite_register(&gserial_driver);
+ }
++module_init(init);
+
+-/*
+- * gs_free_req
+- *
+- * Free a usb_request and its buffer.
+- */
+-static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
++static void __exit cleanup(void)
+ {
+- if (ep != NULL && req != NULL) {
+- kfree(req->buf);
+- usb_ep_free_request(ep, req);
+- }
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/*
+- * gs_module_init
+- *
+- * Register as a USB gadget driver and a tty driver.
+- */
+-static int __init gs_module_init(void)
+-{
+- return usb_gadget_register_driver(&gs_gadget_driver);
+-}
+-module_init(gs_module_init);
+-
+-/*
+- * gs_module_exit
+- *
+- * Unregister as a tty driver and a USB gadget driver.
+- */
+-static void __exit gs_module_exit(void)
+-{
+- usb_gadget_unregister_driver(&gs_gadget_driver);
++ usb_composite_unregister(&gserial_driver);
++ gserial_cleanup();
+ }
+-module_exit(gs_module_exit);
++module_exit(cleanup);
+--- a/drivers/usb/gadget/u_serial.h
++++ b/drivers/usb/gadget/u_serial.h
+@@ -30,11 +30,6 @@ struct gserial {
+
+ /* REVISIT avoid this CDC-ACM support harder ... */
+ struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
+-
+- /* FIXME remove these when we switch to acm_bind_config... */
+- struct usb_ep *notify;
+- struct usb_endpoint_descriptor *notify_desc;
+- u16 port_handshake_bits;
+ };
+
+ /* port setup/teardown is handled by gadget driver */
diff --git a/usb/usb-sisusb-push-down-the-bkl.patch b/usb/usb-sisusb-push-down-the-bkl.patch
new file mode 100644
index 00000000000000..88e1e1f4dd97ce
--- /dev/null
+++ b/usb/usb-sisusb-push-down-the-bkl.patch
@@ -0,0 +1,68 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:15:32 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:48:48 +0100
+Subject: USB: sisusb: Push down the BKL
+To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20080522224848.318ea9a9@core>
+
+
+This is another case where the lock_kernel appears to be unneccessary and
+could be removed with a bit more investigative work
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/sisusbvga/sisusb.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/misc/sisusbvga/sisusb.c
++++ b/drivers/usb/misc/sisusbvga/sisusb.c
+@@ -2982,9 +2982,8 @@ sisusb_handle_command(struct sisusb_usb_
+ return retval;
+ }
+
+-static int
+-sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+- unsigned long arg)
++static long
++sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct sisusb_usb_data *sisusb;
+ struct sisusb_info x;
+@@ -2995,6 +2994,7 @@ sisusb_ioctl(struct inode *inode, struct
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
+ return -ENODEV;
+
++ lock_kernel();
+ mutex_lock(&sisusb->lock);
+
+ /* Sanity check */
+@@ -3053,6 +3053,7 @@ sisusb_ioctl(struct inode *inode, struct
+
+ err_out:
+ mutex_unlock(&sisusb->lock);
++ unlock_kernel();
+ return retval;
+ }
+
+@@ -3066,9 +3067,7 @@ sisusb_compat_ioctl(struct file *f, unsi
+ case SISUSB_GET_CONFIG_SIZE:
+ case SISUSB_GET_CONFIG:
+ case SISUSB_COMMAND:
+- lock_kernel();
+- retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
+- unlock_kernel();
++ retval = sisusb_ioctl(f, cmd, arg);
+ return retval;
+
+ default:
+@@ -3087,7 +3086,7 @@ static const struct file_operations usb_
+ #ifdef SISUSB_NEW_CONFIG_COMPAT
+ .compat_ioctl = sisusb_compat_ioctl,
+ #endif
+- .ioctl = sisusb_ioctl
++ .unlocked_ioctl = sisusb_ioctl
+ };
+
+ static struct usb_class_driver usb_sisusb_class = {
diff --git a/usb/usb-speedtch.c-fix-sparse-shadowed-variable-warning.patch b/usb/usb-speedtch.c-fix-sparse-shadowed-variable-warning.patch
new file mode 100644
index 00000000000000..2a39454197af32
--- /dev/null
+++ b/usb/usb-speedtch.c-fix-sparse-shadowed-variable-warning.patch
@@ -0,0 +1,30 @@
+From harvey.harrison@gmail.com Fri Jun 6 15:17:29 2008
+From: Harvey Harrison <harvey.harrison@gmail.com>
+Date: Fri, 30 May 2008 10:39:04 -0700
+Subject: USB: speedtch.c fix sparse shadowed variable warning
+To: Greg KH <gregkh@suse.de>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Message-ID: <1212169144.28403.200.camel@brick>
+
+
+i is used only as a for-loop index no need to declare another.
+drivers/usb/atm/speedtch.c:832:7: warning: symbol 'i' shadows an earlier one
+drivers/usb/atm/speedtch.c:766:6: originally declared here
+
+Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/atm/speedtch.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/usb/atm/speedtch.c
++++ b/drivers/usb/atm/speedtch.c
+@@ -829,7 +829,6 @@ static int speedtch_bind(struct usbatm_d
+ if (use_isoc) {
+ const struct usb_host_interface *desc = data_intf->cur_altsetting;
+ const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in;
+- int i;
+
+ use_isoc = 0; /* fall back to bulk if endpoint not found */
+
diff --git a/usb/usb-usblcd-push-down-bkl-into-driver.patch b/usb/usb-usblcd-push-down-bkl-into-driver.patch
new file mode 100644
index 00000000000000..b48e17bc18e15c
--- /dev/null
+++ b/usb/usb-usblcd-push-down-bkl-into-driver.patch
@@ -0,0 +1,55 @@
+From alan@lxorguk.ukuu.org.uk Fri Jun 6 15:14:12 2008
+From: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Date: Thu, 22 May 2008 22:07:51 +0100
+Subject: USB: usblcd: Push down BKL into driver
+To: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <20080522220751.599d73ee@core>
+
+
+I'm pretty sure this can be eliminated however I couldn't prove (or find)
+what stopped the device vanishing mid IOCTL_GET_HARD_VERSION. Perhaps a
+USB wizard could double check that and see if the lock_kernel can go
+entirely.
+
+Signed-off-by: Alan Cox <alan@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/usblcd.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/misc/usblcd.c
++++ b/drivers/usb/misc/usblcd.c
+@@ -146,7 +146,7 @@ static ssize_t lcd_read(struct file *fil
+ return retval;
+ }
+
+-static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct usb_lcd *dev;
+ u16 bcdDevice;
+@@ -158,12 +158,14 @@ static int lcd_ioctl(struct inode *inode
+
+ switch (cmd) {
+ case IOCTL_GET_HARD_VERSION:
++ lock_kernel();
+ bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
+ sprintf(buf,"%1d%1d.%1d%1d",
+ (bcdDevice & 0xF000)>>12,
+ (bcdDevice & 0xF00)>>8,
+ (bcdDevice & 0xF0)>>4,
+ (bcdDevice & 0xF));
++ unlock_kernel();
+ if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
+ return -EFAULT;
+ break;
+@@ -272,7 +274,7 @@ static const struct file_operations lcd_
+ .read = lcd_read,
+ .write = lcd_write,
+ .open = lcd_open,
+- .ioctl = lcd_ioctl,
++ .unlocked_ioctl = lcd_ioctl,
+ .release = lcd_release,
+ };
+
diff --git a/usb/wusb-drivers-uwb-wlp-sysfs.c-move-misplaced-debug-statement.patch b/usb/wusb-drivers-uwb-wlp-sysfs.c-move-misplaced-debug-statement.patch
new file mode 100644
index 00000000000000..7c06068322fed2
--- /dev/null
+++ b/usb/wusb-drivers-uwb-wlp-sysfs.c-move-misplaced-debug-statement.patch
@@ -0,0 +1,33 @@
+From akpm@linux-foundation.org Fri Jun 6 15:09:20 2008
+From: akpm@linux-foundation.org
+Date: Thu, 15 May 2008 12:35:11 -0700
+Subject: WUSB: drivers/uwb/wlp/sysfs.c: move misplaced debug statement
+To: greg@kroah.com
+Cc: akpm@linux-foundation.org, anderson.lizardo@gmail.com
+Message-ID: <200805151935.m4FJZBpa006765@imap1.linux-foundation.org>
+
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+drivers/uwb/wlp/sysfs.c:142: warning: control may reach end of non-void function 'wlp_wss_neighborhood_print_remove' being inlined
+
+Cc: "Anderson Lizardo" <anderson.lizardo@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/uwb/wlp/sysfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/uwb/wlp/sysfs.c
++++ b/drivers/uwb/wlp/sysfs.c
+@@ -125,8 +125,8 @@ ssize_t wlp_wss_neighborhood_print_remov
+
+ out:
+ mutex_unlock(&wlp->nbmutex);
+- return used;
+ d_fnend(6, dev, "wlp %p\n", wlp);
++ return used;
+ }
+
+