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

Side by Side Diff: device/usb/usb_device_handle_win.cc

Issue 2702623002: Add support for reading USB descriptors to the new Windows backend. (Closed)
Patch Set: Addressed rockot@'s feedback and rebased. Created 3 years, 10 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 unified diff | Download patch
« no previous file with comments | « device/usb/usb_device_handle_win.h ('k') | device/usb/usb_device_win.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/usb/usb_device_handle_win.h"
6
7 #include <usbioctl.h>
8 #include <usbspec.h>
9 #include <winioctl.h>
10 #include <winusb.h>
11
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string16.h"
19 #include "base/synchronization/lock.h"
20 #include "base/threading/thread_task_runner_handle.h"
21 #include "base/win/object_watcher.h"
22 #include "components/device_event_log/device_event_log.h"
23 #include "device/usb/usb_context.h"
24 #include "device/usb/usb_descriptors.h"
25 #include "device/usb/usb_device_win.h"
26 #include "device/usb/usb_service.h"
27 #include "net/base/io_buffer.h"
28
29 namespace device {
30
31 // Encapsulates waiting for the completion of an overlapped event.
32 class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
33 public:
34 explicit Request(HANDLE handle)
35 : handle_(handle), event_(CreateEvent(nullptr, false, false, nullptr)) {
36 memset(&overlapped_, 0, sizeof(overlapped_));
37 overlapped_.hEvent = event_.Get();
38 }
39
40 ~Request() override {
41 if (callback_) {
42 SetLastError(ERROR_REQUEST_ABORTED);
43 std::move(callback_).Run(this, false, 0);
44 }
45 }
46
47 // Starts watching for completion of the overlapped event.
48 void MaybeStartWatching(
49 BOOL success,
50 base::OnceCallback<void(Request*, DWORD, size_t)> callback) {
51 callback_ = std::move(callback);
52 if (success) {
53 OnObjectSignaled(event_.Get());
54 } else {
55 DWORD error = GetLastError();
56 if (error == ERROR_IO_PENDING) {
57 watcher_.StartWatchingOnce(event_.Get(), this);
58 } else {
59 std::move(callback_).Run(this, error, 0);
60 }
61 }
62 }
63
64 OVERLAPPED* overlapped() { return &overlapped_; }
65
66 // base::win::ObjectWatcher::Delegate
67 void OnObjectSignaled(HANDLE object) override {
68 DCHECK_EQ(object, event_.Get());
69 DWORD size;
70 if (GetOverlappedResult(handle_, &overlapped_, &size, true))
71 std::move(callback_).Run(this, ERROR_SUCCESS, size);
72 else
73 std::move(callback_).Run(this, GetLastError(), 0);
74 }
75
76 private:
77 HANDLE handle_;
78 OVERLAPPED overlapped_;
79 base::win::ScopedHandle event_;
80 base::win::ObjectWatcher watcher_;
81 base::OnceCallback<void(Request*, DWORD, size_t)> callback_;
82
83 DISALLOW_COPY_AND_ASSIGN(Request);
84 };
85
86 scoped_refptr<UsbDevice> UsbDeviceHandleWin::GetDevice() const {
87 return device_;
88 }
89
90 void UsbDeviceHandleWin::Close() {
91 DCHECK(thread_checker_.CalledOnValidThread());
92 if (!device_)
93 return;
94
95 device_->HandleClosed(this);
96 device_ = nullptr;
97
98 if (hub_handle_.IsValid()) {
99 CancelIo(hub_handle_.Get());
100 hub_handle_.Close();
101 }
102
103 requests_.clear();
104 }
105
106 void UsbDeviceHandleWin::SetConfiguration(int configuration_value,
107 const ResultCallback& callback) {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 if (!device_) {
110 callback.Run(false);
111 return;
112 }
113 }
114
115 void UsbDeviceHandleWin::ClaimInterface(int interface_number,
116 const ResultCallback& callback) {
117 DCHECK(thread_checker_.CalledOnValidThread());
118 if (!device_) {
119 callback.Run(false);
120 return;
121 }
122 }
123
124 void UsbDeviceHandleWin::ReleaseInterface(int interface_number,
125 const ResultCallback& callback) {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 if (!device_) {
128 task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
129 return;
130 }
131 }
132
133 void UsbDeviceHandleWin::SetInterfaceAlternateSetting(
134 int interface_number,
135 int alternate_setting,
136 const ResultCallback& callback) {
137 DCHECK(thread_checker_.CalledOnValidThread());
138 if (!device_) {
139 callback.Run(false);
140 return;
141 }
142 }
143
144 void UsbDeviceHandleWin::ResetDevice(const ResultCallback& callback) {
145 DCHECK(thread_checker_.CalledOnValidThread());
146 if (!device_) {
147 callback.Run(false);
148 return;
149 }
150 }
151
152 void UsbDeviceHandleWin::ClearHalt(uint8_t endpoint,
153 const ResultCallback& callback) {
154 DCHECK(thread_checker_.CalledOnValidThread());
155 if (!device_) {
156 callback.Run(false);
157 return;
158 }
159 }
160
161 void UsbDeviceHandleWin::ControlTransfer(UsbEndpointDirection direction,
162 TransferRequestType request_type,
163 TransferRecipient recipient,
164 uint8_t request,
165 uint16_t value,
166 uint16_t index,
167 scoped_refptr<net::IOBuffer> buffer,
168 size_t length,
169 unsigned int timeout,
170 const TransferCallback& callback) {
171 DCHECK(thread_checker_.CalledOnValidThread());
172
173 if (!device_) {
174 task_runner_->PostTask(
175 FROM_HERE, base::Bind(callback, USB_TRANSFER_DISCONNECT, nullptr, 0));
176 return;
177 }
178
179 if (hub_handle_.IsValid()) {
180 if (direction == USB_DIRECTION_INBOUND &&
181 request_type == TransferRequestType::STANDARD &&
182 recipient == TransferRecipient::DEVICE &&
183 request == USB_REQUEST_GET_DESCRIPTOR) {
184 if ((value >> 8) == USB_DEVICE_DESCRIPTOR_TYPE) {
185 auto* node_connection_info = new USB_NODE_CONNECTION_INFORMATION_EX;
186 node_connection_info->ConnectionIndex = device_->port_number();
187
188 Request* request = MakeRequest(hub_handle_.Get());
189 request->MaybeStartWatching(
190 DeviceIoControl(hub_handle_.Get(),
191 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
192 node_connection_info, sizeof(*node_connection_info),
193 node_connection_info, sizeof(*node_connection_info),
194 nullptr, request->overlapped()),
195 base::Bind(&UsbDeviceHandleWin::GotNodeConnectionInformation,
196 weak_factory_.GetWeakPtr(), callback,
197 base::Owned(node_connection_info), buffer, length));
198 return;
199 } else if (((value >> 8) == USB_CONFIGURATION_DESCRIPTOR_TYPE) ||
200 ((value >> 8) == USB_STRING_DESCRIPTOR_TYPE)) {
201 size_t size = sizeof(USB_DESCRIPTOR_REQUEST) + length;
202 scoped_refptr<net::IOBuffer> request_buffer(new net::IOBuffer(size));
203 USB_DESCRIPTOR_REQUEST* descriptor_request =
204 reinterpret_cast<USB_DESCRIPTOR_REQUEST*>(request_buffer->data());
205 descriptor_request->ConnectionIndex = device_->port_number();
206 descriptor_request->SetupPacket.bmRequest = BMREQUEST_DEVICE_TO_HOST;
207 descriptor_request->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
208 descriptor_request->SetupPacket.wValue = value;
209 descriptor_request->SetupPacket.wIndex = index;
210 descriptor_request->SetupPacket.wLength = length;
211
212 Request* request = MakeRequest(hub_handle_.Get());
213 request->MaybeStartWatching(
214 DeviceIoControl(hub_handle_.Get(),
215 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
216 request_buffer->data(), size,
217 request_buffer->data(), size, nullptr,
218 request->overlapped()),
219 base::Bind(&UsbDeviceHandleWin::GotDescriptorFromNodeConnection,
220 weak_factory_.GetWeakPtr(), callback, request_buffer,
221 buffer, length));
222 return;
223 }
224 }
225
226 // Unsupported transfer for hub.
227 task_runner_->PostTask(
228 FROM_HERE, base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
229 return;
230 }
231
232 // Regular control transfers unimplemented.
233 task_runner_->PostTask(FROM_HERE,
234 base::Bind(callback, USB_TRANSFER_ERROR, nullptr, 0));
235 }
236
237 void UsbDeviceHandleWin::IsochronousTransferIn(
238 uint8_t endpoint_number,
239 const std::vector<uint32_t>& packet_lengths,
240 unsigned int timeout,
241 const IsochronousTransferCallback& callback) {
242 DCHECK(thread_checker_.CalledOnValidThread());
243 }
244
245 void UsbDeviceHandleWin::IsochronousTransferOut(
246 uint8_t endpoint_number,
247 scoped_refptr<net::IOBuffer> buffer,
248 const std::vector<uint32_t>& packet_lengths,
249 unsigned int timeout,
250 const IsochronousTransferCallback& callback) {
251 DCHECK(thread_checker_.CalledOnValidThread());
252 }
253
254 void UsbDeviceHandleWin::GenericTransfer(UsbEndpointDirection direction,
255 uint8_t endpoint_number,
256 scoped_refptr<net::IOBuffer> buffer,
257 size_t length,
258 unsigned int timeout,
259 const TransferCallback& callback) {
260 // This one must be callable from any thread.
261 }
262
263 const UsbInterfaceDescriptor* UsbDeviceHandleWin::FindInterfaceByEndpoint(
264 uint8_t endpoint_address) {
265 DCHECK(thread_checker_.CalledOnValidThread());
266 return nullptr;
267 }
268
269 UsbDeviceHandleWin::UsbDeviceHandleWin(
270 scoped_refptr<UsbDeviceWin> device,
271 base::win::ScopedHandle handle,
272 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
273 : device_(std::move(device)),
274 hub_handle_(std::move(handle)),
275 task_runner_(base::ThreadTaskRunnerHandle::Get()),
276 blocking_task_runner_(std::move(blocking_task_runner)),
277 weak_factory_(this) {}
278
279 UsbDeviceHandleWin::~UsbDeviceHandleWin() {}
280
281 UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(HANDLE handle) {
282 auto request = base::MakeUnique<Request>(hub_handle_.Get());
283 Request* request_ptr = request.get();
284 requests_[request_ptr] = std::move(request);
285 return request_ptr;
286 }
287
288 std::unique_ptr<UsbDeviceHandleWin::Request> UsbDeviceHandleWin::UnlinkRequest(
289 UsbDeviceHandleWin::Request* request_ptr) {
290 auto it = requests_.find(request_ptr);
291 DCHECK(it != requests_.end());
292 std::unique_ptr<Request> request = std::move(it->second);
293 requests_.erase(it);
294 return request;
295 }
296
297 void UsbDeviceHandleWin::GotNodeConnectionInformation(
298 const TransferCallback& callback,
299 void* node_connection_info_ptr,
300 scoped_refptr<net::IOBuffer> buffer,
301 size_t buffer_length,
302 Request* request_ptr,
303 DWORD win32_result,
304 size_t bytes_transferred) {
305 USB_NODE_CONNECTION_INFORMATION_EX* node_connection_info =
306 static_cast<USB_NODE_CONNECTION_INFORMATION_EX*>(
307 node_connection_info_ptr);
308 std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
309
310 if (win32_result != ERROR_SUCCESS) {
311 SetLastError(win32_result);
312 USB_PLOG(ERROR) << "Failed to get node connection information";
313 callback.Run(USB_TRANSFER_ERROR, nullptr, 0);
314 return;
315 }
316
317 DCHECK_EQ(bytes_transferred, sizeof(USB_NODE_CONNECTION_INFORMATION_EX));
318 bytes_transferred = std::min(sizeof(USB_DEVICE_DESCRIPTOR), buffer_length);
319 memcpy(buffer->data(), &node_connection_info->DeviceDescriptor,
320 bytes_transferred);
321 callback.Run(USB_TRANSFER_COMPLETED, buffer, bytes_transferred);
322 }
323
324 void UsbDeviceHandleWin::GotDescriptorFromNodeConnection(
325 const TransferCallback& callback,
326 scoped_refptr<net::IOBuffer> request_buffer,
327 scoped_refptr<net::IOBuffer> original_buffer,
328 size_t original_buffer_length,
329 Request* request_ptr,
330 DWORD win32_result,
331 size_t bytes_transferred) {
332 std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
333
334 if (win32_result != ERROR_SUCCESS) {
335 SetLastError(win32_result);
336 USB_PLOG(ERROR) << "Failed to read descriptor from node connection";
337 callback.Run(USB_TRANSFER_ERROR, nullptr, 0);
338 return;
339 }
340
341 DCHECK_GE(bytes_transferred, sizeof(USB_DESCRIPTOR_REQUEST));
342 bytes_transferred -= sizeof(USB_DESCRIPTOR_REQUEST);
343 memcpy(original_buffer->data(),
344 request_buffer->data() + sizeof(USB_DESCRIPTOR_REQUEST),
345 bytes_transferred);
346 callback.Run(USB_TRANSFER_COMPLETED, original_buffer, bytes_transferred);
347 }
348
349 } // namespace device
OLDNEW
« no previous file with comments | « device/usb/usb_device_handle_win.h ('k') | device/usb/usb_device_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698