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/message_loop/message_loop.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string16.h" 13 #include "base/synchronization/lock.h" 14 #include "components/usb_service/usb_context.h" 15 #include "components/usb_service/usb_device_impl.h" 16 #include "components/usb_service/usb_error.h" 17 #include "components/usb_service/usb_interface.h" 18 #include "components/usb_service/usb_service.h" 19 #include "content/public/browser/browser_thread.h" 20 #include "third_party/libusb/src/libusb/libusb.h" 21 22 using content::BrowserThread; 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 static void LIBUSB_CALL 107 PlatformTransferCompletionCallback(PlatformUsbTransferHandle transfer) { 108 BrowserThread::PostTask(BrowserThread::FILE, 109 FROM_HERE, 110 base::Bind(HandleTransferCompletion, transfer)); 111 } 112 113 } // namespace 114 115 void HandleTransferCompletion(PlatformUsbTransferHandle transfer) { 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 117 UsbDeviceHandleImpl* const device_handle = 118 reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data); 119 CHECK(device_handle) << "Device handle is closed before transfer finishes."; 120 device_handle->TransferComplete(transfer); 121 libusb_free_transfer(transfer); 122 } 123 124 class UsbDeviceHandleImpl::InterfaceClaimer 125 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> { 126 public: 127 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle, 128 const int interface_number); 129 130 bool Claim() const; 131 132 int alternate_setting() const { return alternate_setting_; } 133 void set_alternate_setting(const int alternate_setting) { 134 alternate_setting_ = alternate_setting; 135 } 136 137 private: 138 friend class UsbDevice; 139 friend class base::RefCountedThreadSafe<InterfaceClaimer>; 140 ~InterfaceClaimer(); 141 142 const scoped_refptr<UsbDeviceHandleImpl> handle_; 143 const int interface_number_; 144 int alternate_setting_; 145 146 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer); 147 }; 148 149 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer( 150 const scoped_refptr<UsbDeviceHandleImpl> handle, 151 const int interface_number) 152 : handle_(handle), 153 interface_number_(interface_number), 154 alternate_setting_(0) { 155 } 156 157 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() { 158 libusb_release_interface(handle_->handle(), interface_number_); 159 } 160 161 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const { 162 const int rv = libusb_claim_interface(handle_->handle(), interface_number_); 163 if (rv != LIBUSB_SUCCESS) { 164 LOG(ERROR) << "Failed to claim interface: " << ConvertErrorToString(rv); 165 } 166 return rv == LIBUSB_SUCCESS; 167 } 168 169 struct UsbDeviceHandleImpl::Transfer { 170 Transfer(); 171 ~Transfer(); 172 173 UsbTransferType transfer_type; 174 scoped_refptr<net::IOBuffer> buffer; 175 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface; 176 scoped_refptr<base::MessageLoopProxy> message_loop_proxy; 177 size_t length; 178 UsbTransferCallback callback; 179 }; 180 181 UsbDeviceHandleImpl::Transfer::Transfer() 182 : transfer_type(USB_TRANSFER_CONTROL), length(0) { 183 } 184 185 UsbDeviceHandleImpl::Transfer::~Transfer() { 186 } 187 188 UsbDeviceHandleImpl::UsbDeviceHandleImpl( 189 scoped_refptr<UsbContext> context, 190 UsbDeviceImpl* device, 191 PlatformUsbDeviceHandle handle, 192 scoped_refptr<UsbConfigDescriptor> interfaces) 193 : device_(device), 194 handle_(handle), 195 interfaces_(interfaces), 196 context_(context) { 197 DCHECK(thread_checker_.CalledOnValidThread()); 198 DCHECK(handle) << "Cannot create device with NULL handle."; 199 DCHECK(interfaces_) << "Unabled to list interfaces"; 200 } 201 202 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() { 203 DCHECK(thread_checker_.CalledOnValidThread()); 204 205 libusb_close(handle_); 206 handle_ = NULL; 207 } 208 209 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const { 210 return static_cast<UsbDevice*>(device_); 211 } 212 213 void UsbDeviceHandleImpl::Close() { 214 DCHECK(thread_checker_.CalledOnValidThread()); 215 if (device_) 216 device_->Close(this); 217 } 218 219 void UsbDeviceHandleImpl::TransferComplete(PlatformUsbTransferHandle handle) { 220 DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; 221 222 Transfer transfer = transfers_[handle]; 223 transfers_.erase(handle); 224 225 DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; 226 size_t actual_length = 227 static_cast<size_t>(std::max(handle->actual_length, 0)); 228 229 DCHECK(transfer.length >= actual_length) 230 << "data too big for our buffer (libusb failure?)"; 231 232 scoped_refptr<net::IOBuffer> buffer = transfer.buffer; 233 switch (transfer.transfer_type) { 234 case USB_TRANSFER_CONTROL: 235 // If the transfer is a control transfer we do not expose the control 236 // setup header to the caller. This logic strips off the header if 237 // present before invoking the callback provided with the transfer. 238 if (actual_length > 0) { 239 CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) 240 << "buffer was not correctly set: too small for the control header"; 241 242 if (transfer.length >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) { 243 // If the payload is zero bytes long, pad out the allocated buffer 244 // size to one byte so that an IOBuffer of that size can be allocated. 245 scoped_refptr<net::IOBuffer> resized_buffer = 246 new net::IOBuffer(static_cast<int>( 247 std::max(actual_length, static_cast<size_t>(1)))); 248 memcpy(resized_buffer->data(), 249 buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, 250 actual_length); 251 buffer = resized_buffer; 252 } 253 } 254 break; 255 256 case USB_TRANSFER_ISOCHRONOUS: 257 // Isochronous replies might carry data in the different isoc packets even 258 // if the transfer actual_data value is zero. Furthermore, not all of the 259 // received packets might contain data, so we need to calculate how many 260 // data bytes we are effectively providing and pack the results. 261 if (actual_length == 0) { 262 size_t packet_buffer_start = 0; 263 for (int i = 0; i < handle->num_iso_packets; ++i) { 264 PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; 265 if (packet->actual_length > 0) { 266 // We don't need to copy as long as all packets until now provide 267 // all the data the packet can hold. 268 if (actual_length < packet_buffer_start) { 269 CHECK(packet_buffer_start + packet->actual_length <= 270 transfer.length); 271 memmove(buffer->data() + actual_length, 272 buffer->data() + packet_buffer_start, 273 packet->actual_length); 274 } 275 actual_length += packet->actual_length; 276 } 277 278 packet_buffer_start += packet->length; 279 } 280 } 281 break; 282 283 case USB_TRANSFER_BULK: 284 case USB_TRANSFER_INTERRUPT: 285 break; 286 287 default: 288 NOTREACHED() << "Invalid usb transfer type"; 289 break; 290 } 291 292 transfer.message_loop_proxy->PostTask( 293 FROM_HERE, 294 base::Bind(transfer.callback, 295 ConvertTransferStatus(handle->status), 296 buffer, 297 actual_length)); 298 299 // Must release interface first before actually delete this. 300 transfer.claimed_interface = NULL; 301 } 302 303 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) { 304 DCHECK(thread_checker_.CalledOnValidThread()); 305 if (!device_) 306 return false; 307 if (ContainsKey(claimed_interfaces_, interface_number)) 308 return true; 309 310 scoped_refptr<InterfaceClaimer> claimer = 311 new InterfaceClaimer(this, interface_number); 312 313 if (claimer->Claim()) { 314 claimed_interfaces_[interface_number] = claimer; 315 RefreshEndpointMap(); 316 return true; 317 } 318 return false; 319 } 320 321 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) { 322 DCHECK(thread_checker_.CalledOnValidThread()); 323 if (!device_) 324 return false; 325 if (!ContainsKey(claimed_interfaces_, interface_number)) 326 return false; 327 328 // Cancel all the transfers on that interface. 329 InterfaceClaimer* interface_claimer = 330 claimed_interfaces_[interface_number].get(); 331 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); 332 ++it) { 333 if (it->second.claimed_interface.get() == interface_claimer) 334 libusb_cancel_transfer(it->first); 335 } 336 claimed_interfaces_.erase(interface_number); 337 338 RefreshEndpointMap(); 339 return true; 340 } 341 342 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting( 343 const int interface_number, 344 const int alternate_setting) { 345 DCHECK(thread_checker_.CalledOnValidThread()); 346 if (!device_) 347 return false; 348 if (!ContainsKey(claimed_interfaces_, interface_number)) 349 return false; 350 const int rv = libusb_set_interface_alt_setting( 351 handle_, interface_number, alternate_setting); 352 if (rv == LIBUSB_SUCCESS) { 353 claimed_interfaces_[interface_number]->set_alternate_setting( 354 alternate_setting); 355 RefreshEndpointMap(); 356 } else { 357 LOG(ERROR) << "Failed to set interface (" << interface_number 358 << ", " << alternate_setting << "): " << ConvertErrorToString(rv); 359 } 360 return rv == LIBUSB_SUCCESS; 361 } 362 363 bool UsbDeviceHandleImpl::ResetDevice() { 364 DCHECK(thread_checker_.CalledOnValidThread()); 365 if (!device_) 366 return false; 367 368 const int rv = libusb_reset_device(handle_); 369 if (rv != LIBUSB_SUCCESS) { 370 LOG(ERROR) << "Failed to reset device: " << ConvertErrorToString(rv); 371 } 372 return rv == LIBUSB_SUCCESS; 373 } 374 375 bool UsbDeviceHandleImpl::GetSerial(base::string16* serial) { 376 DCHECK(thread_checker_.CalledOnValidThread()); 377 PlatformUsbDevice device = libusb_get_device(handle_); 378 libusb_device_descriptor desc; 379 380 const int rv = libusb_get_device_descriptor(device, &desc); 381 if (rv != LIBUSB_SUCCESS) { 382 LOG(ERROR) << "Failed to read device descriptor: " 383 << ConvertErrorToString(rv); 384 return false; 385 } 386 387 if (desc.iSerialNumber == 0) 388 return false; 389 390 // Getting supported language ID. 391 uint16 langid[128] = {0}; 392 393 int size = 394 libusb_get_string_descriptor(handle_, 395 0, 396 0, 397 reinterpret_cast<unsigned char*>(&langid[0]), 398 sizeof(langid)); 399 if (size < 0) { 400 LOG(ERROR) << "Failed to get language IDs: " 401 << ConvertErrorToString(size); 402 return false; 403 } 404 405 int language_count = (size - 2) / 2; 406 407 for (int i = 1; i <= language_count; ++i) { 408 // Get the string using language ID. 409 base::char16 text[256] = {0}; 410 size = 411 libusb_get_string_descriptor(handle_, 412 desc.iSerialNumber, 413 langid[i], 414 reinterpret_cast<unsigned char*>(&text[0]), 415 sizeof(text)); 416 if (size < 0) { 417 LOG(ERROR) << "Failed to get serial number (langid " << langid[i] << "): " 418 << ConvertErrorToString(size); 419 continue; 420 } 421 if (size <= 2) 422 continue; 423 if ((text[0] >> 8) != LIBUSB_DT_STRING) 424 continue; 425 if ((text[0] & 255) > size) 426 continue; 427 428 size = size / 2 - 1; 429 *serial = base::string16(text + 1, size); 430 return true; 431 } 432 return false; 433 } 434 435 void UsbDeviceHandleImpl::ControlTransfer( 436 const UsbEndpointDirection direction, 437 const TransferRequestType request_type, 438 const TransferRecipient recipient, 439 const uint8 request, 440 const uint16 value, 441 const uint16 index, 442 net::IOBuffer* buffer, 443 const size_t length, 444 const unsigned int timeout, 445 const UsbTransferCallback& callback) { 446 if (!device_) { 447 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 448 return; 449 } 450 451 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length; 452 scoped_refptr<net::IOBuffer> resized_buffer( 453 new net::IOBufferWithSize(static_cast<int>(resized_length))); 454 if (!resized_buffer) { 455 callback.Run(USB_TRANSFER_ERROR, buffer, 0); 456 return; 457 } 458 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, 459 buffer->data(), 460 static_cast<int>(length)); 461 462 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); 463 const uint8 converted_type = 464 CreateRequestType(direction, request_type, recipient); 465 libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), 466 converted_type, 467 request, 468 value, 469 index, 470 static_cast<int16>(length)); 471 libusb_fill_control_transfer(transfer, 472 handle_, 473 reinterpret_cast<uint8*>(resized_buffer->data()), 474 PlatformTransferCompletionCallback, 475 this, 476 timeout); 477 478 BrowserThread::PostTask(BrowserThread::FILE, 479 FROM_HERE, 480 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, 481 this, 482 transfer, 483 USB_TRANSFER_CONTROL, 484 resized_buffer, 485 resized_length, 486 base::MessageLoopProxy::current(), 487 callback)); 488 } 489 490 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction, 491 const uint8 endpoint, 492 net::IOBuffer* buffer, 493 const size_t length, 494 const unsigned int timeout, 495 const UsbTransferCallback& callback) { 496 if (!device_) { 497 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 498 return; 499 } 500 501 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); 502 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 503 libusb_fill_bulk_transfer(transfer, 504 handle_, 505 new_endpoint, 506 reinterpret_cast<uint8*>(buffer->data()), 507 static_cast<int>(length), 508 PlatformTransferCompletionCallback, 509 this, 510 timeout); 511 512 BrowserThread::PostTask(BrowserThread::FILE, 513 FROM_HERE, 514 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, 515 this, 516 transfer, 517 USB_TRANSFER_BULK, 518 make_scoped_refptr(buffer), 519 length, 520 base::MessageLoopProxy::current(), 521 callback)); 522 } 523 524 void UsbDeviceHandleImpl::InterruptTransfer( 525 const UsbEndpointDirection direction, 526 const uint8 endpoint, 527 net::IOBuffer* buffer, 528 const size_t length, 529 const unsigned int timeout, 530 const UsbTransferCallback& callback) { 531 if (!device_) { 532 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 533 return; 534 } 535 536 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); 537 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 538 libusb_fill_interrupt_transfer(transfer, 539 handle_, 540 new_endpoint, 541 reinterpret_cast<uint8*>(buffer->data()), 542 static_cast<int>(length), 543 PlatformTransferCompletionCallback, 544 this, 545 timeout); 546 BrowserThread::PostTask(BrowserThread::FILE, 547 FROM_HERE, 548 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, 549 this, 550 transfer, 551 USB_TRANSFER_INTERRUPT, 552 make_scoped_refptr(buffer), 553 length, 554 base::MessageLoopProxy::current(), 555 callback)); 556 } 557 558 void UsbDeviceHandleImpl::IsochronousTransfer( 559 const UsbEndpointDirection direction, 560 const uint8 endpoint, 561 net::IOBuffer* buffer, 562 const size_t length, 563 const unsigned int packets, 564 const unsigned int packet_length, 565 const unsigned int timeout, 566 const UsbTransferCallback& callback) { 567 if (!device_) { 568 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); 569 return; 570 } 571 572 const uint64 total_length = packets * packet_length; 573 CHECK(packets <= length && total_length <= length) 574 << "transfer length is too small"; 575 576 PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets); 577 const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; 578 libusb_fill_iso_transfer(transfer, 579 handle_, 580 new_endpoint, 581 reinterpret_cast<uint8*>(buffer->data()), 582 static_cast<int>(length), 583 packets, 584 PlatformTransferCompletionCallback, 585 this, 586 timeout); 587 libusb_set_iso_packet_lengths(transfer, packet_length); 588 589 BrowserThread::PostTask(BrowserThread::FILE, 590 FROM_HERE, 591 base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, 592 this, 593 transfer, 594 USB_TRANSFER_ISOCHRONOUS, 595 make_scoped_refptr(buffer), 596 length, 597 base::MessageLoopProxy::current(), 598 callback)); 599 } 600 601 void UsbDeviceHandleImpl::RefreshEndpointMap() { 602 DCHECK(thread_checker_.CalledOnValidThread()); 603 endpoint_map_.clear(); 604 for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin(); 605 it != claimed_interfaces_.end(); 606 ++it) { 607 scoped_refptr<const UsbInterfaceAltSettingDescriptor> interface_desc = 608 interfaces_->GetInterface(it->first) 609 ->GetAltSetting(it->second->alternate_setting()); 610 for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) { 611 scoped_refptr<const UsbEndpointDescriptor> endpoint = 612 interface_desc->GetEndpoint(i); 613 endpoint_map_[endpoint->GetAddress()] = it->first; 614 } 615 } 616 } 617 618 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> 619 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) { 620 unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK; 621 if (ContainsKey(endpoint_map_, address)) 622 return claimed_interfaces_[endpoint_map_[address]]; 623 return NULL; 624 } 625 626 void UsbDeviceHandleImpl::SubmitTransfer( 627 PlatformUsbTransferHandle handle, 628 UsbTransferType transfer_type, 629 net::IOBuffer* buffer, 630 const size_t length, 631 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, 632 const UsbTransferCallback& callback) { 633 DCHECK(thread_checker_.CalledOnValidThread()); 634 if (!device_) { 635 message_loop_proxy->PostTask( 636 FROM_HERE, 637 base::Bind( 638 callback, USB_TRANSFER_DISCONNECT, make_scoped_refptr(buffer), 0)); 639 } 640 641 Transfer transfer; 642 transfer.transfer_type = transfer_type; 643 transfer.buffer = buffer; 644 transfer.length = length; 645 transfer.callback = callback; 646 transfer.message_loop_proxy = message_loop_proxy; 647 648 // It's OK for this method to return NULL. libusb_submit_transfer will fail if 649 // it requires an interface we didn't claim. 650 transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint); 651 652 const int rv = libusb_submit_transfer(handle); 653 if (rv == LIBUSB_SUCCESS) { 654 transfers_[handle] = transfer; 655 } else { 656 LOG(ERROR) << "Failed to submit transfer: " << ConvertErrorToString(rv); 657 message_loop_proxy->PostTask( 658 FROM_HERE, 659 base::Bind( 660 callback, USB_TRANSFER_ERROR, make_scoped_refptr(buffer), 0)); 661 } 662 } 663 664 void UsbDeviceHandleImpl::InternalClose() { 665 DCHECK(thread_checker_.CalledOnValidThread()); 666 if (!device_) 667 return; 668 669 // Cancel all the transfers. 670 for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); 671 ++it) { 672 // The callback will be called some time later. 673 libusb_cancel_transfer(it->first); 674 } 675 676 // Attempt-release all the interfaces. 677 // It will be retained until the transfer cancellation is finished. 678 claimed_interfaces_.clear(); 679 680 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to 681 // finish. 682 device_ = NULL; 683 } 684 685 } // namespace usb_service 686