Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blobd52337901ac63ee6e2a77c7bd952125c76c6d5a2
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"
7 #include <algorithm>
8 #include <vector>
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"
25 namespace device {
27 typedef libusb_device* PlatformUsbDevice;
29 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
31 namespace {
33 static uint8 ConvertTransferDirection(const UsbEndpointDirection direction) {
34 switch (direction) {
35 case USB_DIRECTION_INBOUND:
36 return LIBUSB_ENDPOINT_IN;
37 case USB_DIRECTION_OUTBOUND:
38 return LIBUSB_ENDPOINT_OUT;
39 default:
40 NOTREACHED();
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;
54 break;
55 case UsbDeviceHandle::CLASS:
56 result |= LIBUSB_REQUEST_TYPE_CLASS;
57 break;
58 case UsbDeviceHandle::VENDOR:
59 result |= LIBUSB_REQUEST_TYPE_VENDOR;
60 break;
61 case UsbDeviceHandle::RESERVED:
62 result |= LIBUSB_REQUEST_TYPE_RESERVED;
63 break;
66 switch (recipient) {
67 case UsbDeviceHandle::DEVICE:
68 result |= LIBUSB_RECIPIENT_DEVICE;
69 break;
70 case UsbDeviceHandle::INTERFACE:
71 result |= LIBUSB_RECIPIENT_INTERFACE;
72 break;
73 case UsbDeviceHandle::ENDPOINT:
74 result |= LIBUSB_RECIPIENT_ENDPOINT;
75 break;
76 case UsbDeviceHandle::OTHER:
77 result |= LIBUSB_RECIPIENT_OTHER;
78 break;
81 return result;
84 static UsbTransferStatus ConvertTransferStatus(
85 const libusb_transfer_status status) {
86 switch (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;
101 default:
102 NOTREACHED();
103 return USB_TRANSFER_ERROR;
107 static void RunTransferCallback(
108 scoped_refptr<base::TaskRunner> callback_task_runner,
109 const UsbDeviceHandle::TransferCallback& callback,
110 UsbTransferStatus status,
111 scoped_refptr<net::IOBuffer> buffer,
112 size_t result) {
113 if (callback_task_runner->RunsTasksOnCurrentThread()) {
114 callback.Run(status, buffer, result);
115 } else {
116 callback_task_runner->PostTask(
117 FROM_HERE, base::Bind(callback, status, buffer, result));
121 } // namespace
123 class UsbDeviceHandleImpl::InterfaceClaimer
124 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> {
125 public:
126 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle,
127 const int interface_number);
129 bool Claim() const;
131 int alternate_setting() const { return alternate_setting_; }
132 void set_alternate_setting(const int alternate_setting) {
133 alternate_setting_ = alternate_setting;
136 private:
137 friend class UsbDevice;
138 friend class base::RefCountedThreadSafe<InterfaceClaimer>;
139 ~InterfaceClaimer();
141 const scoped_refptr<UsbDeviceHandleImpl> handle_;
142 const int interface_number_;
143 int alternate_setting_;
145 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
148 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer(
149 const scoped_refptr<UsbDeviceHandleImpl> handle,
150 const int interface_number)
151 : handle_(handle),
152 interface_number_(interface_number),
153 alternate_setting_(0) {
156 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() {
157 libusb_release_interface(handle_->handle(), interface_number_);
160 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const {
161 const int rv = libusb_claim_interface(handle_->handle(), interface_number_);
162 if (rv != LIBUSB_SUCCESS) {
163 USB_LOG(EVENT) << "Failed to claim interface " << interface_number_ << ": "
164 << ConvertPlatformUsbErrorToString(rv);
166 return rv == LIBUSB_SUCCESS;
169 // This inner class owns the underlying libusb_transfer and may outlast
170 // the UsbDeviceHandle that created it.
171 class UsbDeviceHandleImpl::Transfer {
172 public:
173 static scoped_ptr<Transfer> CreateControlTransfer(
174 scoped_refptr<UsbDeviceHandleImpl> device_handle,
175 uint8 type,
176 uint8 request,
177 uint16 value,
178 uint16 index,
179 uint16 length,
180 scoped_refptr<net::IOBuffer> buffer,
181 unsigned int timeout,
182 scoped_refptr<base::TaskRunner> callback_task_runner,
183 const TransferCallback& callback);
184 static scoped_ptr<Transfer> CreateBulkTransfer(
185 scoped_refptr<UsbDeviceHandleImpl> device_handle,
186 uint8 endpoint,
187 scoped_refptr<net::IOBuffer> buffer,
188 int length,
189 unsigned int timeout,
190 scoped_refptr<base::TaskRunner> callback_task_runner,
191 const TransferCallback& callback);
192 static scoped_ptr<Transfer> CreateInterruptTransfer(
193 scoped_refptr<UsbDeviceHandleImpl> device_handle,
194 uint8 endpoint,
195 scoped_refptr<net::IOBuffer> buffer,
196 int length,
197 unsigned int timeout,
198 scoped_refptr<base::TaskRunner> callback_task_runner,
199 const TransferCallback& callback);
200 static scoped_ptr<Transfer> CreateIsochronousTransfer(
201 scoped_refptr<UsbDeviceHandleImpl> device_handle,
202 uint8 endpoint,
203 scoped_refptr<net::IOBuffer> buffer,
204 size_t length,
205 unsigned int packets,
206 unsigned int packet_length,
207 unsigned int timeout,
208 scoped_refptr<base::TaskRunner> task_runner,
209 const TransferCallback& callback);
211 ~Transfer();
213 void Submit();
214 void Cancel();
215 void ProcessCompletion();
216 void TransferComplete(UsbTransferStatus status, size_t bytes_transferred);
218 const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
219 return claimed_interface_.get();
222 scoped_refptr<base::TaskRunner> callback_task_runner() const {
223 return callback_task_runner_;
226 private:
227 Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
228 scoped_refptr<InterfaceClaimer> claimed_interface,
229 UsbTransferType transfer_type,
230 scoped_refptr<net::IOBuffer> buffer,
231 size_t length,
232 scoped_refptr<base::TaskRunner> callback_task_runner,
233 const TransferCallback& callback);
235 static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
237 UsbTransferType transfer_type_;
238 scoped_refptr<UsbDeviceHandleImpl> device_handle_;
239 PlatformUsbTransferHandle platform_transfer_ = nullptr;
240 scoped_refptr<net::IOBuffer> buffer_;
241 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
242 size_t length_;
243 bool cancelled_ = false;
244 scoped_refptr<base::SequencedTaskRunner> task_runner_;
245 scoped_refptr<base::TaskRunner> callback_task_runner_;
246 TransferCallback callback_;
249 // static
250 scoped_ptr<UsbDeviceHandleImpl::Transfer>
251 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
252 scoped_refptr<UsbDeviceHandleImpl> device_handle,
253 uint8 type,
254 uint8 request,
255 uint16 value,
256 uint16 index,
257 uint16 length,
258 scoped_refptr<net::IOBuffer> buffer,
259 unsigned int timeout,
260 scoped_refptr<base::TaskRunner> callback_task_runner,
261 const TransferCallback& callback) {
262 scoped_ptr<Transfer> transfer(new Transfer(
263 device_handle, nullptr, USB_TRANSFER_CONTROL, buffer,
264 length + LIBUSB_CONTROL_SETUP_SIZE, callback_task_runner, callback));
266 transfer->platform_transfer_ = libusb_alloc_transfer(0);
267 if (!transfer->platform_transfer_) {
268 USB_LOG(ERROR) << "Failed to allocate control transfer.";
269 return nullptr;
272 libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
273 request, value, index, length);
274 libusb_fill_control_transfer(transfer->platform_transfer_,
275 device_handle->handle_,
276 reinterpret_cast<uint8*>(buffer->data()),
277 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
278 transfer.get(), timeout);
280 return transfer.Pass();
283 // static
284 scoped_ptr<UsbDeviceHandleImpl::Transfer>
285 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
286 scoped_refptr<UsbDeviceHandleImpl> device_handle,
287 uint8 endpoint,
288 scoped_refptr<net::IOBuffer> buffer,
289 int length,
290 unsigned int timeout,
291 scoped_refptr<base::TaskRunner> callback_task_runner,
292 const TransferCallback& callback) {
293 scoped_ptr<Transfer> transfer(new Transfer(
294 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
295 USB_TRANSFER_BULK, buffer, length, callback_task_runner, callback));
297 transfer->platform_transfer_ = libusb_alloc_transfer(0);
298 if (!transfer->platform_transfer_) {
299 USB_LOG(ERROR) << "Failed to allocate bulk transfer.";
300 return nullptr;
303 libusb_fill_bulk_transfer(
304 transfer->platform_transfer_, device_handle->handle_, endpoint,
305 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
306 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
307 timeout);
309 return transfer.Pass();
312 // static
313 scoped_ptr<UsbDeviceHandleImpl::Transfer>
314 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
315 scoped_refptr<UsbDeviceHandleImpl> device_handle,
316 uint8 endpoint,
317 scoped_refptr<net::IOBuffer> buffer,
318 int length,
319 unsigned int timeout,
320 scoped_refptr<base::TaskRunner> callback_task_runner,
321 const TransferCallback& callback) {
322 scoped_ptr<Transfer> transfer(new Transfer(
323 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
324 USB_TRANSFER_INTERRUPT, buffer, length, callback_task_runner, callback));
326 transfer->platform_transfer_ = libusb_alloc_transfer(0);
327 if (!transfer->platform_transfer_) {
328 USB_LOG(ERROR) << "Failed to allocate interrupt transfer.";
329 return nullptr;
332 libusb_fill_interrupt_transfer(
333 transfer->platform_transfer_, device_handle->handle_, endpoint,
334 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
335 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
336 timeout);
338 return transfer.Pass();
341 // static
342 scoped_ptr<UsbDeviceHandleImpl::Transfer>
343 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
344 scoped_refptr<UsbDeviceHandleImpl> device_handle,
345 uint8 endpoint,
346 scoped_refptr<net::IOBuffer> buffer,
347 size_t length,
348 unsigned int packets,
349 unsigned int packet_length,
350 unsigned int timeout,
351 scoped_refptr<base::TaskRunner> callback_task_runner,
352 const TransferCallback& callback) {
353 DCHECK(packets <= length && (packets * packet_length) <= length)
354 << "transfer length is too small";
356 scoped_ptr<Transfer> transfer(new Transfer(
357 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
358 USB_TRANSFER_ISOCHRONOUS, buffer, length, callback_task_runner,
359 callback));
361 transfer->platform_transfer_ = libusb_alloc_transfer(packets);
362 if (!transfer->platform_transfer_) {
363 USB_LOG(ERROR) << "Failed to allocate isochronous transfer.";
364 return nullptr;
367 libusb_fill_iso_transfer(
368 transfer->platform_transfer_, device_handle->handle_, endpoint,
369 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
370 packets, &Transfer::PlatformCallback, transfer.get(), timeout);
371 libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
373 return transfer.Pass();
376 UsbDeviceHandleImpl::Transfer::Transfer(
377 scoped_refptr<UsbDeviceHandleImpl> device_handle,
378 scoped_refptr<InterfaceClaimer> claimed_interface,
379 UsbTransferType transfer_type,
380 scoped_refptr<net::IOBuffer> buffer,
381 size_t length,
382 scoped_refptr<base::TaskRunner> callback_task_runner,
383 const TransferCallback& callback)
384 : transfer_type_(transfer_type),
385 device_handle_(device_handle),
386 buffer_(buffer),
387 claimed_interface_(claimed_interface),
388 length_(length),
389 callback_task_runner_(callback_task_runner),
390 callback_(callback) {
391 task_runner_ = base::ThreadTaskRunnerHandle::Get();
394 UsbDeviceHandleImpl::Transfer::~Transfer() {
395 if (platform_transfer_) {
396 libusb_free_transfer(platform_transfer_);
400 void UsbDeviceHandleImpl::Transfer::Submit() {
401 const int rv = libusb_submit_transfer(platform_transfer_);
402 if (rv != LIBUSB_SUCCESS) {
403 USB_LOG(EVENT) << "Failed to submit transfer: "
404 << ConvertPlatformUsbErrorToString(rv);
405 TransferComplete(USB_TRANSFER_ERROR, 0);
409 void UsbDeviceHandleImpl::Transfer::Cancel() {
410 if (!cancelled_) {
411 libusb_cancel_transfer(platform_transfer_);
412 claimed_interface_ = nullptr;
414 cancelled_ = true;
417 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
418 DCHECK_GE(platform_transfer_->actual_length, 0)
419 << "Negative actual length received";
420 size_t actual_length =
421 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
423 DCHECK(length_ >= actual_length)
424 << "data too big for our buffer (libusb failure?)";
426 switch (transfer_type_) {
427 case USB_TRANSFER_CONTROL:
428 // If the transfer is a control transfer we do not expose the control
429 // setup header to the caller. This logic strips off the header if
430 // present before invoking the callback provided with the transfer.
431 if (actual_length > 0) {
432 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
433 << "buffer was not correctly set: too small for the control header";
435 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
436 // If the payload is zero bytes long, pad out the allocated buffer
437 // size to one byte so that an IOBuffer of that size can be allocated.
438 scoped_refptr<net::IOBuffer> resized_buffer =
439 new net::IOBuffer(static_cast<int>(
440 std::max(actual_length, static_cast<size_t>(1))));
441 memcpy(resized_buffer->data(),
442 buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
443 buffer_ = resized_buffer;
446 break;
448 case USB_TRANSFER_ISOCHRONOUS:
449 // Isochronous replies might carry data in the different isoc packets even
450 // if the transfer actual_data value is zero. Furthermore, not all of the
451 // received packets might contain data, so we need to calculate how many
452 // data bytes we are effectively providing and pack the results.
453 if (actual_length == 0) {
454 size_t packet_buffer_start = 0;
455 for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
456 PlatformUsbIsoPacketDescriptor packet =
457 &platform_transfer_->iso_packet_desc[i];
458 if (packet->actual_length > 0) {
459 // We don't need to copy as long as all packets until now provide
460 // all the data the packet can hold.
461 if (actual_length < packet_buffer_start) {
462 CHECK(packet_buffer_start + packet->actual_length <= length_);
463 memmove(buffer_->data() + actual_length,
464 buffer_->data() + packet_buffer_start,
465 packet->actual_length);
467 actual_length += packet->actual_length;
470 packet_buffer_start += packet->length;
473 break;
475 case USB_TRANSFER_BULK:
476 case USB_TRANSFER_INTERRUPT:
477 break;
479 default:
480 NOTREACHED() << "Invalid usb transfer type";
481 break;
484 TransferComplete(ConvertTransferStatus(platform_transfer_->status),
485 actual_length);
488 /* static */
489 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
490 PlatformUsbTransferHandle platform_transfer) {
491 Transfer* transfer =
492 reinterpret_cast<Transfer*>(platform_transfer->user_data);
493 DCHECK(transfer->platform_transfer_ == platform_transfer);
494 transfer->ProcessCompletion();
497 void UsbDeviceHandleImpl::Transfer::TransferComplete(UsbTransferStatus status,
498 size_t bytes_transferred) {
499 task_runner_->PostTask(
500 FROM_HERE,
501 base::Bind(&UsbDeviceHandleImpl::TransferComplete, device_handle_,
502 base::Unretained(this),
503 base::Bind(callback_, status, buffer_, bytes_transferred)));
506 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
507 return device_;
510 void UsbDeviceHandleImpl::Close() {
511 DCHECK(thread_checker_.CalledOnValidThread());
512 if (device_)
513 device_->Close(this);
516 void UsbDeviceHandleImpl::SetConfiguration(int configuration_value,
517 const ResultCallback& callback) {
518 DCHECK(thread_checker_.CalledOnValidThread());
519 if (!device_) {
520 callback.Run(false);
521 return;
524 for (Transfer* transfer : transfers_) {
525 transfer->Cancel();
527 claimed_interfaces_.clear();
529 blocking_task_runner_->PostTask(
530 FROM_HERE,
531 base::Bind(&UsbDeviceHandleImpl::SetConfigurationOnBlockingThread, this,
532 configuration_value, callback));
535 void UsbDeviceHandleImpl::ClaimInterface(int interface_number,
536 const ResultCallback& callback) {
537 DCHECK(thread_checker_.CalledOnValidThread());
538 if (!device_) {
539 callback.Run(false);
540 return;
542 if (ContainsKey(claimed_interfaces_, interface_number)) {
543 callback.Run(true);
544 return;
547 blocking_task_runner_->PostTask(
548 FROM_HERE,
549 base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread, this,
550 interface_number, callback));
553 bool UsbDeviceHandleImpl::ReleaseInterface(int interface_number) {
554 DCHECK(thread_checker_.CalledOnValidThread());
555 if (!device_)
556 return false;
557 if (!ContainsKey(claimed_interfaces_, interface_number))
558 return false;
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) {
565 transfer->Cancel();
568 claimed_interfaces_.erase(interface_number);
570 RefreshEndpointMap();
571 return true;
574 void UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
575 int interface_number,
576 int alternate_setting,
577 const ResultCallback& callback) {
578 DCHECK(thread_checker_.CalledOnValidThread());
579 if (!device_ || !ContainsKey(claimed_interfaces_, interface_number)) {
580 callback.Run(false);
581 return;
584 blocking_task_runner_->PostTask(
585 FROM_HERE,
586 base::Bind(
587 &UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread,
588 this, interface_number, alternate_setting, callback));
591 void UsbDeviceHandleImpl::ResetDevice(const ResultCallback& callback) {
592 DCHECK(thread_checker_.CalledOnValidThread());
593 if (!device_) {
594 callback.Run(false);
595 return;
598 blocking_task_runner_->PostTask(
599 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ResetDeviceOnBlockingThread,
600 this, callback));
603 void UsbDeviceHandleImpl::ClearHalt(uint8 endpoint,
604 const ResultCallback& callback) {
605 DCHECK(thread_checker_.CalledOnValidThread());
606 if (!device_) {
607 callback.Run(false);
608 return;
611 InterfaceClaimer* interface_claimer =
612 GetClaimedInterfaceForEndpoint(endpoint).get();
613 for (Transfer* transfer : transfers_) {
614 if (transfer->claimed_interface() == interface_claimer) {
615 transfer->Cancel();
619 blocking_task_runner_->PostTask(
620 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClearHaltOnBlockingThread,
621 this, endpoint, callback));
624 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
625 TransferRequestType request_type,
626 TransferRecipient recipient,
627 uint8 request,
628 uint16 value,
629 uint16 index,
630 scoped_refptr<net::IOBuffer> buffer,
631 size_t length,
632 unsigned int timeout,
633 const TransferCallback& callback) {
634 if (task_runner_->BelongsToCurrentThread()) {
635 ControlTransferInternal(direction, request_type, recipient, request, value,
636 index, buffer, length, timeout, task_runner_,
637 callback);
638 } else {
639 task_runner_->PostTask(
640 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ControlTransferInternal,
641 this, direction, request_type, recipient, request,
642 value, index, buffer, length, timeout,
643 base::ThreadTaskRunnerHandle::Get(), callback));
647 void UsbDeviceHandleImpl::IsochronousTransfer(
648 UsbEndpointDirection direction,
649 uint8 endpoint,
650 scoped_refptr<net::IOBuffer> buffer,
651 size_t length,
652 unsigned int packets,
653 unsigned int packet_length,
654 unsigned int timeout,
655 const TransferCallback& callback) {
656 if (task_runner_->BelongsToCurrentThread()) {
657 IsochronousTransferInternal(direction, endpoint, buffer, length, packets,
658 packet_length, timeout, task_runner_, callback);
659 } else {
660 task_runner_->PostTask(
661 FROM_HERE,
662 base::Bind(&UsbDeviceHandleImpl::IsochronousTransferInternal, this,
663 direction, endpoint, buffer, length, packets, packet_length,
664 timeout, base::ThreadTaskRunnerHandle::Get(), callback));
668 void UsbDeviceHandleImpl::GenericTransfer(UsbEndpointDirection direction,
669 uint8 endpoint,
670 scoped_refptr<net::IOBuffer> buffer,
671 size_t length,
672 unsigned int timeout,
673 const TransferCallback& callback) {
674 if (task_runner_->BelongsToCurrentThread()) {
675 GenericTransferInternal(direction, endpoint, buffer, length, timeout,
676 task_runner_, callback);
677 } else {
678 task_runner_->PostTask(
679 FROM_HERE,
680 base::Bind(&UsbDeviceHandleImpl::GenericTransferInternal, this,
681 direction, endpoint, buffer, length, timeout,
682 base::ThreadTaskRunnerHandle::Get(), callback));
686 UsbDeviceHandleImpl::UsbDeviceHandleImpl(
687 scoped_refptr<UsbContext> context,
688 scoped_refptr<UsbDeviceImpl> device,
689 PlatformUsbDeviceHandle handle,
690 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
691 : device_(device),
692 handle_(handle),
693 context_(context),
694 task_runner_(base::ThreadTaskRunnerHandle::Get()),
695 blocking_task_runner_(blocking_task_runner) {
696 DCHECK(handle) << "Cannot create device with NULL handle.";
699 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
700 // This class is RefCountedThreadSafe and so the destructor may be called on
701 // any thread.
702 libusb_close(handle_);
705 void UsbDeviceHandleImpl::SetConfigurationOnBlockingThread(
706 int configuration_value,
707 const ResultCallback& callback) {
708 int rv = libusb_set_configuration(handle_, configuration_value);
709 if (rv != LIBUSB_SUCCESS) {
710 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
711 << ": " << ConvertPlatformUsbErrorToString(rv);
713 task_runner_->PostTask(
714 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SetConfigurationComplete,
715 this, rv == LIBUSB_SUCCESS, callback));
718 void UsbDeviceHandleImpl::SetConfigurationComplete(
719 bool success,
720 const ResultCallback& callback) {
721 if (success) {
722 device_->RefreshActiveConfiguration();
723 RefreshEndpointMap();
725 callback.Run(success);
728 void UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread(
729 int interface_number,
730 const ResultCallback& callback) {
731 int rv = libusb_claim_interface(handle_, interface_number);
732 if (rv != LIBUSB_SUCCESS) {
733 VLOG(1) << "Failed to claim interface: "
734 << ConvertPlatformUsbErrorToString(rv);
736 task_runner_->PostTask(
737 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceComplete, this,
738 interface_number, rv == LIBUSB_SUCCESS, callback));
741 void UsbDeviceHandleImpl::ClaimInterfaceComplete(
742 int interface_number,
743 bool success,
744 const ResultCallback& callback) {
745 if (success) {
746 claimed_interfaces_[interface_number] =
747 new InterfaceClaimer(this, interface_number);
748 RefreshEndpointMap();
750 callback.Run(success);
753 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread(
754 int interface_number,
755 int alternate_setting,
756 const ResultCallback& callback) {
757 int rv = libusb_set_interface_alt_setting(handle_, interface_number,
758 alternate_setting);
759 if (rv != LIBUSB_SUCCESS) {
760 USB_LOG(EVENT) << "Failed to set interface " << interface_number
761 << " to alternate setting " << alternate_setting << ": "
762 << ConvertPlatformUsbErrorToString(rv);
764 task_runner_->PostTask(
765 FROM_HERE,
766 base::Bind(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
767 this, interface_number, alternate_setting,
768 rv == LIBUSB_SUCCESS, callback));
771 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
772 int interface_number,
773 int alternate_setting,
774 bool success,
775 const ResultCallback& callback) {
776 if (success) {
777 claimed_interfaces_[interface_number]->set_alternate_setting(
778 alternate_setting);
779 RefreshEndpointMap();
781 callback.Run(success);
784 void UsbDeviceHandleImpl::ResetDeviceOnBlockingThread(
785 const ResultCallback& callback) {
786 int rv = libusb_reset_device(handle_);
787 if (rv != LIBUSB_SUCCESS) {
788 USB_LOG(EVENT) << "Failed to reset device: "
789 << ConvertPlatformUsbErrorToString(rv);
791 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rv == LIBUSB_SUCCESS));
794 void UsbDeviceHandleImpl::ClearHaltOnBlockingThread(
795 uint8 endpoint,
796 const ResultCallback& callback) {
797 int rv = libusb_clear_halt(handle_, endpoint);
798 if (rv != LIBUSB_SUCCESS) {
799 USB_LOG(EVENT) << "Failed to clear halt: "
800 << ConvertPlatformUsbErrorToString(rv);
802 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rv == LIBUSB_SUCCESS));
805 void UsbDeviceHandleImpl::RefreshEndpointMap() {
806 DCHECK(thread_checker_.CalledOnValidThread());
807 endpoint_map_.clear();
808 const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
809 if (config) {
810 for (const auto& map_entry : claimed_interfaces_) {
811 int interface_number = map_entry.first;
812 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
814 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
815 if (iface.interface_number == interface_number &&
816 iface.alternate_setting == claimed_iface->alternate_setting()) {
817 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
818 endpoint_map_[endpoint.address] = {interface_number,
819 endpoint.transfer_type};
821 break;
828 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
829 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(uint8 endpoint) {
830 if (ContainsKey(endpoint_map_, endpoint))
831 return claimed_interfaces_[endpoint_map_[endpoint].interface_number];
832 return NULL;
835 void UsbDeviceHandleImpl::ControlTransferInternal(
836 UsbEndpointDirection direction,
837 TransferRequestType request_type,
838 TransferRecipient recipient,
839 uint8 request,
840 uint16 value,
841 uint16 index,
842 scoped_refptr<net::IOBuffer> buffer,
843 size_t length,
844 unsigned int timeout,
845 scoped_refptr<base::TaskRunner> callback_task_runner,
846 const TransferCallback& callback) {
847 DCHECK(thread_checker_.CalledOnValidThread());
849 if (!device_) {
850 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_DISCONNECT,
851 buffer, 0);
852 return;
855 if (length > UINT16_MAX) {
856 USB_LOG(USER) << "Transfer too long.";
857 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
858 buffer, 0);
859 return;
862 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
863 scoped_refptr<net::IOBuffer> resized_buffer(
864 new net::IOBufferWithSize(static_cast<int>(resized_length)));
865 if (!resized_buffer.get()) {
866 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
867 buffer, 0);
868 return;
870 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
871 length);
873 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
874 this, CreateRequestType(direction, request_type, recipient), request,
875 value, index, static_cast<uint16>(length), resized_buffer, timeout,
876 callback_task_runner, callback);
877 if (!transfer) {
878 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
879 buffer, 0);
880 return;
883 SubmitTransfer(transfer.Pass());
886 void UsbDeviceHandleImpl::BulkTransferInternal(
887 const UsbEndpointDirection direction,
888 const uint8 endpoint,
889 scoped_refptr<net::IOBuffer> buffer,
890 const size_t length,
891 const unsigned int timeout,
892 scoped_refptr<base::TaskRunner> callback_task_runner,
893 const TransferCallback& callback) {
894 DCHECK(thread_checker_.CalledOnValidThread());
896 if (!device_) {
897 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_DISCONNECT,
898 buffer, 0);
899 return;
902 if (length > INT_MAX) {
903 USB_LOG(USER) << "Transfer too long.";
904 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
905 buffer, 0);
906 return;
909 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
910 this, ConvertTransferDirection(direction) | endpoint, buffer,
911 static_cast<int>(length), timeout, callback_task_runner, callback);
913 SubmitTransfer(transfer.Pass());
916 void UsbDeviceHandleImpl::InterruptTransferInternal(
917 UsbEndpointDirection direction,
918 uint8 endpoint,
919 scoped_refptr<net::IOBuffer> buffer,
920 size_t length,
921 unsigned int timeout,
922 scoped_refptr<base::TaskRunner> callback_task_runner,
923 const TransferCallback& callback) {
924 DCHECK(thread_checker_.CalledOnValidThread());
926 if (!device_) {
927 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_DISCONNECT,
928 buffer, 0);
929 return;
932 if (length > INT_MAX) {
933 USB_LOG(USER) << "Transfer too long.";
934 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
935 buffer, 0);
936 return;
939 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
940 this, ConvertTransferDirection(direction) | endpoint, buffer,
941 static_cast<int>(length), timeout, callback_task_runner, callback);
943 SubmitTransfer(transfer.Pass());
946 void UsbDeviceHandleImpl::IsochronousTransferInternal(
947 const UsbEndpointDirection direction,
948 uint8 endpoint,
949 scoped_refptr<net::IOBuffer> buffer,
950 size_t length,
951 unsigned int packets,
952 unsigned int packet_length,
953 unsigned int timeout,
954 scoped_refptr<base::TaskRunner> callback_task_runner,
955 const TransferCallback& callback) {
956 DCHECK(thread_checker_.CalledOnValidThread());
958 if (!device_) {
959 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_DISCONNECT,
960 buffer, 0);
961 return;
964 if (length > INT_MAX) {
965 USB_LOG(USER) << "Transfer too long.";
966 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
967 buffer, 0);
968 return;
971 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
972 this, ConvertTransferDirection(direction) | endpoint, buffer,
973 static_cast<int>(length), packets, packet_length, timeout,
974 callback_task_runner, callback);
976 SubmitTransfer(transfer.Pass());
979 void UsbDeviceHandleImpl::GenericTransferInternal(
980 UsbEndpointDirection direction,
981 uint8 endpoint,
982 scoped_refptr<net::IOBuffer> buffer,
983 size_t length,
984 unsigned int timeout,
985 scoped_refptr<base::TaskRunner> callback_task_runner,
986 const TransferCallback& callback) {
987 if (!ContainsKey(endpoint_map_, endpoint)) {
988 USB_LOG(DEBUG)
989 << "Failed to do generic transfer since endpoint not in endpoint_map_.";
990 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
991 buffer, 0);
992 return;
995 UsbTransferType transfer_type = endpoint_map_[endpoint].transfer_type;
996 if (transfer_type == USB_TRANSFER_BULK) {
997 BulkTransferInternal(direction, endpoint, buffer, length, timeout,
998 callback_task_runner, callback);
999 } else if (transfer_type == USB_TRANSFER_INTERRUPT) {
1000 InterruptTransferInternal(direction, endpoint, buffer, length, timeout,
1001 callback_task_runner, callback);
1002 } else {
1003 USB_LOG(DEBUG)
1004 << "Failed to do generic transfer since transfer_type is not "
1005 "bulk or interrupt.";
1006 RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
1007 buffer, 0);
1011 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
1012 DCHECK(thread_checker_.CalledOnValidThread());
1014 // Transfer is owned by libusb until its completion callback is run. This
1015 // object holds a weak reference.
1016 transfers_.insert(transfer.get());
1017 blocking_task_runner_->PostTask(
1018 FROM_HERE,
1019 base::Bind(&Transfer::Submit, base::Unretained(transfer.release())));
1022 void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
1023 const base::Closure& callback) {
1024 DCHECK(thread_checker_.CalledOnValidThread());
1025 DCHECK(ContainsKey(transfers_, transfer)) << "Missing transfer completed";
1026 transfers_.erase(transfer);
1028 if (transfer->callback_task_runner()->RunsTasksOnCurrentThread()) {
1029 callback.Run();
1030 } else {
1031 transfer->callback_task_runner()->PostTask(FROM_HERE, callback);
1034 // libusb_free_transfer races with libusb_submit_transfer and only work-
1035 // around is to make sure to call them on the same thread.
1036 blocking_task_runner_->DeleteSoon(FROM_HERE, transfer);
1039 void UsbDeviceHandleImpl::InternalClose() {
1040 DCHECK(thread_checker_.CalledOnValidThread());
1041 if (!device_)
1042 return;
1044 // Cancel all the transfers.
1045 for (Transfer* transfer : transfers_) {
1046 // The callback will be called some time later.
1047 transfer->Cancel();
1050 // Attempt-release all the interfaces.
1051 // It will be retained until the transfer cancellation is finished.
1052 claimed_interfaces_.clear();
1054 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
1055 // finish.
1056 device_ = NULL;
1059 } // namespace device