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.
14 """Basic functionality for a USB device.
16 Implements standard control requests assuming that a subclass will handle
17 class- or vendor-specific requests.
20 def __init__(self
, device_desc
, fs_config_desc
, hs_config_desc
):
21 """Create a USB gadget device.
24 device_desc: USB device descriptor.
25 fs_config_desc: Low/full-speed device descriptor.
26 hs_config_desc: High-speed device descriptor.
28 self
._speed
= usb_constants
.Speed
.UNKNOWN
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
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
53 raise RuntimeError('Device is not connected.')
58 def AddStringDescriptor(self
, index
, value
, lang
=0x0409):
59 """Add a string descriptor to this device.
62 index: String descriptor index (matches 'i' fields in descriptors).
64 lang: Language code (default: English).
67 ValueError: The index or language code is invalid.
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.
82 speed: Connection speed.
87 def Disconnected(self
):
88 """The device has been disconnected from the USB host."""
89 self
._speed
= usb_constants
.Speed
.UNKNOWN
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).
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.
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).
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.
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.
153 endpoint: Endpoint address.
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
173 endpoint: Endpoint address.
178 def HaltEndpoint(self
, endpoint
):
179 """Signals a STALL condition to the host on the given endpoint.
182 endpoint: Endpoint address.
184 self
._chip
.HaltEndpoint(endpoint
)
186 def StandardControlRead(self
, recipient
, request
, value
, index
, length
):
187 """Handle standard control transfers.
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.
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
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
,
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.
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.
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
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.
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
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.
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.
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
270 def StandardControlWrite(self
, recipient
, request
, value
, index
, data
):
271 """Handle standard control transfers.
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.
281 True on success, None to stall the pipe.
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
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.
306 True on success, None to stall the pipe.
308 _
= recipient
, request
, value
, index
, data
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.
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.
325 True on success, None to stall the pipe.
327 _
= recipient
, request
, value
, index
, data
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
337 See Universal Serial Bus Specification Revision 2.0 section 9.6.7.
340 index: Descriptor index.
341 lang: Descriptor language code.
342 length: Maximum amount of data the host expects the device to return.
345 The string descriptor or None to stall the pipe if the descriptor is not
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
356 elif lang
not in self
._strings
:
358 elif index
not in self
._strings
[lang
]:
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
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.
373 index: Configuration index selected.
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()
386 # SET_CONFIGRATION(0) puts the device into the Address state which
387 # Windows does before suspending the port.
392 config_desc
= self
.GetConfigurationDescriptor()
393 for interface_desc
in config_desc
.GetInterfaces():
394 if interface_desc
.bAlternateSetting
!= 0:
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
)
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.
409 interface: Interface number to configure.
410 alt_setting: Alternate setting to select.
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:
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
)