usb_descriptors.py revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1# Copyright 2014 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"""USB descriptor generation utilities. 6 7Classes to represent and generate USB descriptors. 8""" 9 10import struct 11 12import hid_constants 13import usb_constants 14 15 16class Field(object): 17 """USB descriptor field information.""" 18 19 def __init__(self, name, str_fmt, struct_fmt, required): 20 """Define a new USB descriptor field. 21 22 Args: 23 name: Name of the field. 24 str_fmt: Python 'string' module format string for this field. 25 struct_fmt: Python 'struct' module format string for this field. 26 required: Is this a required field? 27 """ 28 self.name = name 29 self.str_fmt = str_fmt 30 self.struct_fmt = struct_fmt 31 self.required = required 32 33 def Format(self, value): 34 return self.str_fmt.format(value) 35 36 37class Descriptor(object): 38 """Base class for USB descriptor types. 39 40 This class provides general functionality for creating object types that 41 represent USB descriptors. The AddField and related methods are used to 42 define the fields of each structure. Fields can then be set using keyword 43 arguments to the object constructor or by accessing properties on the object. 44 """ 45 46 _fields = None 47 48 @classmethod 49 def AddField(cls, name, struct_fmt, str_fmt='{}', default=None): 50 """Adds a user-specified field to this descriptor. 51 52 Adds a field to the binary structure representing this descriptor. The field 53 can be set by passing a keyword argument name=... to the object constructor 54 will be accessible as foo.name on any instance. 55 56 If no default value is provided then the constructor will through an 57 exception if this field is not one of the provided keyword arguments. 58 59 Args: 60 name: String name of the field. 61 struct_fmt: Python 'struct' module format string for this field. 62 str_fmt: Python 'string' module format string for this field. 63 default: Default value. 64 """ 65 if cls._fields is None: 66 cls._fields = [] 67 cls._fields.append(Field(name, str_fmt, struct_fmt, default is None)) 68 69 member_name = '_{}'.format(name) 70 def Setter(self, value): 71 setattr(self, member_name, value) 72 def Getter(self): 73 try: 74 return getattr(self, member_name) 75 except AttributeError: 76 assert default is not None 77 return default 78 79 setattr(cls, name, property(Getter, Setter)) 80 81 @classmethod 82 def AddFixedField(cls, name, struct_fmt, value, str_fmt='{}'): 83 """Adds a constant field to this descriptor. 84 85 Adds a constant field to the binary structure representing this descriptor. 86 The field will be accessible as foo.name on any instance. 87 88 The value of this field may not be given as a constructor parameter or 89 set on an existing instance. 90 91 Args: 92 name: String name of the field. 93 struct_fmt: Python 'struct' module format string for this field. 94 value: Field value. 95 str_fmt: Python 'string' module format string for this field. 96 """ 97 if cls._fields is None: 98 cls._fields = [] 99 cls._fields.append(Field(name, str_fmt, struct_fmt, False)) 100 101 def Setter(unused_self, unused_value): 102 raise RuntimeError('{} is a fixed field.'.format(name)) 103 def Getter(unused_self): 104 return value 105 106 setattr(cls, name, property(Getter, Setter)) 107 108 @classmethod 109 def AddComputedField(cls, name, struct_fmt, property_name, str_fmt='{}'): 110 """Adds a constant field to this descriptor. 111 112 Adds a field to the binary structure representing this descriptor whos value 113 is equal to an object property. The field will be accessible as foo.name on 114 any instance. 115 116 The value of this field may not be given as a constructor parameter or 117 set on an existing instance. 118 119 Args: 120 name: String name of the field. 121 struct_fmt: Python 'struct' module format string for this field. 122 property_name: Property to read. 123 str_fmt: Python 'string' module format string for this field. 124 """ 125 if cls._fields is None: 126 cls._fields = [] 127 cls._fields.append(Field(name, str_fmt, struct_fmt, False)) 128 129 def Setter(unused_self, unused_value): 130 raise RuntimeError('{} is a computed field.'.format(name)) 131 def Getter(self): 132 return getattr(self, property_name) 133 134 setattr(cls, name, property(Getter, Setter)) 135 136 def __init__(self, **kwargs): 137 """Constructs a new instance of this descriptor. 138 139 All fields which do not have a default value and are not fixed or computed 140 from a property must be specified as keyword arguments. 141 142 Args: 143 **kwargs: Field values. 144 145 Raises: 146 TypeError: A required field was missing or an unexpected field was given. 147 """ 148 fields = {field.name for field in self._fields} 149 required_fields = {field.name for field in self._fields if field.required} 150 151 for arg, value in kwargs.iteritems(): 152 if arg not in fields: 153 raise TypeError('Unexpected field: {}'.format(arg)) 154 155 setattr(self, arg, value) 156 required_fields.discard(arg) 157 158 if required_fields: 159 raise TypeError('Missing fields: {}'.format(', '.join(required_fields))) 160 161 @property 162 def fmt(self): 163 """Returns the Python 'struct' module format string for this descriptor.""" 164 return '<{}'.format(''.join([field.struct_fmt for field in self._fields])) 165 166 @property 167 def struct_size(self): 168 """Returns the size of the struct defined by fmt.""" 169 return struct.calcsize(self.fmt) 170 171 @property 172 def total_size(self): 173 """Returns the total size of this descriptor.""" 174 return self.struct_size 175 176 def Encode(self): 177 """Returns the binary representation of this descriptor.""" 178 values = [getattr(self, field.name) for field in self._fields] 179 return struct.pack(self.fmt, *values) 180 181 def __str__(self): 182 max_length = max(len(field.name) for field in self._fields) 183 184 return '{}:\n {}'.format( 185 self.__class__.__name__, 186 '\n '.join('{} {}'.format( 187 '{}:'.format(field.name).ljust(max_length+1), 188 field.Format(getattr(self, field.name)) 189 ) for field in self._fields) 190 ) 191 192 193class DeviceDescriptor(Descriptor): 194 """Standard Device Descriptor. 195 196 See Universal Serial Bus Specification Revision 2.0 Table 9-8. 197 """ 198 pass 199 200DeviceDescriptor.AddComputedField('bLength', 'B', 'struct_size') 201DeviceDescriptor.AddFixedField('bDescriptorType', 'B', 202 usb_constants.DescriptorType.DEVICE) 203DeviceDescriptor.AddField('bcdUSB', 'H', default=0x0200, str_fmt='0x{:04X}') 204DeviceDescriptor.AddField('bDeviceClass', 'B', 205 default=usb_constants.DeviceClass.PER_INTERFACE) 206DeviceDescriptor.AddField('bDeviceSubClass', 'B', 207 default=usb_constants.DeviceSubClass.PER_INTERFACE) 208DeviceDescriptor.AddField('bDeviceProtocol', 'B', 209 default=usb_constants.DeviceProtocol.PER_INTERFACE) 210DeviceDescriptor.AddField('bMaxPacketSize0', 'B', default=64) 211DeviceDescriptor.AddField('idVendor', 'H', str_fmt='0x{:04X}') 212DeviceDescriptor.AddField('idProduct', 'H', str_fmt='0x{:04X}') 213DeviceDescriptor.AddField('bcdDevice', 'H', str_fmt='0x{:04X}') 214DeviceDescriptor.AddField('iManufacturer', 'B', default=0) 215DeviceDescriptor.AddField('iProduct', 'B', default=0) 216DeviceDescriptor.AddField('iSerialNumber', 'B', default=0) 217DeviceDescriptor.AddField('bNumConfigurations', 'B', default=1) 218 219 220class DescriptorContainer(Descriptor): 221 """Super-class for descriptors which contain more descriptors. 222 223 This class adds the ability for a descriptor to have an array of additional 224 descriptors which follow it. 225 """ 226 227 def __init__(self, **kwargs): 228 super(DescriptorContainer, self).__init__(**kwargs) 229 self._descriptors = [] 230 231 @property 232 def total_size(self): 233 return self.struct_size + sum([descriptor.total_size 234 for descriptor in self._descriptors]) 235 236 def Add(self, descriptor): 237 self._descriptors.append(descriptor) 238 239 def Encode(self): 240 bufs = [super(DescriptorContainer, self).Encode()] 241 bufs.extend(descriptor.Encode() for descriptor in self._descriptors) 242 return ''.join(bufs) 243 244 def __str__(self): 245 return '{}\n{}'.format(super(DescriptorContainer, self).__str__(), 246 '\n'.join(str(descriptor) 247 for descriptor in self._descriptors)) 248 249 250class ConfigurationDescriptor(DescriptorContainer): 251 """Standard Configuration Descriptor. 252 253 See Universal Serial Bus Specification Revision 2.0 Table 9-10. 254 """ 255 256 def __init__(self, **kwargs): 257 super(ConfigurationDescriptor, self).__init__(**kwargs) 258 self._interfaces = {} 259 260 @property 261 def num_interfaces(self): 262 interface_numbers = {key[0] for key in self._interfaces.iterkeys()} 263 return len(interface_numbers) 264 265 def AddInterface(self, interface): 266 key = (interface.bInterfaceNumber, interface.bAlternateSetting) 267 if key in self._interfaces: 268 raise RuntimeError('Interface {} (alternate {}) already defined.' 269 .format(key[0], key[1])) 270 self._interfaces[key] = interface 271 self.Add(interface) 272 273 def GetInterfaces(self): 274 return self._interfaces.values() 275 276ConfigurationDescriptor.AddComputedField('bLength', 'B', 'struct_size') 277ConfigurationDescriptor.AddFixedField( 278 'bDescriptorType', 'B', usb_constants.DescriptorType.CONFIGURATION) 279ConfigurationDescriptor.AddComputedField('wTotalLength', 'H', 'total_size') 280ConfigurationDescriptor.AddComputedField('bNumInterfaces', 'B', 281 'num_interfaces') 282ConfigurationDescriptor.AddField('bConfigurationValue', 'B', default=1) 283ConfigurationDescriptor.AddField('iConfiguration', 'B', default=0) 284ConfigurationDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}') 285ConfigurationDescriptor.AddField('MaxPower', 'B') 286 287 288class InterfaceDescriptor(DescriptorContainer): 289 """Standard Interface Descriptor. 290 291 See Universal Serial Bus Specification Revision 2.0 Table 9-12. 292 """ 293 294 def __init__(self, **kwargs): 295 super(InterfaceDescriptor, self).__init__(**kwargs) 296 self._endpoints = {} 297 298 @property 299 def num_endpoints(self): 300 return len(self._endpoints) 301 302 def AddEndpoint(self, endpoint): 303 if endpoint.bEndpointAddress in self._endpoints: 304 raise RuntimeError('Endpoint 0x{:02X} already defined on this interface.' 305 .format(endpoint.bEndpointAddress)) 306 self._endpoints[endpoint.bEndpointAddress] = endpoint 307 self.Add(endpoint) 308 309 def GetEndpoints(self): 310 return self._endpoints.values() 311 312InterfaceDescriptor.AddComputedField('bLength', 'B', 'struct_size') 313InterfaceDescriptor.AddFixedField('bDescriptorType', 'B', 314 usb_constants.DescriptorType.INTERFACE) 315InterfaceDescriptor.AddField('bInterfaceNumber', 'B') 316InterfaceDescriptor.AddField('bAlternateSetting', 'B', default=0) 317InterfaceDescriptor.AddComputedField('bNumEndpoints', 'B', 'num_endpoints') 318InterfaceDescriptor.AddField('bInterfaceClass', 'B', 319 default=usb_constants.InterfaceClass.VENDOR) 320InterfaceDescriptor.AddField('bInterfaceSubClass', 'B', 321 default=usb_constants.InterfaceSubClass.VENDOR) 322InterfaceDescriptor.AddField('bInterfaceProtocol', 'B', 323 default=usb_constants.InterfaceProtocol.VENDOR) 324InterfaceDescriptor.AddField('iInterface', 'B', default=0) 325 326 327class EndpointDescriptor(Descriptor): 328 """Standard Endpoint Descriptor. 329 330 See Universal Serial Bus Specification Revision 2.0 Table 9-13. 331 """ 332 pass 333 334EndpointDescriptor.AddComputedField('bLength', 'B', 'struct_size') 335EndpointDescriptor.AddFixedField('bDescriptorType', 'B', 336 usb_constants.DescriptorType.ENDPOINT) 337EndpointDescriptor.AddField('bEndpointAddress', 'B', str_fmt='0x{:02X}') 338EndpointDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}') 339EndpointDescriptor.AddField('wMaxPacketSize', 'H') 340EndpointDescriptor.AddField('bInterval', 'B') 341 342 343class HidDescriptor(Descriptor): 344 """HID Descriptor. 345 346 See Device Class Definition for Human Interface Devices (HID) Version 1.11 347 section 6.2.1. 348 """ 349 350 def __init__(self, **kwargs): 351 super(HidDescriptor, self).__init__(**kwargs) 352 self._descriptors = [] 353 354 def AddDescriptor(self, typ, length): 355 self._descriptors.append((typ, length)) 356 357 @property 358 def struct_size(self): 359 return super(HidDescriptor, self).struct_size + self.num_descriptors * 3 360 361 @property 362 def num_descriptors(self): 363 return len(self._descriptors) 364 365 def Encode(self): 366 bufs = [super(HidDescriptor, self).Encode()] 367 bufs.extend(struct.pack('<BH', typ, length) 368 for typ, length in self._descriptors) 369 return ''.join(bufs) 370 371 def __str__(self): 372 return '{}\n{}'.format( 373 super(HidDescriptor, self).__str__(), 374 '\n'.join(' bDescriptorType: 0x{:02X}\n wDescriptorLength: {}' 375 .format(typ, length) for typ, length in self._descriptors)) 376 377HidDescriptor.AddComputedField('bLength', 'B', 'struct_size') 378HidDescriptor.AddFixedField('bDescriptorType', 'B', 379 hid_constants.DescriptorType.HID) 380HidDescriptor.AddField('bcdHID', 'H', default=0x0111, str_fmt='0x{:04X}') 381HidDescriptor.AddField('bCountryCode', 'B', default=0) 382HidDescriptor.AddComputedField('bNumDescriptors', 'B', 'num_descriptors') 383