hid_service_win.cc revision 010d83a9304c5a91596085d917d248abff47903a
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)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/sys_string_conversions.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_win.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "device/hid/hid_device_info.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/io_buffer.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_WIN)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidclass.h>
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidsdi.h>
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidpi.h>
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h"
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(OS_WIN)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Setup API is required to enumerate HID devices.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "setupapi.lib")
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "hid.lib")
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHIDClass[] = "HIDClass";
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::HidServiceWin() {
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Enumerate();
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::~HidServiceWin() {}
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::Enumerate() {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOOL res;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HDEVINFO device_info_set;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVINFO_DATA devinfo_data;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DATA device_interface_data;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info_set = SetupDiGetClassDevs(
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &GUID_DEVINTERFACE_HID,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_info_set == INVALID_HANDLE_VALUE)
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int device_index = 0;
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       SetupDiEnumDeviceInterfaces(device_info_set,
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   NULL,
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   &GUID_DEVINTERFACE_HID,
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   device_index,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   &device_interface_data);
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++device_index) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DWORD required_size = 0;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determime the required size of detail struct.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetupDiGetDeviceInterfaceDetailA(device_info_set,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &device_interface_data,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     0,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     &required_size,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL);
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_interface_detail_data(
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                malloc(required_size)));
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device_interface_detail_data->cbSize =
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Get the detailed data for this device.
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           &device_interface_data,
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           device_interface_detail_data.get(),
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           required_size,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           NULL);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Enumerate device info. Looking for Setup Class "HIDClass".
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (DWORD i = 0;
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        i++) {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      char class_name[256] = {0};
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              &devinfo_data,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              SPDRP_CLASS,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              (PBYTE) class_name,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              sizeof(class_name) - 1,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              NULL);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!res)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        char driver_name[256] = {0};
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Get bounded driver.
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                &devinfo_data,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                SPDRP_DRIVER,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                (PBYTE) driver_name,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                sizeof(driver_name) - 1,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (res) {
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Found the driver.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!res)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PlatformAddDevice(device_interface_detail_data->DevicePath);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidDeviceInfo device_info;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.device_id = device_path;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try to open the device.
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedHandle device_handle(
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateFileA(device_path.c_str(),
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0,
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                  FILE_SHARE_READ,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  NULL,
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  OPEN_EXISTING,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FILE_FLAG_OVERLAPPED,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0));
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!device_handle.IsValid())
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get VID/PID pair.
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HIDD_ATTRIBUTES attrib = {0};
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  attrib.Size = sizeof(HIDD_ATTRIBUTES);
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!HidD_GetAttributes(device_handle.Get(), &attrib))
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.vendor_id = attrib.VendorID;
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.product_id = attrib.ProductID;
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ULONG i = 32;
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      HidD_SetNumInputBuffers(device_handle.Get(), i);
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      i <<= 1);
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get usage and usage page (optional).
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PHIDP_PREPARSED_DATA preparsed_data;
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      preparsed_data) {
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    HIDP_CAPS capabilities;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.input_report_size = capabilities.InputReportByteLength;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.output_report_size = capabilities.OutputReportByteLength;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      device_info.feature_report_size = capabilities.FeatureReportByteLength;
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      device_info.usages.push_back(HidUsageAndPage(
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        capabilities.Usage,
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        static_cast<HidUsageAndPage::Page>(capabilities.UsagePage)));
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Detect if the device supports report ids.
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (capabilities.NumberInputValueCaps > 0) {
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      USHORT value_caps_length = capabilities.NumberInputValueCaps;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            preparsed_data) == HIDP_STATUS_SUCCESS) {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        device_info.has_report_id = (value_caps[0].ReportID != 0);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!device_info.has_report_id && capabilities.NumberInputButtonCaps > 0)
196c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    {
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
198c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new HIDP_BUTTON_CAPS[capabilities.NumberInputButtonCaps]);
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      USHORT button_caps_length = capabilities.NumberInputButtonCaps;
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (HidP_GetButtonCaps(HidP_Input,
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             &button_caps[0],
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             &button_caps_length,
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                             preparsed_data) == HIDP_STATUS_SUCCESS) {
204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        device_info.has_report_id = (button_caps[0].ReportID != 0);
205c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      }
206c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    HidD_FreePreparsedData(preparsed_data);
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddDevice(device_info);
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RemoveDevice(device_path);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Enumerate();
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::GetDevices(devices);
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_refptr<HidConnection> HidServiceWin::Connect(
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const HidDeviceId& device_id) {
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HidDeviceInfo device_info;
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!GetDeviceInfo(device_id, &device_info))
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!connection->available()) {
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG_GETLASTERROR(ERROR) << "Failed to open device.";
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return connection;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
237