Remove APIPermission::kFileSystemWriteDirectory
[chromium-blink-merge.git] / tools / usb_gadget / usb_descriptors.py
blob1ec5dbd41e4f71fa6f10b5e0ca9f858427b70f80
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.
5 """USB descriptor generation utilities.
7 Classes to represent and generate USB descriptors.
8 """
10 import struct
12 import hid_constants
13 import usb_constants
16 class Field(object):
17 """USB descriptor field information."""
19 def __init__(self, name, str_fmt, struct_fmt, required):
20 """Define a new USB descriptor field.
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
33 def Format(self, value):
34 return self.str_fmt.format(value)
37 class Descriptor(object):
38 """Base class for USB descriptor types.
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 """
46 _fields = None
48 @classmethod
49 def AddField(cls, name, struct_fmt, str_fmt='{}', default=None):
50 """Adds a user-specified field to this descriptor.
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.
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.
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))
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
79 setattr(cls, name, property(Getter, Setter))
81 @classmethod
82 def AddFixedField(cls, name, struct_fmt, value, str_fmt='{}'):
83 """Adds a constant field to this descriptor.
85 Adds a constant field to the binary structure representing this descriptor.
86 The field will be accessible as foo.name on any instance.
88 The value of this field may not be given as a constructor parameter or
89 set on an existing instance.
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))
101 def Setter(unused_self, unused_value):
102 raise RuntimeError('{} is a fixed field.'.format(name))
103 def Getter(unused_self):
104 return value
106 setattr(cls, name, property(Getter, Setter))
108 @classmethod
109 def AddComputedField(cls, name, struct_fmt, property_name, str_fmt='{}'):
110 """Adds a constant field to this descriptor.
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.
116 The value of this field may not be given as a constructor parameter or
117 set on an existing instance.
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.
125 if cls._fields is None:
126 cls._fields = []
127 cls._fields.append(Field(name, str_fmt, struct_fmt, False))
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)
134 setattr(cls, name, property(Getter, Setter))
136 def __init__(self, **kwargs):
137 """Constructs a new instance of this descriptor.
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.
142 Args:
143 **kwargs: Field values.
145 Raises:
146 TypeError: A required field was missing or an unexpected field was given.
148 fields = {field.name for field in self._fields}
149 required_fields = {field.name for field in self._fields if field.required}
151 for arg, value in kwargs.iteritems():
152 if arg not in fields:
153 raise TypeError('Unexpected field: {}'.format(arg))
155 setattr(self, arg, value)
156 required_fields.discard(arg)
158 if required_fields:
159 raise TypeError('Missing fields: {}'.format(', '.join(required_fields)))
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]))
166 @property
167 def struct_size(self):
168 """Returns the size of the struct defined by fmt."""
169 return struct.calcsize(self.fmt)
171 @property
172 def total_size(self):
173 """Returns the total size of this descriptor."""
174 return self.struct_size
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)
181 def __str__(self):
182 max_length = max(len(field.name) for field in self._fields)
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)
193 class DeviceDescriptor(Descriptor):
194 """Standard Device Descriptor.
196 See Universal Serial Bus Specification Revision 2.0 Table 9-8.
198 pass
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)
220 class DescriptorContainer(Descriptor):
221 """Super-class for descriptors which contain more descriptors.
223 This class adds the ability for a descriptor to have an array of additional
224 descriptors which follow it.
227 def __init__(self, **kwargs):
228 super(DescriptorContainer, self).__init__(**kwargs)
229 self._descriptors = []
231 @property
232 def total_size(self):
233 return self.struct_size + sum([descriptor.total_size
234 for descriptor in self._descriptors])
236 def Add(self, descriptor):
237 self._descriptors.append(descriptor)
239 def Encode(self):
240 bufs = [super(DescriptorContainer, self).Encode()]
241 bufs.extend(descriptor.Encode() for descriptor in self._descriptors)
242 return ''.join(bufs)
244 def __str__(self):
245 return '{}\n{}'.format(super(DescriptorContainer, self).__str__(),
246 '\n'.join(str(descriptor)
247 for descriptor in self._descriptors))
250 class StringDescriptor(Descriptor):
251 """Standard String Descriptor.
253 See Universal Serial Bus Specification Revision 2.0 Table 9-16.
256 def __init__(self, **kwargs):
257 self.bString = kwargs.pop('bString', '')
258 super(StringDescriptor, self).__init__(**kwargs)
260 @property
261 def total_size(self):
262 return self.struct_size + len(self.bString.encode('UTF-16LE'))
264 def Encode(self):
265 return (
266 super(StringDescriptor, self).Encode() +
267 self.bString.encode('UTF-16LE'))
269 def __str__(self):
270 return '{}\n bString: "{}"'.format(
271 super(StringDescriptor, self).__str__(), self.bString)
273 StringDescriptor.AddComputedField('bLength', 'B', 'total_size')
274 StringDescriptor.AddFixedField(
275 'bDescriptorType', 'B', usb_constants.DescriptorType.STRING)
278 class ConfigurationDescriptor(DescriptorContainer):
279 """Standard Configuration Descriptor.
281 See Universal Serial Bus Specification Revision 2.0 Table 9-10.
284 def __init__(self, **kwargs):
285 super(ConfigurationDescriptor, self).__init__(**kwargs)
286 self._interfaces = {}
288 @property
289 def num_interfaces(self):
290 interface_numbers = {key[0] for key in self._interfaces.iterkeys()}
291 return len(interface_numbers)
293 def AddInterface(self, interface):
294 key = (interface.bInterfaceNumber, interface.bAlternateSetting)
295 if key in self._interfaces:
296 raise RuntimeError('Interface {} (alternate {}) already defined.'
297 .format(key[0], key[1]))
298 self._interfaces[key] = interface
299 self.Add(interface)
301 def GetInterfaces(self):
302 return self._interfaces.values()
304 ConfigurationDescriptor.AddComputedField('bLength', 'B', 'struct_size')
305 ConfigurationDescriptor.AddFixedField(
306 'bDescriptorType', 'B', usb_constants.DescriptorType.CONFIGURATION)
307 ConfigurationDescriptor.AddComputedField('wTotalLength', 'H', 'total_size')
308 ConfigurationDescriptor.AddComputedField('bNumInterfaces', 'B',
309 'num_interfaces')
310 ConfigurationDescriptor.AddField('bConfigurationValue', 'B', default=1)
311 ConfigurationDescriptor.AddField('iConfiguration', 'B', default=0)
312 ConfigurationDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}')
313 ConfigurationDescriptor.AddField('MaxPower', 'B')
316 class InterfaceDescriptor(DescriptorContainer):
317 """Standard Interface Descriptor.
319 See Universal Serial Bus Specification Revision 2.0 Table 9-12.
322 def __init__(self, **kwargs):
323 super(InterfaceDescriptor, self).__init__(**kwargs)
324 self._endpoints = {}
326 @property
327 def num_endpoints(self):
328 return len(self._endpoints)
330 def AddEndpoint(self, endpoint):
331 if endpoint.bEndpointAddress in self._endpoints:
332 raise RuntimeError('Endpoint 0x{:02X} already defined on this interface.'
333 .format(endpoint.bEndpointAddress))
334 self._endpoints[endpoint.bEndpointAddress] = endpoint
335 self.Add(endpoint)
337 def GetEndpoints(self):
338 return self._endpoints.values()
340 InterfaceDescriptor.AddComputedField('bLength', 'B', 'struct_size')
341 InterfaceDescriptor.AddFixedField('bDescriptorType', 'B',
342 usb_constants.DescriptorType.INTERFACE)
343 InterfaceDescriptor.AddField('bInterfaceNumber', 'B')
344 InterfaceDescriptor.AddField('bAlternateSetting', 'B', default=0)
345 InterfaceDescriptor.AddComputedField('bNumEndpoints', 'B', 'num_endpoints')
346 InterfaceDescriptor.AddField('bInterfaceClass', 'B',
347 default=usb_constants.InterfaceClass.VENDOR)
348 InterfaceDescriptor.AddField('bInterfaceSubClass', 'B',
349 default=usb_constants.InterfaceSubClass.VENDOR)
350 InterfaceDescriptor.AddField('bInterfaceProtocol', 'B',
351 default=usb_constants.InterfaceProtocol.VENDOR)
352 InterfaceDescriptor.AddField('iInterface', 'B', default=0)
355 class EndpointDescriptor(Descriptor):
356 """Standard Endpoint Descriptor.
358 See Universal Serial Bus Specification Revision 2.0 Table 9-13.
360 pass
362 EndpointDescriptor.AddComputedField('bLength', 'B', 'struct_size')
363 EndpointDescriptor.AddFixedField('bDescriptorType', 'B',
364 usb_constants.DescriptorType.ENDPOINT)
365 EndpointDescriptor.AddField('bEndpointAddress', 'B', str_fmt='0x{:02X}')
366 EndpointDescriptor.AddField('bmAttributes', 'B', str_fmt='0x{:02X}')
367 EndpointDescriptor.AddField('wMaxPacketSize', 'H')
368 EndpointDescriptor.AddField('bInterval', 'B')
371 class HidDescriptor(Descriptor):
372 """HID Descriptor.
374 See Device Class Definition for Human Interface Devices (HID) Version 1.11
375 section 6.2.1.
378 def __init__(self, **kwargs):
379 super(HidDescriptor, self).__init__(**kwargs)
380 self._descriptors = []
382 def AddDescriptor(self, typ, length):
383 self._descriptors.append((typ, length))
385 @property
386 def struct_size(self):
387 return super(HidDescriptor, self).struct_size + self.num_descriptors * 3
389 @property
390 def num_descriptors(self):
391 return len(self._descriptors)
393 def Encode(self):
394 bufs = [super(HidDescriptor, self).Encode()]
395 bufs.extend(struct.pack('<BH', typ, length)
396 for typ, length in self._descriptors)
397 return ''.join(bufs)
399 def __str__(self):
400 return '{}\n{}'.format(
401 super(HidDescriptor, self).__str__(),
402 '\n'.join(' bDescriptorType: 0x{:02X}\n wDescriptorLength: {}'
403 .format(typ, length) for typ, length in self._descriptors))
405 HidDescriptor.AddComputedField('bLength', 'B', 'struct_size')
406 HidDescriptor.AddFixedField('bDescriptorType', 'B',
407 hid_constants.DescriptorType.HID)
408 HidDescriptor.AddField('bcdHID', 'H', default=0x0111, str_fmt='0x{:04X}')
409 HidDescriptor.AddField('bCountryCode', 'B', default=0)
410 HidDescriptor.AddComputedField('bNumDescriptors', 'B', 'num_descriptors')
413 class BosDescriptor(DescriptorContainer):
414 """Binary Device Object Store descriptor.
416 See Universal Serial Bus 3.1 Specification, Revision 1.0 Table 9-12.
419 def __init__(self, **kwargs):
420 super(BosDescriptor, self).__init__(**kwargs)
421 self._device_caps = []
423 @property
424 def num_device_caps(self):
425 return len(self._device_caps)
427 def AddDeviceCapability(self, device_capability):
428 self._device_caps.append(device_capability)
429 self.Add(device_capability)
431 def GetDeviceCapabilities(self):
432 return self._device_caps
434 BosDescriptor.AddComputedField('bLength', 'B', 'struct_size')
435 BosDescriptor.AddFixedField('bDescriptorType', 'B',
436 usb_constants.DescriptorType.BOS)
437 BosDescriptor.AddComputedField('wTotalLength', 'H', 'total_size')
438 BosDescriptor.AddComputedField('bNumDeviceCaps', 'B', 'num_device_caps')
441 class ContainerIdDescriptor(Descriptor):
442 """Container ID descriptor.
444 See Universal Serial Bus 3.1 Specification, Revision 1.0 Table 9-17.
446 pass
448 ContainerIdDescriptor.AddComputedField('bLength', 'B', 'struct_size')
449 ContainerIdDescriptor.AddFixedField(
450 'bDescriptorType', 'B', usb_constants.DescriptorType.DEVICE_CAPABILITY)
451 ContainerIdDescriptor.AddFixedField(
452 'bDevCapabilityType', 'B', usb_constants.CapabilityType.CONTAINER_ID)
453 ContainerIdDescriptor.AddFixedField('bReserved', 'B', 0)
454 ContainerIdDescriptor.AddField('ContainerID', '16s')