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