Home | History | Annotate | Download | only in usb
      1 // Copyright (c) 2013 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 "chrome/browser/usb/usb_device_handle.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 "chrome/browser/usb/usb_context.h"
     15 #include "chrome/browser/usb/usb_device.h"
     16 #include "chrome/browser/usb/usb_interface.h"
     17 #include "chrome/browser/usb/usb_service.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "third_party/libusb/src/libusb/libusb.h"
     20 
     21 using content::BrowserThread;
     22 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
     23 
     24 namespace {
     25 
     26 static uint8 ConvertTransferDirection(
     27     const UsbEndpointDirection direction) {
     28   switch (direction) {
     29     case USB_DIRECTION_INBOUND:
     30       return LIBUSB_ENDPOINT_IN;
     31     case USB_DIRECTION_OUTBOUND:
     32       return LIBUSB_ENDPOINT_OUT;
     33     default:
     34       NOTREACHED();
     35       return LIBUSB_ENDPOINT_IN;
     36   }
     37 }
     38 
     39 static uint8 CreateRequestType(const UsbEndpointDirection direction,
     40     const UsbDeviceHandle::TransferRequestType request_type,
     41     const UsbDeviceHandle::TransferRecipient recipient) {
     42   uint8 result = ConvertTransferDirection(direction);
     43 
     44   switch (request_type) {
     45     case UsbDeviceHandle::STANDARD:
     46       result |= LIBUSB_REQUEST_TYPE_STANDARD;
     47       break;
     48     case UsbDeviceHandle::CLASS:
     49       result |= LIBUSB_REQUEST_TYPE_CLASS;
     50       break;
     51     case UsbDeviceHandle::VENDOR:
     52       result |= LIBUSB_REQUEST_TYPE_VENDOR;
     53       break;
     54     case UsbDeviceHandle::RESERVED:
     55       result |= LIBUSB_REQUEST_TYPE_RESERVED;
     56       break;
     57   }
     58 
     59   switch (recipient) {
     60     case UsbDeviceHandle::DEVICE:
     61       result |= LIBUSB_RECIPIENT_DEVICE;
     62       break;
     63     case UsbDeviceHandle::INTERFACE:
     64       result |= LIBUSB_RECIPIENT_INTERFACE;
     65       break;
     66     case UsbDeviceHandle::ENDPOINT:
     67       result |= LIBUSB_RECIPIENT_ENDPOINT;
     68       break;
     69     case UsbDeviceHandle::OTHER:
     70       result |= LIBUSB_RECIPIENT_OTHER;
     71       break;
     72   }
     73 
     74   return result;
     75 }
     76 
     77 static UsbTransferStatus ConvertTransferStatus(
     78     const libusb_transfer_status status) {
     79   switch (status) {
     80     case LIBUSB_TRANSFER_COMPLETED:
     81       return USB_TRANSFER_COMPLETED;
     82     case LIBUSB_TRANSFER_ERROR:
     83       return USB_TRANSFER_ERROR;
     84     case LIBUSB_TRANSFER_TIMED_OUT:
     85       return USB_TRANSFER_TIMEOUT;
     86     case LIBUSB_TRANSFER_STALL:
     87       return USB_TRANSFER_STALLED;
     88     case LIBUSB_TRANSFER_NO_DEVICE:
     89       return USB_TRANSFER_DISCONNECT;
     90     case LIBUSB_TRANSFER_OVERFLOW:
     91       return USB_TRANSFER_OVERFLOW;
     92     case LIBUSB_TRANSFER_CANCELLED:
     93       return USB_TRANSFER_CANCELLED;
     94     default:
     95       NOTREACHED();
     96       return USB_TRANSFER_ERROR;
     97   }
     98 }
     99 
    100 static void LIBUSB_CALL PlatformTransferCompletionCallback(
    101     PlatformUsbTransferHandle transfer) {
    102   BrowserThread::PostTask(BrowserThread::FILE,
    103                           FROM_HERE,
    104                           base::Bind(HandleTransferCompletion, transfer));
    105 }
    106 
    107 }  // namespace
    108 
    109 void HandleTransferCompletion(PlatformUsbTransferHandle transfer) {
    110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    111   UsbDeviceHandle* const device_handle =
    112       reinterpret_cast<UsbDeviceHandle*>(transfer->user_data);
    113   CHECK(device_handle) << "Device handle is closed before transfer finishes.";
    114   device_handle->TransferComplete(transfer);
    115   libusb_free_transfer(transfer);
    116 }
    117 
    118 
    119 class UsbDeviceHandle::InterfaceClaimer
    120     : public base::RefCountedThreadSafe<UsbDeviceHandle::InterfaceClaimer> {
    121  public:
    122   InterfaceClaimer(const scoped_refptr<UsbDeviceHandle> handle,
    123                    const int interface_number);
    124 
    125   bool Claim() const;
    126 
    127   int alternate_setting() const { return alternate_setting_; }
    128   void set_alternate_setting(const int alternate_setting) {
    129     alternate_setting_ = alternate_setting;
    130   }
    131 
    132  private:
    133   friend class UsbDevice;
    134   friend class base::RefCountedThreadSafe<InterfaceClaimer>;
    135   ~InterfaceClaimer();
    136 
    137   const scoped_refptr<UsbDeviceHandle> handle_;
    138   const int interface_number_;
    139   int alternate_setting_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
    142 };
    143 
    144 UsbDeviceHandle::InterfaceClaimer::InterfaceClaimer(
    145     const scoped_refptr<UsbDeviceHandle> handle, const int interface_number)
    146     : handle_(handle),
    147       interface_number_(interface_number),
    148       alternate_setting_(0) {
    149 }
    150 
    151 UsbDeviceHandle::InterfaceClaimer::~InterfaceClaimer() {
    152   libusb_release_interface(handle_->handle(), interface_number_);
    153 }
    154 
    155 bool UsbDeviceHandle::InterfaceClaimer::Claim() const {
    156   return libusb_claim_interface(handle_->handle(), interface_number_) == 0;
    157 }
    158 
    159 struct UsbDeviceHandle::Transfer {
    160   Transfer();
    161   ~Transfer();
    162 
    163   UsbTransferType transfer_type;
    164   scoped_refptr<net::IOBuffer> buffer;
    165   scoped_refptr<UsbDeviceHandle::InterfaceClaimer> claimed_interface;
    166   scoped_refptr<base::MessageLoopProxy> message_loop_proxy;
    167   size_t length;
    168   UsbTransferCallback callback;
    169 };
    170 
    171 UsbDeviceHandle::Transfer::Transfer()
    172     : transfer_type(USB_TRANSFER_CONTROL),
    173       length(0) {
    174 }
    175 
    176 UsbDeviceHandle::Transfer::~Transfer() {}
    177 
    178 UsbDeviceHandle::UsbDeviceHandle(
    179     scoped_refptr<UsbContext> context,
    180     UsbDevice* device,
    181     PlatformUsbDeviceHandle handle,
    182     scoped_refptr<UsbConfigDescriptor> interfaces)
    183     : device_(device),
    184       handle_(handle),
    185       interfaces_(interfaces),
    186       context_(context) {
    187   DCHECK(thread_checker_.CalledOnValidThread());
    188   DCHECK(handle) << "Cannot create device with NULL handle.";
    189   DCHECK(interfaces_) << "Unabled to list interfaces";
    190 }
    191 
    192 UsbDeviceHandle::UsbDeviceHandle() : device_(NULL), handle_(NULL) {
    193 }
    194 
    195 UsbDeviceHandle::~UsbDeviceHandle() {
    196   DCHECK(thread_checker_.CalledOnValidThread());
    197 
    198   libusb_close(handle_);
    199   handle_ = NULL;
    200 }
    201 
    202 scoped_refptr<UsbDevice> UsbDeviceHandle::device() const {
    203   return device_;
    204 }
    205 
    206 void UsbDeviceHandle::Close() {
    207   DCHECK(thread_checker_.CalledOnValidThread());
    208   if (device_)
    209     device_->Close(this);
    210 }
    211 
    212 void UsbDeviceHandle::TransferComplete(PlatformUsbTransferHandle handle) {
    213   DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed";
    214 
    215   Transfer transfer = transfers_[handle];
    216   transfers_.erase(handle);
    217 
    218   DCHECK_GE(handle->actual_length, 0) << "Negative actual length received";
    219   size_t actual_length =
    220       static_cast<size_t>(std::max(handle->actual_length, 0));
    221 
    222   DCHECK(transfer.length >= actual_length) <<
    223       "data too big for our buffer (libusb failure?)";
    224 
    225   scoped_refptr<net::IOBuffer> buffer = transfer.buffer;
    226   switch (transfer.transfer_type) {
    227     case USB_TRANSFER_CONTROL:
    228       // If the transfer is a control transfer we do not expose the control
    229       // setup header to the caller. This logic strips off the header if
    230       // present before invoking the callback provided with the transfer.
    231       if (actual_length > 0) {
    232         CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) <<
    233             "buffer was not correctly set: too small for the control header";
    234 
    235         if (transfer.length >= actual_length &&
    236             actual_length >= LIBUSB_CONTROL_SETUP_SIZE) {
    237           // If the payload is zero bytes long, pad out the allocated buffer
    238           // size to one byte so that an IOBuffer of that size can be allocated.
    239           scoped_refptr<net::IOBuffer> resized_buffer = new net::IOBuffer(
    240               std::max(actual_length, static_cast<size_t>(1)));
    241           memcpy(resized_buffer->data(),
    242                  buffer->data() + LIBUSB_CONTROL_SETUP_SIZE,
    243                  actual_length);
    244           buffer = resized_buffer;
    245         }
    246       }
    247       break;
    248 
    249     case USB_TRANSFER_ISOCHRONOUS:
    250       // Isochronous replies might carry data in the different isoc packets even
    251       // if the transfer actual_data value is zero. Furthermore, not all of the
    252       // received packets might contain data, so we need to calculate how many
    253       // data bytes we are effectively providing and pack the results.
    254       if (actual_length == 0) {
    255         size_t packet_buffer_start = 0;
    256         for (int i = 0; i < handle->num_iso_packets; ++i) {
    257           PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i];
    258           if (packet->actual_length > 0) {
    259             // We don't need to copy as long as all packets until now provide
    260             // all the data the packet can hold.
    261             if (actual_length < packet_buffer_start) {
    262               CHECK(packet_buffer_start + packet->actual_length <=
    263                     transfer.length);
    264               memmove(buffer->data() + actual_length,
    265                       buffer->data() + packet_buffer_start,
    266                       packet->actual_length);
    267             }
    268             actual_length += packet->actual_length;
    269           }
    270 
    271           packet_buffer_start += packet->length;
    272         }
    273       }
    274       break;
    275 
    276     case USB_TRANSFER_BULK:
    277     case USB_TRANSFER_INTERRUPT:
    278       break;
    279 
    280     default:
    281       NOTREACHED() << "Invalid usb transfer type";
    282       break;
    283   }
    284 
    285   transfer.message_loop_proxy->PostTask(
    286       FROM_HERE,
    287       base::Bind(transfer.callback,
    288                  ConvertTransferStatus(handle->status),
    289                  buffer,
    290                  actual_length));
    291 
    292   // Must release interface first before actually delete this.
    293   transfer.claimed_interface = NULL;
    294 }
    295 
    296 bool UsbDeviceHandle::ClaimInterface(const int interface_number) {
    297   DCHECK(thread_checker_.CalledOnValidThread());
    298   if (!device_) return false;
    299   if (ContainsKey(claimed_interfaces_, interface_number)) return true;
    300 
    301   scoped_refptr<InterfaceClaimer> claimer =
    302       new InterfaceClaimer(this, interface_number);
    303 
    304   if (claimer->Claim()) {
    305     claimed_interfaces_[interface_number]= claimer;
    306     RefreshEndpointMap();
    307     return true;
    308   }
    309   return false;
    310 }
    311 
    312 bool UsbDeviceHandle::ReleaseInterface(const int interface_number) {
    313   DCHECK(thread_checker_.CalledOnValidThread());
    314   if (!device_) return false;
    315   if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
    316 
    317   // Cancel all the transfers on that interface.
    318   InterfaceClaimer* interface_claimer =
    319       claimed_interfaces_[interface_number].get();
    320   for (TransferMap::iterator it = transfers_.begin();
    321       it != transfers_.end(); ++it) {
    322     if (it->second.claimed_interface.get() == interface_claimer)
    323       libusb_cancel_transfer(it->first);
    324   }
    325   claimed_interfaces_.erase(interface_number);
    326 
    327   RefreshEndpointMap();
    328   return true;
    329 }
    330 
    331 bool UsbDeviceHandle::SetInterfaceAlternateSetting(
    332     const int interface_number,
    333     const int alternate_setting) {
    334   DCHECK(thread_checker_.CalledOnValidThread());
    335   if (!device_) return false;
    336   if (!ContainsKey(claimed_interfaces_, interface_number)) return false;
    337   const int rv = libusb_set_interface_alt_setting(handle_,
    338       interface_number, alternate_setting);
    339   if (rv == 0) {
    340     claimed_interfaces_[interface_number]->
    341       set_alternate_setting(alternate_setting);
    342     RefreshEndpointMap();
    343     return true;
    344   }
    345   return false;
    346 }
    347 
    348 bool UsbDeviceHandle::ResetDevice() {
    349   DCHECK(thread_checker_.CalledOnValidThread());
    350   if (!device_) return false;
    351 
    352   return libusb_reset_device(handle_) == 0;
    353 }
    354 
    355 bool UsbDeviceHandle::GetSerial(base::string16* serial) {
    356   DCHECK(thread_checker_.CalledOnValidThread());
    357   PlatformUsbDevice device = libusb_get_device(handle_);
    358   libusb_device_descriptor desc;
    359 
    360   if (libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS)
    361     return false;
    362 
    363   if (desc.iSerialNumber == 0)
    364     return false;
    365 
    366   // Getting supported language ID.
    367   uint16 langid[128] = { 0 };
    368 
    369   int size = libusb_get_string_descriptor(
    370       handle_, 0, 0,
    371       reinterpret_cast<unsigned char*>(&langid[0]), sizeof(langid));
    372   if (size < 0)
    373     return false;
    374 
    375   int language_count = (size - 2) / 2;
    376 
    377   for (int i = 1; i <= language_count; ++i) {
    378     // Get the string using language ID.
    379     char16 text[256] = { 0 };
    380     size = libusb_get_string_descriptor(
    381         handle_, desc.iSerialNumber, langid[i],
    382         reinterpret_cast<unsigned char*>(&text[0]), sizeof(text));
    383     if (size <= 2)
    384       continue;
    385     if ((text[0] >> 8) != LIBUSB_DT_STRING)
    386       continue;
    387     if ((text[0] & 255) > size)
    388       continue;
    389 
    390     size = size / 2 - 1;
    391     *serial = base::string16(text + 1, size);
    392     return true;
    393   }
    394   return false;
    395 }
    396 
    397 void UsbDeviceHandle::ControlTransfer(const UsbEndpointDirection direction,
    398     const TransferRequestType request_type, const TransferRecipient recipient,
    399     const uint8 request, const uint16 value, const uint16 index,
    400     net::IOBuffer* buffer, const size_t length, const unsigned int timeout,
    401     const UsbTransferCallback& callback) {
    402   if (!device_) {
    403     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
    404     return;
    405   }
    406 
    407   const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
    408   scoped_refptr<net::IOBuffer> resized_buffer(new net::IOBufferWithSize(
    409       resized_length));
    410   memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
    411          length);
    412 
    413   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
    414   const uint8 converted_type = CreateRequestType(direction, request_type,
    415                                                  recipient);
    416   libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()),
    417                             converted_type, request, value, index, length);
    418   libusb_fill_control_transfer(
    419       transfer,
    420       handle_,
    421       reinterpret_cast<uint8*>(resized_buffer->data()),
    422       PlatformTransferCompletionCallback,
    423       this,
    424       timeout);
    425 
    426   BrowserThread::PostTask(
    427       BrowserThread::FILE,
    428       FROM_HERE,
    429       base::Bind(&UsbDeviceHandle::SubmitTransfer,
    430                  this,
    431                  transfer,
    432                  USB_TRANSFER_CONTROL,
    433                  resized_buffer,
    434                  resized_length,
    435                  base::MessageLoopProxy::current(),
    436                  callback));
    437 }
    438 
    439 void UsbDeviceHandle::BulkTransfer(const UsbEndpointDirection direction,
    440     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
    441     const unsigned int timeout, const UsbTransferCallback& callback) {
    442   if (!device_) {
    443     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
    444     return;
    445   }
    446 
    447   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
    448   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
    449   libusb_fill_bulk_transfer(transfer, handle_, new_endpoint,
    450       reinterpret_cast<uint8*>(buffer->data()), length,
    451       PlatformTransferCompletionCallback, this, timeout);
    452 
    453   BrowserThread::PostTask(
    454       BrowserThread::FILE,
    455       FROM_HERE,
    456       base::Bind(&UsbDeviceHandle::SubmitTransfer,
    457                  this,
    458                  transfer,
    459                  USB_TRANSFER_BULK,
    460                  make_scoped_refptr(buffer),
    461                  length,
    462                  base::MessageLoopProxy::current(),
    463                  callback));
    464 }
    465 
    466 void UsbDeviceHandle::InterruptTransfer(const UsbEndpointDirection direction,
    467     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
    468     const unsigned int timeout, const UsbTransferCallback& callback) {
    469   if (!device_) {
    470     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
    471     return;
    472   }
    473 
    474   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0);
    475   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
    476   libusb_fill_interrupt_transfer(transfer, handle_, new_endpoint,
    477       reinterpret_cast<uint8*>(buffer->data()), length,
    478       PlatformTransferCompletionCallback, this, timeout);
    479   BrowserThread::PostTask(
    480       BrowserThread::FILE,
    481       FROM_HERE,
    482       base::Bind(&UsbDeviceHandle::SubmitTransfer,
    483                  this,
    484                  transfer,
    485                  USB_TRANSFER_INTERRUPT,
    486                  make_scoped_refptr(buffer),
    487                  length,
    488                  base::MessageLoopProxy::current(),
    489                  callback));
    490 }
    491 
    492 void UsbDeviceHandle::IsochronousTransfer(const UsbEndpointDirection direction,
    493     const uint8 endpoint, net::IOBuffer* buffer, const size_t length,
    494     const unsigned int packets, const unsigned int packet_length,
    495     const unsigned int timeout, const UsbTransferCallback& callback) {
    496   if (!device_) {
    497     callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
    498     return;
    499   }
    500 
    501   const uint64 total_length = packets * packet_length;
    502   CHECK(packets <= length && total_length <= length) <<
    503       "transfer length is too small";
    504 
    505   PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets);
    506   const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint;
    507   libusb_fill_iso_transfer(transfer, handle_, new_endpoint,
    508       reinterpret_cast<uint8*>(buffer->data()), length, packets,
    509       PlatformTransferCompletionCallback, this, timeout);
    510   libusb_set_iso_packet_lengths(transfer, packet_length);
    511 
    512   BrowserThread::PostTask(
    513       BrowserThread::FILE,
    514       FROM_HERE,
    515       base::Bind(&UsbDeviceHandle::SubmitTransfer,
    516                  this,
    517                  transfer,
    518                  USB_TRANSFER_ISOCHRONOUS,
    519                  make_scoped_refptr(buffer),
    520                  length,
    521                  base::MessageLoopProxy::current(),
    522                  callback));
    523 }
    524 
    525 void UsbDeviceHandle::RefreshEndpointMap() {
    526   DCHECK(thread_checker_.CalledOnValidThread());
    527   endpoint_map_.clear();
    528   for (ClaimedInterfaceMap::iterator it = claimed_interfaces_.begin();
    529       it != claimed_interfaces_.end(); ++it) {
    530     scoped_refptr<const UsbInterfaceAltSettingDescriptor> interface_desc =
    531         interfaces_->GetInterface(it->first)->GetAltSetting(
    532             it->second->alternate_setting());
    533     for (size_t i = 0; i < interface_desc->GetNumEndpoints(); i++) {
    534       scoped_refptr<const UsbEndpointDescriptor> endpoint =
    535           interface_desc->GetEndpoint(i);
    536       endpoint_map_[endpoint->GetAddress()] = it->first;
    537     }
    538   }
    539 }
    540 
    541 scoped_refptr<UsbDeviceHandle::InterfaceClaimer>
    542     UsbDeviceHandle::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
    543   unsigned char address = endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK;
    544   if (ContainsKey(endpoint_map_, address))
    545     return claimed_interfaces_[endpoint_map_[address]];
    546   return NULL;
    547 }
    548 
    549 void UsbDeviceHandle::SubmitTransfer(
    550     PlatformUsbTransferHandle handle,
    551     UsbTransferType transfer_type,
    552     net::IOBuffer* buffer,
    553     const size_t length,
    554     scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
    555     const UsbTransferCallback& callback) {
    556   DCHECK(thread_checker_.CalledOnValidThread());
    557   if (!device_) {
    558     message_loop_proxy->PostTask(
    559         FROM_HERE,
    560         base::Bind(callback, USB_TRANSFER_DISCONNECT,
    561                    make_scoped_refptr(buffer), 0));
    562   }
    563 
    564   Transfer transfer;
    565   transfer.transfer_type = transfer_type;
    566   transfer.buffer = buffer;
    567   transfer.length = length;
    568   transfer.callback = callback;
    569   transfer.message_loop_proxy = message_loop_proxy;
    570 
    571   // It's OK for this method to return NULL. libusb_submit_transfer will fail if
    572   // it requires an interface we didn't claim.
    573   transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint);
    574 
    575   if (libusb_submit_transfer(handle) == LIBUSB_SUCCESS) {
    576     transfers_[handle] = transfer;
    577   } else {
    578     message_loop_proxy->PostTask(
    579         FROM_HERE,
    580         base::Bind(callback, USB_TRANSFER_ERROR,
    581                    make_scoped_refptr(buffer), 0));
    582   }
    583 }
    584 
    585 void UsbDeviceHandle::InternalClose() {
    586   DCHECK(thread_checker_.CalledOnValidThread());
    587   if (!device_) return;
    588 
    589   // Cancel all the transfers.
    590   for (TransferMap::iterator it = transfers_.begin();
    591       it != transfers_.end(); ++it) {
    592     // The callback will be called some time later.
    593     libusb_cancel_transfer(it->first);
    594   }
    595 
    596   // Attempt-release all the interfaces.
    597   // It will be retained until the transfer cancellation is finished.
    598   claimed_interfaces_.clear();
    599 
    600   // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
    601   // finish.
    602   device_ = NULL;
    603 }
    604