blob: b6c53af9414d66f15502f6df7dea9507226d71bb [file] [log] [blame]
# 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.items():
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
if type_name == 'plugable_7port_usb3_part2':
return PLUGABLE_7PORT_USB3_PART2
if type_name == 'plugable_7port_usb3_part3':
return PLUGABLE_7PORT_USB3_PART3
if type_name == 'keedox':
return KEEDOX
if type_name == 'via':
return VIA
raise ValueError('Invalid hub type')