summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
Diffstat (limited to 'device')
-rw-r--r--device/core/BUILD.gn2
-rw-r--r--device/core/core.gyp2
-rw-r--r--device/core/device_info_query_win.cc66
-rw-r--r--device/core/device_info_query_win.h49
-rw-r--r--device/serial/BUILD.gn1
-rw-r--r--device/serial/serial.gyp1
-rw-r--r--device/serial/serial_io_handler.cc1
-rw-r--r--device/serial/serial_io_handler.h12
-rw-r--r--device/serial/serial_io_handler_win.cc103
-rw-r--r--device/serial/serial_io_handler_win.h8
-rw-r--r--device/usb/usb.gyp1
-rw-r--r--device/usb/usb_service_impl.cc80
12 files changed, 252 insertions, 74 deletions
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn
index e85acb6..6f55190 100644
--- a/device/core/BUILD.gn
+++ b/device/core/BUILD.gn
@@ -8,6 +8,8 @@ component("core") {
sources = [
"device_client.cc",
"device_client.h",
+ "device_info_query_win.cc",
+ "device_info_query_win.h",
"device_monitor_win.cc",
"device_monitor_win.h",
]
diff --git a/device/core/core.gyp b/device/core/core.gyp
index d27073d..6002a5f 100644
--- a/device/core/core.gyp
+++ b/device/core/core.gyp
@@ -19,6 +19,8 @@
'sources': [
'device_client.cc',
'device_client.h',
+ 'device_info_query_win.cc',
+ 'device_info_query_win.h',
'device_monitor_win.cc',
'device_monitor_win.h',
],
diff --git a/device/core/device_info_query_win.cc b/device/core/device_info_query_win.cc
new file mode 100644
index 0000000..4d62b32
--- /dev/null
+++ b/device/core/device_info_query_win.cc
@@ -0,0 +1,66 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/core/device_info_query_win.h"
+
+#include <string.h>
+
+#include "base/strings/string_util.h"
+
+namespace device {
+
+DeviceInfoQueryWin::DeviceInfoQueryWin()
+ : device_info_list_(SetupDiCreateDeviceInfoList(nullptr, nullptr)) {
+ memset(&device_info_data_, 0, sizeof(device_info_data_));
+}
+
+DeviceInfoQueryWin::~DeviceInfoQueryWin() {
+ if (device_info_list_valid()) {
+ // Release |device_info_data_| only when it is valid.
+ if (device_info_data_.cbSize != 0)
+ SetupDiDeleteDeviceInfo(device_info_list_, &device_info_data_);
+ SetupDiDestroyDeviceInfoList(device_info_list_);
+ }
+}
+
+bool DeviceInfoQueryWin::AddDevice(const char* device_path) {
+ return SetupDiOpenDeviceInterfaceA(device_info_list_, device_path, 0,
+ nullptr) != FALSE;
+}
+
+bool DeviceInfoQueryWin::GetDeviceInfo() {
+ DCHECK_EQ(0U, device_info_data_.cbSize);
+ device_info_data_.cbSize = sizeof(device_info_data_);
+ if (!SetupDiEnumDeviceInfo(device_info_list_, 0, &device_info_data_)) {
+ // Clear cbSize to maintain the invariant.
+ device_info_data_.cbSize = 0;
+ return false;
+ }
+ return true;
+}
+
+bool DeviceInfoQueryWin::GetDeviceStringProperty(DWORD property,
+ std::string* property_buffer) {
+ DWORD property_reg_data_type;
+ const size_t property_buffer_length = 512;
+ if (!SetupDiGetDeviceRegistryPropertyA(
+ device_info_list_, &device_info_data_, property,
+ &property_reg_data_type,
+ reinterpret_cast<PBYTE>(
+ base::WriteInto(property_buffer, property_buffer_length)),
+ static_cast<DWORD>(property_buffer_length), nullptr))
+ return false;
+
+ if (property_reg_data_type != REG_SZ)
+ return false;
+
+ // Shrink |property_buffer| down to its correct size.
+ size_t eos = property_buffer->find('\0');
+ if (eos != std::string::npos)
+ property_buffer->resize(eos);
+
+ return true;
+}
+
+} // namespace device
diff --git a/device/core/device_info_query_win.h b/device/core/device_info_query_win.h
new file mode 100644
index 0000000..2e399e4
--- /dev/null
+++ b/device/core/device_info_query_win.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_
+#define DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_
+
+#include <windows.h>
+#include <setupapi.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "device/core/device_core_export.h"
+
+namespace device {
+
+// Wraps HDEVINFO and SP_DEVINFO_DATA into a class that can automatically
+// release them. Provides interfaces that can add a device using its
+// device path, get device info and get device string property.
+class DEVICE_CORE_EXPORT DeviceInfoQueryWin {
+ public:
+ DeviceInfoQueryWin();
+ ~DeviceInfoQueryWin();
+
+ // Add a device to |device_info_list_| using its |device_path| so that
+ // its device info can be retrieved.
+ bool AddDevice(const char* device_path);
+ // Get the device info and store it into |device_info_data_|, this function
+ // should be called at most once.
+ bool GetDeviceInfo();
+ // Get device string property and store it into |property_buffer|.
+ bool GetDeviceStringProperty(DWORD property, std::string* property_buffer);
+
+ bool device_info_list_valid() {
+ return device_info_list_ != INVALID_HANDLE_VALUE;
+ }
+
+ private:
+ HDEVINFO device_info_list_ = INVALID_HANDLE_VALUE;
+ // When device_info_data_.cbSize != 0, |device_info_data_| is valid.
+ SP_DEVINFO_DATA device_info_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceInfoQueryWin);
+};
+
+} // namespace device
+
+#endif // DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_
diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn
index 1ee6c5f..f66cedf 100644
--- a/device/serial/BUILD.gn
+++ b/device/serial/BUILD.gn
@@ -45,6 +45,7 @@ static_library("serial") {
public_deps = [
":serial_mojo",
"//base",
+ "//device/core",
]
deps = [
"//mojo/public/cpp/system",
diff --git a/device/serial/serial.gyp b/device/serial/serial.gyp
index de18133..0e56df1 100644
--- a/device/serial/serial.gyp
+++ b/device/serial/serial.gyp
@@ -50,6 +50,7 @@
'../../net/net.gyp:net',
'../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../../third_party/re2/re2.gyp:re2',
+ '../core/core.gyp:device_core',
],
'export_dependent_settings': [
'device_serial_mojo',
diff --git a/device/serial/serial_io_handler.cc b/device/serial/serial_io_handler.cc
index 452f91c..1cfb1cd 100644
--- a/device/serial/serial_io_handler.cc
+++ b/device/serial/serial_io_handler.cc
@@ -44,6 +44,7 @@ void SerialIoHandler::Open(const std::string& port,
DCHECK(file_thread_task_runner_.get());
DCHECK(ui_thread_task_runner_.get());
MergeConnectionOptions(options);
+ port_ = port;
#if defined(OS_CHROMEOS)
chromeos::PermissionBrokerClient* client =
diff --git a/device/serial/serial_io_handler.h b/device/serial/serial_io_handler.h
index 81d7028..63e6c90 100644
--- a/device/serial/serial_io_handler.h
+++ b/device/serial/serial_io_handler.h
@@ -190,6 +190,16 @@ class SerialIoHandler : public base::NonThreadSafe,
// Possibly fixes up a serial port path name in a platform-specific manner.
static std::string MaybeFixUpPortName(const std::string& port_name);
+ base::SingleThreadTaskRunner* file_thread_task_runner() const {
+ return file_thread_task_runner_.get();
+ }
+
+ base::SingleThreadTaskRunner* ui_thread_task_runner() const {
+ return ui_thread_task_runner_.get();
+ }
+
+ const std::string& port() const { return port_; }
+
private:
friend class base::RefCounted<SerialIoHandler>;
@@ -229,6 +239,8 @@ class SerialIoHandler : public base::NonThreadSafe,
// On Chrome OS, PermissionBrokerClient should be called on the UI thread.
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
+ std::string port_;
+
DISALLOW_COPY_AND_ASSIGN(SerialIoHandler);
};
diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc
index 56fe93b..2a1e752 100644
--- a/device/serial/serial_io_handler_win.cc
+++ b/device/serial/serial_io_handler_win.cc
@@ -2,9 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "device/serial/serial_io_handler_win.h"
+
#include <windows.h>
+#include <setupapi.h>
-#include "device/serial/serial_io_handler_win.h"
+#include "base/bind.h"
+#include "base/scoped_observer.h"
+#include "base/threading/thread_checker.h"
+#include "device/core/device_info_query_win.h"
+#include "device/core/device_monitor_win.h"
+#include "third_party/re2/re2/re2.h"
namespace device {
@@ -130,6 +138,12 @@ serial::StopBits StopBitsConstantToEnum(int stop_bits) {
}
}
+// Searches for the COM port in the device's friendly name, assigns its value to
+// com_port, and returns whether the operation was successful.
+bool GetCOMPort(const std::string friendly_name, std::string* com_port) {
+ return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port);
+}
+
} // namespace
// static
@@ -139,6 +153,81 @@ scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner);
}
+class SerialIoHandlerWin::UiThreadHelper : public DeviceMonitorWin::Observer {
+ public:
+ UiThreadHelper(
+ base::WeakPtr<SerialIoHandlerWin> io_handler,
+ scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner)
+ : device_observer_(this),
+ io_handler_(io_handler),
+ io_thread_task_runner_(io_thread_task_runner) {}
+
+ ~UiThreadHelper() { DCHECK(thread_checker_.CalledOnValidThread()); }
+
+ static void Start(UiThreadHelper* self) {
+ self->thread_checker_.DetachFromThread();
+ DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
+ if (device_monitor)
+ self->device_observer_.Add(device_monitor);
+ }
+
+ private:
+ // DeviceMonitorWin::Observer
+ void OnDeviceRemoved(const GUID& class_guid,
+ const std::string& device_path) override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ io_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&SerialIoHandlerWin::OnDeviceRemoved, io_handler_,
+ device_path));
+ }
+
+ base::ThreadChecker thread_checker_;
+ ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
+
+ // This weak pointer is only valid when checked on this task runner.
+ base::WeakPtr<SerialIoHandlerWin> io_handler_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(UiThreadHelper);
+};
+
+void SerialIoHandlerWin::OnDeviceRemoved(const std::string& device_path) {
+ DCHECK(CalledOnValidThread());
+
+ DeviceInfoQueryWin device_info_query;
+ if (!device_info_query.device_info_list_valid()) {
+ DVPLOG(1) << "Failed to create a device information set";
+ return;
+ }
+
+ // This will add the device so we can query driver info.
+ if (!device_info_query.AddDevice(device_path.c_str())) {
+ DVPLOG(1) << "Failed to get device interface data for " << device_path;
+ return;
+ }
+
+ if (!device_info_query.GetDeviceInfo()) {
+ DVPLOG(1) << "Failed to get device info for " << device_path;
+ return;
+ }
+
+ std::string friendly_name;
+ if (!device_info_query.GetDeviceStringProperty(SPDRP_FRIENDLYNAME,
+ &friendly_name)) {
+ DVPLOG(1) << "Failed to get device service property";
+ return;
+ }
+
+ std::string com_port;
+ if (!GetCOMPort(friendly_name, &com_port)) {
+ DVPLOG(1) << "Failed to get port name from \"" << friendly_name << "\".";
+ return;
+ }
+
+ if (port() == com_port)
+ CancelRead(serial::RECEIVE_ERROR_DISCONNECTED);
+}
+
bool SerialIoHandlerWin::PostOpen() {
DCHECK(!comm_context_);
DCHECK(!read_context_);
@@ -159,6 +248,13 @@ bool SerialIoHandlerWin::PostOpen() {
write_context_->handler = this;
memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped));
+ scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner =
+ base::ThreadTaskRunnerHandle::Get();
+ helper_ =
+ new UiThreadHelper(weak_factory_.GetWeakPtr(), io_thread_task_runner);
+ ui_thread_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&UiThreadHelper::Start, helper_));
+
// A ReadIntervalTimeout of MAXDWORD will cause async reads to complete
// immediately with any data that's available, even if there is none.
// This is OK because we never issue a read request until WaitCommEvent
@@ -271,10 +367,11 @@ SerialIoHandlerWin::SerialIoHandlerWin(
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
: SerialIoHandler(file_thread_task_runner, ui_thread_task_runner),
event_mask_(0),
- is_comm_pending_(false) {
-}
+ is_comm_pending_(false),
+ weak_factory_(this) {}
SerialIoHandlerWin::~SerialIoHandlerWin() {
+ ui_thread_task_runner()->DeleteSoon(FROM_HERE, helper_);
}
void SerialIoHandlerWin::OnIOCompleted(
diff --git a/device/serial/serial_io_handler_win.h b/device/serial/serial_io_handler_win.h
index 7f438b5..831eab6 100644
--- a/device/serial/serial_io_handler_win.h
+++ b/device/serial/serial_io_handler_win.h
@@ -32,6 +32,7 @@ class SerialIoHandlerWin : public SerialIoHandler,
bool PostOpen() override;
private:
+ class UiThreadHelper;
friend class SerialIoHandler;
explicit SerialIoHandlerWin(
@@ -44,6 +45,8 @@ class SerialIoHandlerWin : public SerialIoHandler,
DWORD bytes_transfered,
DWORD error) override;
+ void OnDeviceRemoved(const std::string& device_path);
+
// Context used for asynchronous WaitCommEvent calls.
scoped_ptr<base::MessageLoopForIO::IOContext> comm_context_;
@@ -61,6 +64,11 @@ class SerialIoHandlerWin : public SerialIoHandler,
// after a corresponding WaitCommEvent has completed.
bool is_comm_pending_;
+ // The helper lives on the UI thread and holds a weak reference back to the
+ // handler that owns it.
+ UiThreadHelper* helper_ = nullptr;
+ base::WeakPtrFactory<SerialIoHandlerWin> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(SerialIoHandlerWin);
};
diff --git a/device/usb/usb.gyp b/device/usb/usb.gyp
index c7bf776..453ba1a 100644
--- a/device/usb/usb.gyp
+++ b/device/usb/usb.gyp
@@ -14,6 +14,7 @@
'../../components/components.gyp:device_event_log_component',
'../../net/net.gyp:net',
'../../third_party/libusb/libusb.gyp:libusb',
+ '../core/core.gyp:device_core',
],
'include_dirs': [
'../..',
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index dd5cc90..9770007 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -27,6 +27,7 @@
#include <usbiodef.h>
#include "base/strings/string_util.h"
+#include "device/core/device_info_query_win.h"
#endif // OS_WIN
#if defined(USE_UDEV)
@@ -53,96 +54,33 @@ const int kControlTransferTimeout = 60000; // 1 minute
#if defined(OS_WIN)
-// Wrapper around a HDEVINFO that automatically destroys it.
-class ScopedDeviceInfoList {
- public:
- explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {}
-
- ~ScopedDeviceInfoList() {
- if (valid()) {
- SetupDiDestroyDeviceInfoList(handle_);
- }
- }
-
- bool valid() { return handle_ != INVALID_HANDLE_VALUE; }
-
- HDEVINFO get() { return handle_; }
-
- private:
- HDEVINFO handle_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList);
-};
-
-// Wrapper around an SP_DEVINFO_DATA that initializes it properly and
-// automatically deletes it.
-class ScopedDeviceInfo {
- public:
- ScopedDeviceInfo() {
- memset(&dev_info_data_, 0, sizeof(dev_info_data_));
- dev_info_data_.cbSize = sizeof(dev_info_data_);
- }
-
- ~ScopedDeviceInfo() {
- if (dev_info_set_ != INVALID_HANDLE_VALUE) {
- SetupDiDeleteDeviceInfo(dev_info_set_, &dev_info_data_);
- }
- }
-
- // Once the SP_DEVINFO_DATA has been populated it must be freed using the
- // HDEVINFO it was created from.
- void set_valid(HDEVINFO dev_info_set) {
- DCHECK(dev_info_set_ == INVALID_HANDLE_VALUE);
- DCHECK(dev_info_set != INVALID_HANDLE_VALUE);
- dev_info_set_ = dev_info_set;
- }
-
- PSP_DEVINFO_DATA get() { return &dev_info_data_; }
-
- private:
- HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE;
- SP_DEVINFO_DATA dev_info_data_;
-};
-
bool IsWinUsbInterface(const std::string& device_path) {
- ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL));
- if (!dev_info_list.valid()) {
+ DeviceInfoQueryWin device_info_query;
+ if (!device_info_query.device_info_list_valid()) {
USB_PLOG(ERROR) << "Failed to create a device information set";
return false;
}
- // This will add the device to |dev_info_list| so we can query driver info.
- if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0,
- NULL)) {
+ // This will add the device so we can query driver info.
+ if (!device_info_query.AddDevice(device_path.c_str())) {
USB_PLOG(ERROR) << "Failed to get device interface data for "
<< device_path;
return false;
}
- ScopedDeviceInfo dev_info;
- if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) {
+ if (!device_info_query.GetDeviceInfo()) {
USB_PLOG(ERROR) << "Failed to get device info for " << device_path;
return false;
}
- dev_info.set_valid(dev_info_list.get());
- DWORD reg_data_type;
- BYTE buffer[256];
- if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(),
- SPDRP_SERVICE, &reg_data_type,
- &buffer[0], sizeof buffer, NULL)) {
+ std::string buffer;
+ if (!device_info_query.GetDeviceStringProperty(SPDRP_SERVICE, &buffer)) {
USB_PLOG(ERROR) << "Failed to get device service property";
return false;
}
- if (reg_data_type != REG_SZ) {
- USB_LOG(ERROR) << "Unexpected data type for driver service: "
- << reg_data_type;
- return false;
- }
USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << ".";
- if (base::StartsWith(reinterpret_cast<const char*>(buffer), "WinUSB",
- base::CompareCase::INSENSITIVE_ASCII))
+ if (base::StartsWith(buffer, "WinUSB", base::CompareCase::INSENSITIVE_ASCII))
return true;
return false;
}