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

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

Powered by Google App Engine
This is Rietveld 408576698