| 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 #include "components/usb_service/usb_device_handle_impl.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/location.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "base/stl_util.h" | |
| 14 #include "base/strings/string16.h" | |
| 15 #include "base/synchronization/lock.h" | |
| 16 #include "base/thread_task_runner_handle.h" | |
| 17 #include "components/usb_service/usb_context.h" | |
| 18 #include "components/usb_service/usb_device_impl.h" | |
| 19 #include "components/usb_service/usb_error.h" | |
| 20 #include "components/usb_service/usb_interface.h" | |
| 21 #include "components/usb_service/usb_service.h" | |
| 22 #include "third_party/libusb/src/libusb/libusb.h" | |
| 23 | |
| 24 namespace usb_service { | |
| 25 | |
| 26 typedef libusb_device* PlatformUsbDevice; | |
| 27 | |
| 28 void HandleTransferCompletion(usb_service::PlatformUsbTransferHandle transfer); | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 static uint8 ConvertTransferDirection(const UsbEndpointDirection direction) { | |
| 33 switch (direction) { | |
| 34 case USB_DIRECTION_INBOUND: | |
| 35 return LIBUSB_ENDPOINT_IN; | |
| 36 case USB_DIRECTION_OUTBOUND: | |
| 37 return LIBUSB_ENDPOINT_OUT; | |
| 38 default: | |
| 39 NOTREACHED(); | |
| 40 return LIBUSB_ENDPOINT_IN; | |
| 41 } | |
| 42 } | |
| 43 | |
| 44 static uint8 CreateRequestType( | |
| 45 const UsbEndpointDirection direction, | |
| 46 const UsbDeviceHandle::TransferRequestType request_type, | |
| 47 const UsbDeviceHandle::TransferRecipient recipient) { | |
| 48 uint8 result = ConvertTransferDirection(direction); | |
| 49 | |
| 50 switch (request_type) { | |
| 51 case UsbDeviceHandle::STANDARD: | |
| 52 result |= LIBUSB_REQUEST_TYPE_STANDARD; | |
| 53 break; | |
| 54 case UsbDeviceHandle::CLASS: | |
| 55 result |= LIBUSB_REQUEST_TYPE_CLASS; | |
| 56 break; | |
| 57 case UsbDeviceHandle::VENDOR: | |
| 58 result |= LIBUSB_REQUEST_TYPE_VENDOR; | |
| 59 break; | |
| 60 case UsbDeviceHandle::RESERVED: | |
| 61 result |= LIBUSB_REQUEST_TYPE_RESERVED; | |
| 62 break; | |
| 63 } | |
| 64 | |
| 65 switch (recipient) { | |
| 66 case UsbDeviceHandle::DEVICE: | |
| 67 result |= LIBUSB_RECIPIENT_DEVICE; | |
| 68 break; | |
| 69 case UsbDeviceHandle::INTERFACE: | |
| 70 result |= LIBUSB_RECIPIENT_INTERFACE; | |
| 71 break; | |
| 72 case UsbDeviceHandle::ENDPOINT: | |
| 73 result |= LIBUSB_RECIPIENT_ENDPOINT; | |
| 74 break; | |
| 75 case UsbDeviceHandle::OTHER: | |
| 76 result |= LIBUSB_RECIPIENT_OTHER; | |
| 77 break; | |
| 78 } | |
| 79 | |
| 80 return result; | |
| 81 } | |
| 82 | |
| 83 static UsbTransferStatus ConvertTransferStatus( | |
| 84 const libusb_transfer_status status) { | |
| 85 switch (status) { | |
| 86 case LIBUSB_TRANSFER_COMPLETED: | |
| 87 return USB_TRANSFER_COMPLETED; | |
| 88 case LIBUSB_TRANSFER_ERROR: | |
| 89 return USB_TRANSFER_ERROR; | |
| 90 case LIBUSB_TRANSFER_TIMED_OUT: | |
| 91 return USB_TRANSFER_TIMEOUT; | |
| 92 case LIBUSB_TRANSFER_STALL: | |
| 93 return USB_TRANSFER_STALLED; | |
| 94 case LIBUSB_TRANSFER_NO_DEVICE: | |
| 95 return USB_TRANSFER_DISCONNECT; | |
| 96 case LIBUSB_TRANSFER_OVERFLOW: | |
| 97 return USB_TRANSFER_OVERFLOW; | |
| 98 case LIBUSB_TRANSFER_CANCELLED: | |
| 99 return USB_TRANSFER_CANCELLED; | |
| 100 default: | |
| 101 NOTREACHED(); | |
| 102 return USB_TRANSFER_ERROR; | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 } // namespace | |
| 107 | |
| 108 class UsbDeviceHandleImpl::InterfaceClaimer | |
| 109 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> { | |
| 110 public: | |
| 111 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle, | |
| 112 const int interface_number); | |
| 113 | |
| 114 bool Claim() const; | |
| 115 | |
| 116 int alternate_setting() const { return alternate_setting_; } | |
| 117 void set_alternate_setting(const int alternate_setting) { | |
| 118 alternate_setting_ = alternate_setting; | |
| 119 } | |
| 120 | |
| 121 private: | |
| 122 friend class UsbDevice; | |
| 123 friend class base::RefCountedThreadSafe<InterfaceClaimer>; | |
| 124 ~InterfaceClaimer(); | |
| 125 | |
| 126 const scoped_refptr<UsbDeviceHandleImpl> handle_; | |
| 127 const int interface_number_; | |
| 128 int alternate_setting_; | |
| 129 | |
| 130 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer); | |
| 131 }; | |
| 132 | |
| 133 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer( | |
| 134 const scoped_refptr<UsbDeviceHandleImpl> handle, | |
| 135 const int interface_number) | |
| 136 : handle_(handle), | |
| 137 interface_number_(interface_number), | |
| 138 alternate_setting_(0) { | |
| 139 } | |
| 140 | |
| 141 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() { | |
| 142 libusb_release_interface(handle_->handle(), interface_number_); | |
| 143 } | |
| 144 | |
| 145 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const { | |
| 146 const int rv = libusb_claim_interface(handle_->handle(), interface_number_); | |
| 147 if (rv != LIBUSB_SUCCESS) { | |
| 148 VLOG(1) << "Failed to claim interface: " << ConvertErrorToString(rv); | |
| 149 } | |
| 150 return rv == LIBUSB_SUCCESS; | |
| 151 } | |
| 152 | |
| 153 struct UsbDeviceHandleImpl::Transfer { | |
| 154 Transfer(); | |
| 155 ~Transfer(); | |
| 156 | |
| 157 void Complete(UsbTransferStatus status, size_t bytes_transferred); | |
| 158 | |
| 159 UsbTransferType transfer_type; | |
| 160 scoped_refptr<net::IOBuffer> buffer; | |
| 161 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface; | |
| 162 scoped_refptr<base::SingleThreadTaskRunner> task_runner; | |
| 163 size_t length; | |
| 164 UsbTransferCallback callback; | |
| 165 }; | |
| 166 | |
| 167 UsbDeviceHandleImpl::Transfer::Transfer() | |
| 168 : transfer_type(USB_TRANSFER_CONTROL), length(0) { | |
| 169 } | |
| 170 | |
| 171 UsbDeviceHandleImpl::Transfer::~Transfer() { | |
| 172 } | |
| 173 | |
| 174 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status, | |
| 175 size_t bytes_transferred) { | |
| 176 if (task_runner->RunsTasksOnCurrentThread()) { | |
| 177 callback.Run(status, buffer, bytes_transferred); | |
| 178 } else { | |
| 179 task_runner->PostTask( | |
| 180 FROM_HERE, base::Bind(callback, status, buffer, bytes_transferred)); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 UsbDeviceHandleImpl::UsbDeviceHandleImpl( | |
| 185 scoped_refptr<UsbContext> context, | |
| 186 UsbDeviceImpl* device, | |
| 187 PlatformUsbDeviceHandle handle, | |
| 188 scoped_refptr<UsbConfigDescriptor> interfaces) | |
| 189 : device_(device), | |
| 190 handle_(handle), | |
| 191 interfaces_(interfaces), | |
| 192 context_(context), | |
| 193 task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
| 194 DCHECK(handle) << "Cannot create device with NULL handle."; | |
| 195 DCHECK(interfaces_.get()) << "Unable to list interfaces"; | |
| 196 } | |
| 197 | |
| 198 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() { | |
| 199 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 200 | |
| 201 libusb_close(handle_); | |
| 202 handle_ = NULL; | |
| 203 } | |
| 204 | |
| 205 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const { | |
| 206 return static_cast<UsbDevice*>(device_); | |
| 207 } | |
| 208 | |
| 209 void UsbDeviceHandleImpl::Close() { | |
| 210 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 211 if (device_) | |
| 212 device_->Close(this); | |
| 213 } | |
| 214 | |
| 215 /* static */ | |
| 216 void LIBUSB_CALL UsbDeviceHandleImpl::PlatformTransferCallback( | |
| 217 PlatformUsbTransferHandle transfer) { | |
| 218 UsbDeviceHandleImpl* device_handle = | |
| 219 reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data); | |
| 220 device_handle->task_runner_->PostTask( | |
| 221 FROM_HERE, | |
| 222 base::Bind( | |
| 223 &UsbDeviceHandleImpl::CompleteTransfer, device_handle, transfer)); | |
| 224 } | |
| 225 | |
| 226 void UsbDeviceHandleImpl::CompleteTransfer(PlatformUsbTransferHandle handle) { | |
| 227 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; | |
| 228 | |
| 229 Transfer transfer = transfers_[handle]; | |
| 230 transfers_.erase(handle); | |
| 231 | |
| 232 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; | |
| 233 size_t actual_length = | |
| 234 static_cast<size_t>(std::max(handle->actual_length, 0)); | |
| 235 | |
| 236 DCHECK(transfer.length >= actual_length) | |
| 237 << "data too big for our buffer (libusb failure?)"; | |
| 238 | |
| 239 switch (transfer.transfer_type) { | |
| 240 case USB_TRANSFER_CONTROL: | |
| 241 // If the transfer is a control transfer we do not expose the control | |
| 242 // setup header to the caller. This logic strips off the header if | |
| 243 // present before invoking the callback provided with the transfer. | |
| 244 if (actual_length > 0) { | |
| 245 CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) | |
| 246 << "buffer was not correctly set: too small for the control header"; | |
| 247 | |
| 248 if (transfer.length >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) { | |
| 249 // If the payload is zero bytes long, pad out the allocated buffer | |
| 250 // size to one byte so that an IOBuffer of that size can be allocated. | |
| 251 scoped_refptr<net::IOBuffer> resized_buffer = | |
| 252 new net::IOBuffer(static_cast<int>( | |
| 253 std::max(actual_length, static_cast<size_t>(1)))); | |
| 254 memcpy(resized_buffer->data(), | |
| 255 transfer.buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, | |
| 256 actual_length); | |
| 257 transfer.buffer = resized_buffer; | |
| 258 } | |
| 259 } | |
| 260 break; | |
| 261 | |
| 262 case USB_TRANSFER_ISOCHRONOUS: | |
| 263 // Isochronous replies might carry data in the different isoc packets even | |
| 264 // if the transfer actual_data value is zero. Furthermore, not all of the | |
| 265 // received packets might contain data, so we need to calculate how many | |
| 266 // data bytes we are effectively providing and pack the results. | |
| 267 if (actual_length == 0) { | |
| 268 size_t packet_buffer_start = 0; | |
| 269 for (int i = 0; i < handle->num_iso_packets; ++i) { | |
| 270 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; | |
| 271 if (packet->actual_length > 0) { | |
| 272 // We don't need to copy as long as all packets until now provide | |
| 273 // all the data the packet can hold. | |
| 274 if (actual_length < packet_buffer_start) { | |
| 275 CHECK(packet_buffer_start + packet->actual_length <= | |
| 276 transfer.length); | |
| 277 memmove(transfer.buffer->data() + actual_length, | |
| 278 transfer.buffer->data() + packet_buffer_start, | |
| 279 packet->actual_length); | |
| 280 } | |
| 281 actual_length += packet->actual_length; | |
| 282 } | |
| 283 | |
| 284 packet_buffer_start += packet->length; | |
| 285 } | |
| 286 } | |
| 287 break; | |
| 288 | |
| 289 case USB_TRANSFER_BULK: | |
| 290 case USB_TRANSFER_INTERRUPT: | |
| 291 break; | |
| 292 | |
| 293 default: | |
| 294 NOTREACHED() << "Invalid usb transfer type"; | |
| 295 break; | |
| 296 } | |
| 297 | |
| 298 transfer.Complete(ConvertTransferStatus(handle->status), actual_length); | |
| 299 libusb_free_transfer(handle); | |
| 300 | |
| 301 // Must release interface first before actually delete this. | |
| 302 transfer.claimed_interface = NULL; | |
| 303 } | |
| 304 | |
| 305 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) { | |
| 306 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 307 if (!device_) | |
| 308 return false; | |
| 309 if (ContainsKey(claimed_interfaces_, interface_number)) | |
| 310 return true; | |
| 311 | |
| 312 scoped_refptr<InterfaceClaimer> claimer = | |
| 313 new InterfaceClaimer(this, interface_number); | |
| 314 | |
| 315 if (claimer->Claim()) { | |
| 316 claimed_interfaces_[interface_number] = claimer; | |
| 317 RefreshEndpointMap(); | |
| 318 return true; | |
| 319 } | |
| 320 return false; | |
| 321 } | |
| 322 | |
| 323 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) { | |
| 324 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 325 if (!device_) | |
| 326 return false; | |
| 327 if (!ContainsKey(claimed_interfaces_, interface_number)) | |
| 328 return false; | |
| 329 | |
| 330 // Cancel all the transfers on that interface. | |
| 331 InterfaceClaimer* interface_claimer = | |
| 332 claimed_interfaces_[interface_number].get(); | |
| 333 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); | |
| 334 ++it) { | |
| 335 if (it->second.claimed_interface.get() == interface_claimer) | |
| 336 libusb_cancel_transfer(it->first); | |
| 337 } | |
| 338 claimed_interfaces_.erase(interface_number); | |
| 339 | |
| 340 RefreshEndpointMap(); | |
| 341 return true; | |
| 342 } | |
| 343 | |
| 344 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting( | |
| 345 const int interface_number, | |
| 346 const int alternate_setting) { | |
| 347 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 348 if (!device_) | |
| 349 return false; | |
| 350 if (!ContainsKey(claimed_interfaces_, interface_number)) | |
| 351 return false; | |
| 352 const int rv = libusb_set_interface_alt_setting( | |
| 353 handle_, interface_number, alternate_setting); | |
| 354 if (rv == LIBUSB_SUCCESS) { | |
| 355 claimed_interfaces_[interface_number]->set_alternate_setting( | |
| 356 alternate_setting); | |
| 357 RefreshEndpointMap(); | |
| 358 } else { | |
| 359 VLOG(1) << "Failed to set interface (" << interface_number << ", " | |
| 360 << alternate_setting << "): " << ConvertErrorToString(rv); | |
| 361 } | |
| 362 return rv == LIBUSB_SUCCESS; | |
| 363 } | |
| 364 | |
| 365 bool UsbDeviceHandleImpl::ResetDevice() { | |
| 366 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 367 if (!device_) | |
| 368 return false; | |
| 369 | |
| 370 const int rv = libusb_reset_device(handle_); | |
| 371 if (rv != LIBUSB_SUCCESS) { | |
| 372 VLOG(1) << "Failed to reset device: " << ConvertErrorToString(rv); | |
| 373 } | |
| 374 return rv == LIBUSB_SUCCESS; | |
| 375 } | |
| 376 | |
| 377 bool UsbDeviceHandleImpl::GetSupportedLanguages() { | |
| 378 if (!languages_.empty()) { | |
| 379 return true; | |
| 380 } | |
| 381 | |
| 382 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s). | |
| 383 uint16 languages[128]; | |
| 384 int size = libusb_get_string_descriptor( | |
| 385 handle_, | |
| 386 0, | |
| 387 0, | |
| 388 reinterpret_cast<unsigned char*>(&languages[0]), | |
| 389 sizeof(languages)); | |
| 390 if (size < 0) { | |
| 391 VLOG(1) << "Failed to get list of supported languages: " | |
| 392 << ConvertErrorToString(size); | |
| 393 return false; | |
| 394 } else if (size < 2) { | |
| 395 VLOG(1) << "String descriptor zero has no header."; | |
| 396 return false; | |
| 397 // The first 2 bytes of the descriptor are the total length and type tag. | |
| 398 } else if ((languages[0] & 0xff) != size) { | |
| 399 VLOG(1) << "String descriptor zero size mismatch: " << (languages[0] & 0xff) | |
| 400 << " != " << size; | |
| 401 return false; | |
| 402 } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) { | |
| 403 VLOG(1) << "String descriptor zero is not a string descriptor."; | |
| 404 return false; | |
| 405 } | |
| 406 | |
| 407 languages_.assign(languages[1], languages[(size - 2) / 2]); | |
| 408 return true; | |
| 409 } | |
| 410 | |
| 411 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id, | |
| 412 base::string16* string) { | |
| 413 if (!GetSupportedLanguages()) { | |
| 414 return false; | |
| 415 } | |
| 416 | |
| 417 std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id); | |
| 418 if (it != strings_.end()) { | |
| 419 *string = it->second; | |
| 420 return true; | |
| 421 } | |
| 422 | |
| 423 for (size_t i = 0; i < languages_.size(); ++i) { | |
| 424 // Get the string using language ID. | |
| 425 uint16 language_id = languages_[i]; | |
| 426 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s). | |
| 427 base::char16 text[128]; | |
| 428 int size = | |
| 429 libusb_get_string_descriptor(handle_, | |
| 430 string_id, | |
| 431 language_id, | |
| 432 reinterpret_cast<unsigned char*>(&text[0]), | |
| 433 sizeof(text)); | |
| 434 if (size < 0) { | |
| 435 VLOG(1) << "Failed to get string descriptor " << string_id << " (langid " | |
| 436 << language_id << "): " << ConvertErrorToString(size); | |
| 437 continue; | |
| 438 } else if (size < 2) { | |
| 439 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
| 440 << ") has no header."; | |
| 441 continue; | |
| 442 // The first 2 bytes of the descriptor are the total length and type tag. | |
| 443 } else if ((text[0] & 0xff) != size) { | |
| 444 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
| 445 << ") size mismatch: " << (text[0] & 0xff) << " != " << size; | |
| 446 continue; | |
| 447 } else if ((text[0] >> 8) != LIBUSB_DT_STRING) { | |
| 448 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id | |
| 449 << ") is not a string descriptor."; | |
| 450 continue; | |
| 451 } | |
| 452 | |
| 453 *string = base::string16(text + 1, (size - 2) / 2); | |
| 454 strings_[string_id] = *string; | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 return false; | |
| 459 } | |
| 460 | |
| 461 bool UsbDeviceHandleImpl::GetManufacturer(base::string16* manufacturer) { | |
| 462 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 463 PlatformUsbDevice device = libusb_get_device(handle_); | |
| 464 libusb_device_descriptor desc; | |
| 465 | |
| 466 // This is a non-blocking call as libusb has the descriptor in memory. | |
| 467 const int rv = libusb_get_device_descriptor(device, &desc); | |
| 468 if (rv != LIBUSB_SUCCESS) { | |
| 469 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
| 470 return false; | |
| 471 } | |
| 472 | |
| 473 if (desc.iManufacturer == 0) { | |
| 474 return false; | |
| 475 } | |
| 476 | |
| 477 return GetStringDescriptor(desc.iManufacturer, manufacturer); | |
| 478 } | |
| 479 | |
| 480 bool UsbDeviceHandleImpl::GetProduct(base::string16* product) { | |
| 481 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 482 PlatformUsbDevice device = libusb_get_device(handle_); | |
| 483 libusb_device_descriptor desc; | |
| 484 | |
| 485 // This is a non-blocking call as libusb has the descriptor in memory. | |
| 486 const int rv = libusb_get_device_descriptor(device, &desc); | |
| 487 if (rv != LIBUSB_SUCCESS) { | |
| 488 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
| 489 return false; | |
| 490 } | |
| 491 | |
| 492 if (desc.iProduct == 0) { | |
| 493 return false; | |
| 494 } | |
| 495 | |
| 496 return GetStringDescriptor(desc.iProduct, product); | |
| 497 } | |
| 498 | |
| 499 bool UsbDeviceHandleImpl::GetSerial(base::string16* serial) { | |
| 500 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 501 PlatformUsbDevice device = libusb_get_device(handle_); | |
| 502 libusb_device_descriptor desc; | |
| 503 | |
| 504 // This is a non-blocking call as libusb has the descriptor in memory. | |
| 505 const int rv = libusb_get_device_descriptor(device, &desc); | |
| 506 if (rv != LIBUSB_SUCCESS) { | |
| 507 VLOG(1) << "Failed to read device descriptor: " << ConvertErrorToString(rv); | |
| 508 return false; | |
| 509 } | |
| 510 | |
| 511 if (desc.iSerialNumber == 0) { | |
| 512 return false; | |
| 513 } | |
| 514 | |
| 515 return GetStringDescriptor(desc.iSerialNumber, serial); | |
| 516 } | |
| 517 | |
| 518 void UsbDeviceHandleImpl::ControlTransfer( | |
| 519 const UsbEndpointDirection direction, | |
| 520 const TransferRequestType request_type, | |
| 521 const TransferRecipient recipient, | |
| 522 const uint8 request, | |
| 523 const uint16 value, | |
| 524 const uint16 index, | |
| 525 net::IOBuffer* buffer, | |
| 526 const size_t length, | |
| 527 const unsigned int timeout, | |
| 528 const UsbTransferCallback& callback) { | |
| 529 if (!device_) { | |
| 530 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
| 531 return; | |
| 532 } | |
| 533 | |
| 534 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; | |
| 535 scoped_refptr<net::IOBuffer> resized_buffer( | |
| 536 new net::IOBufferWithSize(static_cast<int>(resized_length))); | |
| 537 if (!resized_buffer.get()) { | |
| 538 callback.Run(USB_TRANSFER_ERROR, buffer, 0); | |
| 539 return; | |
| 540 } | |
| 541 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, | |
| 542 buffer->data(), | |
| 543 static_cast<int>(length)); | |
| 544 | |
| 545 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
| 546 const uint8 converted_type = | |
| 547 CreateRequestType(direction, request_type, recipient); | |
| 548 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), | |
| 549 converted_type, | |
| 550 request, | |
| 551 value, | |
| 552 index, | |
| 553 static_cast<int16>(length)); | |
| 554 libusb_fill_control_transfer(transfer, | |
| 555 handle_, | |
| 556 reinterpret_cast<uint8*>(resized_buffer->data()), | |
| 557 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
| 558 this, | |
| 559 timeout); | |
| 560 | |
| 561 PostOrSubmitTransfer( | |
| 562 transfer, USB_TRANSFER_CONTROL, resized_buffer, resized_length, callback); | |
| 563 } | |
| 564 | |
| 565 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction, | |
| 566 const uint8 endpoint, | |
| 567 net::IOBuffer* buffer, | |
| 568 const size_t length, | |
| 569 const unsigned int timeout, | |
| 570 const UsbTransferCallback& callback) { | |
| 571 if (!device_) { | |
| 572 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
| 573 return; | |
| 574 } | |
| 575 | |
| 576 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
| 577 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
| 578 libusb_fill_bulk_transfer(transfer, | |
| 579 handle_, | |
| 580 new_endpoint, | |
| 581 reinterpret_cast<uint8*>(buffer->data()), | |
| 582 static_cast<int>(length), | |
| 583 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
| 584 this, | |
| 585 timeout); | |
| 586 | |
| 587 PostOrSubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback); | |
| 588 } | |
| 589 | |
| 590 void UsbDeviceHandleImpl::InterruptTransfer( | |
| 591 const UsbEndpointDirection direction, | |
| 592 const uint8 endpoint, | |
| 593 net::IOBuffer* buffer, | |
| 594 const size_t length, | |
| 595 const unsigned int timeout, | |
| 596 const UsbTransferCallback& callback) { | |
| 597 if (!device_) { | |
| 598 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
| 599 return; | |
| 600 } | |
| 601 | |
| 602 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); | |
| 603 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
| 604 libusb_fill_interrupt_transfer(transfer, | |
| 605 handle_, | |
| 606 new_endpoint, | |
| 607 reinterpret_cast<uint8*>(buffer->data()), | |
| 608 static_cast<int>(length), | |
| 609 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
| 610 this, | |
| 611 timeout); | |
| 612 | |
| 613 PostOrSubmitTransfer( | |
| 614 transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback); | |
| 615 } | |
| 616 | |
| 617 void UsbDeviceHandleImpl::IsochronousTransfer( | |
| 618 const UsbEndpointDirection direction, | |
| 619 const uint8 endpoint, | |
| 620 net::IOBuffer* buffer, | |
| 621 const size_t length, | |
| 622 const unsigned int packets, | |
| 623 const unsigned int packet_length, | |
| 624 const unsigned int timeout, | |
| 625 const UsbTransferCallback& callback) { | |
| 626 if (!device_) { | |
| 627 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); | |
| 628 return; | |
| 629 } | |
| 630 | |
| 631 const uint64 total_length = packets * packet_length; | |
| 632 CHECK(packets <= length && total_length <= length) | |
| 633 << "transfer length is too small"; | |
| 634 | |
| 635 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets); | |
| 636 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; | |
| 637 libusb_fill_iso_transfer(transfer, | |
| 638 handle_, | |
| 639 new_endpoint, | |
| 640 reinterpret_cast<uint8*>(buffer->data()), | |
| 641 static_cast<int>(length), | |
| 642 packets, | |
| 643 &UsbDeviceHandleImpl::PlatformTransferCallback, | |
| 644 this, | |
| 645 timeout); | |
| 646 libusb_set_iso_packet_lengths(transfer, packet_length); | |
| 647 | |
| 648 PostOrSubmitTransfer( | |
| 649 transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback); | |
| 650 } | |
| 651 | |
| 652 void UsbDeviceHandleImpl::RefreshEndpointMap() { | |
| 653 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 654 endpoint_map_.clear(); | |
| 655 for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin(); | |
| 656 it != claimed_interfaces_.end(); | |
| 657 ++it) { | |
| 658 scoped_refptr<const UsbInterfaceAltSettingDescriptor> interface_desc = | |
| 659 interfaces_->GetInterface(it->first) | |
| 660 ->GetAltSetting(it->second->alternate_setting()); | |
| 661 for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) { | |
| 662 scoped_refptr<const UsbEndpointDescriptor> endpoint = | |
| 663 interface_desc->GetEndpoint(i); | |
| 664 endpoint_map_[endpoint->GetAddress()] = it->first; | |
| 665 } | |
| 666 } | |
| 667 } | |
| 668 | |
| 669 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> | |
| 670 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) { | |
| 671 unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK; | |
| 672 if (ContainsKey(endpoint_map_, address)) | |
| 673 return claimed_interfaces_[endpoint_map_[address]]; | |
| 674 return NULL; | |
| 675 } | |
| 676 | |
| 677 void UsbDeviceHandleImpl::PostOrSubmitTransfer( | |
| 678 PlatformUsbTransferHandle transfer, | |
| 679 UsbTransferType transfer_type, | |
| 680 net::IOBuffer* buffer, | |
| 681 size_t length, | |
| 682 const UsbTransferCallback& callback) { | |
| 683 if (task_runner_->RunsTasksOnCurrentThread()) { | |
| 684 SubmitTransfer(transfer, | |
| 685 transfer_type, | |
| 686 buffer, | |
| 687 length, | |
| 688 base::ThreadTaskRunnerHandle::Get(), | |
| 689 callback); | |
| 690 } else { | |
| 691 task_runner_->PostTask(FROM_HERE, | |
| 692 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, | |
| 693 this, | |
| 694 transfer, | |
| 695 transfer_type, | |
| 696 make_scoped_refptr(buffer), | |
| 697 length, | |
| 698 base::ThreadTaskRunnerHandle::Get(), | |
| 699 callback)); | |
| 700 } | |
| 701 } | |
| 702 | |
| 703 void UsbDeviceHandleImpl::SubmitTransfer( | |
| 704 PlatformUsbTransferHandle handle, | |
| 705 UsbTransferType transfer_type, | |
| 706 net::IOBuffer* buffer, | |
| 707 const size_t length, | |
| 708 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
| 709 const UsbTransferCallback& callback) { | |
| 710 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 711 | |
| 712 Transfer transfer; | |
| 713 transfer.transfer_type = transfer_type; | |
| 714 transfer.buffer = buffer; | |
| 715 transfer.length = length; | |
| 716 transfer.callback = callback; | |
| 717 transfer.task_runner = task_runner; | |
| 718 | |
| 719 if (!device_) { | |
| 720 transfer.Complete(USB_TRANSFER_DISCONNECT, 0); | |
| 721 return; | |
| 722 } | |
| 723 | |
| 724 // It's OK for this method to return NULL. libusb_submit_transfer will fail if | |
| 725 // it requires an interface we didn't claim. | |
| 726 transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint); | |
| 727 | |
| 728 const int rv = libusb_submit_transfer(handle); | |
| 729 if (rv == LIBUSB_SUCCESS) { | |
| 730 transfers_[handle] = transfer; | |
| 731 } else { | |
| 732 VLOG(1) << "Failed to submit transfer: " << ConvertErrorToString(rv); | |
| 733 transfer.Complete(USB_TRANSFER_ERROR, 0); | |
| 734 } | |
| 735 } | |
| 736 | |
| 737 void UsbDeviceHandleImpl::InternalClose() { | |
| 738 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 739 if (!device_) | |
| 740 return; | |
| 741 | |
| 742 // Cancel all the transfers. | |
| 743 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); | |
| 744 ++it) { | |
| 745 // The callback will be called some time later. | |
| 746 libusb_cancel_transfer(it->first); | |
| 747 } | |
| 748 | |
| 749 // Attempt-release all the interfaces. | |
| 750 // It will be retained until the transfer cancellation is finished. | |
| 751 claimed_interfaces_.clear(); | |
| 752 | |
| 753 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to | |
| 754 // finish. | |
| 755 device_ = NULL; | |
| 756 } | |
| 757 | |
| 758 } // namespace usb_service | |
| OLD | NEW |