Given that root hub port peers are already established external hub peer ports can be determined by traversing the device topology: 1/ ascend to the parent hub and find the upstream port_dev 2/ walk ->peer to find the peer port 3/ descend to the peer hub via ->child 4/ find the port with the matching port id Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/usb/core/port.c | 23 +++++++++++++++++++++-- 1 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 8d3ec2daf6fe..7fd22020d7ee 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -150,15 +150,15 @@ struct device_type usb_port_device_type = { static struct usb_port *find_peer_port(struct usb_hub *hub, int port1) { struct usb_device *hdev = hub->hdev; + struct usb_device *peer_hdev; struct usb_port *peer = NULL; + struct usb_hub *peer_hub; /* set the default peer port for root hubs. Platform firmware * can later fix this up if tier-mismatch is present. Assumes * the primary_hcd is usb2.0 and registered first */ if (!hdev->parent) { - struct usb_hub *peer_hub; - struct usb_device *peer_hdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); struct usb_hcd *peer_hcd = hcd->primary_hcd; @@ -170,6 +170,24 @@ static struct usb_port *find_peer_port(struct usb_hub *hub, int port1) peer_hub = usb_hub_to_struct_hub(peer_hdev); if (peer_hub && port1 <= peer_hdev->maxchild) peer = peer_hub->ports[port1 - 1]; + } else { + struct usb_port *upstream; + struct usb_device *parent = hdev->parent; + struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); + + if (!parent_hub) + return NULL; + + upstream = parent_hub->ports[hdev->portnum - 1]; + if (!upstream->peer) + return NULL; + + peer_hdev = upstream->peer->child; + peer_hub = usb_hub_to_struct_hub(peer_hdev); + if (!peer_hub || port1 > peer_hdev->maxchild) + return NULL; + + peer = peer_hub->ports[port1 - 1]; } return peer; @@ -202,6 +220,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) spin_lock(&peer_lock); get_device(&peer->dev); port_dev->peer = peer; + WARN_ON(peer->peer); get_device(&port_dev->dev); peer->peer = port_dev; spin_unlock(&peer_lock); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html