| // Copyright 2017 The Chromium Authors |
| // 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 <list> |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.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" |
| |
| struct _USB_NODE_CONNECTION_INFORMATION_EX; |
| |
| 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: |
| UsbDeviceHandleWin(const UsbDeviceHandleWin&) = delete; |
| UsbDeviceHandleWin& operator=(const UsbDeviceHandleWin&) = delete; |
| |
| 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. To avoid |
| // bugs in USB hub drivers a single global sequenced task runner is used for |
| // all calls to the driver. |
| UsbDeviceHandleWin( |
| scoped_refptr<UsbDeviceWin> device, |
| base::win::ScopedHandle handle, |
| scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); |
| |
| ~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 Interface&) = delete; |
| Interface& operator=(const Interface&) = delete; |
| |
| ~Interface(); |
| |
| // This may be nullptr in the rare case of a device which doesn't have any |
| // interfaces. In that case the Windows API still considers the device to |
| // have a single function which is represented here by initializing |
| // |interface_number| and |first_interface| to create a fake interface 0. |
| raw_ptr<const mojom::UsbInterfaceInfo> info = nullptr; |
| |
| // These fields are copied from |info| and initialized to 0 in case it is |
| // nullptr. |
| uint8_t interface_number = 0; |
| uint8_t first_interface = 0; |
| |
| // 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; |
| }; |
| |
| struct Endpoint { |
| raw_ptr<const mojom::UsbInterfaceInfo, DanglingUntriaged> 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, |
| std::unique_ptr<_USB_NODE_CONNECTION_INFORMATION_EX> node_connection_info, |
| scoped_refptr<base::RefCountedBytes> buffer, |
| std::pair<DWORD, DWORD> result_and_bytes_transferred); |
| void GotDescriptorFromNodeConnection( |
| TransferCallback callback, |
| scoped_refptr<base::RefCountedBytes> request_buffer, |
| scoped_refptr<base::RefCountedBytes> original_buffer, |
| std::pair<DWORD, DWORD> result_and_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::list<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}; |
| }; |
| |
| } // namespace device |
| |
| #endif // SERVICES_DEVICE_USB_USB_DEVICE_HANDLE_WIN_H_ |