OLD | NEW |
(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 |
OLD | NEW |