summaryrefslogtreecommitdiffstats
path: root/device/hid/hid_service_win.cc
diff options
context:
space:
mode:
authorrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-31 20:13:23 +0000
committerrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-31 20:13:23 +0000
commit125724f2dd1b339cc6dc3f3bcf2b0d565765471f (patch)
treeb6b1f0d2bd292f39161de8317338edb6076fd848 /device/hid/hid_service_win.cc
parent64e3d73b60bbe5d3e7808c444ae1e1e392981a41 (diff)
downloadchromium_src-125724f2dd1b339cc6dc3f3bcf2b0d565765471f.zip
chromium_src-125724f2dd1b339cc6dc3f3bcf2b0d565765471f.tar.gz
chromium_src-125724f2dd1b339cc6dc3f3bcf2b0d565765471f.tar.bz2
HID backend.
This is a continuation of https://codereview.chromium.org/143883005. [ps#1 here is (post-revert) ps#12 there.] BUG=290428 TBR=miket@chromium.org Review URL: https://codereview.chromium.org/150773004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@248250 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/hid/hid_service_win.cc')
-rw-r--r--device/hid/hid_service_win.cc240
1 files changed, 240 insertions, 0 deletions
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc
new file mode 100644
index 0000000..cf9db15
--- /dev/null
+++ b/device/hid/hid_service_win.cc
@@ -0,0 +1,240 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/hid/hid_service_win.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "device/hid/hid_connection.h"
+#include "device/hid/hid_connection_win.h"
+#include "device/hid/hid_service.h"
+#include "net/base/io_buffer.h"
+
+#if defined(OS_WIN)
+
+#define INITGUID
+
+#include <windows.h>
+#include <hidclass.h>
+
+extern "C" {
+
+#include <hidsdi.h>
+#include <hidpi.h>
+
+}
+
+#include <setupapi.h>
+#include <winioctl.h>
+#include "base/win/scoped_handle.h"
+
+#endif // defined(OS_WIN)
+
+// Setup API is required to enumerate HID devices.
+#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "hid.lib")
+
+namespace device {
+namespace {
+
+const char kHIDClass[] = "HIDClass";
+
+} // namespace
+
+HidServiceWin::HidServiceWin() {
+ initialized_ = Enumerate();
+}
+HidServiceWin::~HidServiceWin() {}
+
+bool HidServiceWin::Enumerate() {
+ BOOL res;
+ HDEVINFO device_info_set;
+ SP_DEVINFO_DATA devinfo_data;
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+
+ memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
+ devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+ device_info_set = SetupDiGetClassDevs(
+ &GUID_DEVINTERFACE_HID,
+ NULL,
+ NULL,
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ if (device_info_set == INVALID_HANDLE_VALUE)
+ return false;
+
+ for (int device_index = 0;
+ SetupDiEnumDeviceInterfaces(device_info_set,
+ NULL,
+ &GUID_DEVINTERFACE_HID,
+ device_index,
+ &device_interface_data);
+ device_index++) {
+ DWORD required_size = 0;
+
+ // Determime the required size of detail struct.
+ SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ NULL,
+ 0,
+ &required_size,
+ NULL);
+
+ scoped_ptr_malloc<SP_DEVICE_INTERFACE_DETAIL_DATA_A>
+ device_interface_detail_data(
+ reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
+ malloc(required_size)));
+ device_interface_detail_data->cbSize =
+ sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+
+ // Get the detailed data for this device.
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ device_interface_detail_data.get(),
+ required_size,
+ NULL,
+ NULL);
+ if (!res)
+ continue;
+
+ // Enumerate device info. Looking for Setup Class "HIDClass".
+ for (DWORD i = 0;
+ SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+ i++) {
+ char class_name[256] = {0};
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
+ &devinfo_data,
+ SPDRP_CLASS,
+ NULL,
+ (PBYTE) class_name,
+ sizeof(class_name) - 1,
+ NULL);
+ if (!res)
+ break;
+ if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
+ char driver_name[256] = {0};
+ // Get bounded driver.
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
+ &devinfo_data,
+ SPDRP_DRIVER,
+ NULL,
+ (PBYTE) driver_name,
+ sizeof(driver_name) - 1,
+ NULL);
+ if (res) {
+ // Found the drive.
+ break;
+ }
+ }
+ }
+
+ if (!res)
+ continue;
+
+ PlatformAddDevice(device_interface_detail_data->DevicePath);
+ }
+
+ return true;
+}
+
+void HidServiceWin::PlatformAddDevice(std::string device_path) {
+ HidDeviceInfo device_info;
+ device_info.device_id = device_path;
+
+ // Try to open the device.
+ base::win::ScopedHandle device_handle(
+ CreateFileA(device_path.c_str(),
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ 0));
+ if (!device_handle.IsValid())
+ return;
+
+ // Get VID/PID pair.
+ HIDD_ATTRIBUTES attrib = {0};
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
+ if (!HidD_GetAttributes(device_handle.Get(), &attrib))
+ return;
+
+ device_info.vendor_id = attrib.VendorID;
+ device_info.product_id = attrib.ProductID;
+
+ for (ULONG i = 32;
+ HidD_SetNumInputBuffers(device_handle.Get(), i);
+ i <<= 1);
+
+ // Get usage and usage page (optional).
+ PHIDP_PREPARSED_DATA preparsed_data;
+ if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
+ preparsed_data) {
+ HIDP_CAPS capabilities;
+ if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
+ device_info.usage = capabilities.Usage;
+ device_info.usage_page = capabilities.UsagePage;
+ device_info.input_report_size = capabilities.InputReportByteLength;
+ device_info.output_report_size = capabilities.OutputReportByteLength;
+ device_info.feature_report_size = capabilities.FeatureReportByteLength;
+ }
+ // Detect if the device supports report ids.
+ if (capabilities.NumberInputValueCaps > 0) {
+ scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
+ new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
+ USHORT value_caps_length = capabilities.NumberInputValueCaps;
+ if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
+ preparsed_data) == HIDP_STATUS_SUCCESS) {
+ device_info.has_report_id = (value_caps[0].ReportID != 0);
+ }
+ }
+ HidD_FreePreparsedData(preparsed_data);
+ }
+
+ // Get the serial number
+ wchar_t str_property[512] = { 0 };
+ if (HidD_GetSerialNumberString(device_handle.Get(),
+ str_property,
+ sizeof(str_property))) {
+ device_info.serial_number = base::SysWideToUTF8(str_property);
+ }
+
+ if (HidD_GetProductString(device_handle.Get(),
+ str_property,
+ sizeof(str_property))) {
+ device_info.product_name = base::SysWideToUTF8(str_property);
+ }
+
+ HidService::AddDevice(device_info);
+}
+
+void HidServiceWin::PlatformRemoveDevice(std::string device_path) {
+ HidService::RemoveDevice(device_path);
+}
+
+void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
+ Enumerate();
+ HidService::GetDevices(devices);
+}
+
+scoped_refptr<HidConnection> HidServiceWin::Connect(std::string device_id) {
+ if (!ContainsKey(devices_, device_id)) return NULL;
+ scoped_refptr<HidConnectionWin> connection(
+ new HidConnectionWin(devices_[device_id]));
+ if (!connection->available()) {
+ LOG_GETLASTERROR(ERROR) << "Failed to open device.";
+ return NULL;
+ }
+ return connection;
+}
+
+} // namespace device