| Index: device/usb/usb_device_handle_win.cc
|
| diff --git a/device/usb/usb_device_handle_win.cc b/device/usb/usb_device_handle_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..74a7de63bd7c1a8996d7bdf9319c42b1bdd19803
|
| --- /dev/null
|
| +++ b/device/usb/usb_device_handle_win.cc
|
| @@ -0,0 +1,349 @@
|
| +// Copyright 2017 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_win.h"
|
| +
|
| +#include <usbioctl.h>
|
| +#include <usbspec.h>
|
| +#include <winioctl.h>
|
| +#include <winusb.h>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/location.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/strings/string16.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "base/win/object_watcher.h"
|
| +#include "components/device_event_log/device_event_log.h"
|
| +#include "device/usb/usb_context.h"
|
| +#include "device/usb/usb_descriptors.h"
|
| +#include "device/usb/usb_device_win.h"
|
| +#include "device/usb/usb_service.h"
|
| +#include "net/base/io_buffer.h"
|
| +
|
| +namespace device {
|
| +
|
| +// Encapsulates waiting for the completion of an overlapped event.
|
| +class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
|
| + public:
|
| + explicit Request(HANDLE handle)
|
| + : handle_(handle), event_(CreateEvent(nullptr, false, false, nullptr)) {
|
| + memset(&overlapped_, 0, sizeof(overlapped_));
|
| + overlapped_.hEvent = event_.Get();
|
| + }
|
| +
|
| + ~Request() override {
|
| + if (callback_) {
|
| + SetLastError(ERROR_REQUEST_ABORTED);
|
| + std::move(callback_).Run(this, false, 0);
|
| + }
|
| + }
|
| +
|
| + // Starts watching for completion of the overlapped event.
|
| + void MaybeStartWatching(
|
| + BOOL success,
|
| + base::OnceCallback<void(Request*, DWORD, size_t)> callback) {
|
| + callback_ = std::move(callback);
|
| + if (success) {
|
| + OnObjectSignaled(event_.Get());
|
| + } else {
|
| + DWORD error = GetLastError();
|
| + if (error == ERROR_IO_PENDING) {
|
| + watcher_.StartWatchingOnce(event_.Get(), this);
|
| + } else {
|
| + std::move(callback_).Run(this, error, 0);
|
| + }
|
| + }
|
| + }
|
| +
|
| + OVERLAPPED* overlapped() { return &overlapped_; }
|
| +
|
| + // base::win::ObjectWatcher::Delegate
|
| + void OnObjectSignaled(HANDLE object) override {
|
| + DCHECK_EQ(object, event_.Get());
|
| + DWORD size;
|
| + if (GetOverlappedResult(handle_, &overlapped_, &size, true))
|
| + std::move(callback_).Run(this, ERROR_SUCCESS, size);
|
| + else
|
| + std::move(callback_).Run(this, GetLastError(), 0);
|
| + }
|
| +
|
| + private:
|
| + HANDLE handle_;
|
| + OVERLAPPED overlapped_;
|
| + base::win::ScopedHandle event_;
|
| + base::win::ObjectWatcher watcher_;
|
| + base::OnceCallback<void(Request*, DWORD, size_t)> callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Request);
|
| +};
|
| +
|
| +scoped_refptr<UsbDevice> UsbDeviceHandleWin::GetDevice() const {
|
| + return device_;
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::Close() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_)
|
| + return;
|
| +
|
| + device_->HandleClosed(this);
|
| + device_ = nullptr;
|
| +
|
| + if (hub_handle_.IsValid()) {
|
| + CancelIo(hub_handle_.Get());
|
| + hub_handle_.Close();
|
| + }
|
| +
|
| + requests_.clear();
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::SetConfiguration(int configuration_value,
|
| + const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + callback.Run(false);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::ClaimInterface(int interface_number,
|
| + const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + callback.Run(false);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::ReleaseInterface(int interface_number,
|
| + const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::SetInterfaceAlternateSetting(
|
| + int interface_number,
|
| + int alternate_setting,
|
| + const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + callback.Run(false);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::ResetDevice(const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + callback.Run(false);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::ClearHalt(uint8_t endpoint,
|
| + const ResultCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!device_) {
|
| + callback.Run(false);
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::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) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + if (!device_) {
|
| + task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
|
| + return;
|
| + }
|
| +
|
| + if (hub_handle_.IsValid()) {
|
| + if (direction == USB_DIRECTION_INBOUND &&
|
| + request_type == TransferRequestType::STANDARD &&
|
| + recipient == TransferRecipient::DEVICE &&
|
| + request == USB_REQUEST_GET_DESCRIPTOR) {
|
| + if ((value >> 8) == USB_DEVICE_DESCRIPTOR_TYPE) {
|
| + auto* node_connection_info = new USB_NODE_CONNECTION_INFORMATION_EX;
|
| + node_connection_info->ConnectionIndex = device_->port_number();
|
| +
|
| + Request* request = MakeRequest(hub_handle_.Get());
|
| + request->MaybeStartWatching(
|
| + DeviceIoControl(hub_handle_.Get(),
|
| + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
|
| + node_connection_info, sizeof(*node_connection_info),
|
| + node_connection_info, sizeof(*node_connection_info),
|
| + nullptr, request->overlapped()),
|
| + base::Bind(&UsbDeviceHandleWin::GotNodeConnectionInformation,
|
| + weak_factory_.GetWeakPtr(), callback,
|
| + base::Owned(node_connection_info), buffer, length));
|
| + return;
|
| + } else if (((value >> 8) == USB_CONFIGURATION_DESCRIPTOR_TYPE) ||
|
| + ((value >> 8) == USB_STRING_DESCRIPTOR_TYPE)) {
|
| + size_t size = sizeof(USB_DESCRIPTOR_REQUEST) + length;
|
| + scoped_refptr<net::IOBuffer> request_buffer(new net::IOBuffer(size));
|
| + USB_DESCRIPTOR_REQUEST* descriptor_request =
|
| + reinterpret_cast<USB_DESCRIPTOR_REQUEST*>(request_buffer->data());
|
| + descriptor_request->ConnectionIndex = device_->port_number();
|
| + descriptor_request->SetupPacket.bmRequest = BMREQUEST_DEVICE_TO_HOST;
|
| + descriptor_request->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
| + descriptor_request->SetupPacket.wValue = value;
|
| + descriptor_request->SetupPacket.wIndex = index;
|
| + descriptor_request->SetupPacket.wLength = length;
|
| +
|
| + Request* request = MakeRequest(hub_handle_.Get());
|
| + request->MaybeStartWatching(
|
| + DeviceIoControl(hub_handle_.Get(),
|
| + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
|
| + request_buffer->data(), size,
|
| + request_buffer->data(), size, nullptr,
|
| + request->overlapped()),
|
| + base::Bind(&UsbDeviceHandleWin::GotDescriptorFromNodeConnection,
|
| + weak_factory_.GetWeakPtr(), callback, request_buffer,
|
| + buffer, length));
|
| + return;
|
| + }
|
| + }
|
| +
|
| + // Unsupported transfer for hub.
|
| + task_runner_->PostTask(
|
| + FROM_HERE, base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
|
| + return;
|
| + }
|
| +
|
| + // Regular control transfers unimplemented.
|
| + task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::IsochronousTransferIn(
|
| + uint8_t endpoint_number,
|
| + const std::vector<uint32_t>& packet_lengths,
|
| + unsigned int timeout,
|
| + const IsochronousTransferCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::IsochronousTransferOut(
|
| + uint8_t endpoint_number,
|
| + scoped_refptr<net::IOBuffer> buffer,
|
| + const std::vector<uint32_t>& packet_lengths,
|
| + unsigned int timeout,
|
| + const IsochronousTransferCallback& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::GenericTransfer(UsbEndpointDirection direction,
|
| + uint8_t endpoint_number,
|
| + scoped_refptr<net::IOBuffer> buffer,
|
| + size_t length,
|
| + unsigned int timeout,
|
| + const TransferCallback& callback) {
|
| + // This one must be callable from any thread.
|
| +}
|
| +
|
| +const UsbInterfaceDescriptor* UsbDeviceHandleWin::FindInterfaceByEndpoint(
|
| + uint8_t endpoint_address) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return nullptr;
|
| +}
|
| +
|
| +UsbDeviceHandleWin::UsbDeviceHandleWin(
|
| + scoped_refptr<UsbDeviceWin> device,
|
| + base::win::ScopedHandle handle,
|
| + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
|
| + : device_(std::move(device)),
|
| + hub_handle_(std::move(handle)),
|
| + task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + blocking_task_runner_(std::move(blocking_task_runner)),
|
| + weak_factory_(this) {}
|
| +
|
| +UsbDeviceHandleWin::~UsbDeviceHandleWin() {}
|
| +
|
| +UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(HANDLE handle) {
|
| + auto request = base::MakeUnique<Request>(hub_handle_.Get());
|
| + Request* request_ptr = request.get();
|
| + requests_[request_ptr] = std::move(request);
|
| + return request_ptr;
|
| +}
|
| +
|
| +std::unique_ptr<UsbDeviceHandleWin::Request> UsbDeviceHandleWin::UnlinkRequest(
|
| + UsbDeviceHandleWin::Request* request_ptr) {
|
| + auto it = requests_.find(request_ptr);
|
| + DCHECK(it != requests_.end());
|
| + std::unique_ptr<Request> request = std::move(it->second);
|
| + requests_.erase(it);
|
| + return request;
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::GotNodeConnectionInformation(
|
| + const TransferCallback& callback,
|
| + void* node_connection_info_ptr,
|
| + scoped_refptr<net::IOBuffer> buffer,
|
| + size_t buffer_length,
|
| + Request* request_ptr,
|
| + DWORD win32_result,
|
| + size_t bytes_transferred) {
|
| + USB_NODE_CONNECTION_INFORMATION_EX* node_connection_info =
|
| + static_cast<USB_NODE_CONNECTION_INFORMATION_EX*>(
|
| + node_connection_info_ptr);
|
| + std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
|
| +
|
| + if (win32_result != ERROR_SUCCESS) {
|
| + SetLastError(win32_result);
|
| + USB_PLOG(ERROR) << "Failed to get node connection information";
|
| + callback.Run(USB_TRANSFER_ERROR, nullptr, 0);
|
| + return;
|
| + }
|
| +
|
| + DCHECK_EQ(bytes_transferred, sizeof(USB_NODE_CONNECTION_INFORMATION_EX));
|
| + bytes_transferred = std::min(sizeof(USB_DEVICE_DESCRIPTOR), buffer_length);
|
| + memcpy(buffer->data(), &node_connection_info->DeviceDescriptor,
|
| + bytes_transferred);
|
| + callback.Run(USB_TRANSFER_COMPLETED, buffer, bytes_transferred);
|
| +}
|
| +
|
| +void UsbDeviceHandleWin::GotDescriptorFromNodeConnection(
|
| + const TransferCallback& callback,
|
| + scoped_refptr<net::IOBuffer> request_buffer,
|
| + scoped_refptr<net::IOBuffer> original_buffer,
|
| + size_t original_buffer_length,
|
| + Request* request_ptr,
|
| + DWORD win32_result,
|
| + size_t bytes_transferred) {
|
| + std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
|
| +
|
| + if (win32_result != ERROR_SUCCESS) {
|
| + SetLastError(win32_result);
|
| + USB_PLOG(ERROR) << "Failed to read descriptor from node connection";
|
| + callback.Run(USB_TRANSFER_ERROR, nullptr, 0);
|
| + return;
|
| + }
|
| +
|
| + DCHECK_GE(bytes_transferred, sizeof(USB_DESCRIPTOR_REQUEST));
|
| + bytes_transferred -= sizeof(USB_DESCRIPTOR_REQUEST);
|
| + memcpy(original_buffer->data(),
|
| + request_buffer->data() + sizeof(USB_DESCRIPTOR_REQUEST),
|
| + bytes_transferred);
|
| + callback.Run(USB_TRANSFER_COMPLETED, original_buffer, bytes_transferred);
|
| +}
|
| +
|
| +} // namespace device
|
|
|