Home | History | Annotate | Download | only in usb_service
      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