[PATCH v3 02/10] usb: find external hub port peers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux