Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Side by Side Diff: tools/usb_gadget/gadget.py

Issue 407353002: [usb_gadget p02] Basic USB device implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed copyright text and added specification references. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/usb_gadget/gadget_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 """Generic USB gadget functionality.
6 """
7
8 import struct
9
10 import usb_constants
11
12
13 class Gadget(object):
14 """Basic functionality for a USB device.
15
16 Implements standard control requests assuming that a subclass will handle
17 class- or vendor-specific requests.
18 """
19
20 def __init__(self, device_desc, fs_config_desc, hs_config_desc):
21 """Create a USB gadget device.
22
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 = {}
37
38 def GetDeviceDescriptor(self):
39 return self._device_desc
40
41 def GetFullSpeedConfigurationDescriptor(self):
42 return self._fs_config_desc
43
44 def GetHighSpeedConfigurationDescriptor(self):
45 return self._hs_config_desc
46
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.')
54
55 def GetSpeed(self):
56 return self._speed
57
58 def AddStringDescriptor(self, index, value, lang=0x0409):
59 """Add a string descriptor to this device.
60
61 Args:
62 index: String descriptor index (matches 'i' fields in descriptors).
63 value: The string.
64 lang: Language code (default: English).
65
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.')
73
74 lang_strings = self._strings.setdefault(lang, {})
75 lang_strings[index] = value
76
77 def Connected(self, chip, speed):
78 """The device has been connected to a USB host.
79
80 Args:
81 chip: USB controller.
82 speed: Connection speed.
83 """
84 self._speed = speed
85 self._chip = chip
86
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()
92
93 def IsConnected(self):
94 return self._chip is not None
95
96 def ControlRead(self, request_type, request, value, index, length):
97 """Handle a read on the control pipe (endpoint zero).
98
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.
105
106 Returns:
107 A buffer to return to the USB host with len <= length on success or
108 None to stall the pipe.
109 """
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)
122
123 def ControlWrite(self, request_type, request, value, index, data):
124 """Handle a write to the control pipe (endpoint zero).
125
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.
132
133 Returns:
134 True on success, None to stall the pipe.
135 """
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)
148
149 def SendPacket(self, endpoint, data):
150 """Send a data packet on the given endpoint.
151
152 Args:
153 endpoint: Endpoint address.
154 data: Data buffer.
155
156 Raises:
157 ValueError: If the endpoint address is not valid.
158 RuntimeError: If the device is not connected.
159 """
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)
165
166 def ReceivePacket(self, endpoint, data):
167 """Handle an incoming data packet on one of the device's active endpoints.
168
169 This method should be overridden by a subclass implementing endpoint-based
170 data transfers.
171
172 Args:
173 endpoint: Endpoint address.
174 data: Data buffer.
175 """
176 pass
177
178 def HaltEndpoint(self, endpoint):
179 """Signals a STALL condition to the host on the given endpoint.
180
181 Args:
182 endpoint: Endpoint address.
183 """
184 self._chip.HaltEndpoint(endpoint)
185
186 def StandardControlRead(self, recipient, request, value, index, length):
187 """Handle standard control transfers.
188
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.
195
196 Returns:
197 A buffer to return to the USB host with len <= length on success or
198 None to stall the pipe.
199 """
200 if request == usb_constants.Request.GET_DESCRIPTOR:
201 desc_type = value >> 8
202 desc_index = value & 0xff
203 desc_lang = index
204
205 print 'GetDescriptor(recipient={}, type={}, index={}, lang={})'.format(
206 recipient, desc_type, desc_index, desc_lang)
207
208 return self.GetDescriptor(recipient, desc_type, desc_index, desc_lang,
209 length)
210
211 def GetDescriptor(self, recipient, typ, index, lang, length):
212 """Handle a standard GET_DESCRIPTOR request.
213
214 See Universal Serial Bus Specification Revision 2.0 section 9.4.3.
215
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.
222
223 Returns:
224 The value of the descriptor or None to stall the pipe.
225 """
226 if recipient == usb_constants.Recipient.DEVICE:
227 if typ == usb_constants.DescriptorType.STRING:
228 return self.GetStringDescriptor(index, lang, length)
229
230 def ClassControlRead(self, recipient, request, value, index, length):
231 """Handle class-specific control transfers.
232
233 This function should be overridden by a subclass implementing a particular
234 device class.
235
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.
242
243 Returns:
244 A buffer to return to the USB host with len <= length on success or
245 None to stall the pipe.
246 """
247 _ = recipient, request, value, index, length
248 return None
249
250 def VendorControlRead(self, recipient, request, value, index, length):
251 """Handle vendor-specific control transfers.
252
253 This function should be overridden by a subclass if implementing a device
254 that responds to vendor-specific requests.
255
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.
262
263 Returns:
264 A buffer to return to the USB host with len <= length on success or
265 None to stall the pipe.
266 """
267 _ = recipient, request, value, index, length
268 return None
269
270 def StandardControlWrite(self, recipient, request, value, index, data):
271 """Handle standard control transfers.
272
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.
279
280 Returns:
281 True on success, None to stall the pipe.
282 """
283 _ = data
284
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)
291
292 def ClassControlWrite(self, recipient, request, value, index, data):
293 """Handle class-specific control transfers.
294
295 This function should be overridden by a subclass implementing a particular
296 device class.
297
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.
304
305 Returns:
306 True on success, None to stall the pipe.
307 """
308 _ = recipient, request, value, index, data
309 return None
310
311 def VendorControlWrite(self, recipient, request, value, index, data):
312 """Handle vendor-specific control transfers.
313
314 This function should be overridden by a subclass if implementing a device
315 that responds to vendor-specific requests.
316
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.
323
324 Returns:
325 True on success, None to stall the pipe.
326 """
327 _ = recipient, request, value, index, data
328 return None
329
330 def GetStringDescriptor(self, index, lang, length):
331 """Handle a GET_DESCRIPTOR(String) request from the host.
332
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.
336
337 See Universal Serial Bus Specification Revision 2.0 section 9.6.7.
338
339 Args:
340 index: Descriptor index.
341 lang: Descriptor language code.
342 length: Maximum amount of data the host expects the device to return.
343
344 Returns:
345 The string descriptor or None to stall the pipe if the descriptor is not
346 found.
347 """
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]
366
367 def SetConfiguration(self, index):
368 """Handle a SET_CONFIGURATION request from the host.
369
370 See Universal Serial Bus Specification Revision 2.0 section 9.4.7.
371
372 Args:
373 index: Configuration index selected.
374
375 Returns:
376 True on success, None on error to stall the pipe.
377 """
378 print 'SetConfiguration({})'.format(index)
379
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()
384
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
391
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
402
403 def SetInterface(self, interface, alt_setting):
404 """Handle a SET_INTERFACE request from the host.
405
406 See Universal Serial Bus Specification Revision 2.0 section 9.4.10.
407
408 Args:
409 interface: Interface number to configure.
410 alt_setting: Alternate setting to select.
411
412 Returns:
413 True on success, None on error to stall the pipe.
414 """
415 print 'SetInterface({}, {})'.format(interface, alt_setting)
416
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
425
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
OLDNEW
« no previous file with comments | « no previous file | tools/usb_gadget/gadget_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698