1# Copyright 2016 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5PLUGABLE_7PORT_LAYOUT = {1:7, 6 2:6, 7 3:5, 8 4:{1:4, 2:3, 3:2, 4:1}} 9 10PLUGABLE_7PORT_USB3_LAYOUT = {1:{1:1, 2:2, 3:3, 4:4}, 11 2:5, 12 3:6, 13 4:7} 14 15class HubType(object): 16 def __init__(self, id_func, port_mapping): 17 """Defines a type of hub. 18 19 Args: 20 id_func: [USBNode -> bool] is a function that can be run on a node 21 to determine if the node represents this type of hub. 22 port_mapping: [dict(int:(int|dict))] maps virtual to physical port 23 numbers. For instance, {3:1, 1:2, 2:3} means that virtual port 3 24 corresponds to physical port 1, virtual port 1 corresponds to physical 25 port 2, and virtual port 2 corresponds to physical port 3. In the 26 case of hubs with "internal" topology, this is represented by nested 27 maps. For instance, {1:{1:1,2:2},2:{1:3,2:4}} means, e.g. that the 28 device plugged into physical port 3 will show up as being connected 29 to port 1, on a device which is connected to port 2 on the hub. 30 """ 31 self._id_func = id_func 32 # v2p = "virtual to physical" ports 33 self._v2p_port = port_mapping 34 35 def IsType(self, node): 36 """Determines if the given Node is a hub of this type. 37 38 Args: 39 node: [USBNode] Node to check. 40 """ 41 return self._id_func(node) 42 43 def GetPhysicalPortToNodeTuples(self, node): 44 """Gets devices connected to the physical ports on a hub of this type. 45 46 Args: 47 node: [USBNode] Node representing a hub of this type. 48 49 Yields: 50 A series of (int, USBNode) tuples giving a physical port 51 and the USBNode connected to it. 52 53 Raises: 54 ValueError: If the given node isn't a hub of this type. 55 """ 56 if self.IsType(node): 57 for res in self._GppHelper(node, self._v2p_port): 58 yield res 59 else: 60 raise ValueError('Node must be a hub of this type') 61 62 def _GppHelper(self, node, mapping): 63 """Helper function for GetPhysicalPortToNodeMap. 64 65 Gets devices connected to physical ports, based on device tree 66 rooted at the given node and the mapping between virtual and physical 67 ports. 68 69 Args: 70 node: [USBNode] Root of tree to search for devices. 71 mapping: [dict] Mapping between virtual and physical ports. 72 73 Yields: 74 A series of (int, USBNode) tuples giving a physical port 75 and the Node connected to it. 76 """ 77 for (virtual, physical) in mapping.iteritems(): 78 if node.HasPort(virtual): 79 if isinstance(physical, dict): 80 for res in self._GppHelper(node.PortToDevice(virtual), physical): 81 yield res 82 else: 83 yield (physical, node.PortToDevice(virtual)) 84 85def _is_plugable_7port_hub(node): 86 """Check if a node is a Plugable 7-Port Hub 87 (Model USB2-HUB7BC) 88 The topology of this device is a 4-port hub, 89 with another 4-port hub connected on port 4. 90 """ 91 if '1a40:0101' not in node.desc: 92 return False 93 if not node.HasPort(4): 94 return False 95 return '1a40:0101' in node.PortToDevice(4).desc 96 97# Plugable 7-Port USB-3 Hubs show up twice in the USB devices list; they have 98# two different "branches", one which has USB2 devices and one which has 99# USB3 devices. The "part2" is the "USB-2" branch of the hub, the 100# "part3" is the "USB-3" branch of the hub. 101 102def _is_plugable_7port_usb3_part2_hub(node): 103 """Check if a node is the "USB2 branch" of 104 a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) 105 The topology of this device is a 4-port hub, 106 with another 4-port hub connected on port 1. 107 """ 108 if '2109:2811' not in node.desc: 109 return False 110 if not node.HasPort(1): 111 return False 112 return '2109:2811' in node.PortToDevice(1).desc 113 114def _is_plugable_7port_usb3_part3_hub(node): 115 """Check if a node is the "USB3 branch" of 116 a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) 117 The topology of this device is a 4-port hub, 118 with another 4-port hub connected on port 1. 119 """ 120 if '2109:8110' not in node.desc: 121 return False 122 if not node.HasPort(1): 123 return False 124 return '2109:8110' in node.PortToDevice(1).desc 125 126PLUGABLE_7PORT = HubType(_is_plugable_7port_hub, PLUGABLE_7PORT_LAYOUT) 127PLUGABLE_7PORT_USB3_PART2 = HubType(_is_plugable_7port_usb3_part2_hub, 128 PLUGABLE_7PORT_USB3_LAYOUT) 129PLUGABLE_7PORT_USB3_PART3 = HubType(_is_plugable_7port_usb3_part3_hub, 130 PLUGABLE_7PORT_USB3_LAYOUT) 131 132def GetHubType(type_name): 133 if type_name == 'plugable_7port': 134 return PLUGABLE_7PORT 135 if type_name == 'plugable_7port_usb3_part2': 136 return PLUGABLE_7PORT_USB3_PART2 137 if type_name == 'plugable_7port_usb3_part3': 138 return PLUGABLE_7PORT_USB3_PART3 139 else: 140 raise ValueError('Invalid hub type') 141