diff options
Diffstat (limited to 'device/serial')
-rw-r--r-- | device/serial/BUILD.gn | 1 | ||||
-rw-r--r-- | device/serial/serial.gyp | 1 | ||||
-rw-r--r-- | device/serial/serial_io_handler.cc | 1 | ||||
-rw-r--r-- | device/serial/serial_io_handler.h | 12 | ||||
-rw-r--r-- | device/serial/serial_io_handler_win.cc | 103 | ||||
-rw-r--r-- | device/serial/serial_io_handler_win.h | 8 |
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); }; |