Cleanup favicon after componentization completion
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blobfc14e82c30723f560ebb1a50ab29691d715c1c80
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 uint8 type,
161 uint8 request,
162 uint16 value,
163 uint16 index,
164 uint16 length,
165 scoped_refptr<net::IOBuffer> buffer,
166 unsigned int timeout,
167 const UsbTransferCallback& callback);
168 static scoped_ptr<Transfer> CreateBulkTransfer(
169 uint8 endpoint,
170 scoped_refptr<net::IOBuffer> buffer,
171 int length,
172 unsigned int timeout,
173 const UsbTransferCallback& callback);
174 static scoped_ptr<Transfer> CreateInterruptTransfer(
175 uint8 endpoint,
176 scoped_refptr<net::IOBuffer> buffer,
177 int length,
178 unsigned int timeout,
179 const UsbTransferCallback& callback);
180 static scoped_ptr<Transfer> CreateIsochronousTransfer(
181 uint8 endpoint,
182 scoped_refptr<net::IOBuffer> buffer,
183 size_t length,
184 unsigned int packets,
185 unsigned int packet_length,
186 unsigned int timeout,
187 const UsbTransferCallback& callback);
189 ~Transfer();
191 bool Submit(base::WeakPtr<UsbDeviceHandleImpl> device_handle);
192 void Cancel();
193 void ProcessCompletion();
194 void Complete(UsbTransferStatus status, size_t bytes_transferred);
196 const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
197 return claimed_interface_.get();
200 private:
201 Transfer(UsbTransferType transfer_type,
202 scoped_refptr<net::IOBuffer> buffer,
203 size_t length,
204 const UsbTransferCallback& callback);
206 static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
208 UsbTransferType transfer_type_;
209 base::WeakPtr<UsbDeviceHandleImpl> device_handle_;
210 PlatformUsbTransferHandle platform_transfer_;
211 scoped_refptr<net::IOBuffer> buffer_;
212 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
213 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
214 size_t length_;
215 bool cancelled_;
216 UsbTransferCallback callback_;
217 scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
220 // static
221 scoped_ptr<UsbDeviceHandleImpl::Transfer>
222 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
223 uint8 type,
224 uint8 request,
225 uint16 value,
226 uint16 index,
227 uint16 length,
228 scoped_refptr<net::IOBuffer> buffer,
229 unsigned int timeout,
230 const UsbTransferCallback& callback) {
231 scoped_ptr<Transfer> transfer(new Transfer(USB_TRANSFER_CONTROL, buffer,
232 length + LIBUSB_CONTROL_SETUP_SIZE,
233 callback));
235 transfer->platform_transfer_ = libusb_alloc_transfer(0);
236 if (!transfer->platform_transfer_) {
237 USB_LOG(ERROR) << "Failed to allocate control transfer.";
238 return nullptr;
241 libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
242 request, value, index, length);
243 libusb_fill_control_transfer(transfer->platform_transfer_,
244 nullptr, /* filled in by Submit() */
245 reinterpret_cast<uint8*>(buffer->data()),
246 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
247 transfer.get(), timeout);
249 return transfer.Pass();
252 // static
253 scoped_ptr<UsbDeviceHandleImpl::Transfer>
254 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
255 uint8 endpoint,
256 scoped_refptr<net::IOBuffer> buffer,
257 int length,
258 unsigned int timeout,
259 const UsbTransferCallback& callback) {
260 scoped_ptr<Transfer> transfer(
261 new Transfer(USB_TRANSFER_BULK, buffer, length, callback));
263 transfer->platform_transfer_ = libusb_alloc_transfer(0);
264 if (!transfer->platform_transfer_) {
265 USB_LOG(ERROR) << "Failed to allocate bulk transfer.";
266 return nullptr;
269 libusb_fill_bulk_transfer(transfer->platform_transfer_,
270 nullptr, /* filled in by Submit() */
271 endpoint, reinterpret_cast<uint8*>(buffer->data()),
272 static_cast<int>(length),
273 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
274 transfer.get(), timeout);
276 return transfer.Pass();
279 // static
280 scoped_ptr<UsbDeviceHandleImpl::Transfer>
281 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
282 uint8 endpoint,
283 scoped_refptr<net::IOBuffer> buffer,
284 int length,
285 unsigned int timeout,
286 const UsbTransferCallback& callback) {
287 scoped_ptr<Transfer> transfer(
288 new Transfer(USB_TRANSFER_INTERRUPT, buffer, length, callback));
290 transfer->platform_transfer_ = libusb_alloc_transfer(0);
291 if (!transfer->platform_transfer_) {
292 USB_LOG(ERROR) << "Failed to allocate interrupt transfer.";
293 return nullptr;
296 libusb_fill_interrupt_transfer(
297 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
298 endpoint, reinterpret_cast<uint8*>(buffer->data()),
299 static_cast<int>(length),
300 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
301 timeout);
303 return transfer.Pass();
306 // static
307 scoped_ptr<UsbDeviceHandleImpl::Transfer>
308 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
309 uint8 endpoint,
310 scoped_refptr<net::IOBuffer> buffer,
311 size_t length,
312 unsigned int packets,
313 unsigned int packet_length,
314 unsigned int timeout,
315 const UsbTransferCallback& callback) {
316 DCHECK(packets <= length && (packets * packet_length) <= length)
317 << "transfer length is too small";
319 scoped_ptr<Transfer> transfer(
320 new Transfer(USB_TRANSFER_ISOCHRONOUS, buffer, length, callback));
322 transfer->platform_transfer_ = libusb_alloc_transfer(packets);
323 if (!transfer->platform_transfer_) {
324 USB_LOG(ERROR) << "Failed to allocate isochronous transfer.";
325 return nullptr;
328 libusb_fill_iso_transfer(
329 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
330 endpoint, reinterpret_cast<uint8*>(buffer->data()),
331 static_cast<int>(length), packets, &Transfer::PlatformCallback,
332 transfer.get(), timeout);
333 libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
335 return transfer.Pass();
338 UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type,
339 scoped_refptr<net::IOBuffer> buffer,
340 size_t length,
341 const UsbTransferCallback& callback)
342 : transfer_type_(transfer_type),
343 buffer_(buffer),
344 length_(length),
345 cancelled_(false),
346 callback_(callback) {
347 // Remember the thread from which this transfer was created so that |callback|
348 // can be dispatched there.
349 callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
352 UsbDeviceHandleImpl::Transfer::~Transfer() {
353 if (platform_transfer_) {
354 libusb_free_transfer(platform_transfer_);
358 bool UsbDeviceHandleImpl::Transfer::Submit(
359 base::WeakPtr<UsbDeviceHandleImpl> device_handle) {
360 device_handle_ = device_handle;
361 // Remember the thread from which this transfer was submitted so that it can
362 // be marked complete there.
363 task_runner_ = base::ThreadTaskRunnerHandle::Get();
364 // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer
365 // will fail if it requires an interface we didn't claim.
366 claimed_interface_ = device_handle->GetClaimedInterfaceForEndpoint(
367 platform_transfer_->endpoint);
368 platform_transfer_->dev_handle = device_handle_->handle_;
370 const int rv = libusb_submit_transfer(platform_transfer_);
371 if (rv == LIBUSB_SUCCESS) {
372 return true;
373 } else {
374 USB_LOG(EVENT) << "Failed to submit transfer: "
375 << ConvertPlatformUsbErrorToString(rv);
376 Complete(USB_TRANSFER_ERROR, 0);
377 return false;
381 void UsbDeviceHandleImpl::Transfer::Cancel() {
382 if (!cancelled_) {
383 libusb_cancel_transfer(platform_transfer_);
384 claimed_interface_ = nullptr;
386 cancelled_ = true;
389 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
390 DCHECK_GE(platform_transfer_->actual_length, 0)
391 << "Negative actual length received";
392 size_t actual_length =
393 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
395 DCHECK(length_ >= actual_length)
396 << "data too big for our buffer (libusb failure?)";
398 switch (transfer_type_) {
399 case USB_TRANSFER_CONTROL:
400 // If the transfer is a control transfer we do not expose the control
401 // setup header to the caller. This logic strips off the header if
402 // present before invoking the callback provided with the transfer.
403 if (actual_length > 0) {
404 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
405 << "buffer was not correctly set: too small for the control header";
407 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
408 // If the payload is zero bytes long, pad out the allocated buffer
409 // size to one byte so that an IOBuffer of that size can be allocated.
410 scoped_refptr<net::IOBuffer> resized_buffer =
411 new net::IOBuffer(static_cast<int>(
412 std::max(actual_length, static_cast<size_t>(1))));
413 memcpy(resized_buffer->data(),
414 buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
415 buffer_ = resized_buffer;
418 break;
420 case USB_TRANSFER_ISOCHRONOUS:
421 // Isochronous replies might carry data in the different isoc packets even
422 // if the transfer actual_data value is zero. Furthermore, not all of the
423 // received packets might contain data, so we need to calculate how many
424 // data bytes we are effectively providing and pack the results.
425 if (actual_length == 0) {
426 size_t packet_buffer_start = 0;
427 for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
428 PlatformUsbIsoPacketDescriptor packet =
429 &platform_transfer_->iso_packet_desc[i];
430 if (packet->actual_length > 0) {
431 // We don't need to copy as long as all packets until now provide
432 // all the data the packet can hold.
433 if (actual_length < packet_buffer_start) {
434 CHECK(packet_buffer_start + packet->actual_length <= length_);
435 memmove(buffer_->data() + actual_length,
436 buffer_->data() + packet_buffer_start,
437 packet->actual_length);
439 actual_length += packet->actual_length;
442 packet_buffer_start += packet->length;
445 break;
447 case USB_TRANSFER_BULK:
448 case USB_TRANSFER_INTERRUPT:
449 break;
451 default:
452 NOTREACHED() << "Invalid usb transfer type";
453 break;
456 Complete(ConvertTransferStatus(platform_transfer_->status), actual_length);
459 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status,
460 size_t bytes_transferred) {
461 if (callback_task_runner_->RunsTasksOnCurrentThread()) {
462 callback_.Run(status, buffer_, bytes_transferred);
463 } else {
464 callback_task_runner_->PostTask(
465 FROM_HERE, base::Bind(callback_, status, buffer_, bytes_transferred));
469 /* static */
470 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
471 PlatformUsbTransferHandle platform_transfer) {
472 scoped_ptr<Transfer> transfer(
473 reinterpret_cast<Transfer*>(platform_transfer->user_data));
474 DCHECK(transfer->platform_transfer_ == platform_transfer);
476 // Because device_handle_ is a weak pointer it is guaranteed that the callback
477 // will be discarded if the handle has been freed.
478 Transfer* tmp_transfer = transfer.get(); // base::Passed invalidates transfer
479 tmp_transfer->task_runner_->PostTask(
480 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer,
481 tmp_transfer->device_handle_,
482 base::Passed(&transfer)));
485 UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr<UsbContext> context,
486 scoped_refptr<UsbDeviceImpl> device,
487 PlatformUsbDeviceHandle handle)
488 : device_(device),
489 handle_(handle),
490 context_(context),
491 task_runner_(base::ThreadTaskRunnerHandle::Get()),
492 weak_factory_(this) {
493 DCHECK(handle) << "Cannot create device with NULL handle.";
496 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
497 DCHECK(thread_checker_.CalledOnValidThread());
499 libusb_close(handle_);
500 handle_ = NULL;
503 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
504 return device_;
507 void UsbDeviceHandleImpl::Close() {
508 DCHECK(thread_checker_.CalledOnValidThread());
509 if (device_)
510 device_->Close(this);
513 bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value) {
514 DCHECK(thread_checker_.CalledOnValidThread());
515 if (!device_) {
516 return false;
519 for (Transfer* transfer : transfers_) {
520 transfer->Cancel();
522 claimed_interfaces_.clear();
524 int rv = libusb_set_configuration(handle_, configuration_value);
525 if (rv == LIBUSB_SUCCESS) {
526 device_->RefreshConfiguration();
527 RefreshEndpointMap();
528 } else {
529 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
530 << ": " << ConvertPlatformUsbErrorToString(rv);
532 return rv == LIBUSB_SUCCESS;
535 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) {
536 DCHECK(thread_checker_.CalledOnValidThread());
537 if (!device_)
538 return false;
539 if (ContainsKey(claimed_interfaces_, interface_number))
540 return true;
542 scoped_refptr<InterfaceClaimer> claimer =
543 new InterfaceClaimer(this, interface_number);
545 if (claimer->Claim()) {
546 claimed_interfaces_[interface_number] = claimer;
547 RefreshEndpointMap();
548 return true;
550 return false;
553 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) {
554 DCHECK(thread_checker_.CalledOnValidThread());
555 if (!device_)
556 return false;
557 if (!ContainsKey(claimed_interfaces_, interface_number))
558 return false;
560 // Cancel all the transfers on that interface.
561 InterfaceClaimer* interface_claimer =
562 claimed_interfaces_[interface_number].get();
563 for (Transfer* transfer : transfers_) {
564 if (transfer->claimed_interface() == interface_claimer) {
565 transfer->Cancel();
568 claimed_interfaces_.erase(interface_number);
570 RefreshEndpointMap();
571 return true;
574 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
575 const int interface_number,
576 const int alternate_setting) {
577 DCHECK(thread_checker_.CalledOnValidThread());
578 if (!device_)
579 return false;
580 if (!ContainsKey(claimed_interfaces_, interface_number))
581 return false;
582 const int rv = libusb_set_interface_alt_setting(
583 handle_, interface_number, alternate_setting);
584 if (rv == LIBUSB_SUCCESS) {
585 claimed_interfaces_[interface_number]->set_alternate_setting(
586 alternate_setting);
587 RefreshEndpointMap();
588 } else {
589 USB_LOG(EVENT) << "Failed to set interface " << interface_number
590 << " to alternate setting " << alternate_setting << ": "
591 << ConvertPlatformUsbErrorToString(rv);
593 return rv == LIBUSB_SUCCESS;
596 bool UsbDeviceHandleImpl::ResetDevice() {
597 DCHECK(thread_checker_.CalledOnValidThread());
598 if (!device_)
599 return false;
601 const int rv = libusb_reset_device(handle_);
602 if (rv != LIBUSB_SUCCESS) {
603 USB_LOG(EVENT) << "Failed to reset device: "
604 << ConvertPlatformUsbErrorToString(rv);
606 return rv == LIBUSB_SUCCESS;
609 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id,
610 base::string16* string) {
611 if (!GetSupportedLanguages()) {
612 return false;
615 std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id);
616 if (it != strings_.end()) {
617 *string = it->second;
618 return true;
621 for (size_t i = 0; i < languages_.size(); ++i) {
622 // Get the string using language ID.
623 uint16 language_id = languages_[i];
624 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s).
625 base::char16 text[128];
626 int size =
627 libusb_get_string_descriptor(handle_,
628 string_id,
629 language_id,
630 reinterpret_cast<unsigned char*>(&text[0]),
631 sizeof(text));
632 if (size < 0) {
633 USB_LOG(EVENT) << "Failed to get string descriptor " << string_id
634 << " (langid " << language_id
635 << "): " << ConvertPlatformUsbErrorToString(size);
636 continue;
637 } else if (size < 2) {
638 USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
639 << language_id << ") has no header.";
640 continue;
641 // The first 2 bytes of the descriptor are the total length and type tag.
642 } else if ((text[0] & 0xff) != size) {
643 USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
644 << language_id << ") size mismatch: " << (text[0] & 0xff)
645 << " != " << size;
646 continue;
647 } else if ((text[0] >> 8) != LIBUSB_DT_STRING) {
648 USB_LOG(EVENT) << "String descriptor " << string_id << " (langid "
649 << language_id << ") is not a string descriptor.";
650 continue;
653 *string = base::string16(text + 1, (size - 2) / 2);
654 strings_[string_id] = *string;
655 return true;
658 return false;
661 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
662 TransferRequestType request_type,
663 TransferRecipient recipient,
664 uint8 request,
665 uint16 value,
666 uint16 index,
667 net::IOBuffer* buffer,
668 size_t length,
669 unsigned int timeout,
670 const UsbTransferCallback& callback) {
671 if (length > UINT16_MAX) {
672 USB_LOG(USER) << "Transfer too long.";
673 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
674 return;
677 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
678 scoped_refptr<net::IOBuffer> resized_buffer(
679 new net::IOBufferWithSize(static_cast<int>(resized_length)));
680 if (!resized_buffer.get()) {
681 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
682 return;
684 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
685 length);
687 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
688 CreateRequestType(direction, request_type, recipient), request, value,
689 index, static_cast<uint16>(length), resized_buffer, timeout, callback);
690 if (!transfer) {
691 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
692 return;
695 PostOrSubmitTransfer(transfer.Pass());
698 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
699 const uint8 endpoint,
700 net::IOBuffer* buffer,
701 const size_t length,
702 const unsigned int timeout,
703 const UsbTransferCallback& callback) {
704 if (length > INT_MAX) {
705 USB_LOG(USER) << "Transfer too long.";
706 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
707 return;
710 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
711 ConvertTransferDirection(direction) | endpoint, buffer,
712 static_cast<int>(length), timeout, callback);
714 PostOrSubmitTransfer(transfer.Pass());
717 void UsbDeviceHandleImpl::InterruptTransfer(
718 UsbEndpointDirection direction,
719 uint8 endpoint,
720 net::IOBuffer* buffer,
721 size_t length,
722 unsigned int timeout,
723 const UsbTransferCallback& callback) {
724 if (length > INT_MAX) {
725 USB_LOG(USER) << "Transfer too long.";
726 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
727 return;
730 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
731 ConvertTransferDirection(direction) | endpoint, buffer,
732 static_cast<int>(length), timeout, callback);
734 PostOrSubmitTransfer(transfer.Pass());
737 void UsbDeviceHandleImpl::IsochronousTransfer(
738 const UsbEndpointDirection direction,
739 const uint8 endpoint,
740 net::IOBuffer* buffer,
741 const size_t length,
742 const unsigned int packets,
743 const unsigned int packet_length,
744 const unsigned int timeout,
745 const UsbTransferCallback& callback) {
746 if (length > INT_MAX) {
747 USB_LOG(USER) << "Transfer too long.";
748 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
749 return;
752 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
753 ConvertTransferDirection(direction) | endpoint, buffer,
754 static_cast<int>(length), packets, packet_length, timeout, callback);
756 PostOrSubmitTransfer(transfer.Pass());
759 void UsbDeviceHandleImpl::RefreshEndpointMap() {
760 DCHECK(thread_checker_.CalledOnValidThread());
761 endpoint_map_.clear();
762 const UsbConfigDescriptor* config = device_->GetConfiguration();
763 if (config) {
764 for (const auto& map_entry : claimed_interfaces_) {
765 int interface_number = map_entry.first;
766 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
768 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
769 if (iface.interface_number == interface_number &&
770 iface.alternate_setting == claimed_iface->alternate_setting()) {
771 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
772 endpoint_map_[endpoint.address] = interface_number;
774 break;
781 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
782 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
783 if (ContainsKey(endpoint_map_, endpoint))
784 return claimed_interfaces_[endpoint_map_[endpoint]];
785 return NULL;
788 void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr<Transfer> transfer) {
789 if (task_runner_->RunsTasksOnCurrentThread()) {
790 SubmitTransfer(transfer.Pass());
791 } else {
792 task_runner_->PostTask(
793 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, this,
794 base::Passed(&transfer)));
798 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
799 DCHECK(thread_checker_.CalledOnValidThread());
801 if (device_) {
802 if (transfer->Submit(weak_factory_.GetWeakPtr())) {
803 // Transfer is now owned by libusb until its completion callback is run.
804 // This object holds a weak reference.
805 transfers_.insert(transfer.release());
807 } else {
808 transfer->Complete(USB_TRANSFER_DISCONNECT, 0);
812 void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr<Transfer> transfer) {
813 DCHECK(ContainsKey(transfers_, transfer.get()))
814 << "Missing transfer completed";
815 transfers_.erase(transfer.get());
816 transfer->ProcessCompletion();
819 bool UsbDeviceHandleImpl::GetSupportedLanguages() {
820 if (!languages_.empty()) {
821 return true;
824 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s).
825 uint16 languages[128];
826 int size = libusb_get_string_descriptor(
827 handle_,
830 reinterpret_cast<unsigned char*>(&languages[0]),
831 sizeof(languages));
832 if (size < 0) {
833 USB_LOG(EVENT) << "Failed to get list of supported languages: "
834 << ConvertPlatformUsbErrorToString(size);
835 return false;
836 } else if (size < 2) {
837 USB_LOG(EVENT) << "String descriptor zero has no header.";
838 return false;
839 // The first 2 bytes of the descriptor are the total length and type tag.
840 } else if ((languages[0] & 0xff) != size) {
841 USB_LOG(EVENT) << "String descriptor zero size mismatch: "
842 << (languages[0] & 0xff) << " != " << size;
843 return false;
844 } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) {
845 USB_LOG(EVENT) << "String descriptor zero is not a string descriptor.";
846 return false;
849 languages_.assign(languages[1], languages[(size - 2) / 2]);
850 return true;
853 void UsbDeviceHandleImpl::InternalClose() {
854 DCHECK(thread_checker_.CalledOnValidThread());
855 if (!device_)
856 return;
858 // Cancel all the transfers.
859 for (Transfer* transfer : transfers_) {
860 // The callback will be called some time later.
861 transfer->Cancel();
864 // Attempt-release all the interfaces.
865 // It will be retained until the transfer cancellation is finished.
866 claimed_interfaces_.clear();
868 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
869 // finish.
870 device_ = NULL;
873 } // namespace device