2008-01-19 14:35:38

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH 0/4] USB OTG Targeted Peripheral List changes

Hi all,

The following patches changes the behavior of otg tpl and makes it
more compliant to otg specs.

The 5th patch shouldn't be applied and is against musb driver which
you can find in linux-omap git tree. It's here just to show another
feature that could be done with otg tpl; make it come from platform_data.

Any comments are welcome.

Best regards,
Felipe Balbi
[email protected]


2008-01-19 14:35:56

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH 1/4] USB: OTG: Introduce new otg.c code

This patch creates moves code from otg_whitelist.h to
otg.c in order to add support for configuring OTG
options during the runtime in following patches.

No functional changes, only clean-up whitespace on few
occasions.

Signed-off-by: Felipe Balbi <[email protected]>
---
drivers/usb/core/Makefile | 4 +
drivers/usb/core/otg.c | 120 ++++++++++++++++++++++++++++++++++++++
drivers/usb/core/otg_whitelist.h | 102 ++------------------------------
3 files changed, 129 insertions(+), 97 deletions(-)
create mode 100644 drivers/usb/core/otg.c

diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index b607870..c2e51b6 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -6,6 +6,10 @@ usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
devio.o notify.o generic.o quirks.o

+ifeq ($(CONFIG_USB_OTG),y)
+ usbcore-objs += otg.o
+endif
+
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
endif
diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
new file mode 100644
index 0000000..11967c0
--- /dev/null
+++ b/drivers/usb/core/otg.c
@@ -0,0 +1,120 @@
+/*
+ * drivers/usb/core/otg.c
+ *
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/byteorder/generic.h>
+#include <linux/gfp.h>
+#include <linux/usb.h>
+
+#include "otg_whitelist.h"
+
+#ifdef CONFIG_USB_OTG_WHITELIST
+
+/*
+ * This OTG Whitelist is the OTG "Targeted Peripheral List". It should
+ * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
+ *
+ * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
+ */
+
+static struct usb_device_id whitelist_table [] = {
+
+/* hubs are optional in OTG, but very handy ... */
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
+
+#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
+/* FIXME actually, printers are NOT supposed to use device classes;
+ * they're supposed to use interface classes...
+ */
+{ USB_DEVICE_INFO(7, 1, 1) },
+{ USB_DEVICE_INFO(7, 1, 2) },
+{ USB_DEVICE_INFO(7, 1, 3) },
+#endif
+
+#ifdef CONFIG_USB_NET_CDCETHER
+/* Linux-USB CDC Ethernet gadget */
+{ USB_DEVICE(0x0525, 0xa4a1), },
+/* Linux-USB CDC Ethernet + RNDIS gadget */
+{ USB_DEVICE(0x0525, 0xa4a2), },
+#endif
+
+#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
+/* gadget zero, for testing */
+{ USB_DEVICE(0x0525, 0xa4a0), },
+#endif
+
+{ } /* Terminating entry */
+};
+
+int is_targeted(struct usb_device *dev)
+{
+ struct usb_device_id *id = whitelist_table;
+
+ /* possible in developer configs only! */
+ if (!dev->bus->otg_port)
+ return 1;
+
+ /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
+ return 0;
+
+ /* NOTE: can't use usb_match_id() since interface caches
+ * aren't set up yet. this is cut/paste from that code.
+ */
+ for (id = whitelist_table; id->match_flags; id++) {
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
+ continue;
+
+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
+ greater than any unsigned number. */
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+ (id->bDeviceClass != dev->descriptor.bDeviceClass))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+ (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+ continue;
+
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+ continue;
+
+ return 1;
+ }
+
+ /* add other match criteria here ... */
+
+
+ /* OTG MESSAGE: report errors here, customize to match your product */
+ dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ return 0;
+}
+
+#endif /* CONFIG_USB_OTG_WHITELIST */
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index 7f31a49..d6b352e 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -9,104 +9,12 @@
* (at your option) any later version.
*/

-/*
- * This OTG Whitelist is the OTG "Targeted Peripheral List". It should
- * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
- *
- * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
- */
-
-static struct usb_device_id whitelist_table [] = {
-
-/* hubs are optional in OTG, but very handy ... */
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
-
-#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
-/* FIXME actually, printers are NOT supposed to use device classes;
- * they're supposed to use interface classes...
- */
-{ USB_DEVICE_INFO(7, 1, 1) },
-{ USB_DEVICE_INFO(7, 1, 2) },
-{ USB_DEVICE_INFO(7, 1, 3) },
-#endif
-
-#ifdef CONFIG_USB_NET_CDCETHER
-/* Linux-USB CDC Ethernet gadget */
-{ USB_DEVICE(0x0525, 0xa4a1), },
-/* Linux-USB CDC Ethernet + RNDIS gadget */
-{ USB_DEVICE(0x0525, 0xa4a2), },
-#endif
-
-#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
-/* gadget zero, for testing */
-{ USB_DEVICE(0x0525, 0xa4a0), },
-#endif
-
-{ } /* Terminating entry */
-};
-
-static int is_targeted(struct usb_device *dev)
-{
- struct usb_device_id *id = whitelist_table;
-
- /* possible in developer configs only! */
- if (!dev->bus->otg_port)
- return 1;
-
- /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
- if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
- le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
- return 0;
-
- /* NOTE: can't use usb_match_id() since interface caches
- * aren't set up yet. this is cut/paste from that code.
- */
- for (id = whitelist_table; id->match_flags; id++) {
- if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
- id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
- continue;
-
- if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
- id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
- continue;
-
- /* No need to test id->bcdDevice_lo != 0, since 0 is never
- greater than any unsigned number. */
- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
- (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
- continue;
-
- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
- (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
- continue;
-
- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
- (id->bDeviceClass != dev->descriptor.bDeviceClass))
- continue;
-
- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
- (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
- continue;
-
- if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
- (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
- continue;
-
- return 1;
- }
-
- /* add other match criteria here ... */
-
-
- /* OTG MESSAGE: report errors here, customize to match your product */
- dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
#ifdef CONFIG_USB_OTG_WHITELIST
- return 0;
+extern int is_targeted(struct usb_device *);
#else
- return 1;
-#endif
+static inline int is_targeted(struct usb_device *d)
+{
+ return 0;
}
+#endif

--
1.5.4.rc3.24.gb53139

2008-01-19 14:36:18

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH 2/4] USB: OTG: Make otg_get_transceiver() and otg_set_transceiver() generic

From: Tony Lidgren <[email protected]>

Move otg_get_transceiver() and otg_set_transceiver() from omap specific code
to common otg.c so other upcoming drivers can share them.

Signed-off-by: Tony Lindgren <[email protected]>
Signed-off-by: Felipe Balbi <[email protected]>
---
arch/arm/plat-omap/usb.c | 32 --------------------------------
drivers/usb/core/otg.c | 20 ++++++++++++++++++++
2 files changed, 20 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
index 11967c0..531afa6 100644
--- a/drivers/usb/core/otg.c
+++ b/drivers/usb/core/otg.c
@@ -14,9 +14,29 @@
#include <linux/byteorder/generic.h>
#include <linux/gfp.h>
#include <linux/usb.h>
+#include <linux/usb/otg.h>

#include "otg_whitelist.h"

+static struct otg_transceiver *xceiv;
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+ if (xceiv && x)
+ return -EBUSY;
+ xceiv = x;
+ return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+struct otg_transceiver *otg_get_transceiver(void)
+{
+ if (xceiv)
+ get_device(xceiv->dev);
+ return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
#ifdef CONFIG_USB_OTG_WHITELIST

/*
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index a5aedf9..5cd39fa 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -76,38 +76,6 @@

/*-------------------------------------------------------------------------*/

-#ifdef CONFIG_ARCH_OMAP_OTG
-
-static struct otg_transceiver *xceiv;
-
-/**
- * otg_get_transceiver - find the (single) OTG transceiver driver
- *
- * Returns the transceiver driver, after getting a refcount to it; or
- * null if there is no such transceiver. The caller is responsible for
- * releasing that count.
- */
-struct otg_transceiver *otg_get_transceiver(void)
-{
- if (xceiv)
- get_device(xceiv->dev);
- return xceiv;
-}
-EXPORT_SYMBOL(otg_get_transceiver);
-
-int otg_set_transceiver(struct otg_transceiver *x)
-{
- if (xceiv && x)
- return -EBUSY;
- xceiv = x;
- return 0;
-}
-EXPORT_SYMBOL(otg_set_transceiver);
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
#if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP15XX)

static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
--
1.5.4.rc3.24.gb53139

2008-01-19 14:36:33

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH 3/4] USB: OTG: Start using new otg tpl.

Introduces otg_set_error and start using it when we
want to show otg_errors.

Based on previous patch from Tony Lindgren <[email protected]>

Signed-off-by: Felipe Balbi <[email protected]>
---
drivers/usb/core/hub.c | 16 ++++-
drivers/usb/core/otg.c | 127 ++++++++++++++++++++++++++++++++-----
drivers/usb/core/otg_whitelist.h | 20 ------
drivers/usb/core/sysfs.c | 131 ++++++++++++++++++++++++++++++++++++++
include/linux/usb/otg.h | 19 ++++++
5 files changed, 273 insertions(+), 40 deletions(-)
delete mode 100644 drivers/usb/core/otg_whitelist.h

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b04d232..0b1a7b9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -23,6 +23,8 @@
#include <linux/mutex.h>
#include <linux/freezer.h>

+#include <linux/usb/otg.h>
+
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -1252,6 +1254,7 @@ static int usb_configure_device_otg(struct usb_device *udev)
le16_to_cpu(udev->config[0].desc.wTotalLength),
USB_DT_OTG, (void **) &desc) == 0) {
if (desc->bmAttributes & USB_OTG_HNP) {
+ struct otg_transceiver *xceiv = otg_get_transceiver();
unsigned port1 = udev->portnum;

dev_info(&udev->dev,
@@ -1270,19 +1273,23 @@ static int usb_configure_device_otg(struct usb_device *udev)
: USB_DEVICE_A_ALT_HNP_SUPPORT,
0, NULL, 0, USB_CTRL_SET_TIMEOUT);
if (err < 0) {
- /* OTG MESSAGE: report errors here,
- * customize to match your product.
- */
+ otg_set_error(xceiv,
+ OTG_ERR_DEVICE_NOT_RESPONDING);
dev_info(&udev->dev,
"can't set HNP mode; %d\n",
err);
bus->b_hnp_enable = 0;
}
+ tpl_enabled = xceiv->tpl_enabled;
+ put_device(xceiv->dev);
}
}
}

- if (!is_targeted(udev)) {
+ if (err == 0)
+ err = otg_targeted(udev);
+
+ if (err != OTG_ERR_DEVICE_SUPPORTED && tpl_enabled) {

/* Maybe it can talk to us, though we can't talk to it.
* (Includes HNP test device.)
@@ -1316,6 +1323,7 @@ fail:
static int usb_configure_device(struct usb_device *udev)
{
int err;
+ unsigned tpl_enabled = 0;

if (udev->config == NULL) {
err = usb_get_configuration(udev);
diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
index 531afa6..e9ece31 100644
--- a/drivers/usb/core/otg.c
+++ b/drivers/usb/core/otg.c
@@ -2,6 +2,7 @@
* drivers/usb/core/otg.c
*
* Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2007-2008 Nokia Corporation
*
* 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
@@ -9,15 +10,10 @@
* (at your option) any later version.
*/

-#include <linux/device.h>
-#include <linux/mod_devicetable.h>
-#include <linux/byteorder/generic.h>
-#include <linux/gfp.h>
+#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>

-#include "otg_whitelist.h"
-
static struct otg_transceiver *xceiv;

int otg_set_transceiver(struct otg_transceiver *x)
@@ -37,6 +33,22 @@ struct otg_transceiver *otg_get_transceiver(void)
}
EXPORT_SYMBOL(otg_get_transceiver);

+/* OTG MESSAGE: report errors here, customize to match your product */
+void otg_set_error(struct otg_transceiver *x, enum usb_otg_error errno)
+{
+ if (!x)
+ return;
+ if (!x->tpl_enabled)
+ x->last_error = OTG_ERR_DEVICE_SUPPORTED;
+ else
+ x->last_error = errno;
+
+ sysfs_notify(&x->host->root_hub->dev.kobj, NULL, "otg_last_error");
+}
+EXPORT_SYMBOL(otg_set_error);
+
+/*-------------------------------------------------------------------------*/
+
#ifdef CONFIG_USB_OTG_WHITELIST

/*
@@ -46,7 +58,7 @@ EXPORT_SYMBOL(otg_get_transceiver);
* YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
*/

-static struct usb_device_id whitelist_table [] = {
+static struct usb_device_id whitelist_table [] __initdata = {

/* hubs are optional in OTG, but very handy ... */
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
@@ -76,23 +88,74 @@ static struct usb_device_id whitelist_table [] = {
{ } /* Terminating entry */
};

-int is_targeted(struct usb_device *dev)
+struct otg_device {
+ struct list_head list;
+ struct usb_device_id id;
+};
+
+static struct list_head tpl_devices;
+
+static void tpl_add_device(struct usb_device_id *id)
+{
+ struct otg_device *otg;
+
+ otg = kzalloc(sizeof(*otg), GFP_KERNEL);
+ if (!otg)
+ return;
+ INIT_LIST_HEAD(&otg->list);
+ memcpy(&otg->id, id, sizeof(struct usb_device_id));
+ list_add_tail(&otg->list, &tpl_devices);
+}
+
+static void tpl_add_devices(struct usb_device_id *whitelist_table)
+{
+ struct usb_device_id *id;
+
+ for (id = whitelist_table; id->match_flags; id++)
+ tpl_add_device(id);
+}
+
+ssize_t otg_print_whitelist(char *buf)
+{
+ struct otg_device *otg;
+ ssize_t len = 0;
+
+ list_for_each_entry(otg, &tpl_devices, list)
+ len += sprintf(buf + len, "%04x:%04x\t%02x %02x %02x\n",
+ le16_to_cpu(otg->id.idVendor),
+ le16_to_cpu(otg->id.idProduct),
+ otg->id.bDeviceClass,
+ otg->id.bDeviceSubClass,
+ otg->id.bDeviceProtocol);
+ return len;
+}
+
+int otg_targeted(struct usb_device *dev)
{
- struct usb_device_id *id = whitelist_table;
+ struct otg_device *otg;
+
+ if (!xceiv || !xceiv->tpl_enabled)
+ return OTG_ERR_DEVICE_SUPPORTED;

/* possible in developer configs only! */
if (!dev->bus->otg_port)
- return 1;
+ goto targeted;

/* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
- return 0;
+ goto err;
+
+ /* roothub don't need to be tested here */
+ if (!dev->parent)
+ goto targeted;

/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
- for (id = whitelist_table; id->match_flags; id++) {
+ list_for_each_entry(otg, &tpl_devices, list) {
+ struct usb_device_id *id = &otg->id;
+
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
continue;
@@ -123,18 +186,50 @@ int is_targeted(struct usb_device *dev)
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;

- return 1;
+ goto targeted;
}

/* add other match criteria here ... */

-
- /* OTG MESSAGE: report errors here, customize to match your product */
- dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+err:
+ dev_err(&dev->dev, "%s v%04x p%04x is not supported\n",
+ dev->descriptor.bDeviceClass & USB_CLASS_HUB ? "hub" : "device",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
+ if (dev->descriptor.bDeviceClass & USB_CLASS_HUB)
+ otg_set_error(xceiv, OTG_ERR_HUB_NOT_SUPPORTED);
+ else
+ otg_set_error(xceiv, OTG_ERR_DEVICE_NOT_SUPPORTED);
+
+ return xceiv->last_error;
+
+targeted:
+ xceiv->last_error = OTG_ERR_DEVICE_SUPPORTED;
+ return xceiv->last_error;
+}
+
+static int __init tpl_init(void)
+{
+ INIT_LIST_HEAD(&tpl_devices);
+ tpl_add_devices(whitelist_table);
+ if (xceiv)
+ xceiv->tpl_enabled = 1;

return 0;
}

+static void __exit tpl_exit(void)
+{
+ struct otg_device *otg;
+
+ if (xceiv)
+ xceiv->tpl_enabled = 0;
+
+ list_for_each_entry(otg, &tpl_devices, list)
+ kfree(otg);
+}
+
+module_init(tpl_init);
+module_exit(tpl_exit);
+
#endif /* CONFIG_USB_OTG_WHITELIST */
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
deleted file mode 100644
index d6b352e..0000000
--- a/drivers/usb/core/otg_whitelist.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * drivers/usb/core/otg_whitelist.h
- *
- * Copyright (C) 2004 Texas Instruments
- *
- * 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.
- */
-
-#ifdef CONFIG_USB_OTG_WHITELIST
-extern int is_targeted(struct usb_device *);
-#else
-static inline int is_targeted(struct usb_device *d)
-{
- return 0;
-}
-#endif
-
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 32bd130..9efc01a 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/usb.h>
+#include <linux/usb/otg.h>
#include "usb.h"

/* Active configuration fields */
@@ -91,6 +92,132 @@ usb_string_attr(product);
usb_string_attr(manufacturer);
usb_string_attr(serial);

+#ifdef CONFIG_USB_OTG
+
+static ssize_t
+otg_last_error_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct otg_transceiver *xceiv = otg_get_transceiver();
+ char *msg;
+ ssize_t ret;
+
+ if (!xceiv)
+ return -ENODEV;
+
+ switch (xceiv->last_error) {
+ case OTG_ERR_DEVICE_SUPPORTED:
+ msg = "is supported";
+ break;
+ case OTG_ERR_DEVICE_NOT_SUPPORTED:
+ msg = "is not supported";
+ break;
+ case OTG_ERR_DEVICE_NOT_RESPONDING:
+ msg = "is not responding";
+ break;
+ default:
+ msg = "unknown error";
+ }
+
+ ret = sprintf(buf, "OTG%02d: Device %s\n", xceiv->last_error, msg);
+ put_device(xceiv->dev);
+
+ return ret;
+}
+static DEVICE_ATTR(otg_last_error, 0444, otg_last_error_show, NULL);
+
+#ifdef CONFIG_USB_OTG_WHITELIST
+
+static ssize_t
+otg_whitelist_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return otg_print_whitelist(buf);
+}
+static DEVICE_ATTR(otg_whitelist, 0644, otg_whitelist_show, NULL);
+
+static ssize_t
+otg_whitelist_status_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct otg_transceiver *xceiv = otg_get_transceiver();
+ int enable;
+
+ sscanf(buf, "%d", &enable);
+ if (!xceiv)
+ return 0;
+ if (enable)
+ xceiv->tpl_enabled = 1;
+ else
+ xceiv->tpl_enabled = 0;
+ put_device(xceiv->dev);
+
+ return n;
+}
+
+static ssize_t
+otg_whitelist_status_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct otg_transceiver *xceiv = otg_get_transceiver();
+ int ret;
+
+ if (!xceiv)
+ return -ENODEV;
+
+ if (xceiv->tpl_enabled)
+ ret = sprintf(buf, "enabled\n");
+ else
+ ret = sprintf(buf, "disabled\n");
+ put_device(xceiv->dev);
+
+ return ret;
+}
+static DEVICE_ATTR(otg_whitelist_status, 0644, otg_whitelist_status_show,
+ otg_whitelist_status_store);
+
+#endif /* CONFIG_USB_OTG_WHITELIST */
+
+static struct attribute *otg_dev_attrs[] = {
+ &dev_attr_otg_last_error.attr,
+
+#ifdef CONFIG_USB_OTG_WHITELIST
+ &dev_attr_otg_whitelist.attr,
+ &dev_attr_otg_whitelist_status.attr,
+#endif
+
+};
+
+static int add_otg_attributes(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ struct usb_bus *bus = udev->bus;
+ int ret = 0, i;
+
+ if (is_usb_device(dev) && !udev->parent && bus->otg_port)
+ for (i = 0; i < ARRAY_SIZE(otg_dev_attrs); i++) {
+ ret = sysfs_create_file(&dev->kobj, otg_dev_attrs[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void remove_otg_attributes(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ struct usb_bus *bus = udev->bus;
+ int i;
+
+ if (is_usb_device(dev) && !udev->parent && bus->otg_port)
+ for (i = 0; i < ARRAY_SIZE(otg_dev_attrs); i++)
+ sysfs_remove_file(&dev->kobj, otg_dev_attrs[i]);
+}
+
+#else
+#define add_otg_attributes(x) 0
+#define remove_otg_attributes(x) do {} while (0)
+#endif /* CONFIG_USB_OTG */
+
static ssize_t
show_speed(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -575,6 +702,9 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
goto error;
}
+ retval = add_otg_attributes(dev);
+ if (retval)
+ goto error;
retval = usb_create_ep_files(dev, &udev->ep0, udev);
if (retval)
goto error;
@@ -593,6 +723,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
device_remove_file(dev, &dev_attr_serial);
remove_power_attributes(dev);
+ remove_otg_attributes(dev);
remove_persist_attributes(dev);
device_remove_bin_file(dev, &dev_bin_attr_descriptors);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 9897f7a..e748030 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -31,6 +31,13 @@ enum usb_otg_state {
OTG_STATE_A_VBUS_ERR,
};

+enum usb_otg_error {
+ OTG_ERR_DEVICE_SUPPORTED,
+ OTG_ERR_DEVICE_NOT_SUPPORTED,
+ OTG_ERR_DEVICE_NOT_RESPONDING,
+ OTG_ERR_HUB_NOT_SUPPORTED,
+};
+
/*
* the otg driver needs to interact with both device side and host side
* usb controllers. it decides which controller is active at a given
@@ -42,7 +49,10 @@ struct otg_transceiver {
const char *label;

u8 default_a;
+ unsigned tpl_enabled:1;
+
enum usb_otg_state state;
+ enum usb_otg_error last_error;

struct usb_bus *host;
struct usb_gadget *gadget;
@@ -89,6 +99,7 @@ otg_start_hnp(struct otg_transceiver *otg)
return otg->start_hnp(otg);
}

+extern void otg_set_error(struct otg_transceiver *otg, enum usb_otg_error);

/* for HCDs */
static inline int
@@ -129,3 +140,11 @@ otg_start_srp(struct otg_transceiver *otg)

/* for OTG controller drivers (and maybe other stuff) */
extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
+
+#ifdef CONFIG_USB_OTG_WHITELIST
+struct usb_device;
+extern int otg_targeted(struct usb_device *dev);
+extern ssize_t otg_print_whitelist(char *buf);
+#else
+#define otg_targeted(x) OTG_ERR_IS_TARGETED
+#endif
--
1.5.4.rc3.24.gb53139

2008-01-19 14:36:50

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH 4/4] USB: OTG: Add check for roothub initialization

From: Tony Lindgren <[email protected]>

Roothub may not be initialized if no gadget is loaded on musb
for example. Add check for roothub initialization. Also make
comment more accurate.

Signed-off-by: Tony Lindgren <[email protected]>
Signed-off-by: Felipe Balbi <[email protected]>
---
drivers/usb/core/otg.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
index e9ece31..9a2ce7e 100644
--- a/drivers/usb/core/otg.c
+++ b/drivers/usb/core/otg.c
@@ -33,16 +33,25 @@ struct otg_transceiver *otg_get_transceiver(void)
}
EXPORT_SYMBOL(otg_get_transceiver);

-/* OTG MESSAGE: report errors here, customize to match your product */
+/*
+ * OTG MESSAGE: report errors here, customize to match your product
+ * See also otg_last_error_show().
+ */
void otg_set_error(struct otg_transceiver *x, enum usb_otg_error errno)
{
if (!x)
return;
+
if (!x->tpl_enabled)
x->last_error = OTG_ERR_DEVICE_SUPPORTED;
else
x->last_error = errno;

+ if (!x->host->root_hub) {
+ printk(KERN_WARNING "OTG: root hub not yet initialized\n");
+ return;
+ }
+
sysfs_notify(&x->host->root_hub->dev.kobj, NULL, "otg_last_error");
}
EXPORT_SYMBOL(otg_set_error);
--
1.5.4.rc3.24.gb53139

2008-01-19 14:37:10

by Felipe Balbi

[permalink] [raw]
Subject: [PATCH] USB: OTG: Make otg_tpl come from platform_data

This is applicable to n8X0. It makes otg tpl come
from musb_platform_data and be initialized in otg.c

This provides a better code style and better handling
of otg capable devices.

Signed-off-by: Felipe Balbi <[email protected]>
---
arch/arm/mach-omap2/board-n800-usb.c | 14 +++++++++++
drivers/usb/core/otg.c | 43 ++++------------------------------
drivers/usb/musb/musb_core.c | 4 +++
include/linux/usb/musb.h | 5 ++++
include/linux/usb/otg.h | 5 ++++
5 files changed, 33 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-omap2/board-n800-usb.c b/arch/arm/mach-omap2/board-n800-usb.c
index 7599f64..a2ea1a0 100644
--- a/arch/arm/mach-omap2/board-n800-usb.c
+++ b/arch/arm/mach-omap2/board-n800-usb.c
@@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/usb/musb.h>
+#include <linux/usb.h>
#include <asm/arch/gpmc.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pm.h>
@@ -35,6 +36,16 @@ static int tusb_set_clock(struct clk *osc_ck, int state);
# define BOARD_MODE MUSB_HOST
#endif

+#ifdef CONFIG_USB_OTG_WHITELIST
+struct usb_device_id otg_tpl[] __initdata = {
+ /* Support known mass storage devices */
+ { USB_DEVICE(0x0421, 0x0431), }, /* N770 */
+ { USB_DEVICE(0x0421, 0x04c3), }, /* N800 */
+ { USB_DEVICE(0x0421, 0x0096), }, /* RX44 */
+ { } /* Terminating entry */
+};
+#endif
+
static struct musb_hdrc_platform_data tusb_data = {
.mode = BOARD_MODE,
.multipoint = 1,
@@ -43,6 +54,9 @@ static struct musb_hdrc_platform_data tusb_data = {
.min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */
.power = 100, /* Max 100 mA VBUS for host mode */
.clock = "osc_ck",
+#ifdef CONFIG_USB_OTG_WHITELIST
+ .otg_tpl = otg_tpl,
+#endif
};

/*
diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
index 9a2ce7e..8795382 100644
--- a/drivers/usb/core/otg.c
+++ b/drivers/usb/core/otg.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
+#include <linux/platform_device.h>

static struct otg_transceiver *xceiv;

@@ -60,43 +61,6 @@ EXPORT_SYMBOL(otg_set_error);

#ifdef CONFIG_USB_OTG_WHITELIST

-/*
- * This OTG Whitelist is the OTG "Targeted Peripheral List". It should
- * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
- *
- * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
- */
-
-static struct usb_device_id whitelist_table [] __initdata = {
-
-/* hubs are optional in OTG, but very handy ... */
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
-
-#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
-/* FIXME actually, printers are NOT supposed to use device classes;
- * they're supposed to use interface classes...
- */
-{ USB_DEVICE_INFO(7, 1, 1) },
-{ USB_DEVICE_INFO(7, 1, 2) },
-{ USB_DEVICE_INFO(7, 1, 3) },
-#endif
-
-#ifdef CONFIG_USB_NET_CDCETHER
-/* Linux-USB CDC Ethernet gadget */
-{ USB_DEVICE(0x0525, 0xa4a1), },
-/* Linux-USB CDC Ethernet + RNDIS gadget */
-{ USB_DEVICE(0x0525, 0xa4a2), },
-#endif
-
-#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
-/* gadget zero, for testing */
-{ USB_DEVICE(0x0525, 0xa4a0), },
-#endif
-
-{ } /* Terminating entry */
-};
-
struct otg_device {
struct list_head list;
struct usb_device_id id;
@@ -220,10 +184,13 @@ targeted:
static int __init tpl_init(void)
{
INIT_LIST_HEAD(&tpl_devices);
- tpl_add_devices(whitelist_table);
+
if (xceiv)
xceiv->tpl_enabled = 1;

+ if (xceiv->otg_tpl != NULL)
+ tpl_add_devices(xceiv->otg_tpl);
+
return 0;
}

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index fb37e2c..cf29bde 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1939,6 +1939,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb->set_clock = plat->set_clock;
musb->min_power = plat->min_power;

+#ifdef CONFIG_USB_OTG_WHITELIST
+ musb->xceiv.otg_tpl = plat->otg_tpl;
+#endif
+
/* Clock usage is chip-specific ... functional clock (DaVinci,
* OMAP2430), or PHY ref (some TUSB6010 boards). All this core
* code does is make sure a clock handle is available; platform
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
index d325a0d..76f21b7 100644
--- a/include/linux/usb/musb.h
+++ b/include/linux/usb/musb.h
@@ -7,6 +7,8 @@
* key configuration differences between boards.
*/

+#include <linux/mod_devicetable.h>
+
/* The USB role is defined by the connector used on the board, so long as
* standards are being followed. (Developer boards sometimes won't.)
*/
@@ -26,6 +28,9 @@ struct musb_hdrc_platform_data {
/* for clk_get() */
const char *clock;

+ /* OTG Targeted Peripheral List */
+ struct usb_device_id *otg_tpl;
+
/* (HOST or OTG) switch VBUS on/off */
int (*set_vbus)(struct device *dev, int is_on);

diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index e748030..79c36fc 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -1,5 +1,7 @@
// include/linux/usb/otg.h

+#include <linux/mod_devicetable.h>
+
/*
* These APIs may be used between USB controllers. USB device drivers
* (for either host or peripheral roles) don't use these calls; they
@@ -57,6 +59,9 @@ struct otg_transceiver {
struct usb_bus *host;
struct usb_gadget *gadget;

+ /* OTG Target Peripheral List */
+ struct usb_device_id *otg_tpl;
+
/* to pass extra port status to the root hub */
u16 port_status;
u16 port_change;
--
1.5.4.rc3.24.gb53139

2008-08-25 13:35:24

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH 2/4] USB: OTG: Make otg_get_transceiver() and otg_set_transceiver() generic

Hi,

On Sat, Jan 19, 2008 at 4:37 PM, Felipe Balbi <[email protected]> wrote:
> From: Tony Lidgren <[email protected]>
>
> Move otg_get_transceiver() and otg_set_transceiver() from omap specific code
> to common otg.c so other upcoming drivers can share them.
>
> Signed-off-by: Tony Lindgren <[email protected]>
> Signed-off-by: Felipe Balbi <[email protected]>
> ---
> arch/arm/plat-omap/usb.c | 32 --------------------------------
> drivers/usb/core/otg.c | 20 ++++++++++++++++++++
> 2 files changed, 20 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/usb/core/otg.c b/drivers/usb/core/otg.c
> index 11967c0..531afa6 100644
> --- a/drivers/usb/core/otg.c
> +++ b/drivers/usb/core/otg.c
> @@ -14,9 +14,29 @@
> #include <linux/byteorder/generic.h>
> #include <linux/gfp.h>
> #include <linux/usb.h>
> +#include <linux/usb/otg.h>
>
> #include "otg_whitelist.h"
>
> +static struct otg_transceiver *xceiv;
> +
> +int otg_set_transceiver(struct otg_transceiver *x)
> +{
> + if (xceiv && x)
> + return -EBUSY;
> + xceiv = x;
> + return 0;
> +}
> +EXPORT_SYMBOL(otg_set_transceiver);
> +
> +struct otg_transceiver *otg_get_transceiver(void)
> +{
> + if (xceiv)
> + get_device(xceiv->dev);
> + return xceiv;
> +}
> +EXPORT_SYMBOL(otg_get_transceiver);
> +
> #ifdef CONFIG_USB_OTG_WHITELIST
>
> /*
> diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
> index a5aedf9..5cd39fa 100644
> --- a/arch/arm/plat-omap/usb.c
> +++ b/arch/arm/plat-omap/usb.c
> @@ -76,38 +76,6 @@
>
> /*-------------------------------------------------------------------------*/
>
> -#ifdef CONFIG_ARCH_OMAP_OTG
> -
> -static struct otg_transceiver *xceiv;
> -
> -/**
> - * otg_get_transceiver - find the (single) OTG transceiver driver
> - *
> - * Returns the transceiver driver, after getting a refcount to it; or
> - * null if there is no such transceiver. The caller is responsible for
> - * releasing that count.
> - */
> -struct otg_transceiver *otg_get_transceiver(void)
> -{
> - if (xceiv)
> - get_device(xceiv->dev);
> - return xceiv;
> -}
> -EXPORT_SYMBOL(otg_get_transceiver);
> -
> -int otg_set_transceiver(struct otg_transceiver *x)
> -{
> - if (xceiv && x)
> - return -EBUSY;
> - xceiv = x;
> - return 0;
> -}
> -EXPORT_SYMBOL(otg_set_transceiver);
> -
> -#endif
> -
> -/*-------------------------------------------------------------------------*/
> -
> #if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP15XX)
>
> static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
> --
> 1.5.4.rc3.24.gb53139
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

what is the status of this patch? I guess moving
otg_get/set_transceiver into usb core like this (and adding
otg_put_transceiver) is better than duplicating this code for PXA and
other architectures?

regards
Philipp

2008-08-25 13:40:00

by Felipe Balbi

[permalink] [raw]
Subject: Re: [PATCH 2/4] USB: OTG: Make otg_get_transceiver() and otg_set_transceiver() generic

On Mon, Aug 25, 2008 at 03:35:06PM +0200, ext pHilipp Zabel wrote:
> what is the status of this patch? I guess moving
> otg_get/set_transceiver into usb core like this (and adding
> otg_put_transceiver) is better than duplicating this code for PXA and
> other architectures?

Yeah, this was never applied. I'll try to format the patches again, but
it'll take a while since I'm really busy with work.

--
balbi