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.
4
5 #include "services/device/usb/usb_device_handle_impl.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <numeric>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/location.h"
16 #include "base/macros.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/sequence_checker.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string16.h"
22 #include "base/threading/scoped_blocking_call.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "components/device_event_log/device_event_log.h"
25 #include "services/device/public/cpp/usb/usb_utils.h"
26 #include "services/device/usb/usb_context.h"
27 #include "services/device/usb/usb_descriptors.h"
28 #include "services/device/usb/usb_device_impl.h"
29 #include "services/device/usb/usb_error.h"
30 #include "services/device/usb/usb_service.h"
31 #include "third_party/libusb/src/libusb/libusb.h"
32
33 namespace device {
34
35 using mojom::UsbControlTransferRecipient;
36 using mojom::UsbControlTransferType;
37 using mojom::UsbIsochronousPacketPtr;
38 using mojom::UsbTransferDirection;
39 using mojom::UsbTransferStatus;
40 using mojom::UsbTransferType;
41
42 void HandleTransferCompletion(PlatformUsbTransferHandle transfer);
43
44 namespace {
45
ConvertTransferDirection(UsbTransferDirection direction)46 uint8_t ConvertTransferDirection(UsbTransferDirection direction) {
47 switch (direction) {
48 case UsbTransferDirection::INBOUND:
49 return LIBUSB_ENDPOINT_IN;
50 case UsbTransferDirection::OUTBOUND:
51 return LIBUSB_ENDPOINT_OUT;
52 }
53 NOTREACHED();
54 return 0;
55 }
56
CreateRequestType(UsbTransferDirection direction,UsbControlTransferType request_type,UsbControlTransferRecipient recipient)57 uint8_t CreateRequestType(UsbTransferDirection direction,
58 UsbControlTransferType request_type,
59 UsbControlTransferRecipient recipient) {
60 uint8_t result = ConvertTransferDirection(direction);
61
62 switch (request_type) {
63 case UsbControlTransferType::STANDARD:
64 result |= LIBUSB_REQUEST_TYPE_STANDARD;
65 break;
66 case UsbControlTransferType::CLASS:
67 result |= LIBUSB_REQUEST_TYPE_CLASS;
68 break;
69 case UsbControlTransferType::VENDOR:
70 result |= LIBUSB_REQUEST_TYPE_VENDOR;
71 break;
72 case UsbControlTransferType::RESERVED:
73 result |= LIBUSB_REQUEST_TYPE_RESERVED;
74 break;
75 }
76
77 switch (recipient) {
78 case UsbControlTransferRecipient::DEVICE:
79 result |= LIBUSB_RECIPIENT_DEVICE;
80 break;
81 case UsbControlTransferRecipient::INTERFACE:
82 result |= LIBUSB_RECIPIENT_INTERFACE;
83 break;
84 case UsbControlTransferRecipient::ENDPOINT:
85 result |= LIBUSB_RECIPIENT_ENDPOINT;
86 break;
87 case UsbControlTransferRecipient::OTHER:
88 result |= LIBUSB_RECIPIENT_OTHER;
89 break;
90 }
91
92 return result;
93 }
94
ConvertTransferStatus(const libusb_transfer_status status)95 static UsbTransferStatus ConvertTransferStatus(
96 const libusb_transfer_status status) {
97 switch (status) {
98 case LIBUSB_TRANSFER_COMPLETED:
99 return UsbTransferStatus::COMPLETED;
100 case LIBUSB_TRANSFER_ERROR:
101 return UsbTransferStatus::TRANSFER_ERROR;
102 case LIBUSB_TRANSFER_TIMED_OUT:
103 return UsbTransferStatus::TIMEOUT;
104 case LIBUSB_TRANSFER_STALL:
105 return UsbTransferStatus::STALLED;
106 case LIBUSB_TRANSFER_NO_DEVICE:
107 return UsbTransferStatus::DISCONNECT;
108 case LIBUSB_TRANSFER_OVERFLOW:
109 return UsbTransferStatus::BABBLE;
110 case LIBUSB_TRANSFER_CANCELLED:
111 return UsbTransferStatus::CANCELLED;
112 }
113 NOTREACHED();
114 return UsbTransferStatus::TRANSFER_ERROR;
115 }
116
117 } // namespace
118
119 class UsbDeviceHandleImpl::InterfaceClaimer
120 : public base::RefCountedThreadSafe<UsbDeviceHandleImpl::InterfaceClaimer> {
121 public:
122 InterfaceClaimer(scoped_refptr<UsbDeviceHandleImpl> handle,
123 int interface_number,
124 scoped_refptr<base::SequencedTaskRunner> task_runner);
125
interface_number() const126 int interface_number() const { return interface_number_; }
alternate_setting() const127 int alternate_setting() const { return alternate_setting_; }
set_alternate_setting(const int alternate_setting)128 void set_alternate_setting(const int alternate_setting) {
129 alternate_setting_ = alternate_setting;
130 }
131
set_release_callback(ResultCallback callback)132 void set_release_callback(ResultCallback callback) {
133 release_callback_ = std::move(callback);
134 }
135
136 private:
137 friend class base::RefCountedThreadSafe<InterfaceClaimer>;
138 ~InterfaceClaimer();
139
140 const scoped_refptr<UsbDeviceHandleImpl> handle_;
141 const int interface_number_;
142 int alternate_setting_;
143 const scoped_refptr<base::SequencedTaskRunner> task_runner_;
144 ResultCallback release_callback_;
145 base::SequenceChecker sequence_checker_;
146
147 DISALLOW_COPY_AND_ASSIGN(InterfaceClaimer);
148 };
149
InterfaceClaimer(scoped_refptr<UsbDeviceHandleImpl> handle,int interface_number,scoped_refptr<base::SequencedTaskRunner> task_runner)150 UsbDeviceHandleImpl::InterfaceClaimer::InterfaceClaimer(
151 scoped_refptr<UsbDeviceHandleImpl> handle,
152 int interface_number,
153 scoped_refptr<base::SequencedTaskRunner> task_runner)
154 : handle_(handle),
155 interface_number_(interface_number),
156 alternate_setting_(0),
157 task_runner_(task_runner) {}
158
~InterfaceClaimer()159 UsbDeviceHandleImpl::InterfaceClaimer::~InterfaceClaimer() {
160 DCHECK(sequence_checker_.CalledOnValidSequence());
161 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
162 base::BlockingType::MAY_BLOCK);
163 int rc = libusb_release_interface(handle_->handle(), interface_number_);
164 if (rc != LIBUSB_SUCCESS) {
165 USB_LOG(DEBUG) << "Failed to release interface: "
166 << ConvertPlatformUsbErrorToString(rc);
167 }
168 if (!release_callback_.is_null()) {
169 task_runner_->PostTask(
170 FROM_HERE,
171 base::BindOnce(std::move(release_callback_), rc == LIBUSB_SUCCESS));
172 }
173 }
174
175 // This inner class owns the underlying libusb_transfer and may outlast
176 // the UsbDeviceHandle that created it.
177 class UsbDeviceHandleImpl::Transfer {
178 public:
179 // These functions takes |*callback| if they successfully create Transfer
180 // instance, otherwise |*callback| left unchanged.
181 static std::unique_ptr<Transfer> CreateControlTransfer(
182 scoped_refptr<UsbDeviceHandleImpl> device_handle,
183 uint8_t type,
184 uint8_t request,
185 uint16_t value,
186 uint16_t index,
187 uint16_t length,
188 scoped_refptr<base::RefCountedBytes> buffer,
189 unsigned int timeout,
190 TransferCallback* callback);
191 static std::unique_ptr<Transfer> CreateBulkTransfer(
192 scoped_refptr<UsbDeviceHandleImpl> device_handle,
193 uint8_t endpoint,
194 scoped_refptr<base::RefCountedBytes> buffer,
195 int length,
196 unsigned int timeout,
197 TransferCallback* callback);
198 static std::unique_ptr<Transfer> CreateInterruptTransfer(
199 scoped_refptr<UsbDeviceHandleImpl> device_handle,
200 uint8_t endpoint,
201 scoped_refptr<base::RefCountedBytes> buffer,
202 int length,
203 unsigned int timeout,
204 TransferCallback* callback);
205 static std::unique_ptr<Transfer> CreateIsochronousTransfer(
206 scoped_refptr<UsbDeviceHandleImpl> device_handle,
207 uint8_t endpoint,
208 scoped_refptr<base::RefCountedBytes> buffer,
209 size_t length,
210 const std::vector<uint32_t>& packet_lengths,
211 unsigned int timeout,
212 IsochronousTransferCallback* callback);
213
214 ~Transfer();
215
216 void Submit();
217 void Cancel();
218 void ProcessCompletion();
219 void TransferComplete(UsbTransferStatus status, size_t bytes_transferred);
220
claimed_interface() const221 const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const {
222 return claimed_interface_.get();
223 }
224
225 private:
226 Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
227 scoped_refptr<InterfaceClaimer> claimed_interface,
228 UsbTransferType transfer_type,
229 scoped_refptr<base::RefCountedBytes> buffer,
230 size_t length,
231 TransferCallback callback);
232 Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
233 scoped_refptr<InterfaceClaimer> claimed_interface,
234 scoped_refptr<base::RefCountedBytes> buffer,
235 IsochronousTransferCallback callback);
236
237 static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
238
239 void IsochronousTransferComplete();
240
241 UsbTransferType transfer_type_;
242 scoped_refptr<UsbDeviceHandleImpl> device_handle_;
243 PlatformUsbTransferHandle platform_transfer_ = nullptr;
244 scoped_refptr<base::RefCountedBytes> buffer_;
245 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_;
246 size_t length_;
247 bool cancelled_ = false;
248 TransferCallback callback_;
249 IsochronousTransferCallback iso_callback_;
250 scoped_refptr<base::SequencedTaskRunner> task_runner_;
251 };
252
253 // static
254 std::unique_ptr<UsbDeviceHandleImpl::Transfer>
CreateControlTransfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,uint8_t type,uint8_t request,uint16_t value,uint16_t index,uint16_t length,scoped_refptr<base::RefCountedBytes> buffer,unsigned int timeout,TransferCallback * callback)255 UsbDeviceHandleImpl::Transfer::CreateControlTransfer(
256 scoped_refptr<UsbDeviceHandleImpl> device_handle,
257 uint8_t type,
258 uint8_t request,
259 uint16_t value,
260 uint16_t index,
261 uint16_t length,
262 scoped_refptr<base::RefCountedBytes> buffer,
263 unsigned int timeout,
264 TransferCallback* callback) {
265 std::unique_ptr<Transfer> transfer(
266 new Transfer(device_handle, nullptr, UsbTransferType::CONTROL, buffer,
267 length + LIBUSB_CONTROL_SETUP_SIZE, std::move(*callback)));
268
269 transfer->platform_transfer_ = libusb_alloc_transfer(0);
270 if (!transfer->platform_transfer_) {
271 USB_LOG(ERROR) << "Failed to allocate control transfer.";
272 *callback = std::move(transfer->callback_);
273 return nullptr;
274 }
275
276 libusb_fill_control_setup(buffer->front(), type, request, value, index,
277 length);
278 libusb_fill_control_transfer(transfer->platform_transfer_,
279 device_handle->handle(), buffer->front(),
280 &UsbDeviceHandleImpl::Transfer::PlatformCallback,
281 transfer.get(), timeout);
282
283 return transfer;
284 }
285
286 // static
287 std::unique_ptr<UsbDeviceHandleImpl::Transfer>
CreateBulkTransfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,uint8_t endpoint,scoped_refptr<base::RefCountedBytes> buffer,int length,unsigned int timeout,TransferCallback * callback)288 UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
289 scoped_refptr<UsbDeviceHandleImpl> device_handle,
290 uint8_t endpoint,
291 scoped_refptr<base::RefCountedBytes> buffer,
292 int length,
293 unsigned int timeout,
294 TransferCallback* callback) {
295 std::unique_ptr<Transfer> transfer(new Transfer(
296 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
297 UsbTransferType::BULK, buffer, length, std::move(*callback)));
298
299 transfer->platform_transfer_ = libusb_alloc_transfer(0);
300 if (!transfer->platform_transfer_) {
301 USB_LOG(ERROR) << "Failed to allocate bulk transfer.";
302 *callback = std::move(transfer->callback_);
303 return nullptr;
304 }
305
306 libusb_fill_bulk_transfer(
307 transfer->platform_transfer_, device_handle->handle(), endpoint,
308 buffer->front(), length, &UsbDeviceHandleImpl::Transfer::PlatformCallback,
309 transfer.get(), timeout);
310
311 return transfer;
312 }
313
314 // static
315 std::unique_ptr<UsbDeviceHandleImpl::Transfer>
CreateInterruptTransfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,uint8_t endpoint,scoped_refptr<base::RefCountedBytes> buffer,int length,unsigned int timeout,TransferCallback * callback)316 UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
317 scoped_refptr<UsbDeviceHandleImpl> device_handle,
318 uint8_t endpoint,
319 scoped_refptr<base::RefCountedBytes> buffer,
320 int length,
321 unsigned int timeout,
322 TransferCallback* callback) {
323 std::unique_ptr<Transfer> transfer(new Transfer(
324 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
325 UsbTransferType::INTERRUPT, buffer, length, std::move(*callback)));
326
327 transfer->platform_transfer_ = libusb_alloc_transfer(0);
328 if (!transfer->platform_transfer_) {
329 USB_LOG(ERROR) << "Failed to allocate interrupt transfer.";
330 *callback = std::move(transfer->callback_);
331 return nullptr;
332 }
333
334 libusb_fill_interrupt_transfer(
335 transfer->platform_transfer_, device_handle->handle(), endpoint,
336 buffer->front(), length, &UsbDeviceHandleImpl::Transfer::PlatformCallback,
337 transfer.get(), timeout);
338
339 return transfer;
340 }
341
342 // static
343 std::unique_ptr<UsbDeviceHandleImpl::Transfer>
CreateIsochronousTransfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,uint8_t endpoint,scoped_refptr<base::RefCountedBytes> buffer,size_t length,const std::vector<uint32_t> & packet_lengths,unsigned int timeout,IsochronousTransferCallback * callback)344 UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
345 scoped_refptr<UsbDeviceHandleImpl> device_handle,
346 uint8_t endpoint,
347 scoped_refptr<base::RefCountedBytes> buffer,
348 size_t length,
349 const std::vector<uint32_t>& packet_lengths,
350 unsigned int timeout,
351 IsochronousTransferCallback* callback) {
352 std::unique_ptr<Transfer> transfer(new Transfer(
353 device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
354 buffer, std::move(*callback)));
355
356 int num_packets = static_cast<int>(packet_lengths.size());
357 transfer->platform_transfer_ = libusb_alloc_transfer(num_packets);
358 if (!transfer->platform_transfer_) {
359 USB_LOG(ERROR) << "Failed to allocate isochronous transfer.";
360 *callback = std::move(transfer->iso_callback_);
361 return nullptr;
362 }
363
364 libusb_fill_iso_transfer(
365 transfer->platform_transfer_, device_handle->handle(), endpoint,
366 buffer->front(), static_cast<int>(length), num_packets,
367 &Transfer::PlatformCallback, transfer.get(), timeout);
368
369 for (size_t i = 0; i < packet_lengths.size(); ++i)
370 transfer->platform_transfer_->iso_packet_desc[i].length = packet_lengths[i];
371
372 return transfer;
373 }
374
Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,scoped_refptr<InterfaceClaimer> claimed_interface,UsbTransferType transfer_type,scoped_refptr<base::RefCountedBytes> buffer,size_t length,TransferCallback callback)375 UsbDeviceHandleImpl::Transfer::Transfer(
376 scoped_refptr<UsbDeviceHandleImpl> device_handle,
377 scoped_refptr<InterfaceClaimer> claimed_interface,
378 UsbTransferType transfer_type,
379 scoped_refptr<base::RefCountedBytes> buffer,
380 size_t length,
381 TransferCallback callback)
382 : transfer_type_(transfer_type),
383 device_handle_(device_handle),
384 buffer_(buffer),
385 claimed_interface_(claimed_interface),
386 length_(length),
387 callback_(std::move(callback)),
388 task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
389
Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,scoped_refptr<InterfaceClaimer> claimed_interface,scoped_refptr<base::RefCountedBytes> buffer,IsochronousTransferCallback callback)390 UsbDeviceHandleImpl::Transfer::Transfer(
391 scoped_refptr<UsbDeviceHandleImpl> device_handle,
392 scoped_refptr<InterfaceClaimer> claimed_interface,
393 scoped_refptr<base::RefCountedBytes> buffer,
394 IsochronousTransferCallback callback)
395 : transfer_type_(UsbTransferType::ISOCHRONOUS),
396 device_handle_(device_handle),
397 buffer_(buffer),
398 claimed_interface_(claimed_interface),
399 iso_callback_(std::move(callback)),
400 task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
401
~Transfer()402 UsbDeviceHandleImpl::Transfer::~Transfer() {
403 if (platform_transfer_) {
404 libusb_free_transfer(platform_transfer_);
405 }
406 }
407
Submit()408 void UsbDeviceHandleImpl::Transfer::Submit() {
409 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
410 base::BlockingType::MAY_BLOCK);
411 const int rv = libusb_submit_transfer(platform_transfer_);
412 if (rv != LIBUSB_SUCCESS) {
413 USB_LOG(EVENT) << "Failed to submit transfer: "
414 << ConvertPlatformUsbErrorToString(rv);
415 TransferComplete(UsbTransferStatus::TRANSFER_ERROR, 0);
416 }
417 }
418
Cancel()419 void UsbDeviceHandleImpl::Transfer::Cancel() {
420 if (!cancelled_) {
421 libusb_cancel_transfer(platform_transfer_);
422 claimed_interface_ = nullptr;
423 }
424 cancelled_ = true;
425 }
426
ProcessCompletion()427 void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
428 DCHECK_GE(platform_transfer_->actual_length, 0)
429 << "Negative actual length received";
430 size_t actual_length =
431 static_cast<size_t>(std::max(platform_transfer_->actual_length, 0));
432
433 DCHECK(length_ >= actual_length)
434 << "data too big for our buffer (libusb failure?)";
435
436 switch (transfer_type_) {
437 case UsbTransferType::CONTROL:
438 // If the transfer is a control transfer we do not expose the control
439 // setup header to the caller. This logic strips off the header if
440 // present before invoking the callback provided with the transfer.
441 if (actual_length > 0) {
442 CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE)
443 << "buffer was not correctly set: too small for the control header";
444
445 if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) {
446 auto resized_buffer =
447 base::MakeRefCounted<base::RefCountedBytes>(actual_length);
448 memcpy(resized_buffer->front(),
449 buffer_->front() + LIBUSB_CONTROL_SETUP_SIZE, actual_length);
450 buffer_ = resized_buffer;
451 }
452 }
453 FALLTHROUGH;
454
455 case UsbTransferType::BULK:
456 case UsbTransferType::INTERRUPT:
457 TransferComplete(ConvertTransferStatus(platform_transfer_->status),
458 actual_length);
459 break;
460
461 case UsbTransferType::ISOCHRONOUS:
462 IsochronousTransferComplete();
463 break;
464
465 default:
466 NOTREACHED() << "Invalid usb transfer type";
467 break;
468 }
469 }
470
471 /* static */
PlatformCallback(PlatformUsbTransferHandle platform_transfer)472 void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
473 PlatformUsbTransferHandle platform_transfer) {
474 Transfer* transfer =
475 reinterpret_cast<Transfer*>(platform_transfer->user_data);
476 DCHECK(transfer->platform_transfer_ == platform_transfer);
477 transfer->ProcessCompletion();
478 }
479
TransferComplete(UsbTransferStatus status,size_t bytes_transferred)480 void UsbDeviceHandleImpl::Transfer::TransferComplete(UsbTransferStatus status,
481 size_t bytes_transferred) {
482 base::OnceClosure closure;
483 if (transfer_type_ == UsbTransferType::ISOCHRONOUS) {
484 DCHECK_NE(LIBUSB_TRANSFER_COMPLETED, platform_transfer_->status);
485 std::vector<UsbIsochronousPacketPtr> packets(
486 platform_transfer_->num_iso_packets);
487 for (size_t i = 0; i < packets.size(); ++i) {
488 packets[i] = mojom::UsbIsochronousPacket::New();
489 packets[i]->length = platform_transfer_->iso_packet_desc[i].length;
490 packets[i]->transferred_length = 0;
491 packets[i]->status = status;
492 }
493 closure =
494 base::BindOnce(std::move(iso_callback_), buffer_, std::move(packets));
495 } else {
496 closure = base::BindOnce(std::move(callback_), status, buffer_,
497 bytes_transferred);
498 }
499 task_runner_->PostTask(
500 FROM_HERE,
501 base::BindOnce(&UsbDeviceHandleImpl::TransferComplete, device_handle_,
502 base::Unretained(this), std::move(closure)));
503 }
504
IsochronousTransferComplete()505 void UsbDeviceHandleImpl::Transfer::IsochronousTransferComplete() {
506 std::vector<UsbIsochronousPacketPtr> packets(
507 platform_transfer_->num_iso_packets);
508 for (size_t i = 0; i < packets.size(); ++i) {
509 packets[i] = mojom::UsbIsochronousPacket::New();
510 packets[i]->length = platform_transfer_->iso_packet_desc[i].length;
511 packets[i]->transferred_length =
512 platform_transfer_->iso_packet_desc[i].actual_length;
513 packets[i]->status =
514 ConvertTransferStatus(platform_transfer_->iso_packet_desc[i].status);
515 }
516 task_runner_->PostTask(
517 FROM_HERE, base::BindOnce(&UsbDeviceHandleImpl::TransferComplete,
518 device_handle_, base::Unretained(this),
519 base::BindOnce(std::move(iso_callback_),
520 buffer_, std::move(packets))));
521 }
522
GetDevice() const523 scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
524 return device_;
525 }
526
Close()527 void UsbDeviceHandleImpl::Close() {
528 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
529
530 if (!device_)
531 return;
532
533 // Cancel all the transfers, their callbacks will be called some time later.
534 for (Transfer* transfer : transfers_)
535 transfer->Cancel();
536
537 // Release all remaining interfaces once their transfers have completed.
538 // This loop must ensure that what may be the final reference is released on
539 // the right thread.
540 for (auto& map_entry : claimed_interfaces_) {
541 blocking_task_runner_->ReleaseSoon(FROM_HERE, std::move(map_entry.second));
542 }
543
544 device_->HandleClosed(this);
545 device_ = nullptr;
546
547 // The device handle cannot be closed here. When libusb_cancel_transfer is
548 // finished the last references to this device will be released and the
549 // destructor will close the handle.
550 }
551
SetConfiguration(int configuration_value,ResultCallback callback)552 void UsbDeviceHandleImpl::SetConfiguration(int configuration_value,
553 ResultCallback callback) {
554 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
555
556 if (!device_) {
557 std::move(callback).Run(false);
558 return;
559 }
560
561 for (Transfer* transfer : transfers_) {
562 transfer->Cancel();
563 }
564 claimed_interfaces_.clear();
565
566 blocking_task_runner_->PostTask(
567 FROM_HERE,
568 base::BindOnce(&UsbDeviceHandleImpl::SetConfigurationBlocking, this,
569 configuration_value, std::move(callback)));
570 }
571
ClaimInterface(int interface_number,ResultCallback callback)572 void UsbDeviceHandleImpl::ClaimInterface(int interface_number,
573 ResultCallback callback) {
574 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
575
576 if (!device_) {
577 std::move(callback).Run(false);
578 return;
579 }
580 if (base::Contains(claimed_interfaces_, interface_number)) {
581 std::move(callback).Run(true);
582 return;
583 }
584
585 blocking_task_runner_->PostTask(
586 FROM_HERE, base::BindOnce(&UsbDeviceHandleImpl::ClaimInterfaceBlocking,
587 this, interface_number, std::move(callback)));
588 }
589
ReleaseInterface(int interface_number,ResultCallback callback)590 void UsbDeviceHandleImpl::ReleaseInterface(int interface_number,
591 ResultCallback callback) {
592 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
593
594 if (!device_ || !base::Contains(claimed_interfaces_, interface_number)) {
595 task_runner_->PostTask(FROM_HERE,
596 base::BindOnce(std::move(callback), false));
597 return;
598 }
599
600 // Cancel all the transfers on that interface.
601 InterfaceClaimer* interface_claimer =
602 claimed_interfaces_[interface_number].get();
603 for (Transfer* transfer : transfers_) {
604 if (transfer->claimed_interface() == interface_claimer) {
605 transfer->Cancel();
606 }
607 }
608 interface_claimer->set_release_callback(std::move(callback));
609 blocking_task_runner_->ReleaseSoon(
610 FROM_HERE, std::move(claimed_interfaces_[interface_number]));
611 claimed_interfaces_.erase(interface_number);
612
613 RefreshEndpointMap();
614 }
615
SetInterfaceAlternateSetting(int interface_number,int alternate_setting,ResultCallback callback)616 void UsbDeviceHandleImpl::SetInterfaceAlternateSetting(
617 int interface_number,
618 int alternate_setting,
619 ResultCallback callback) {
620 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
621
622 if (!device_ || !base::Contains(claimed_interfaces_, interface_number)) {
623 std::move(callback).Run(false);
624 return;
625 }
626
627 blocking_task_runner_->PostTask(
628 FROM_HERE,
629 base::BindOnce(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingBlocking,
630 this, interface_number, alternate_setting,
631 std::move(callback)));
632 }
633
ResetDevice(ResultCallback callback)634 void UsbDeviceHandleImpl::ResetDevice(ResultCallback callback) {
635 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
636
637 if (!device_) {
638 std::move(callback).Run(false);
639 return;
640 }
641
642 blocking_task_runner_->PostTask(
643 FROM_HERE, base::BindOnce(&UsbDeviceHandleImpl::ResetDeviceBlocking, this,
644 std::move(callback)));
645 }
646
ClearHalt(uint8_t endpoint,ResultCallback callback)647 void UsbDeviceHandleImpl::ClearHalt(uint8_t endpoint, ResultCallback callback) {
648 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
649
650 if (!device_) {
651 std::move(callback).Run(false);
652 return;
653 }
654
655 InterfaceClaimer* interface_claimer =
656 GetClaimedInterfaceForEndpoint(endpoint).get();
657 for (Transfer* transfer : transfers_) {
658 if (transfer->claimed_interface() == interface_claimer) {
659 transfer->Cancel();
660 }
661 }
662
663 blocking_task_runner_->PostTask(
664 FROM_HERE, base::BindOnce(&UsbDeviceHandleImpl::ClearHaltBlocking, this,
665 endpoint, std::move(callback)));
666 }
667
ControlTransfer(UsbTransferDirection direction,UsbControlTransferType request_type,UsbControlTransferRecipient recipient,uint8_t request,uint16_t value,uint16_t index,scoped_refptr<base::RefCountedBytes> buffer,unsigned int timeout,TransferCallback callback)668 void UsbDeviceHandleImpl::ControlTransfer(
669 UsbTransferDirection direction,
670 UsbControlTransferType request_type,
671 UsbControlTransferRecipient recipient,
672 uint8_t request,
673 uint16_t value,
674 uint16_t index,
675 scoped_refptr<base::RefCountedBytes> buffer,
676 unsigned int timeout,
677 TransferCallback callback) {
678 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
679
680 if (!device_) {
681 task_runner_->PostTask(
682 FROM_HERE, base::BindOnce(std::move(callback),
683 UsbTransferStatus::DISCONNECT, buffer, 0));
684 return;
685 }
686
687 if (!base::IsValueInRangeForNumericType<uint16_t>(buffer->size())) {
688 USB_LOG(USER) << "Transfer too long.";
689 task_runner_->PostTask(
690 FROM_HERE,
691 base::BindOnce(std::move(callback), UsbTransferStatus::TRANSFER_ERROR,
692 buffer, 0));
693 return;
694 }
695
696 const size_t resized_length = LIBUSB_CONTROL_SETUP_SIZE + buffer->size();
697 auto resized_buffer =
698 base::MakeRefCounted<base::RefCountedBytes>(resized_length);
699 memcpy(resized_buffer->front() + LIBUSB_CONTROL_SETUP_SIZE, buffer->front(),
700 buffer->size());
701
702 std::unique_ptr<Transfer> transfer = Transfer::CreateControlTransfer(
703 this, CreateRequestType(direction, request_type, recipient), request,
704 value, index, static_cast<uint16_t>(buffer->size()), resized_buffer,
705 timeout, &callback);
706 if (!transfer) {
707 DCHECK(callback);
708 task_runner_->PostTask(
709 FROM_HERE,
710 base::BindOnce(std::move(callback), UsbTransferStatus::TRANSFER_ERROR,
711 buffer, 0));
712 return;
713 }
714
715 SubmitTransfer(std::move(transfer));
716 }
717
IsochronousTransferIn(uint8_t endpoint_number,const std::vector<uint32_t> & packet_lengths,unsigned int timeout,IsochronousTransferCallback callback)718 void UsbDeviceHandleImpl::IsochronousTransferIn(
719 uint8_t endpoint_number,
720 const std::vector<uint32_t>& packet_lengths,
721 unsigned int timeout,
722 IsochronousTransferCallback callback) {
723 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
724
725 if (!device_) {
726 ReportIsochronousTransferError(std::move(callback), packet_lengths,
727 UsbTransferStatus::DISCONNECT);
728 return;
729 }
730
731 uint8_t endpoint_address =
732 ConvertTransferDirection(UsbTransferDirection::INBOUND) | endpoint_number;
733 size_t length =
734 std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
735 auto buffer = base::MakeRefCounted<base::RefCountedBytes>(length);
736 std::unique_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
737 this, endpoint_address, buffer, length, packet_lengths, timeout,
738 &callback);
739 DCHECK(transfer);
740 SubmitTransfer(std::move(transfer));
741 }
742
IsochronousTransferOut(uint8_t endpoint_number,scoped_refptr<base::RefCountedBytes> buffer,const std::vector<uint32_t> & packet_lengths,unsigned int timeout,IsochronousTransferCallback callback)743 void UsbDeviceHandleImpl::IsochronousTransferOut(
744 uint8_t endpoint_number,
745 scoped_refptr<base::RefCountedBytes> buffer,
746 const std::vector<uint32_t>& packet_lengths,
747 unsigned int timeout,
748 IsochronousTransferCallback callback) {
749 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
750
751 if (!device_) {
752 ReportIsochronousTransferError(std::move(callback), packet_lengths,
753 UsbTransferStatus::DISCONNECT);
754 return;
755 }
756
757 uint8_t endpoint_address =
758 ConvertTransferDirection(UsbTransferDirection::OUTBOUND) |
759 endpoint_number;
760 size_t length =
761 std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
762 std::unique_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
763 this, endpoint_address, buffer, length, packet_lengths, timeout,
764 &callback);
765 DCHECK(transfer);
766 SubmitTransfer(std::move(transfer));
767 }
768
GenericTransfer(UsbTransferDirection direction,uint8_t endpoint_number,scoped_refptr<base::RefCountedBytes> buffer,unsigned int timeout,TransferCallback callback)769 void UsbDeviceHandleImpl::GenericTransfer(
770 UsbTransferDirection direction,
771 uint8_t endpoint_number,
772 scoped_refptr<base::RefCountedBytes> buffer,
773 unsigned int timeout,
774 TransferCallback callback) {
775 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
776
777 if (!device_) {
778 task_runner_->PostTask(
779 FROM_HERE, base::BindOnce(std::move(callback),
780 UsbTransferStatus::DISCONNECT, buffer, 0));
781 return;
782 }
783
784 uint8_t endpoint_address =
785 ConvertTransferDirection(direction) | endpoint_number;
786 const auto endpoint_it = endpoint_map_.find(endpoint_address);
787 if (endpoint_it == endpoint_map_.end()) {
788 USB_LOG(DEBUG) << "Failed to submit transfer because endpoint "
789 << static_cast<int>(endpoint_address)
790 << " not part of a claimed interface.";
791 task_runner_->PostTask(
792 FROM_HERE,
793 base::BindOnce(std::move(callback), UsbTransferStatus::TRANSFER_ERROR,
794 buffer, 0));
795 return;
796 }
797
798 if (!base::IsValueInRangeForNumericType<int>(buffer->size())) {
799 USB_LOG(DEBUG) << "Transfer too long.";
800 task_runner_->PostTask(
801 FROM_HERE,
802 base::BindOnce(std::move(callback), UsbTransferStatus::TRANSFER_ERROR,
803 buffer, 0));
804 return;
805 }
806
807 std::unique_ptr<Transfer> transfer;
808 UsbTransferType transfer_type = endpoint_it->second.endpoint->type;
809 if (transfer_type == UsbTransferType::BULK) {
810 transfer = Transfer::CreateBulkTransfer(this, endpoint_address, buffer,
811 static_cast<int>(buffer->size()),
812 timeout, &callback);
813 } else if (transfer_type == UsbTransferType::INTERRUPT) {
814 transfer = Transfer::CreateInterruptTransfer(
815 this, endpoint_address, buffer, static_cast<int>(buffer->size()),
816 timeout, &callback);
817 } else {
818 USB_LOG(DEBUG) << "Endpoint " << static_cast<int>(endpoint_address)
819 << " is not a bulk or interrupt endpoint.";
820 task_runner_->PostTask(
821 FROM_HERE,
822 base::BindOnce(std::move(callback), UsbTransferStatus::TRANSFER_ERROR,
823 buffer, 0));
824 return;
825 }
826 DCHECK(transfer);
827 SubmitTransfer(std::move(transfer));
828 }
829
FindInterfaceByEndpoint(uint8_t endpoint_address)830 const mojom::UsbInterfaceInfo* UsbDeviceHandleImpl::FindInterfaceByEndpoint(
831 uint8_t endpoint_address) {
832 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
833
834 const auto endpoint_it = endpoint_map_.find(endpoint_address);
835 if (endpoint_it != endpoint_map_.end())
836 return endpoint_it->second.interface;
837 return nullptr;
838 }
839
UsbDeviceHandleImpl(scoped_refptr<UsbDeviceImpl> device,ScopedLibusbDeviceHandle handle,scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)840 UsbDeviceHandleImpl::UsbDeviceHandleImpl(
841 scoped_refptr<UsbDeviceImpl> device,
842 ScopedLibusbDeviceHandle handle,
843 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
844 : device_(std::move(device)),
845 handle_(std::move(handle)),
846 task_runner_(base::SequencedTaskRunnerHandle::Get()),
847 blocking_task_runner_(blocking_task_runner) {
848 DCHECK(handle_.IsValid()) << "Cannot create device with an invalid handle.";
849 }
850
~UsbDeviceHandleImpl()851 UsbDeviceHandleImpl::~UsbDeviceHandleImpl() {
852 DCHECK(!device_) << "UsbDeviceHandle must be closed before it is destroyed.";
853
854 // This class is RefCountedThreadSafe and so the destructor may be called on
855 // any thread. libusb is not safe to reentrancy so be sure not to try to close
856 // the device from inside a transfer completion callback.
857 if (blocking_task_runner_->RunsTasksInCurrentSequence()) {
858 handle_.Reset();
859 } else {
860 blocking_task_runner_->PostTask(
861 FROM_HERE,
862 base::BindOnce(base::DoNothing::Once<ScopedLibusbDeviceHandle>(),
863 std::move(handle_)));
864 }
865 }
866
SetConfigurationBlocking(int configuration_value,ResultCallback callback)867 void UsbDeviceHandleImpl::SetConfigurationBlocking(int configuration_value,
868 ResultCallback callback) {
869 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
870 base::BlockingType::MAY_BLOCK);
871 int rv = libusb_set_configuration(handle(), configuration_value);
872 if (rv != LIBUSB_SUCCESS) {
873 USB_LOG(EVENT) << "Failed to set configuration " << configuration_value
874 << ": " << ConvertPlatformUsbErrorToString(rv);
875 }
876 task_runner_->PostTask(
877 FROM_HERE,
878 base::BindOnce(&UsbDeviceHandleImpl::SetConfigurationComplete, this,
879 rv == LIBUSB_SUCCESS, std::move(callback)));
880 }
881
SetConfigurationComplete(bool success,ResultCallback callback)882 void UsbDeviceHandleImpl::SetConfigurationComplete(bool success,
883 ResultCallback callback) {
884 if (!device_) {
885 std::move(callback).Run(false);
886 return;
887 }
888
889 if (success) {
890 device_->RefreshActiveConfiguration();
891 RefreshEndpointMap();
892 }
893 std::move(callback).Run(success);
894 }
895
ClaimInterfaceBlocking(int interface_number,ResultCallback callback)896 void UsbDeviceHandleImpl::ClaimInterfaceBlocking(int interface_number,
897 ResultCallback callback) {
898 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
899 base::BlockingType::MAY_BLOCK);
900 int rv = libusb_claim_interface(handle(), interface_number);
901 scoped_refptr<InterfaceClaimer> interface_claimer;
902 if (rv == LIBUSB_SUCCESS) {
903 interface_claimer =
904 new InterfaceClaimer(this, interface_number, task_runner_);
905 } else {
906 USB_LOG(EVENT) << "Failed to claim interface: "
907 << ConvertPlatformUsbErrorToString(rv);
908 }
909 task_runner_->PostTask(
910 FROM_HERE, base::BindOnce(&UsbDeviceHandleImpl::ClaimInterfaceComplete,
911 this, interface_claimer, std::move(callback)));
912 }
913
ClaimInterfaceComplete(scoped_refptr<InterfaceClaimer> interface_claimer,ResultCallback callback)914 void UsbDeviceHandleImpl::ClaimInterfaceComplete(
915 scoped_refptr<InterfaceClaimer> interface_claimer,
916 ResultCallback callback) {
917 if (!device_) {
918 if (interface_claimer) {
919 // Ensure that the InterfaceClaimer is released on the blocking thread.
920 blocking_task_runner_->ReleaseSoon(FROM_HERE,
921 std::move(interface_claimer));
922 }
923
924 std::move(callback).Run(false);
925 return;
926 }
927
928 if (interface_claimer) {
929 claimed_interfaces_[interface_claimer->interface_number()] =
930 interface_claimer;
931 RefreshEndpointMap();
932 }
933 std::move(callback).Run(interface_claimer != nullptr);
934 }
935
SetInterfaceAlternateSettingBlocking(int interface_number,int alternate_setting,ResultCallback callback)936 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingBlocking(
937 int interface_number,
938 int alternate_setting,
939 ResultCallback callback) {
940 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
941 base::BlockingType::MAY_BLOCK);
942 int rv = libusb_set_interface_alt_setting(handle(), interface_number,
943 alternate_setting);
944 if (rv != LIBUSB_SUCCESS) {
945 USB_LOG(EVENT) << "Failed to set interface " << interface_number
946 << " to alternate setting " << alternate_setting << ": "
947 << ConvertPlatformUsbErrorToString(rv);
948 }
949 task_runner_->PostTask(
950 FROM_HERE,
951 base::BindOnce(&UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete,
952 this, interface_number, alternate_setting,
953 rv == LIBUSB_SUCCESS, std::move(callback)));
954 }
955
SetInterfaceAlternateSettingComplete(int interface_number,int alternate_setting,bool success,ResultCallback callback)956 void UsbDeviceHandleImpl::SetInterfaceAlternateSettingComplete(
957 int interface_number,
958 int alternate_setting,
959 bool success,
960 ResultCallback callback) {
961 if (!device_) {
962 std::move(callback).Run(false);
963 return;
964 }
965
966 if (success) {
967 claimed_interfaces_[interface_number]->set_alternate_setting(
968 alternate_setting);
969 RefreshEndpointMap();
970 }
971 std::move(callback).Run(success);
972 }
973
ResetDeviceBlocking(ResultCallback callback)974 void UsbDeviceHandleImpl::ResetDeviceBlocking(ResultCallback callback) {
975 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
976 base::BlockingType::MAY_BLOCK);
977 int rv = libusb_reset_device(handle());
978 if (rv != LIBUSB_SUCCESS) {
979 USB_LOG(EVENT) << "Failed to reset device: "
980 << ConvertPlatformUsbErrorToString(rv);
981 }
982 task_runner_->PostTask(
983 FROM_HERE, base::BindOnce(std::move(callback), rv == LIBUSB_SUCCESS));
984 }
985
ClearHaltBlocking(uint8_t endpoint,ResultCallback callback)986 void UsbDeviceHandleImpl::ClearHaltBlocking(uint8_t endpoint,
987 ResultCallback callback) {
988 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
989 base::BlockingType::MAY_BLOCK);
990 int rv = libusb_clear_halt(handle(), endpoint);
991 if (rv != LIBUSB_SUCCESS) {
992 USB_LOG(EVENT) << "Failed to clear halt: "
993 << ConvertPlatformUsbErrorToString(rv);
994 }
995 task_runner_->PostTask(
996 FROM_HERE, base::BindOnce(std::move(callback), rv == LIBUSB_SUCCESS));
997 }
998
RefreshEndpointMap()999 void UsbDeviceHandleImpl::RefreshEndpointMap() {
1000 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1001 DCHECK(device_);
1002 endpoint_map_.clear();
1003 const mojom::UsbConfigurationInfo* config = device_->GetActiveConfiguration();
1004 if (!config)
1005 return;
1006
1007 for (const auto& map_entry : claimed_interfaces_) {
1008 CombinedInterfaceInfo interface_info = FindInterfaceInfoFromConfig(
1009 config, map_entry.first, map_entry.second->alternate_setting());
1010
1011 if (!interface_info.IsValid())
1012 return;
1013
1014 for (const auto& endpoint : interface_info.alternate->endpoints) {
1015 endpoint_map_[ConvertEndpointNumberToAddress(*endpoint)] = {
1016 interface_info.interface, endpoint.get()};
1017 }
1018 }
1019 }
1020
1021 scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer>
GetClaimedInterfaceForEndpoint(uint8_t endpoint)1022 UsbDeviceHandleImpl::GetClaimedInterfaceForEndpoint(uint8_t endpoint) {
1023 const auto endpoint_it = endpoint_map_.find(endpoint);
1024 if (endpoint_it != endpoint_map_.end())
1025 return claimed_interfaces_[endpoint_it->second.interface->interface_number];
1026 return nullptr;
1027 }
1028
ReportIsochronousTransferError(UsbDeviceHandle::IsochronousTransferCallback callback,const std::vector<uint32_t> packet_lengths,UsbTransferStatus status)1029 void UsbDeviceHandleImpl::ReportIsochronousTransferError(
1030 UsbDeviceHandle::IsochronousTransferCallback callback,
1031 const std::vector<uint32_t> packet_lengths,
1032 UsbTransferStatus status) {
1033 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1034
1035 std::vector<UsbIsochronousPacketPtr> packets(packet_lengths.size());
1036 for (size_t i = 0; i < packet_lengths.size(); ++i) {
1037 packets[i] = mojom::UsbIsochronousPacket::New();
1038 packets[i]->length = packet_lengths[i];
1039 packets[i]->transferred_length = 0;
1040 packets[i]->status = status;
1041 }
1042 task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(callback), nullptr,
1043 std::move(packets)));
1044 }
1045
SubmitTransfer(std::unique_ptr<Transfer> transfer)1046 void UsbDeviceHandleImpl::SubmitTransfer(std::unique_ptr<Transfer> transfer) {
1047 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1048 DCHECK(transfer);
1049
1050 // Transfer is owned by libusb until its completion callback is run. This
1051 // object holds a weak reference.
1052 transfers_.insert(transfer.get());
1053 blocking_task_runner_->PostTask(
1054 FROM_HERE,
1055 base::BindOnce(&Transfer::Submit, base::Unretained(transfer.release())));
1056 }
1057
TransferComplete(Transfer * transfer,base::OnceClosure callback)1058 void UsbDeviceHandleImpl::TransferComplete(Transfer* transfer,
1059 base::OnceClosure callback) {
1060 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1061 DCHECK(base::Contains(transfers_, transfer)) << "Missing transfer completed";
1062 transfers_.erase(transfer);
1063
1064 std::move(callback).Run();
1065
1066 // libusb_free_transfer races with libusb_submit_transfer and only work-
1067 // around is to make sure to call them on the same thread.
1068 blocking_task_runner_->DeleteSoon(FROM_HERE, transfer);
1069 }
1070
1071 } // namespace device
1072