| Index: device/serial/serial_io_handler_win.cc
|
| diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc
|
| index 56fe93bbbf527589e0859171ce2627c3d5dffb61..2a1e752c9f7d7444be2e44ce84c86def4e9ba6b6 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(
|
|
|