Add ICU message format support
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blob1840232caf2311f22674d44fb6c5e5cb01c63b0a
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::ClearHalt(uint8 endpoint,
590 const ResultCallback& callback) {
591 DCHECK(thread_checker_.CalledOnValidThread());
592 if (!device_) {
593 callback.Run(false);
594 return;
597 InterfaceClaimer* interface_claimer =
598 GetClaimedInterfaceForEndpoint(endpoint).get();
599 for (Transfer* transfer : transfers_) {
600 if (transfer->claimed_interface() == interface_claimer) {
601 transfer->Cancel();
605 blocking_task_runner_->PostTask(
606 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClearHaltOnBlockingThread,
607 this, endpoint, callback));
610 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
611 TransferRequestType request_type,
612 TransferRecipient recipient,
613 uint8 request,
614 uint16 value,
615 uint16 index,
616 scoped_refptr<net::IOBuffer> buffer,
617 size_t length,
618 unsigned int timeout,
619 const TransferCallback& callback) {
620 if (task_runner_->BelongsToCurrentThread()) {
621 ControlTransferInternal(direction, request_type, recipient, request, value,
622 index, buffer, length, timeout, task_runner_,
623 callback);
624 } else {
625 task_runner_->PostTask(
626 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ControlTransferInternal,
627 this, direction, request_type, recipient, request,
628 value, index, buffer, length, timeout,
629 base::ThreadTaskRunnerHandle::Get(), callback));
633 void UsbDeviceHandleImpl::BulkTransfer(UsbEndpointDirection direction,
634 uint8 endpoint,
635 scoped_refptr<net::IOBuffer> buffer,
636 size_t length,
637 unsigned int timeout,
638 const TransferCallback& callback) {
639 if (task_runner_->BelongsToCurrentThread()) {
640 BulkTransferInternal(direction, endpoint, buffer, length, timeout,
641 task_runner_, callback);
642 } else {
643 task_runner_->PostTask(
644 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::BulkTransferInternal, this,
645 direction, endpoint, buffer, length, timeout,
646 base::ThreadTaskRunnerHandle::Get(), callback));
650 void UsbDeviceHandleImpl::InterruptTransfer(UsbEndpointDirection direction,
651 uint8 endpoint,
652 scoped_refptr<net::IOBuffer> buffer,
653 size_t length,
654 unsigned int timeout,
655 const TransferCallback& callback) {
656 if (task_runner_->BelongsToCurrentThread()) {
657 InterruptTransferInternal(direction, endpoint, buffer, length, timeout,
658 task_runner_, callback);
659 } else {
660 task_runner_->PostTask(
661 FROM_HERE,
662 base::Bind(&UsbDeviceHandleImpl::InterruptTransferInternal, this,
663 direction, endpoint, buffer, length, timeout,
664 base::ThreadTaskRunnerHandle::Get(), callback));
668 void UsbDeviceHandleImpl::IsochronousTransfer(
669 UsbEndpointDirection direction,
670 uint8 endpoint,
671 scoped_refptr<net::IOBuffer> buffer,
672 size_t length,
673 unsigned int packets,
674 unsigned int packet_length,
675 unsigned int timeout,
676 const TransferCallback& callback) {
677 if (task_runner_->BelongsToCurrentThread()) {
678 IsochronousTransferInternal(direction, endpoint, buffer, length, packets,
679 packet_length, timeout, task_runner_, callback);
680 } else {
681 task_runner_->PostTask(
682 FROM_HERE,
683 base::Bind(&UsbDeviceHandleImpl::IsochronousTransferInternal, this,
684 direction, endpoint, buffer, length, packets, packet_length,
685 timeout, base::ThreadTaskRunnerHandle::Get(), callback));
689 UsbDeviceHandleImpl::UsbDeviceHandleImpl(
690 scoped_refptr<UsbContext> context,
691 scoped_refptr<UsbDeviceImpl> device,
692 PlatformUsbDeviceHandle handle,
693 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
694 : device_(device),
695 handle_(handle),
696 context_(context),
697 task_runner_(base::ThreadTaskRunnerHandle::Get()),
698 blocking_task_runner_(blocking_task_runner) {
699 DCHECK(handle) << "Cannot create device with NULL handle.";
702 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
703 // This class is RefCountedThreadSafe and so the destructor may be called on
704 // any thread.
705 libusb_close(handle_);
708 void UsbDeviceHandleImpl::SetConfigurationOnBlockingThread(
709 int configuration_value,
710 const ResultCallback& callback) {
711 int rv = libusb_set_configuration(handle_, configuration_value);
712 if (rv != LIBUSB_SUCCESS) {
713 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
714 << ": " << ConvertPlatformUsbErrorToString(rv);
716 task_runner_->PostTask(
717 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SetConfigurationComplete,
718 this, rv == LIBUSB_SUCCESS, callback));
721 void UsbDeviceHandleImpl::SetConfigurationComplete(
722 bool success,
723 const ResultCallback& callback) {
724 if (success) {
725 device_->RefreshActiveConfiguration();
726 RefreshEndpointMap();
728 callback.Run(success);
731 void UsbDeviceHandleImpl::ClaimInterfaceOnBlockingThread(
732 int interface_number,
733 const ResultCallback& callback) {
734 int rv = libusb_claim_interface(handle_, interface_number);
735 if (rv != LIBUSB_SUCCESS) {
736 VLOG(1) << "Failed to claim interface: "
737 << ConvertPlatformUsbErrorToString(rv);
739 task_runner_->PostTask(
740 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::ClaimInterfaceComplete, this,
741 interface_number, rv == LIBUSB_SUCCESS, callback));
744 void UsbDeviceHandleImpl::ClaimInterfaceComplete(
745 int interface_number,
746 bool success,
747 const ResultCallback& callback) {
748 if (success) {
749 claimed_interfaces_[interface_number] =
750 new InterfaceClaimer(this, interface_number);
751 RefreshEndpointMap();
753 callback.Run(success);
756 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingOnBlockingThread(
757 int interface_number,
758 int alternate_setting,
759 const ResultCallback& callback) {
760 int rv = libusb_set_interface_alt_setting(handle_, interface_number,
761 alternate_setting);
762 if (rv != LIBUSB_SUCCESS) {
763 USB_LOG(EVENT) << "Failed to set interface " << interface_number
764 << " to alternate setting " << alternate_setting << ": "
765 << ConvertPlatformUsbErrorToString(rv);
767 task_runner_->PostTask(
768 FROM_HERE,
769 base::Bind(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
770 this, interface_number, alternate_setting,
771 rv == LIBUSB_SUCCESS, callback));
774 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
775 int interface_number,
776 int alternate_setting,
777 bool success,
778 const ResultCallback& callback) {
779 if (success) {
780 claimed_interfaces_[interface_number]->set_alternate_setting(
781 alternate_setting);
782 RefreshEndpointMap();
784 callback.Run(success);
787 void UsbDeviceHandleImpl::ResetDeviceOnBlockingThread(
788 const ResultCallback& callback) {
789 int rv = libusb_reset_device(handle_);
790 if (rv != LIBUSB_SUCCESS) {
791 USB_LOG(EVENT) << "Failed to reset device: "
792 << ConvertPlatformUsbErrorToString(rv);
794 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rv == LIBUSB_SUCCESS));
797 void UsbDeviceHandleImpl::ClearHaltOnBlockingThread(
798 uint8 endpoint,
799 const ResultCallback& callback) {
800 int rv = libusb_clear_halt(handle_, endpoint);
801 if (rv != LIBUSB_SUCCESS) {
802 USB_LOG(EVENT) << "Failed to clear halt: "
803 << ConvertPlatformUsbErrorToString(rv);
805 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rv == LIBUSB_SUCCESS));
808 void UsbDeviceHandleImpl::RefreshEndpointMap() {
809 DCHECK(thread_checker_.CalledOnValidThread());
810 endpoint_map_.clear();
811 const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
812 if (config) {
813 for (const auto& map_entry : claimed_interfaces_) {
814 int interface_number = map_entry.first;
815 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
817 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
818 if (iface.interface_number == interface_number &&
819 iface.alternate_setting == claimed_iface->alternate_setting()) {
820 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
821 endpoint_map_[endpoint.address] = interface_number;
823 break;
830 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
831 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(uint8 endpoint) {
832 if (ContainsKey(endpoint_map_, endpoint))
833 return claimed_interfaces_[endpoint_map_[endpoint]];
834 return NULL;
837 void UsbDeviceHandleImpl::ControlTransferInternal(
838 UsbEndpointDirection direction,
839 TransferRequestType request_type,
840 TransferRecipient recipient,
841 uint8 request,
842 uint16 value,
843 uint16 index,
844 scoped_refptr<net::IOBuffer> buffer,
845 size_t length,
846 unsigned int timeout,
847 scoped_refptr<base::TaskRunner> callback_task_runner,
848 const TransferCallback& callback) {
849 DCHECK(thread_checker_.CalledOnValidThread());
851 if (!device_) {
852 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
853 return;
856 if (length > UINT16_MAX) {
857 USB_LOG(USER) << "Transfer too long.";
858 callback.Run(USB_TRANSFER_ERROR, 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 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
867 return;
869 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
870 length);
872 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
873 this, CreateRequestType(direction, request_type, recipient), request,
874 value, index, static_cast<uint16>(length), resized_buffer, timeout,
875 callback_task_runner, callback);
876 if (!transfer) {
877 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
878 return;
881 SubmitTransfer(transfer.Pass());
884 void UsbDeviceHandleImpl::BulkTransferInternal(
885 const UsbEndpointDirection direction,
886 const uint8 endpoint,
887 scoped_refptr<net::IOBuffer> buffer,
888 const size_t length,
889 const unsigned int timeout,
890 scoped_refptr<base::TaskRunner> callback_task_runner,
891 const TransferCallback& callback) {
892 DCHECK(thread_checker_.CalledOnValidThread());
894 if (!device_) {
895 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
896 return;
899 if (length > INT_MAX) {
900 USB_LOG(USER) << "Transfer too long.";
901 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
902 return;
905 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
906 this, ConvertTransferDirection(direction) | endpoint, buffer,
907 static_cast<int>(length), timeout, callback_task_runner, callback);
909 SubmitTransfer(transfer.Pass());
912 void UsbDeviceHandleImpl::InterruptTransferInternal(
913 UsbEndpointDirection direction,
914 uint8 endpoint,
915 scoped_refptr<net::IOBuffer> buffer,
916 size_t length,
917 unsigned int timeout,
918 scoped_refptr<base::TaskRunner> callback_task_runner,
919 const TransferCallback& callback) {
920 DCHECK(thread_checker_.CalledOnValidThread());
922 if (!device_) {
923 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
924 return;
927 if (length > INT_MAX) {
928 USB_LOG(USER) << "Transfer too long.";
929 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
930 return;
933 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
934 this, ConvertTransferDirection(direction) | endpoint, buffer,
935 static_cast<int>(length), timeout, callback_task_runner, callback);
937 SubmitTransfer(transfer.Pass());
940 void UsbDeviceHandleImpl::IsochronousTransferInternal(
941 const UsbEndpointDirection direction,
942 uint8 endpoint,
943 scoped_refptr<net::IOBuffer> buffer,
944 size_t length,
945 unsigned int packets,
946 unsigned int packet_length,
947 unsigned int timeout,
948 scoped_refptr<base::TaskRunner> callback_task_runner,
949 const TransferCallback& callback) {
950 DCHECK(thread_checker_.CalledOnValidThread());
952 if (!device_) {
953 callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0);
954 return;
957 if (length > INT_MAX) {
958 USB_LOG(USER) << "Transfer too long.";
959 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
960 return;
963 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
964 this, ConvertTransferDirection(direction) | endpoint, buffer,
965 static_cast<int>(length), packets, packet_length, timeout,
966 callback_task_runner, callback);
968 SubmitTransfer(transfer.Pass());
971 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
972 DCHECK(thread_checker_.CalledOnValidThread());
974 // Transfer is owned by libusb until its completion callback is run. This
975 // object holds a weak reference.
976 transfers_.insert(transfer.get());
977 blocking_task_runner_->PostTask(
978 FROM_HERE,
979 base::Bind(&Transfer::Submit, base::Unretained(transfer.release())));
982 void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
983 const base::Closure& callback) {
984 DCHECK(thread_checker_.CalledOnValidThread());
985 DCHECK(ContainsKey(transfers_, transfer)) << "Missing transfer completed";
986 transfers_.erase(transfer);
988 if (transfer->callback_task_runner()->RunsTasksOnCurrentThread()) {
989 callback.Run();
990 } else {
991 transfer->callback_task_runner()->PostTask(FROM_HERE, callback);
994 // libusb_free_transfer races with libusb_submit_transfer and only work-
995 // around is to make sure to call them on the same thread.
996 blocking_task_runner_->DeleteSoon(FROM_HERE, transfer);
999 void UsbDeviceHandleImpl::InternalClose() {
1000 DCHECK(thread_checker_.CalledOnValidThread());
1001 if (!device_)
1002 return;
1004 // Cancel all the transfers.
1005 for (Transfer* transfer : transfers_) {
1006 // The callback will be called some time later.
1007 transfer->Cancel();
1010 // Attempt-release all the interfaces.
1011 // It will be retained until the transfer cancellation is finished.
1012 claimed_interfaces_.clear();
1014 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
1015 // finish.
1016 device_ = NULL;
1019 } // namespace device