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 "device/core/device_monitor_win.h" | |
| 14 #include "third_party/re2/re2/re2.h" | |
| 8 | 15 |
| 9 namespace device { | 16 namespace device { |
| 10 | 17 |
| 11 namespace { | 18 namespace { |
| 12 | 19 |
| 13 int BitrateToSpeedConstant(int bitrate) { | 20 int BitrateToSpeedConstant(int bitrate) { |
| 14 #define BITRATE_TO_SPEED_CASE(x) \ | 21 #define BITRATE_TO_SPEED_CASE(x) \ |
| 15 case x: \ | 22 case x: \ |
| 16 return CBR_##x; | 23 return CBR_##x; |
| 17 switch (bitrate) { | 24 switch (bitrate) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 serial::StopBits StopBitsConstantToEnum(int stop_bits) { | 130 serial::StopBits StopBitsConstantToEnum(int stop_bits) { |
| 124 switch (stop_bits) { | 131 switch (stop_bits) { |
| 125 case TWOSTOPBITS: | 132 case TWOSTOPBITS: |
| 126 return serial::STOP_BITS_TWO; | 133 return serial::STOP_BITS_TWO; |
| 127 case ONESTOPBIT: | 134 case ONESTOPBIT: |
| 128 default: | 135 default: |
| 129 return serial::STOP_BITS_ONE; | 136 return serial::STOP_BITS_ONE; |
| 130 } | 137 } |
| 131 } | 138 } |
| 132 | 139 |
| 140 // Wrapper around a HDEVINFO that automatically destroys it. | |
| 141 class ScopedDeviceInfoList { | |
|
Reilly Grant (use Gerrit)
2015/11/11 20:43:59
Let's see if we can get these into //base/win.
juncai
2015/11/12 05:27:08
Done.
Lei Zhang
2015/11/13 01:40:50
You can certainly try, but you'll need to back it
| |
| 142 public: | |
| 143 explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {} | |
| 144 | |
| 145 ~ScopedDeviceInfoList() { | |
| 146 if (valid()) { | |
| 147 SetupDiDestroyDeviceInfoList(handle_); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 bool valid() { return handle_ != INVALID_HANDLE_VALUE; } | |
| 152 | |
| 153 HDEVINFO get() { return handle_; } | |
| 154 | |
| 155 private: | |
| 156 HDEVINFO handle_; | |
| 157 | |
| 158 DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList); | |
| 159 }; | |
| 160 | |
| 161 // Wrapper around an SP_DEVINFO_DATA that initializes it properly and | |
| 162 // automatically deletes it. | |
| 163 class ScopedDeviceInfo { | |
| 164 public: | |
| 165 ScopedDeviceInfo() { | |
| 166 memset(&dev_info_data_, 0, sizeof(dev_info_data_)); | |
| 167 dev_info_data_.cbSize = sizeof(dev_info_data_); | |
| 168 } | |
| 169 | |
| 170 ~ScopedDeviceInfo() { | |
| 171 if (dev_info_set_ != INVALID_HANDLE_VALUE) { | |
| 172 SetupDiDeleteDeviceInfo(dev_info_set_, &dev_info_data_); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Once the SP_DEVINFO_DATA has been populated it must be freed using the | |
| 177 // HDEVINFO it was created from. | |
| 178 void set_valid(HDEVINFO dev_info_set) { | |
| 179 DCHECK(dev_info_set_ == INVALID_HANDLE_VALUE); | |
| 180 DCHECK(dev_info_set != INVALID_HANDLE_VALUE); | |
| 181 dev_info_set_ = dev_info_set; | |
| 182 } | |
| 183 | |
| 184 PSP_DEVINFO_DATA get() { return &dev_info_data_; } | |
| 185 | |
| 186 private: | |
| 187 HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE; | |
| 188 SP_DEVINFO_DATA dev_info_data_; | |
| 189 }; | |
| 190 | |
| 191 // Searches for the COM port in the device's friendly name, assigns its value to | |
| 192 // com_port, and returns whether the operation was successful. | |
| 193 bool GetCOMPort(const std::string friendly_name, std::string* com_port) { | |
| 194 return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port); | |
| 195 } | |
| 196 | |
| 133 } // namespace | 197 } // namespace |
| 134 | 198 |
| 135 // static | 199 // static |
| 136 scoped_refptr<SerialIoHandler> SerialIoHandler::Create( | 200 scoped_refptr<SerialIoHandler> SerialIoHandler::Create( |
| 137 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, | 201 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| 138 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) { | 202 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) { |
| 139 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); | 203 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); |
| 140 } | 204 } |
| 141 | 205 |
| 206 class SerialIoHandlerWin::UiThreadHelper : public DeviceMonitorWin::Observer { | |
| 207 public: | |
| 208 UiThreadHelper( | |
| 209 base::WeakPtr<SerialIoHandlerWin> io_handler, | |
| 210 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) | |
| 211 : device_observer_(this), | |
| 212 io_handler_(io_handler), | |
| 213 io_thread_task_runner_(io_thread_task_runner) {} | |
| 214 | |
| 215 ~UiThreadHelper() { DCHECK(thread_checker_.CalledOnValidThread()); } | |
| 216 | |
| 217 static void Start(scoped_ptr<UiThreadHelper> self) { | |
| 218 self->thread_checker_.DetachFromThread(); | |
| 219 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces(); | |
| 220 if (device_monitor) { | |
| 221 self->device_observer_.Add(device_monitor); | |
| 222 } | |
| 223 // |self| is now owned by the current message loop. | |
| 224 ignore_result(self.release()); | |
|
Reilly Grant (use Gerrit)
2015/11/11 20:43:59
Since this object is not also a MessageLoopDestruc
juncai
2015/11/12 05:27:08
Done.
| |
| 225 } | |
| 226 | |
| 227 private: | |
| 228 // DeviceMonitorWin::Observer | |
| 229 void OnDeviceRemoved(const GUID& class_guid, | |
| 230 const std::string& device_path) override { | |
| 231 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 232 io_thread_task_runner_->PostTask( | |
| 233 FROM_HERE, base::Bind(&SerialIoHandlerWin::RemoveDevice, io_handler_, | |
| 234 device_path)); | |
| 235 } | |
| 236 | |
| 237 base::ThreadChecker thread_checker_; | |
| 238 ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; | |
| 239 | |
| 240 // This weak pointer is only valid when checked on this task runner. | |
| 241 base::WeakPtr<SerialIoHandlerWin> io_handler_; | |
| 242 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_; | |
| 243 | |
| 244 DISALLOW_COPY_AND_ASSIGN(UiThreadHelper); | |
| 245 }; | |
| 246 | |
| 247 void SerialIoHandlerWin::RemoveDevice(const std::string& device_path) { | |
| 248 DCHECK(CalledOnValidThread()); | |
| 249 ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL)); | |
| 250 if (!dev_info_list.valid()) { | |
| 251 VPLOG(1) << "Failed to create a device information set"; | |
| 252 return; | |
| 253 } | |
| 254 | |
| 255 // This will add the device to |dev_info_list| so we can query driver info. | |
| 256 if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0, | |
| 257 NULL)) { | |
| 258 VPLOG(1) << "Failed to get device interface data for " << device_path; | |
| 259 return; | |
| 260 } | |
| 261 | |
| 262 ScopedDeviceInfo dev_info; | |
| 263 if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) { | |
| 264 VPLOG(1) << "Failed to get device info for " << device_path; | |
| 265 return; | |
| 266 } | |
| 267 | |
| 268 dev_info.set_valid(dev_info_list.get()); | |
| 269 | |
| 270 BYTE friendly_name[512]; | |
| 271 if (!SetupDiGetDeviceRegistryPropertyA( | |
| 272 dev_info_list.get(), dev_info.get(), SPDRP_FRIENDLYNAME, NULL, | |
| 273 friendly_name, sizeof(friendly_name), NULL)) { | |
| 274 VPLOG(1) << "Failed to get device service property"; | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 std::string port; | |
| 279 if (!GetCOMPort(reinterpret_cast<const char*>(friendly_name), &port)) | |
| 280 return; | |
| 281 | |
| 282 if (port_ == port) | |
| 283 CancelRead(serial::RECEIVE_ERROR_SYSTEM_ERROR); | |
|
Reilly Grant (use Gerrit)
2015/11/11 20:43:59
s/SYSTEM_ERROR/DISCONNECTED/
juncai
2015/11/12 05:27:08
Done.
| |
| 284 } | |
| 285 | |
| 142 bool SerialIoHandlerWin::PostOpen() { | 286 bool SerialIoHandlerWin::PostOpen() { |
| 143 DCHECK(!comm_context_); | 287 DCHECK(!comm_context_); |
| 144 DCHECK(!read_context_); | 288 DCHECK(!read_context_); |
| 145 DCHECK(!write_context_); | 289 DCHECK(!write_context_); |
| 146 | 290 |
| 147 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(), | 291 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(), |
| 148 this); | 292 this); |
| 149 | 293 |
| 150 comm_context_.reset(new base::MessageLoopForIO::IOContext()); | 294 comm_context_.reset(new base::MessageLoopForIO::IOContext()); |
| 151 comm_context_->handler = this; | 295 comm_context_->handler = this; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 return false; | 408 return false; |
| 265 } | 409 } |
| 266 return true; | 410 return true; |
| 267 } | 411 } |
| 268 | 412 |
| 269 SerialIoHandlerWin::SerialIoHandlerWin( | 413 SerialIoHandlerWin::SerialIoHandlerWin( |
| 270 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, | 414 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, |
| 271 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) | 415 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) |
| 272 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), | 416 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), |
| 273 event_mask_(0), | 417 event_mask_(0), |
| 274 is_comm_pending_(false) { | 418 is_comm_pending_(false), |
| 419 weak_factory_(this) { | |
| 420 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner = | |
| 421 base::ThreadTaskRunnerHandle::Get(); | |
| 422 scoped_ptr<UiThreadHelper> helper( | |
| 423 new UiThreadHelper(weak_factory_.GetWeakPtr(), io_thread_task_runner)); | |
|
Reilly Grant (use Gerrit)
2015/11/11 20:43:59
The helper should be created in PostOpen, which sh
juncai
2015/11/12 05:27:08
Done.
| |
| 424 helper_ = helper.get(); | |
| 425 ui_thread_task_runner->PostTask( | |
| 426 FROM_HERE, base::Bind(&UiThreadHelper::Start, base::Passed(&helper))); | |
| 275 } | 427 } |
| 276 | 428 |
| 277 SerialIoHandlerWin::~SerialIoHandlerWin() { | 429 SerialIoHandlerWin::~SerialIoHandlerWin() { |
| 430 ui_thread_task_runner_->DeleteSoon(FROM_HERE, helper_); | |
| 278 } | 431 } |
| 279 | 432 |
| 280 void SerialIoHandlerWin::OnIOCompleted( | 433 void SerialIoHandlerWin::OnIOCompleted( |
| 281 base::MessageLoopForIO::IOContext* context, | 434 base::MessageLoopForIO::IOContext* context, |
| 282 DWORD bytes_transferred, | 435 DWORD bytes_transferred, |
| 283 DWORD error) { | 436 DWORD error) { |
| 284 DCHECK(CalledOnValidThread()); | 437 DCHECK(CalledOnValidThread()); |
| 285 if (context == comm_context_) { | 438 if (context == comm_context_) { |
| 286 DWORD errors; | 439 DWORD errors; |
| 287 COMSTAT status; | 440 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) { | 587 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { |
| 435 // For COM numbers less than 9, CreateFile is called with a string such as | 588 // 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. | 589 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added. |
| 437 if (port_name.length() > std::string("COM9").length()) | 590 if (port_name.length() > std::string("COM9").length()) |
| 438 return std::string("\\\\.\\").append(port_name); | 591 return std::string("\\\\.\\").append(port_name); |
| 439 | 592 |
| 440 return port_name; | 593 return port_name; |
| 441 } | 594 } |
| 442 | 595 |
| 443 } // namespace device | 596 } // namespace device |
| OLD | NEW |