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 433