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, 2: 6, 3: 5, 4: {1: 4, 2: 3, 3: 2, 4: 1}} 6 7PLUGABLE_7PORT_USB3_LAYOUT = {1: {1: 1, 2: 2, 3: 3, 4: 4}, 2: 5, 3: 6, 4: 7} 8 9KEEDOX_LAYOUT = {1: 1, 2: 2, 3: 3, 4: {1: 4, 2: 5, 3: 6, 4: 7}} 10 11VIA_LAYOUT = {1: 1, 2: 2, 3: 3, 4: {1: 4, 2: 5, 3: 6, 4: 7}} 12 13 14class HubType(object): 15 def __init__(self, id_func, port_mapping): 16 """Defines a type of hub. 17 18 Args: 19 id_func: [USBNode -> bool] is a function that can be run on a node 20 to determine if the node represents this type of hub. 21 port_mapping: [dict(int:(int|dict))] maps virtual to physical port 22 numbers. For instance, {3:1, 1:2, 2:3} means that virtual port 3 23 corresponds to physical port 1, virtual port 1 corresponds to physical 24 port 2, and virtual port 2 corresponds to physical port 3. In the 25 case of hubs with "internal" topology, this is represented by nested 26 maps. For instance, {1:{1:1,2:2},2:{1:3,2:4}} means, e.g. that the 27 device plugged into physical port 3 will show up as being connected 28 to port 1, on a device which is connected to port 2 on the hub. 29 """ 30 self._id_func = id_func 31 # v2p = "virtual to physical" ports 32 self._v2p_port = port_mapping 33 34 def IsType(self, node): 35 """Determines if the given Node is a hub of this type. 36 37 Args: 38 node: [USBNode] Node to check. 39 """ 40 return self._id_func(node) 41 42 def GetPhysicalPortToNodeTuples(self, node): 43 """Gets devices connected to the physical ports on a hub of this type. 44 45 Args: 46 node: [USBNode] Node representing a hub of this type. 47 48 Yields: 49 A series of (int, USBNode) tuples giving a physical port 50 and the USBNode connected to it. 51 52 Raises: 53 ValueError: If the given node isn't a hub of this type. 54 """ 55 if self.IsType(node): 56 for res in self._GppHelper(node, self._v2p_port): 57 yield res 58 else: 59 raise ValueError('Node must be a hub of this type') 60 61 def _GppHelper(self, node, mapping): 62 """Helper function for GetPhysicalPortToNodeMap. 63 64 Gets devices connected to physical ports, based on device tree 65 rooted at the given node and the mapping between virtual and physical 66 ports. 67 68 Args: 69 node: [USBNode] Root of tree to search for devices. 70 mapping: [dict] Mapping between virtual and physical ports. 71 72 Yields: 73 A series of (int, USBNode) tuples giving a physical port 74 and the Node connected to it. 75 """ 76 for (virtual, physical) in mapping.items(): 77 if node.HasPort(virtual): 78 if isinstance(physical, dict): 79 for res in self._GppHelper(node.PortToDevice(virtual), physical): 80 yield res 81 else: 82 yield (physical, node.PortToDevice(virtual)) 83 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 98# Plugable 7-Port USB-3 Hubs show up twice in the USB devices list; they have 99# two different "branches", one which has USB2 devices and one which has 100# USB3 devices. The "part2" is the "USB-2" branch of the hub, the 101# "part3" is the "USB-3" branch of the hub. 102 103 104def _is_plugable_7port_usb3_part2_hub(node): 105 """Check if a node is the "USB2 branch" of 106 a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) 107 The topology of this device is a 4-port hub, 108 with another 4-port hub connected on port 1. 109 """ 110 if '2109:2811' not in node.desc: 111 return False 112 if not node.HasPort(1): 113 return False 114 return '2109:2811' in node.PortToDevice(1).desc 115 116 117def _is_plugable_7port_usb3_part3_hub(node): 118 """Check if a node is the "USB3 branch" of 119 a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) 120 The topology of this device is a 4-port hub, 121 with another 4-port hub connected on port 1. 122 """ 123 if '2109:8110' not in node.desc: 124 return False 125 if not node.HasPort(1): 126 return False 127 return '2109:8110' in node.PortToDevice(1).desc 128 129 130def _is_keedox_hub(node): 131 """Check if a node is a Keedox hub. 132 The topology of this device is a 4-port hub, 133 with another 4-port hub connected on port 4. 134 """ 135 if '0bda:5411' not in node.desc: 136 return False 137 if not node.HasPort(4): 138 return False 139 return '0bda:5411' in node.PortToDevice(4).desc 140 141 142def _is_via_hub(node): 143 """Check if a node is a Via Labs hub. 144 The topology of this device is a 4-port hub, 145 with another 4-port hub connected on port 4. 146 """ 147 if '2109:2812' not in node.desc and '2109:0812' not in node.desc: 148 return False 149 if not node.HasPort(4): 150 return False 151 return ('2109:2812' in node.PortToDevice(4).desc 152 or '2109:0812' in node.PortToDevice(4).desc) 153 154 155PLUGABLE_7PORT = HubType(_is_plugable_7port_hub, PLUGABLE_7PORT_LAYOUT) 156PLUGABLE_7PORT_USB3_PART2 = HubType(_is_plugable_7port_usb3_part2_hub, 157 PLUGABLE_7PORT_USB3_LAYOUT) 158PLUGABLE_7PORT_USB3_PART3 = HubType(_is_plugable_7port_usb3_part3_hub, 159 PLUGABLE_7PORT_USB3_LAYOUT) 160KEEDOX = HubType(_is_keedox_hub, KEEDOX_LAYOUT) 161VIA = HubType(_is_via_hub, VIA_LAYOUT) 162 163ALL_HUBS = [ 164 PLUGABLE_7PORT, PLUGABLE_7PORT_USB3_PART2, PLUGABLE_7PORT_USB3_PART3, 165 KEEDOX, VIA 166] 167 168 169def GetHubType(type_name): 170 if type_name == 'plugable_7port': 171 return PLUGABLE_7PORT 172 elif type_name == 'plugable_7port_usb3_part2': 173 return PLUGABLE_7PORT_USB3_PART2 174 elif type_name == 'plugable_7port_usb3_part3': 175 return PLUGABLE_7PORT_USB3_PART3 176 elif type_name == 'keedox': 177 return KEEDOX 178 elif type_name == 'via': 179 return VIA 180 raise ValueError('Invalid hub type') 181