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

Side by Side Diff: device/hid/hid_service_win.cc

Issue 936603003: Enumerate HID devices asynchronously on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use "OnFileThread" suffix. Created 5 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/hid/hid_service_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/hid/hid_service_win.h" 5 #include "device/hid/hid_service_win.h"
6 6
7 #define INITGUID 7 #define INITGUID
8 8
9 #include <dbt.h> 9 #include <dbt.h>
10 #include <setupapi.h> 10 #include <setupapi.h>
(...skipping 10 matching lines...) Expand all
21 #include "device/hid/hid_connection_win.h" 21 #include "device/hid/hid_connection_win.h"
22 #include "device/hid/hid_device_info.h" 22 #include "device/hid/hid_device_info.h"
23 #include "net/base/io_buffer.h" 23 #include "net/base/io_buffer.h"
24 24
25 // Setup API is required to enumerate HID devices. 25 // Setup API is required to enumerate HID devices.
26 #pragma comment(lib, "setupapi.lib") 26 #pragma comment(lib, "setupapi.lib")
27 #pragma comment(lib, "hid.lib") 27 #pragma comment(lib, "hid.lib")
28 28
29 namespace device { 29 namespace device {
30 30
31 HidServiceWin::HidServiceWin() : device_observer_(this) { 31 namespace {
32
33 void Noop() {
34 // This function does nothing.
35 }
36 }
37
38 HidServiceWin::HidServiceWin(
39 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
40 : device_observer_(this),
41 file_task_runner_(file_task_runner),
42 weak_factory_(this) {
32 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 43 task_runner_ = base::ThreadTaskRunnerHandle::Get();
33 DCHECK(task_runner_.get()); 44 DCHECK(task_runner_.get());
34 DeviceMonitorWin* device_monitor = 45 DeviceMonitorWin* device_monitor =
35 DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_HID); 46 DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_HID);
36 if (device_monitor) { 47 if (device_monitor) {
37 device_observer_.Add(device_monitor); 48 device_observer_.Add(device_monitor);
38 } 49 }
39 DoInitialEnumeration(); 50 file_task_runner_->PostTask(
51 FROM_HERE, base::Bind(&HidServiceWin::EnumerateOnFileThread,
52 weak_factory_.GetWeakPtr(), task_runner_));
40 } 53 }
41 54
42 void HidServiceWin::Connect(const HidDeviceId& device_id, 55 void HidServiceWin::Connect(const HidDeviceId& device_id,
43 const ConnectCallback& callback) { 56 const ConnectCallback& callback) {
44 DCHECK(thread_checker_.CalledOnValidThread()); 57 DCHECK(thread_checker_.CalledOnValidThread());
45 const auto& map_entry = devices().find(device_id); 58 const auto& map_entry = devices().find(device_id);
46 if (map_entry == devices().end()) { 59 if (map_entry == devices().end()) {
47 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); 60 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
48 return; 61 return;
49 } 62 }
50 scoped_refptr<HidDeviceInfo> device_info = map_entry->second; 63 scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
51 64
52 base::win::ScopedHandle file(OpenDevice(device_info->device_id())); 65 base::win::ScopedHandle file(OpenDevice(device_info->device_id()));
53 if (!file.IsValid()) { 66 if (!file.IsValid()) {
54 PLOG(ERROR) << "Failed to open device"; 67 PLOG(ERROR) << "Failed to open device";
55 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); 68 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
56 return; 69 return;
57 } 70 }
58 71
59 task_runner_->PostTask( 72 task_runner_->PostTask(
60 FROM_HERE, 73 FROM_HERE,
61 base::Bind(callback, new HidConnectionWin(device_info, file.Pass()))); 74 base::Bind(callback, new HidConnectionWin(device_info, file.Pass())));
62 } 75 }
63 76
64 HidServiceWin::~HidServiceWin() { 77 HidServiceWin::~HidServiceWin() {
65 } 78 }
66 79
67 void HidServiceWin::DoInitialEnumeration() { 80 // static
81 void HidServiceWin::EnumerateOnFileThread(
82 base::WeakPtr<HidServiceWin> service,
83 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
68 HDEVINFO device_info_set = 84 HDEVINFO device_info_set =
69 SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, 85 SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL,
70 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 86 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
71 87
72 if (device_info_set != INVALID_HANDLE_VALUE) { 88 if (device_info_set != INVALID_HANDLE_VALUE) {
73 SP_DEVICE_INTERFACE_DATA device_interface_data; 89 SP_DEVICE_INTERFACE_DATA device_interface_data;
74 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 90 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
75 91
76 for (int device_index = 0; 92 for (int device_index = 0;
77 SetupDiEnumDeviceInterfaces(device_info_set, 93 SetupDiEnumDeviceInterfaces(device_info_set,
(...skipping 18 matching lines...) Expand all
96 BOOL res = SetupDiGetDeviceInterfaceDetail( 112 BOOL res = SetupDiGetDeviceInterfaceDetail(
97 device_info_set, &device_interface_data, 113 device_info_set, &device_interface_data,
98 device_interface_detail_data.get(), required_size, NULL, NULL); 114 device_interface_detail_data.get(), required_size, NULL, NULL);
99 if (!res) { 115 if (!res) {
100 continue; 116 continue;
101 } 117 }
102 118
103 std::string device_path( 119 std::string device_path(
104 base::SysWideToUTF8(device_interface_detail_data->DevicePath)); 120 base::SysWideToUTF8(device_interface_detail_data->DevicePath));
105 DCHECK(base::IsStringASCII(device_path)); 121 DCHECK(base::IsStringASCII(device_path));
106 OnDeviceAdded(base::StringToLowerASCII(device_path)); 122 AddDeviceOnFileThread(service, task_runner,
123 base::StringToLowerASCII(device_path));
107 } 124 }
108 } 125 }
109 126
110 FirstEnumerationComplete(); 127 task_runner->PostTask(
128 FROM_HERE, base::Bind(&HidServiceWin::FirstEnumerationComplete, service));
111 } 129 }
112 130
113 // static 131 // static
114 void HidServiceWin::CollectInfoFromButtonCaps( 132 void HidServiceWin::CollectInfoFromButtonCaps(
115 PHIDP_PREPARSED_DATA preparsed_data, 133 PHIDP_PREPARSED_DATA preparsed_data,
116 HIDP_REPORT_TYPE report_type, 134 HIDP_REPORT_TYPE report_type,
117 USHORT button_caps_length, 135 USHORT button_caps_length,
118 HidCollectionInfo* collection_info) { 136 HidCollectionInfo* collection_info) {
119 if (button_caps_length > 0) { 137 if (button_caps_length > 0) {
120 scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps( 138 scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
(...skipping 27 matching lines...) Expand all
148 for (size_t i = 0; i < value_caps_length; i++) { 166 for (size_t i = 0; i < value_caps_length; i++) {
149 int report_id = value_caps[i].ReportID; 167 int report_id = value_caps[i].ReportID;
150 if (report_id != 0) { 168 if (report_id != 0) {
151 collection_info->report_ids.insert(report_id); 169 collection_info->report_ids.insert(report_id);
152 } 170 }
153 } 171 }
154 } 172 }
155 } 173 }
156 } 174 }
157 175
158 void HidServiceWin::OnDeviceAdded(const std::string& device_path) { 176 // static
177 void HidServiceWin::AddDeviceOnFileThread(
178 base::WeakPtr<HidServiceWin> service,
179 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
180 const std::string& device_path) {
159 base::win::ScopedHandle device_handle(OpenDevice(device_path)); 181 base::win::ScopedHandle device_handle(OpenDevice(device_path));
160 if (!device_handle.IsValid()) { 182 if (!device_handle.IsValid()) {
161 return; 183 return;
162 } 184 }
163 185
164 HIDD_ATTRIBUTES attrib = {0}; 186 HIDD_ATTRIBUTES attrib = {0};
165 attrib.Size = sizeof(HIDD_ATTRIBUTES); 187 attrib.Size = sizeof(HIDD_ATTRIBUTES);
166 if (!HidD_GetAttributes(device_handle.Get(), &attrib)) { 188 if (!HidD_GetAttributes(device_handle.Get(), &attrib)) {
167 VLOG(1) << "Failed to get device attributes."; 189 VLOG(1) << "Failed to get device attributes.";
168 return; 190 return;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 &collection_info); 235 &collection_info);
214 CollectInfoFromValueCaps(preparsed_data, HidP_Input, 236 CollectInfoFromValueCaps(preparsed_data, HidP_Input,
215 capabilities.NumberInputValueCaps, &collection_info); 237 capabilities.NumberInputValueCaps, &collection_info);
216 CollectInfoFromValueCaps(preparsed_data, HidP_Output, 238 CollectInfoFromValueCaps(preparsed_data, HidP_Output,
217 capabilities.NumberOutputValueCaps, 239 capabilities.NumberOutputValueCaps,
218 &collection_info); 240 &collection_info);
219 CollectInfoFromValueCaps(preparsed_data, HidP_Feature, 241 CollectInfoFromValueCaps(preparsed_data, HidP_Feature,
220 capabilities.NumberFeatureValueCaps, 242 capabilities.NumberFeatureValueCaps,
221 &collection_info); 243 &collection_info);
222 244
245 // 1023 characters plus NULL terminator is more than enough for a USB string
246 // descriptor which is limited to 126 characters.
247 wchar_t buffer[1024];
248 std::string product_name;
249 if (HidD_GetProductString(device_handle.Get(), &buffer[0], sizeof(buffer))) {
250 // NULL termination guaranteed by the API.
251 product_name = base::SysWideToUTF8(buffer);
252 }
253 std::string serial_number;
254 if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0],
255 sizeof(buffer))) {
256 // NULL termination guaranteed by the API.
257 serial_number = base::SysWideToUTF8(buffer);
258 }
259
223 // This populates the HidDeviceInfo instance without a raw report descriptor. 260 // This populates the HidDeviceInfo instance without a raw report descriptor.
224 // The descriptor is unavailable on Windows because HID devices are exposed to 261 // The descriptor is unavailable on Windows because HID devices are exposed to
225 // user-space as individual top-level collections. 262 // user-space as individual top-level collections.
226 scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo( 263 scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo(
227 device_path, attrib.VendorID, attrib.ProductID, 264 device_path, attrib.VendorID, attrib.ProductID, product_name,
228 "", // TODO(reillyg): Get product name from Windows. 265 serial_number,
229 "", // TODO(reillyg): Get serial number from Windows.
230 kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335 266 kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335
231 collection_info, max_input_report_size, max_output_report_size, 267 collection_info, max_input_report_size, max_output_report_size,
232 max_feature_report_size)); 268 max_feature_report_size));
233 269
234 HidD_FreePreparsedData(preparsed_data); 270 HidD_FreePreparsedData(preparsed_data);
235 AddDevice(device_info); 271 task_runner->PostTask(
272 FROM_HERE, base::Bind(&HidServiceWin::AddDevice, service, device_info));
273 }
274
275 void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
276 file_task_runner_->PostTask(
277 FROM_HERE,
278 base::Bind(&HidServiceWin::AddDeviceOnFileThread,
279 weak_factory_.GetWeakPtr(), task_runner_, device_path));
236 } 280 }
237 281
238 void HidServiceWin::OnDeviceRemoved(const std::string& device_path) { 282 void HidServiceWin::OnDeviceRemoved(const std::string& device_path) {
239 RemoveDevice(device_path); 283 // Execute a no-op closure on the file task runner to synchronize with any
284 // devices that are still being enumerated.
285 file_task_runner_->PostTaskAndReply(
286 FROM_HERE, base::Bind(&Noop),
287 base::Bind(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
288 device_path));
240 } 289 }
241 290
291 // static
242 base::win::ScopedHandle HidServiceWin::OpenDevice( 292 base::win::ScopedHandle HidServiceWin::OpenDevice(
243 const std::string& device_path) { 293 const std::string& device_path) {
244 base::win::ScopedHandle file( 294 base::win::ScopedHandle file(
245 CreateFileA(device_path.c_str(), GENERIC_WRITE | GENERIC_READ, 295 CreateFileA(device_path.c_str(), GENERIC_WRITE | GENERIC_READ,
246 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 296 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
247 FILE_FLAG_OVERLAPPED, NULL)); 297 FILE_FLAG_OVERLAPPED, NULL));
248 if (!file.IsValid() && 298 if (!file.IsValid() &&
249 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) { 299 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
250 file.Set(CreateFileA(device_path.c_str(), GENERIC_READ, FILE_SHARE_READ, 300 file.Set(CreateFileA(device_path.c_str(), GENERIC_READ, FILE_SHARE_READ,
251 NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)); 301 NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL));
252 } 302 }
253 return file.Pass(); 303 return file.Pass();
254 } 304 }
255 305
256 } // namespace device 306 } // namespace device
OLDNEW
« no previous file with comments | « device/hid/hid_service_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698