Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / device / hid / hid_service_win.cc
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.
4
5 #include "device/hid/hid_service_win.h"
6
7 #include <cstdlib>
8
9 #include "base/files/file.h"
10 #include "base/stl_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "device/hid/hid_connection_win.h"
13 #include "device/hid/hid_device_info.h"
14 #include "net/base/io_buffer.h"
15
16 #if defined(OS_WIN)
17
18 #define INITGUID
19
20 #include <windows.h>
21 #include <hidclass.h>
22
23 extern "C" {
24
25 #include <hidsdi.h>
26 #include <hidpi.h>
27
28 }
29
30 #include <setupapi.h>
31 #include <winioctl.h>
32 #include "base/win/scoped_handle.h"
33
34 #endif  // defined(OS_WIN)
35
36 // Setup API is required to enumerate HID devices.
37 #pragma comment(lib, "setupapi.lib")
38 #pragma comment(lib, "hid.lib")
39
40 namespace device {
41 namespace {
42
43 const char kHIDClass[] = "HIDClass";
44
45 }  // namespace
46
47 HidServiceWin::HidServiceWin() {
48   Enumerate();
49 }
50
51 HidServiceWin::~HidServiceWin() {}
52
53 void HidServiceWin::Enumerate() {
54   BOOL res;
55   HDEVINFO device_info_set;
56   SP_DEVINFO_DATA devinfo_data;
57   SP_DEVICE_INTERFACE_DATA device_interface_data;
58
59   memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
60   devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
61   device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
62
63   device_info_set = SetupDiGetClassDevs(
64       &GUID_DEVINTERFACE_HID,
65       NULL,
66       NULL,
67       DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
68
69   std::set<std::string> connected_devices;
70
71   if (device_info_set != INVALID_HANDLE_VALUE) {
72     for (int device_index = 0;
73          SetupDiEnumDeviceInterfaces(device_info_set,
74                                      NULL,
75                                      &GUID_DEVINTERFACE_HID,
76                                      device_index,
77                                      &device_interface_data);
78          ++device_index) {
79       DWORD required_size = 0;
80
81       // Determime the required size of detail struct.
82       SetupDiGetDeviceInterfaceDetailA(device_info_set,
83                                        &device_interface_data,
84                                        NULL,
85                                        0,
86                                        &required_size,
87                                        NULL);
88
89       scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
90           device_interface_detail_data(
91               static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
92                   malloc(required_size)));
93       device_interface_detail_data->cbSize =
94           sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
95
96       // Get the detailed data for this device.
97       res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
98                                              &device_interface_data,
99                                              device_interface_detail_data.get(),
100                                              required_size,
101                                              NULL,
102                                              NULL);
103       if (!res)
104         continue;
105
106       // Enumerate device info. Looking for Setup Class "HIDClass".
107       for (DWORD i = 0;
108           SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
109           i++) {
110         char class_name[256] = {0};
111         res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
112                                                 &devinfo_data,
113                                                 SPDRP_CLASS,
114                                                 NULL,
115                                                 (PBYTE) class_name,
116                                                 sizeof(class_name) - 1,
117                                                 NULL);
118         if (!res)
119           break;
120         if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
121           char driver_name[256] = {0};
122           // Get bounded driver.
123           res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
124                                                   &devinfo_data,
125                                                   SPDRP_DRIVER,
126                                                   NULL,
127                                                   (PBYTE) driver_name,
128                                                   sizeof(driver_name) - 1,
129                                                   NULL);
130           if (res) {
131             // Found the driver.
132             break;
133           }
134         }
135       }
136
137       if (!res)
138         continue;
139
140       PlatformAddDevice(device_interface_detail_data->DevicePath);
141       connected_devices.insert(device_interface_detail_data->DevicePath);
142     }
143   }
144
145   // Find disconnected devices.
146   const DeviceMap& devices = GetDevicesNoEnumerate();
147   std::vector<std::string> disconnected_devices;
148   for (DeviceMap::const_iterator it = devices.begin();
149        it != devices.end();
150        ++it) {
151     if (!ContainsKey(connected_devices, it->first)) {
152       disconnected_devices.push_back(it->first);
153     }
154   }
155
156   // Remove disconnected devices.
157   for (size_t i = 0; i < disconnected_devices.size(); ++i) {
158     PlatformRemoveDevice(disconnected_devices[i]);
159   }
160 }
161
162 void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
163   HidDeviceInfo device_info;
164   device_info.device_id = device_path;
165
166   // Try to open the device.
167   base::win::ScopedHandle device_handle(
168       CreateFileA(device_path.c_str(),
169                   GENERIC_WRITE | GENERIC_READ,
170                   FILE_SHARE_READ | FILE_SHARE_WRITE,
171                   NULL,
172                   OPEN_EXISTING,
173                   FILE_FLAG_OVERLAPPED,
174                   0));
175
176   if (!device_handle.IsValid() &&
177       GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
178     base::win::ScopedHandle device_handle(
179       CreateFileA(device_path.c_str(),
180       GENERIC_READ,
181       FILE_SHARE_READ,
182       NULL,
183       OPEN_EXISTING,
184       FILE_FLAG_OVERLAPPED,
185       0));
186
187     if (!device_handle.IsValid())
188       return;
189   }
190
191   // Get VID/PID pair.
192   HIDD_ATTRIBUTES attrib = {0};
193   attrib.Size = sizeof(HIDD_ATTRIBUTES);
194   if (!HidD_GetAttributes(device_handle.Get(), &attrib))
195     return;
196
197   device_info.vendor_id = attrib.VendorID;
198   device_info.product_id = attrib.ProductID;
199
200   for (ULONG i = 32;
201       HidD_SetNumInputBuffers(device_handle.Get(), i);
202       i <<= 1);
203
204   // Get usage and usage page (optional).
205   PHIDP_PREPARSED_DATA preparsed_data;
206   if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
207       preparsed_data) {
208     HIDP_CAPS capabilities = {0};
209     if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
210       device_info.max_input_report_size = capabilities.InputReportByteLength;
211       device_info.max_output_report_size = capabilities.OutputReportByteLength;
212       device_info.max_feature_report_size =
213           capabilities.FeatureReportByteLength;
214       HidCollectionInfo collection_info;
215       collection_info.usage = HidUsageAndPage(
216           capabilities.Usage,
217           static_cast<HidUsageAndPage::Page>(capabilities.UsagePage));
218       USHORT button_caps_length = capabilities.NumberInputButtonCaps;
219       if (button_caps_length > 0) {
220         scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
221             new HIDP_BUTTON_CAPS[button_caps_length]);
222         if (HidP_GetButtonCaps(HidP_Input,
223                                &button_caps[0],
224                                &button_caps_length,
225                                preparsed_data) == HIDP_STATUS_SUCCESS) {
226           for (int i = 0; i < button_caps_length; i++) {
227             int report_id = button_caps[i].ReportID;
228             if (report_id != 0) {
229               collection_info.report_ids.insert(report_id);
230               device_info.has_report_id = true;
231             }
232           }
233         }
234       }
235       USHORT value_caps_length = capabilities.NumberInputValueCaps;
236       if (value_caps_length > 0) {
237         scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
238             new HIDP_VALUE_CAPS[value_caps_length]);
239         if (HidP_GetValueCaps(HidP_Input,
240                               &value_caps[0],
241                               &value_caps_length,
242                               preparsed_data) == HIDP_STATUS_SUCCESS) {
243           for (int i = 0; i < value_caps_length; i++) {
244             int report_id = value_caps[i].ReportID;
245             if (report_id != 0) {
246               collection_info.report_ids.insert(report_id);
247               device_info.has_report_id = true;
248             }
249           }
250         }
251       }
252       device_info.collections.push_back(collection_info);
253     }
254     // Whether or not the device includes report IDs in its reports the size
255     // of the report ID is included in the value provided by Windows. This
256     // appears contrary to the MSDN documentation.
257     if (device_info.max_input_report_size > 0) {
258       device_info.max_input_report_size--;
259     }
260     if (device_info.max_output_report_size > 0) {
261       device_info.max_output_report_size--;
262     }
263     if (device_info.max_feature_report_size > 0) {
264       device_info.max_feature_report_size--;
265     }
266     HidD_FreePreparsedData(preparsed_data);
267   }
268
269   AddDevice(device_info);
270 }
271
272 void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
273   RemoveDevice(device_path);
274 }
275
276 void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
277   Enumerate();
278   HidService::GetDevices(devices);
279 }
280
281 scoped_refptr<HidConnection> HidServiceWin::Connect(
282     const HidDeviceId& device_id) {
283   HidDeviceInfo device_info;
284   if (!GetDeviceInfo(device_id, &device_info))
285     return NULL;
286   scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
287   if (!connection->available()) {
288     PLOG(ERROR) << "Failed to open device.";
289     return NULL;
290   }
291   return connection;
292 }
293
294 }  // namespace device