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