summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hcd.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2015-05-13 14:42:15 +0200
committerSimon Glass <sjg@chromium.org>2015-05-14 18:49:35 -0600
commit44dbc33056f731e3704907eb0fd28a01185d333e (patch)
treeb74d24e89afb0e15fbe14660d8363d3fb21f9451 /drivers/usb/host/ohci-hcd.c
parent3a812e7c72f6865b70c8882f1de6bbc99cc54981 (diff)
downloadblackbird-obmc-uboot-44dbc33056f731e3704907eb0fd28a01185d333e.tar.gz
blackbird-obmc-uboot-44dbc33056f731e3704907eb0fd28a01185d333e.zip
usb: ohci: Do not reuse ed for interrupt endpoints of different devices
When submitting interrupt packets to an endpoint we only link in the ed once to avoid some races surrounding unlinking of periodic endpoints, but we share one ohci_device struct / one set of ed-s for all devices, which means that if we have an interrupt endpoint at endpoint 1 with one device, and a non interrupt endpoint 1 with another device we end up with the same ed linked into both the periodic and async lists, which is not good (tm). This commit switches over to using separate ohci_device structs, and thus separate ed-s for devices with interrupt endpoints, fixing this. This fixes e.g. matching a usb storage device and keyboard on the same usb-1 hub not working. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Marek Vasut <marex@denx.de>
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r--drivers/usb/host/ohci-hcd.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 2f976d2a1a..5364ced6b6 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1478,6 +1478,31 @@ pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
/*-------------------------------------------------------------------------*/
+static ohci_dev_t *ohci_get_ohci_dev(ohci_t *ohci, int devnum, int intr)
+{
+ int i;
+
+ if (!intr)
+ return &ohci->ohci_dev;
+
+ /* First see if we already have an ohci_dev for this dev. */
+ for (i = 0; i < NUM_INT_DEVS; i++) {
+ if (ohci->int_dev[i].devnum == devnum)
+ return &ohci->int_dev[i];
+ }
+
+ /* If not then find a free one. */
+ for (i = 0; i < NUM_INT_DEVS; i++) {
+ if (ohci->int_dev[i].devnum == -1) {
+ ohci->int_dev[i].devnum = devnum;
+ return &ohci->int_dev[i];
+ }
+ }
+
+ printf("ohci: Error out of ohci_devs for interrupt endpoints\n");
+ return NULL;
+}
+
/* common code for handling submit messages - used for all but root hub */
/* accesses. */
static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
@@ -1488,6 +1513,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
int maxsize = usb_maxpacket(dev, pipe);
int timeout;
urb_priv_t *urb;
+ ohci_dev_t *ohci_dev;
urb = malloc(sizeof(urb_priv_t));
memset(urb, 0, sizeof(urb_priv_t));
@@ -1511,7 +1537,11 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
return -1;
}
- if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) {
+ ohci_dev = ohci_get_ohci_dev(ohci, dev->devnum, usb_pipeint(pipe));
+ if (!ohci_dev)
+ return -ENOMEM;
+
+ if (sohci_submit_job(ohci, ohci_dev, urb, setup) < 0) {
err("sohci_submit_job failed");
return -1;
}
@@ -1711,8 +1741,11 @@ static int hc_start(ohci_t *ohci)
{
__u32 mask;
unsigned int fminterval;
+ int i;
ohci->disabled = 1;
+ for (i = 0; i < NUM_INT_DEVS; i++)
+ ohci->int_dev[i].devnum = -1;
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
OpenPOWER on IntegriCloud