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.
17 """USB descriptor field information."""
19 def __init__(self
, name
, str_fmt
, struct_fmt
, required
):
20 """Define a new USB descriptor field.
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?
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.
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.
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.
65 if cls
._fields
is None:
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
)
74 return getattr(self
, member_name
)
75 except AttributeError:
76 assert default
is not None
79 setattr(cls
, name
, property(Getter
, Setter
))
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.
92 name: String name of the field.
93 struct_fmt: Python 'struct' module format string for this field.
95 str_fmt: Python 'string' module format string for this field.
97 if cls
._fields
is None:
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
):
106 setattr(cls
, name
, property(Getter
, Setter
))
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
116 The value of this field may not be given as a constructor parameter or
117 set on an existing instance.
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:
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
))
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.
143 **kwargs: Field values.
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
)
159 raise TypeError('Missing fields: {}'.format(', '.join(required_fields
)))
163 """Returns the Python 'struct' module format string for this descriptor."""
164 return '<{}'.format(''.join([field
.struct_fmt
for field
in self
._fields
]))
167 def struct_size(self
):
168 """Returns the size of the struct defined by fmt."""
169 return struct
.calcsize(self
.fmt
)
172 def total_size(self
):
173 """Returns the total size of this descriptor."""
174 return self
.struct_size
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
)
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.
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
= []
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
)
240 bufs
= [super(DescriptorContainer
, self
).Encode()]
241 bufs
.extend(descriptor
.Encode() for descriptor
in self
._descriptors
)
245 return '{}\n{}'.format(super(DescriptorContainer
, self
).__str
__(),
246 '\n'.join(str(descriptor
)
247 for descriptor
in self
._descriptors
))
250 class ConfigurationDescriptor(DescriptorContainer
):
251 """Standard Configuration Descriptor.
253 See Universal Serial Bus Specification Revision 2.0 Table 9-10.
256 def __init__(self
, **kwargs
):
257 super(ConfigurationDescriptor
, self
).__init
__(**kwargs
)
258 self
._interfaces
= {}
261 def num_interfaces(self
):
262 interface_numbers
= {key
[0] for key
in self
._interfaces
.iterkeys()}
263 return len(interface_numbers
)
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
273 def GetInterfaces(self
):
274 return self
._interfaces
.values()
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',
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')
288 class InterfaceDescriptor(DescriptorContainer
):
289 """Standard Interface Descriptor.
291 See Universal Serial Bus Specification Revision 2.0 Table 9-12.
294 def __init__(self
, **kwargs
):
295 super(InterfaceDescriptor
, self
).__init
__(**kwargs
)
299 def num_endpoints(self
):
300 return len(self
._endpoints
)
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
309 def GetEndpoints(self
):
310 return self
._endpoints
.values()
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)
327 class EndpointDescriptor(Descriptor
):
328 """Standard Endpoint Descriptor.
330 See Universal Serial Bus Specification Revision 2.0 Table 9-13.
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')
343 class HidDescriptor(Descriptor
):
346 See Device Class Definition for Human Interface Devices (HID) Version 1.11
350 def __init__(self
, **kwargs
):
351 super(HidDescriptor
, self
).__init
__(**kwargs
)
352 self
._descriptors
= []
354 def AddDescriptor(self
, typ
, length
):
355 self
._descriptors
.append((typ
, length
))
358 def struct_size(self
):
359 return super(HidDescriptor
, self
).struct_size
+ self
.num_descriptors
* 3
362 def num_descriptors(self
):
363 return len(self
._descriptors
)
366 bufs
= [super(HidDescriptor
, self
).Encode()]
367 bufs
.extend(struct
.pack('<BH', typ
, length
)
368 for typ
, length
in self
._descriptors
)
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
))
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')