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.
5 #include "device/usb/usb_device_handle_impl.h"
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/device_event_log/device_event_log.h"
18 #include "device/usb/usb_context.h"
19 #include "device/usb/usb_descriptors.h"
20 #include "device/usb/usb_device_impl.h"
21 #include "device/usb/usb_error.h"
22 #include "device/usb/usb_service.h"
23 #include "third_party/libusb/src/libusb/libusb.h"
27 typedef libusb_device
* PlatformUsbDevice
;
29 void HandleTransferCompletion(PlatformUsbTransferHandle transfer
);
33 static uint8
ConvertTransferDirection(const UsbEndpointDirection direction
) {
35 case USB_DIRECTION_INBOUND
:
36 return LIBUSB_ENDPOINT_IN
;
37 case USB_DIRECTION_OUTBOUND
:
38 return LIBUSB_ENDPOINT_OUT
;
41 return LIBUSB_ENDPOINT_IN
;
45 static uint8
CreateRequestType(
46 const UsbEndpointDirection direction
,
47 const UsbDeviceHandle::TransferRequestType request_type
,
48 const UsbDeviceHandle::TransferRecipient recipient
) {
49 uint8 result
= ConvertTransferDirection(direction
);
51 switch (request_type
) {
52 case UsbDeviceHandle::STANDARD
:
53 result
|= LIBUSB_REQUEST_TYPE_STANDARD
;
55 case UsbDeviceHandle::CLASS
:
56 result
|= LIBUSB_REQUEST_TYPE_CLASS
;
58 case UsbDeviceHandle::VENDOR
:
59 result
|= LIBUSB_REQUEST_TYPE_VENDOR
;
61 case UsbDeviceHandle::RESERVED
:
62 result
|= LIBUSB_REQUEST_TYPE_RESERVED
;
67 case UsbDeviceHandle::DEVICE
:
68 result
|= LIBUSB_RECIPIENT_DEVICE
;
70 case UsbDeviceHandle::INTERFACE
:
71 result
|= LIBUSB_RECIPIENT_INTERFACE
;
73 case UsbDeviceHandle::ENDPOINT
:
74 result
|= LIBUSB_RECIPIENT_ENDPOINT
;
76 case UsbDeviceHandle::OTHER
:
77 result
|= LIBUSB_RECIPIENT_OTHER
;
84 static UsbTransferStatus
ConvertTransferStatus(
85 const libusb_transfer_status status
) {
87 case LIBUSB_TRANSFER_COMPLETED
:
88 return USB_TRANSFER_COMPLETED
;
89 case LIBUSB_TRANSFER_ERROR
:
90 return USB_TRANSFER_ERROR
;
91 case LIBUSB_TRANSFER_TIMED_OUT
:
92 return USB_TRANSFER_TIMEOUT
;
93 case LIBUSB_TRANSFER_STALL
:
94 return USB_TRANSFER_STALLED
;
95 case LIBUSB_TRANSFER_NO_DEVICE
:
96 return USB_TRANSFER_DISCONNECT
;
97 case LIBUSB_TRANSFER_OVERFLOW
:
98 return USB_TRANSFER_OVERFLOW
;
99 case LIBUSB_TRANSFER_CANCELLED
:
100 return USB_TRANSFER_CANCELLED
;
103 return USB_TRANSFER_ERROR
;
109 class UsbDeviceHandleImpl::InterfaceClaimer
110 : public base::RefCountedThreadSafe
<UsbDeviceHandleImpl::InterfaceClaimer
> {
112 InterfaceClaimer(const scoped_refptr
<UsbDeviceHandleImpl
> handle
,
113 const int interface_number
);
117 int alternate_setting() const { return alternate_setting_
; }
118 void set_alternate_setting(const int alternate_setting
) {
119 alternate_setting_
= alternate_setting
;
123 friend class UsbDevice
;
124 friend class base::RefCountedThreadSafe
<InterfaceClaimer
>;
127 const scoped_refptr
<UsbDeviceHandleImpl
> handle_
;
128 const int interface_number_
;
129 int alternate_setting_
;
131 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer
);
134 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer(
135 const scoped_refptr
<UsbDeviceHandleImpl
> handle
,
136 const int interface_number
)
138 interface_number_(interface_number
),
139 alternate_setting_(0) {
142 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() {
143 libusb_release_interface(handle_
->handle(), interface_number_
);
146 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const {
147 const int rv
= libusb_claim_interface(handle_
->handle(), interface_number_
);
148 if (rv
!= LIBUSB_SUCCESS
) {
149 USB_LOG(EVENT
) << "Failed to claim interface " << interface_number_
<< ": "
150 << ConvertPlatformUsbErrorToString(rv
);
152 return rv
== LIBUSB_SUCCESS
;
155 // This inner class owns the underlying libusb_transfer and may outlast
156 // the UsbDeviceHandle that created it.
157 class UsbDeviceHandleImpl::Transfer
{
159 static scoped_ptr
<Transfer
> CreateControlTransfer(
165 scoped_refptr
<net::IOBuffer
> buffer
,
166 unsigned int timeout
,
167 const UsbTransferCallback
& callback
);
168 static scoped_ptr
<Transfer
> CreateBulkTransfer(
170 scoped_refptr
<net::IOBuffer
> buffer
,
172 unsigned int timeout
,
173 const UsbTransferCallback
& callback
);
174 static scoped_ptr
<Transfer
> CreateInterruptTransfer(
176 scoped_refptr
<net::IOBuffer
> buffer
,
178 unsigned int timeout
,
179 const UsbTransferCallback
& callback
);
180 static scoped_ptr
<Transfer
> CreateIsochronousTransfer(
182 scoped_refptr
<net::IOBuffer
> buffer
,
184 unsigned int packets
,
185 unsigned int packet_length
,
186 unsigned int timeout
,
187 const UsbTransferCallback
& callback
);
191 bool Submit(base::WeakPtr
<UsbDeviceHandleImpl
> device_handle
);
193 void ProcessCompletion();
194 void Complete(UsbTransferStatus status
, size_t bytes_transferred
);
196 const UsbDeviceHandleImpl::InterfaceClaimer
* claimed_interface() const {
197 return claimed_interface_
.get();
201 Transfer(UsbTransferType transfer_type
,
202 scoped_refptr
<net::IOBuffer
> buffer
,
204 const UsbTransferCallback
& callback
);
206 static void LIBUSB_CALL
PlatformCallback(PlatformUsbTransferHandle handle
);
208 UsbTransferType transfer_type_
;
209 base::WeakPtr
<UsbDeviceHandleImpl
> device_handle_
;
210 PlatformUsbTransferHandle platform_transfer_
;
211 scoped_refptr
<net::IOBuffer
> buffer_
;
212 scoped_refptr
<UsbDeviceHandleImpl::InterfaceClaimer
> claimed_interface_
;
213 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
216 UsbTransferCallback callback_
;
217 scoped_refptr
<base::SingleThreadTaskRunner
> callback_task_runner_
;
221 scoped_ptr
<UsbDeviceHandleImpl::Transfer
>
222 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
228 scoped_refptr
<net::IOBuffer
> buffer
,
229 unsigned int timeout
,
230 const UsbTransferCallback
& callback
) {
231 scoped_ptr
<Transfer
> transfer(new Transfer(USB_TRANSFER_CONTROL
, buffer
,
232 length
+ LIBUSB_CONTROL_SETUP_SIZE
,
235 transfer
->platform_transfer_
= libusb_alloc_transfer(0);
236 if (!transfer
->platform_transfer_
) {
237 USB_LOG(ERROR
) << "Failed to allocate control transfer.";
241 libusb_fill_control_setup(reinterpret_cast<uint8
*>(buffer
->data()), type
,
242 request
, value
, index
, length
);
243 libusb_fill_control_transfer(transfer
->platform_transfer_
,
244 nullptr, /* filled in by Submit() */
245 reinterpret_cast<uint8
*>(buffer
->data()),
246 &UsbDeviceHandleImpl::Transfer::PlatformCallback
,
247 transfer
.get(), timeout
);
249 return transfer
.Pass();
253 scoped_ptr
<UsbDeviceHandleImpl::Transfer
>
254 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
256 scoped_refptr
<net::IOBuffer
> buffer
,
258 unsigned int timeout
,
259 const UsbTransferCallback
& callback
) {
260 scoped_ptr
<Transfer
> transfer(
261 new Transfer(USB_TRANSFER_BULK
, buffer
, length
, callback
));
263 transfer
->platform_transfer_
= libusb_alloc_transfer(0);
264 if (!transfer
->platform_transfer_
) {
265 USB_LOG(ERROR
) << "Failed to allocate bulk transfer.";
269 libusb_fill_bulk_transfer(transfer
->platform_transfer_
,
270 nullptr, /* filled in by Submit() */
271 endpoint
, reinterpret_cast<uint8
*>(buffer
->data()),
272 static_cast<int>(length
),
273 &UsbDeviceHandleImpl::Transfer::PlatformCallback
,
274 transfer
.get(), timeout
);
276 return transfer
.Pass();
280 scoped_ptr
<UsbDeviceHandleImpl::Transfer
>
281 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
283 scoped_refptr
<net::IOBuffer
> buffer
,
285 unsigned int timeout
,
286 const UsbTransferCallback
& callback
) {
287 scoped_ptr
<Transfer
> transfer(
288 new Transfer(USB_TRANSFER_INTERRUPT
, buffer
, length
, callback
));
290 transfer
->platform_transfer_
= libusb_alloc_transfer(0);
291 if (!transfer
->platform_transfer_
) {
292 USB_LOG(ERROR
) << "Failed to allocate interrupt transfer.";
296 libusb_fill_interrupt_transfer(
297 transfer
->platform_transfer_
, nullptr, /* filled in by Submit() */
298 endpoint
, reinterpret_cast<uint8
*>(buffer
->data()),
299 static_cast<int>(length
),
300 &UsbDeviceHandleImpl::Transfer::PlatformCallback
, transfer
.get(),
303 return transfer
.Pass();
307 scoped_ptr
<UsbDeviceHandleImpl::Transfer
>
308 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
310 scoped_refptr
<net::IOBuffer
> buffer
,
312 unsigned int packets
,
313 unsigned int packet_length
,
314 unsigned int timeout
,
315 const UsbTransferCallback
& callback
) {
316 DCHECK(packets
<= length
&& (packets
* packet_length
) <= length
)
317 << "transfer length is too small";
319 scoped_ptr
<Transfer
> transfer(
320 new Transfer(USB_TRANSFER_ISOCHRONOUS
, buffer
, length
, callback
));
322 transfer
->platform_transfer_
= libusb_alloc_transfer(packets
);
323 if (!transfer
->platform_transfer_
) {
324 USB_LOG(ERROR
) << "Failed to allocate isochronous transfer.";
328 libusb_fill_iso_transfer(
329 transfer
->platform_transfer_
, nullptr, /* filled in by Submit() */
330 endpoint
, reinterpret_cast<uint8
*>(buffer
->data()),
331 static_cast<int>(length
), packets
, &Transfer::PlatformCallback
,
332 transfer
.get(), timeout
);
333 libusb_set_iso_packet_lengths(transfer
->platform_transfer_
, packet_length
);
335 return transfer
.Pass();
338 UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type
,
339 scoped_refptr
<net::IOBuffer
> buffer
,
341 const UsbTransferCallback
& callback
)
342 : transfer_type_(transfer_type
),
346 callback_(callback
) {
347 // Remember the thread from which this transfer was created so that |callback|
348 // can be dispatched there.
349 callback_task_runner_
= base::ThreadTaskRunnerHandle::Get();
352 UsbDeviceHandleImpl::Transfer::~Transfer() {
353 if (platform_transfer_
) {
354 libusb_free_transfer(platform_transfer_
);
358 bool UsbDeviceHandleImpl::Transfer::Submit(
359 base::WeakPtr
<UsbDeviceHandleImpl
> device_handle
) {
360 device_handle_
= device_handle
;
361 // Remember the thread from which this transfer was submitted so that it can
362 // be marked complete there.
363 task_runner_
= base::ThreadTaskRunnerHandle::Get();
364 // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer
365 // will fail if it requires an interface we didn't claim.
366 claimed_interface_
= device_handle
->GetClaimedInterfaceForEndpoint(
367 platform_transfer_
->endpoint
);
368 platform_transfer_
->dev_handle
= device_handle_
->handle_
;
370 const int rv
= libusb_submit_transfer(platform_transfer_
);
371 if (rv
== LIBUSB_SUCCESS
) {
374 USB_LOG(EVENT
) << "Failed to submit transfer: "
375 << ConvertPlatformUsbErrorToString(rv
);
376 Complete(USB_TRANSFER_ERROR
, 0);
381 void UsbDeviceHandleImpl::Transfer::Cancel() {
383 libusb_cancel_transfer(platform_transfer_
);
384 claimed_interface_
= nullptr;
389 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
390 DCHECK_GE(platform_transfer_
->actual_length
, 0)
391 << "Negative actual length received";
392 size_t actual_length
=
393 static_cast<size_t>(std::max(platform_transfer_
->actual_length
, 0));
395 DCHECK(length_
>= actual_length
)
396 << "data too big for our buffer (libusb failure?)";
398 switch (transfer_type_
) {
399 case USB_TRANSFER_CONTROL
:
400 // If the transfer is a control transfer we do not expose the control
401 // setup header to the caller. This logic strips off the header if
402 // present before invoking the callback provided with the transfer.
403 if (actual_length
> 0) {
404 CHECK(length_
>= LIBUSB_CONTROL_SETUP_SIZE
)
405 << "buffer was not correctly set: too small for the control header";
407 if (length_
>= (LIBUSB_CONTROL_SETUP_SIZE
+ actual_length
)) {
408 // If the payload is zero bytes long, pad out the allocated buffer
409 // size to one byte so that an IOBuffer of that size can be allocated.
410 scoped_refptr
<net::IOBuffer
> resized_buffer
=
411 new net::IOBuffer(static_cast<int>(
412 std::max(actual_length
, static_cast<size_t>(1))));
413 memcpy(resized_buffer
->data(),
414 buffer_
->data() + LIBUSB_CONTROL_SETUP_SIZE
, actual_length
);
415 buffer_
= resized_buffer
;
420 case USB_TRANSFER_ISOCHRONOUS
:
421 // Isochronous replies might carry data in the different isoc packets even
422 // if the transfer actual_data value is zero. Furthermore, not all of the
423 // received packets might contain data, so we need to calculate how many
424 // data bytes we are effectively providing and pack the results.
425 if (actual_length
== 0) {
426 size_t packet_buffer_start
= 0;
427 for (int i
= 0; i
< platform_transfer_
->num_iso_packets
; ++i
) {
428 PlatformUsbIsoPacketDescriptor packet
=
429 &platform_transfer_
->iso_packet_desc
[i
];
430 if (packet
->actual_length
> 0) {
431 // We don't need to copy as long as all packets until now provide
432 // all the data the packet can hold.
433 if (actual_length
< packet_buffer_start
) {
434 CHECK(packet_buffer_start
+ packet
->actual_length
<= length_
);
435 memmove(buffer_
->data() + actual_length
,
436 buffer_
->data() + packet_buffer_start
,
437 packet
->actual_length
);
439 actual_length
+= packet
->actual_length
;
442 packet_buffer_start
+= packet
->length
;
447 case USB_TRANSFER_BULK
:
448 case USB_TRANSFER_INTERRUPT
:
452 NOTREACHED() << "Invalid usb transfer type";
456 Complete(ConvertTransferStatus(platform_transfer_
->status
), actual_length
);
459 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status
,
460 size_t bytes_transferred
) {
461 if (callback_task_runner_
->RunsTasksOnCurrentThread()) {
462 callback_
.Run(status
, buffer_
, bytes_transferred
);
464 callback_task_runner_
->PostTask(
465 FROM_HERE
, base::Bind(callback_
, status
, buffer_
, bytes_transferred
));
470 void LIBUSB_CALL
UsbDeviceHandleImpl::Transfer::PlatformCallback(
471 PlatformUsbTransferHandle platform_transfer
) {
472 scoped_ptr
<Transfer
> transfer(
473 reinterpret_cast<Transfer
*>(platform_transfer
->user_data
));
474 DCHECK(transfer
->platform_transfer_
== platform_transfer
);
476 // Because device_handle_ is a weak pointer it is guaranteed that the callback
477 // will be discarded if the handle has been freed.
478 Transfer
* tmp_transfer
= transfer
.get(); // base::Passed invalidates transfer
479 tmp_transfer
->task_runner_
->PostTask(
480 FROM_HERE
, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer
,
481 tmp_transfer
->device_handle_
,
482 base::Passed(&transfer
)));
485 UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr
<UsbContext
> context
,
486 scoped_refptr
<UsbDeviceImpl
> device
,
487 PlatformUsbDeviceHandle handle
)
491 task_runner_(base::ThreadTaskRunnerHandle::Get()),
492 weak_factory_(this) {
493 DCHECK(handle
) << "Cannot create device with NULL handle.";
496 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
497 DCHECK(thread_checker_
.CalledOnValidThread());
499 libusb_close(handle_
);
503 scoped_refptr
<UsbDevice
> UsbDeviceHandleImpl::GetDevice() const {
507 void UsbDeviceHandleImpl::Close() {
508 DCHECK(thread_checker_
.CalledOnValidThread());
510 device_
->Close(this);
513 bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value
) {
514 DCHECK(thread_checker_
.CalledOnValidThread());
519 for (Transfer
* transfer
: transfers_
) {
522 claimed_interfaces_
.clear();
524 int rv
= libusb_set_configuration(handle_
, configuration_value
);
525 if (rv
== LIBUSB_SUCCESS
) {
526 device_
->RefreshConfiguration();
527 RefreshEndpointMap();
529 USB_LOG(EVENT
) << "Failed to set configuration " << configuration_value
530 << ": " << ConvertPlatformUsbErrorToString(rv
);
532 return rv
== LIBUSB_SUCCESS
;
535 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number
) {
536 DCHECK(thread_checker_
.CalledOnValidThread());
539 if (ContainsKey(claimed_interfaces_
, interface_number
))
542 scoped_refptr
<InterfaceClaimer
> claimer
=
543 new InterfaceClaimer(this, interface_number
);
545 if (claimer
->Claim()) {
546 claimed_interfaces_
[interface_number
] = claimer
;
547 RefreshEndpointMap();
553 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number
) {
554 DCHECK(thread_checker_
.CalledOnValidThread());
557 if (!ContainsKey(claimed_interfaces_
, interface_number
))
560 // Cancel all the transfers on that interface.
561 InterfaceClaimer
* interface_claimer
=
562 claimed_interfaces_
[interface_number
].get();
563 for (Transfer
* transfer
: transfers_
) {
564 if (transfer
->claimed_interface() == interface_claimer
) {
568 claimed_interfaces_
.erase(interface_number
);
570 RefreshEndpointMap();
574 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
575 const int interface_number
,
576 const int alternate_setting
) {
577 DCHECK(thread_checker_
.CalledOnValidThread());
580 if (!ContainsKey(claimed_interfaces_
, interface_number
))
582 const int rv
= libusb_set_interface_alt_setting(
583 handle_
, interface_number
, alternate_setting
);
584 if (rv
== LIBUSB_SUCCESS
) {
585 claimed_interfaces_
[interface_number
]->set_alternate_setting(
587 RefreshEndpointMap();
589 USB_LOG(EVENT
) << "Failed to set interface " << interface_number
590 << " to alternate setting " << alternate_setting
<< ": "
591 << ConvertPlatformUsbErrorToString(rv
);
593 return rv
== LIBUSB_SUCCESS
;
596 bool UsbDeviceHandleImpl::ResetDevice() {
597 DCHECK(thread_checker_
.CalledOnValidThread());
601 const int rv
= libusb_reset_device(handle_
);
602 if (rv
!= LIBUSB_SUCCESS
) {
603 USB_LOG(EVENT
) << "Failed to reset device: "
604 << ConvertPlatformUsbErrorToString(rv
);
606 return rv
== LIBUSB_SUCCESS
;
609 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id
,
610 base::string16
* string
) {
611 if (!GetSupportedLanguages()) {
615 std::map
<uint8
, base::string16
>::const_iterator it
= strings_
.find(string_id
);
616 if (it
!= strings_
.end()) {
617 *string
= it
->second
;
621 for (size_t i
= 0; i
< languages_
.size(); ++i
) {
622 // Get the string using language ID.
623 uint16 language_id
= languages_
[i
];
624 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s).
625 base::char16 text
[128];
627 libusb_get_string_descriptor(handle_
,
630 reinterpret_cast<unsigned char*>(&text
[0]),
633 USB_LOG(EVENT
) << "Failed to get string descriptor " << string_id
634 << " (langid " << language_id
635 << "): " << ConvertPlatformUsbErrorToString(size
);
637 } else if (size
< 2) {
638 USB_LOG(EVENT
) << "String descriptor " << string_id
<< " (langid "
639 << language_id
<< ") has no header.";
641 // The first 2 bytes of the descriptor are the total length and type tag.
642 } else if ((text
[0] & 0xff) != size
) {
643 USB_LOG(EVENT
) << "String descriptor " << string_id
<< " (langid "
644 << language_id
<< ") size mismatch: " << (text
[0] & 0xff)
647 } else if ((text
[0] >> 8) != LIBUSB_DT_STRING
) {
648 USB_LOG(EVENT
) << "String descriptor " << string_id
<< " (langid "
649 << language_id
<< ") is not a string descriptor.";
653 *string
= base::string16(text
+ 1, (size
- 2) / 2);
654 strings_
[string_id
] = *string
;
661 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction
,
662 TransferRequestType request_type
,
663 TransferRecipient recipient
,
667 net::IOBuffer
* buffer
,
669 unsigned int timeout
,
670 const UsbTransferCallback
& callback
) {
671 if (length
> UINT16_MAX
) {
672 USB_LOG(USER
) << "Transfer too long.";
673 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
677 const size_t resized_length
= LIBUSB_CONTROL_SETUP_SIZE
+ length
;
678 scoped_refptr
<net::IOBuffer
> resized_buffer(
679 new net::IOBufferWithSize(static_cast<int>(resized_length
)));
680 if (!resized_buffer
.get()) {
681 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
684 memcpy(resized_buffer
->data() + LIBUSB_CONTROL_SETUP_SIZE
, buffer
->data(),
687 scoped_ptr
<Transfer
> transfer
= Transfer::CreateControlTransfer(
688 CreateRequestType(direction
, request_type
, recipient
), request
, value
,
689 index
, static_cast<uint16
>(length
), resized_buffer
, timeout
, callback
);
691 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
695 PostOrSubmitTransfer(transfer
.Pass());
698 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction
,
699 const uint8 endpoint
,
700 net::IOBuffer
* buffer
,
702 const unsigned int timeout
,
703 const UsbTransferCallback
& callback
) {
704 if (length
> INT_MAX
) {
705 USB_LOG(USER
) << "Transfer too long.";
706 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
710 scoped_ptr
<Transfer
> transfer
= Transfer::CreateBulkTransfer(
711 ConvertTransferDirection(direction
) | endpoint
, buffer
,
712 static_cast<int>(length
), timeout
, callback
);
714 PostOrSubmitTransfer(transfer
.Pass());
717 void UsbDeviceHandleImpl::InterruptTransfer(
718 UsbEndpointDirection direction
,
720 net::IOBuffer
* buffer
,
722 unsigned int timeout
,
723 const UsbTransferCallback
& callback
) {
724 if (length
> INT_MAX
) {
725 USB_LOG(USER
) << "Transfer too long.";
726 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
730 scoped_ptr
<Transfer
> transfer
= Transfer::CreateInterruptTransfer(
731 ConvertTransferDirection(direction
) | endpoint
, buffer
,
732 static_cast<int>(length
), timeout
, callback
);
734 PostOrSubmitTransfer(transfer
.Pass());
737 void UsbDeviceHandleImpl::IsochronousTransfer(
738 const UsbEndpointDirection direction
,
739 const uint8 endpoint
,
740 net::IOBuffer
* buffer
,
742 const unsigned int packets
,
743 const unsigned int packet_length
,
744 const unsigned int timeout
,
745 const UsbTransferCallback
& callback
) {
746 if (length
> INT_MAX
) {
747 USB_LOG(USER
) << "Transfer too long.";
748 callback
.Run(USB_TRANSFER_ERROR
, buffer
, 0);
752 scoped_ptr
<Transfer
> transfer
= Transfer::CreateIsochronousTransfer(
753 ConvertTransferDirection(direction
) | endpoint
, buffer
,
754 static_cast<int>(length
), packets
, packet_length
, timeout
, callback
);
756 PostOrSubmitTransfer(transfer
.Pass());
759 void UsbDeviceHandleImpl::RefreshEndpointMap() {
760 DCHECK(thread_checker_
.CalledOnValidThread());
761 endpoint_map_
.clear();
762 const UsbConfigDescriptor
* config
= device_
->GetConfiguration();
764 for (const auto& map_entry
: claimed_interfaces_
) {
765 int interface_number
= map_entry
.first
;
766 const scoped_refptr
<InterfaceClaimer
>& claimed_iface
= map_entry
.second
;
768 for (const UsbInterfaceDescriptor
& iface
: config
->interfaces
) {
769 if (iface
.interface_number
== interface_number
&&
770 iface
.alternate_setting
== claimed_iface
->alternate_setting()) {
771 for (const UsbEndpointDescriptor
& endpoint
: iface
.endpoints
) {
772 endpoint_map_
[endpoint
.address
] = interface_number
;
781 scoped_refptr
<UsbDeviceHandleImpl::InterfaceClaimer
>
782 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint
) {
783 if (ContainsKey(endpoint_map_
, endpoint
))
784 return claimed_interfaces_
[endpoint_map_
[endpoint
]];
788 void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr
<Transfer
> transfer
) {
789 if (task_runner_
->RunsTasksOnCurrentThread()) {
790 SubmitTransfer(transfer
.Pass());
792 task_runner_
->PostTask(
793 FROM_HERE
, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer
, this,
794 base::Passed(&transfer
)));
798 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr
<Transfer
> transfer
) {
799 DCHECK(thread_checker_
.CalledOnValidThread());
802 if (transfer
->Submit(weak_factory_
.GetWeakPtr())) {
803 // Transfer is now owned by libusb until its completion callback is run.
804 // This object holds a weak reference.
805 transfers_
.insert(transfer
.release());
808 transfer
->Complete(USB_TRANSFER_DISCONNECT
, 0);
812 void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr
<Transfer
> transfer
) {
813 DCHECK(ContainsKey(transfers_
, transfer
.get()))
814 << "Missing transfer completed";
815 transfers_
.erase(transfer
.get());
816 transfer
->ProcessCompletion();
819 bool UsbDeviceHandleImpl::GetSupportedLanguages() {
820 if (!languages_
.empty()) {
824 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s).
825 uint16 languages
[128];
826 int size
= libusb_get_string_descriptor(
830 reinterpret_cast<unsigned char*>(&languages
[0]),
833 USB_LOG(EVENT
) << "Failed to get list of supported languages: "
834 << ConvertPlatformUsbErrorToString(size
);
836 } else if (size
< 2) {
837 USB_LOG(EVENT
) << "String descriptor zero has no header.";
839 // The first 2 bytes of the descriptor are the total length and type tag.
840 } else if ((languages
[0] & 0xff) != size
) {
841 USB_LOG(EVENT
) << "String descriptor zero size mismatch: "
842 << (languages
[0] & 0xff) << " != " << size
;
844 } else if ((languages
[0] >> 8) != LIBUSB_DT_STRING
) {
845 USB_LOG(EVENT
) << "String descriptor zero is not a string descriptor.";
849 languages_
.assign(languages
[1], languages
[(size
- 2) / 2]);
853 void UsbDeviceHandleImpl::InternalClose() {
854 DCHECK(thread_checker_
.CalledOnValidThread());
858 // Cancel all the transfers.
859 for (Transfer
* transfer
: transfers_
) {
860 // The callback will be called some time later.
864 // Attempt-release all the interfaces.
865 // It will be retained until the transfer cancellation is finished.
866 claimed_interfaces_
.clear();
868 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
873 } // namespace device