summaryrefslogtreecommitdiffstats
path: root/device/hid
diff options
context:
space:
mode:
Diffstat (limited to 'device/hid')
-rw-r--r--device/hid/hid_service.cc2
-rw-r--r--device/hid/hid_service_win.cc72
-rw-r--r--device/hid/hid_service_win.h15
3 files changed, 74 insertions, 15 deletions
diff --git a/device/hid/hid_service.cc b/device/hid/hid_service.cc
index c0b176e..8f502df 100644
--- a/device/hid/hid_service.cc
+++ b/device/hid/hid_service.cc
@@ -41,7 +41,7 @@ HidService* HidService::GetInstance(
#elif defined(OS_MACOSX)
g_service = new HidServiceMac(file_task_runner);
#elif defined(OS_WIN)
- g_service = new HidServiceWin();
+ g_service = new HidServiceWin(file_task_runner);
#endif
if (g_service != nullptr) {
base::AtExitManager::RegisterTask(base::Bind(
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc
index 234d37b..3ab8286 100644
--- a/device/hid/hid_service_win.cc
+++ b/device/hid/hid_service_win.cc
@@ -28,7 +28,18 @@
namespace device {
-HidServiceWin::HidServiceWin() : device_observer_(this) {
+namespace {
+
+void Noop() {
+ // This function does nothing.
+}
+}
+
+HidServiceWin::HidServiceWin(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
+ : device_observer_(this),
+ file_task_runner_(file_task_runner),
+ weak_factory_(this) {
task_runner_ = base::ThreadTaskRunnerHandle::Get();
DCHECK(task_runner_.get());
DeviceMonitorWin* device_monitor =
@@ -36,7 +47,9 @@ HidServiceWin::HidServiceWin() : device_observer_(this) {
if (device_monitor) {
device_observer_.Add(device_monitor);
}
- DoInitialEnumeration();
+ file_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::EnumerateOnFileThread,
+ weak_factory_.GetWeakPtr(), task_runner_));
}
void HidServiceWin::Connect(const HidDeviceId& device_id,
@@ -64,7 +77,10 @@ void HidServiceWin::Connect(const HidDeviceId& device_id,
HidServiceWin::~HidServiceWin() {
}
-void HidServiceWin::DoInitialEnumeration() {
+// static
+void HidServiceWin::EnumerateOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
HDEVINFO device_info_set =
SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
@@ -103,11 +119,13 @@ void HidServiceWin::DoInitialEnumeration() {
std::string device_path(
base::SysWideToUTF8(device_interface_detail_data->DevicePath));
DCHECK(base::IsStringASCII(device_path));
- OnDeviceAdded(base::StringToLowerASCII(device_path));
+ AddDeviceOnFileThread(service, task_runner,
+ base::StringToLowerASCII(device_path));
}
}
- FirstEnumerationComplete();
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::FirstEnumerationComplete, service));
}
// static
@@ -155,7 +173,11 @@ void HidServiceWin::CollectInfoFromValueCaps(
}
}
-void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
+// static
+void HidServiceWin::AddDeviceOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const std::string& device_path) {
base::win::ScopedHandle device_handle(OpenDevice(device_path));
if (!device_handle.IsValid()) {
return;
@@ -220,25 +242,53 @@ void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
capabilities.NumberFeatureValueCaps,
&collection_info);
+ // 1023 characters plus NULL terminator is more than enough for a USB string
+ // descriptor which is limited to 126 characters.
+ wchar_t buffer[1024];
+ std::string product_name;
+ if (HidD_GetProductString(device_handle.Get(), &buffer[0], sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ product_name = base::SysWideToUTF8(buffer);
+ }
+ std::string serial_number;
+ if (HidD_GetSerialNumberString(device_handle.Get(), &buffer[0],
+ sizeof(buffer))) {
+ // NULL termination guaranteed by the API.
+ serial_number = base::SysWideToUTF8(buffer);
+ }
+
// This populates the HidDeviceInfo instance without a raw report descriptor.
// The descriptor is unavailable on Windows because HID devices are exposed to
// user-space as individual top-level collections.
scoped_refptr<HidDeviceInfo> device_info(new HidDeviceInfo(
- device_path, attrib.VendorID, attrib.ProductID,
- "", // TODO(reillyg): Get product name from Windows.
- "", // TODO(reillyg): Get serial number from Windows.
+ device_path, attrib.VendorID, attrib.ProductID, product_name,
+ serial_number,
kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335
collection_info, max_input_report_size, max_output_report_size,
max_feature_report_size));
HidD_FreePreparsedData(preparsed_data);
- AddDevice(device_info);
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::AddDevice, service, device_info));
+}
+
+void HidServiceWin::OnDeviceAdded(const std::string& device_path) {
+ file_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&HidServiceWin::AddDeviceOnFileThread,
+ weak_factory_.GetWeakPtr(), task_runner_, device_path));
}
void HidServiceWin::OnDeviceRemoved(const std::string& device_path) {
- RemoveDevice(device_path);
+ // Execute a no-op closure on the file task runner to synchronize with any
+ // devices that are still being enumerated.
+ file_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&Noop),
+ base::Bind(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
+ device_path));
}
+// static
base::win::ScopedHandle HidServiceWin::OpenDevice(
const std::string& device_path) {
base::win::ScopedHandle file(
diff --git a/device/hid/hid_service_win.h b/device/hid/hid_service_win.h
index 902d431..1704ac7 100644
--- a/device/hid/hid_service_win.h
+++ b/device/hid/hid_service_win.h
@@ -14,6 +14,7 @@ extern "C" {
}
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/win/scoped_handle.h"
#include "device/core/device_monitor_win.h"
@@ -30,7 +31,7 @@ namespace device {
class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
public:
- HidServiceWin();
+ HidServiceWin(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
virtual void Connect(const HidDeviceId& device_id,
const ConnectCallback& callback) override;
@@ -38,7 +39,9 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
private:
virtual ~HidServiceWin();
- void DoInitialEnumeration();
+ static void EnumerateOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
static void CollectInfoFromButtonCaps(PHIDP_PREPARSED_DATA preparsed_data,
HIDP_REPORT_TYPE report_type,
USHORT button_caps_length,
@@ -47,16 +50,22 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
HIDP_REPORT_TYPE report_type,
USHORT value_caps_length,
HidCollectionInfo* collection_info);
+ static void AddDeviceOnFileThread(
+ base::WeakPtr<HidServiceWin> service,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const std::string& device_path);
// DeviceMonitorWin::Observer implementation:
void OnDeviceAdded(const std::string& device_path) override;
void OnDeviceRemoved(const std::string& device_path) override;
// Tries to open the device read-write and falls back to read-only.
- base::win::ScopedHandle OpenDevice(const std::string& device_path);
+ static base::win::ScopedHandle OpenDevice(const std::string& device_path);
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
+ base::WeakPtrFactory<HidServiceWin> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(HidServiceWin);
};