Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: device/serial/serial_io_handler_win.cc

Issue 1439443002: Reland: Add code to deal with serial device disconnection detection on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: updated BUILD.gn and gyp files Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "device/core/scoped_device_info_list.h"
15 #include "device/core/scoped_device_info_object.h"
16 #include "third_party/re2/re2/re2.h"
8 17
9 namespace device { 18 namespace device {
10 19
11 namespace { 20 namespace {
12 21
13 int BitrateToSpeedConstant(int bitrate) { 22 int BitrateToSpeedConstant(int bitrate) {
14 #define BITRATE_TO_SPEED_CASE(x) \ 23 #define BITRATE_TO_SPEED_CASE(x) \
15 case x: \ 24 case x: \
16 return CBR_##x; 25 return CBR_##x;
17 switch (bitrate) { 26 switch (bitrate) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 serial::StopBits StopBitsConstantToEnum(int stop_bits) { 132 serial::StopBits StopBitsConstantToEnum(int stop_bits) {
124 switch (stop_bits) { 133 switch (stop_bits) {
125 case TWOSTOPBITS: 134 case TWOSTOPBITS:
126 return serial::STOP_BITS_TWO; 135 return serial::STOP_BITS_TWO;
127 case ONESTOPBIT: 136 case ONESTOPBIT:
128 default: 137 default:
129 return serial::STOP_BITS_ONE; 138 return serial::STOP_BITS_ONE;
130 } 139 }
131 } 140 }
132 141
142 // Searches for the COM port in the device's friendly name, assigns its value to
143 // com_port, and returns whether the operation was successful.
144 bool GetCOMPort(const std::string friendly_name, std::string* com_port) {
145 return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port);
146 }
147
133 } // namespace 148 } // namespace
134 149
135 // static 150 // static
136 scoped_refptr<SerialIoHandler> SerialIoHandler::Create( 151 scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
137 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, 152 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
138 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) { 153 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) {
139 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); 154 return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner);
140 } 155 }
141 156
157 class SerialIoHandlerWin::UiThreadHelper : public DeviceMonitorWin::Observer {
158 public:
159 UiThreadHelper(
160 base::WeakPtr<SerialIoHandlerWin> io_handler,
161 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner)
162 : device_observer_(this),
163 io_handler_(io_handler),
164 io_thread_task_runner_(io_thread_task_runner) {}
165
166 ~UiThreadHelper() { DCHECK(thread_checker_.CalledOnValidThread()); }
167
168 static void Start(UiThreadHelper* self) {
169 self->thread_checker_.DetachFromThread();
170 DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
171 if (device_monitor)
172 self->device_observer_.Add(device_monitor);
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";
grt (UTC plus 2) 2015/11/13 19:40:05 can these be debug-only logs? do you really need t
juncai 2015/11/14 01:51:24 Done.
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());
grt (UTC plus 2) 2015/11/13 19:40:05 this looks like an awkward api that is easy to get
juncai 2015/11/14 01:51:24 Done.
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)) {
229 VPLOG(1) << "Failed to get port name from \"" << friendly_name << "\".";
230 return;
231 }
232
233 if (port_ == port)
234 CancelRead(serial::RECEIVE_ERROR_DISCONNECTED);
235 }
236
142 bool SerialIoHandlerWin::PostOpen() { 237 bool SerialIoHandlerWin::PostOpen() {
143 DCHECK(!comm_context_); 238 DCHECK(!comm_context_);
144 DCHECK(!read_context_); 239 DCHECK(!read_context_);
145 DCHECK(!write_context_); 240 DCHECK(!write_context_);
146 241
147 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(), 242 base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(),
148 this); 243 this);
149 244
150 comm_context_.reset(new base::MessageLoopForIO::IOContext()); 245 comm_context_.reset(new base::MessageLoopForIO::IOContext());
151 comm_context_->handler = this; 246 comm_context_->handler = this;
152 memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped)); 247 memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped));
153 248
154 read_context_.reset(new base::MessageLoopForIO::IOContext()); 249 read_context_.reset(new base::MessageLoopForIO::IOContext());
155 read_context_->handler = this; 250 read_context_->handler = this;
156 memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped)); 251 memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped));
157 252
158 write_context_.reset(new base::MessageLoopForIO::IOContext()); 253 write_context_.reset(new base::MessageLoopForIO::IOContext());
159 write_context_->handler = this; 254 write_context_->handler = this;
160 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); 255 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped));
161 256
257 scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner =
258 base::ThreadTaskRunnerHandle::Get();
259 helper_ =
260 new UiThreadHelper(weak_factory_.GetWeakPtr(), io_thread_task_runner);
261 ui_thread_task_runner_->PostTask(FROM_HERE,
262 base::Bind(&UiThreadHelper::Start, helper_));
263
162 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete 264 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete
163 // immediately with any data that's available, even if there is none. 265 // 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 266 // This is OK because we never issue a read request until WaitCommEvent
165 // signals that data is available. 267 // signals that data is available.
166 COMMTIMEOUTS timeouts = {0}; 268 COMMTIMEOUTS timeouts = {0};
167 timeouts.ReadIntervalTimeout = MAXDWORD; 269 timeouts.ReadIntervalTimeout = MAXDWORD;
168 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) { 270 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) {
169 VPLOG(1) << "Failed to set serial timeouts"; 271 VPLOG(1) << "Failed to set serial timeouts";
170 return false; 272 return false;
171 } 273 }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 return false; 366 return false;
265 } 367 }
266 return true; 368 return true;
267 } 369 }
268 370
269 SerialIoHandlerWin::SerialIoHandlerWin( 371 SerialIoHandlerWin::SerialIoHandlerWin(
270 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, 372 scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
271 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) 373 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
272 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), 374 : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner),
273 event_mask_(0), 375 event_mask_(0),
274 is_comm_pending_(false) { 376 is_comm_pending_(false),
275 } 377 weak_factory_(this) {}
276 378
277 SerialIoHandlerWin::~SerialIoHandlerWin() { 379 SerialIoHandlerWin::~SerialIoHandlerWin() {
380 ui_thread_task_runner_->DeleteSoon(FROM_HERE, helper_);
278 } 381 }
279 382
280 void SerialIoHandlerWin::OnIOCompleted( 383 void SerialIoHandlerWin::OnIOCompleted(
281 base::MessageLoopForIO::IOContext* context, 384 base::MessageLoopForIO::IOContext* context,
282 DWORD bytes_transferred, 385 DWORD bytes_transferred,
283 DWORD error) { 386 DWORD error) {
284 DCHECK(CalledOnValidThread()); 387 DCHECK(CalledOnValidThread());
285 if (context == comm_context_) { 388 if (context == comm_context_) {
286 DWORD errors; 389 DWORD errors;
287 COMSTAT status; 390 COMSTAT status;
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { 537 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
435 // For COM numbers less than 9, CreateFile is called with a string such as 538 // 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. 539 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added.
437 if (port_name.length() > std::string("COM9").length()) 540 if (port_name.length() > std::string("COM9").length())
438 return std::string("\\\\.\\").append(port_name); 541 return std::string("\\\\.\\").append(port_name);
439 542
440 return port_name; 543 return port_name;
441 } 544 }
442 545
443 } // namespace device 546 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698