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"
121675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch#include "base/threading/thread_restrictions.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_win.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "device/hid/hid_device_info.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/io_buffer.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_WIN)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // defined(OS_WIN)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Setup API is required to enumerate HID devices.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "setupapi.lib")
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#pragma comment(lib, "hid.lib")
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHIDClass[] = "HIDClass";
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::HidServiceWin() {
391675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  base::ThreadRestrictions::AssertIOAllowed();
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Enumerate();
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidServiceWin::~HidServiceWin() {}
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::Enumerate() {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOOL res;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HDEVINFO device_info_set;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVINFO_DATA devinfo_data;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DATA device_interface_data;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info_set = SetupDiGetClassDevs(
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &GUID_DEVINTERFACE_HID,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::set<std::string> connected_devices;
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (device_info_set != INVALID_HANDLE_VALUE) {
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (int device_index = 0;
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         SetupDiEnumDeviceInterfaces(device_info_set,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     NULL,
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     &GUID_DEVINTERFACE_HID,
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     device_index,
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     &device_interface_data);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         ++device_index) {
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DWORD required_size = 0;
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Determime the required size of detail struct.
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      SetupDiGetDeviceInterfaceDetailA(device_info_set,
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       &device_interface_data,
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       NULL,
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       0,
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       &required_size,
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       NULL);
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scoped_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A, base::FreeDeleter>
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          device_interface_detail_data(
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                  malloc(required_size)));
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_interface_detail_data->cbSize =
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Get the detailed data for this device.
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             &device_interface_data,
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             device_interface_detail_data.get(),
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             required_size,
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             NULL,
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             NULL);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!res)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Enumerate device info. Looking for Setup Class "HIDClass".
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for (DWORD i = 0;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          i++) {
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        char class_name[256] = {0};
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                &devinfo_data,
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                SPDRP_CLASS,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL,
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                (PBYTE) class_name,
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                sizeof(class_name) - 1,
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                NULL);
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (!res)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (memcmp(class_name, kHIDClass, sizeof(kHIDClass)) == 0) {
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          char driver_name[256] = {0};
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // Get bounded driver.
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          res = SetupDiGetDeviceRegistryPropertyA(device_info_set,
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  &devinfo_data,
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  SPDRP_DRIVER,
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  NULL,
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  (PBYTE) driver_name,
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  sizeof(driver_name) - 1,
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                  NULL);
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          if (res) {
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            // Found the driver.
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            break;
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!res)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      PlatformAddDevice(device_interface_detail_data->DevicePath);
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      connected_devices.insert(device_interface_detail_data->DevicePath);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Find disconnected devices.
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> disconnected_devices;
1391675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  for (DeviceMap::const_iterator it = devices().begin(); it != devices().end();
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++it) {
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!ContainsKey(connected_devices, it->first)) {
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      disconnected_devices.push_back(it->first);
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Remove disconnected devices.
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < disconnected_devices.size(); ++i) {
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformRemoveDevice(disconnected_devices[i]);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void HidServiceWin::CollectInfoFromButtonCaps(
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    PHIDP_PREPARSED_DATA preparsed_data,
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    HIDP_REPORT_TYPE report_type,
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    USHORT button_caps_length,
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    HidCollectionInfo* collection_info) {
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (button_caps_length > 0) {
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        new HIDP_BUTTON_CAPS[button_caps_length]);
16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (HidP_GetButtonCaps(report_type,
16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                           &button_caps[0],
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                           &button_caps_length,
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                           preparsed_data) == HIDP_STATUS_SUCCESS) {
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      for (size_t i = 0; i < button_caps_length; i++) {
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        int report_id = button_caps[i].ReportID;
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        if (report_id != 0) {
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          collection_info->report_ids.insert(report_id);
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        }
16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      }
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void HidServiceWin::CollectInfoFromValueCaps(
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    PHIDP_PREPARSED_DATA preparsed_data,
17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    HIDP_REPORT_TYPE report_type,
17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    USHORT value_caps_length,
17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    HidCollectionInfo* collection_info) {
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (value_caps_length > 0) {
18003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
18103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        new HIDP_VALUE_CAPS[value_caps_length]);
18203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (HidP_GetValueCaps(
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            report_type, &value_caps[0], &value_caps_length, preparsed_data) ==
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        HIDP_STATUS_SUCCESS) {
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      for (size_t i = 0; i < value_caps_length; i++) {
18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        int report_id = value_caps[i].ReportID;
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        if (report_id != 0) {
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          collection_info->report_ids.insert(report_id);
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        }
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      }
19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
19203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
19303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
19403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidDeviceInfo device_info;
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.device_id = device_path;
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try to open the device.
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedHandle device_handle(
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateFileA(device_path.c_str(),
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  GENERIC_WRITE | GENERIC_READ,
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                  FILE_SHARE_READ | FILE_SHARE_WRITE,
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  NULL,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  OPEN_EXISTING,
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  FILE_FLAG_OVERLAPPED,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  0));
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!device_handle.IsValid() &&
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::win::ScopedHandle device_handle(
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      CreateFileA(device_path.c_str(),
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GENERIC_READ,
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FILE_SHARE_READ,
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NULL,
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      OPEN_EXISTING,
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FILE_FLAG_OVERLAPPED,
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      0));
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!device_handle.IsValid())
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return;
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get VID/PID pair.
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HIDD_ATTRIBUTES attrib = {0};
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  attrib.Size = sizeof(HIDD_ATTRIBUTES);
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!HidD_GetAttributes(device_handle.Get(), &attrib))
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.vendor_id = attrib.VendorID;
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_info.product_id = attrib.ProductID;
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ULONG i = 32;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      HidD_SetNumInputBuffers(device_handle.Get(), i);
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      i <<= 1);
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get usage and usage page (optional).
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PHIDP_PREPARSED_DATA preparsed_data;
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      preparsed_data) {
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    HIDP_CAPS capabilities = {0};
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      device_info.max_input_report_size = capabilities.InputReportByteLength;
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      device_info.max_output_report_size = capabilities.OutputReportByteLength;
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      device_info.max_feature_report_size =
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          capabilities.FeatureReportByteLength;
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      HidCollectionInfo collection_info;
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      collection_info.usage = HidUsageAndPage(
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          capabilities.Usage,
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          static_cast<HidUsageAndPage::Page>(capabilities.UsagePage));
25103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromButtonCaps(preparsed_data,
25203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                HidP_Input,
25303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                capabilities.NumberInputButtonCaps,
25403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                &collection_info);
25503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromButtonCaps(preparsed_data,
25603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                HidP_Output,
25703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                capabilities.NumberOutputButtonCaps,
25803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                &collection_info);
25903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromButtonCaps(preparsed_data,
26003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                HidP_Feature,
26103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                capabilities.NumberFeatureButtonCaps,
26203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                &collection_info);
26303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromValueCaps(preparsed_data,
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               HidP_Input,
26503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               capabilities.NumberInputValueCaps,
26603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               &collection_info);
26703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromValueCaps(preparsed_data,
26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               HidP_Output,
26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               capabilities.NumberOutputValueCaps,
27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               &collection_info);
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      CollectInfoFromValueCaps(preparsed_data,
27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               HidP_Feature,
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               capabilities.NumberFeatureValueCaps,
27403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               &collection_info);
27503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (!collection_info.report_ids.empty()) {
27603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        device_info.has_report_id = true;
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      device_info.collections.push_back(collection_info);
279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Whether or not the device includes report IDs in its reports the size
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // of the report ID is included in the value provided by Windows. This
28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // appears contrary to the MSDN documentation.
28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (device_info.max_input_report_size > 0) {
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_info.max_input_report_size--;
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (device_info.max_output_report_size > 0) {
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_info.max_output_report_size--;
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (device_info.max_feature_report_size > 0) {
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_info.max_feature_report_size--;
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
292010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    HidD_FreePreparsedData(preparsed_data);
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddDevice(device_info);
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidServiceWin::PlatformRemoveDevice(const std::string& device_path) {
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RemoveDevice(device_path);
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidServiceWin::GetDevices(std::vector<HidDeviceInfo>* devices) {
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Enumerate();
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HidService::GetDevices(devices);
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_refptr<HidConnection> HidServiceWin::Connect(
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const HidDeviceId& device_id) {
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HidDeviceInfo device_info;
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!GetDeviceInfo(device_id, &device_info))
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<HidConnectionWin> connection(new HidConnectionWin(device_info));
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!connection->available()) {
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(ERROR) << "Failed to open device.";
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return connection;
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
321