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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/usb/usb_device_handle_usbfs.cc
diff --git a/device/usb/usb_device_handle_usbfs.cc b/device/usb/usb_device_handle_usbfs.cc
deleted file mode 100644
index 693b21e042d82de24c3115baddf642734f184a2d..0000000000000000000000000000000000000000
--- a/device/usb/usb_device_handle_usbfs.cc
+++ /dev/null
@@ -1,800 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/usb/usb_device_handle_usbfs.h"
-
-#if defined(OS_ANDROID) && __ANDROID_API__ < 21
-#include <linux/usb_ch9.h>
-#else
-#include <linux/usb/ch9.h>
-#endif
-
-#include <linux/usbdevice_fs.h>
-#include <sys/ioctl.h>
-
-#include <numeric>
-
-#include "base/bind.h"
-#include "base/cancelable_callback.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_libevent.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/stl_util.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/threading/thread_restrictions.h"
-#include "components/device_event_log/device_event_log.h"
-#include "device/usb/usb_device_impl.h"
-#include "net/base/io_buffer.h"
-
-namespace device {
-
-namespace {
-
-uint8_t ConvertEndpointDirection(UsbEndpointDirection direction) {
- switch (direction) {
- case USB_DIRECTION_INBOUND:
- return USB_DIR_IN;
- case USB_DIRECTION_OUTBOUND:
- return USB_DIR_OUT;
- }
- NOTREACHED();
- return 0;
-}
-
-uint8_t ConvertRequestType(UsbDeviceHandle::TransferRequestType request_type) {
- switch (request_type) {
- case UsbDeviceHandle::STANDARD:
- return USB_TYPE_STANDARD;
- case UsbDeviceHandle::CLASS:
- return USB_TYPE_CLASS;
- case UsbDeviceHandle::VENDOR:
- return USB_TYPE_VENDOR;
- case UsbDeviceHandle::RESERVED:
- return USB_TYPE_RESERVED;
- }
- NOTREACHED();
- return 0;
-}
-
-uint8_t ConvertRecipient(UsbDeviceHandle::TransferRecipient recipient) {
- switch (recipient) {
- case UsbDeviceHandle::DEVICE:
- return USB_RECIP_DEVICE;
- case UsbDeviceHandle::INTERFACE:
- return USB_RECIP_INTERFACE;
- case UsbDeviceHandle::ENDPOINT:
- return USB_RECIP_ENDPOINT;
- case UsbDeviceHandle::OTHER:
- return USB_RECIP_OTHER;
- }
- NOTREACHED();
- return 0;
-}
-
-scoped_refptr<net::IOBuffer> BuildControlTransferBuffer(
- UsbEndpointDirection direction,
- UsbDeviceHandle::TransferRequestType request_type,
- UsbDeviceHandle::TransferRecipient recipient,
- uint8_t request,
- uint16_t value,
- uint16_t index,
- scoped_refptr<net::IOBuffer> original_buffer,
- size_t length) {
- scoped_refptr<net::IOBuffer> new_buffer(
- new net::IOBuffer(length + sizeof(usb_ctrlrequest)));
- usb_ctrlrequest* setup =
- reinterpret_cast<usb_ctrlrequest*>(new_buffer->data());
- setup->bRequestType = ConvertEndpointDirection(direction) |
- ConvertRequestType(request_type) |
- ConvertRecipient(recipient);
- setup->bRequest = request;
- setup->wValue = value;
- setup->wIndex = index;
- setup->wLength = length;
- memcpy(new_buffer->data() + sizeof(usb_ctrlrequest), original_buffer->data(),
- length);
- return new_buffer;
-}
-
-uint8_t ConvertTransferType(UsbTransferType type) {
- switch (type) {
- case USB_TRANSFER_CONTROL:
- return USBDEVFS_URB_TYPE_CONTROL;
- case USB_TRANSFER_ISOCHRONOUS:
- return USBDEVFS_URB_TYPE_ISO;
- case USB_TRANSFER_BULK:
- return USBDEVFS_URB_TYPE_BULK;
- case USB_TRANSFER_INTERRUPT:
- return USBDEVFS_URB_TYPE_INTERRUPT;
- }
- NOTREACHED();
- return 0;
-}
-
-UsbTransferStatus ConvertTransferResult(int rc) {
- switch (rc) {
- case 0:
- return USB_TRANSFER_COMPLETED;
- case EPIPE:
- return USB_TRANSFER_STALLED;
- case ENODEV:
- case ESHUTDOWN:
- return USB_TRANSFER_DISCONNECT;
- default:
- // TODO(reillyg): Add a specific error message whenever one of the cases
- // above fails to match.
- USB_LOG(ERROR) << "Unknown system error: "
- << logging::SystemErrorCodeToString(rc);
- return USB_TRANSFER_ERROR;
- }
-}
-
-} // namespace
-
-class UsbDeviceHandleUsbfs::FileThreadHelper
- : public base::MessagePumpLibevent::Watcher,
- public base::MessageLoop::DestructionObserver {
- public:
- FileThreadHelper(int fd,
- scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
- scoped_refptr<base::SequencedTaskRunner> task_runner);
- ~FileThreadHelper() override;
-
- static void Start(scoped_ptr<FileThreadHelper> self);
-
- // base::MessagePumpLibevent::Watcher overrides.
- void OnFileCanReadWithoutBlocking(int fd) override;
- void OnFileCanWriteWithoutBlocking(int fd) override;
-
- // base::MessageLoop::DestructionObserver overrides.
- void WillDestroyCurrentMessageLoop() override;
-
- private:
- int fd_;
- scoped_refptr<UsbDeviceHandleUsbfs> device_handle_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
- base::MessagePumpLibevent::FileDescriptorWatcher file_watcher_;
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(FileThreadHelper);
-};
-
-UsbDeviceHandleUsbfs::FileThreadHelper::FileThreadHelper(
- int fd,
- scoped_refptr<UsbDeviceHandleUsbfs> device_handle,
- scoped_refptr<base::SequencedTaskRunner> task_runner)
- : fd_(fd), device_handle_(device_handle), task_runner_(task_runner) {}
-
-UsbDeviceHandleUsbfs::FileThreadHelper::~FileThreadHelper() {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-}
-
-// static
-void UsbDeviceHandleUsbfs::FileThreadHelper::Start(
- scoped_ptr<FileThreadHelper> self) {
- base::ThreadRestrictions::AssertIOAllowed();
- self->thread_checker_.DetachFromThread();
-
- // Linux indicates that URBs are available to reap by marking the file
- // descriptor writable.
- if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
- self->fd_, true, base::MessageLoopForIO::WATCH_WRITE,
- &self->file_watcher_, self.get())) {
- USB_LOG(ERROR) << "Failed to start watching device file descriptor.";
- }
-
- // |self| is now owned by the current message loop.
- base::MessageLoop::current()->AddDestructionObserver(self.release());
-}
-
-void UsbDeviceHandleUsbfs::FileThreadHelper::OnFileCanReadWithoutBlocking(
- int fd) {
- NOTREACHED(); // Only listening for writability.
-}
-
-void UsbDeviceHandleUsbfs::FileThreadHelper::OnFileCanWriteWithoutBlocking(
- int fd) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(fd_, fd);
-
- const size_t MAX_URBS_PER_EVENT = 10;
- std::vector<usbdevfs_urb*> urbs;
- urbs.reserve(MAX_URBS_PER_EVENT);
- for (size_t i = 0; i < MAX_URBS_PER_EVENT; ++i) {
- usbdevfs_urb* urb;
- int rc = HANDLE_EINTR(ioctl(fd_, USBDEVFS_REAPURBNDELAY, &urb));
- if (rc) {
- if (errno == EAGAIN)
- break;
- USB_PLOG(DEBUG) << "Failed to reap urbs";
- } else {
- urbs.push_back(urb);
- }
- }
-
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UsbDeviceHandleUsbfs::ReapedUrbs, device_handle_, urbs));
-}
-
-void UsbDeviceHandleUsbfs::FileThreadHelper::WillDestroyCurrentMessageLoop() {
- DCHECK(thread_checker_.CalledOnValidThread());
- delete this;
-}
-
-struct UsbDeviceHandleUsbfs::Transfer {
- Transfer() = delete;
- Transfer(scoped_refptr<net::IOBuffer> buffer,
- const TransferCallback& callback);
- Transfer(scoped_refptr<net::IOBuffer> buffer,
- const IsochronousTransferCallback& callback);
- ~Transfer();
-
- void* operator new(std::size_t size, size_t number_of_iso_packets);
-
- scoped_refptr<net::IOBuffer> control_transfer_buffer;
- scoped_refptr<net::IOBuffer> buffer;
- TransferCallback callback;
- IsochronousTransferCallback isoc_callback;
- base::CancelableClosure timeout_closure;
- bool timed_out = false;
-
- // The |urb| field must be the last in the struct so that the extra space
- // allocated by the overridden new function above extends the length of its
- // |iso_frame_desc| field.
- usbdevfs_urb urb;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Transfer);
-};
-
-UsbDeviceHandleUsbfs::Transfer::Transfer(scoped_refptr<net::IOBuffer> buffer,
- const TransferCallback& callback)
- : buffer(buffer), callback(callback) {
- memset(&urb, 0, sizeof(urb));
- urb.usercontext = this;
- urb.buffer = buffer->data();
-}
-
-UsbDeviceHandleUsbfs::Transfer::Transfer(
- scoped_refptr<net::IOBuffer> buffer,
- const IsochronousTransferCallback& callback)
- : buffer(buffer), isoc_callback(callback) {
- memset(&urb, 0, sizeof(urb) +
- sizeof(usbdevfs_iso_packet_desc) * urb.number_of_packets);
- urb.usercontext = this;
- urb.buffer = buffer->data();
-}
-
-UsbDeviceHandleUsbfs::Transfer::~Transfer() = default;
-
-void* UsbDeviceHandleUsbfs::Transfer::operator new(
- std::size_t size,
- size_t number_of_iso_packets) {
- void* p = ::operator new(
- size + sizeof(usbdevfs_iso_packet_desc) * number_of_iso_packets);
- Transfer* transfer = static_cast<Transfer*>(p);
- transfer->urb.number_of_packets = number_of_iso_packets;
- return p;
-}
-
-UsbDeviceHandleUsbfs::UsbDeviceHandleUsbfs(
- scoped_refptr<UsbDevice> device,
- base::ScopedFD fd,
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
- : device_(device),
- fd_(std::move(fd)),
- blocking_task_runner_(blocking_task_runner) {
- DCHECK(device_);
- DCHECK(fd_.is_valid());
- DCHECK(blocking_task_runner_);
-
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
-
- scoped_ptr<FileThreadHelper> helper(
- new FileThreadHelper(fd_.get(), this, task_runner_));
- helper_ = helper.get();
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&FileThreadHelper::Start, base::Passed(&helper)));
-}
-
-scoped_refptr<UsbDevice> UsbDeviceHandleUsbfs::GetDevice() const {
- return device_;
-}
-
-void UsbDeviceHandleUsbfs::Close() {
- // On the |task_runner_| thread check |device_| to see if the handle is
- // closed. On the |blocking_task_runner_| thread check |fd_.is_valid()| to
- // see if the handle is closed.
- DCHECK(device_);
-#if !defined(OS_ANDROID)
- static_cast<UsbDeviceImpl*>(device_.get())->HandleClosed(this);
-#endif
- device_ = nullptr;
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::CloseBlocking, this));
-}
-
-void UsbDeviceHandleUsbfs::SetConfiguration(int configuration_value,
- const ResultCallback& callback) {
- // USBDEVFS_SETCONFIGURATION synchronously issues a SET_CONFIGURATION request
- // to the device so it must be performed on a thread where it is okay to
- // block.
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetConfigurationBlocking,
- this, configuration_value, callback));
-}
-
-void UsbDeviceHandleUsbfs::ClaimInterface(int interface_number,
- const ResultCallback& callback) {
- if (!device_) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- if (ContainsKey(interfaces_, interface_number)) {
- USB_LOG(DEBUG) << "Interface " << interface_number << " already claimed.";
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- // It appears safe to assume that this ioctl will not block.
- int rc = HANDLE_EINTR(
- ioctl(fd_.get(), USBDEVFS_CLAIMINTERFACE, &interface_number));
- if (rc) {
- USB_PLOG(DEBUG) << "Failed to claim interface " << interface_number;
- } else {
- interfaces_[interface_number].alternate_setting = 0;
- RefreshEndpointInfo();
- }
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
-}
-
-void UsbDeviceHandleUsbfs::ReleaseInterface(int interface_number,
- const ResultCallback& callback) {
- // USBDEVFS_RELEASEINTERFACE may issue a SET_INTERFACE request to the
- // device to restore alternate setting 0 so it must be performed on a thread
- // where it is okay to block.
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ReleaseInterfaceBlocking,
- this, interface_number, callback));
-}
-
-void UsbDeviceHandleUsbfs::SetInterfaceAlternateSetting(
- int interface_number,
- int alternate_setting,
- const ResultCallback& callback) {
- // USBDEVFS_SETINTERFACE is synchronous because it issues a SET_INTERFACE
- // request to the device so it must be performed on a thread where it is okay
- // to block.
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetInterfaceBlocking, this,
- interface_number, alternate_setting, callback));
-}
-
-void UsbDeviceHandleUsbfs::ResetDevice(const ResultCallback& callback) {
- // USBDEVFS_RESET is synchronous because it waits for the port to be reset
- // and the device re-enumerated so it must be performed on a thread where it
- // is okay to block.
- blocking_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UsbDeviceHandleUsbfs::ResetDeviceBlocking, this, callback));
-}
-
-void UsbDeviceHandleUsbfs::ClearHalt(uint8_t endpoint_address,
- const ResultCallback& callback) {
- // USBDEVFS_CLEAR_HALT is synchronous because it issues a CLEAR_FEATURE
- // request to the device so it must be performed on a thread where it is okay
- // to block.
- blocking_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ClearHaltBlocking, this,
- endpoint_address, callback));
-}
-
-void UsbDeviceHandleUsbfs::ControlTransfer(UsbEndpointDirection direction,
- TransferRequestType request_type,
- TransferRecipient recipient,
- uint8_t request,
- uint16_t value,
- uint16_t index,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int timeout,
- const TransferCallback& callback) {
- if (!device_) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
- return;
- }
-
- scoped_ptr<Transfer> transfer(new (0) Transfer(buffer, callback));
- transfer->control_transfer_buffer =
- BuildControlTransferBuffer(direction, request_type, recipient, request,
- value, index, buffer, length);
- transfer->urb.type = USBDEVFS_URB_TYPE_CONTROL;
- transfer->urb.endpoint = 0;
- transfer->urb.buffer = transfer->control_transfer_buffer->data();
- transfer->urb.buffer_length = 8 + length;
-
- // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
- // by USBDEVFS_REAPURBNDELAY.
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
- if (rc) {
- rc = logging::GetLastSystemErrorCode();
- USB_PLOG(DEBUG) << "Failed to submit control transfer";
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, ConvertTransferResult(rc), nullptr, 0));
- } else {
- SetUpTimeoutCallback(transfer.get(), timeout);
- transfers_.push_back(std::move(transfer));
- }
-}
-
-void UsbDeviceHandleUsbfs::IsochronousTransferIn(
- uint8_t endpoint_number,
- const std::vector<uint32_t>& packet_lengths,
- unsigned int timeout,
- const IsochronousTransferCallback& callback) {
- uint8_t endpoint_address = USB_DIR_IN | endpoint_number;
- size_t total_length =
- std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
- IsochronousTransferInternal(endpoint_address, new net::IOBuffer(total_length),
- total_length, packet_lengths, timeout, callback);
-}
-
-void UsbDeviceHandleUsbfs::IsochronousTransferOut(
- uint8_t endpoint_number,
- scoped_refptr<net::IOBuffer> buffer,
- const std::vector<uint32_t>& packet_lengths,
- unsigned int timeout,
- const IsochronousTransferCallback& callback) {
- uint8_t endpoint_address = USB_DIR_OUT | endpoint_number;
- size_t total_length =
- std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
- IsochronousTransferInternal(endpoint_address, buffer, total_length,
- packet_lengths, timeout, callback);
-}
-
-void UsbDeviceHandleUsbfs::GenericTransfer(UsbEndpointDirection direction,
- uint8_t endpoint_number,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int timeout,
- const TransferCallback& callback) {
- if (!device_) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
- return;
- }
-
- uint8_t endpoint_address =
- ConvertEndpointDirection(direction) | endpoint_number;
- auto it = endpoints_.find(endpoint_address);
- if (it == endpoints_.end()) {
- USB_LOG(USER) << "Endpoint address " << static_cast<int>(endpoint_address)
- << " is not part of a claimed interface.";
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
- return;
- }
-
- scoped_ptr<Transfer> transfer(new (0) Transfer(buffer, callback));
- transfer->urb.endpoint = endpoint_address;
- transfer->urb.buffer_length = length;
- transfer->urb.type = ConvertTransferType(it->second.type);
-
- // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
- // by USBDEVFS_REAPURBNDELAY. This code assumes a recent kernel that can
- // accept arbitrarily large transfer requests, hopefully also using a scatter-
- // gather list.
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
- if (rc) {
- rc = logging::GetLastSystemErrorCode();
- USB_PLOG(DEBUG) << "Failed to submit transfer";
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, ConvertTransferResult(rc), nullptr, 0));
- } else {
- SetUpTimeoutCallback(transfer.get(), timeout);
- transfers_.push_back(std::move(transfer));
- }
-}
-
-const UsbInterfaceDescriptor* UsbDeviceHandleUsbfs::FindInterfaceByEndpoint(
- uint8_t endpoint_address) {
- auto it = endpoints_.find(endpoint_address);
- if (it != endpoints_.end())
- return it->second.interface;
- return nullptr;
-}
-
-UsbDeviceHandleUsbfs::~UsbDeviceHandleUsbfs() {
- DCHECK(!device_) << "Handle must be closed before it is destroyed.";
-}
-
-void UsbDeviceHandleUsbfs::CloseBlocking() {
- fd_.reset(-1);
- delete helper_;
-}
-
-void UsbDeviceHandleUsbfs::SetConfigurationBlocking(
- int configuration_value,
- const ResultCallback& callback) {
- if (!fd_.is_valid()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- int rc = HANDLE_EINTR(
- ioctl(fd_.get(), USBDEVFS_SETCONFIGURATION, &configuration_value));
- if (rc)
- USB_PLOG(DEBUG) << "Failed to set configuration " << configuration_value;
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::SetConfigurationComplete,
- this, configuration_value, rc == 0, callback));
-}
-
-void UsbDeviceHandleUsbfs::SetConfigurationComplete(
- int configuration_value,
- bool success,
- const ResultCallback& callback) {
- if (success && device_) {
-#if !defined(OS_ANDROID)
- static_cast<UsbDeviceImpl*>(device_.get())
- ->ActiveConfigurationChanged(configuration_value);
-#endif
- // TODO(reillyg): If all interfaces are unclaimed before a new configuration
- // is set then this will do nothing. Investigate.
- RefreshEndpointInfo();
- }
- callback.Run(success);
-}
-
-void UsbDeviceHandleUsbfs::ReleaseInterfaceBlocking(
- int interface_number,
- const ResultCallback& callback) {
- if (!fd_.is_valid()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- int rc = HANDLE_EINTR(
- ioctl(fd_.get(), USBDEVFS_RELEASEINTERFACE, &interface_number));
- if (rc) {
- USB_PLOG(DEBUG) << "Failed to release interface " << interface_number;
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- } else {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&UsbDeviceHandleUsbfs::ReleaseInterfaceComplete,
- this, interface_number, callback));
- }
-}
-
-void UsbDeviceHandleUsbfs::ReleaseInterfaceComplete(
- int interface_number,
- const ResultCallback& callback) {
- auto it = interfaces_.find(interface_number);
- DCHECK(it != interfaces_.end());
- interfaces_.erase(it);
- RefreshEndpointInfo();
- callback.Run(true);
-}
-
-void UsbDeviceHandleUsbfs::SetInterfaceBlocking(
- int interface_number,
- int alternate_setting,
- const ResultCallback& callback) {
- if (!fd_.is_valid()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- usbdevfs_setinterface cmd = {0};
- cmd.interface = interface_number;
- cmd.altsetting = alternate_setting;
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SETINTERFACE, &cmd));
- if (rc) {
- USB_PLOG(DEBUG) << "Failed to set interface " << interface_number
- << " to alternate setting " << alternate_setting;
- }
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
-}
-
-void UsbDeviceHandleUsbfs::ResetDeviceBlocking(const ResultCallback& callback) {
- if (!fd_.is_valid()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- // TODO(reillyg): libusb releases interfaces before and then reclaims
- // interfaces after a reset. We should probably do this too or document that
- // callers have to call ClaimInterface as well.
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_RESET, nullptr));
- if (rc)
- USB_PLOG(DEBUG) << "Failed to reset the device";
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
-}
-
-void UsbDeviceHandleUsbfs::ClearHaltBlocking(uint8_t endpoint_address,
- const ResultCallback& callback) {
- if (!fd_.is_valid()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
- return;
- }
-
- int tmp_endpoint = endpoint_address;
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_CLEAR_HALT, &tmp_endpoint));
- if (rc) {
- USB_PLOG(DEBUG) << "Failed to clear the stall condition on endpoint "
- << static_cast<int>(endpoint_address);
- }
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, rc == 0));
-}
-
-void UsbDeviceHandleUsbfs::IsochronousTransferInternal(
- uint8_t endpoint_address,
- scoped_refptr<net::IOBuffer> buffer,
- size_t total_length,
- const std::vector<uint32_t>& packet_lengths,
- unsigned int timeout,
- const IsochronousTransferCallback& callback) {
- if (!device_) {
- ReportIsochronousError(packet_lengths, callback, USB_TRANSFER_DISCONNECT);
- return;
- }
-
- auto it = endpoints_.find(endpoint_address);
- if (it == endpoints_.end()) {
- USB_LOG(USER) << "Endpoint address " << static_cast<int>(endpoint_address)
- << " is not part of a claimed interface.";
- ReportIsochronousError(packet_lengths, callback, USB_TRANSFER_ERROR);
- return;
- }
-
- scoped_ptr<Transfer> transfer(new (packet_lengths.size())
- Transfer(buffer, callback));
- transfer->urb.type = USBDEVFS_URB_TYPE_ISO;
- transfer->urb.endpoint = endpoint_address;
- transfer->urb.buffer_length = total_length;
-
- for (size_t i = 0; i < packet_lengths.size(); ++i)
- transfer->urb.iso_frame_desc[i].length = packet_lengths[i];
-
- // USBDEVFS_SUBMITURB appears to be non-blocking as completion is reported
- // by USBDEVFS_REAPURBNDELAY. This code assumes a recent kernel that can
- // accept arbitrarily large transfer requests, hopefully also using a scatter-
- // gather list.
- int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SUBMITURB, &transfer->urb));
- if (rc) {
- rc = logging::GetLastSystemErrorCode();
- USB_PLOG(DEBUG) << "Failed to submit transfer";
- ReportIsochronousError(packet_lengths, callback, ConvertTransferResult(rc));
- } else {
- SetUpTimeoutCallback(transfer.get(), timeout);
- transfers_.push_back(std::move(transfer));
- }
-}
-
-void UsbDeviceHandleUsbfs::ReapedUrbs(const std::vector<usbdevfs_urb*>& urbs) {
- for (const auto& urb : urbs) {
- Transfer* this_transfer = static_cast<Transfer*>(urb->usercontext);
- DCHECK_EQ(urb, &this_transfer->urb);
- auto it = std::find_if(
- transfers_.begin(), transfers_.end(),
- [this_transfer](const scoped_ptr<Transfer>& transfer) -> bool {
- return transfer.get() == this_transfer;
- });
- DCHECK(it != transfers_.end());
- scoped_ptr<Transfer> transfer = std::move(*it);
- transfers_.erase(it);
- TransferComplete(std::move(transfer));
- }
-}
-
-void UsbDeviceHandleUsbfs::TransferComplete(scoped_ptr<Transfer> transfer) {
- if (transfer->timed_out)
- return;
-
- // The transfer will soon be freed. Cancel the timeout callback so that the
- // raw pointer it holds to |transfer| is not used.
- transfer->timeout_closure.Cancel();
-
- if (transfer->urb.type == USBDEVFS_URB_TYPE_ISO) {
- std::vector<IsochronousPacket> packets(transfer->urb.number_of_packets);
- for (size_t i = 0; i < packets.size(); ++i) {
- packets[i].length = transfer->urb.iso_frame_desc[i].length;
- packets[i].transferred_length =
- transfer->urb.iso_frame_desc[i].actual_length;
- packets[i].status = ConvertTransferResult(
- transfer->urb.status == 0 ? transfer->urb.iso_frame_desc[i].status
- : transfer->urb.status);
- }
-
- transfer->isoc_callback.Run(transfer->buffer, packets);
- } else {
- if (transfer->urb.status == 0 &&
- transfer->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
- // Copy the result of the control transfer back into the original buffer.
- memcpy(transfer->buffer->data(),
- transfer->control_transfer_buffer->data() + 8,
- transfer->urb.actual_length);
- }
-
- transfer->callback.Run(ConvertTransferResult(-transfer->urb.status),
- transfer->buffer, transfer->urb.actual_length);
- }
-}
-
-void UsbDeviceHandleUsbfs::RefreshEndpointInfo() {
- endpoints_.clear();
-
- const UsbConfigDescriptor* config = device_->GetActiveConfiguration();
- if (!config)
- return;
-
- for (const auto& entry : interfaces_) {
- auto interface_it = std::find_if(
- config->interfaces.begin(), config->interfaces.end(),
- [entry](const UsbInterfaceDescriptor& interface) {
- uint8_t interface_number = entry.first;
- uint8_t alternate_setting = entry.second.alternate_setting;
- return interface.interface_number == interface_number &&
- interface.alternate_setting == alternate_setting;
- });
- DCHECK(interface_it != config->interfaces.end());
-
- for (const auto& endpoint : interface_it->endpoints) {
- EndpointInfo& info = endpoints_[endpoint.address];
- info.type = endpoint.transfer_type;
- info.interface = &*interface_it;
- }
- }
-}
-
-void UsbDeviceHandleUsbfs::ReportIsochronousError(
- const std::vector<uint32_t>& packet_lengths,
- const UsbDeviceHandle::IsochronousTransferCallback& callback,
- UsbTransferStatus status) {
- std::vector<UsbDeviceHandle::IsochronousPacket> packets(
- packet_lengths.size());
- for (size_t i = 0; i < packet_lengths.size(); ++i) {
- packets[i].length = packet_lengths[i];
- packets[i].transferred_length = 0;
- packets[i].status = status;
- }
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr, packets));
-}
-
-void UsbDeviceHandleUsbfs::SetUpTimeoutCallback(Transfer* transfer,
- unsigned int timeout) {
- if (timeout > 0) {
- transfer->timeout_closure.Reset(
- base::Bind(&UsbDeviceHandleUsbfs::TransferTimedOut, transfer));
- task_runner_->PostDelayedTask(FROM_HERE,
- transfer->timeout_closure.callback(),
- base::TimeDelta::FromMilliseconds(timeout));
- }
-}
-
-// static
-void UsbDeviceHandleUsbfs::TransferTimedOut(Transfer* transfer) {
- // |transfer| must stay in |transfers_| as it is still being processed by the
- // kernel and will be reaped later. Just tell the caller that the timeout
- // elapsed.
- transfer->timed_out = true;
- if (transfer->urb.type == USBDEVFS_URB_TYPE_ISO) {
- std::vector<IsochronousPacket> packets(transfer->urb.number_of_packets);
- for (size_t i = 0; i < packets.size(); ++i) {
- packets[i].length = transfer->urb.iso_frame_desc[i].length;
- packets[i].transferred_length = 0;
- packets[i].status = USB_TRANSFER_TIMEOUT;
- }
- transfer->isoc_callback.Run(transfer->buffer, packets);
- } else {
- transfer->callback.Run(USB_TRANSFER_TIMEOUT, transfer->buffer, 0);
- }
-}
-
-} // namespace device
« 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