Use a less compiler-specific way for preventing inlining / tail-call optimization.
[chromium-blink-merge.git] / tools / usb_gadget / gadget.py
blobfb48a2cfb3a122f8fede2b203c6755ec989913ef
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 usb_constants
13 class Gadget(object):
14 """Basic functionality for a USB device.
16 Implements standard control requests assuming that a subclass will handle
17 class- or vendor-specific requests.
18 """
20 def __init__(self, device_desc, fs_config_desc, hs_config_desc):
21 """Create a USB gadget device.
23 Args:
24 device_desc: USB device descriptor.
25 fs_config_desc: Low/full-speed device descriptor.
26 hs_config_desc: High-speed device descriptor.
27 """
28 self._speed = usb_constants.Speed.UNKNOWN
29 self._chip = None
30 self._device_desc = device_desc
31 self._fs_config_desc = fs_config_desc
32 self._hs_config_desc = hs_config_desc
33 # dict mapping language codes to a dict mapping indexes to strings
34 self._strings = {}
35 # dict mapping interface numbers to a set of endpoint addresses
36 self._active_endpoints = {}
38 def GetDeviceDescriptor(self):
39 return self._device_desc
41 def GetFullSpeedConfigurationDescriptor(self):
42 return self._fs_config_desc
44 def GetHighSpeedConfigurationDescriptor(self):
45 return self._hs_config_desc
47 def GetConfigurationDescriptor(self):
48 if self._speed == usb_constants.Speed.FULL:
49 return self._fs_config_desc
50 elif self._speed == usb_constants.Speed.HIGH:
51 return self._hs_config_desc
52 else:
53 raise RuntimeError('Device is not connected.')
55 def GetSpeed(self):
56 return self._speed
58 def AddStringDescriptor(self, index, value, lang=0x0409):
59 """Add a string descriptor to this device.
61 Args:
62 index: String descriptor index (matches 'i' fields in descriptors).
63 value: The string.
64 lang: Language code (default: English).
66 Raises:
67 ValueError: The index or language code is invalid.
68 """
69 if index < 1 or index > 255:
70 raise ValueError('String descriptor index out of range.')
71 if lang < 0 or lang > 0xffff:
72 raise ValueError('String descriptor language code out of range.')
74 lang_strings = self._strings.setdefault(lang, {})
75 lang_strings[index] = value
77 def Connected(self, chip, speed):
78 """The device has been connected to a USB host.
80 Args:
81 chip: USB controller.
82 speed: Connection speed.
83 """
84 self._speed = speed
85 self._chip = chip
87 def Disconnected(self):
88 """The device has been disconnected from the USB host."""
89 self._speed = usb_constants.Speed.UNKNOWN
90 self._chip = None
91 self._active_endpoints.clear()
93 def IsConnected(self):
94 return self._chip is not None
96 def ControlRead(self, request_type, request, value, index, length):
97 """Handle a read on the control pipe (endpoint zero).
99 Args:
100 request_type: bmRequestType field of the setup packet.
101 request: bRequest field of the setup packet.
102 value: wValue field of the setup packet.
103 index: wIndex field of the setup packet.
104 length: Maximum amount of data the host expects the device to return.
106 Returns:
107 A buffer to return to the USB host with len <= length on success or
108 None to stall the pipe.
110 assert request_type & usb_constants.Dir.IN
111 typ = request_type & usb_constants.Type.MASK
112 recipient = request_type & usb_constants.Recipient.MASK
113 if typ == usb_constants.Type.STANDARD:
114 return self.StandardControlRead(
115 recipient, request, value, index, length)
116 elif typ == usb_constants.Type.CLASS:
117 return self.ClassControlRead(
118 recipient, request, value, index, length)
119 elif typ == usb_constants.Type.VENDOR:
120 return self.VendorControlRead(
121 recipient, request, value, index, length)
123 def ControlWrite(self, request_type, request, value, index, data):
124 """Handle a write to the control pipe (endpoint zero).
126 Args:
127 request_type: bmRequestType field of the setup packet.
128 request: bRequest field of the setup packet.
129 value: wValue field of the setup packet.
130 index: wIndex field of the setup packet.
131 data: Data stage of the request.
133 Returns:
134 True on success, None to stall the pipe.
136 assert not request_type & usb_constants.Dir.IN
137 typ = request_type & usb_constants.Type.MASK
138 recipient = request_type & usb_constants.Recipient.MASK
139 if typ == usb_constants.Type.STANDARD:
140 return self.StandardControlWrite(
141 recipient, request, value, index, data)
142 elif typ == usb_constants.Type.CLASS:
143 return self.ClassControlWrite(
144 recipient, request, value, index, data)
145 elif typ == usb_constants.Type.VENDOR:
146 return self.VendorControlWrite(
147 recipient, request, value, index, data)
149 def SendPacket(self, endpoint, data):
150 """Send a data packet on the given endpoint.
152 Args:
153 endpoint: Endpoint address.
154 data: Data buffer.
156 Raises:
157 ValueError: If the endpoint address is not valid.
158 RuntimeError: If the device is not connected.
160 if self._chip is None:
161 raise RuntimeError('Device is not connected.')
162 if not endpoint & usb_constants.Dir.IN:
163 raise ValueError('Cannot write to non-input endpoint.')
164 self._chip.SendPacket(endpoint, data)
166 def ReceivePacket(self, endpoint, data):
167 """Handle an incoming data packet on one of the device's active endpoints.
169 This method should be overridden by a subclass implementing endpoint-based
170 data transfers.
172 Args:
173 endpoint: Endpoint address.
174 data: Data buffer.
176 pass
178 def HaltEndpoint(self, endpoint):
179 """Signals a STALL condition to the host on the given endpoint.
181 Args:
182 endpoint: Endpoint address.
184 self._chip.HaltEndpoint(endpoint)
186 def StandardControlRead(self, recipient, request, value, index, length):
187 """Handle standard control transfers.
189 Args:
190 recipient: Request recipient (device, interface, endpoint, etc.)
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 length: Maximum amount of data the host expects the device to return.
196 Returns:
197 A buffer to return to the USB host with len <= length on success or
198 None to stall the pipe.
200 if request == usb_constants.Request.GET_DESCRIPTOR:
201 desc_type = value >> 8
202 desc_index = value & 0xff
203 desc_lang = index
205 print 'GetDescriptor(recipient={}, type={}, index={}, lang={})'.format(
206 recipient, desc_type, desc_index, desc_lang)
208 return self.GetDescriptor(recipient, desc_type, desc_index, desc_lang,
209 length)
211 def GetDescriptor(self, recipient, typ, index, lang, length):
212 """Handle a standard GET_DESCRIPTOR request.
214 See Universal Serial Bus Specification Revision 2.0 section 9.4.3.
216 Args:
217 recipient: Request recipient (device, interface, endpoint, etc.)
218 typ: Descriptor type.
219 index: Descriptor index.
220 lang: Descriptor language code.
221 length: Maximum amount of data the host expects the device to return.
223 Returns:
224 The value of the descriptor or None to stall the pipe.
226 if recipient == usb_constants.Recipient.DEVICE:
227 if typ == usb_constants.DescriptorType.STRING:
228 return self.GetStringDescriptor(index, lang, length)
230 def ClassControlRead(self, recipient, request, value, index, length):
231 """Handle class-specific control transfers.
233 This function should be overridden by a subclass implementing a particular
234 device class.
236 Args:
237 recipient: Request recipient (device, interface, endpoint, etc.)
238 request: bRequest field of the setup packet.
239 value: wValue field of the setup packet.
240 index: wIndex field of the setup packet.
241 length: Maximum amount of data the host expects the device to return.
243 Returns:
244 A buffer to return to the USB host with len <= length on success or
245 None to stall the pipe.
247 _ = recipient, request, value, index, length
248 return None
250 def VendorControlRead(self, recipient, request, value, index, length):
251 """Handle vendor-specific control transfers.
253 This function should be overridden by a subclass if implementing a device
254 that responds to vendor-specific requests.
256 Args:
257 recipient: Request recipient (device, interface, endpoint, etc.)
258 request: bRequest field of the setup packet.
259 value: wValue field of the setup packet.
260 index: wIndex field of the setup packet.
261 length: Maximum amount of data the host expects the device to return.
263 Returns:
264 A buffer to return to the USB host with len <= length on success or
265 None to stall the pipe.
267 _ = recipient, request, value, index, length
268 return None
270 def StandardControlWrite(self, recipient, request, value, index, data):
271 """Handle standard control transfers.
273 Args:
274 recipient: Request recipient (device, interface, endpoint, etc.)
275 request: bRequest field of the setup packet.
276 value: wValue field of the setup packet.
277 index: wIndex field of the setup packet.
278 data: Data stage of the request.
280 Returns:
281 True on success, None to stall the pipe.
283 _ = data
285 if request == usb_constants.Request.SET_CONFIGURATION:
286 if recipient == usb_constants.Recipient.DEVICE:
287 return self.SetConfiguration(value)
288 elif request == usb_constants.Request.SET_INTERFACE:
289 if recipient == usb_constants.Recipient.INTERFACE:
290 return self.SetInterface(index, value)
292 def ClassControlWrite(self, recipient, request, value, index, data):
293 """Handle class-specific control transfers.
295 This function should be overridden by a subclass implementing a particular
296 device class.
298 Args:
299 recipient: Request recipient (device, interface, endpoint, etc.)
300 request: bRequest field of the setup packet.
301 value: wValue field of the setup packet.
302 index: wIndex field of the setup packet.
303 data: Data stage of the request.
305 Returns:
306 True on success, None to stall the pipe.
308 _ = recipient, request, value, index, data
309 return None
311 def VendorControlWrite(self, recipient, request, value, index, data):
312 """Handle vendor-specific control transfers.
314 This function should be overridden by a subclass if implementing a device
315 that responds to vendor-specific requests.
317 Args:
318 recipient: Request recipient (device, interface, endpoint, etc.)
319 request: bRequest field of the setup packet.
320 value: wValue field of the setup packet.
321 index: wIndex field of the setup packet.
322 data: Data stage of the request.
324 Returns:
325 True on success, None to stall the pipe.
327 _ = recipient, request, value, index, data
328 return None
330 def GetStringDescriptor(self, index, lang, length):
331 """Handle a GET_DESCRIPTOR(String) request from the host.
333 Descriptor index 0 returns the set of languages supported by the device.
334 All other indices return the string descriptors registered with those
335 indices.
337 See Universal Serial Bus Specification Revision 2.0 section 9.6.7.
339 Args:
340 index: Descriptor index.
341 lang: Descriptor language code.
342 length: Maximum amount of data the host expects the device to return.
344 Returns:
345 The string descriptor or None to stall the pipe if the descriptor is not
346 found.
348 if index == 0:
349 length = 2 + len(self._strings) * 2
350 header = struct.pack('<BB', length, usb_constants.DescriptorType.STRING)
351 lang_codes = [struct.pack('<H', lang)
352 for lang in self._strings.iterkeys()]
353 buf = header + ''.join(lang_codes)
354 assert len(buf) == length
355 return buf[:length]
356 elif lang not in self._strings:
357 return None
358 elif index not in self._strings[lang]:
359 return None
360 else:
361 string = self._strings[lang][index].encode('UTF-16LE')
362 header = struct.pack(
363 '<BB', 2 + len(string), usb_constants.DescriptorType.STRING)
364 buf = header + string
365 return buf[:length]
367 def SetConfiguration(self, index):
368 """Handle a SET_CONFIGURATION request from the host.
370 See Universal Serial Bus Specification Revision 2.0 section 9.4.7.
372 Args:
373 index: Configuration index selected.
375 Returns:
376 True on success, None on error to stall the pipe.
378 print 'SetConfiguration({})'.format(index)
380 for endpoint_addrs in self._active_endpoints.values():
381 for endpoint_addr in endpoint_addrs:
382 self._chip.StopEndpoint(endpoint_addr)
383 endpoint_addrs.clear()
385 if index == 0:
386 # SET_CONFIGRATION(0) puts the device into the Address state which
387 # Windows does before suspending the port.
388 return True
389 elif index != 1:
390 return None
392 config_desc = self.GetConfigurationDescriptor()
393 for interface_desc in config_desc.GetInterfaces():
394 if interface_desc.bAlternateSetting != 0:
395 continue
396 endpoint_addrs = self._active_endpoints.setdefault(
397 interface_desc.bInterfaceNumber, set())
398 for endpoint_desc in interface_desc.GetEndpoints():
399 self._chip.StartEndpoint(endpoint_desc)
400 endpoint_addrs.add(endpoint_desc.bEndpointAddress)
401 return True
403 def SetInterface(self, interface, alt_setting):
404 """Handle a SET_INTERFACE request from the host.
406 See Universal Serial Bus Specification Revision 2.0 section 9.4.10.
408 Args:
409 interface: Interface number to configure.
410 alt_setting: Alternate setting to select.
412 Returns:
413 True on success, None on error to stall the pipe.
415 print 'SetInterface({}, {})'.format(interface, alt_setting)
417 config_desc = self.GetConfigurationDescriptor()
418 interface_desc = None
419 for interface_option in config_desc.GetInterfaces():
420 if (interface_option.bInterfaceNumber == interface and
421 interface_option.bAlternateSetting == alt_setting):
422 interface_desc = interface_option
423 if interface_desc is None:
424 return None
426 endpoint_addrs = self._active_endpoints.setdefault(interface, set())
427 for endpoint_addr in endpoint_addrs:
428 self._chip.StopEndpoint(endpoint_addr)
429 for endpoint_desc in interface_desc.GetEndpoints():
430 self._chip.StartEndpoint(endpoint_desc)
431 endpoint_addrs.add(endpoint_desc.bEndpointAddress)
432 return True