Extensions: Store disable reasons in Sync
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blobbd53ada53288f2645b5207de329d9c69c8bfded7
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 } // namespace
109 class UsbDeviceHandleImpl::InterfaceClaimer
110 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> {
111 public:
112 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle,
113 const int interface_number);
115 bool Claim() const;
117 int alternate_setting() const { return alternate_setting_; }
118 void set_alternate_setting(const int alternate_setting) {
119 alternate_setting_ = alternate_setting;
122 private:
123 friend class UsbDevice;
124 friend class base::RefCountedThreadSafe<InterfaceClaimer>;
125 ~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)
137 : handle_(handle),
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 {
158 public:
159 static scoped_ptr<Transfer> CreateControlTransfer(
160 scoped_refptr<UsbDeviceHandleImpl> device_handle,
161 uint8 type,
162 uint8 request,
163 uint16 value,
164 uint16 index,
165 uint16 length,
166 scoped_refptr<net::IOBuffer> buffer,
167 unsigned int timeout,
168 scoped_refptr<base::TaskRunner> callback_task_runner,
169 const TransferCallback& callback);
170 static scoped_ptr<Transfer> CreateBulkTransfer(
171 scoped_refptr<UsbDeviceHandleImpl> device_handle,
172 uint8 endpoint,
173 scoped_refptr<net::IOBuffer> buffer,
174 int length,
175 unsigned int timeout,
176 scoped_refptr<base::TaskRunner> callback_task_runner,
177 const TransferCallback& callback);
178 static scoped_ptr<Transfer> CreateInterruptTransfer(
179 scoped_refptr<UsbDeviceHandleImpl> device_handle,
180 uint8 endpoint,
181 scoped_refptr<net::IOBuffer> buffer,
182 int length,
183 unsigned int timeout,
184 scoped_refptr<base::TaskRunner> callback_task_runner,
185 const TransferCallback& callback);
186 static scoped_ptr<Transfer> CreateIsochronousTransfer(
187 scoped_refptr<UsbDeviceHandleImpl> device_handle,
188 uint8 endpoint,
189 scoped_refptr<net::IOBuffer> buffer,
190 size_t length,
191 unsigned int packets,
192 unsigned int packet_length,
193 unsigned int timeout,
194 scoped_refptr<base::TaskRunner> task_runner,
195 const TransferCallback& callback);
197 ~Transfer();
199 void Submit();
200 void Cancel();
201 void ProcessCompletion();
202 void TransferComplete(UsbTransferStatus status, size_t bytes_transferred);
204 const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
205 return claimed_interface_.get();
208 scoped_refptr<base::TaskRunner> callback_task_runner() const {
209 return callback_task_runner_;
212 private:
213 Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
214 scoped_refptr<InterfaceClaimer> claimed_interface,
215 UsbTransferType transfer_type,
216 scoped_refptr<net::IOBuffer> buffer,
217 size_t length,
218 scoped_refptr<base::TaskRunner> callback_task_runner,
219 const TransferCallback& callback);
221 static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
223 UsbTransferType transfer_type_;
224 scoped_refptr<UsbDeviceHandleImpl> device_handle_;
225 PlatformUsbTransferHandle platform_transfer_ = nullptr;
226 scoped_refptr<net::IOBuffer> buffer_;
227 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
228 size_t length_;
229 bool cancelled_ = false;
230 scoped_refptr<base::SequencedTaskRunner> task_runner_;
231 scoped_refptr<base::TaskRunner> callback_task_runner_;
232 TransferCallback callback_;
235 // static
236 scoped_ptr<UsbDeviceHandleImpl::Transfer>
237 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
238 scoped_refptr<UsbDeviceHandleImpl> device_handle,
239 uint8 type,
240 uint8 request,
241 uint16 value,
242 uint16 index,
243 uint16 length,
244 scoped_refptr<net::IOBuffer> buffer,
245 unsigned int timeout,
246 scoped_refptr<base::TaskRunner> callback_task_runner,
247 const TransferCallback& callback) {
248 scoped_ptr<Transfer> transfer(new Transfer(
249 device_handle, nullptr, USB_TRANSFER_CONTROL, buffer,
250 length + LIBUSB_CONTROL_SETUP_SIZE, callback_task_runner, callback));
252 transfer->platform_transfer_ = libusb_alloc_transfer(0);
253 if (!transfer->platform_transfer_) {
254 USB_LOG(ERROR) << "Failed to allocate control transfer.";
255 return nullptr;
258 libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
259 request, value, index, length);
260 libusb_fill_control_transfer(transfer->platform_transfer_,
261 device_handle->handle_,
262 reinterpret_cast<uint8*>(buffer->data()),
263 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
264 transfer.get(), timeout);
266 return transfer.Pass();
269 // static
270 scoped_ptr<UsbDeviceHandleImpl::Transfer>
271 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
272 scoped_refptr<UsbDeviceHandleImpl> device_handle,
273 uint8 endpoint,
274 scoped_refptr<net::IOBuffer> buffer,
275 int length,
276 unsigned int timeout,
277 scoped_refptr<base::TaskRunner> callback_task_runner,
278 const TransferCallback& callback) {
279 scoped_ptr<Transfer> transfer(new Transfer(
280 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
281 USB_TRANSFER_BULK, buffer, length, callback_task_runner, callback));
283 transfer->platform_transfer_ = libusb_alloc_transfer(0);
284 if (!transfer->platform_transfer_) {
285 USB_LOG(ERROR) << "Failed to allocate bulk transfer.";
286 return nullptr;
289 libusb_fill_bulk_transfer(
290 transfer->platform_transfer_, device_handle->handle_, endpoint,
291 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
292 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
293 timeout);
295 return transfer.Pass();
298 // static
299 scoped_ptr<UsbDeviceHandleImpl::Transfer>
300 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
301 scoped_refptr<UsbDeviceHandleImpl> device_handle,
302 uint8 endpoint,
303 scoped_refptr<net::IOBuffer> buffer,
304 int length,
305 unsigned int timeout,
306 scoped_refptr<base::TaskRunner> callback_task_runner,
307 const TransferCallback& callback) {
308 scoped_ptr<Transfer> transfer(new Transfer(
309 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
310 USB_TRANSFER_INTERRUPT, buffer, length, callback_task_runner, callback));
312 transfer->platform_transfer_ = libusb_alloc_transfer(0);
313 if (!transfer->platform_transfer_) {
314 USB_LOG(ERROR) << "Failed to allocate interrupt transfer.";
315 return nullptr;
318 libusb_fill_interrupt_transfer(
319 transfer->platform_transfer_, device_handle->handle_, endpoint,
320 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
321 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
322 timeout);
324 return transfer.Pass();
327 // static
328 scoped_ptr<UsbDeviceHandleImpl::Transfer>
329 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
330 scoped_refptr<UsbDeviceHandleImpl> device_handle,
331 uint8 endpoint,
332 scoped_refptr<net::IOBuffer> buffer,
333 size_t length,
334 unsigned int packets,
335 unsigned int packet_length,
336 unsigned int timeout,
337 scoped_refptr<base::TaskRunner> callback_task_runner,
338 const TransferCallback& callback) {
339 DCHECK(packets <= length && (packets * packet_length) <= length)
340 << "transfer length is too small";
342 scoped_ptr<Transfer> transfer(new Transfer(
343 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
344 USB_TRANSFER_ISOCHRONOUS, buffer, length, callback_task_runner,
345 callback));
347 transfer->platform_transfer_ = libusb_alloc_transfer(packets);
348 if (!transfer->platform_transfer_) {
349 USB_LOG(ERROR) << "Failed to allocate isochronous transfer.";
350 return nullptr;
353 libusb_fill_iso_transfer(
354 transfer->platform_transfer_, device_handle->handle_, endpoint,
355 reinterpret_cast<uint8*>(buffer->data()), static_cast<int>(length),
356 packets, &Transfer::PlatformCallback, transfer.get(), timeout);
357 libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
359 return transfer.Pass();
362 UsbDeviceHandleImpl::Transfer::Transfer(
363 scoped_refptr<UsbDeviceHandleImpl> device_handle,
364 scoped_refptr<InterfaceClaimer> claimed_interface,
365 UsbTransferType transfer_type,
366 scoped_refptr<net::IOBuffer> buffer,
367 size_t length,
368 scoped_refptr<base::TaskRunner> callback_task_runner,
369 const TransferCallback& callback)
370 : transfer_type_(transfer_type),
371 device_handle_(device_handle),
372 buffer_(buffer),
373 claimed_interface_(claimed_interface),
374 length_(length),
375 callback_task_runner_(callback_task_runner),
376 callback_(callback) {
377 task_runner_ = base::ThreadTaskRunnerHandle::Get();
380 UsbDeviceHandleImpl::Transfer::~Transfer() {
381 if (platform_transfer_) {
382 libusb_free_transfer(platform_transfer_);
386 void UsbDeviceHandleImpl::Transfer::Submit() {
387 const int rv = libusb_submit_transfer(platform_transfer_);
388 if (rv != LIBUSB_SUCCESS) {
389 USB_LOG(EVENT) << "Failed to submit transfer: "
390 << ConvertPlatformUsbErrorToString(rv);
391 TransferComplete(USB_TRANSFER_ERROR, 0);
395 void UsbDeviceHandleImpl::Transfer::Cancel() {
396 if (!cancelled_) {
397 libusb_cancel_transfer(platform_transfer_);
398 claimed_interface_ = nullptr;
400 cancelled_ = true;
403 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
404 DCHECK_GE(platform_transfer_->actual_length, 0)
405 << "Negative actual length received";
406 size_t actual_length =
407 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
409 DCHECK(length_ >= actual_length)
410 << "data too big for our buffer (libusb failure?)";
412 switch (transfer_type_) {
413 case USB_TRANSFER_CONTROL:
414 // If the transfer is a control transfer we do not expose the control
415 // setup header to the caller. This logic strips off the header if
416 // present before invoking the callback provided with the transfer.
417 if (actual_length > 0) {
418 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
419 << "buffer was not correctly set: too small for the control header";
421 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
422 // If the payload is zero bytes long, pad out the allocated buffer
423 // size to one byte so that an IOBuffer of that size can be allocated.
424 scoped_refptr<net::IOBuffer> resized_buffer =
425 new net::IOBuffer(static_cast<int>(
426 std::max(actual_length, static_cast<size_t>(1))));
427 memcpy(resized_buffer->data(),
428 buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
429 buffer_ = resized_buffer;
432 break;
434 case USB_TRANSFER_ISOCHRONOUS:
435 // Isochronous replies might carry data in the different isoc packets even
436 // if the transfer actual_data value is zero. Furthermore, not all of the
437 // received packets might contain data, so we need to calculate how many
438 // data bytes we are effectively providing and pack the results.
439 if (actual_length == 0) {
440 size_t packet_buffer_start = 0;
441 for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
442 PlatformUsbIsoPacketDescriptor packet =
443 &platform_transfer_->iso_packet_desc[i];
444 if (packet->actual_length > 0) {
445 // We don't need to copy as long as all packets until now provide
446 // all the data the packet can hold.
447 if (actual_length < packet_buffer_start) {
448 CHECK(packet_buffer_start + packet->actual_length <= length_);
449 memmove(buffer_->data() + actual_length,
450 buffer_->data() + packet_buffer_start,
451 packet->actual_length);
453 actual_length += packet->actual_length;
456 packet_buffer_start += packet->length;
459 break;
461 case USB_TRANSFER_BULK:
462 case USB_TRANSFER_INTERRUPT:
463 break;
465 default:
466 NOTREACHED() << "Invalid usb transfer type";
467 break;
470 TransferComplete(ConvertTransferStatus(platform_transfer_->status),
471 actual_length);
474 /* static */
475 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
476 PlatformUsbTransferHandle platform_transfer) {
477 Transfer* transfer =
478 reinterpret_cast<Transfer*>(platform_transfer->user_data);
479 DCHECK(transfer->platform_transfer_ == platform_transfer);
480 transfer->ProcessCompletion();
483 void UsbDeviceHandleImpl::Transfer::TransferComplete(UsbTransferStatus status,
484 size_t bytes_transferred) {
485 task_runner_->PostTask(
486 FROM_HERE,
487 base::Bind(&UsbDeviceHandleImpl::TransferComplete, device_handle_,
488 base::Unretained(this),
489 base::Bind(callback_, status, buffer_, bytes_transferred)));
492 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
493 return device_;
496 void UsbDeviceHandleImpl::Close() {
497 DCHECK(thread_checker_.CalledOnValidThread());
498 if (device_)
499 device_->Close(this);
502 void UsbDeviceHandleImpl::SetConfiguration(int configuration_value,
503 const ResultCallback& callback) {
504 DCHECK(thread_checker_.CalledOnValidThread());
505 if (!device_) {
506 callback.Run(false);
507 return;
510 for (Transfer* transfer : transfers_) {
511 transfer->Cancel();
513 claimed_interfaces_.clear();
515 blocking_task_runner_->PostTask(
516 FROM_HERE,
517 base::Bind(&UsbDeviceHandleImpl::SetConfigurationOnBlockingThread, this,
518 handle_, configuration_value, callback));
521 void UsbDeviceHandleImpl::ClaimInterface(int interface_number,
522 const ResultCallback& callback) {
523 DCHECK(thread_checker_.CalledOnValidThread());
524 if (!device_) {
525 callback.Run(false);
526 return;
528 if (ContainsKey(claimed_interfaces_, interface_number)) {
529 callback.Run(true);
530 return;
533 blocking_task_runner_->PostTask(
534 FROM_HERE,
535 base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread, this,
536 handle_, interface_number, callback));
539 bool UsbDeviceHandleImpl::ReleaseInterface(int interface_number) {
540 DCHECK(thread_checker_.CalledOnValidThread());
541 if (!device_)
542 return false;
543 if (!ContainsKey(claimed_interfaces_, interface_number))
544 return false;
546 // Cancel all the transfers on that interface.
547 InterfaceClaimer* interface_claimer =
548 claimed_interfaces_[interface_number].get();
549 for (Transfer* transfer : transfers_) {
550 if (transfer->claimed_interface() == interface_claimer) {
551 transfer->Cancel();
554 claimed_interfaces_.erase(interface_number);
556 RefreshEndpointMap();
557 return true;
560 void UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
561 int interface_number,
562 int alternate_setting,
563 const ResultCallback& callback) {
564 DCHECK(thread_checker_.CalledOnValidThread());
565 if (!device_ || !ContainsKey(claimed_interfaces_, interface_number)) {
566 callback.Run(false);
567 return;
570 blocking_task_runner_->PostTask(
571 FROM_HERE,
572 base::Bind(
573 &UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread,
574 this, handle_, interface_number, alternate_setting, callback));
577 void UsbDeviceHandleImpl::ResetDevice(const ResultCallback& callback) {
578 DCHECK(thread_checker_.CalledOnValidThread());
579 if (!device_) {
580 callback.Run(false);
581 return;
584 blocking_task_runner_->PostTask(
585 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ResetDeviceOnBlockingThread,
586 this, handle_, callback));
589 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
590 TransferRequestType request_type,
591 TransferRecipient recipient,
592 uint8 request,
593 uint16 value,
594 uint16 index,
595 scoped_refptr<net::IOBuffer> buffer,
596 size_t length,
597 unsigned int timeout,
598 const TransferCallback& callback) {
599 if (task_runner_->BelongsToCurrentThread()) {
600 ControlTransferInternal(direction, request_type, recipient, request, value,
601 index, buffer, length, timeout, task_runner_,
602 callback);
603 } else {
604 task_runner_->PostTask(
605 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ControlTransferInternal,
606 this, direction, request_type, recipient, request,
607 value, index, buffer, length, timeout,
608 base::ThreadTaskRunnerHandle::Get(), callback));
612 void UsbDeviceHandleImpl::BulkTransfer(UsbEndpointDirection direction,
613 uint8 endpoint,
614 scoped_refptr<net::IOBuffer> buffer,
615 size_t length,
616 unsigned int timeout,
617 const TransferCallback& callback) {
618 if (task_runner_->BelongsToCurrentThread()) {
619 BulkTransferInternal(direction, endpoint, buffer, length, timeout,
620 task_runner_, callback);
621 } else {
622 task_runner_->PostTask(
623 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::BulkTransferInternal, this,
624 direction, endpoint, buffer, length, timeout,
625 base::ThreadTaskRunnerHandle::Get(), callback));
629 void UsbDeviceHandleImpl::InterruptTransfer(UsbEndpointDirection direction,
630 uint8 endpoint,
631 scoped_refptr<net::IOBuffer> buffer,
632 size_t length,
633 unsigned int timeout,
634 const TransferCallback& callback) {
635 if (task_runner_->BelongsToCurrentThread()) {
636 InterruptTransferInternal(direction, endpoint, buffer, length, timeout,
637 task_runner_, callback);
638 } else {
639 task_runner_->PostTask(
640 FROM_HERE,
641 base::Bind(&UsbDeviceHandleImpl::InterruptTransferInternal, this,
642 direction, endpoint, 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 UsbDeviceHandleImpl::UsbDeviceHandleImpl(
669 scoped_refptr<UsbContext> context,
670 scoped_refptr<UsbDeviceImpl> device,
671 PlatformUsbDeviceHandle handle,
672 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
673 : device_(device),
674 handle_(handle),
675 context_(context),
676 task_runner_(base::ThreadTaskRunnerHandle::Get()),
677 blocking_task_runner_(blocking_task_runner) {
678 DCHECK(handle) << "Cannot create device with NULL handle.";
681 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
682 DCHECK(thread_checker_.CalledOnValidThread());
684 libusb_close(handle_);
685 handle_ = NULL;
688 void UsbDeviceHandleImpl::SetConfigurationOnBlockingThread(
689 PlatformUsbDeviceHandle handle,
690 int configuration_value,
691 const ResultCallback& callback) {
692 int rv = libusb_set_configuration(handle_, configuration_value);
693 if (rv != LIBUSB_SUCCESS) {
694 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
695 << ": " << ConvertPlatformUsbErrorToString(rv);
697 task_runner_->PostTask(
698 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SetConfigurationComplete,
699 this, rv == LIBUSB_SUCCESS, callback));
702 void UsbDeviceHandleImpl::SetConfigurationComplete(
703 bool success,
704 const ResultCallback& callback) {
705 if (success) {
706 device_->RefreshConfiguration();
707 RefreshEndpointMap();
709 callback.Run(success);
712 void UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread(
713 PlatformUsbDeviceHandle handle,
714 int interface_number,
715 const ResultCallback& callback) {
716 int rv = libusb_claim_interface(handle, interface_number);
717 if (rv != LIBUSB_SUCCESS) {
718 VLOG(1) << "Failed to claim interface: "
719 << ConvertPlatformUsbErrorToString(rv);
721 task_runner_->PostTask(
722 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceComplete, this,
723 interface_number, rv == LIBUSB_SUCCESS, callback));
726 void UsbDeviceHandleImpl::ClaimInterfaceComplete(
727 int interface_number,
728 bool success,
729 const ResultCallback& callback) {
730 if (success) {
731 claimed_interfaces_[interface_number] =
732 new InterfaceClaimer(this, interface_number);
733 RefreshEndpointMap();
735 callback.Run(success);
738 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread(
739 PlatformUsbDeviceHandle handle,
740 int interface_number,
741 int alternate_setting,
742 const ResultCallback& callback) {
743 int rv = libusb_set_interface_alt_setting(handle, interface_number,
744 alternate_setting);
745 if (rv != LIBUSB_SUCCESS) {
746 USB_LOG(EVENT) << "Failed to set interface " << interface_number
747 << " to alternate setting " << alternate_setting << ": "
748 << ConvertPlatformUsbErrorToString(rv);
750 task_runner_->PostTask(
751 FROM_HERE,
752 base::Bind(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
753 this, interface_number, alternate_setting,
754 rv == LIBUSB_SUCCESS, callback));
757 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
758 int interface_number,
759 int alternate_setting,
760 bool success,
761 const ResultCallback& callback) {
762 if (success) {
763 claimed_interfaces_[interface_number]->set_alternate_setting(
764 alternate_setting);
765 RefreshEndpointMap();
767 callback.Run(success);
770 void UsbDeviceHandleImpl::ResetDeviceOnBlockingThread(
771 PlatformUsbDeviceHandle handle,
772 const ResultCallback& callback) {
773 int rv = libusb_reset_device(handle);
774 if (rv != LIBUSB_SUCCESS) {
775 USB_LOG(EVENT) << "Failed to reset device: "
776 << ConvertPlatformUsbErrorToString(rv);
778 task_runner_->PostTask(
779 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ResetDeviceComplete, this,
780 rv == LIBUSB_SUCCESS, callback));
783 void UsbDeviceHandleImpl::ResetDeviceComplete(bool success,
784 const ResultCallback& callback) {
785 callback.Run(success);
788 void UsbDeviceHandleImpl::RefreshEndpointMap() {
789 DCHECK(thread_checker_.CalledOnValidThread());
790 endpoint_map_.clear();
791 const UsbConfigDescriptor* config = device_->GetConfiguration();
792 if (config) {
793 for (const auto& map_entry : claimed_interfaces_) {
794 int interface_number = map_entry.first;
795 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
797 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
798 if (iface.interface_number == interface_number &&
799 iface.alternate_setting == claimed_iface->alternate_setting()) {
800 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
801 endpoint_map_[endpoint.address] = interface_number;
803 break;
810 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
811 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
812 if (ContainsKey(endpoint_map_, endpoint))
813 return claimed_interfaces_[endpoint_map_[endpoint]];
814 return NULL;
817 void UsbDeviceHandleImpl::ControlTransferInternal(
818 UsbEndpointDirection direction,
819 TransferRequestType request_type,
820 TransferRecipient recipient,
821 uint8 request,
822 uint16 value,
823 uint16 index,
824 scoped_refptr<net::IOBuffer> buffer,
825 size_t length,
826 unsigned int timeout,
827 scoped_refptr<base::TaskRunner> callback_task_runner,
828 const TransferCallback& callback) {
829 DCHECK(thread_checker_.CalledOnValidThread());
831 if (!device_) {
832 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
833 return;
836 if (length > UINT16_MAX) {
837 USB_LOG(USER) << "Transfer too long.";
838 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
839 return;
842 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
843 scoped_refptr<net::IOBuffer> resized_buffer(
844 new net::IOBufferWithSize(static_cast<int>(resized_length)));
845 if (!resized_buffer.get()) {
846 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
847 return;
849 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
850 length);
852 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
853 this, CreateRequestType(direction, request_type, recipient), request,
854 value, index, static_cast<uint16>(length), resized_buffer, timeout,
855 callback_task_runner, callback);
856 if (!transfer) {
857 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
858 return;
861 SubmitTransfer(transfer.Pass());
864 void UsbDeviceHandleImpl::BulkTransferInternal(
865 const UsbEndpointDirection direction,
866 const uint8 endpoint,
867 scoped_refptr<net::IOBuffer> buffer,
868 const size_t length,
869 const unsigned int timeout,
870 scoped_refptr<base::TaskRunner> callback_task_runner,
871 const TransferCallback& callback) {
872 DCHECK(thread_checker_.CalledOnValidThread());
874 if (!device_) {
875 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
876 return;
879 if (length > INT_MAX) {
880 USB_LOG(USER) << "Transfer too long.";
881 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
882 return;
885 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
886 this, ConvertTransferDirection(direction) | endpoint, buffer,
887 static_cast<int>(length), timeout, callback_task_runner, callback);
889 SubmitTransfer(transfer.Pass());
892 void UsbDeviceHandleImpl::InterruptTransferInternal(
893 UsbEndpointDirection direction,
894 uint8 endpoint,
895 scoped_refptr<net::IOBuffer> buffer,
896 size_t length,
897 unsigned int timeout,
898 scoped_refptr<base::TaskRunner> callback_task_runner,
899 const TransferCallback& callback) {
900 DCHECK(thread_checker_.CalledOnValidThread());
902 if (!device_) {
903 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
904 return;
907 if (length > INT_MAX) {
908 USB_LOG(USER) << "Transfer too long.";
909 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
910 return;
913 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
914 this, ConvertTransferDirection(direction) | endpoint, buffer,
915 static_cast<int>(length), timeout, callback_task_runner, callback);
917 SubmitTransfer(transfer.Pass());
920 void UsbDeviceHandleImpl::IsochronousTransferInternal(
921 const UsbEndpointDirection direction,
922 uint8 endpoint,
923 scoped_refptr<net::IOBuffer> buffer,
924 size_t length,
925 unsigned int packets,
926 unsigned int packet_length,
927 unsigned int timeout,
928 scoped_refptr<base::TaskRunner> callback_task_runner,
929 const TransferCallback& callback) {
930 DCHECK(thread_checker_.CalledOnValidThread());
932 if (!device_) {
933 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
934 return;
937 if (length > INT_MAX) {
938 USB_LOG(USER) << "Transfer too long.";
939 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
940 return;
943 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
944 this, ConvertTransferDirection(direction) | endpoint, buffer,
945 static_cast<int>(length), packets, packet_length, timeout,
946 callback_task_runner, callback);
948 SubmitTransfer(transfer.Pass());
951 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
952 DCHECK(thread_checker_.CalledOnValidThread());
954 // Transfer is owned by libusb until its completion callback is run. This
955 // object holds a weak reference.
956 transfers_.insert(transfer.get());
957 blocking_task_runner_->PostTask(
958 FROM_HERE,
959 base::Bind(&Transfer::Submit, base::Unretained(transfer.release())));
962 void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
963 const base::Closure& callback) {
964 DCHECK(thread_checker_.CalledOnValidThread());
965 DCHECK(ContainsKey(transfers_, transfer)) << "Missing transfer completed";
966 transfers_.erase(transfer);
968 if (transfer->callback_task_runner()->RunsTasksOnCurrentThread()) {
969 callback.Run();
970 } else {
971 transfer->callback_task_runner()->PostTask(FROM_HERE, callback);
974 // libusb_free_transfer races with libusb_submit_transfer and only work-
975 // around is to make sure to call them on the same thread.
976 blocking_task_runner_->DeleteSoon(FROM_HERE, transfer);
979 void UsbDeviceHandleImpl::InternalClose() {
980 DCHECK(thread_checker_.CalledOnValidThread());
981 if (!device_)
982 return;
984 // Cancel all the transfers.
985 for (Transfer* transfer : transfers_) {
986 // The callback will be called some time later.
987 transfer->Cancel();
990 // Attempt-release all the interfaces.
991 // It will be retained until the transfer cancellation is finished.
992 claimed_interfaces_.clear();
994 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
995 // finish.
996 device_ = NULL;
999 } // namespace device