# Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. PLUGABLE_7PORT_LAYOUT = {1:7, 2:6, 3:5, 4:{1:4, 2:3, 3:2, 4:1}} PLUGABLE_7PORT_USB3_LAYOUT = {1:{1:1, 2:2, 3:3, 4:4}, 2:5, 3:6, 4:7} KEEDOX_LAYOUT = {1:1, 2:2, 3:3, 4:{1:4, 2:5, 3:6, 4:7}} VIA_LAYOUT = {1:1, 2:2, 3:3, 4:{1:4, 2:5, 3:6, 4:7}} class HubType(object): def __init__(self, id_func, port_mapping): """Defines a type of hub. Args: id_func: [USBNode -> bool] is a function that can be run on a node to determine if the node represents this type of hub. port_mapping: [dict(int:(int|dict))] maps virtual to physical port numbers. For instance, {3:1, 1:2, 2:3} means that virtual port 3 corresponds to physical port 1, virtual port 1 corresponds to physical port 2, and virtual port 2 corresponds to physical port 3. In the case of hubs with "internal" topology, this is represented by nested maps. For instance, {1:{1:1,2:2},2:{1:3,2:4}} means, e.g. that the device plugged into physical port 3 will show up as being connected to port 1, on a device which is connected to port 2 on the hub. """ self._id_func = id_func # v2p = "virtual to physical" ports self._v2p_port = port_mapping def IsType(self, node): """Determines if the given Node is a hub of this type. Args: node: [USBNode] Node to check. """ return self._id_func(node) def GetPhysicalPortToNodeTuples(self, node): """Gets devices connected to the physical ports on a hub of this type. Args: node: [USBNode] Node representing a hub of this type. Yields: A series of (int, USBNode) tuples giving a physical port and the USBNode connected to it. Raises: ValueError: If the given node isn't a hub of this type. """ if self.IsType(node): for res in self._GppHelper(node, self._v2p_port): yield res else: raise ValueError('Node must be a hub of this type') def _GppHelper(self, node, mapping): """Helper function for GetPhysicalPortToNodeMap. Gets devices connected to physical ports, based on device tree rooted at the given node and the mapping between virtual and physical ports. Args: node: [USBNode] Root of tree to search for devices. mapping: [dict] Mapping between virtual and physical ports. Yields: A series of (int, USBNode) tuples giving a physical port and the Node connected to it. """ for (virtual, physical) in mapping.iteritems(): if node.HasPort(virtual): if isinstance(physical, dict): for res in self._GppHelper(node.PortToDevice(virtual), physical): yield res else: yield (physical, node.PortToDevice(virtual)) def _is_plugable_7port_hub(node): """Check if a node is a Plugable 7-Port Hub (Model USB2-HUB7BC) The topology of this device is a 4-port hub, with another 4-port hub connected on port 4. """ if '1a40:0101' not in node.desc: return False if not node.HasPort(4): return False return '1a40:0101' in node.PortToDevice(4).desc # Plugable 7-Port USB-3 Hubs show up twice in the USB devices list; they have # two different "branches", one which has USB2 devices and one which has # USB3 devices. The "part2" is the "USB-2" branch of the hub, the # "part3" is the "USB-3" branch of the hub. def _is_plugable_7port_usb3_part2_hub(node): """Check if a node is the "USB2 branch" of a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) The topology of this device is a 4-port hub, with another 4-port hub connected on port 1. """ if '2109:2811' not in node.desc: return False if not node.HasPort(1): return False return '2109:2811' in node.PortToDevice(1).desc def _is_plugable_7port_usb3_part3_hub(node): """Check if a node is the "USB3 branch" of a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC) The topology of this device is a 4-port hub, with another 4-port hub connected on port 1. """ if '2109:8110' not in node.desc: return False if not node.HasPort(1): return False return '2109:8110' in node.PortToDevice(1).desc def _is_keedox_hub(node): """Check if a node is a Keedox hub. The topology of this device is a 4-port hub, with another 4-port hub connected on port 4. """ if '0bda:5411' not in node.desc: return False if not node.HasPort(4): return False return '0bda:5411' in node.PortToDevice(4).desc def _is_via_hub(node): """Check if a node is a Via Labs hub. The topology of this device is a 4-port hub, with another 4-port hub connected on port 4. """ if '2109:2812' not in node.desc and '2109:0812' not in node.desc: return False if not node.HasPort(4): return False return ('2109:2812' in node.PortToDevice(4).desc or '2109:0812' in node.PortToDevice(4).desc) PLUGABLE_7PORT = HubType(_is_plugable_7port_hub, PLUGABLE_7PORT_LAYOUT) PLUGABLE_7PORT_USB3_PART2 = HubType(_is_plugable_7port_usb3_part2_hub, PLUGABLE_7PORT_USB3_LAYOUT) PLUGABLE_7PORT_USB3_PART3 = HubType(_is_plugable_7port_usb3_part3_hub, PLUGABLE_7PORT_USB3_LAYOUT) KEEDOX = HubType(_is_keedox_hub, KEEDOX_LAYOUT) VIA = HubType(_is_via_hub, VIA_LAYOUT) ALL_HUBS = [PLUGABLE_7PORT, PLUGABLE_7PORT_USB3_PART2, PLUGABLE_7PORT_USB3_PART3, KEEDOX, VIA] def GetHubType(type_name): if type_name == 'plugable_7port': return PLUGABLE_7PORT elif type_name == 'plugable_7port_usb3_part2': return PLUGABLE_7PORT_USB3_PART2 elif type_name == 'plugable_7port_usb3_part3': return PLUGABLE_7PORT_USB3_PART3 elif type_name == 'keedox': return KEEDOX elif type_name == 'via': return VIA raise ValueError('Invalid hub type')