Home | History | Annotate | Download | only in usb_gadget
      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 hid_constants
     13 import usb_constants
     14 
     15 
     16 class 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 
     37 class 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 
    193 class DeviceDescriptor(Descriptor):
    194   """Standard Device Descriptor.
    195 
    196   See Universal Serial Bus Specification Revision 2.0 Table 9-8.
    197   """
    198   pass
    199 
    200 DeviceDescriptor.AddComputedField('bLength', 'B', 'struct_size')
    201 DeviceDescriptor.AddFixedField('bDescriptorType', 'B',
    202                                usb_constants.DescriptorType.DEVICE)
    203 DeviceDescriptor.AddField('bcdUSB', 'H', default=0x0200, str_fmt='0x{:04X}')
    204 DeviceDescriptor.AddField('bDeviceClass', 'B',
    205                           default=usb_constants.DeviceClass.PER_INTERFACE)
    206 DeviceDescriptor.AddField('bDeviceSubClass', 'B',
    207                           default=usb_constants.DeviceSubClass.PER_INTERFACE)
    208 DeviceDescriptor.AddField('bDeviceProtocol', 'B',
    209                           default=usb_constants.DeviceProtocol.PER_INTERFACE)
    210 DeviceDescriptor.AddField('bMaxPacketSize0', 'B', default=64)
    211 DeviceDescriptor.AddField('idVendor', 'H', str_fmt='0x{:04X}')
    212 DeviceDescriptor.AddField('idProduct', 'H', str_fmt='0x{:04X}')
    213 DeviceDescriptor.AddField('bcdDevice', 'H', str_fmt='0x{:04X}')
    214 DeviceDescriptor.AddField('iManufacturer', 'B', default=0)
    215 DeviceDescriptor.AddField('iProduct', 'B', default=0)
    216 DeviceDescriptor.AddField('iSerialNumber', 'B', default=0)
    217 DeviceDescriptor.AddField('bNumConfigurations', 'B', default=1)
    218 
    219 
    220 class 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 
    250 class 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 
    276 ConfigurationDescriptor.AddComputedField('bLength', 'B', 'struct_size')
    277 ConfigurationDescriptor.AddFixedField(
    278     'bDescriptorType', 'B', usb_constants.DescriptorType.CONFIGURATION)
    279 ConfigurationDescriptor.AddComputedField('wTotalLength', 'H', 'total_size')
    280 ConfigurationDescriptor.AddComputedField('bNumInterfaces', 'B',
    281                                          'num_interfaces')
    282 ConfigurationDescriptor.AddField('bConfigurationValue', 'B', default=1)
    283 ConfigurationDescriptor.AddField('iConfiguration', 'B', default=0)
    284 ConfigurationDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}')
    285 ConfigurationDescriptor.AddField('MaxPower', 'B')
    286 
    287 
    288 class 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 
    312 InterfaceDescriptor.AddComputedField('bLength', 'B', 'struct_size')
    313 InterfaceDescriptor.AddFixedField('bDescriptorType', 'B',
    314                                   usb_constants.DescriptorType.INTERFACE)
    315 InterfaceDescriptor.AddField('bInterfaceNumber', 'B')
    316 InterfaceDescriptor.AddField('bAlternateSetting', 'B', default=0)
    317 InterfaceDescriptor.AddComputedField('bNumEndpoints', 'B', 'num_endpoints')
    318 InterfaceDescriptor.AddField('bInterfaceClass', 'B',
    319                              default=usb_constants.InterfaceClass.VENDOR)
    320 InterfaceDescriptor.AddField('bInterfaceSubClass', 'B',
    321                              default=usb_constants.InterfaceSubClass.VENDOR)
    322 InterfaceDescriptor.AddField('bInterfaceProtocol', 'B',
    323                              default=usb_constants.InterfaceProtocol.VENDOR)
    324 InterfaceDescriptor.AddField('iInterface', 'B', default=0)
    325 
    326 
    327 class EndpointDescriptor(Descriptor):
    328   """Standard Endpoint Descriptor.
    329 
    330   See Universal Serial Bus Specification Revision 2.0 Table 9-13.
    331   """
    332   pass
    333 
    334 EndpointDescriptor.AddComputedField('bLength', 'B', 'struct_size')
    335 EndpointDescriptor.AddFixedField('bDescriptorType', 'B',
    336                                  usb_constants.DescriptorType.ENDPOINT)
    337 EndpointDescriptor.AddField('bEndpointAddress', 'B', str_fmt='0x{:02X}')
    338 EndpointDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}')
    339 EndpointDescriptor.AddField('wMaxPacketSize', 'H')
    340 EndpointDescriptor.AddField('bInterval', 'B')
    341 
    342 
    343 class 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 
    377 HidDescriptor.AddComputedField('bLength', 'B', 'struct_size')
    378 HidDescriptor.AddFixedField('bDescriptorType', 'B',
    379                             hid_constants.DescriptorType.HID)
    380 HidDescriptor.AddField('bcdHID', 'H', default=0x0111, str_fmt='0x{:04X}')
    381 HidDescriptor.AddField('bCountryCode', 'B', default=0)
    382 HidDescriptor.AddComputedField('bNumDescriptors', 'B', 'num_descriptors')
    383