blob: a07bc7b13b1c91fad76d05ef14a331a409b10767 [file] [log] [blame]
// 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.
#ifndef SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_
#define SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_
#include <map>
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/win/scoped_handle.h"
#include "services/device/usb/scoped_winusb_handle.h"
#include "services/device/usb/usb_device_handle.h"
namespace base {
class RefCountedBytes;
class SequencedTaskRunner;
} // namespace base
namespace device {
class UsbDeviceWin;
// UsbDeviceHandle class provides basic I/O related functionalities.
class UsbDeviceHandleWin : public UsbDeviceHandle {
public:
scoped_refptr<UsbDevice> GetDevice() const override;
void Close() override;
void SetConfiguration(int configuration_value,
ResultCallback callback) override;
void ClaimInterface(int interface_number, ResultCallback callback) override;
void ReleaseInterface(int interface_number, ResultCallback callback) override;
void SetInterfaceAlternateSetting(int interface_number,
int alternate_setting,
ResultCallback callback) override;
void ResetDevice(ResultCallback callback) override;
void ClearHalt(mojom::UsbTransferDirection direction,
uint8_t endpoint_number,
ResultCallback callback) override;
void ControlTransfer(mojom::UsbTransferDirection direction,
mojom::UsbControlTransferType request_type,
mojom::UsbControlTransferRecipient recipient,
uint8_t request,
uint16_t value,
uint16_t index,
scoped_refptr<base::RefCountedBytes> buffer,
unsigned int timeout,
TransferCallback callback) override;
void IsochronousTransferIn(uint8_t endpoint,
const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
IsochronousTransferCallback callback) override;
void IsochronousTransferOut(uint8_t endpoint,
scoped_refptr<base::RefCountedBytes> buffer,
const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
IsochronousTransferCallback callback) override;
void GenericTransfer(mojom::UsbTransferDirection direction,
uint8_t endpoint_number,
scoped_refptr<base::RefCountedBytes> buffer,
unsigned int timeout,
TransferCallback callback) override;
const mojom::UsbInterfaceInfo* FindInterfaceByEndpoint(
uint8_t endpoint_address) override;
protected:
friend class UsbDeviceWin;
// Constructor used to build a connection to the device.
UsbDeviceHandleWin(scoped_refptr<UsbDeviceWin> device);
// Constructor used to build a connection to the device's parent hub.
UsbDeviceHandleWin(scoped_refptr<UsbDeviceWin> device,
base::win::ScopedHandle handle);
~UsbDeviceHandleWin() override;
void UpdateFunction(int interface_number,
const std::wstring& function_driver,
const std::wstring& function_path);
private:
struct Interface;
class Request;
using OpenInterfaceCallback = base::OnceCallback<void(Interface*)>;
struct Interface {
Interface();
~Interface();
const mojom::UsbInterfaceInfo* info;
// In a composite device each function has its own driver and path to open.
std::wstring function_driver;
std::wstring function_path;
base::win::ScopedHandle function_handle;
ScopedWinUsbHandle handle;
bool claimed = false;
// The currently selected alternative interface setting. This is assumed to
// be the first alternate when the device is opened.
uint8_t alternate_setting = 0;
// The count of outstanding requests, including associated interfaces
// claimed which require keeping the handles owned by this object open.
int reference_count = 0;
// Closures to execute when |function_path| has been populated.
std::vector<OpenInterfaceCallback> ready_callbacks;
DISALLOW_COPY_AND_ASSIGN(Interface);
};
struct Endpoint {
const mojom::UsbInterfaceInfo* interface;
mojom::UsbTransferType type;
};
void OpenInterfaceHandle(Interface* interface,
OpenInterfaceCallback callback);
// Interfaces on a USB device are organized into "functions". When making a
// request to a device the first interface of each function is the one that
// has a valid |function_handle|. This function finds the correct interface
// for making requests to the provided interface based on the device's driver
// configuration.
Interface* GetFirstInterfaceForFunction(Interface* interface);
void OnFunctionAvailable(OpenInterfaceCallback callback,
Interface* interface);
void OnFirstInterfaceOpened(int interface_number,
OpenInterfaceCallback callback,
Interface* first_interface);
void OnInterfaceClaimed(ResultCallback callback, Interface* interface);
void OnSetAlternateInterfaceSetting(int interface_number,
int alternate_setting,
ResultCallback callback,
bool result);
void RegisterEndpoints(const mojom::UsbInterfaceInfo* interface,
const mojom::UsbAlternateInterfaceInfo& alternate);
void UnregisterEndpoints(const mojom::UsbAlternateInterfaceInfo& alternate);
void OnClearHalt(int interface_number, ResultCallback callback, bool result);
void OpenInterfaceForControlTransfer(
mojom::UsbControlTransferRecipient recipient,
uint16_t index,
OpenInterfaceCallback callback);
void OnFunctionAvailableForEp0(OpenInterfaceCallback callback,
Interface* interface);
void OnInterfaceOpenedForControlTransfer(
mojom::UsbTransferDirection direction,
mojom::UsbControlTransferType request_type,
mojom::UsbControlTransferRecipient recipient,
uint8_t request,
uint16_t value,
uint16_t index,
scoped_refptr<base::RefCountedBytes> buffer,
unsigned int timeout,
TransferCallback callback,
Interface* interface);
Request* MakeRequest(Interface* interface);
std::unique_ptr<Request> UnlinkRequest(Request* request);
void GotNodeConnectionInformation(TransferCallback callback,
void* node_connection_info,
scoped_refptr<base::RefCountedBytes> buffer,
Request* request_ptr,
DWORD win32_result,
size_t bytes_transferred);
void GotDescriptorFromNodeConnection(
TransferCallback callback,
scoped_refptr<base::RefCountedBytes> request_buffer,
scoped_refptr<base::RefCountedBytes> original_buffer,
Request* request_ptr,
DWORD win32_result,
size_t bytes_transferred);
void TransferComplete(TransferCallback callback,
scoped_refptr<base::RefCountedBytes> buffer,
Request* request_ptr,
DWORD win32_result,
size_t bytes_transferred);
void ReportIsochronousError(const std::vector<uint32_t>& packet_lengths,
IsochronousTransferCallback callback,
mojom::UsbTransferStatus status);
bool AllFunctionsEnumerated() const;
void ReleaseInterfaceReference(Interface* interface);
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<UsbDeviceWin> device_;
// |hub_handle_| or all the handles for claimed interfaces in |interfaces_|
// must outlive their associated |requests_| because individual Request
// objects hold on to the raw handles for the purpose of calling
// GetOverlappedResult().
base::win::ScopedHandle hub_handle_;
std::map<uint8_t, Interface> interfaces_;
std::map<uint8_t, Endpoint> endpoints_;
std::map<Request*, std::unique_ptr<Request>> requests_;
// Control transfers which are waiting for a function handle to be ready.
std::vector<OpenInterfaceCallback> ep0_ready_callbacks_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
base::WeakPtrFactory<UsbDeviceHandleWin> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(UsbDeviceHandleWin);
};
} // namespace device
#endif // SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_