* [PATCH 01/12] USB: i.MX chipidea: Implement OTG support for the poor
2014-07-19 9:15 USB Host patches Sascha Hauer
@ 2014-07-19 9:15 ` Sascha Hauer
2014-07-19 9:15 ` [PATCH 02/12] commands: usb: add tree view capability Sascha Hauer
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:15 UTC (permalink / raw)
To: barebox
For situations when we don't know the desired mode for the OTG port
we register a otg device which has a mode parameter to specifiy the
desired mode on the command line.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/imx/chipidea-imx.c | 101 +++++++++++++++++++++++++++++++++++++----
include/usb/chipidea-imx.h | 1 +
2 files changed, 93 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 9b6829b..62feae8 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -20,6 +20,7 @@
#include <driver.h>
#include <usb/usb.h>
#include <usb/ehci.h>
+#include <regulator.h>
#include <usb/chipidea-imx.h>
#include <usb/ulpi.h>
#include <usb/fsl_usb2.h>
@@ -31,9 +32,12 @@ struct imx_chipidea {
void __iomem *base;
struct ehci_data data;
unsigned long flags;
- enum imx_usb_mode mode;
+ uint32_t mode;
int portno;
enum usb_phy_interface phymode;
+ struct param_d *param_mode;
+ int role_registered;
+ struct regulator *vbus;
};
static int imx_chipidea_port_init(void *drvdata)
@@ -99,6 +103,19 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
case USB_DR_MODE_PERIPHERAL:
ci->mode = IMX_USB_MODE_DEVICE;
break;
+ case USB_DR_MODE_OTG:
+ ci->mode = IMX_USB_MODE_OTG;
+ break;
+ case USB_DR_MODE_UNKNOWN:
+ /*
+ * No dr_mode specified. This means it can either be OTG
+ * for port 0 or host mode for the other host-only ports.
+ */
+ if (ci->portno == 0)
+ ci->mode = IMX_USB_MODE_OTG;
+ else
+ ci->mode = IMX_USB_MODE_HOST;
+ break;
}
ci->phymode = of_usb_get_phy_mode(ci->dev->device_node, NULL);
@@ -129,6 +146,72 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
return 0;
}
+static int ci_register_role(struct imx_chipidea *ci)
+{
+ if (ci->role_registered)
+ return -EBUSY;
+
+ if (ci->mode == IMX_USB_MODE_HOST) {
+ if (IS_ENABLED(CONFIG_USB_EHCI)) {
+ ci->role_registered = 1;
+ return ehci_register(ci->dev, &ci->data);
+ } else {
+ dev_err(ci->dev, "Host support not available\n");
+ return -ENODEV;
+ }
+ }
+
+ if (ci->mode == IMX_USB_MODE_DEVICE) {
+ if (IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC)) {
+ ci->role_registered = 1;
+ return ci_udc_register(ci->dev, ci->base);
+ } else {
+ dev_err(ci->dev, "USB device support not available\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static int ci_set_mode(struct param_d *param, void *priv)
+{
+ struct imx_chipidea *ci = priv;
+
+ if (ci->role_registered)
+ return -EBUSY;
+
+ return ci_register_role(ci);
+}
+
+static const char *ci_mode_names[] = {
+ "host", "peripheral", "otg"
+};
+
+static struct device_d imx_otg_device = {
+ .name = "otg",
+ .id = DEVICE_ID_SINGLE,
+};
+
+static int ci_register_otg_device(struct imx_chipidea *ci)
+{
+ int ret;
+
+ if (imx_otg_device.parent)
+ return -EBUSY;
+
+ imx_otg_device.parent = ci->dev;
+
+ ret = register_device(&imx_otg_device);
+ if (ret)
+ return ret;
+
+ ci->param_mode = dev_add_param_enum(&imx_otg_device, "mode",
+ ci_set_mode, NULL, &ci->mode,
+ ci_mode_names, ARRAY_SIZE(ci_mode_names), ci);
+ return 0;
+}
+
static int imx_chipidea_probe(struct device_d *dev)
{
struct imxusb_platformdata *pdata = dev->platform_data;
@@ -154,6 +237,10 @@ static int imx_chipidea_probe(struct device_d *dev)
ci->mode = pdata->mode;
}
+ ci->vbus = regulator_get(dev, "vbus");
+
+ regulator_enable(ci->vbus);
+
base = dev_request_mem_region(dev, 0);
if (!base)
return -ENODEV;
@@ -178,14 +265,10 @@ static int imx_chipidea_probe(struct device_d *dev)
ci->data.hcor = base + 0x140;
ci->data.flags = EHCI_HAS_TT;
- if (ci->mode == IMX_USB_MODE_HOST && IS_ENABLED(CONFIG_USB_EHCI)) {
- ret = ehci_register(dev, &ci->data);
- } else if (ci->mode == IMX_USB_MODE_DEVICE && IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC)) {
- ret = ci_udc_register(dev, base);
- } else {
- dev_err(dev, "No supported role\n");
- ret = -ENODEV;
- }
+ if (ci->mode == IMX_USB_MODE_OTG)
+ ret = ci_register_otg_device(ci);
+ else
+ ret = ci_register_role(ci);
return ret;
};
diff --git a/include/usb/chipidea-imx.h b/include/usb/chipidea-imx.h
index 487217c..09e19af 100644
--- a/include/usb/chipidea-imx.h
+++ b/include/usb/chipidea-imx.h
@@ -37,6 +37,7 @@
enum imx_usb_mode {
IMX_USB_MODE_HOST,
IMX_USB_MODE_DEVICE,
+ IMX_USB_MODE_OTG,
};
struct imxusb_platformdata {
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 02/12] commands: usb: add tree view capability
2014-07-19 9:15 USB Host patches Sascha Hauer
2014-07-19 9:15 ` [PATCH 01/12] USB: i.MX chipidea: Implement OTG support for the poor Sascha Hauer
@ 2014-07-19 9:15 ` Sascha Hauer
2014-07-19 9:15 ` [PATCH 03/12] USB: host: simplify usb_new_device Sascha Hauer
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:15 UTC (permalink / raw)
To: barebox
From: Antony Pavlov <antonynpavlov@gmail.com>
This patch adds U-Boot 'usb tree' command functionality to barebox.
Here is an example output:
1 ID 0000:0000
| u-boot EHCI Host Controller
|
+-2 ID 05e3:0606
| USB2.0 Hub
|
+-3 ID 10c4:ea60
| Silicon Labs CP2102 USB to UART Bridge Contr P-00-00669
|
+-4 ID 05e3:0606
| | USB2.0 Hub
| |
| +-5 ID 05e3:0608
| | | USB2.0 Hub
| | |
| | +-6 ID 0d8c:000c
| | C-Media USB Headphone Set
| |
| +-7 ID 0d8c:000c
| C-Media USB Headphone Set
|
+-8 ID 0846:1040
NETGEAR NETGEAR FA120 Adapter
The tree view is enabled with 'usb -t'
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/usb.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++--
drivers/usb/core/usb.c | 2 +-
include/usb/usb.h | 3 ++
3 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/commands/usb.c b/commands/usb.c
index 073c79c..c158852 100644
--- a/commands/usb.c
+++ b/commands/usb.c
@@ -22,21 +22,118 @@
#include <usb/usb.h>
#include <getopt.h>
+/* shows the device tree recursively */
+static void usb_show_tree_graph(struct usb_device *dev, char *pre)
+{
+ int i, index;
+ int has_child, last_child;
+
+ index = strlen(pre);
+ printf(" %s", pre);
+ /* check if the device has connected children */
+ has_child = 0;
+
+ for (i = 0; i < dev->maxchild; i++) {
+ if (dev->children[i] != NULL)
+ has_child = 1;
+ }
+
+ /* check if we are the last one */
+ last_child = 1;
+
+ if (dev->parent) {
+ for (i = 0; i < dev->parent->maxchild; i++) {
+ if (dev->parent->children[i])
+ last_child = 0;
+
+ if (dev->parent->children[i] == dev)
+ last_child = 1;
+ } /* for all children of the parent */
+ printf("\b+-");
+
+ /* correct last child */
+ if (last_child)
+ pre[index - 1] = ' ';
+ } else {
+ /* if not root hub */
+ printf(" ");
+ }
+
+ printf("%d ", dev->devnum);
+
+ pre[index++] = ' ';
+ pre[index++] = has_child ? '|' : ' ';
+ pre[index] = 0;
+
+ printf("ID %04x:%04x\n", dev->descriptor->idVendor, dev->descriptor->idProduct);
+
+ if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial))
+ printf(" %s %s %s %s\n", pre, dev->mf, dev->prod, dev->serial);
+
+ printf(" %s\n", pre);
+
+ if (dev->maxchild > 0) {
+ for (i = 0; i < dev->maxchild; i++) {
+ if (dev->children[i] != NULL) {
+ usb_show_tree_graph(dev->children[i], pre);
+ pre[index] = 0;
+ }
+ }
+ }
+}
+
+/* main routine for the tree command */
+static void usb_show_tree(struct usb_device *dev)
+{
+ char preamble[32];
+
+ memset(preamble, 0, 32);
+ usb_show_tree_graph(dev, &preamble[0]);
+}
+
+static void usb_show_devices(bool tree)
+{
+ struct usb_device *dev;
+
+ list_for_each_entry(dev, &usb_device_list, list) {
+ if (tree) {
+ if (dev->parent == NULL)
+ usb_show_tree(dev);
+ } else {
+ printf("Bus %03d Device %03d: ID %04x:%04x %s\n",
+ dev->host->busnum, dev->devnum,
+ dev->descriptor->idVendor,
+ dev->descriptor->idProduct,
+ dev->prod);
+ }
+ }
+}
+
static int do_usb(int argc, char *argv[])
{
int opt;
- int force = 0;
+ int force = 0, tree = 0, show = 0;
- while ((opt = getopt(argc, argv, "f")) > 0) {
+ while ((opt = getopt(argc, argv, "fts")) > 0) {
switch (opt) {
case 'f':
force = 1;
break;
+ case 't':
+ tree = 1;
+ show = 1;
+ break;
+ case 's':
+ show = 1;
+ break;
}
}
usb_rescan(force);
+ if (show)
+ usb_show_devices(tree);
+
return 0;
}
@@ -45,12 +142,14 @@ BAREBOX_CMD_HELP_TEXT("Scan for USB devices.")
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT("-f", "force rescan")
+BAREBOX_CMD_HELP_OPT("-s", "show devices")
+BAREBOX_CMD_HELP_OPT("-t", "show USB tree")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(usb)
.cmd = do_usb,
BAREBOX_CMD_DESC("(re-)detect USB devices")
- BAREBOX_CMD_OPTS("[-f]")
+ BAREBOX_CMD_OPTS("[-fts]")
BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
BAREBOX_CMD_HELP(cmd_usb_help)
BAREBOX_CMD_COMPLETE(empty_complete)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f572432..710f611 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -70,7 +70,7 @@ static int hub_port_reset(struct usb_device *dev, int port,
unsigned short *portstat);
static LIST_HEAD(host_list);
-static LIST_HEAD(usb_device_list);
+LIST_HEAD(usb_device_list);
static void print_usb_device(struct usb_device *dev)
{
diff --git a/include/usb/usb.h b/include/usb/usb.h
index ff5242b..34edbae 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -473,4 +473,7 @@ enum usb_phy_interface {
USBPHY_INTERFACE_MODE_SERIAL,
USBPHY_INTERFACE_MODE_HSIC,
};
+
+extern struct list_head usb_device_list;
+
#endif /*_USB_H_ */
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 03/12] USB: host: simplify usb_new_device
2014-07-19 9:15 USB Host patches Sascha Hauer
2014-07-19 9:15 ` [PATCH 01/12] USB: i.MX chipidea: Implement OTG support for the poor Sascha Hauer
2014-07-19 9:15 ` [PATCH 02/12] commands: usb: add tree view capability Sascha Hauer
@ 2014-07-19 9:15 ` Sascha Hauer
2014-07-19 9:15 ` [PATCH 04/12] USB: host: hub: Turn into a driver Sascha Hauer
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:15 UTC (permalink / raw)
To: barebox
usb_new_device tries to find the port number it is attached to
by iterating over the parents children and using the loop counter
index as port number. Instead, just use the portnr field in struct
usb_device.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/usb.c | 23 +++++------------------
1 file changed, 5 insertions(+), 18 deletions(-)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 710f611..4f5c0ed 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -297,7 +297,6 @@ static int usb_new_device(struct usb_device *dev)
int tmp;
void *buf;
struct usb_device_descriptor *desc;
- int port = -1;
struct usb_device *parent = dev->parent;
unsigned short portstatus;
char str[16];
@@ -338,24 +337,10 @@ static int usb_new_device(struct usb_device *dev)
/* find the port number we're at */
if (parent) {
- int j;
-
- for (j = 0; j < parent->maxchild; j++) {
- if (parent->children[j] == dev) {
- port = j;
- break;
- }
- }
- if (port < 0) {
- printf("%s: cannot locate device's port.\n", __func__);
- err = -ENODEV;
- goto err_out;
- }
-
/* reset the port for the second time */
- err = hub_port_reset(dev->parent, port, &portstatus);
+ err = hub_port_reset(dev->parent, dev->portnr - 1, &portstatus);
if (err < 0) {
- printf("\n Couldn't reset port %i\n", port);
+ printf("\n Couldn't reset port %i\n", dev->portnr);
goto err_out;
}
}
@@ -433,7 +418,7 @@ static int usb_new_device(struct usb_device *dev)
dev->serial, sizeof(dev->serial));
if (parent) {
- sprintf(dev->dev.name, "%s-%d", parent->dev.name, port);
+ sprintf(dev->dev.name, "%s-%d", parent->dev.name, dev->portnr - 1);
} else {
sprintf(dev->dev.name, "usb%d", dev->host->busnum);
}
@@ -1108,6 +1093,8 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
dev->children[port] = usb;
usb->parent = dev;
+ usb->portnr = port + 1;
+
/* Run it through the hoops (find a driver, etc) */
if (usb_new_device(usb)) {
/* Woops, disable the port */
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 04/12] USB: host: hub: Turn into a driver
2014-07-19 9:15 USB Host patches Sascha Hauer
` (2 preceding siblings ...)
2014-07-19 9:15 ` [PATCH 03/12] USB: host: simplify usb_new_device Sascha Hauer
@ 2014-07-19 9:15 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 05/12] USB: host: fixup USB device hierarchy Sascha Hauer
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:15 UTC (permalink / raw)
To: barebox
Since we have a driver model we can make the hub driver a
real driver model driver. Put it into a new file to separate
the hub from the USB core stuff.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/Makefile | 3 +-
drivers/usb/core/hub.c | 434 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/usb/core/hub.h | 7 +
drivers/usb/core/usb.c | 424 ++------------------------------------------
drivers/usb/core/usb.h | 7 +
5 files changed, 460 insertions(+), 415 deletions(-)
create mode 100644 drivers/usb/core/hub.c
create mode 100644 drivers/usb/core/hub.h
create mode 100644 drivers/usb/core/usb.h
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index a74f141..dc7e635 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -1,3 +1,2 @@
-
-obj-$(CONFIG_USB_HOST) += usb.o
+obj-$(CONFIG_USB_HOST) += usb.o hub.o
obj-$(CONFIG_OFDEVICE) += of.o
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
new file mode 100644
index 0000000..0f43955
--- /dev/null
+++ b/drivers/usb/core/hub.c
@@ -0,0 +1,434 @@
+/*
+ * hub.c - USB hub support
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <errno.h>
+#include <scsi.h>
+#include <usb/usb.h>
+#include <usb/usb_defs.h>
+
+#include "usb.h"
+#include "hub.h"
+
+#undef USB_HUB_DEBUG
+
+#ifdef USB_HUB_DEBUG
+#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args)
+#else
+#define USB_HUB_PRINTF(fmt, args...)
+#endif
+
+#define USB_BUFSIZ 512
+
+static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+ USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT);
+}
+
+static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
+ port, NULL, 0, USB_CNTL_TIMEOUT);
+}
+
+static int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+static int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+ data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
+}
+
+
+static void usb_hub_power_on(struct usb_hub_device *hub)
+{
+ int i;
+ struct usb_device *dev;
+
+ dev = hub->pusb_dev;
+ /* Enable power to the ports */
+ USB_HUB_PRINTF("enabling power on all ports\n");
+ for (i = 0; i < dev->maxchild; i++) {
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status);
+ }
+ /* power on is encoded in 2ms increments -> times 2 for the actual delay */
+ mdelay(hub->desc.bPwrOn2PwrGood*2);
+}
+
+#define MAX_TRIES 5
+
+static inline char *portspeed(int portstatus)
+{
+ if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+ return "480 Mb/s";
+ else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
+int hub_port_reset(struct usb_device *dev, int port,
+ unsigned short *portstat)
+{
+ int tries;
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
+ for (tries = 0; tries < MAX_TRIES; tries++) {
+
+ usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
+ wait_ms(200);
+
+ if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed status %lX\n",
+ dev->status);
+ return -1;
+ }
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ portstatus, portchange,
+ portspeed(portstatus));
+
+ USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
+ " USB_PORT_STAT_ENABLE %d\n",
+ (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
+ (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
+
+ if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+ !(portstatus & USB_PORT_STAT_CONNECTION))
+ return -1;
+
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ break;
+
+ wait_ms(200);
+ }
+
+ if (tries == MAX_TRIES) {
+ USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \
+ "disabling port.\n", port + 1, MAX_TRIES);
+ USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
+ return -1;
+ }
+
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
+ *portstat = portstatus;
+ return 0;
+}
+
+
+static void usb_hub_port_connect_change(struct usb_device *dev, int port)
+{
+ struct usb_device *usb;
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ /* Check status */
+ if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ return;
+ }
+
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+ USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ portstatus, portchange, portspeed(portstatus));
+
+ /* Clear the connection change status */
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+ /* Disconnect any existing devices under this port */
+ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+ (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
+ USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
+ /* Return now if nothing is connected */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return;
+ }
+ wait_ms(200);
+
+ /* Reset the port */
+ if (hub_port_reset(dev, port, &portstatus) < 0) {
+ printf("cannot reset port %i!?\n", port + 1);
+ return;
+ }
+
+ wait_ms(200);
+
+ /* Allocate a new device struct for it */
+ usb = usb_alloc_new_device();
+ usb->host = dev->host;
+
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ usb->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ usb->speed = USB_SPEED_LOW;
+ else
+ usb->speed = USB_SPEED_FULL;
+
+ dev->children[port] = usb;
+ usb->parent = dev;
+ usb->portnr = port + 1;
+
+ /* Run it through the hoops (find a driver, etc) */
+ if (usb_new_device(usb)) {
+ /* Woops, disable the port */
+ USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
+ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
+ }
+}
+
+static int usb_hub_configure(struct usb_device *dev)
+{
+ unsigned char buffer[USB_BUFSIZ], *bitmap;
+ struct usb_hub_descriptor *descriptor;
+ struct usb_hub_status *hubsts;
+ int i;
+ struct usb_hub_device *hub;
+
+ hub = xzalloc(sizeof (*hub));
+ dev->hub = hub;
+
+ hub->pusb_dev = dev;
+ /* Get the the hub descriptor */
+ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
+ USB_HUB_PRINTF("%s: failed to get hub " \
+ "descriptor, giving up %lX\n", __func__, dev->status);
+ return -1;
+ }
+ descriptor = (struct usb_hub_descriptor *)buffer;
+
+ /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */
+ i = descriptor->bLength;
+ if (i > USB_BUFSIZ) {
+ USB_HUB_PRINTF("%s: failed to get hub " \
+ "descriptor - too long: %d\n", __func__,
+ descriptor->bLength);
+ return -1;
+ }
+
+ if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
+ USB_HUB_PRINTF("%s: failed to get hub " \
+ "descriptor 2nd giving up %lX\n", __func__, dev->status);
+ return -1;
+ }
+ memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength);
+ /* adjust 16bit values */
+ hub->desc.wHubCharacteristics =
+ le16_to_cpu(descriptor->wHubCharacteristics);
+ /* set the bitmap */
+ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0];
+ /* devices not removable by default */
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8);
+ bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0];
+ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i];
+
+ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
+ hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i];
+
+ dev->maxchild = descriptor->bNbrPorts;
+ USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
+ case 0x00:
+ USB_HUB_PRINTF("ganged power switching\n");
+ break;
+ case 0x01:
+ USB_HUB_PRINTF("individual port power switching\n");
+ break;
+ case 0x02:
+ case 0x03:
+ USB_HUB_PRINTF("unknown reserved power switching mode\n");
+ break;
+ }
+
+ if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
+ USB_HUB_PRINTF("part of a compound device\n");
+ else
+ USB_HUB_PRINTF("standalone hub\n");
+
+ switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
+ case 0x00:
+ USB_HUB_PRINTF("global over-current protection\n");
+ break;
+ case 0x08:
+ USB_HUB_PRINTF("individual port over-current protection\n");
+ break;
+ case 0x10:
+ case 0x18:
+ USB_HUB_PRINTF("no over-current protection\n");
+ break;
+ }
+
+ USB_HUB_PRINTF("power on to power good time: %dms\n",
+ descriptor->bPwrOn2PwrGood * 2);
+ USB_HUB_PRINTF("hub controller current requirement: %dmA\n",
+ descriptor->bHubContrCurrent);
+
+ for (i = 0; i < dev->maxchild; i++)
+ USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
+ hub->desc.DeviceRemovable[(i + 1) / 8] & \
+ (1 << ((i + 1) % 8)) ? " not" : "");
+
+ if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
+ USB_HUB_PRINTF("%s: failed to get Status - " \
+ "too long: %d\n", __func__, descriptor->bLength);
+ return -1;
+ }
+
+ if (usb_get_hub_status(dev, buffer) < 0) {
+ USB_HUB_PRINTF("%s: failed to get Status %lX\n", __func__,
+ dev->status);
+ return -1;
+ }
+
+ hubsts = (struct usb_hub_status *)buffer;
+ USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
+ le16_to_cpu(hubsts->wHubStatus),
+ le16_to_cpu(hubsts->wHubChange));
+ USB_HUB_PRINTF("local power source is %s\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \
+ "lost (inactive)" : "good");
+ USB_HUB_PRINTF("%sover-current condition exists\n",
+ (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
+ "" : "no ");
+ usb_hub_power_on(hub);
+
+ for (i = 0; i < dev->maxchild; i++) {
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
+ USB_HUB_PRINTF("get_port_status failed\n");
+ continue;
+ }
+
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+ USB_HUB_PRINTF("Port %d Status %X Change %X\n",
+ i + 1, portstatus, portchange);
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ USB_HUB_PRINTF("port %d connection change\n", i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ USB_HUB_PRINTF("port %d enable change, status %x\n",
+ i + 1, portstatus);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_ENABLE);
+
+ /* EM interference sometimes causes bad shielded USB
+ * devices to be shutdown by the hub, this hack enables
+ * them again. Works at least with mouse driver */
+ if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) &&
+ ((dev->children[i]))) {
+ USB_HUB_PRINTF("already running port %i " \
+ "disabled by hub (EMI?), " \
+ "re-enabling...\n", i + 1);
+ usb_hub_port_connect_change(dev, i);
+ }
+ }
+ if (portstatus & USB_PORT_STAT_SUSPEND) {
+ USB_HUB_PRINTF("port %d suspend change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_SUSPEND);
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ USB_HUB_PRINTF("port %d over-current change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ usb_hub_power_on(hub);
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ USB_HUB_PRINTF("port %d reset change\n", i + 1);
+ usb_clear_port_feature(dev, i + 1,
+ USB_PORT_FEAT_C_RESET);
+ }
+ } /* end for i all ports */
+
+ return 0;
+}
+
+static int usb_hub_probe(struct usb_device *usbdev,
+ const struct usb_device_id *id)
+{
+ return usb_hub_configure(usbdev);
+}
+
+static void usb_hub_disconnect(struct usb_device *usbdev)
+{
+ free(usbdev->hub);
+}
+
+/* Table with supported devices, most specific first. */
+static struct usb_device_id usb_hubage_usb_ids[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+ .bInterfaceClass = USB_CLASS_HUB,
+ },
+ { }
+};
+
+
+/***********************************************************************
+ * USB Storage driver initialization and registration
+ ***********************************************************************/
+
+static struct usb_driver usb_hubage_driver = {
+ .name = "usb-hub",
+ .id_table = usb_hubage_usb_ids,
+ .probe = usb_hub_probe,
+ .disconnect = usb_hub_disconnect,
+};
+
+static int __init usb_hub_init(void)
+{
+ return usb_driver_register(&usb_hubage_driver);
+}
+device_initcall(usb_hub_init);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
new file mode 100644
index 0000000..fcf1f0c
--- /dev/null
+++ b/drivers/usb/core/hub.h
@@ -0,0 +1,7 @@
+#ifndef __CORE_HUB_H
+#define __CORE_HUB_H
+
+int hub_port_reset(struct usb_device *dev, int port,
+ unsigned short *portstat);
+
+#endif /* __CORE_HUB_H */
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4f5c0ed..c289bbb 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -52,6 +52,9 @@
#include <usb/usb.h>
+#include "usb.h"
+#include "hub.h"
+
/* #define USB_DEBUG */
#ifdef USB_DEBUG
@@ -65,10 +68,6 @@
static int dev_index;
static int asynch_allowed;
-static int usb_hub_probe(struct usb_device *dev, int ifnum);
-static int hub_port_reset(struct usb_device *dev, int port,
- unsigned short *portstat);
-
static LIST_HEAD(host_list);
LIST_HEAD(usb_device_list);
@@ -291,7 +290,7 @@ static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
*
* Returns 0 for success, != 0 for error.
*/
-static int usb_new_device(struct usb_device *dev)
+int usb_new_device(struct usb_device *dev)
{
int addr, err;
int tmp;
@@ -427,13 +426,14 @@ static int usb_new_device(struct usb_device *dev)
if (dev->host->hw_dev)
dev->dev.parent = dev->host->hw_dev;
- register_device(&dev->dev);
-
- /* now prode if the device is a hub */
- usb_hub_probe(dev, 0);
-
print_usb_device(dev);
+ err = register_device(&dev->dev);
+ if (err) {
+ printf("Failed to register device: %s\n", strerror(-err));
+ return err;
+ }
+
dev_add_param_int_ro(&dev->dev, "iManufacturer",
dev->descriptor->iManufacturer, "%d");
dev_add_param_int_ro(&dev->dev, "iProduct",
@@ -457,7 +457,7 @@ err_out:
return err;
}
-static struct usb_device *usb_alloc_new_device(void)
+struct usb_device *usb_alloc_new_device(void)
{
struct usb_device *usbdev = xzalloc(sizeof (*usbdev));
@@ -911,408 +911,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err;
}
-/****************************************************************************
- * HUB "Driver"
- * Probes device for being a hub and configurate it
- */
-
-#undef USB_HUB_DEBUG
-
-#ifdef USB_HUB_DEBUG
-#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args)
-#else
-#define USB_HUB_PRINTF(fmt, args...)
-#endif
-
-static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
- USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT);
-}
-
-static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature,
- port, NULL, 0, USB_CNTL_TIMEOUT);
-}
-
-static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
-{
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
- port, NULL, 0, USB_CNTL_TIMEOUT);
-}
-
-static int usb_get_hub_status(struct usb_device *dev, void *data)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
- data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
-}
-
-static int usb_get_port_status(struct usb_device *dev, int port, void *data)
-{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
- data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
-}
-
-
-static void usb_hub_power_on(struct usb_hub_device *hub)
-{
- int i;
- struct usb_device *dev;
-
- dev = hub->pusb_dev;
- /* Enable power to the ports */
- USB_HUB_PRINTF("enabling power on all ports\n");
- for (i = 0; i < dev->maxchild; i++) {
- usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
- USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status);
- }
- /* power on is encoded in 2ms increments -> times 2 for the actual delay */
- mdelay(hub->desc.bPwrOn2PwrGood*2);
-}
-
-#define MAX_TRIES 5
-
-static inline char *portspeed(int portstatus)
-{
- if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
- return "480 Mb/s";
- else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
- return "1.5 Mb/s";
- else
- return "12 Mb/s";
-}
-
-static int hub_port_reset(struct usb_device *dev, int port,
- unsigned short *portstat)
-{
- int tries;
- struct usb_port_status portsts;
- unsigned short portstatus, portchange;
-
- USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
- for (tries = 0; tries < MAX_TRIES; tries++) {
-
- usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
- wait_ms(200);
-
- if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed status %lX\n",
- dev->status);
- return -1;
- }
- portstatus = le16_to_cpu(portsts.wPortStatus);
- portchange = le16_to_cpu(portsts.wPortChange);
-
- USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
- portstatus, portchange,
- portspeed(portstatus));
-
- USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
- " USB_PORT_STAT_ENABLE %d\n",
- (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
- (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
- (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
-
- if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
- !(portstatus & USB_PORT_STAT_CONNECTION))
- return -1;
-
- if (portstatus & USB_PORT_STAT_ENABLE)
- break;
-
- wait_ms(200);
- }
-
- if (tries == MAX_TRIES) {
- USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \
- "disabling port.\n", port + 1, MAX_TRIES);
- USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
- return -1;
- }
-
- usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET);
- *portstat = portstatus;
- return 0;
-}
-
-
-static void usb_hub_port_connect_change(struct usb_device *dev, int port)
-{
- struct usb_device *usb;
- struct usb_port_status portsts;
- unsigned short portstatus, portchange;
-
- /* Check status */
- if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed\n");
- return;
- }
-
- portstatus = le16_to_cpu(portsts.wPortStatus);
- portchange = le16_to_cpu(portsts.wPortChange);
- USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
- portstatus, portchange, portspeed(portstatus));
-
- /* Clear the connection change status */
- usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
-
- /* Disconnect any existing devices under this port */
- if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
- (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
- USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
- /* Return now if nothing is connected */
- if (!(portstatus & USB_PORT_STAT_CONNECTION))
- return;
- }
- wait_ms(200);
-
- /* Reset the port */
- if (hub_port_reset(dev, port, &portstatus) < 0) {
- printf("cannot reset port %i!?\n", port + 1);
- return;
- }
-
- wait_ms(200);
-
- /* Allocate a new device struct for it */
- usb = usb_alloc_new_device();
- usb->host = dev->host;
-
- if (portstatus & USB_PORT_STAT_HIGH_SPEED)
- usb->speed = USB_SPEED_HIGH;
- else if (portstatus & USB_PORT_STAT_LOW_SPEED)
- usb->speed = USB_SPEED_LOW;
- else
- usb->speed = USB_SPEED_FULL;
-
- dev->children[port] = usb;
- usb->parent = dev;
- usb->portnr = port + 1;
-
- /* Run it through the hoops (find a driver, etc) */
- if (usb_new_device(usb)) {
- /* Woops, disable the port */
- USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
- usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
- }
-}
-
-
-static int usb_hub_configure(struct usb_device *dev)
-{
- unsigned char buffer[USB_BUFSIZ], *bitmap;
- struct usb_hub_descriptor *descriptor;
- struct usb_hub_status *hubsts;
- int i;
- struct usb_hub_device *hub;
-
- hub = xzalloc(sizeof (*hub));
- dev->hub = hub;
-
- hub->pusb_dev = dev;
- /* Get the the hub descriptor */
- if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
- USB_HUB_PRINTF("%s: failed to get hub " \
- "descriptor, giving up %lX\n", __func__, dev->status);
- return -1;
- }
- descriptor = (struct usb_hub_descriptor *)buffer;
-
- /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */
- i = descriptor->bLength;
- if (i > USB_BUFSIZ) {
- USB_HUB_PRINTF("%s: failed to get hub " \
- "descriptor - too long: %d\n", __func__,
- descriptor->bLength);
- return -1;
- }
-
- if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
- USB_HUB_PRINTF("%s: failed to get hub " \
- "descriptor 2nd giving up %lX\n", __func__, dev->status);
- return -1;
- }
- memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength);
- /* adjust 16bit values */
- hub->desc.wHubCharacteristics =
- le16_to_cpu(descriptor->wHubCharacteristics);
- /* set the bitmap */
- bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0];
- /* devices not removable by default */
- memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8);
- bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0];
- memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */
-
- for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
- hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i];
-
- for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++)
- hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i];
-
- dev->maxchild = descriptor->bNbrPorts;
- USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
-
- switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
- case 0x00:
- USB_HUB_PRINTF("ganged power switching\n");
- break;
- case 0x01:
- USB_HUB_PRINTF("individual port power switching\n");
- break;
- case 0x02:
- case 0x03:
- USB_HUB_PRINTF("unknown reserved power switching mode\n");
- break;
- }
-
- if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
- USB_HUB_PRINTF("part of a compound device\n");
- else
- USB_HUB_PRINTF("standalone hub\n");
-
- switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
- case 0x00:
- USB_HUB_PRINTF("global over-current protection\n");
- break;
- case 0x08:
- USB_HUB_PRINTF("individual port over-current protection\n");
- break;
- case 0x10:
- case 0x18:
- USB_HUB_PRINTF("no over-current protection\n");
- break;
- }
-
- USB_HUB_PRINTF("power on to power good time: %dms\n",
- descriptor->bPwrOn2PwrGood * 2);
- USB_HUB_PRINTF("hub controller current requirement: %dmA\n",
- descriptor->bHubContrCurrent);
-
- for (i = 0; i < dev->maxchild; i++)
- USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
- hub->desc.DeviceRemovable[(i + 1) / 8] & \
- (1 << ((i + 1) % 8)) ? " not" : "");
-
- if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
- USB_HUB_PRINTF("%s: failed to get Status - " \
- "too long: %d\n", __func__, descriptor->bLength);
- return -1;
- }
-
- if (usb_get_hub_status(dev, buffer) < 0) {
- USB_HUB_PRINTF("%s: failed to get Status %lX\n", __func__,
- dev->status);
- return -1;
- }
-
- hubsts = (struct usb_hub_status *)buffer;
- USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
- le16_to_cpu(hubsts->wHubStatus),
- le16_to_cpu(hubsts->wHubChange));
- USB_HUB_PRINTF("local power source is %s\n",
- (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \
- "lost (inactive)" : "good");
- USB_HUB_PRINTF("%sover-current condition exists\n",
- (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
- "" : "no ");
- usb_hub_power_on(hub);
-
- for (i = 0; i < dev->maxchild; i++) {
- struct usb_port_status portsts;
- unsigned short portstatus, portchange;
-
- if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed\n");
- continue;
- }
-
- portstatus = le16_to_cpu(portsts.wPortStatus);
- portchange = le16_to_cpu(portsts.wPortChange);
- USB_HUB_PRINTF("Port %d Status %X Change %X\n",
- i + 1, portstatus, portchange);
-
- if (portchange & USB_PORT_STAT_C_CONNECTION) {
- USB_HUB_PRINTF("port %d connection change\n", i + 1);
- usb_hub_port_connect_change(dev, i);
- }
- if (portchange & USB_PORT_STAT_C_ENABLE) {
- USB_HUB_PRINTF("port %d enable change, status %x\n",
- i + 1, portstatus);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_ENABLE);
-
- /* EM interference sometimes causes bad shielded USB
- * devices to be shutdown by the hub, this hack enables
- * them again. Works at least with mouse driver */
- if (!(portstatus & USB_PORT_STAT_ENABLE) &&
- (portstatus & USB_PORT_STAT_CONNECTION) &&
- ((dev->children[i]))) {
- USB_HUB_PRINTF("already running port %i " \
- "disabled by hub (EMI?), " \
- "re-enabling...\n", i + 1);
- usb_hub_port_connect_change(dev, i);
- }
- }
- if (portstatus & USB_PORT_STAT_SUSPEND) {
- USB_HUB_PRINTF("port %d suspend change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_SUSPEND);
- }
-
- if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
- USB_HUB_PRINTF("port %d over-current change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_OVER_CURRENT);
- usb_hub_power_on(hub);
- }
-
- if (portchange & USB_PORT_STAT_C_RESET) {
- USB_HUB_PRINTF("port %d reset change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_RESET);
- }
- } /* end for i all ports */
-
- return 0;
-}
-
-static int usb_hub_probe(struct usb_device *dev, int ifnum)
-{
- struct usb_interface *iface;
- struct usb_endpoint_descriptor *ep;
- int ret;
-
- iface = &dev->config.interface[ifnum];
- /* Is it a hub? */
- if (iface->desc.bInterfaceClass != USB_CLASS_HUB)
- return 0;
- /* Some hubs have a subclass of 1, which AFAICT according to the */
- /* specs is not defined, but it works */
- if ((iface->desc.bInterfaceSubClass != 0) &&
- (iface->desc.bInterfaceSubClass != 1))
- return 0;
- /* Multiple endpoints? What kind of mutant ninja-hub is this? */
- if (iface->desc.bNumEndpoints != 1)
- return 0;
- ep = &iface->ep_desc[0];
- /* Output endpoint? Curiousier and curiousier.. */
- if (!(ep->bEndpointAddress & USB_DIR_IN))
- return 0;
- /* If it's not an interrupt endpoint, we'd better punt! */
- if ((ep->bmAttributes & 3) != 3)
- return 0;
- /* We found a hub */
- USB_HUB_PRINTF("USB hub found\n");
- ret = usb_hub_configure(dev);
- return ret;
-}
-
int usb_driver_register(struct usb_driver *drv)
{
drv->driver.name = drv->name;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
new file mode 100644
index 0000000..3e79407
--- /dev/null
+++ b/drivers/usb/core/usb.h
@@ -0,0 +1,7 @@
+#ifndef __CORE_USB_H
+#define __CORE_USB_H
+
+struct usb_device *usb_alloc_new_device(void);
+int usb_new_device(struct usb_device *dev);
+
+#endif /* __CORE_USB_H */
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 05/12] USB: host: fixup USB device hierarchy
2014-07-19 9:15 USB Host patches Sascha Hauer
` (3 preceding siblings ...)
2014-07-19 9:15 ` [PATCH 04/12] USB: host: hub: Turn into a driver Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 06/12] USB: host: hub: Use dev_dbg Sascha Hauer
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
Make all USB devices children to the hub device they are
attached to.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 1 +
drivers/usb/core/usb.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0f43955..26c2ca0 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -196,6 +196,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
/* Allocate a new device struct for it */
usb = usb_alloc_new_device();
+ usb->dev.parent = &dev->dev;
usb->host = dev->host;
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c289bbb..7c69e10 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -424,8 +424,6 @@ int usb_new_device(struct usb_device *dev)
dev->dev.id = DEVICE_ID_SINGLE;
- if (dev->host->hw_dev)
- dev->dev.parent = dev->host->hw_dev;
print_usb_device(dev);
err = register_device(&dev->dev);
@@ -500,6 +498,7 @@ int usb_host_detect(struct usb_host *host, int force)
return ret;
dev = usb_alloc_new_device();
+ dev->dev.parent = host->hw_dev;
dev->host = host;
usb_new_device(dev);
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 06/12] USB: host: hub: Use dev_dbg
2014-07-19 9:15 USB Host patches Sascha Hauer
` (4 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 05/12] USB: host: fixup USB device hierarchy Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 07/12] USB: host: hub: Use usb_hub_power_on from U-Boot Sascha Hauer
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
Now that a hub is a driver use dev_dbg rather than plain
printf.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 88 +++++++++++++++++++++++---------------------------
1 file changed, 40 insertions(+), 48 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 26c2ca0..6d5e3b9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -28,14 +28,6 @@
#include "usb.h"
#include "hub.h"
-#undef USB_HUB_DEBUG
-
-#ifdef USB_HUB_DEBUG
-#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args)
-#else
-#define USB_HUB_PRINTF(fmt, args...)
-#endif
-
#define USB_BUFSIZ 512
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
@@ -81,10 +73,10 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
dev = hub->pusb_dev;
/* Enable power to the ports */
- USB_HUB_PRINTF("enabling power on all ports\n");
+ dev_dbg(&dev->dev, "enabling power on all ports\n");
for (i = 0; i < dev->maxchild; i++) {
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
- USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status);
+ dev_dbg(&dev->dev, "port %d returns %lX\n", i + 1, dev->status);
}
/* power on is encoded in 2ms increments -> times 2 for the actual delay */
mdelay(hub->desc.bPwrOn2PwrGood*2);
@@ -109,25 +101,25 @@ int hub_port_reset(struct usb_device *dev, int port,
struct usb_port_status portsts;
unsigned short portstatus, portchange;
- USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
+ dev_dbg(&dev->dev, "hub_port_reset: resetting port %d...\n", port);
for (tries = 0; tries < MAX_TRIES; tries++) {
usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
wait_ms(200);
if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed status %lX\n",
+ dev_dbg(&dev->dev, "get_port_status failed status %lX\n",
dev->status);
return -1;
}
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
- USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ dev_dbg(&dev->dev, "portstatus %x, change %x, %s\n",
portstatus, portchange,
portspeed(portstatus));
- USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
+ dev_dbg(&dev->dev, "STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
" USB_PORT_STAT_ENABLE %d\n",
(portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
(portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
@@ -144,9 +136,9 @@ int hub_port_reset(struct usb_device *dev, int port,
}
if (tries == MAX_TRIES) {
- USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \
+ dev_dbg(&dev->dev, "Cannot enable port %i after %i retries, " \
"disabling port.\n", port + 1, MAX_TRIES);
- USB_HUB_PRINTF("Maybe the USB cable is bad?\n");
+ dev_dbg(&dev->dev, "Maybe the USB cable is bad?\n");
return -1;
}
@@ -164,13 +156,13 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
/* Check status */
if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed\n");
+ dev_dbg(&dev->dev, "get_port_status failed\n");
return;
}
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
- USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
+ dev_dbg(&dev->dev, "portstatus %x, change %x, %s\n",
portstatus, portchange, portspeed(portstatus));
/* Clear the connection change status */
@@ -179,7 +171,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
/* Disconnect any existing devices under this port */
if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
(!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
- USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
+ dev_dbg(&dev->dev, "usb_disconnect(&hub->children[port]);\n");
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION))
return;
@@ -213,7 +205,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
/* Run it through the hoops (find a driver, etc) */
if (usb_new_device(usb)) {
/* Woops, disable the port */
- USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
+ dev_dbg(&dev->dev, "hub: disabling port %d\n", port + 1);
usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
}
}
@@ -232,7 +224,7 @@ static int usb_hub_configure(struct usb_device *dev)
hub->pusb_dev = dev;
/* Get the the hub descriptor */
if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
- USB_HUB_PRINTF("%s: failed to get hub " \
+ dev_dbg(&dev->dev, "%s: failed to get hub " \
"descriptor, giving up %lX\n", __func__, dev->status);
return -1;
}
@@ -241,14 +233,14 @@ static int usb_hub_configure(struct usb_device *dev)
/* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */
i = descriptor->bLength;
if (i > USB_BUFSIZ) {
- USB_HUB_PRINTF("%s: failed to get hub " \
+ dev_dbg(&dev->dev, "%s: failed to get hub " \
"descriptor - too long: %d\n", __func__,
descriptor->bLength);
return -1;
}
if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) {
- USB_HUB_PRINTF("%s: failed to get hub " \
+ dev_dbg(&dev->dev, "%s: failed to get hub " \
"descriptor 2nd giving up %lX\n", __func__, dev->status);
return -1;
}
@@ -270,69 +262,69 @@ static int usb_hub_configure(struct usb_device *dev)
hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i];
dev->maxchild = descriptor->bNbrPorts;
- USB_HUB_PRINTF("%d ports detected\n", dev->maxchild);
+ dev_dbg(&dev->dev, "%d ports detected\n", dev->maxchild);
switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) {
case 0x00:
- USB_HUB_PRINTF("ganged power switching\n");
+ dev_dbg(&dev->dev, "ganged power switching\n");
break;
case 0x01:
- USB_HUB_PRINTF("individual port power switching\n");
+ dev_dbg(&dev->dev, "individual port power switching\n");
break;
case 0x02:
case 0x03:
- USB_HUB_PRINTF("unknown reserved power switching mode\n");
+ dev_dbg(&dev->dev, "unknown reserved power switching mode\n");
break;
}
if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND)
- USB_HUB_PRINTF("part of a compound device\n");
+ dev_dbg(&dev->dev, "part of a compound device\n");
else
- USB_HUB_PRINTF("standalone hub\n");
+ dev_dbg(&dev->dev, "standalone hub\n");
switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) {
case 0x00:
- USB_HUB_PRINTF("global over-current protection\n");
+ dev_dbg(&dev->dev, "global over-current protection\n");
break;
case 0x08:
- USB_HUB_PRINTF("individual port over-current protection\n");
+ dev_dbg(&dev->dev, "individual port over-current protection\n");
break;
case 0x10:
case 0x18:
- USB_HUB_PRINTF("no over-current protection\n");
+ dev_dbg(&dev->dev, "no over-current protection\n");
break;
}
- USB_HUB_PRINTF("power on to power good time: %dms\n",
+ dev_dbg(&dev->dev, "power on to power good time: %dms\n",
descriptor->bPwrOn2PwrGood * 2);
- USB_HUB_PRINTF("hub controller current requirement: %dmA\n",
+ dev_dbg(&dev->dev, "hub controller current requirement: %dmA\n",
descriptor->bHubContrCurrent);
for (i = 0; i < dev->maxchild; i++)
- USB_HUB_PRINTF("port %d is%s removable\n", i + 1,
+ dev_dbg(&dev->dev, "port %d is%s removable\n", i + 1,
hub->desc.DeviceRemovable[(i + 1) / 8] & \
(1 << ((i + 1) % 8)) ? " not" : "");
if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
- USB_HUB_PRINTF("%s: failed to get Status - " \
+ dev_dbg(&dev->dev, "%s: failed to get Status - " \
"too long: %d\n", __func__, descriptor->bLength);
return -1;
}
if (usb_get_hub_status(dev, buffer) < 0) {
- USB_HUB_PRINTF("%s: failed to get Status %lX\n", __func__,
+ dev_dbg(&dev->dev, "%s: failed to get Status %lX\n", __func__,
dev->status);
return -1;
}
hubsts = (struct usb_hub_status *)buffer;
- USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n",
+ dev_dbg(&dev->dev, "get_hub_status returned status %X, change %X\n",
le16_to_cpu(hubsts->wHubStatus),
le16_to_cpu(hubsts->wHubChange));
- USB_HUB_PRINTF("local power source is %s\n",
+ dev_dbg(&dev->dev, "local power source is %s\n",
(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \
"lost (inactive)" : "good");
- USB_HUB_PRINTF("%sover-current condition exists\n",
+ dev_dbg(&dev->dev, "%sover-current condition exists\n",
(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
"" : "no ");
usb_hub_power_on(hub);
@@ -342,21 +334,21 @@ static int usb_hub_configure(struct usb_device *dev)
unsigned short portstatus, portchange;
if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
- USB_HUB_PRINTF("get_port_status failed\n");
+ dev_dbg(&dev->dev, "get_port_status failed\n");
continue;
}
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
- USB_HUB_PRINTF("Port %d Status %X Change %X\n",
+ dev_dbg(&dev->dev, "Port %d Status %X Change %X\n",
i + 1, portstatus, portchange);
if (portchange & USB_PORT_STAT_C_CONNECTION) {
- USB_HUB_PRINTF("port %d connection change\n", i + 1);
+ dev_dbg(&dev->dev, "port %d connection change\n", i + 1);
usb_hub_port_connect_change(dev, i);
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
- USB_HUB_PRINTF("port %d enable change, status %x\n",
+ dev_dbg(&dev->dev, "port %d enable change, status %x\n",
i + 1, portstatus);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_ENABLE);
@@ -367,27 +359,27 @@ static int usb_hub_configure(struct usb_device *dev)
if (!(portstatus & USB_PORT_STAT_ENABLE) &&
(portstatus & USB_PORT_STAT_CONNECTION) &&
((dev->children[i]))) {
- USB_HUB_PRINTF("already running port %i " \
+ dev_dbg(&dev->dev, "already running port %i " \
"disabled by hub (EMI?), " \
"re-enabling...\n", i + 1);
usb_hub_port_connect_change(dev, i);
}
}
if (portstatus & USB_PORT_STAT_SUSPEND) {
- USB_HUB_PRINTF("port %d suspend change\n", i + 1);
+ dev_dbg(&dev->dev, "port %d suspend change\n", i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_SUSPEND);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
- USB_HUB_PRINTF("port %d over-current change\n", i + 1);
+ dev_dbg(&dev->dev, "port %d over-current change\n", i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_OVER_CURRENT);
usb_hub_power_on(hub);
}
if (portchange & USB_PORT_STAT_C_RESET) {
- USB_HUB_PRINTF("port %d reset change\n", i + 1);
+ dev_dbg(&dev->dev, "port %d reset change\n", i + 1);
usb_clear_port_feature(dev, i + 1,
USB_PORT_FEAT_C_RESET);
}
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 07/12] USB: host: hub: Use usb_hub_power_on from U-Boot
2014-07-19 9:15 USB Host patches Sascha Hauer
` (5 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 06/12] USB: host: hub: Use dev_dbg Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 08/12] USB: host: factor out port configuration to separate function Sascha Hauer
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
U-Boots power good delay function is more conservative than
ours. Use it to be on the safe side. The U-Boot guys have
discussed a lot about it, let's hope they got it right.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6d5e3b9..9c87037 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -70,16 +70,33 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
{
int i;
struct usb_device *dev;
+ unsigned pgood_delay = hub->desc.bPwrOn2PwrGood * 2;
dev = hub->pusb_dev;
+
+ /*
+ * Enable power to the ports:
+ * Here we Power-cycle the ports: aka,
+ * turning them off and turning on again.
+ */
+ for (i = 0; i < dev->maxchild; i++) {
+ usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ dev_dbg(&dev->dev, "port %d returns %lX\n", i + 1, dev->status);
+ }
+
+ /* Wait at least 2 * bPwrOn2PwrGood for PP to change */
+ mdelay(pgood_delay);
+
/* Enable power to the ports */
dev_dbg(&dev->dev, "enabling power on all ports\n");
+
for (i = 0; i < dev->maxchild; i++) {
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
dev_dbg(&dev->dev, "port %d returns %lX\n", i + 1, dev->status);
}
+
/* power on is encoded in 2ms increments -> times 2 for the actual delay */
- mdelay(hub->desc.bPwrOn2PwrGood*2);
+ mdelay(pgood_delay + 1000);
}
#define MAX_TRIES 5
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 08/12] USB: host: factor out port configuration to separate function
2014-07-19 9:15 USB Host patches Sascha Hauer
` (6 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 07/12] USB: host: hub: Use usb_hub_power_on from U-Boot Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 09/12] USB: host: hub: only configure hub once Sascha Hauer
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 125 +++++++++++++++++++++++++++++--------------------
1 file changed, 74 insertions(+), 51 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9c87037..689a79c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -227,6 +227,65 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
}
}
+static int usb_hub_configure_port(struct usb_device *dev, int port)
+{
+ struct usb_port_status portsts;
+ unsigned short portstatus, portchange;
+
+ if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
+ dev_dbg(&dev->dev, "get_port_status failed\n");
+ return -EIO;
+ }
+
+ portstatus = le16_to_cpu(portsts.wPortStatus);
+ portchange = le16_to_cpu(portsts.wPortChange);
+ dev_dbg(&dev->dev, "Port %d Status %X Change %X\n",
+ port + 1, portstatus, portchange);
+
+ if (portchange & USB_PORT_STAT_C_CONNECTION) {
+ dev_dbg(&dev->dev, "port %d connection change\n", port + 1);
+ usb_hub_port_connect_change(dev, port);
+ }
+ if (portchange & USB_PORT_STAT_C_ENABLE) {
+ dev_dbg(&dev->dev, "port %d enable change, status %x\n",
+ port + 1, portstatus);
+ usb_clear_port_feature(dev, port + 1,
+ USB_PORT_FEAT_C_ENABLE);
+
+ /* EM interference sometimes causes bad shielded USB
+ * devices to be shutdown by the hub, this hack enables
+ * them again. Works at least with mouse driver */
+ if (!(portstatus & USB_PORT_STAT_ENABLE) &&
+ (portstatus & USB_PORT_STAT_CONNECTION) &&
+ ((dev->children[port]))) {
+ dev_dbg(&dev->dev, "already running port %i " \
+ "disabled by hub (EMI?), " \
+ "re-enabling...\n", port + 1);
+ usb_hub_port_connect_change(dev, port);
+ }
+ }
+ if (portstatus & USB_PORT_STAT_SUSPEND) {
+ dev_dbg(&dev->dev, "port %d suspend change\n", port + 1);
+ usb_clear_port_feature(dev, port + 1,
+ USB_PORT_FEAT_SUSPEND);
+ }
+
+ if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ dev_dbg(&dev->dev, "port %d over-current change\n", port + 1);
+ usb_clear_port_feature(dev, port + 1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ usb_hub_power_on(dev->hub);
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+ dev_dbg(&dev->dev, "port %d reset change\n", port + 1);
+ usb_clear_port_feature(dev, port + 1,
+ USB_PORT_FEAT_C_RESET);
+ }
+
+ return 0;
+}
+
static int usb_hub_configure(struct usb_device *dev)
{
unsigned char buffer[USB_BUFSIZ], *bitmap;
@@ -346,61 +405,23 @@ static int usb_hub_configure(struct usb_device *dev)
"" : "no ");
usb_hub_power_on(hub);
- for (i = 0; i < dev->maxchild; i++) {
- struct usb_port_status portsts;
- unsigned short portstatus, portchange;
-
- if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
- dev_dbg(&dev->dev, "get_port_status failed\n");
- continue;
- }
+ for (i = 0; i < dev->maxchild; i++)
+ usb_hub_configure_port(dev, i);
- portstatus = le16_to_cpu(portsts.wPortStatus);
- portchange = le16_to_cpu(portsts.wPortChange);
- dev_dbg(&dev->dev, "Port %d Status %X Change %X\n",
- i + 1, portstatus, portchange);
+ return 0;
+}
- if (portchange & USB_PORT_STAT_C_CONNECTION) {
- dev_dbg(&dev->dev, "port %d connection change\n", i + 1);
- usb_hub_port_connect_change(dev, i);
- }
- if (portchange & USB_PORT_STAT_C_ENABLE) {
- dev_dbg(&dev->dev, "port %d enable change, status %x\n",
- i + 1, portstatus);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_ENABLE);
-
- /* EM interference sometimes causes bad shielded USB
- * devices to be shutdown by the hub, this hack enables
- * them again. Works at least with mouse driver */
- if (!(portstatus & USB_PORT_STAT_ENABLE) &&
- (portstatus & USB_PORT_STAT_CONNECTION) &&
- ((dev->children[i]))) {
- dev_dbg(&dev->dev, "already running port %i " \
- "disabled by hub (EMI?), " \
- "re-enabling...\n", i + 1);
- usb_hub_port_connect_change(dev, i);
- }
- }
- if (portstatus & USB_PORT_STAT_SUSPEND) {
- dev_dbg(&dev->dev, "port %d suspend change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_SUSPEND);
- }
+static int usb_hub_detect(struct device_d *dev)
+{
+ struct usb_device *usbdev = container_of(dev, struct usb_device, dev);
+ int i;
- if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
- dev_dbg(&dev->dev, "port %d over-current change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_OVER_CURRENT);
- usb_hub_power_on(hub);
- }
+ usb_hub_configure(usbdev);
- if (portchange & USB_PORT_STAT_C_RESET) {
- dev_dbg(&dev->dev, "port %d reset change\n", i + 1);
- usb_clear_port_feature(dev, i + 1,
- USB_PORT_FEAT_C_RESET);
- }
- } /* end for i all ports */
+ for (i = 0; i < usbdev->maxchild; i++) {
+ if (usbdev->children[i])
+ device_detect(&usbdev->children[i]->dev);
+ }
return 0;
}
@@ -408,6 +429,8 @@ static int usb_hub_configure(struct usb_device *dev)
static int usb_hub_probe(struct usb_device *usbdev,
const struct usb_device_id *id)
{
+ usbdev->dev.detect = usb_hub_detect;
+
return usb_hub_configure(usbdev);
}
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 09/12] USB: host: hub: only configure hub once
2014-07-19 9:15 USB Host patches Sascha Hauer
` (7 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 08/12] USB: host: factor out port configuration to separate function Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 10/12] USB: host: implement usb_remove_device Sascha Hauer
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
We had a single function which configures the hub and scans
the ports. Split this up and configure the hub only once and
scan the ports during detect() time. This allows to plug in
additional devices into a hub while continuing to use the
already existing devices.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 689a79c..39cadb5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -405,6 +405,13 @@ static int usb_hub_configure(struct usb_device *dev)
"" : "no ");
usb_hub_power_on(hub);
+ return 0;
+}
+
+static int usb_hub_configure_ports(struct usb_device *dev)
+{
+ int i;
+
for (i = 0; i < dev->maxchild; i++)
usb_hub_configure_port(dev, i);
@@ -416,7 +423,7 @@ static int usb_hub_detect(struct device_d *dev)
struct usb_device *usbdev = container_of(dev, struct usb_device, dev);
int i;
- usb_hub_configure(usbdev);
+ usb_hub_configure_ports(usbdev);
for (i = 0; i < usbdev->maxchild; i++) {
if (usbdev->children[i])
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 10/12] USB: host: implement usb_remove_device
2014-07-19 9:15 USB Host patches Sascha Hauer
` (8 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 09/12] USB: host: hub: only configure hub once Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 11/12] USB: host: detect port change only once in usb_hub_configure_port Sascha Hauer
2014-07-19 9:16 ` [PATCH 12/12] USB: host: drop force rescan Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 1 +
drivers/usb/core/usb.c | 19 +++++++++++++++++++
drivers/usb/core/usb.h | 1 +
3 files changed, 21 insertions(+)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 39cadb5..144442a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -189,6 +189,7 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
(!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
dev_dbg(&dev->dev, "usb_disconnect(&hub->children[port]);\n");
+ usb_remove_device(dev->children[port]);
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION))
return;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7c69e10..faf509e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -455,6 +455,25 @@ err_out:
return err;
}
+void usb_remove_device(struct usb_device *usbdev)
+{
+ int i, ret;
+
+ for (i = 0; i < usbdev->maxchild; i++) {
+ if (usbdev->children[i])
+ usb_remove_device(usbdev->children[i]);
+ }
+
+ dev_info(&usbdev->dev, "removing\n");
+
+ ret = unregister_device(&usbdev->dev);
+ if (ret)
+ dev_err(&usbdev->dev, "failed to unregister\n");
+
+ usbdev->parent->children[usbdev->portnr - 1] = NULL;
+ free(usbdev);
+}
+
struct usb_device *usb_alloc_new_device(void)
{
struct usb_device *usbdev = xzalloc(sizeof (*usbdev));
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 3e79407..a0c0550 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -3,5 +3,6 @@
struct usb_device *usb_alloc_new_device(void);
int usb_new_device(struct usb_device *dev);
+void usb_remove_device(struct usb_device *dev);
#endif /* __CORE_USB_H */
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 11/12] USB: host: detect port change only once in usb_hub_configure_port
2014-07-19 9:15 USB Host patches Sascha Hauer
` (9 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 10/12] USB: host: implement usb_remove_device Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
2014-07-19 9:16 ` [PATCH 12/12] USB: host: drop force rescan Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
Otherwise a device may be registered/unregistered multiple times
during scanning the hub ports.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/usb/core/hub.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 144442a..f90a927 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -226,12 +226,14 @@ static void usb_hub_port_connect_change(struct usb_device *dev, int port)
dev_dbg(&dev->dev, "hub: disabling port %d\n", port + 1);
usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
}
+ device_detect(&usb->dev);
}
static int usb_hub_configure_port(struct usb_device *dev, int port)
{
struct usb_port_status portsts;
unsigned short portstatus, portchange;
+ int connect_change = 0;
if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
dev_dbg(&dev->dev, "get_port_status failed\n");
@@ -245,7 +247,7 @@ static int usb_hub_configure_port(struct usb_device *dev, int port)
if (portchange & USB_PORT_STAT_C_CONNECTION) {
dev_dbg(&dev->dev, "port %d connection change\n", port + 1);
- usb_hub_port_connect_change(dev, port);
+ connect_change = 1;
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
dev_dbg(&dev->dev, "port %d enable change, status %x\n",
@@ -262,9 +264,13 @@ static int usb_hub_configure_port(struct usb_device *dev, int port)
dev_dbg(&dev->dev, "already running port %i " \
"disabled by hub (EMI?), " \
"re-enabling...\n", port + 1);
- usb_hub_port_connect_change(dev, port);
+ connect_change = 1;
}
}
+
+ if (connect_change)
+ usb_hub_port_connect_change(dev, port);
+
if (portstatus & USB_PORT_STAT_SUSPEND) {
dev_dbg(&dev->dev, "port %d suspend change\n", port + 1);
usb_clear_port_feature(dev, port + 1,
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 12/12] USB: host: drop force rescan
2014-07-19 9:15 USB Host patches Sascha Hauer
` (10 preceding siblings ...)
2014-07-19 9:16 ` [PATCH 11/12] USB: host: detect port change only once in usb_hub_configure_port Sascha Hauer
@ 2014-07-19 9:16 ` Sascha Hauer
11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2014-07-19 9:16 UTC (permalink / raw)
To: barebox
We can now detect changes in the USB device hierarchy properly, so
the 'force' option to the usb command is no longer necessary. We just
scan the busses each time the usb command is called.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/usb.c | 9 +++------
drivers/usb/core/usb.c | 39 ++++++++++++---------------------------
drivers/usb/host/ehci-hcd.c | 2 +-
include/usb/usb.h | 6 +++---
4 files changed, 19 insertions(+), 37 deletions(-)
diff --git a/commands/usb.c b/commands/usb.c
index c158852..a37d503 100644
--- a/commands/usb.c
+++ b/commands/usb.c
@@ -112,13 +112,10 @@ static void usb_show_devices(bool tree)
static int do_usb(int argc, char *argv[])
{
int opt;
- int force = 0, tree = 0, show = 0;
+ int tree = 0, show = 0;
- while ((opt = getopt(argc, argv, "fts")) > 0) {
+ while ((opt = getopt(argc, argv, "ts")) > 0) {
switch (opt) {
- case 'f':
- force = 1;
- break;
case 't':
tree = 1;
show = 1;
@@ -129,7 +126,7 @@ static int do_usb(int argc, char *argv[])
}
}
- usb_rescan(force);
+ usb_rescan();
if (show)
usb_show_devices(tree);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index faf509e..fdf9d94 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -492,50 +492,35 @@ struct usb_device *usb_alloc_new_device(void)
return usbdev;
}
-int usb_host_detect(struct usb_host *host, int force)
+int usb_host_detect(struct usb_host *host)
{
- struct usb_device *dev, *tmp;
int ret;
- if (host->scanned && !force)
- return -EBUSY;
-
- list_for_each_entry_safe(dev, tmp, &usb_device_list, list) {
- if (dev->host != host)
- continue;
+ if (!host->root_dev) {
+ ret = host->init(host);
+ if (ret)
+ return ret;
- list_del(&dev->list);
- unregister_device(&dev->dev);
- free(dev->hub);
- dma_free(dev->setup_packet);
- dma_free(dev->descriptor);
- free(dev);
+ host->root_dev = usb_alloc_new_device();
+ host->root_dev->dev.parent = host->hw_dev;
+ host->root_dev->host = host;
+ usb_new_device(host->root_dev);
}
- ret = host->init(host);
- if (ret)
- return ret;
-
- dev = usb_alloc_new_device();
- dev->dev.parent = host->hw_dev;
- dev->host = host;
- usb_new_device(dev);
-
- host->scanned = 1;
+ device_detect(&host->root_dev->dev);
return 0;
}
-void usb_rescan(int force)
+void usb_rescan(void)
{
struct usb_host *host;
int ret;
pr_info("USB: scanning bus for devices...\n");
- dev_index = 0;
list_for_each_entry(host, &host_list, list) {
- ret = usb_host_detect(host, force);
+ ret = usb_host_detect(host);
if (ret)
continue;
}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d30c3aa..9e30deb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -871,7 +871,7 @@ static int ehci_detect(struct device_d *dev)
{
struct ehci_priv *ehci = dev->priv;
- return usb_host_detect(&ehci->host, 0);
+ return usb_host_detect(&ehci->host);
}
int ehci_register(struct device_d *dev, struct ehci_data *data)
diff --git a/include/usb/usb.h b/include/usb/usb.h
index 34edbae..41f92c2 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -150,12 +150,12 @@ struct usb_host {
struct device_d *hw_dev;
int busnum;
- int scanned;
+ struct usb_device *root_dev;
};
int usb_register_host(struct usb_host *);
-int usb_host_detect(struct usb_host *host, int force);
+int usb_host_detect(struct usb_host *host);
int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
int usb_set_idle(struct usb_device *dev, int ifnum, int duration,
@@ -185,7 +185,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe);
int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
-void usb_rescan(int force);
+void usb_rescan(void);
/* big endian -> little endian conversion */
/* some CPUs are already little endian e.g. the ARM920T */
--
2.0.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 13+ messages in thread