Update Smart lock strings in chrome://settings.
[chromium-blink-merge.git] / device / hid / hid_service_win.cc
blob3e0bb15ab67f68da8d4c7e42a311c5df8d30d941
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
3 // found in the LICENSE file.
5 #include "device/hid/hid_service_win.h"
7 #include <cstdlib>
9 #include "base/bind.h"
10 #include "base/files/file.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "device/hid/hid_connection_win.h"
18 #include "device/hid/hid_device_info.h"
19 #include "net/base/io_buffer.h"
21 #if defined(OS_WIN)
23 #define INITGUID
25 #include <setupapi.h>
26 #include <winioctl.h>
27 #include "base/win/scoped_handle.h"
29 #endif // defined(OS_WIN)
31 // Setup API is required to enumerate HID devices.
32 #pragma comment(lib, "setupapi.lib")
33 #pragma comment(lib, "hid.lib")
35 namespace device {
36 namespace {
38 const char kHIDClass[] = "HIDClass";
40 } // namespace
42 HidServiceWin::HidServiceWin() {
43 base::ThreadRestrictions::AssertIOAllowed();
44 task_runner_ = base::ThreadTaskRunnerHandle::Get();
45 DCHECK(task_runner_.get());
46 Enumerate();
49 HidServiceWin::~HidServiceWin() {}
51 void HidServiceWin::Enumerate() {
52 BOOL res;
53 HDEVINFO device_info_set;
54 SP_DEVINFO_DATA devinfo_data;
55 SP_DEVICE_INTERFACE_DATA device_interface_data;
57 memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
58 devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
59 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
61 device_info_set = SetupDiGetClassDevs(
62 &GUID_DEVINTERFACE_HID,
63 NULL,
64 NULL,
65 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
67 std::set<std::string> connected_devices;
69 if (device_info_set != INVALID_HANDLE_VALUE) {
70 for (int device_index = 0;
71 SetupDiEnumDeviceInterfaces(device_info_set,
72 NULL,
73 &GUID_DEVINTERFACE_HID,
74 device_index,
75 &device_interface_data);
76 ++device_index) {
77 DWORD required_size = 0;
79 // Determime the required size of detail struct.
80 SetupDiGetDeviceInterfaceDetailA(device_info_set,
81 &device_interface_data,
82 NULL,
84 &required_size,
85 NULL);
87 scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
88 device_interface_detail_data(
89 static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
90 malloc(required_size)));
91 device_interface_detail_data->cbSize =
92 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
94 // Get the detailed data for this device.
95 res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
96 &device_interface_data,
97 device_interface_detail_data.get(),
98 required_size,
99 NULL,
100 NULL);
101 if (!res)
102 continue;
104 // Enumerate device info. Looking for Setup Class "HIDClass".
105 for (DWORD i = 0;
106 SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
107 i++) {
108 char class_name[256] = {0};
109 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
110 &devinfo_data,
111 SPDRP_CLASS,
112 NULL,
113 (PBYTE) class_name,
114 sizeof(class_name) - 1,
115 NULL);
116 if (!res)
117 break;
118 if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
119 char driver_name[256] = {0};
120 // Get bounded driver.
121 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
122 &devinfo_data,
123 SPDRP_DRIVER,
124 NULL,
125 (PBYTE) driver_name,
126 sizeof(driver_name) - 1,
127 NULL);
128 if (res) {
129 // Found the driver.
130 break;
135 if (!res)
136 continue;
138 PlatformAddDevice(device_interface_detail_data->DevicePath);
139 connected_devices.insert(device_interface_detail_data->DevicePath);
143 // Find disconnected devices.
144 std::vector<std::string> disconnected_devices;
145 for (DeviceMap::const_iterator it = devices().begin(); it != devices().end();
146 ++it) {
147 if (!ContainsKey(connected_devices, it->first)) {
148 disconnected_devices.push_back(it->first);
152 // Remove disconnected devices.
153 for (size_t i = 0; i < disconnected_devices.size(); ++i) {
154 PlatformRemoveDevice(disconnected_devices[i]);
158 void HidServiceWin::CollectInfoFromButtonCaps(
159 PHIDP_PREPARSED_DATA preparsed_data,
160 HIDP_REPORT_TYPE report_type,
161 USHORT button_caps_length,
162 HidCollectionInfo* collection_info) {
163 if (button_caps_length > 0) {
164 scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
165 new HIDP_BUTTON_CAPS[button_caps_length]);
166 if (HidP_GetButtonCaps(report_type,
167 &button_caps[0],
168 &button_caps_length,
169 preparsed_data) == HIDP_STATUS_SUCCESS) {
170 for (size_t i = 0; i < button_caps_length; i++) {
171 int report_id = button_caps[i].ReportID;
172 if (report_id != 0) {
173 collection_info->report_ids.insert(report_id);
180 void HidServiceWin::CollectInfoFromValueCaps(
181 PHIDP_PREPARSED_DATA preparsed_data,
182 HIDP_REPORT_TYPE report_type,
183 USHORT value_caps_length,
184 HidCollectionInfo* collection_info) {
185 if (value_caps_length > 0) {
186 scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
187 new HIDP_VALUE_CAPS[value_caps_length]);
188 if (HidP_GetValueCaps(
189 report_type, &value_caps[0], &value_caps_length, preparsed_data) ==
190 HIDP_STATUS_SUCCESS) {
191 for (size_t i = 0; i < value_caps_length; i++) {
192 int report_id = value_caps[i].ReportID;
193 if (report_id != 0) {
194 collection_info->report_ids.insert(report_id);
201 void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
202 HidDeviceInfo device_info;
203 device_info.device_id = device_path;
205 // Try to open the device.
206 base::win::ScopedHandle device_handle(
207 CreateFileA(device_path.c_str(),
208 GENERIC_WRITE | GENERIC_READ,
209 FILE_SHARE_READ | FILE_SHARE_WRITE,
210 NULL,
211 OPEN_EXISTING,
212 FILE_FLAG_OVERLAPPED,
213 0));
215 if (!device_handle.IsValid() &&
216 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
217 base::win::ScopedHandle device_handle(
218 CreateFileA(device_path.c_str(),
219 GENERIC_READ,
220 FILE_SHARE_READ,
221 NULL,
222 OPEN_EXISTING,
223 FILE_FLAG_OVERLAPPED,
224 0));
226 if (!device_handle.IsValid())
227 return;
230 // Get VID/PID pair.
231 HIDD_ATTRIBUTES attrib = {0};
232 attrib.Size = sizeof(HIDD_ATTRIBUTES);
233 if (!HidD_GetAttributes(device_handle.Get(), &attrib))
234 return;
236 device_info.vendor_id = attrib.VendorID;
237 device_info.product_id = attrib.ProductID;
239 for (ULONG i = 32;
240 HidD_SetNumInputBuffers(device_handle.Get(), i);
241 i <<= 1);
243 // Get usage and usage page (optional).
244 PHIDP_PREPARSED_DATA preparsed_data;
245 if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
246 preparsed_data) {
247 HIDP_CAPS capabilities = {0};
248 if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
249 device_info.max_input_report_size = capabilities.InputReportByteLength;
250 device_info.max_output_report_size = capabilities.OutputReportByteLength;
251 device_info.max_feature_report_size =
252 capabilities.FeatureReportByteLength;
253 HidCollectionInfo collection_info;
254 collection_info.usage = HidUsageAndPage(
255 capabilities.Usage,
256 static_cast<HidUsageAndPage::Page>(capabilities.UsagePage));
257 CollectInfoFromButtonCaps(preparsed_data,
258 HidP_Input,
259 capabilities.NumberInputButtonCaps,
260 &collection_info);
261 CollectInfoFromButtonCaps(preparsed_data,
262 HidP_Output,
263 capabilities.NumberOutputButtonCaps,
264 &collection_info);
265 CollectInfoFromButtonCaps(preparsed_data,
266 HidP_Feature,
267 capabilities.NumberFeatureButtonCaps,
268 &collection_info);
269 CollectInfoFromValueCaps(preparsed_data,
270 HidP_Input,
271 capabilities.NumberInputValueCaps,
272 &collection_info);
273 CollectInfoFromValueCaps(preparsed_data,
274 HidP_Output,
275 capabilities.NumberOutputValueCaps,
276 &collection_info);
277 CollectInfoFromValueCaps(preparsed_data,
278 HidP_Feature,
279 capabilities.NumberFeatureValueCaps,
280 &collection_info);
281 if (!collection_info.report_ids.empty()) {
282 device_info.has_report_id = true;
284 device_info.collections.push_back(collection_info);
286 // Whether or not the device includes report IDs in its reports the size
287 // of the report ID is included in the value provided by Windows. This
288 // appears contrary to the MSDN documentation.
289 if (device_info.max_input_report_size > 0) {
290 device_info.max_input_report_size--;
292 if (device_info.max_output_report_size > 0) {
293 device_info.max_output_report_size--;
295 if (device_info.max_feature_report_size > 0) {
296 device_info.max_feature_report_size--;
298 HidD_FreePreparsedData(preparsed_data);
301 AddDevice(device_info);
304 void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
305 RemoveDevice(device_path);
308 void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
309 Enumerate();
310 HidService::GetDevices(devices);
313 void HidServiceWin::Connect(const HidDeviceId& device_id,
314 const ConnectCallback& callback) {
315 DCHECK(thread_checker_.CalledOnValidThread());
316 const auto& map_entry = devices().find(device_id);
317 if (map_entry == devices().end()) {
318 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
319 return;
321 const HidDeviceInfo& device_info = map_entry->second;
323 scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
324 if (!connection->available()) {
325 PLOG(ERROR) << "Failed to open device";
326 connection = nullptr;
328 task_runner_->PostTask(FROM_HERE, base::Bind(callback, connection));
331 } // namespace device