[Mac] Implement Ambient Light API
[chromium-blink-merge.git] / device / usb / usb_device_handle_impl.cc
blob567a854124e4c18ac95517bb86c76c7f9f0ac7d6
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 UsbTransferCallback callback_;
215 scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
218 // static
219 scoped_ptr<UsbDeviceHandleImpl::Transfer>
220 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
221 uint8 type,
222 uint8 request,
223 uint16 value,
224 uint16 index,
225 uint16 length,
226 scoped_refptr<net::IOBuffer> buffer,
227 unsigned int timeout,
228 const UsbTransferCallback& callback) {
229 scoped_ptr<Transfer> transfer(new Transfer(USB_TRANSFER_CONTROL, buffer,
230 length + LIBUSB_CONTROL_SETUP_SIZE,
231 callback));
233 transfer->platform_transfer_ = libusb_alloc_transfer(0);
234 if (!transfer->platform_transfer_) {
235 LOG(ERROR) << "Failed to allocate control transfer.";
236 return nullptr;
239 libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type,
240 request, value, index, length);
241 libusb_fill_control_transfer(transfer->platform_transfer_,
242 nullptr, /* filled in by Submit() */
243 reinterpret_cast<uint8*>(buffer->data()),
244 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
245 transfer.get(), timeout);
247 return transfer.Pass();
250 // static
251 scoped_ptr<UsbDeviceHandleImpl::Transfer>
252 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
253 uint8 endpoint,
254 scoped_refptr<net::IOBuffer> buffer,
255 int length,
256 unsigned int timeout,
257 const UsbTransferCallback& callback) {
258 scoped_ptr<Transfer> transfer(
259 new Transfer(USB_TRANSFER_BULK, buffer, length, callback));
261 transfer->platform_transfer_ = libusb_alloc_transfer(0);
262 if (!transfer->platform_transfer_) {
263 LOG(ERROR) << "Failed to allocate bulk transfer.";
264 return nullptr;
267 libusb_fill_bulk_transfer(transfer->platform_transfer_,
268 nullptr, /* filled in by Submit() */
269 endpoint, reinterpret_cast<uint8*>(buffer->data()),
270 static_cast<int>(length),
271 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
272 transfer.get(), timeout);
274 return transfer.Pass();
277 // static
278 scoped_ptr<UsbDeviceHandleImpl::Transfer>
279 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
280 uint8 endpoint,
281 scoped_refptr<net::IOBuffer> buffer,
282 int length,
283 unsigned int timeout,
284 const UsbTransferCallback& callback) {
285 scoped_ptr<Transfer> transfer(
286 new Transfer(USB_TRANSFER_INTERRUPT, buffer, length, callback));
288 transfer->platform_transfer_ = libusb_alloc_transfer(0);
289 if (!transfer->platform_transfer_) {
290 LOG(ERROR) << "Failed to allocate interrupt transfer.";
291 return nullptr;
294 libusb_fill_interrupt_transfer(
295 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
296 endpoint, reinterpret_cast<uint8*>(buffer->data()),
297 static_cast<int>(length),
298 &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
299 timeout);
301 return transfer.Pass();
304 // static
305 scoped_ptr<UsbDeviceHandleImpl::Transfer>
306 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
307 uint8 endpoint,
308 scoped_refptr<net::IOBuffer> buffer,
309 size_t length,
310 unsigned int packets,
311 unsigned int packet_length,
312 unsigned int timeout,
313 const UsbTransferCallback& callback) {
314 DCHECK(packets <= length && (packets * packet_length) <= length)
315 << "transfer length is too small";
317 scoped_ptr<Transfer> transfer(
318 new Transfer(USB_TRANSFER_ISOCHRONOUS, buffer, length, callback));
320 transfer->platform_transfer_ = libusb_alloc_transfer(packets);
321 if (!transfer->platform_transfer_) {
322 LOG(ERROR) << "Failed to allocate isochronous transfer.";
323 return nullptr;
326 libusb_fill_iso_transfer(
327 transfer->platform_transfer_, nullptr, /* filled in by Submit() */
328 endpoint, reinterpret_cast<uint8*>(buffer->data()),
329 static_cast<int>(length), packets, &Transfer::PlatformCallback,
330 transfer.get(), timeout);
331 libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
333 return transfer.Pass();
336 UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type,
337 scoped_refptr<net::IOBuffer> buffer,
338 size_t length,
339 const UsbTransferCallback& callback)
340 : transfer_type_(transfer_type),
341 buffer_(buffer),
342 length_(length),
343 callback_(callback) {
344 // Remember the thread from which this transfer was created so that |callback|
345 // can be dispatched there.
346 callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
349 UsbDeviceHandleImpl::Transfer::~Transfer() {
350 if (platform_transfer_) {
351 libusb_free_transfer(platform_transfer_);
355 bool UsbDeviceHandleImpl::Transfer::Submit(
356 base::WeakPtr<UsbDeviceHandleImpl> device_handle) {
357 device_handle_ = device_handle;
358 // Remember the thread from which this transfer was submitted so that it can
359 // be marked complete there.
360 task_runner_ = base::ThreadTaskRunnerHandle::Get();
361 // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer
362 // will fail if it requires an interface we didn't claim.
363 claimed_interface_ = device_handle->GetClaimedInterfaceForEndpoint(
364 platform_transfer_->endpoint);
365 platform_transfer_->dev_handle = device_handle_->handle_;
367 const int rv = libusb_submit_transfer(platform_transfer_);
368 if (rv == LIBUSB_SUCCESS) {
369 return true;
370 } else {
371 VLOG(1) << "Failed to submit transfer: "
372 << ConvertPlatformUsbErrorToString(rv);
373 Complete(USB_TRANSFER_ERROR, 0);
374 return false;
378 void UsbDeviceHandleImpl::Transfer::Cancel() {
379 libusb_cancel_transfer(platform_transfer_);
380 claimed_interface_ = nullptr;
383 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
384 DCHECK_GE(platform_transfer_->actual_length, 0)
385 << "Negative actual length received";
386 size_t actual_length =
387 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
389 DCHECK(length_ >= actual_length)
390 << "data too big for our buffer (libusb failure?)";
392 switch (transfer_type_) {
393 case USB_TRANSFER_CONTROL:
394 // If the transfer is a control transfer we do not expose the control
395 // setup header to the caller. This logic strips off the header if
396 // present before invoking the callback provided with the transfer.
397 if (actual_length > 0) {
398 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
399 << "buffer was not correctly set: too small for the control header";
401 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
402 // If the payload is zero bytes long, pad out the allocated buffer
403 // size to one byte so that an IOBuffer of that size can be allocated.
404 scoped_refptr<net::IOBuffer> resized_buffer =
405 new net::IOBuffer(static_cast<int>(
406 std::max(actual_length, static_cast<size_t>(1))));
407 memcpy(resized_buffer->data(),
408 buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
409 buffer_ = resized_buffer;
412 break;
414 case USB_TRANSFER_ISOCHRONOUS:
415 // Isochronous replies might carry data in the different isoc packets even
416 // if the transfer actual_data value is zero. Furthermore, not all of the
417 // received packets might contain data, so we need to calculate how many
418 // data bytes we are effectively providing and pack the results.
419 if (actual_length == 0) {
420 size_t packet_buffer_start = 0;
421 for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
422 PlatformUsbIsoPacketDescriptor packet =
423 &platform_transfer_->iso_packet_desc[i];
424 if (packet->actual_length > 0) {
425 // We don't need to copy as long as all packets until now provide
426 // all the data the packet can hold.
427 if (actual_length < packet_buffer_start) {
428 CHECK(packet_buffer_start + packet->actual_length <= length_);
429 memmove(buffer_->data() + actual_length,
430 buffer_->data() + packet_buffer_start,
431 packet->actual_length);
433 actual_length += packet->actual_length;
436 packet_buffer_start += packet->length;
439 break;
441 case USB_TRANSFER_BULK:
442 case USB_TRANSFER_INTERRUPT:
443 break;
445 default:
446 NOTREACHED() << "Invalid usb transfer type";
447 break;
450 Complete(ConvertTransferStatus(platform_transfer_->status), actual_length);
453 void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status,
454 size_t bytes_transferred) {
455 if (callback_task_runner_->RunsTasksOnCurrentThread()) {
456 callback_.Run(status, buffer_, bytes_transferred);
457 } else {
458 callback_task_runner_->PostTask(
459 FROM_HERE, base::Bind(callback_, status, buffer_, bytes_transferred));
463 /* static */
464 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
465 PlatformUsbTransferHandle platform_transfer) {
466 scoped_ptr<Transfer> transfer(
467 reinterpret_cast<Transfer*>(platform_transfer->user_data));
468 DCHECK(transfer->platform_transfer_ == platform_transfer);
470 // Because device_handle_ is a weak pointer it is guaranteed that the callback
471 // will be discarded if the handle has been freed.
472 Transfer* tmp_transfer = transfer.get(); // base::Passed invalidates transfer
473 tmp_transfer->task_runner_->PostTask(
474 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer,
475 tmp_transfer->device_handle_,
476 base::Passed(&transfer)));
479 UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr<UsbContext> context,
480 scoped_refptr<UsbDeviceImpl> device,
481 PlatformUsbDeviceHandle handle)
482 : device_(device),
483 handle_(handle),
484 context_(context),
485 task_runner_(base::ThreadTaskRunnerHandle::Get()),
486 weak_factory_(this) {
487 DCHECK(handle) << "Cannot create device with NULL handle.";
490 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
491 DCHECK(thread_checker_.CalledOnValidThread());
493 libusb_close(handle_);
494 handle_ = NULL;
497 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
498 return device_;
501 void UsbDeviceHandleImpl::Close() {
502 DCHECK(thread_checker_.CalledOnValidThread());
503 if (device_)
504 device_->Close(this);
507 bool UsbDeviceHandleImpl::SetConfiguration(int configuration_value) {
508 DCHECK(thread_checker_.CalledOnValidThread());
509 if (!device_) {
510 return false;
513 for (Transfer* transfer : transfers_) {
514 transfer->Cancel();
516 claimed_interfaces_.clear();
518 int rv = libusb_set_configuration(handle_, configuration_value);
519 if (rv == LIBUSB_SUCCESS) {
520 device_->RefreshConfiguration();
521 RefreshEndpointMap();
522 } else {
523 VLOG(1) << "Failed to set configuration " << configuration_value << ": "
524 << ConvertPlatformUsbErrorToString(rv);
526 return rv == LIBUSB_SUCCESS;
529 bool UsbDeviceHandleImpl::ClaimInterface(const int interface_number) {
530 DCHECK(thread_checker_.CalledOnValidThread());
531 if (!device_)
532 return false;
533 if (ContainsKey(claimed_interfaces_, interface_number))
534 return true;
536 scoped_refptr<InterfaceClaimer> claimer =
537 new InterfaceClaimer(this, interface_number);
539 if (claimer->Claim()) {
540 claimed_interfaces_[interface_number] = claimer;
541 RefreshEndpointMap();
542 return true;
544 return false;
547 bool UsbDeviceHandleImpl::ReleaseInterface(const int interface_number) {
548 DCHECK(thread_checker_.CalledOnValidThread());
549 if (!device_)
550 return false;
551 if (!ContainsKey(claimed_interfaces_, interface_number))
552 return false;
554 // Cancel all the transfers on that interface.
555 InterfaceClaimer* interface_claimer =
556 claimed_interfaces_[interface_number].get();
557 for (Transfer* transfer : transfers_) {
558 if (transfer->claimed_interface() == interface_claimer) {
559 transfer->Cancel();
562 claimed_interfaces_.erase(interface_number);
564 RefreshEndpointMap();
565 return true;
568 bool UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
569 const int interface_number,
570 const int alternate_setting) {
571 DCHECK(thread_checker_.CalledOnValidThread());
572 if (!device_)
573 return false;
574 if (!ContainsKey(claimed_interfaces_, interface_number))
575 return false;
576 const int rv = libusb_set_interface_alt_setting(
577 handle_, interface_number, alternate_setting);
578 if (rv == LIBUSB_SUCCESS) {
579 claimed_interfaces_[interface_number]->set_alternate_setting(
580 alternate_setting);
581 RefreshEndpointMap();
582 } else {
583 VLOG(1) << "Failed to set interface (" << interface_number << ", "
584 << alternate_setting
585 << "): " << ConvertPlatformUsbErrorToString(rv);
587 return rv == LIBUSB_SUCCESS;
590 bool UsbDeviceHandleImpl::ResetDevice() {
591 DCHECK(thread_checker_.CalledOnValidThread());
592 if (!device_)
593 return false;
595 const int rv = libusb_reset_device(handle_);
596 if (rv != LIBUSB_SUCCESS) {
597 VLOG(1) << "Failed to reset device: "
598 << ConvertPlatformUsbErrorToString(rv);
600 return rv == LIBUSB_SUCCESS;
603 bool UsbDeviceHandleImpl::GetStringDescriptor(uint8 string_id,
604 base::string16* string) {
605 if (!GetSupportedLanguages()) {
606 return false;
609 std::map<uint8, base::string16>::const_iterator it = strings_.find(string_id);
610 if (it != strings_.end()) {
611 *string = it->second;
612 return true;
615 for (size_t i = 0; i < languages_.size(); ++i) {
616 // Get the string using language ID.
617 uint16 language_id = languages_[i];
618 // The 1-byte length field limits the descriptor to 256-bytes (128 char16s).
619 base::char16 text[128];
620 int size =
621 libusb_get_string_descriptor(handle_,
622 string_id,
623 language_id,
624 reinterpret_cast<unsigned char*>(&text[0]),
625 sizeof(text));
626 if (size < 0) {
627 VLOG(1) << "Failed to get string descriptor " << string_id << " (langid "
628 << language_id << "): " << ConvertPlatformUsbErrorToString(size);
629 continue;
630 } else if (size < 2) {
631 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
632 << ") has no header.";
633 continue;
634 // The first 2 bytes of the descriptor are the total length and type tag.
635 } else if ((text[0] & 0xff) != size) {
636 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
637 << ") size mismatch: " << (text[0] & 0xff) << " != " << size;
638 continue;
639 } else if ((text[0] >> 8) != LIBUSB_DT_STRING) {
640 VLOG(1) << "String descriptor " << string_id << " (langid " << language_id
641 << ") is not a string descriptor.";
642 continue;
645 *string = base::string16(text + 1, (size - 2) / 2);
646 strings_[string_id] = *string;
647 return true;
650 return false;
653 void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
654 TransferRequestType request_type,
655 TransferRecipient recipient,
656 uint8 request,
657 uint16 value,
658 uint16 index,
659 net::IOBuffer* buffer,
660 size_t length,
661 unsigned int timeout,
662 const UsbTransferCallback& callback) {
663 if (length > UINT16_MAX) {
664 LOG(ERROR) << "Transfer too long.";
665 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
666 return;
669 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + length;
670 scoped_refptr<net::IOBuffer> resized_buffer(
671 new net::IOBufferWithSize(static_cast<int>(resized_length)));
672 if (!resized_buffer.get()) {
673 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
674 return;
676 memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(),
677 length);
679 scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
680 CreateRequestType(direction, request_type, recipient), request, value,
681 index, static_cast<uint16>(length), resized_buffer, timeout, callback);
682 if (!transfer) {
683 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
684 return;
687 PostOrSubmitTransfer(transfer.Pass());
690 void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction,
691 const uint8 endpoint,
692 net::IOBuffer* buffer,
693 const size_t length,
694 const unsigned int timeout,
695 const UsbTransferCallback& callback) {
696 if (length > INT_MAX) {
697 LOG(ERROR) << "Transfer too long.";
698 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
699 return;
702 scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer(
703 ConvertTransferDirection(direction) | endpoint, buffer,
704 static_cast<int>(length), timeout, callback);
706 PostOrSubmitTransfer(transfer.Pass());
709 void UsbDeviceHandleImpl::InterruptTransfer(
710 UsbEndpointDirection direction,
711 uint8 endpoint,
712 net::IOBuffer* buffer,
713 size_t length,
714 unsigned int timeout,
715 const UsbTransferCallback& callback) {
716 if (length > INT_MAX) {
717 LOG(ERROR) << "Transfer too long.";
718 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
719 return;
722 scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer(
723 ConvertTransferDirection(direction) | endpoint, buffer,
724 static_cast<int>(length), timeout, callback);
726 PostOrSubmitTransfer(transfer.Pass());
729 void UsbDeviceHandleImpl::IsochronousTransfer(
730 const UsbEndpointDirection direction,
731 const uint8 endpoint,
732 net::IOBuffer* buffer,
733 const size_t length,
734 const unsigned int packets,
735 const unsigned int packet_length,
736 const unsigned int timeout,
737 const UsbTransferCallback& callback) {
738 if (length > INT_MAX) {
739 LOG(ERROR) << "Transfer too long.";
740 callback.Run(USB_TRANSFER_ERROR, buffer, 0);
741 return;
744 scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
745 ConvertTransferDirection(direction) | endpoint, buffer,
746 static_cast<int>(length), packets, packet_length, timeout, callback);
748 PostOrSubmitTransfer(transfer.Pass());
751 void UsbDeviceHandleImpl::RefreshEndpointMap() {
752 DCHECK(thread_checker_.CalledOnValidThread());
753 endpoint_map_.clear();
754 const UsbConfigDescriptor* config = device_->GetConfiguration();
755 if (config) {
756 for (const auto& map_entry : claimed_interfaces_) {
757 int interface_number = map_entry.first;
758 const scoped_refptr<InterfaceClaimer>& claimed_iface = map_entry.second;
760 for (const UsbInterfaceDescriptor& iface : config->interfaces) {
761 if (iface.interface_number == interface_number &&
762 iface.alternate_setting == claimed_iface->alternate_setting()) {
763 for (const UsbEndpointDescriptor& endpoint : iface.endpoints) {
764 endpoint_map_[endpoint.address] = interface_number;
766 break;
773 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
774 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(unsigned char endpoint) {
775 if (ContainsKey(endpoint_map_, endpoint))
776 return claimed_interfaces_[endpoint_map_[endpoint]];
777 return NULL;
780 void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr<Transfer> transfer) {
781 if (task_runner_->RunsTasksOnCurrentThread()) {
782 SubmitTransfer(transfer.Pass());
783 } else {
784 task_runner_->PostTask(
785 FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, this,
786 base::Passed(&transfer)));
790 void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) {
791 DCHECK(thread_checker_.CalledOnValidThread());
793 if (device_) {
794 if (transfer->Submit(weak_factory_.GetWeakPtr())) {
795 // Transfer is now owned by libusb until its completion callback is run.
796 // This object holds a weak reference.
797 transfers_.insert(transfer.release());
799 } else {
800 transfer->Complete(USB_TRANSFER_DISCONNECT, 0);
804 void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr<Transfer> transfer) {
805 DCHECK(ContainsKey(transfers_, transfer.get()))
806 << "Missing transfer completed";
807 transfers_.erase(transfer.get());
808 transfer->ProcessCompletion();
811 bool UsbDeviceHandleImpl::GetSupportedLanguages() {
812 if (!languages_.empty()) {
813 return true;
816 // The 1-byte length field limits the descriptor to 256-bytes (128 uint16s).
817 uint16 languages[128];
818 int size = libusb_get_string_descriptor(
819 handle_,
822 reinterpret_cast<unsigned char*>(&languages[0]),
823 sizeof(languages));
824 if (size < 0) {
825 VLOG(1) << "Failed to get list of supported languages: "
826 << ConvertPlatformUsbErrorToString(size);
827 return false;
828 } else if (size < 2) {
829 VLOG(1) << "String descriptor zero has no header.";
830 return false;
831 // The first 2 bytes of the descriptor are the total length and type tag.
832 } else if ((languages[0] & 0xff) != size) {
833 VLOG(1) << "String descriptor zero size mismatch: " << (languages[0] & 0xff)
834 << " != " << size;
835 return false;
836 } else if ((languages[0] >> 8) != LIBUSB_DT_STRING) {
837 VLOG(1) << "String descriptor zero is not a string descriptor.";
838 return false;
841 languages_.assign(languages[1], languages[(size - 2) / 2]);
842 return true;
845 void UsbDeviceHandleImpl::InternalClose() {
846 DCHECK(thread_checker_.CalledOnValidThread());
847 if (!device_)
848 return;
850 // Cancel all the transfers.
851 for (Transfer* transfer : transfers_) {
852 // The callback will be called some time later.
853 transfer->Cancel();
856 // Attempt-release all the interfaces.
857 // It will be retained until the transfer cancellation is finished.
858 claimed_interfaces_.clear();
860 // Cannot close device handle here. Need to wait for libusb_cancel_transfer to
861 // finish.
862 device_ = NULL;
865 } // namespace device