summaryrefslogtreecommitdiffstats
path: root/device/serial
diff options
context:
space:
mode:
Diffstat (limited to 'device/serial')
-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
6 files changed, 123 insertions, 3 deletions
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 623985f..98635cb 100644
--- a/device/serial/serial.gyp
+++ b/device/serial/serial.gyp
@@ -51,6 +51,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);
};