Roll src/third_party/WebKit 75320b7:bf8feaf (svn 199088:199092)
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blob6a0861263e58f50557f68731b46079fecd62df9b
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 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 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, 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, 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 // This class is RefCountedThreadSafe and so the destructor may be called on
683 // any thread.
684 libusb_close(handle_);
687 void UsbDeviceHandleImpl::SetConfigurationOnBlockingThread(
688 int configuration_value,
689 const ResultCallback& callback) {
690 int rv = libusb_set_configuration(handle_, configuration_value);
691 if (rv != LIBUSB_SUCCESS) {
692 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
693 << ": " << ConvertPlatformUsbErrorToString(rv);
695 task_runner_->PostTask(
696 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SetConfigurationComplete,
697 this, rv == LIBUSB_SUCCESS, callback));
700 void UsbDeviceHandleImpl::SetConfigurationComplete(
701 bool success,
702 const ResultCallback& callback) {
703 if (success) {
704 device_->RefreshConfiguration();
705 RefreshEndpointMap();
707 callback.Run(success);
710 void UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread(
711 int interface_number,
712 const ResultCallback& callback) {
713 int rv = libusb_claim_interface(handle_, interface_number);
714 if (rv != LIBUSB_SUCCESS) {
715 VLOG(1) << "Failed to claim interface: "
716 << ConvertPlatformUsbErrorToString(rv);
718 task_runner_->PostTask(
719 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceComplete, this,
720 interface_number, rv == LIBUSB_SUCCESS, callback));
723 void UsbDeviceHandleImpl::ClaimInterfaceComplete(
724 int interface_number,
725 bool success,
726 const ResultCallback& callback) {
727 if (success) {
728 claimed_interfaces_[interface_number] =
729 new InterfaceClaimer(this, interface_number);
730 RefreshEndpointMap();
732 callback.Run(success);
735 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread(
736 int interface_number,
737 int alternate_setting,
738 const ResultCallback& callback) {
739 int rv = libusb_set_interface_alt_setting(handle_, interface_number,
740 alternate_setting);
741 if (rv != LIBUSB_SUCCESS) {
742 USB_LOG(EVENT) << "Failed to set interface " << interface_number
743 << " to alternate setting " << alternate_setting << ": "
744 << ConvertPlatformUsbErrorToString(rv);
746 task_runner_->PostTask(
747 FROM_HERE,
748 base::Bind(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
749 this, interface_number, alternate_setting,
750 rv == LIBUSB_SUCCESS, callback));
753 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
754 int interface_number,
755 int alternate_setting,
756 bool success,
757 const ResultCallback& callback) {
758 if (success) {
759 claimed_interfaces_[interface_number]->set_alternate_setting(
760 alternate_setting);
761 RefreshEndpointMap();
763 callback.Run(success);
766 void UsbDeviceHandleImpl::ResetDeviceOnBlockingThread(
767 const ResultCallback& callback) {
768 int rv = libusb_reset_device(handle_);
769 if (rv != LIBUSB_SUCCESS) {
770 USB_LOG(EVENT) << "Failed to reset device: "
771 << ConvertPlatformUsbErrorToString(rv);
773 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rv == LIBUSB_SUCCESS));
776 void UsbDeviceHandleImpl::RefreshEndpointMap() {
777 DCHECK(thread_checker_.CalledOnValidThread());
778 endpoint_map_.clear();
779 const UsbConfigDescriptor* config = device_->GetConfiguration();
780 if (config) {
781 for (const auto& map_entry : claimed_interfaces_) {
782 int interface_number = map_entry.first;
783 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
785 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
786 if (iface.interface_number == interface_number &&
787 iface.alternate_setting == claimed_iface->alternate_setting()) {
788 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
789 endpoint_map_[endpoint.address] = interface_number;
791 break;
798 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
799 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
800 if (ContainsKey(endpoint_map_, endpoint))
801 return claimed_interfaces_[endpoint_map_[endpoint]];
802 return NULL;
805 void UsbDeviceHandleImpl::ControlTransferInternal(
806 UsbEndpointDirection direction,
807 TransferRequestType request_type,
808 TransferRecipient recipient,
809 uint8 request,
810 uint16 value,
811 uint16 index,
812 scoped_refptr<net::IOBuffer> buffer,
813 size_t length,
814 unsigned int timeout,
815 scoped_refptr<base::TaskRunner> callback_task_runner,
816 const TransferCallback& callback) {
817 DCHECK(thread_checker_.CalledOnValidThread());
819 if (!device_) {
820 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
821 return;
824 if (length > UINT16_MAX) {
825 USB_LOG(USER) << "Transfer too long.";
826 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
827 return;
830 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
831 scoped_refptr<net::IOBuffer> resized_buffer(
832 new net::IOBufferWithSize(static_cast<int>(resized_length)));
833 if (!resized_buffer.get()) {
834 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
835 return;
837 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
838 length);
840 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
841 this, CreateRequestType(direction, request_type, recipient), request,
842 value, index, static_cast<uint16>(length), resized_buffer, timeout,
843 callback_task_runner, callback);
844 if (!transfer) {
845 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
846 return;
849 SubmitTransfer(transfer.Pass());
852 void UsbDeviceHandleImpl::BulkTransferInternal(
853 const UsbEndpointDirection direction,
854 const uint8 endpoint,
855 scoped_refptr<net::IOBuffer> buffer,
856 const size_t length,
857 const unsigned int timeout,
858 scoped_refptr<base::TaskRunner> callback_task_runner,
859 const TransferCallback& callback) {
860 DCHECK(thread_checker_.CalledOnValidThread());
862 if (!device_) {
863 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
864 return;
867 if (length > INT_MAX) {
868 USB_LOG(USER) << "Transfer too long.";
869 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
870 return;
873 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
874 this, ConvertTransferDirection(direction) | endpoint, buffer,
875 static_cast<int>(length), timeout, callback_task_runner, callback);
877 SubmitTransfer(transfer.Pass());
880 void UsbDeviceHandleImpl::InterruptTransferInternal(
881 UsbEndpointDirection direction,
882 uint8 endpoint,
883 scoped_refptr<net::IOBuffer> buffer,
884 size_t length,
885 unsigned int timeout,
886 scoped_refptr<base::TaskRunner> callback_task_runner,
887 const TransferCallback& callback) {
888 DCHECK(thread_checker_.CalledOnValidThread());
890 if (!device_) {
891 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
892 return;
895 if (length > INT_MAX) {
896 USB_LOG(USER) << "Transfer too long.";
897 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
898 return;
901 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
902 this, ConvertTransferDirection(direction) | endpoint, buffer,
903 static_cast<int>(length), timeout, callback_task_runner, callback);
905 SubmitTransfer(transfer.Pass());
908 void UsbDeviceHandleImpl::IsochronousTransferInternal(
909 const UsbEndpointDirection direction,
910 uint8 endpoint,
911 scoped_refptr<net::IOBuffer> buffer,
912 size_t length,
913 unsigned int packets,
914 unsigned int packet_length,
915 unsigned int timeout,
916 scoped_refptr<base::TaskRunner> callback_task_runner,
917 const TransferCallback& callback) {
918 DCHECK(thread_checker_.CalledOnValidThread());
920 if (!device_) {
921 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
922 return;
925 if (length > INT_MAX) {
926 USB_LOG(USER) << "Transfer too long.";
927 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
928 return;
931 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
932 this, ConvertTransferDirection(direction) | endpoint, buffer,
933 static_cast<int>(length), packets, packet_length, timeout,
934 callback_task_runner, callback);
936 SubmitTransfer(transfer.Pass());
939 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
940 DCHECK(thread_checker_.CalledOnValidThread());
942 // Transfer is owned by libusb until its completion callback is run. This
943 // object holds a weak reference.
944 transfers_.insert(transfer.get());
945 blocking_task_runner_->PostTask(
946 FROM_HERE,
947 base::Bind(&Transfer::Submit, base::Unretained(transfer.release())));
950 void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
951 const base::Closure& callback) {
952 DCHECK(thread_checker_.CalledOnValidThread());
953 DCHECK(ContainsKey(transfers_, transfer)) << "Missing transfer completed";
954 transfers_.erase(transfer);
956 if (transfer->callback_task_runner()->RunsTasksOnCurrentThread()) {
957 callback.Run();
958 } else {
959 transfer->callback_task_runner()->PostTask(FROM_HERE, callback);
962 // libusb_free_transfer races with libusb_submit_transfer and only work-
963 // around is to make sure to call them on the same thread.
964 blocking_task_runner_->DeleteSoon(FROM_HERE, transfer);
967 void UsbDeviceHandleImpl::InternalClose() {
968 DCHECK(thread_checker_.CalledOnValidThread());
969 if (!device_)
970 return;
972 // Cancel all the transfers.
973 for (Transfer* transfer : transfers_) {
974 // The callback will be called some time later.
975 transfer->Cancel();
978 // Attempt-release all the interfaces.
979 // It will be retained until the transfer cancellation is finished.
980 claimed_interfaces_.clear();
982 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
983 // finish.
984 device_ = NULL;
987 } // namespace device