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