MD Downloads: only show "Today" or "Yesterday" when available
[chromium-blink-merge.git] / tools / usb_gadget / gadget.py
blobc29075003f6e456a6dd1c0dc96dd0af80f2c8aa2
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 """Generic USB gadget functionality.
6 """
8 import struct
10 import msos20_descriptors
11 import usb_constants
12 import usb_descriptors
15 class Gadget(object):
16 """Basic functionality for a USB device.
18 Implements standard control requests assuming that a subclass will handle
19 class- or vendor-specific requests.
20 """
22 def __init__(self, device_desc, fs_config_desc, hs_config_desc):
23 """Create a USB gadget device.
25 Args:
26 device_desc: USB device descriptor.
27 fs_config_desc: Low/full-speed device descriptor.
28 hs_config_desc: High-speed device descriptor.
29 """
30 self._speed = usb_constants.Speed.UNKNOWN
31 self._chip = None
32 self._device_desc = device_desc
33 self._fs_config_desc = fs_config_desc
34 self._hs_config_desc = hs_config_desc
35 # dict mapping language codes to a dict mapping indexes to strings
36 self._strings = {}
37 self._bos_descriptor = None
38 # dict mapping interface numbers to a set of endpoint addresses
39 self._active_endpoints = {}
40 # dict mapping endpoint addresses to interfaces
41 self._endpoint_interface_map = {}
42 self._ms_vendor_code_v1 = None
43 self._ms_vendor_code_v2 = None
44 self._ms_compat_ids = {}
45 self._ms_os20_config_subset = None
47 def GetDeviceDescriptor(self):
48 return self._device_desc
50 def GetFullSpeedConfigurationDescriptor(self):
51 return self._fs_config_desc
53 def GetHighSpeedConfigurationDescriptor(self):
54 return self._hs_config_desc
56 def GetConfigurationDescriptor(self):
57 if self._speed == usb_constants.Speed.FULL:
58 return self._fs_config_desc
59 elif self._speed == usb_constants.Speed.HIGH:
60 return self._hs_config_desc
61 else:
62 raise RuntimeError('Device is not connected.')
64 def GetSpeed(self):
65 return self._speed
67 def AddStringDescriptor(self, index, value, lang=0x0409):
68 """Add a string descriptor to this device.
70 Args:
71 index: String descriptor index (matches 'i' fields in descriptors).
72 value: The string.
73 lang: Language code (default: English).
75 Raises:
76 ValueError: The index or language code is invalid.
77 """
78 if index < 1 or index > 255:
79 raise ValueError('String descriptor index out of range.')
80 if lang < 0 or lang > 0xffff:
81 raise ValueError('String descriptor language code out of range.')
83 lang_strings = self._strings.setdefault(lang, {})
84 lang_strings[index] = value
86 def EnableMicrosoftOSDescriptorsV1(self, vendor_code=0x01):
87 if vendor_code < 0 or vendor_code > 255:
88 raise ValueError('Vendor code out of range.')
89 if vendor_code == self._ms_vendor_code_v1:
90 raise ValueError('OS Descriptor v1 vendor code conflicts with v2.')
92 self._ms_vendor_code_v1 = vendor_code
94 def EnableMicrosoftOSDescriptorsV2(self, vendor_code=0x02):
95 if vendor_code < 0 or vendor_code > 255:
96 raise ValueError('Vendor code out of range.')
97 if vendor_code == self._ms_vendor_code_v1:
98 raise ValueError('OS Descriptor v2 vendor code conflicts with v1.')
100 self._ms_vendor_code_v2 = vendor_code
101 self._ms_os20_descriptor_set = \
102 msos20_descriptors.DescriptorSetHeader(dwWindowsVersion=0x06030000)
103 # Gadget devices currently only support one configuration. Contrary to
104 # Microsoft's documentation the bConfigurationValue field should be set to
105 # the index passed to GET_DESCRIPTOR that returned the configuration instead
106 # of the configuration's bConfigurationValue field. (i.e. 0 instead of 1).
108 # https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/ae64282c-3bc3-49af-8391-4d174479d9e7/microsoft-os-20-descriptors-not-working-on-an-interface-of-a-composite-usb-device
109 self._ms_os20_config_subset = msos20_descriptors.ConfigurationSubsetHeader(
110 bConfigurationValue=0)
111 self._ms_os20_descriptor_set.Add(self._ms_os20_config_subset)
112 self._ms_os20_platform_descriptor = \
113 msos20_descriptors.PlatformCapabilityDescriptor(
114 dwWindowsVersion=0x06030000,
115 bMS_VendorCode=self._ms_vendor_code_v2)
116 self._ms_os20_platform_descriptor.SetDescriptorSet(
117 self._ms_os20_descriptor_set)
118 self.AddDeviceCapabilityDescriptor(self._ms_os20_platform_descriptor)
120 def SetMicrosoftCompatId(self, interface_number, compat_id, sub_compat_id=''):
121 self._ms_compat_ids[interface_number] = (compat_id, sub_compat_id)
122 if self._ms_os20_config_subset is not None:
123 function_header = msos20_descriptors.FunctionSubsetHeader(
124 bFirstInterface=interface_number)
125 function_header.Add(msos20_descriptors.CompatibleId(
126 CompatibleID=compat_id, SubCompatibleID=sub_compat_id))
127 self._ms_os20_config_subset.Add(function_header)
129 def AddDeviceCapabilityDescriptor(self, device_capability):
130 """Add a device capability descriptor to this device.
132 Args:
133 device_capability: The Descriptor object.
135 if self._bos_descriptor is None:
136 self._bos_descriptor = usb_descriptors.BosDescriptor()
137 self._bos_descriptor.AddDeviceCapability(device_capability)
139 def Connected(self, chip, speed):
140 """The device has been connected to a USB host.
142 Args:
143 chip: USB controller.
144 speed: Connection speed.
146 self._speed = speed
147 self._chip = chip
149 def Disconnected(self):
150 """The device has been disconnected from the USB host."""
151 self._speed = usb_constants.Speed.UNKNOWN
152 self._chip = None
153 self._active_endpoints.clear()
154 self._endpoint_interface_map.clear()
156 def IsConnected(self):
157 return self._chip is not None
159 def ControlRead(self, request_type, request, value, index, length):
160 """Handle a read on the control pipe (endpoint zero).
162 Args:
163 request_type: bmRequestType field of the setup packet.
164 request: bRequest field of the setup packet.
165 value: wValue field of the setup packet.
166 index: wIndex field of the setup packet.
167 length: Maximum amount of data the host expects the device to return.
169 Returns:
170 A buffer to return to the USB host with len <= length on success or
171 None to stall the pipe.
173 assert request_type & usb_constants.Dir.IN
174 typ = request_type & usb_constants.Type.MASK
175 recipient = request_type & usb_constants.Recipient.MASK
176 if typ == usb_constants.Type.STANDARD:
177 return self.StandardControlRead(
178 recipient, request, value, index, length)
179 elif typ == usb_constants.Type.CLASS:
180 return self.ClassControlRead(
181 recipient, request, value, index, length)
182 elif typ == usb_constants.Type.VENDOR:
183 return self.VendorControlRead(
184 recipient, request, value, index, length)
186 def ControlWrite(self, request_type, request, value, index, data):
187 """Handle a write to the control pipe (endpoint zero).
189 Args:
190 request_type: bmRequestType field of the setup packet.
191 request: bRequest field of the setup packet.
192 value: wValue field of the setup packet.
193 index: wIndex field of the setup packet.
194 data: Data stage of the request.
196 Returns:
197 True on success, None to stall the pipe.
199 assert not request_type & usb_constants.Dir.IN
200 typ = request_type & usb_constants.Type.MASK
201 recipient = request_type & usb_constants.Recipient.MASK
202 if typ == usb_constants.Type.STANDARD:
203 return self.StandardControlWrite(
204 recipient, request, value, index, data)
205 elif typ == usb_constants.Type.CLASS:
206 return self.ClassControlWrite(
207 recipient, request, value, index, data)
208 elif typ == usb_constants.Type.VENDOR:
209 return self.VendorControlWrite(
210 recipient, request, value, index, data)
212 def SendPacket(self, endpoint, data):
213 """Send a data packet on the given endpoint.
215 Args:
216 endpoint: Endpoint address.
217 data: Data buffer.
219 Raises:
220 ValueError: If the endpoint address is not valid.
221 RuntimeError: If the device is not connected.
223 if self._chip is None:
224 raise RuntimeError('Device is not connected.')
225 if not endpoint & usb_constants.Dir.IN:
226 raise ValueError('Cannot write to non-input endpoint.')
227 self._chip.SendPacket(endpoint, data)
229 def ReceivePacket(self, endpoint, data):
230 """Handle an incoming data packet on one of the device's active endpoints.
232 This method should be overridden by a subclass implementing endpoint-based
233 data transfers.
235 Args:
236 endpoint: Endpoint address.
237 data: Data buffer.
239 pass
241 def HaltEndpoint(self, endpoint):
242 """Signals a STALL condition to the host on the given endpoint.
244 Args:
245 endpoint: Endpoint address.
247 self._chip.HaltEndpoint(endpoint)
249 def StandardControlRead(self, recipient, request, value, index, length):
250 """Handle standard control transfers.
252 Args:
253 recipient: Request recipient (device, interface, endpoint, etc.)
254 request: bRequest field of the setup packet.
255 value: wValue field of the setup packet.
256 index: wIndex field of the setup packet.
257 length: Maximum amount of data the host expects the device to return.
259 Returns:
260 A buffer to return to the USB host with len <= length on success or
261 None to stall the pipe.
263 if recipient == usb_constants.Recipient.DEVICE:
264 if request == usb_constants.Request.GET_DESCRIPTOR:
265 desc_type = value >> 8
266 desc_index = value & 0xff
267 desc_lang = index
269 print 'GetDescriptor(recipient={}, type={}, index={}, lang={})'.format(
270 recipient, desc_type, desc_index, desc_lang)
272 return self.GetDescriptor(recipient, desc_type, desc_index, desc_lang,
273 length)
275 def GetDescriptor(self, recipient, typ, index, lang, length):
276 """Handle a standard GET_DESCRIPTOR request.
278 See Universal Serial Bus Specification Revision 2.0 section 9.4.3.
280 Args:
281 recipient: Request recipient (device, interface, endpoint, etc.)
282 typ: Descriptor type.
283 index: Descriptor index.
284 lang: Descriptor language code.
285 length: Maximum amount of data the host expects the device to return.
287 Returns:
288 The value of the descriptor or None to stall the pipe.
290 if typ == usb_constants.DescriptorType.STRING:
291 return self.GetStringDescriptor(index, lang, length)
292 elif typ == usb_constants.DescriptorType.BOS:
293 return self.GetBosDescriptor(length)
295 def ClassControlRead(self, recipient, request, value, index, length):
296 """Handle class-specific control transfers.
298 This function should be overridden by a subclass implementing a particular
299 device class.
301 Args:
302 recipient: Request recipient (device, interface, endpoint, etc.)
303 request: bRequest field of the setup packet.
304 value: wValue field of the setup packet.
305 index: wIndex field of the setup packet.
306 length: Maximum amount of data the host expects the device to return.
308 Returns:
309 A buffer to return to the USB host with len <= length on success or
310 None to stall the pipe.
312 _ = recipient, request, value, index, length
313 return None
315 def VendorControlRead(self, recipient, request, value, index, length):
316 """Handle vendor-specific control transfers.
318 This function should be overridden by a subclass if implementing a device
319 that responds to vendor-specific requests.
321 Args:
322 recipient: Request recipient (device, interface, endpoint, etc.)
323 request: bRequest field of the setup packet.
324 value: wValue field of the setup packet.
325 index: wIndex field of the setup packet.
326 length: Maximum amount of data the host expects the device to return.
328 Returns:
329 A buffer to return to the USB host with len <= length on success or
330 None to stall the pipe.
332 if (self._ms_vendor_code_v1 is not None and
333 request == self._ms_vendor_code_v1 and
334 (recipient == usb_constants.Recipient.DEVICE or
335 recipient == usb_constants.Recipient.INTERFACE)):
336 return self.GetMicrosoftOSDescriptorV1(recipient, value, index, length)
337 if (self._ms_vendor_code_v2 is not None and
338 request == self._ms_vendor_code_v2 and
339 recipient == usb_constants.Recipient.DEVICE and
340 value == 0x0000 and
341 index == 0x0007):
342 return self.GetMicrosoftOSDescriptorV2(length)
344 return None
346 def StandardControlWrite(self, recipient, request, value, index, data):
347 """Handle standard control transfers.
349 Args:
350 recipient: Request recipient (device, interface, endpoint, etc.)
351 request: bRequest field of the setup packet.
352 value: wValue field of the setup packet.
353 index: wIndex field of the setup packet.
354 data: Data stage of the request.
356 Returns:
357 True on success, None to stall the pipe.
359 _ = data
361 if request == usb_constants.Request.SET_CONFIGURATION:
362 if recipient == usb_constants.Recipient.DEVICE:
363 return self.SetConfiguration(value)
364 elif request == usb_constants.Request.SET_INTERFACE:
365 if recipient == usb_constants.Recipient.INTERFACE:
366 return self.SetInterface(index, value)
368 def ClassControlWrite(self, recipient, request, value, index, data):
369 """Handle class-specific control transfers.
371 This function should be overridden by a subclass implementing a particular
372 device class.
374 Args:
375 recipient: Request recipient (device, interface, endpoint, etc.)
376 request: bRequest field of the setup packet.
377 value: wValue field of the setup packet.
378 index: wIndex field of the setup packet.
379 data: Data stage of the request.
381 Returns:
382 True on success, None to stall the pipe.
384 _ = recipient, request, value, index, data
385 return None
387 def VendorControlWrite(self, recipient, request, value, index, data):
388 """Handle vendor-specific control transfers.
390 This function should be overridden by a subclass if implementing a device
391 that responds to vendor-specific requests.
393 Args:
394 recipient: Request recipient (device, interface, endpoint, etc.)
395 request: bRequest field of the setup packet.
396 value: wValue field of the setup packet.
397 index: wIndex field of the setup packet.
398 data: Data stage of the request.
400 Returns:
401 True on success, None to stall the pipe.
403 _ = recipient, request, value, index, data
404 return None
406 def GetStringDescriptor(self, index, lang, length):
407 """Handle a GET_DESCRIPTOR(String) request from the host.
409 Descriptor index 0 returns the set of languages supported by the device.
410 All other indices return the string descriptors registered with those
411 indices.
413 See Universal Serial Bus Specification Revision 2.0 section 9.6.7.
415 Args:
416 index: Descriptor index.
417 lang: Descriptor language code.
418 length: Maximum amount of data the host expects the device to return.
420 Returns:
421 The string descriptor or None to stall the pipe if the descriptor is not
422 found.
424 if index == 0:
425 length = 2 + len(self._strings) * 2
426 header = struct.pack('<BB', length, usb_constants.DescriptorType.STRING)
427 lang_codes = [struct.pack('<H', lang)
428 for lang in self._strings.iterkeys()]
429 buf = header + ''.join(lang_codes)
430 assert len(buf) == length
431 return buf[:length]
432 if index == 0xEE and lang == 0 and self._ms_vendor_code_v1 is not None:
433 # See https://msdn.microsoft.com/en-us/windows/hardware/gg463179 for the
434 # definition of this special string descriptor.
435 buf = (struct.pack('<BB', 18, usb_constants.DescriptorType.STRING) +
436 'MSFT100'.encode('UTF-16LE') +
437 struct.pack('<BB', self._ms_vendor_code_v1, 0))
438 assert len(buf) == 18
439 return buf[:length]
440 elif lang not in self._strings:
441 return None
442 elif index not in self._strings[lang]:
443 return None
444 else:
445 descriptor = usb_descriptors.StringDescriptor(
446 bString=self._strings[lang][index])
447 return descriptor.Encode()[:length]
449 def GetMicrosoftOSDescriptorV1(self, recipient, value, index, length):
450 """Handle a the Microsoft OS 1.0 Descriptor request from the host.
452 See https://msdn.microsoft.com/en-us/windows/hardware/gg463179 for the
453 format of these descriptors.
455 Args:
456 recipient: Request recipient (device or interface)
457 value: wValue field of the setup packet.
458 index: wIndex field of the setup packet.
459 length: Maximum amount of data the host expects the device to return.
461 Returns:
462 The descriptor or None to stall the pipe if the descriptor is not
463 supported.
465 _ = recipient, value
466 if index == 0x0004:
467 return self.GetMicrosoftCompatIds(length)
469 def GetMicrosoftCompatIds(self, length):
470 interfaces = self.GetConfigurationDescriptor().GetInterfaces()
471 max_interface = max([iface.bInterfaceNumber for iface in interfaces])
473 header = struct.pack('<IHHBxxxxxxx',
474 16 + 24 * (max_interface + 1),
475 0x0100,
476 0x0004,
477 max_interface + 1)
478 if length <= len(header):
479 return header[:length]
481 buf = header
482 for interface in xrange(max_interface + 1):
483 compat_id, sub_compat_id = self._ms_compat_ids.get(interface, ('', ''))
484 buf += struct.pack('<BB8s8sxxxxxx',
485 interface, 0x01, compat_id, sub_compat_id)
486 return buf[:length]
488 def GetMicrosoftOSDescriptorV2(self, length):
489 return self._ms_os20_descriptor_set.Encode()[:length]
491 def GetBosDescriptor(self, length):
492 """Handle a GET_DESCRIPTOR(BOS) request from the host.
494 Device capability descriptors can be added to the Binary Device Object Store
495 returned by this method by calling AddDeviceCapabilityDescriptor.
497 See Universal Serial Bus 3.1 Specification, Revision 1.0 section 9.6.2.
499 Args:
500 length: Maximum amount of data the host expects the device to return.
502 Returns:
503 The device's binary object store descriptor or None to stall the pipe if
504 no device capability descriptors have been configured.
506 if self._bos_descriptor is None:
507 return None
509 return self._bos_descriptor.Encode()[:length]
511 def SetConfiguration(self, index):
512 """Handle a SET_CONFIGURATION request from the host.
514 See Universal Serial Bus Specification Revision 2.0 section 9.4.7.
516 Args:
517 index: Configuration index selected.
519 Returns:
520 True on success, None on error to stall the pipe.
522 print 'SetConfiguration({})'.format(index)
524 for endpoint_addrs in self._active_endpoints.values():
525 for endpoint_addr in endpoint_addrs:
526 self._chip.StopEndpoint(endpoint_addr)
527 endpoint_addrs.clear()
528 self._endpoint_interface_map.clear();
530 if index == 0:
531 # SET_CONFIGRATION(0) puts the device into the Address state which
532 # Windows does before suspending the port.
533 return True
534 elif index != 1:
535 return None
537 config_desc = self.GetConfigurationDescriptor()
538 for interface_desc in config_desc.GetInterfaces():
539 if interface_desc.bAlternateSetting != 0:
540 continue
541 endpoint_addrs = self._active_endpoints.setdefault(
542 interface_desc.bInterfaceNumber, set())
543 for endpoint_desc in interface_desc.GetEndpoints():
544 self._chip.StartEndpoint(endpoint_desc)
545 endpoint_addrs.add(endpoint_desc.bEndpointAddress)
546 self._endpoint_interface_map[endpoint_desc.bEndpointAddress] = \
547 interface_desc.bInterfaceNumber
548 return True
550 def SetInterface(self, interface, alt_setting):
551 """Handle a SET_INTERFACE request from the host.
553 See Universal Serial Bus Specification Revision 2.0 section 9.4.10.
555 Args:
556 interface: Interface number to configure.
557 alt_setting: Alternate setting to select.
559 Returns:
560 True on success, None on error to stall the pipe.
562 print 'SetInterface({}, {})'.format(interface, alt_setting)
564 config_desc = self.GetConfigurationDescriptor()
565 interface_desc = None
566 for interface_option in config_desc.GetInterfaces():
567 if (interface_option.bInterfaceNumber == interface and
568 interface_option.bAlternateSetting == alt_setting):
569 interface_desc = interface_option
570 if interface_desc is None:
571 return None
573 endpoint_addrs = self._active_endpoints.setdefault(interface, set())
574 for endpoint_addr in endpoint_addrs:
575 self._chip.StopEndpoint(endpoint_addr)
576 del self._endpoint_interface_map[endpoint_addr]
577 for endpoint_desc in interface_desc.GetEndpoints():
578 self._chip.StartEndpoint(endpoint_desc)
579 endpoint_addrs.add(endpoint_desc.bEndpointAddress)
580 self._endpoint_interface_map[endpoint_desc.bEndpointAddress] = \
581 interface_desc.bInterfaceNumber
582 return True
584 def GetInterfaceForEndpoint(self, endpoint_addr):
585 return self._endpoint_interface_map.get(endpoint_addr)