hid_service_win.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 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)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/files/file.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/sys_string_conversions.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_win.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "device/hid/hid_device_info.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/io_buffer.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_WIN)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidclass.h>
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidsdi.h>
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidpi.h>
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h"
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(OS_WIN)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Setup API is required to enumerate HID devices.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "setupapi.lib")
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "hid.lib")
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHIDClass[] = "HIDClass";
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::HidServiceWin() {
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Enumerate();
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::~HidServiceWin() {}
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::Enumerate() {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOOL res;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HDEVINFO device_info_set;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVINFO_DATA devinfo_data;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DATA device_interface_data;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info_set = SetupDiGetClassDevs(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &GUID_DEVINTERFACE_HID,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_info_set == INVALID_HANDLE_VALUE)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int device_index = 0;
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       SetupDiEnumDeviceInterfaces(device_info_set,
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   NULL,
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   &GUID_DEVINTERFACE_HID,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   device_index,
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   &device_interface_data);
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++device_index) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD required_size = 0;
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determime the required size of detail struct.
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetupDiGetDeviceInterfaceDetailA(device_info_set,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &device_interface_data,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     0,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &required_size,
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL);
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_interface_detail_data(
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                malloc(required_size)));
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_interface_detail_data->cbSize =
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Get the detailed data for this device.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           &device_interface_data,
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           device_interface_detail_data.get(),
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           required_size,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Enumerate device info. Looking for Setup Class "HIDClass".
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (DWORD i = 0;
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        i++) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      char class_name[256] = {0};
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              &devinfo_data,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              SPDRP_CLASS,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              (PBYTE) class_name,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              sizeof(class_name) - 1,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL);
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!res)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        char driver_name[256] = {0};
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Get bounded driver.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                &devinfo_data,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                SPDRP_DRIVER,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                (PBYTE) driver_name,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                sizeof(driver_name) - 1,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (res) {
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Found the driver.
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PlatformAddDevice(device_interface_detail_data->DevicePath);
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidDeviceInfo device_info;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.device_id = device_path;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try to open the device.
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedHandle device_handle(
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateFileA(device_path.c_str(),
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  GENERIC_WRITE | GENERIC_READ,
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  FILE_SHARE_READ | FILE_SHARE_WRITE,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  NULL,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  OPEN_EXISTING,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FILE_FLAG_OVERLAPPED,
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0));
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!device_handle.IsValid() &&
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::win::ScopedHandle device_handle(
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      CreateFileA(device_path.c_str(),
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GENERIC_READ,
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FILE_SHARE_READ,
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NULL,
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      OPEN_EXISTING,
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FILE_FLAG_OVERLAPPED,
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      0));
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!device_handle.IsValid())
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return;
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get VID/PID pair.
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HIDD_ATTRIBUTES attrib = {0};
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  attrib.Size = sizeof(HIDD_ATTRIBUTES);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!HidD_GetAttributes(device_handle.Get(), &attrib))
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.vendor_id = attrib.VendorID;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.product_id = attrib.ProductID;
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ULONG i = 32;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      HidD_SetNumInputBuffers(device_handle.Get(), i);
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      i <<= 1);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get usage and usage page (optional).
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PHIDP_PREPARSED_DATA preparsed_data;
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      preparsed_data) {
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HIDP_CAPS capabilities;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.input_report_size = capabilities.InputReportByteLength;
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.output_report_size = capabilities.OutputReportByteLength;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.feature_report_size = capabilities.FeatureReportByteLength;
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      device_info.usages.push_back(HidUsageAndPage(
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        capabilities.Usage,
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        static_cast<HidUsageAndPage::Page>(capabilities.UsagePage)));
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Detect if the device supports report ids.
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (capabilities.NumberInputValueCaps > 0) {
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      USHORT value_caps_length = capabilities.NumberInputValueCaps;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            preparsed_data) == HIDP_STATUS_SUCCESS) {
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_info.has_report_id = (value_caps[0].ReportID != 0);
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
209c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!device_info.has_report_id && capabilities.NumberInputButtonCaps > 0)
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    {
211c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new HIDP_BUTTON_CAPS[capabilities.NumberInputButtonCaps]);
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      USHORT button_caps_length = capabilities.NumberInputButtonCaps;
214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (HidP_GetButtonCaps(HidP_Input,
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             &button_caps[0],
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             &button_caps_length,
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             preparsed_data) == HIDP_STATUS_SUCCESS) {
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        device_info.has_report_id = (button_caps[0].ReportID != 0);
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      }
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    HidD_FreePreparsedData(preparsed_data);
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddDevice(device_info);
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RemoveDevice(device_path);
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Enumerate();
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::GetDevices(devices);
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_refptr<HidConnection> HidServiceWin::Connect(
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const HidDeviceId& device_id) {
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HidDeviceInfo device_info;
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!GetDeviceInfo(device_id, &device_info))
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!connection->available()) {
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to open device.";
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return connection;
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
251