| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 #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 |  | 
| OLD | NEW | 
|---|