Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(923)

Side by Side Diff: device/usb/usb_device_handle_usbfs.cc

Issue 1897483003: Revert of Replace libusb in the Linux/Chrome OS USB I/O path. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « device/usb/usb_device_handle_usbfs.h ('k') | device/usb/usb_device_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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 "device/usb/usb_device_handle_usbfs.h"
6
7 #if defined(OS_ANDROID) && __ANDROID_API__ < 21
8 #include <linux/usb_ch9.h>
9 #else
10 #include <linux/usb/ch9.h>
11 #endif
12
13 #include <linux/usbdevice_fs.h>
14 #include <sys/ioctl.h>
15
16 #include <numeric>
17
18 #include "base/bind.h"
19 #include "base/cancelable_callback.h"
20 #include "base/logging.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/message_loop/message_pump_libevent.h"
23 #include "base/posix/eintr_wrapper.h"
24 #include "base/stl_util.h"
25 #include "base/thread_task_runner_handle.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "components/device_event_log/device_event_log.h"
28 #include "device/usb/usb_device_impl.h"
29 #include "net/base/io_buffer.h"
30
31 namespace device {
32
33 namespace {
34
35 uint8_t ConvertEndpointDirection(UsbEndpointDirection direction) {
36 switch (direction) {
37 case USB_DIRECTION_INBOUND:
38 return USB_DIR_IN;
39 case USB_DIRECTION_OUTBOUND:
40 return USB_DIR_OUT;
41 }
42 NOTREACHED();
43 return 0;
44 }
45
46 uint8_t ConvertRequestType(UsbDeviceHandle::TransferRequestType request_type) {
47 switch (request_type) {
48 case UsbDeviceHandle::STANDARD:
49 return USB_TYPE_STANDARD;
50 case UsbDeviceHandle::CLASS:
51 return USB_TYPE_CLASS;
52 case UsbDeviceHandle::VENDOR:
53 return USB_TYPE_VENDOR;
54 case UsbDeviceHandle::RESERVED:
55 return USB_TYPE_RESERVED;
56 }
57 NOTREACHED();
58 return 0;
59 }
60
61 uint8_t ConvertRecipient(UsbDeviceHandle::TransferRecipient recipient) {
62 switch (recipient) {
63 case UsbDeviceHandle::DEVICE:
64 return USB_RECIP_DEVICE;
65 case UsbDeviceHandle::INTERFACE:
66 return USB_RECIP_INTERFACE;
67 case UsbDeviceHandle::ENDPOINT:
68 return USB_RECIP_ENDPOINT;
69 case UsbDeviceHandle::OTHER:
70 return USB_RECIP_OTHER;
71 }
72 NOTREACHED();
73 return 0;
74 }
75
76 scoped_refptr<net::IOBuffer> BuildControlTransferBuffer(
77 UsbEndpointDirection direction,
78 UsbDeviceHandle::TransferRequestType request_type,
79 UsbDeviceHandle::TransferRecipient recipient,
80 uint8_t request,
81 uint16_t value,
82 uint16_t index,
83 scoped_refptr<net::IOBuffer> original_buffer,
84 size_t length) {
85 scoped_refptr<net::IOBuffer> new_buffer(
86 new net::IOBuffer(length + sizeof(usb_ctrlrequest)));
87 usb_ctrlrequest* setup =
88 reinterpret_cast<usb_ctrlrequest*>(new_buffer->data());
89 setup->bRequestType = ConvertEndpointDirection(direction) |
90 ConvertRequestType(request_type) |
91 ConvertRecipient(recipient);
92 setup->bRequest = request;
93 setup->wValue = value;
94 setup->wIndex = index;
95 setup->wLength = length;
96 memcpy(new_buffer->data() + sizeof(usb_ctrlrequest), original_buffer->data(),
97 length);
98 return new_buffer;
99 }
100
101 uint8_t ConvertTransferType(UsbTransferType type) {
102 switch (type) {
103 case USB_TRANSFER_CONTROL:
104 return USBDEVFS_URB_TYPE_CONTROL;
105 case USB_TRANSFER_ISOCHRONOUS:
106 return USBDEVFS_URB_TYPE_ISO;
107 case USB_TRANSFER_BULK:
108 return USBDEVFS_URB_TYPE_BULK;
109 case USB_TRANSFER_INTERRUPT:
110 return USBDEVFS_URB_TYPE_INTERRUPT;
111 }
112 NOTREACHED();
113 return 0;
114 }
115
116 UsbTransferStatus ConvertTransferResult(int rc) {
117 switch (rc) {
118 case 0:
119 return USB_TRANSFER_COMPLETED;
120 case EPIPE:
121 return USB_TRANSFER_STALLED;
122 case ENODEV:
123 case ESHUTDOWN:
124 return USB_TRANSFER_DISCONNECT;
125 default:
126 // TODO(reillyg): Add a specific error message whenever one of the cases
127 // above fails to match.
128 USB_LOG(ERROR) << "Unknown system error: "
129 << logging::SystemErrorCodeToString(rc);
130 return USB_TRANSFER_ERROR;
131 }
132 }
133
134 } // namespace
135
136 class UsbDeviceHandleUsbfs::FileThreadHelper
137 : public base::MessagePumpLibevent::Watcher,
138 public base::MessageLoop::DestructionObserver {
139 public:
140 FileThreadHelper(int fd,
141 scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
142 scoped_refptr<base::SequencedTaskRunner> task_runner);
143 ~FileThreadHelper() override;
144
145 static void Start(scoped_ptr<FileThreadHelper> self);
146
147 // base::MessagePumpLibevent::Watcher overrides.
148 void OnFileCanReadWithoutBlocking(int fd) override;
149 void OnFileCanWriteWithoutBlocking(int fd) override;
150
151 // base::MessageLoop::DestructionObserver overrides.
152 void WillDestroyCurrentMessageLoop() override;
153
154 private:
155 int fd_;
156 scoped_refptr<UsbDeviceHandleUsbfs> device_handle_;
157 scoped_refptr<base::SequencedTaskRunner> task_runner_;
158 base::MessagePumpLibevent::FileDescriptorWatcher file_watcher_;
159 base::ThreadChecker thread_checker_;
160
161 DISALLOW_COPY_AND_ASSIGN(FileThreadHelper);
162 };
163
164 UsbDeviceHandleUsbfs::FileThreadHelper::FileThreadHelper(
165 int fd,
166 scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
167 scoped_refptr<base::SequencedTaskRunner> task_runner)
168 : fd_(fd), device_handle_(device_handle), task_runner_(task_runner) {}
169
170 UsbDeviceHandleUsbfs::FileThreadHelper::~FileThreadHelper() {
171 DCHECK(thread_checker_.CalledOnValidThread());
172 base::MessageLoop::current()->RemoveDestructionObserver(this);
173 }
174
175 // static
176 void UsbDeviceHandleUsbfs::FileThreadHelper::Start(
177 scoped_ptr<FileThreadHelper> self) {
178 base::ThreadRestrictions::AssertIOAllowed();
179 self->thread_checker_.DetachFromThread();
180
181 // Linux indicates that URBs are available to reap by marking the file
182 // descriptor writable.
183 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
184 self->fd_, true, base::MessageLoopForIO::WATCH_WRITE,
185 &self->file_watcher_, self.get())) {
186 USB_LOG(ERROR) << "Failed to start watching device file descriptor.";
187 }
188
189 // |self| is now owned by the current message loop.
190 base::MessageLoop::current()->AddDestructionObserver(self.release());
191 }
192
193 void UsbDeviceHandleUsbfs::FileThreadHelper::OnFileCanReadWithoutBlocking(
194 int fd) {
195 NOTREACHED(); // Only listening for writability.
196 }
197
198 void UsbDeviceHandleUsbfs::FileThreadHelper::OnFileCanWriteWithoutBlocking(
199 int fd) {
200 DCHECK(thread_checker_.CalledOnValidThread());
201 DCHECK_EQ(fd_, fd);
202
203 const size_t MAX_URBS_PER_EVENT = 10;
204 std::vector<usbdevfs_urb*> urbs;
205 urbs.reserve(MAX_URBS_PER_EVENT);
206 for (size_t i = 0; i < MAX_URBS_PER_EVENT; ++i) {
207 usbdevfs_urb* urb;
208 int rc = HANDLE_EINTR(ioctl(fd_, USBDEVFS_REAPURBNDELAY, &urb));
209 if (rc) {
210 if (errno == EAGAIN)
211 break;
212 USB_PLOG(DEBUG) << "Failed to reap urbs";
213 } else {
214 urbs.push_back(urb);
215 }
216 }
217
218 task_runner_->PostTask(
219 FROM_HERE,
220 base::Bind(&UsbDeviceHandleUsbfs::ReapedUrbs, device_handle_, urbs));
221 }
222
223 void UsbDeviceHandleUsbfs::FileThreadHelper::WillDestroyCurrentMessageLoop() {
224 DCHECK(thread_checker_.CalledOnValidThread());
225 delete this;
226 }
227
228 struct UsbDeviceHandleUsbfs::Transfer {
229 Transfer() = delete;
230 Transfer(scoped_refptr<net::IOBuffer> buffer,
231 const TransferCallback& callback);
232 Transfer(scoped_refptr<net::IOBuffer> buffer,
233 const IsochronousTransferCallback& callback);
234 ~Transfer();
235
236 void* operator new(std::size_t size, size_t number_of_iso_packets);
237
238 scoped_refptr<net::IOBuffer> control_transfer_buffer;
239 scoped_refptr<net::IOBuffer> buffer;
240 TransferCallback callback;
241 IsochronousTransferCallback isoc_callback;
242 base::CancelableClosure timeout_closure;
243 bool timed_out = false;
244
245 // The |urb| field must be the last in the struct so that the extra space
246 // allocated by the overridden new function above extends the length of its
247 // |iso_frame_desc| field.
248 usbdevfs_urb urb;
249
250 private:
251 DISALLOW_COPY_AND_ASSIGN(Transfer);
252 };
253
254 UsbDeviceHandleUsbfs::Transfer::Transfer(scoped_refptr<net::IOBuffer> buffer,
255 const TransferCallback& callback)
256 : buffer(buffer), callback(callback) {
257 memset(&urb, 0, sizeof(urb));
258 urb.usercontext = this;
259 urb.buffer = buffer->data();
260 }
261
262 UsbDeviceHandleUsbfs::Transfer::Transfer(
263 scoped_refptr<net::IOBuffer> buffer,
264 const IsochronousTransferCallback& callback)
265 : buffer(buffer), isoc_callback(callback) {
266 memset(&urb, 0, sizeof(urb) +
267 sizeof(usbdevfs_iso_packet_desc) * urb.number_of_packets);
268 urb.usercontext = this;
269 urb.buffer = buffer->data();
270 }
271
272 UsbDeviceHandleUsbfs::Transfer::~Transfer() = default;
273
274 void* UsbDeviceHandleUsbfs::Transfer::operator new(
275 std::size_t size,
276 size_t number_of_iso_packets) {
277 void* p = ::operator new(
278 size + sizeof(usbdevfs_iso_packet_desc) * number_of_iso_packets);
279 Transfer* transfer = static_cast<Transfer*>(p);
280 transfer->urb.number_of_packets = number_of_iso_packets;
281 return p;
282 }
283
284 UsbDeviceHandleUsbfs::UsbDeviceHandleUsbfs(
285 scoped_refptr<UsbDevice> device,
286 base::ScopedFD fd,
287 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
288 : device_(device),
289 fd_(std::move(fd)),
290 blocking_task_runner_(blocking_task_runner) {
291 DCHECK(device_);
292 DCHECK(fd_.is_valid());
293 DCHECK(blocking_task_runner_);
294
295 task_runner_ = base::ThreadTaskRunnerHandle::Get();
296
297 scoped_ptr<FileThreadHelper> helper(
298 new FileThreadHelper(fd_.get(), this, task_runner_));
299 helper_ = helper.get();
300 blocking_task_runner_->PostTask(
301 FROM_HERE, base::Bind(&FileThreadHelper::Start, base::Passed(&helper)));
302 }
303
304 scoped_refptr<UsbDevice> UsbDeviceHandleUsbfs::GetDevice() const {
305 return device_;
306 }
307
308 void UsbDeviceHandleUsbfs::Close() {
309 // On the |task_runner_| thread check |device_| to see if the handle is
310 // closed. On the |blocking_task_runner_| thread check |fd_.is_valid()| to
311 // see if the handle is closed.
312 DCHECK(device_);
313 #if !defined(OS_ANDROID)
314 static_cast<UsbDeviceImpl*>(device_.get())->HandleClosed(this);
315 #endif
316 device_ = nullptr;
317 blocking_task_runner_->PostTask(
318 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::CloseBlocking, this));
319 }
320
321 void UsbDeviceHandleUsbfs::SetConfiguration(int configuration_value,
322 const ResultCallback& callback) {
323 // USBDEVFS_SETCONFIGURATION synchronously issues a SET_CONFIGURATION request
324 // to the device so it must be performed on a thread where it is okay to
325 // block.
326 blocking_task_runner_->PostTask(
327 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetConfigurationBlocking,
328 this, configuration_value, callback));
329 }
330
331 void UsbDeviceHandleUsbfs::ClaimInterface(int interface_number,
332 const ResultCallback& callback) {
333 if (!device_) {
334 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
335 return;
336 }
337
338 if (ContainsKey(interfaces_, interface_number)) {
339 USB_LOG(DEBUG) << "Interface " << interface_number << " already claimed.";
340 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
341 return;
342 }
343
344 // It appears safe to assume that this ioctl will not block.
345 int rc = HANDLE_EINTR(
346 ioctl(fd_.get(), USBDEVFS_CLAIMINTERFACE, &interface_number));
347 if (rc) {
348 USB_PLOG(DEBUG) << "Failed to claim interface " << interface_number;
349 } else {
350 interfaces_[interface_number].alternate_setting = 0;
351 RefreshEndpointInfo();
352 }
353 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
354 }
355
356 void UsbDeviceHandleUsbfs::ReleaseInterface(int interface_number,
357 const ResultCallback& callback) {
358 // USBDEVFS_RELEASEINTERFACE may issue a SET_INTERFACE request to the
359 // device to restore alternate setting 0 so it must be performed on a thread
360 // where it is okay to block.
361 blocking_task_runner_->PostTask(
362 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ReleaseInterfaceBlocking,
363 this, interface_number, callback));
364 }
365
366 void UsbDeviceHandleUsbfs::SetInterfaceAlternateSetting(
367 int interface_number,
368 int alternate_setting,
369 const ResultCallback& callback) {
370 // USBDEVFS_SETINTERFACE is synchronous because it issues a SET_INTERFACE
371 // request to the device so it must be performed on a thread where it is okay
372 // to block.
373 blocking_task_runner_->PostTask(
374 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetInterfaceBlocking, this,
375 interface_number, alternate_setting, callback));
376 }
377
378 void UsbDeviceHandleUsbfs::ResetDevice(const ResultCallback& callback) {
379 // USBDEVFS_RESET is synchronous because it waits for the port to be reset
380 // and the device re-enumerated so it must be performed on a thread where it
381 // is okay to block.
382 blocking_task_runner_->PostTask(
383 FROM_HERE,
384 base::Bind(&UsbDeviceHandleUsbfs::ResetDeviceBlocking, this, callback));
385 }
386
387 void UsbDeviceHandleUsbfs::ClearHalt(uint8_t endpoint_address,
388 const ResultCallback& callback) {
389 // USBDEVFS_CLEAR_HALT is synchronous because it issues a CLEAR_FEATURE
390 // request to the device so it must be performed on a thread where it is okay
391 // to block.
392 blocking_task_runner_->PostTask(
393 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ClearHaltBlocking, this,
394 endpoint_address, callback));
395 }
396
397 void UsbDeviceHandleUsbfs::ControlTransfer(UsbEndpointDirection direction,
398 TransferRequestType request_type,
399 TransferRecipient recipient,
400 uint8_t request,
401 uint16_t value,
402 uint16_t index,
403 scoped_refptr<net::IOBuffer> buffer,
404 size_t length,
405 unsigned int timeout,
406 const TransferCallback& callback) {
407 if (!device_) {
408 task_runner_->PostTask(
409 FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
410 return;
411 }
412
413 scoped_ptr<Transfer> transfer(new (0) Transfer(buffer, callback));
414 transfer->control_transfer_buffer =
415 BuildControlTransferBuffer(direction, request_type, recipient, request,
416 value, index, buffer, length);
417 transfer->urb.type = USBDEVFS_URB_TYPE_CONTROL;
418 transfer->urb.endpoint = 0;
419 transfer->urb.buffer = transfer->control_transfer_buffer->data();
420 transfer->urb.buffer_length = 8 + length;
421
422 // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
423 // by USBDEVFS_REAPURBNDELAY.
424 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
425 if (rc) {
426 rc = logging::GetLastSystemErrorCode();
427 USB_PLOG(DEBUG) << "Failed to submit control transfer";
428 task_runner_->PostTask(
429 FROM_HERE, base::Bind(callback, ConvertTransferResult(rc), nullptr, 0));
430 } else {
431 SetUpTimeoutCallback(transfer.get(), timeout);
432 transfers_.push_back(std::move(transfer));
433 }
434 }
435
436 void UsbDeviceHandleUsbfs::IsochronousTransferIn(
437 uint8_t endpoint_number,
438 const std::vector<uint32_t>& packet_lengths,
439 unsigned int timeout,
440 const IsochronousTransferCallback& callback) {
441 uint8_t endpoint_address = USB_DIR_IN | endpoint_number;
442 size_t total_length =
443 std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
444 IsochronousTransferInternal(endpoint_address, new net::IOBuffer(total_length),
445 total_length, packet_lengths, timeout, callback);
446 }
447
448 void UsbDeviceHandleUsbfs::IsochronousTransferOut(
449 uint8_t endpoint_number,
450 scoped_refptr<net::IOBuffer> buffer,
451 const std::vector<uint32_t>& packet_lengths,
452 unsigned int timeout,
453 const IsochronousTransferCallback& callback) {
454 uint8_t endpoint_address = USB_DIR_OUT | endpoint_number;
455 size_t total_length =
456 std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
457 IsochronousTransferInternal(endpoint_address, buffer, total_length,
458 packet_lengths, timeout, callback);
459 }
460
461 void UsbDeviceHandleUsbfs::GenericTransfer(UsbEndpointDirection direction,
462 uint8_t endpoint_number,
463 scoped_refptr<net::IOBuffer> buffer,
464 size_t length,
465 unsigned int timeout,
466 const TransferCallback& callback) {
467 if (!device_) {
468 task_runner_->PostTask(
469 FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
470 return;
471 }
472
473 uint8_t endpoint_address =
474 ConvertEndpointDirection(direction) | endpoint_number;
475 auto it = endpoints_.find(endpoint_address);
476 if (it == endpoints_.end()) {
477 USB_LOG(USER) << "Endpoint address " << static_cast<int>(endpoint_address)
478 << " is not part of a claimed interface.";
479 task_runner_->PostTask(
480 FROM_HERE, base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
481 return;
482 }
483
484 scoped_ptr<Transfer> transfer(new (0) Transfer(buffer, callback));
485 transfer->urb.endpoint = endpoint_address;
486 transfer->urb.buffer_length = length;
487 transfer->urb.type = ConvertTransferType(it->second.type);
488
489 // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
490 // by USBDEVFS_REAPURBNDELAY. This code assumes a recent kernel that can
491 // accept arbitrarily large transfer requests, hopefully also using a scatter-
492 // gather list.
493 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
494 if (rc) {
495 rc = logging::GetLastSystemErrorCode();
496 USB_PLOG(DEBUG) << "Failed to submit transfer";
497 task_runner_->PostTask(
498 FROM_HERE, base::Bind(callback, ConvertTransferResult(rc), nullptr, 0));
499 } else {
500 SetUpTimeoutCallback(transfer.get(), timeout);
501 transfers_.push_back(std::move(transfer));
502 }
503 }
504
505 const UsbInterfaceDescriptor* UsbDeviceHandleUsbfs::FindInterfaceByEndpoint(
506 uint8_t endpoint_address) {
507 auto it = endpoints_.find(endpoint_address);
508 if (it != endpoints_.end())
509 return it->second.interface;
510 return nullptr;
511 }
512
513 UsbDeviceHandleUsbfs::~UsbDeviceHandleUsbfs() {
514 DCHECK(!device_) << "Handle must be closed before it is destroyed.";
515 }
516
517 void UsbDeviceHandleUsbfs::CloseBlocking() {
518 fd_.reset(-1);
519 delete helper_;
520 }
521
522 void UsbDeviceHandleUsbfs::SetConfigurationBlocking(
523 int configuration_value,
524 const ResultCallback& callback) {
525 if (!fd_.is_valid()) {
526 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
527 return;
528 }
529
530 int rc = HANDLE_EINTR(
531 ioctl(fd_.get(), USBDEVFS_SETCONFIGURATION, &configuration_value));
532 if (rc)
533 USB_PLOG(DEBUG) << "Failed to set configuration " << configuration_value;
534 task_runner_->PostTask(
535 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetConfigurationComplete,
536 this, configuration_value, rc == 0, callback));
537 }
538
539 void UsbDeviceHandleUsbfs::SetConfigurationComplete(
540 int configuration_value,
541 bool success,
542 const ResultCallback& callback) {
543 if (success && device_) {
544 #if !defined(OS_ANDROID)
545 static_cast<UsbDeviceImpl*>(device_.get())
546 ->ActiveConfigurationChanged(configuration_value);
547 #endif
548 // TODO(reillyg): If all interfaces are unclaimed before a new configuration
549 // is set then this will do nothing. Investigate.
550 RefreshEndpointInfo();
551 }
552 callback.Run(success);
553 }
554
555 void UsbDeviceHandleUsbfs::ReleaseInterfaceBlocking(
556 int interface_number,
557 const ResultCallback& callback) {
558 if (!fd_.is_valid()) {
559 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
560 return;
561 }
562
563 int rc = HANDLE_EINTR(
564 ioctl(fd_.get(), USBDEVFS_RELEASEINTERFACE, &interface_number));
565 if (rc) {
566 USB_PLOG(DEBUG) << "Failed to release interface " << interface_number;
567 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
568 } else {
569 task_runner_->PostTask(
570 FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ReleaseInterfaceComplete,
571 this, interface_number, callback));
572 }
573 }
574
575 void UsbDeviceHandleUsbfs::ReleaseInterfaceComplete(
576 int interface_number,
577 const ResultCallback& callback) {
578 auto it = interfaces_.find(interface_number);
579 DCHECK(it != interfaces_.end());
580 interfaces_.erase(it);
581 RefreshEndpointInfo();
582 callback.Run(true);
583 }
584
585 void UsbDeviceHandleUsbfs::SetInterfaceBlocking(
586 int interface_number,
587 int alternate_setting,
588 const ResultCallback& callback) {
589 if (!fd_.is_valid()) {
590 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
591 return;
592 }
593
594 usbdevfs_setinterface cmd = {0};
595 cmd.interface = interface_number;
596 cmd.altsetting = alternate_setting;
597 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SETINTERFACE, &cmd));
598 if (rc) {
599 USB_PLOG(DEBUG) << "Failed to set interface " << interface_number
600 << " to alternate setting " << alternate_setting;
601 }
602 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
603 }
604
605 void UsbDeviceHandleUsbfs::ResetDeviceBlocking(const ResultCallback& callback) {
606 if (!fd_.is_valid()) {
607 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
608 return;
609 }
610
611 // TODO(reillyg): libusb releases interfaces before and then reclaims
612 // interfaces after a reset. We should probably do this too or document that
613 // callers have to call ClaimInterface as well.
614 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_RESET, nullptr));
615 if (rc)
616 USB_PLOG(DEBUG) << "Failed to reset the device";
617 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
618 }
619
620 void UsbDeviceHandleUsbfs::ClearHaltBlocking(uint8_t endpoint_address,
621 const ResultCallback& callback) {
622 if (!fd_.is_valid()) {
623 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
624 return;
625 }
626
627 int tmp_endpoint = endpoint_address;
628 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_CLEAR_HALT, &tmp_endpoint));
629 if (rc) {
630 USB_PLOG(DEBUG) << "Failed to clear the stall condition on endpoint "
631 << static_cast<int>(endpoint_address);
632 }
633 task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
634 }
635
636 void UsbDeviceHandleUsbfs::IsochronousTransferInternal(
637 uint8_t endpoint_address,
638 scoped_refptr<net::IOBuffer> buffer,
639 size_t total_length,
640 const std::vector<uint32_t>& packet_lengths,
641 unsigned int timeout,
642 const IsochronousTransferCallback& callback) {
643 if (!device_) {
644 ReportIsochronousError(packet_lengths, callback, USB_TRANSFER_DISCONNECT);
645 return;
646 }
647
648 auto it = endpoints_.find(endpoint_address);
649 if (it == endpoints_.end()) {
650 USB_LOG(USER) << "Endpoint address " << static_cast<int>(endpoint_address)
651 << " is not part of a claimed interface.";
652 ReportIsochronousError(packet_lengths, callback, USB_TRANSFER_ERROR);
653 return;
654 }
655
656 scoped_ptr<Transfer> transfer(new (packet_lengths.size())
657 Transfer(buffer, callback));
658 transfer->urb.type = USBDEVFS_URB_TYPE_ISO;
659 transfer->urb.endpoint = endpoint_address;
660 transfer->urb.buffer_length = total_length;
661
662 for (size_t i = 0; i < packet_lengths.size(); ++i)
663 transfer->urb.iso_frame_desc[i].length = packet_lengths[i];
664
665 // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
666 // by USBDEVFS_REAPURBNDELAY. This code assumes a recent kernel that can
667 // accept arbitrarily large transfer requests, hopefully also using a scatter-
668 // gather list.
669 int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
670 if (rc) {
671 rc = logging::GetLastSystemErrorCode();
672 USB_PLOG(DEBUG) << "Failed to submit transfer";
673 ReportIsochronousError(packet_lengths, callback, ConvertTransferResult(rc));
674 } else {
675 SetUpTimeoutCallback(transfer.get(), timeout);
676 transfers_.push_back(std::move(transfer));
677 }
678 }
679
680 void UsbDeviceHandleUsbfs::ReapedUrbs(const std::vector<usbdevfs_urb*>& urbs) {
681 for (const auto& urb : urbs) {
682 Transfer* this_transfer = static_cast<Transfer*>(urb->usercontext);
683 DCHECK_EQ(urb, &this_transfer->urb);
684 auto it = std::find_if(
685 transfers_.begin(), transfers_.end(),
686 [this_transfer](const scoped_ptr<Transfer>& transfer) -> bool {
687 return transfer.get() == this_transfer;
688 });
689 DCHECK(it != transfers_.end());
690 scoped_ptr<Transfer> transfer = std::move(*it);
691 transfers_.erase(it);
692 TransferComplete(std::move(transfer));
693 }
694 }
695
696 void UsbDeviceHandleUsbfs::TransferComplete(scoped_ptr<Transfer> transfer) {
697 if (transfer->timed_out)
698 return;
699
700 // The transfer will soon be freed. Cancel the timeout callback so that the
701 // raw pointer it holds to |transfer| is not used.
702 transfer->timeout_closure.Cancel();
703
704 if (transfer->urb.type == USBDEVFS_URB_TYPE_ISO) {
705 std::vector<IsochronousPacket> packets(transfer->urb.number_of_packets);
706 for (size_t i = 0; i < packets.size(); ++i) {
707 packets[i].length = transfer->urb.iso_frame_desc[i].length;
708 packets[i].transferred_length =
709 transfer->urb.iso_frame_desc[i].actual_length;
710 packets[i].status = ConvertTransferResult(
711 transfer->urb.status == 0 ? transfer->urb.iso_frame_desc[i].status
712 : transfer->urb.status);
713 }
714
715 transfer->isoc_callback.Run(transfer->buffer, packets);
716 } else {
717 if (transfer->urb.status == 0 &&
718 transfer->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
719 // Copy the result of the control transfer back into the original buffer.
720 memcpy(transfer->buffer->data(),
721 transfer->control_transfer_buffer->data() + 8,
722 transfer->urb.actual_length);
723 }
724
725 transfer->callback.Run(ConvertTransferResult(-transfer->urb.status),
726 transfer->buffer, transfer->urb.actual_length);
727 }
728 }
729
730 void UsbDeviceHandleUsbfs::RefreshEndpointInfo() {
731 endpoints_.clear();
732
733 const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
734 if (!config)
735 return;
736
737 for (const auto& entry : interfaces_) {
738 auto interface_it = std::find_if(
739 config->interfaces.begin(), config->interfaces.end(),
740 [entry](const UsbInterfaceDescriptor& interface) {
741 uint8_t interface_number = entry.first;
742 uint8_t alternate_setting = entry.second.alternate_setting;
743 return interface.interface_number == interface_number &&
744 interface.alternate_setting == alternate_setting;
745 });
746 DCHECK(interface_it != config->interfaces.end());
747
748 for (const auto& endpoint : interface_it->endpoints) {
749 EndpointInfo& info = endpoints_[endpoint.address];
750 info.type = endpoint.transfer_type;
751 info.interface = &*interface_it;
752 }
753 }
754 }
755
756 void UsbDeviceHandleUsbfs::ReportIsochronousError(
757 const std::vector<uint32_t>& packet_lengths,
758 const UsbDeviceHandle::IsochronousTransferCallback& callback,
759 UsbTransferStatus status) {
760 std::vector<UsbDeviceHandle::IsochronousPacket> packets(
761 packet_lengths.size());
762 for (size_t i = 0; i < packet_lengths.size(); ++i) {
763 packets[i].length = packet_lengths[i];
764 packets[i].transferred_length = 0;
765 packets[i].status = status;
766 }
767 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr, packets));
768 }
769
770 void UsbDeviceHandleUsbfs::SetUpTimeoutCallback(Transfer* transfer,
771 unsigned int timeout) {
772 if (timeout > 0) {
773 transfer->timeout_closure.Reset(
774 base::Bind(&UsbDeviceHandleUsbfs::TransferTimedOut, transfer));
775 task_runner_->PostDelayedTask(FROM_HERE,
776 transfer->timeout_closure.callback(),
777 base::TimeDelta::FromMilliseconds(timeout));
778 }
779 }
780
781 // static
782 void UsbDeviceHandleUsbfs::TransferTimedOut(Transfer* transfer) {
783 // |transfer| must stay in |transfers_| as it is still being processed by the
784 // kernel and will be reaped later. Just tell the caller that the timeout
785 // elapsed.
786 transfer->timed_out = true;
787 if (transfer->urb.type == USBDEVFS_URB_TYPE_ISO) {
788 std::vector<IsochronousPacket> packets(transfer->urb.number_of_packets);
789 for (size_t i = 0; i < packets.size(); ++i) {
790 packets[i].length = transfer->urb.iso_frame_desc[i].length;
791 packets[i].transferred_length = 0;
792 packets[i].status = USB_TRANSFER_TIMEOUT;
793 }
794 transfer->isoc_callback.Run(transfer->buffer, packets);
795 } else {
796 transfer->callback.Run(USB_TRANSFER_TIMEOUT, transfer->buffer, 0);
797 }
798 }
799
800 } // namespace device
OLDNEW
« no previous file with comments | « device/usb/usb_device_handle_usbfs.h ('k') | device/usb/usb_device_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698