Adding self to OWNERS for Chrome on Android.
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blobc64931c7cba6768c7756fbf06082c2094cde4740
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 "device/usb/usb_context.h"
18 #include "device/usb/usb_descriptors.h"
19 #include "device/usb/usb_device_impl.h"
20 #include "device/usb/usb_error.h"
21 #include "device/usb/usb_service.h"
22 #include "third_party/libusb/src/libusb/libusb.h"
24 namespace device {
26 typedef libusb_device* PlatformUsbDevice;
28 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
30 namespace {
32 static uint8 ConvertTransferDirection(const UsbEndpointDirection direction) {
33 switch (direction) {
34 case USB_DIRECTION_INBOUND:
35 return LIBUSB_ENDPOINT_IN;
36 case USB_DIRECTION_OUTBOUND:
37 return LIBUSB_ENDPOINT_OUT;
38 default:
39 NOTREACHED();
40 return LIBUSB_ENDPOINT_IN;
44 static uint8 CreateRequestType(
45 const UsbEndpointDirection direction,
46 const UsbDeviceHandle::TransferRequestType request_type,
47 const UsbDeviceHandle::TransferRecipient recipient) {
48 uint8 result = ConvertTransferDirection(direction);
50 switch (request_type) {
51 case UsbDeviceHandle::STANDARD:
52 result |= LIBUSB_REQUEST_TYPE_STANDARD;
53 break;
54 case UsbDeviceHandle::CLASS:
55 result |= LIBUSB_REQUEST_TYPE_CLASS;
56 break;
57 case UsbDeviceHandle::VENDOR:
58 result |= LIBUSB_REQUEST_TYPE_VENDOR;
59 break;
60 case UsbDeviceHandle::RESERVED:
61 result |= LIBUSB_REQUEST_TYPE_RESERVED;
62 break;
65 switch (recipient) {
66 case UsbDeviceHandle::DEVICE:
67 result |= LIBUSB_RECIPIENT_DEVICE;
68 break;
69 case UsbDeviceHandle::INTERFACE:
70 result |= LIBUSB_RECIPIENT_INTERFACE;
71 break;
72 case UsbDeviceHandle::ENDPOINT:
73 result |= LIBUSB_RECIPIENT_ENDPOINT;
74 break;
75 case UsbDeviceHandle::OTHER:
76 result |= LIBUSB_RECIPIENT_OTHER;
77 break;
80 return result;
83 static UsbTransferStatus ConvertTransferStatus(
84 const libusb_transfer_status status) {
85 switch (status) {
86 case LIBUSB_TRANSFER_COMPLETED:
87 return USB_TRANSFER_COMPLETED;
88 case LIBUSB_TRANSFER_ERROR:
89 return USB_TRANSFER_ERROR;
90 case LIBUSB_TRANSFER_TIMED_OUT:
91 return USB_TRANSFER_TIMEOUT;
92 case LIBUSB_TRANSFER_STALL:
93 return USB_TRANSFER_STALLED;
94 case LIBUSB_TRANSFER_NO_DEVICE:
95 return USB_TRANSFER_DISCONNECT;
96 case LIBUSB_TRANSFER_OVERFLOW:
97 return USB_TRANSFER_OVERFLOW;
98 case LIBUSB_TRANSFER_CANCELLED:
99 return USB_TRANSFER_CANCELLED;
100 default:
101 NOTREACHED();
102 return USB_TRANSFER_ERROR;
106 } // namespace
108 class UsbDeviceHandleImpl::InterfaceClaimer
109 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> {
110 public:
111 InterfaceClaimer(const scoped_refptr<UsbDeviceHandleImpl> handle,
112 const int interface_number);
114 bool Claim() const;
116 int alternate_setting() const { return alternate_setting_; }
117 void set_alternate_setting(const int alternate_setting) {
118 alternate_setting_ = alternate_setting;
121 private:
122 friend class UsbDevice;
123 friend class base::RefCountedThreadSafe<InterfaceClaimer>;
124 ~InterfaceClaimer();
126 const scoped_refptr<UsbDeviceHandleImpl> handle_;
127 const int interface_number_;
128 int alternate_setting_;
130 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
133 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer(
134 const scoped_refptr<UsbDeviceHandleImpl> handle,
135 const int interface_number)
136 : handle_(handle),
137 interface_number_(interface_number),
138 alternate_setting_(0) {
141 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() {
142 libusb_release_interface(handle_->handle(), interface_number_);
145 bool UsbDeviceHandleImpl::InterfaceClaimer::Claim() const {
146 const int rv = libusb_claim_interface(handle_->handle(), interface_number_);
147 if (rv != LIBUSB_SUCCESS) {
148 VLOG(1) << "Failed to claim interface: "
149 << ConvertPlatformUsbErrorToString(rv);
151 return rv == LIBUSB_SUCCESS;
154 // This inner class owns the underlying libusb_transfer and may outlast
155 // the UsbDeviceHandle that created it.
156 class UsbDeviceHandleImpl::Transfer {
157 public:
158 static scoped_ptr<Transfer> CreateControlTransfer(
159 uint8 type,
160 uint8 request,
161 uint16 value,
162 uint16 index,
163 uint16 length,
164 scoped_refptr<net::IOBuffer> buffer,
165 unsigned int timeout,
166 const UsbTransferCallback& callback);
167 static scoped_ptr<Transfer> CreateBulkTransfer(
168 uint8 endpoint,
169 scoped_refptr<net::IOBuffer> buffer,
170 int length,
171 unsigned int timeout,
172 const UsbTransferCallback& callback);
173 static scoped_ptr<Transfer> CreateInterruptTransfer(
174 uint8 endpoint,
175 scoped_refptr<net::IOBuffer> buffer,
176 int length,
177 unsigned int timeout,
178 const UsbTransferCallback& callback);
179 static scoped_ptr<Transfer> CreateIsochronousTransfer(
180 uint8 endpoint,
181 scoped_refptr<net::IOBuffer> buffer,
182 size_t length,
183 unsigned int packets,
184 unsigned int packet_length,
185 unsigned int timeout,
186 const UsbTransferCallback& callback);
188 ~Transfer();
190 bool Submit(base::WeakPtr<UsbDeviceHandleImpl> device_handle);
191 void Cancel();
192 void ProcessCompletion();
193 void Complete(UsbTransferStatus status, size_t bytes_transferred);
195 const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
196 return claimed_interface_.get();
199 private:
200 Transfer(UsbTransferType transfer_type,
201 scoped_refptr<net::IOBuffer> buffer,
202 size_t length,
203 const UsbTransferCallback& callback);
205 static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
207 UsbTransferType transfer_type_;
208 base::WeakPtr<UsbDeviceHandleImpl> device_handle_;
209 PlatformUsbTransferHandle platform_transfer_;
210 scoped_refptr<net::IOBuffer> buffer_;
211 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
212 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
213 size_t length_;
214 bool cancelled_;
215 UsbTransferCallback callback_;
216 scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
219 // static
220 scoped_ptr<UsbDeviceHandleImpl::Transfer>
221 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
222 uint8 type,
223 uint8 request,
224 uint16 value,
225 uint16 index,
226 uint16 length,
227 scoped_refptr<net::IOBuffer> buffer,
228 unsigned int timeout,
229 const UsbTransferCallback& callback) {
230 scoped_ptr<Transfer> transfer(new Transfer(USB_TRANSFER_CONTROL, buffer,
231 length + LIBUSB_CONTROL_SETUP_SIZE,
232 callback));
234 transfer->platform_transfer_ = libusb_alloc_transfer(0);
235 if (!transfer->platform_transfer_) {
236 LOG(ERROR) << "Failed to allocate control transfer.";
237 return nullptr;
240 libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
241 request, value, index, length);
242 libusb_fill_control_transfer(transfer->platform_transfer_,
243 nullptr, /* filled in by Submit() */
244 reinterpret_cast<uint8*>(buffer->data()),
245 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
246 transfer.get(), timeout);
248 return transfer.Pass();
251 // static
252 scoped_ptr<UsbDeviceHandleImpl::Transfer>
253 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
254 uint8 endpoint,
255 scoped_refptr<net::IOBuffer> buffer,
256 int length,
257 unsigned int timeout,
258 const UsbTransferCallback& callback) {
259 scoped_ptr<Transfer> transfer(
260 new Transfer(USB_TRANSFER_BULK, buffer, length, callback));
262 transfer->platform_transfer_ = libusb_alloc_transfer(0);
263 if (!transfer->platform_transfer_) {
264 LOG(ERROR) << "Failed to allocate bulk transfer.";
265 return nullptr;
268 libusb_fill_bulk_transfer(transfer->platform_transfer_,
269 nullptr, /* filled in by Submit() */
270 endpoint, reinterpret_cast<uint8*>(buffer->data()),
271 static_cast<int>(length),
272 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
273 transfer.get(), timeout);
275 return transfer.Pass();
278 // static
279 scoped_ptr<UsbDeviceHandleImpl::Transfer>
280 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
281 uint8 endpoint,
282 scoped_refptr<net::IOBuffer> buffer,
283 int length,
284 unsigned int timeout,
285 const UsbTransferCallback& callback) {
286 scoped_ptr<Transfer> transfer(
287 new Transfer(USB_TRANSFER_INTERRUPT, buffer, length, callback));
289 transfer->platform_transfer_ = libusb_alloc_transfer(0);
290 if (!transfer->platform_transfer_) {
291 LOG(ERROR) << "Failed to allocate interrupt transfer.";
292 return nullptr;
295 libusb_fill_interrupt_transfer(
296 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
297 endpoint, reinterpret_cast<uint8*>(buffer->data()),
298 static_cast<int>(length),
299 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
300 timeout);
302 return transfer.Pass();
305 // static
306 scoped_ptr<UsbDeviceHandleImpl::Transfer>
307 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
308 uint8 endpoint,
309 scoped_refptr<net::IOBuffer> buffer,
310 size_t length,
311 unsigned int packets,
312 unsigned int packet_length,
313 unsigned int timeout,
314 const UsbTransferCallback& callback) {
315 DCHECK(packets <= length && (packets * packet_length) <= length)
316 << "transfer length is too small";
318 scoped_ptr<Transfer> transfer(
319 new Transfer(USB_TRANSFER_ISOCHRONOUS, buffer, length, callback));
321 transfer->platform_transfer_ = libusb_alloc_transfer(packets);
322 if (!transfer->platform_transfer_) {
323 LOG(ERROR) << "Failed to allocate isochronous transfer.";
324 return nullptr;
327 libusb_fill_iso_transfer(
328 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
329 endpoint, reinterpret_cast<uint8*>(buffer->data()),
330 static_cast<int>(length), packets, &Transfer::PlatformCallback,
331 transfer.get(), timeout);
332 libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
334 return transfer.Pass();
337 UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type,
338 scoped_refptr<net::IOBuffer> buffer,
339 size_t length,
340 const UsbTransferCallback& callback)
341 : transfer_type_(transfer_type),
342 buffer_(buffer),
343 length_(length),
344 cancelled_(false),
345 callback_(callback) {
346 // Remember the thread from which this transfer was created so that |callback|
347 // can be dispatched there.
348 callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
351 UsbDeviceHandleImpl::Transfer::~Transfer() {
352 if (platform_transfer_) {
353 libusb_free_transfer(platform_transfer_);
357 bool UsbDeviceHandleImpl::Transfer::Submit(
358 base::WeakPtr<UsbDeviceHandleImpl> device_handle) {
359 device_handle_ = device_handle;
360 // Remember the thread from which this transfer was submitted so that it can
361 // be marked complete there.
362 task_runner_ = base::ThreadTaskRunnerHandle::Get();
363 // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer
364 // will fail if it requires an interface we didn't claim.
365 claimed_interface_ = device_handle->GetClaimedInterfaceForEndpoint(
366 platform_transfer_->endpoint);
367 platform_transfer_->dev_handle = device_handle_->handle_;
369 const int rv = libusb_submit_transfer(platform_transfer_);
370 if (rv == LIBUSB_SUCCESS) {
371 return true;
372 } else {
373 VLOG(1) << "Failed to submit transfer: "
374 << ConvertPlatformUsbErrorToString(rv);
375 Complete(USB_TRANSFER_ERROR, 0);
376 return false;
380 void UsbDeviceHandleImpl::Transfer::Cancel() {
381 if (!cancelled_) {
382 libusb_cancel_transfer(platform_transfer_);
383 claimed_interface_ = nullptr;
385 cancelled_ = true;
388 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
389 DCHECK_GE(platform_transfer_->actual_length, 0)
390 << "Negative actual length received";
391 size_t actual_length =
392 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
394 DCHECK(length_ >= actual_length)
395 << "data too big for our buffer (libusb failure?)";
397 switch (transfer_type_) {
398 case USB_TRANSFER_CONTROL:
399 // If the transfer is a control transfer we do not expose the control
400 // setup header to the caller. This logic strips off the header if
401 // present before invoking the callback provided with the transfer.
402 if (actual_length > 0) {
403 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
404 << "buffer was not correctly set: too small for the control header";
406 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
407 // If the payload is zero bytes long, pad out the allocated buffer
408 // size to one byte so that an IOBuffer of that size can be allocated.
409 scoped_refptr<net::IOBuffer> resized_buffer =
410 new net::IOBuffer(static_cast<int>(
411 std::max(actual_length, static_cast<size_t>(1))));
412 memcpy(resized_buffer->data(),
413 buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
414 buffer_ = resized_buffer;
417 break;
419 case USB_TRANSFER_ISOCHRONOUS:
420 // Isochronous replies might carry data in the different isoc packets even
421 // if the transfer actual_data value is zero. Furthermore, not all of the
422 // received packets might contain data, so we need to calculate how many
423 // data bytes we are effectively providing and pack the results.
424 if (actual_length == 0) {
425 size_t packet_buffer_start = 0;
426 for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
427 PlatformUsbIsoPacketDescriptor packet =
428 &platform_transfer_->iso_packet_desc[i];
429 if (packet->actual_length > 0) {
430 // We don't need to copy as long as all packets until now provide
431 // all the data the packet can hold.
432 if (actual_length < packet_buffer_start) {
433 CHECK(packet_buffer_start + packet->actual_length <= length_);
434 memmove(buffer_->data() + actual_length,
435 buffer_->data() + packet_buffer_start,
436 packet->actual_length);
438 actual_length += packet->actual_length;
441 packet_buffer_start += packet->length;
444 break;
446 case USB_TRANSFER_BULK:
447 case USB_TRANSFER_INTERRUPT:
448 break;
450 default:
451 NOTREACHED() << "Invalid usb transfer type";
452 break;
455 Complete(ConvertTransferStatus(platform_transfer_->status), actual_length);
458 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status,
459 size_t bytes_transferred) {
460 if (callback_task_runner_->RunsTasksOnCurrentThread()) {
461 callback_.Run(status, buffer_, bytes_transferred);
462 } else {
463 callback_task_runner_->PostTask(
464 FROM_HERE, base::Bind(callback_, status, buffer_, bytes_transferred));
468 /* static */
469 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
470 PlatformUsbTransferHandle platform_transfer) {
471 scoped_ptr<Transfer> transfer(
472 reinterpret_cast<Transfer*>(platform_transfer->user_data));
473 DCHECK(transfer->platform_transfer_ == platform_transfer);
475 // Because device_handle_ is a weak pointer it is guaranteed that the callback
476 // will be discarded if the handle has been freed.
477 Transfer* tmp_transfer = transfer.get(); // base::Passed invalidates transfer
478 tmp_transfer->task_runner_->PostTask(
479 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer,
480 tmp_transfer->device_handle_,
481 base::Passed(&transfer)));
484 UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr<UsbContext> context,
485 scoped_refptr<UsbDeviceImpl> device,
486 PlatformUsbDeviceHandle handle)
487 : device_(device),
488 handle_(handle),
489 context_(context),
490 task_runner_(base::ThreadTaskRunnerHandle::Get()),
491 weak_factory_(this) {
492 DCHECK(handle) << "Cannot create device with NULL handle.";
495 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
496 DCHECK(thread_checker_.CalledOnValidThread());
498 libusb_close(handle_);
499 handle_ = NULL;
502 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
503 return device_;
506 void UsbDeviceHandleImpl::Close() {
507 DCHECK(thread_checker_.CalledOnValidThread());
508 if (device_)
509 device_->Close(this);
512 bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value) {
513 DCHECK(thread_checker_.CalledOnValidThread());
514 if (!device_) {
515 return false;
518 for (Transfer* transfer : transfers_) {
519 transfer->Cancel();
521 claimed_interfaces_.clear();
523 int rv = libusb_set_configuration(handle_, configuration_value);
524 if (rv == LIBUSB_SUCCESS) {
525 device_->RefreshConfiguration();
526 RefreshEndpointMap();
527 } else {
528 VLOG(1) << "Failed to set configuration " << configuration_value << ": "
529 << ConvertPlatformUsbErrorToString(rv);
531 return rv == LIBUSB_SUCCESS;
534 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) {
535 DCHECK(thread_checker_.CalledOnValidThread());
536 if (!device_)
537 return false;
538 if (ContainsKey(claimed_interfaces_, interface_number))
539 return true;
541 scoped_refptr<InterfaceClaimer> claimer =
542 new InterfaceClaimer(this, interface_number);
544 if (claimer->Claim()) {
545 claimed_interfaces_[interface_number] = claimer;
546 RefreshEndpointMap();
547 return true;
549 return false;
552 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) {
553 DCHECK(thread_checker_.CalledOnValidThread());
554 if (!device_)
555 return false;
556 if (!ContainsKey(claimed_interfaces_, interface_number))
557 return false;
559 // Cancel all the transfers on that interface.
560 InterfaceClaimer* interface_claimer =
561 claimed_interfaces_[interface_number].get();
562 for (Transfer* transfer : transfers_) {
563 if (transfer->claimed_interface() == interface_claimer) {
564 transfer->Cancel();
567 claimed_interfaces_.erase(interface_number);
569 RefreshEndpointMap();
570 return true;
573 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
574 const int interface_number,
575 const int alternate_setting) {
576 DCHECK(thread_checker_.CalledOnValidThread());
577 if (!device_)
578 return false;
579 if (!ContainsKey(claimed_interfaces_, interface_number))
580 return false;
581 const int rv = libusb_set_interface_alt_setting(
582 handle_, interface_number, alternate_setting);
583 if (rv == LIBUSB_SUCCESS) {
584 claimed_interfaces_[interface_number]->set_alternate_setting(
585 alternate_setting);
586 RefreshEndpointMap();
587 } else {
588 VLOG(1) << "Failed to set interface (" << interface_number << ", "
589 << alternate_setting
590 << "): " << ConvertPlatformUsbErrorToString(rv);
592 return rv == LIBUSB_SUCCESS;
595 bool UsbDeviceHandleImpl::ResetDevice() {
596 DCHECK(thread_checker_.CalledOnValidThread());
597 if (!device_)
598 return false;
600 const int rv = libusb_reset_device(handle_);
601 if (rv != LIBUSB_SUCCESS) {
602 VLOG(1) << "Failed to reset device: "
603 << ConvertPlatformUsbErrorToString(rv);
605 return rv == LIBUSB_SUCCESS;
608 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id,
609 base::string16* string) {
610 if (!GetSupportedLanguages()) {
611 return false;
614 std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id);
615 if (it != strings_.end()) {
616 *string = it->second;
617 return true;
620 for (size_t i = 0; i < languages_.size(); ++i) {
621 // Get the string using language ID.
622 uint16 language_id = languages_[i];
623 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s).
624 base::char16 text[128];
625 int size =
626 libusb_get_string_descriptor(handle_,
627 string_id,
628 language_id,
629 reinterpret_cast<unsigned char*>(&text[0]),
630 sizeof(text));
631 if (size < 0) {
632 VLOG(1) << "Failed to get string descriptor " << string_id << " (langid "
633 << language_id << "): " << ConvertPlatformUsbErrorToString(size);
634 continue;
635 } else if (size < 2) {
636 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
637 << ") has no header.";
638 continue;
639 // The first 2 bytes of the descriptor are the total length and type tag.
640 } else if ((text[0] & 0xff) != size) {
641 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
642 << ") size mismatch: " << (text[0] & 0xff) << " != " << size;
643 continue;
644 } else if ((text[0] >> 8) != LIBUSB_DT_STRING) {
645 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
646 << ") is not a string descriptor.";
647 continue;
650 *string = base::string16(text + 1, (size - 2) / 2);
651 strings_[string_id] = *string;
652 return true;
655 return false;
658 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
659 TransferRequestType request_type,
660 TransferRecipient recipient,
661 uint8 request,
662 uint16 value,
663 uint16 index,
664 net::IOBuffer* buffer,
665 size_t length,
666 unsigned int timeout,
667 const UsbTransferCallback& callback) {
668 if (length > UINT16_MAX) {
669 LOG(ERROR) << "Transfer too long.";
670 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
671 return;
674 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
675 scoped_refptr<net::IOBuffer> resized_buffer(
676 new net::IOBufferWithSize(static_cast<int>(resized_length)));
677 if (!resized_buffer.get()) {
678 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
679 return;
681 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
682 length);
684 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
685 CreateRequestType(direction, request_type, recipient), request, value,
686 index, static_cast<uint16>(length), resized_buffer, timeout, callback);
687 if (!transfer) {
688 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
689 return;
692 PostOrSubmitTransfer(transfer.Pass());
695 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
696 const uint8 endpoint,
697 net::IOBuffer* buffer,
698 const size_t length,
699 const unsigned int timeout,
700 const UsbTransferCallback& callback) {
701 if (length > INT_MAX) {
702 LOG(ERROR) << "Transfer too long.";
703 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
704 return;
707 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
708 ConvertTransferDirection(direction) | endpoint, buffer,
709 static_cast<int>(length), timeout, callback);
711 PostOrSubmitTransfer(transfer.Pass());
714 void UsbDeviceHandleImpl::InterruptTransfer(
715 UsbEndpointDirection direction,
716 uint8 endpoint,
717 net::IOBuffer* buffer,
718 size_t length,
719 unsigned int timeout,
720 const UsbTransferCallback& callback) {
721 if (length > INT_MAX) {
722 LOG(ERROR) << "Transfer too long.";
723 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
724 return;
727 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
728 ConvertTransferDirection(direction) | endpoint, buffer,
729 static_cast<int>(length), timeout, callback);
731 PostOrSubmitTransfer(transfer.Pass());
734 void UsbDeviceHandleImpl::IsochronousTransfer(
735 const UsbEndpointDirection direction,
736 const uint8 endpoint,
737 net::IOBuffer* buffer,
738 const size_t length,
739 const unsigned int packets,
740 const unsigned int packet_length,
741 const unsigned int timeout,
742 const UsbTransferCallback& callback) {
743 if (length > INT_MAX) {
744 LOG(ERROR) << "Transfer too long.";
745 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
746 return;
749 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
750 ConvertTransferDirection(direction) | endpoint, buffer,
751 static_cast<int>(length), packets, packet_length, timeout, callback);
753 PostOrSubmitTransfer(transfer.Pass());
756 void UsbDeviceHandleImpl::RefreshEndpointMap() {
757 DCHECK(thread_checker_.CalledOnValidThread());
758 endpoint_map_.clear();
759 const UsbConfigDescriptor* config = device_->GetConfiguration();
760 if (config) {
761 for (const auto& map_entry : claimed_interfaces_) {
762 int interface_number = map_entry.first;
763 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
765 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
766 if (iface.interface_number == interface_number &&
767 iface.alternate_setting == claimed_iface->alternate_setting()) {
768 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
769 endpoint_map_[endpoint.address] = interface_number;
771 break;
778 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
779 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
780 if (ContainsKey(endpoint_map_, endpoint))
781 return claimed_interfaces_[endpoint_map_[endpoint]];
782 return NULL;
785 void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr<Transfer> transfer) {
786 if (task_runner_->RunsTasksOnCurrentThread()) {
787 SubmitTransfer(transfer.Pass());
788 } else {
789 task_runner_->PostTask(
790 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, this,
791 base::Passed(&transfer)));
795 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
796 DCHECK(thread_checker_.CalledOnValidThread());
798 if (device_) {
799 if (transfer->Submit(weak_factory_.GetWeakPtr())) {
800 // Transfer is now owned by libusb until its completion callback is run.
801 // This object holds a weak reference.
802 transfers_.insert(transfer.release());
804 } else {
805 transfer->Complete(USB_TRANSFER_DISCONNECT, 0);
809 void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr<Transfer> transfer) {
810 DCHECK(ContainsKey(transfers_, transfer.get()))
811 << "Missing transfer completed";
812 transfers_.erase(transfer.get());
813 transfer->ProcessCompletion();
816 bool UsbDeviceHandleImpl::GetSupportedLanguages() {
817 if (!languages_.empty()) {
818 return true;
821 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s).
822 uint16 languages[128];
823 int size = libusb_get_string_descriptor(
824 handle_,
827 reinterpret_cast<unsigned char*>(&languages[0]),
828 sizeof(languages));
829 if (size < 0) {
830 VLOG(1) << "Failed to get list of supported languages: "
831 << ConvertPlatformUsbErrorToString(size);
832 return false;
833 } else if (size < 2) {
834 VLOG(1) << "String descriptor zero has no header.";
835 return false;
836 // The first 2 bytes of the descriptor are the total length and type tag.
837 } else if ((languages[0] & 0xff) != size) {
838 VLOG(1) << "String descriptor zero size mismatch: " << (languages[0] & 0xff)
839 << " != " << size;
840 return false;
841 } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) {
842 VLOG(1) << "String descriptor zero is not a string descriptor.";
843 return false;
846 languages_.assign(languages[1], languages[(size - 2) / 2]);
847 return true;
850 void UsbDeviceHandleImpl::InternalClose() {
851 DCHECK(thread_checker_.CalledOnValidThread());
852 if (!device_)
853 return;
855 // Cancel all the transfers.
856 for (Transfer* transfer : transfers_) {
857 // The callback will be called some time later.
858 transfer->Cancel();
861 // Attempt-release all the interfaces.
862 // It will be retained until the transfer cancellation is finished.
863 claimed_interfaces_.clear();
865 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
866 // finish.
867 device_ = NULL;
870 } // namespace device