summaryrefslogtreecommitdiff
path: root/chromium/services/device/usb/usb_device_handle_win.h
blob: 0f86ebccd36d8fd7ff27483bc1b1916598c0655f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// 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 <list>
#include <map>
#include <memory>
#include <vector>

#include "base/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"

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> 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,
      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_