Home | History | Annotate | Download | only in utils
      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 
      5 PLUGABLE_7PORT_LAYOUT = {1:7,
      6                          2:6,
      7                          3:5,
      8                          4:{1:4, 2:3, 3:2, 4:1}}
      9 
     10 PLUGABLE_7PORT_USB3_LAYOUT = {1:{1:1, 2:2, 3:3, 4:4},
     11                               2:5,
     12                               3:6,
     13                               4:7}
     14 
     15 KEEDOX_LAYOUT = {1:1,
     16                  2:2,
     17                  3:3,
     18                  4:{1:4, 2:5, 3:6, 4:7}}
     19 
     20 VIA_LAYOUT = {1:1,
     21               2:2,
     22               3:3,
     23               4:{1:4, 2:5, 3:6, 4:7}}
     24 
     25 class 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 
     95 def _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 
    112 def _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 
    124 def _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 
    136 def _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 
    147 def _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 
    160 PLUGABLE_7PORT = HubType(_is_plugable_7port_hub, PLUGABLE_7PORT_LAYOUT)
    161 PLUGABLE_7PORT_USB3_PART2 = HubType(_is_plugable_7port_usb3_part2_hub,
    162                                     PLUGABLE_7PORT_USB3_LAYOUT)
    163 PLUGABLE_7PORT_USB3_PART3 = HubType(_is_plugable_7port_usb3_part3_hub,
    164                                     PLUGABLE_7PORT_USB3_LAYOUT)
    165 KEEDOX = HubType(_is_keedox_hub, KEEDOX_LAYOUT)
    166 VIA = HubType(_is_via_hub, VIA_LAYOUT)
    167 
    168 ALL_HUBS = [PLUGABLE_7PORT,
    169             PLUGABLE_7PORT_USB3_PART2,
    170             PLUGABLE_7PORT_USB3_PART3,
    171             KEEDOX,
    172             VIA]
    173 
    174 def 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