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