1"""Utility class representing a CfM USB device. 2 3This class represents actual data found by running the usb-device command. 4""" 5 6class UsbDevice(object): 7 """Utility class representing a CfM USB device.""" 8 9 def __init__(self, 10 vid, 11 pid, 12 product, 13 interfaces, 14 bus, 15 port, 16 level, 17 parent=None): 18 """ 19 Constructor. 20 21 @param vid: Vendor ID. String. 22 @param pid: Product ID. String. 23 @param product: Product description. String 24 @param interfaces: List of strings. 25 @param bus: The bus this device is connected to. Number. 26 @param port: The port number as specified in /sys/bus/usb/devices/usb*. 27 Number. 28 @param level: The level in the device hierarchy this device is connected 29 at. A device connected directly to a port is typically at level 1. 30 @param parent: Optional parent UsbDevice. A parent device is a device that 31 this device is connected to, typically a USB Hub. 32 """ 33 self._vid = vid 34 self._pid = pid 35 self._product = product 36 self._interfaces = interfaces 37 self._bus = bus 38 self._port = port 39 self._level = level 40 self._parent = parent 41 42 @property 43 def vendor_id(self): 44 """Returns the vendor id for this USB device.""" 45 return self._vid 46 47 @property 48 def product_id(self): 49 """Returns the product id for this USB device.""" 50 return self._pid 51 52 @property 53 def vid_pid(self): 54 """Return the <vendor_id>:<product_id> as a string.""" 55 return '%s:%s' % (self._vid, self._pid) 56 57 @property 58 def product(self): 59 """Returns the product name.""" 60 return self._product 61 62 @property 63 def interfaces(self): 64 """Returns the list of interfaces.""" 65 return self._interfaces 66 67 @property 68 def port(self): 69 """Returns the port this USB device is connected to.""" 70 return self._port 71 72 @property 73 def bus(self): 74 """Returns the bus this USB device is connected to.""" 75 return self._bus 76 77 @property 78 def level(self): 79 """Returns the level of this USB Device.""" 80 return self._level 81 82 @property 83 def parent(self): 84 """ 85 Returns the parent device of this device. 86 87 Or None if this is the top level device. 88 @returns the parent or None. 89 """ 90 return self._parent 91 92 @parent.setter 93 def parent(self, value): 94 """ 95 Sets the parent device of this device. 96 97 We allow setting parents to make it easier to create the device tree. 98 @param value the new parent. 99 """ 100 self._parent = value 101 102 def interfaces_match_spec(self, usb_device_spec): 103 """ 104 Checks that the interfaces of this device matches those of the given spec. 105 106 @param usb_device_spec an instance of UsbDeviceSpec 107 @returns True or False 108 """ 109 # List of expected interfaces. This might be a sublist of the actual 110 # list of interfaces. Note: we have to use lists and not sets since 111 # the list of interfaces might contain duplicates. 112 expected_interfaces = sorted(usb_device_spec.interfaces) 113 length = len(expected_interfaces) 114 actual_interfaces = sorted(self.interfaces) 115 return actual_interfaces[0:length] == expected_interfaces 116 117 def get_parent(self, level): 118 """ 119 Gets the parent device at the specified level. 120 121 Devices are connected in a hierarchy. Typically like this: 122 Level 0: Machine's internal USB hub 123 | 124 +--+ Level 1: Device connected to the machine's physical ports. 125 | 126 +--+ Level 2: If level 1 is a Hub, this is a device connected to 127 that Hub. 128 129 A typical application of this method is when power cycling. Then we get a 130 device's parent at level 1 to locate the port that should be power cycled. 131 132 @param level the level of the parent to return. 133 @returns A UsbDevice instance of the parent at the specified level. 134 @raises ValueError if we did not find a device at the specified level. 135 """ 136 device = self 137 while device != None: 138 if device.level < level: 139 raise ValueError( 140 'Reached lower level without finding level %d', level) 141 if device.level == level: 142 return device 143 device = device.parent 144 145 def __str__(self): 146 return "%s (%s)" % (self._product, self.vid_pid) 147 148 def __repr__(self): 149 return "%s (%s), bus=%s, port=%s, parent=%s" % ( 150 self._product, self.vid_pid, self._bus, self._port, self.parent) 151