Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / device / hid / hid_service_win.cc
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.
4
5 #include "device/hid/hid_service_win.h"
6
7 #include <cstdlib>
8 #include <string>
9
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"
19
20 #if defined(OS_WIN)
21
22 #define INITGUID
23
24 #include <windows.h>
25 #include <hidclass.h>
26
27 extern "C" {
28
29 #include <hidsdi.h>
30 #include <hidpi.h>
31
32 }
33
34 #include <setupapi.h>
35 #include <winioctl.h>
36 #include "base/win/scoped_handle.h"
37
38 #endif  // defined(OS_WIN)
39
40 // Setup API is required to enumerate HID devices.
41 #pragma comment(lib, "setupapi.lib")
42 #pragma comment(lib, "hid.lib")
43
44 namespace device {
45 namespace {
46
47 const char kHIDClass[] = "HIDClass";
48
49 }  // namespace
50
51 HidServiceWin::HidServiceWin() {
52   initialized_ = Enumerate();
53 }
54 HidServiceWin::~HidServiceWin() {}
55
56 bool HidServiceWin::Enumerate() {
57   BOOL res;
58   HDEVINFO device_info_set;
59   SP_DEVINFO_DATA devinfo_data;
60   SP_DEVICE_INTERFACE_DATA device_interface_data;
61
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);
65
66   device_info_set = SetupDiGetClassDevs(
67       &GUID_DEVINTERFACE_HID,
68       NULL,
69       NULL,
70       DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
71
72   if (device_info_set == INVALID_HANDLE_VALUE)
73     return false;
74
75   for (int device_index = 0;
76       SetupDiEnumDeviceInterfaces(device_info_set,
77                                   NULL,
78                                   &GUID_DEVINTERFACE_HID,
79                                   device_index,
80                                   &device_interface_data);
81       device_index++) {
82     DWORD required_size = 0;
83
84     // Determime the required size of detail struct.
85     SetupDiGetDeviceInterfaceDetailA(device_info_set,
86                                      &device_interface_data,
87                                      NULL,
88                                      0,
89                                      &required_size,
90                                      NULL);
91
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);
98
99     // Get the detailed data for this device.
100     res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
101                                            &device_interface_data,
102                                            device_interface_detail_data.get(),
103                                            required_size,
104                                            NULL,
105                                            NULL);
106     if (!res)
107       continue;
108
109     // Enumerate device info. Looking for Setup Class "HIDClass".
110     for (DWORD i = 0;
111         SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
112         i++) {
113       char class_name[256] = {0};
114       res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
115                                               &devinfo_data,
116                                               SPDRP_CLASS,
117                                               NULL,
118                                               (PBYTE) class_name,
119                                               sizeof(class_name) - 1,
120                                               NULL);
121       if (!res)
122         break;
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,
127                                                 &devinfo_data,
128                                                 SPDRP_DRIVER,
129                                                 NULL,
130                                                 (PBYTE) driver_name,
131                                                 sizeof(driver_name) - 1,
132                                                 NULL);
133         if (res) {
134           // Found the drive.
135           break;
136         }
137       }
138     }
139
140     if (!res)
141       continue;
142
143     PlatformAddDevice(device_interface_detail_data->DevicePath);
144   }
145
146   return true;
147 }
148
149 void HidServiceWin::PlatformAddDevice(std::string device_path) {
150   HidDeviceInfo device_info;
151   device_info.device_id = device_path;
152
153   // Try to open the device.
154   base::win::ScopedHandle device_handle(
155       CreateFileA(device_path.c_str(),
156                   0,
157                   FILE_SHARE_READ | FILE_SHARE_WRITE,
158                   NULL,
159                   OPEN_EXISTING,
160                   FILE_FLAG_OVERLAPPED,
161                   0));
162   if (!device_handle.IsValid())
163     return;
164
165   // Get VID/PID pair.
166   HIDD_ATTRIBUTES attrib = {0};
167   attrib.Size = sizeof(HIDD_ATTRIBUTES);
168   if (!HidD_GetAttributes(device_handle.Get(), &attrib))
169     return;
170
171   device_info.vendor_id = attrib.VendorID;
172   device_info.product_id = attrib.ProductID;
173
174   for (ULONG i = 32;
175       HidD_SetNumInputBuffers(device_handle.Get(), i);
176       i <<= 1);
177
178   // Get usage and usage page (optional).
179   PHIDP_PREPARSED_DATA preparsed_data;
180   if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
181       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;
189     }
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);
198       }
199     }
200     HidD_FreePreparsedData(preparsed_data);
201   }
202
203   // Get the serial number
204   wchar_t str_property[512] = { 0 };
205   if (HidD_GetSerialNumberString(device_handle.Get(),
206                                  str_property,
207                                  sizeof(str_property))) {
208     device_info.serial_number = base::SysWideToUTF8(str_property);
209   }
210
211   if (HidD_GetProductString(device_handle.Get(),
212                             str_property,
213                             sizeof(str_property))) {
214     device_info.product_name = base::SysWideToUTF8(str_property);
215   }
216
217   HidService::AddDevice(device_info);
218 }
219
220 void HidServiceWin::PlatformRemoveDevice(std::string device_path) {
221   HidService::RemoveDevice(device_path);
222 }
223
224 void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
225   Enumerate();
226   HidService::GetDevices(devices);
227 }
228
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.";
235     return NULL;
236   }
237   return connection;
238 }
239
240 }  // namespace device