diff options
Diffstat (limited to 'device/hid')
-rw-r--r-- | device/hid/hid_service.cc | 2 | ||||
-rw-r--r-- | device/hid/hid_service_win.cc | 72 | ||||
-rw-r--r-- | device/hid/hid_service_win.h | 15 |
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); }; |