OLD | NEW |
---|---|
(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 | |
OLD | NEW |