diff options
author | Dan Williams <dan.j.williams@intel.com> | 2014-05-20 21:08:33 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 19:38:52 -0400 |
commit | 8b1ba80c59fb3e77f9e1761480617d5ea9ee159c (patch) | |
tree | 120b54fcb3cf3d97d6798bd41d19b2b725554bab /drivers/usb | |
parent | d8521afe35862f4fbe3ccd6ca37897c0a304edf3 (diff) |
usb: assign usb3 external hub port peers
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
Note that this assumes the port labeling scheme required by the
specification [1].
[1]: usb3 3.1 section 10.3.3
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/port.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 5ecdbf31dfcb..9b7496b52f2a 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c | |||
@@ -187,15 +187,18 @@ static void unlink_peers(struct usb_port *left, struct usb_port *right) | |||
187 | left->peer = NULL; | 187 | left->peer = NULL; |
188 | } | 188 | } |
189 | 189 | ||
190 | /* set the default peer port for root hubs */ | 190 | /* |
191 | * Set the default peer port for root hubs, or via the upstream peer | ||
192 | * relationship for all other hubs | ||
193 | */ | ||
191 | static void find_and_link_peer(struct usb_hub *hub, int port1) | 194 | static void find_and_link_peer(struct usb_hub *hub, int port1) |
192 | { | 195 | { |
193 | struct usb_port *port_dev = hub->ports[port1 - 1], *peer; | 196 | struct usb_port *port_dev = hub->ports[port1 - 1], *peer; |
194 | struct usb_device *hdev = hub->hdev; | 197 | struct usb_device *hdev = hub->hdev; |
198 | struct usb_device *peer_hdev; | ||
199 | struct usb_hub *peer_hub; | ||
195 | 200 | ||
196 | if (!hdev->parent) { | 201 | if (!hdev->parent) { |
197 | struct usb_hub *peer_hub; | ||
198 | struct usb_device *peer_hdev; | ||
199 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); | 202 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); |
200 | struct usb_hcd *peer_hcd = hcd->shared_hcd; | 203 | struct usb_hcd *peer_hcd = hcd->shared_hcd; |
201 | 204 | ||
@@ -203,15 +206,28 @@ static void find_and_link_peer(struct usb_hub *hub, int port1) | |||
203 | return; | 206 | return; |
204 | 207 | ||
205 | peer_hdev = peer_hcd->self.root_hub; | 208 | peer_hdev = peer_hcd->self.root_hub; |
206 | peer_hub = usb_hub_to_struct_hub(peer_hdev); | 209 | } else { |
207 | if (!peer_hub || port1 > peer_hdev->maxchild) | 210 | struct usb_port *upstream; |
211 | struct usb_device *parent = hdev->parent; | ||
212 | struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); | ||
213 | |||
214 | if (!parent_hub) | ||
208 | return; | 215 | return; |
209 | 216 | ||
210 | peer = peer_hub->ports[port1 - 1]; | 217 | upstream = parent_hub->ports[hdev->portnum - 1]; |
218 | if (!upstream || !upstream->peer) | ||
219 | return; | ||
211 | 220 | ||
212 | if (peer) | 221 | peer_hdev = upstream->peer->child; |
213 | link_peers(port_dev, peer); | ||
214 | } | 222 | } |
223 | |||
224 | peer_hub = usb_hub_to_struct_hub(peer_hdev); | ||
225 | if (!peer_hub || port1 > peer_hdev->maxchild) | ||
226 | return; | ||
227 | |||
228 | peer = peer_hub->ports[port1 - 1]; | ||
229 | if (peer) | ||
230 | link_peers(port_dev, peer); | ||
215 | } | 231 | } |
216 | 232 | ||
217 | int usb_hub_create_port_device(struct usb_hub *hub, int port1) | 233 | int usb_hub_create_port_device(struct usb_hub *hub, int port1) |