1 // Copyright (c) 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"
10 #include "base/callback_helpers.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/stl_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "device/hid/hid_connection.h"
16 #include "device/hid/hid_connection_win.h"
17 #include "device/hid/hid_service.h"
18 #include "net/base/io_buffer.h"
36 #include "base/win/scoped_handle.h"
38 #endif // defined(OS_WIN)
40 // Setup API is required to enumerate HID devices.
41 #pragma comment(lib, "setupapi.lib")
42 #pragma comment(lib, "hid.lib")
47 const char kHIDClass[] = "HIDClass";
51 HidServiceWin::HidServiceWin() {
52 initialized_ = Enumerate();
54 HidServiceWin::~HidServiceWin() {}
56 bool HidServiceWin::Enumerate() {
58 HDEVINFO device_info_set;
59 SP_DEVINFO_DATA devinfo_data;
60 SP_DEVICE_INTERFACE_DATA device_interface_data;
62 memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
63 devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
64 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
66 device_info_set = SetupDiGetClassDevs(
67 &GUID_DEVINTERFACE_HID,
70 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
72 if (device_info_set == INVALID_HANDLE_VALUE)
75 for (int device_index = 0;
76 SetupDiEnumDeviceInterfaces(device_info_set,
78 &GUID_DEVINTERFACE_HID,
80 &device_interface_data);
82 DWORD required_size = 0;
84 // Determime the required size of detail struct.
85 SetupDiGetDeviceInterfaceDetailA(device_info_set,
86 &device_interface_data,
92 scoped_ptr_malloc<SP_DEVICE_INTERFACE_DETAIL_DATA_A>
93 device_interface_detail_data(
94 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
95 malloc(required_size)));
96 device_interface_detail_data->cbSize =
97 sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
99 // Get the detailed data for this device.
100 res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
101 &device_interface_data,
102 device_interface_detail_data.get(),
109 // Enumerate device info. Looking for Setup Class "HIDClass".
111 SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
113 char class_name[256] = {0};
114 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
119 sizeof(class_name) - 1,
123 if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
124 char driver_name[256] = {0};
125 // Get bounded driver.
126 res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
131 sizeof(driver_name) - 1,
143 PlatformAddDevice(device_interface_detail_data->DevicePath);
149 void HidServiceWin::PlatformAddDevice(std::string device_path) {
150 HidDeviceInfo device_info;
151 device_info.device_id = device_path;
153 // Try to open the device.
154 base::win::ScopedHandle device_handle(
155 CreateFileA(device_path.c_str(),
157 FILE_SHARE_READ | FILE_SHARE_WRITE,
160 FILE_FLAG_OVERLAPPED,
162 if (!device_handle.IsValid())
166 HIDD_ATTRIBUTES attrib = {0};
167 attrib.Size = sizeof(HIDD_ATTRIBUTES);
168 if (!HidD_GetAttributes(device_handle.Get(), &attrib))
171 device_info.vendor_id = attrib.VendorID;
172 device_info.product_id = attrib.ProductID;
175 HidD_SetNumInputBuffers(device_handle.Get(), i);
178 // Get usage and usage page (optional).
179 PHIDP_PREPARSED_DATA preparsed_data;
180 if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
182 HIDP_CAPS capabilities;
183 if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
184 device_info.usage = capabilities.Usage;
185 device_info.usage_page = capabilities.UsagePage;
186 device_info.input_report_size = capabilities.InputReportByteLength;
187 device_info.output_report_size = capabilities.OutputReportByteLength;
188 device_info.feature_report_size = capabilities.FeatureReportByteLength;
190 // Detect if the device supports report ids.
191 if (capabilities.NumberInputValueCaps > 0) {
192 scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
193 new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
194 USHORT value_caps_length = capabilities.NumberInputValueCaps;
195 if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
196 preparsed_data) == HIDP_STATUS_SUCCESS) {
197 device_info.has_report_id = (value_caps[0].ReportID != 0);
200 HidD_FreePreparsedData(preparsed_data);
203 // Get the serial number
204 wchar_t str_property[512] = { 0 };
205 if (HidD_GetSerialNumberString(device_handle.Get(),
207 sizeof(str_property))) {
208 device_info.serial_number = base::SysWideToUTF8(str_property);
211 if (HidD_GetProductString(device_handle.Get(),
213 sizeof(str_property))) {
214 device_info.product_name = base::SysWideToUTF8(str_property);
217 HidService::AddDevice(device_info);
220 void HidServiceWin::PlatformRemoveDevice(std::string device_path) {
221 HidService::RemoveDevice(device_path);
224 void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
226 HidService::GetDevices(devices);
229 scoped_refptr<HidConnection> HidServiceWin::Connect(std::string device_id) {
230 if (!ContainsKey(devices_, device_id)) return NULL;
231 scoped_refptr<HidConnectionWin> connection(
232 new HidConnectionWin(devices_[device_id]));
233 if (!connection->available()) {
234 LOG_GETLASTERROR(ERROR) << "Failed to open device.";
240 } // namespace device