hid_service_win.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service_win.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <cstdlib>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/callback_helpers.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/lazy_instance.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/sys_string_conversions.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_win.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/io_buffer.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_WIN)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidclass.h>
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" {
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidsdi.h>
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidpi.h>
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h"
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(OS_WIN)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Setup API is required to enumerate HID devices.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "setupapi.lib")
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "hid.lib")
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHIDClass[] = "HIDClass";
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::HidServiceWin() {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  initialized_ = Enumerate();
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::~HidServiceWin() {}
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HidServiceWin::Enumerate() {
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOOL res;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HDEVINFO device_info_set;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVINFO_DATA devinfo_data;
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DATA device_interface_data;
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info_set = SetupDiGetClassDevs(
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &GUID_DEVINTERFACE_HID,
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_info_set == INVALID_HANDLE_VALUE)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int device_index = 0;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SetupDiEnumDeviceInterfaces(device_info_set,
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  NULL,
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  &GUID_DEVINTERFACE_HID,
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  device_index,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  &device_interface_data);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_index++) {
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD required_size = 0;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determime the required size of detail struct.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetupDiGetDeviceInterfaceDetailA(device_info_set,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &device_interface_data,
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     0,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &required_size,
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr_malloc<SP_DEVICE_INTERFACE_DETAIL_DATA_A>
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_interface_detail_data(
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                malloc(required_size)));
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_interface_detail_data->cbSize =
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Get the detailed data for this device.
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           &device_interface_data,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           device_interface_detail_data.get(),
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           required_size,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL,
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL);
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Enumerate device info. Looking for Setup Class "HIDClass".
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (DWORD i = 0;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        i++) {
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      char class_name[256] = {0};
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              &devinfo_data,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              SPDRP_CLASS,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              (PBYTE) class_name,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              sizeof(class_name) - 1,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!res)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        char driver_name[256] = {0};
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Get bounded driver.
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                &devinfo_data,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                SPDRP_DRIVER,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                (PBYTE) driver_name,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                sizeof(driver_name) - 1,
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL);
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (res) {
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Found the drive.
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PlatformAddDevice(device_interface_detail_data->DevicePath);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::PlatformAddDevice(std::string device_path) {
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidDeviceInfo device_info;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.device_id = device_path;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try to open the device.
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedHandle device_handle(
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateFileA(device_path.c_str(),
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0,
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FILE_SHARE_READ | FILE_SHARE_WRITE,
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  NULL,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  OPEN_EXISTING,
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FILE_FLAG_OVERLAPPED,
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0));
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!device_handle.IsValid())
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get VID/PID pair.
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HIDD_ATTRIBUTES attrib = {0};
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  attrib.Size = sizeof(HIDD_ATTRIBUTES);
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!HidD_GetAttributes(device_handle.Get(), &attrib))
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.vendor_id = attrib.VendorID;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.product_id = attrib.ProductID;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ULONG i = 32;
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      HidD_SetNumInputBuffers(device_handle.Get(), i);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      i <<= 1);
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get usage and usage page (optional).
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PHIDP_PREPARSED_DATA preparsed_data;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      preparsed_data) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HIDP_CAPS capabilities;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.usage = capabilities.Usage;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.usage_page = capabilities.UsagePage;
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.input_report_size = capabilities.InputReportByteLength;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.output_report_size = capabilities.OutputReportByteLength;
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.feature_report_size = capabilities.FeatureReportByteLength;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Detect if the device supports report ids.
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (capabilities.NumberInputValueCaps > 0) {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      USHORT value_caps_length = capabilities.NumberInputValueCaps;
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            preparsed_data) == HIDP_STATUS_SUCCESS) {
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_info.has_report_id = (value_caps[0].ReportID != 0);
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HidD_FreePreparsedData(preparsed_data);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the serial number
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  wchar_t str_property[512] = { 0 };
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetSerialNumberString(device_handle.Get(),
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 str_property,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 sizeof(str_property))) {
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_info.serial_number = base::SysWideToUTF8(str_property);
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetProductString(device_handle.Get(),
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            str_property,
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            sizeof(str_property))) {
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_info.product_name = base::SysWideToUTF8(str_property);
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::AddDevice(device_info);
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::PlatformRemoveDevice(std::string device_path) {
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::RemoveDevice(device_path);
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Enumerate();
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::GetDevices(devices);
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<HidConnection> HidServiceWin::Connect(std::string device_id) {
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ContainsKey(devices_, device_id)) return NULL;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<HidConnectionWin> connection(
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new HidConnectionWin(devices_[device_id]));
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!connection->available()) {
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG_GETLASTERROR(ERROR) << "Failed to open device.";
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return connection;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
241