Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/serial/serial_io_handler_win.h" | |
| 6 | |
| 5 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <setupapi.h> | |
| 6 | 9 |
| 7 #include "device/serial/serial_io_handler_win.h" | 10 #include "base/bind.h" |
| 11 #include "base/scoped_observer.h" | |
| 12 #include "base/threading/thread_checker.h" | |
| 13 #include "base/win/scoped_device_info_object.h" | |
| 14 #include "device/core/device_monitor_win.h" | |
| 15 #include "third_party/re2/re2/re2.h" | |
| 8 | 16 |
| 9 namespace device { | 17 namespace device { |
| 10 | 18 |
| 11 namespace { | 19 namespace { |
| 12 | 20 |
| 13 int BitrateToSpeedConstant(int bitrate) { | 21 int BitrateToSpeedConstant(int bitrate) { |
| 14 #define BITRATE_TO_SPEED_CASE(x) \ | 22 #define BITRATE_TO_SPEED_CASE(x) \ |
| 15 case x: \ | 23 case x: \ |
| 16 return CBR_##x; | 24 return CBR_##x; |
| 17 switch (bitrate) { | 25 switch (bitrate) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 serial::StopBits StopBitsConstantToEnum(int stop_bits) { | 131 serial::StopBits StopBitsConstantToEnum(int stop_bits) { |
| 124 switch (stop_bits) { | 132 switch (stop_bits) { |
| 125 case TWOSTOPBITS: | 133 case TWOSTOPBITS: |
| 126 return serial::STOP_BITS_TWO; | 134 return serial::STOP_BITS_TWO; |
| 127 case ONESTOPBIT: | 135 case ONESTOPBIT: |
| 128 default: | 136 default: |
| 129 return serial::STOP_BITS_ONE; | 137 return serial::STOP_BITS_ONE; |
| 130 } | 138 } |
| 131 } | 139 } |
| 132 | 140 |
| 141 // Searches for the COM port in the device's friendly name, assigns its value to | |
| 142 // com_port, and returns whether the operation was successful. | |
| 143 bool GetCOMPort(const std::string friendly_name, std::string* com_port) { | |
| 144 return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port); | |
| 145 } | |
| 146 | |
| 133 } // namespace | 147 } // namespace |
| 134 | 148 |
| 135 // static | 149 // static |
| 136 scoped_refptr<SerialIoHandler> SerialIoHandler::Create( | 150 scoped_refptr<SerialIoHandler> SerialIoHandler::Create( |
| 137 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, | 151 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| 138 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) { | 152 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) { |
| 139 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); | 153 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); |
| 140 } | 154 } |
| 141 | 155 |
| 156 class SerialIoHandlerWin::UiThreadHelper : public DeviceMonitorWin::Observer { | |
| 157 public: | |
| 158 UiThreadHelper( | |
| 159 base::WeakPtr<SerialIoHandlerWin> io_handler, | |
| 160 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) | |
| 161 : device_observer_(this), | |
| 162 io_handler_(io_handler), | |
| 163 io_thread_task_runner_(io_thread_task_runner) {} | |
| 164 | |
| 165 ~UiThreadHelper() { DCHECK(thread_checker_.CalledOnValidThread()); } | |
| 166 | |
| 167 static void Start(UiThreadHelper* self) { | |
| 168 self->thread_checker_.DetachFromThread(); | |
| 169 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces(); | |
| 170 if (device_monitor) { | |
|
Reilly Grant (use Gerrit)
2015/11/12 19:30:02
nit: no braces around single-line if
juncai
2015/11/12 23:21:39
Done.
| |
| 171 self->device_observer_.Add(device_monitor); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 private: | |
| 176 // DeviceMonitorWin::Observer | |
| 177 void OnDeviceRemoved(const GUID& class_guid, | |
| 178 const std::string& device_path) override { | |
| 179 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 180 io_thread_task_runner_->PostTask( | |
| 181 FROM_HERE, base::Bind(&SerialIoHandlerWin::OnDeviceRemoved, io_handler_, | |
| 182 device_path)); | |
| 183 } | |
| 184 | |
| 185 base::ThreadChecker thread_checker_; | |
| 186 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; | |
| 187 | |
| 188 // This weak pointer is only valid when checked on this task runner. | |
| 189 base::WeakPtr<SerialIoHandlerWin> io_handler_; | |
| 190 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_; | |
| 191 | |
| 192 DISALLOW_COPY_AND_ASSIGN(UiThreadHelper); | |
| 193 }; | |
| 194 | |
| 195 void SerialIoHandlerWin::OnDeviceRemoved(const std::string& device_path) { | |
| 196 DCHECK(CalledOnValidThread()); | |
| 197 base::win::ScopedDeviceInfoList dev_info_list( | |
| 198 SetupDiCreateDeviceInfoList(NULL, NULL)); | |
| 199 if (!dev_info_list.IsValid()) { | |
| 200 VPLOG(1) << "Failed to create a device information set"; | |
| 201 return; | |
| 202 } | |
| 203 | |
| 204 // This will add the device to |dev_info_list| so we can query driver info. | |
| 205 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.Get(), device_path.c_str(), 0, | |
| 206 NULL)) { | |
| 207 VPLOG(1) << "Failed to get device interface data for " << device_path; | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 base::win::ScopedDeviceInfo dev_info; | |
| 212 if (!SetupDiEnumDeviceInfo(dev_info_list.Get(), 0, dev_info.get())) { | |
| 213 VPLOG(1) << "Failed to get device info for " << device_path; | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 dev_info.set_valid(dev_info_list.Get()); | |
| 218 | |
| 219 BYTE friendly_name[512]; | |
| 220 if (!SetupDiGetDeviceRegistryPropertyA( | |
| 221 dev_info_list.Get(), dev_info.get(), SPDRP_FRIENDLYNAME, NULL, | |
| 222 friendly_name, sizeof(friendly_name), NULL)) { | |
| 223 VPLOG(1) << "Failed to get device service property"; | |
| 224 return; | |
| 225 } | |
| 226 | |
| 227 std::string port; | |
| 228 if (!GetCOMPort(reinterpret_cast<const char*>(friendly_name), &port)) | |
|
Reilly Grant (use Gerrit)
2015/11/12 19:30:02
VPLOG(1) << "Failed to get port name from \"" << f
juncai
2015/11/12 23:21:39
Done.
| |
| 229 return; | |
| 230 | |
| 231 if (port_ == port) | |
| 232 CancelRead(serial::RECEIVE_ERROR_DISCONNECTED); | |
| 233 } | |
| 234 | |
| 142 bool SerialIoHandlerWin::PostOpen() { | 235 bool SerialIoHandlerWin::PostOpen() { |
| 143 DCHECK(!comm_context_); | 236 DCHECK(!comm_context_); |
| 144 DCHECK(!read_context_); | 237 DCHECK(!read_context_); |
| 145 DCHECK(!write_context_); | 238 DCHECK(!write_context_); |
| 146 | 239 |
| 147 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(), | 240 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(), |
| 148 this); | 241 this); |
| 149 | 242 |
| 150 comm_context_.reset(new base::MessageLoopForIO::IOContext()); | 243 comm_context_.reset(new base::MessageLoopForIO::IOContext()); |
| 151 comm_context_->handler = this; | 244 comm_context_->handler = this; |
| 152 memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped)); | 245 memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped)); |
| 153 | 246 |
| 154 read_context_.reset(new base::MessageLoopForIO::IOContext()); | 247 read_context_.reset(new base::MessageLoopForIO::IOContext()); |
| 155 read_context_->handler = this; | 248 read_context_->handler = this; |
| 156 memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped)); | 249 memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped)); |
| 157 | 250 |
| 158 write_context_.reset(new base::MessageLoopForIO::IOContext()); | 251 write_context_.reset(new base::MessageLoopForIO::IOContext()); |
| 159 write_context_->handler = this; | 252 write_context_->handler = this; |
| 160 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); | 253 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); |
| 161 | 254 |
| 255 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner = | |
| 256 base::ThreadTaskRunnerHandle::Get(); | |
| 257 helper_ = | |
| 258 new UiThreadHelper(weak_factory_.GetWeakPtr(), io_thread_task_runner); | |
| 259 ui_thread_task_runner_->PostTask(FROM_HERE, | |
| 260 base::Bind(&UiThreadHelper::Start, helper_)); | |
| 261 | |
| 162 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete | 262 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete |
| 163 // immediately with any data that's available, even if there is none. | 263 // immediately with any data that's available, even if there is none. |
| 164 // This is OK because we never issue a read request until WaitCommEvent | 264 // This is OK because we never issue a read request until WaitCommEvent |
| 165 // signals that data is available. | 265 // signals that data is available. |
| 166 COMMTIMEOUTS timeouts = {0}; | 266 COMMTIMEOUTS timeouts = {0}; |
| 167 timeouts.ReadIntervalTimeout = MAXDWORD; | 267 timeouts.ReadIntervalTimeout = MAXDWORD; |
| 168 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) { | 268 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) { |
| 169 VPLOG(1) << "Failed to set serial timeouts"; | 269 VPLOG(1) << "Failed to set serial timeouts"; |
| 170 return false; | 270 return false; |
| 171 } | 271 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 return false; | 364 return false; |
| 265 } | 365 } |
| 266 return true; | 366 return true; |
| 267 } | 367 } |
| 268 | 368 |
| 269 SerialIoHandlerWin::SerialIoHandlerWin( | 369 SerialIoHandlerWin::SerialIoHandlerWin( |
| 270 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, | 370 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| 271 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) | 371 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) |
| 272 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), | 372 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), |
| 273 event_mask_(0), | 373 event_mask_(0), |
| 274 is_comm_pending_(false) { | 374 is_comm_pending_(false), |
| 275 } | 375 weak_factory_(this) {} |
| 276 | 376 |
| 277 SerialIoHandlerWin::~SerialIoHandlerWin() { | 377 SerialIoHandlerWin::~SerialIoHandlerWin() { |
| 378 ui_thread_task_runner_->DeleteSoon(FROM_HERE, helper_); | |
| 278 } | 379 } |
| 279 | 380 |
| 280 void SerialIoHandlerWin::OnIOCompleted( | 381 void SerialIoHandlerWin::OnIOCompleted( |
| 281 base::MessageLoopForIO::IOContext* context, | 382 base::MessageLoopForIO::IOContext* context, |
| 282 DWORD bytes_transferred, | 383 DWORD bytes_transferred, |
| 283 DWORD error) { | 384 DWORD error) { |
| 284 DCHECK(CalledOnValidThread()); | 385 DCHECK(CalledOnValidThread()); |
| 285 if (context == comm_context_) { | 386 if (context == comm_context_) { |
| 286 DWORD errors; | 387 DWORD errors; |
| 287 COMSTAT status; | 388 COMSTAT status; |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 434 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { | 535 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { |
| 435 // For COM numbers less than 9, CreateFile is called with a string such as | 536 // For COM numbers less than 9, CreateFile is called with a string such as |
| 436 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added. | 537 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added. |
| 437 if (port_name.length() > std::string("COM9").length()) | 538 if (port_name.length() > std::string("COM9").length()) |
| 438 return std::string("\\\\.\\").append(port_name); | 539 return std::string("\\\\.\\").append(port_name); |
| 439 | 540 |
| 440 return port_name; | 541 return port_name; |
| 441 } | 542 } |
| 442 | 543 |
| 443 } // namespace device | 544 } // namespace device |
| OLD | NEW |