1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <windows.h>
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "device/serial/serial_io_handler_win.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace device {
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint BitrateToSpeedConstant(int bitrate) {
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define BITRATE_TO_SPEED_CASE(x) \
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  case x:                        \
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return CBR_##x;
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (bitrate) {
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(110);
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(300);
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(600);
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(1200);
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(2400);
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(4800);
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(9600);
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(14400);
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(19200);
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(38400);
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(57600);
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(115200);
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(128000);
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    BITRATE_TO_SPEED_CASE(256000);
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // If the bitrate doesn't match that of one of the standard
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // index constants, it may be provided as-is to the DCB
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // structure, according to MSDN.
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return bitrate;
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#undef BITRATE_TO_SPEED_CASE
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint DataBitsEnumToConstant(serial::DataBits data_bits) {
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (data_bits) {
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::DATA_BITS_SEVEN:
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return 7;
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::DATA_BITS_EIGHT:
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return 8;
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint ParityBitEnumToConstant(serial::ParityBit parity_bit) {
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (parity_bit) {
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::PARITY_BIT_EVEN:
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return EVENPARITY;
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::PARITY_BIT_ODD:
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return ODDPARITY;
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::PARITY_BIT_NO:
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return NOPARITY;
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint StopBitsEnumToConstant(serial::StopBits stop_bits) {
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (stop_bits) {
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::STOP_BITS_TWO:
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return TWOSTOPBITS;
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case serial::STOP_BITS_ONE:
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return ONESTOPBIT;
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdochint SpeedConstantToBitrate(int speed) {
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define SPEED_TO_BITRATE_CASE(x) \
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  case CBR_##x:                  \
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return x;
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (speed) {
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(110);
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(300);
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(600);
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(1200);
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(2400);
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(4800);
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(9600);
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(14400);
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(19200);
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(38400);
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(57600);
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(115200);
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(128000);
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SPEED_TO_BITRATE_CASE(256000);
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // If it's not one of the standard index constants,
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // it should be an integral baud rate, according to
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // MSDN.
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return speed;
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#undef SPEED_TO_BITRATE_CASE
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdochserial::DataBits DataBitsConstantToEnum(int data_bits) {
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (data_bits) {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 7:
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::DATA_BITS_SEVEN;
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case 8:
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::DATA_BITS_EIGHT;
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdochserial::ParityBit ParityBitConstantToEnum(int parity_bit) {
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (parity_bit) {
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case EVENPARITY:
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::PARITY_BIT_EVEN;
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case ODDPARITY:
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::PARITY_BIT_ODD;
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case NOPARITY:
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::PARITY_BIT_NO;
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdochserial::StopBits StopBitsConstantToEnum(int stop_bits) {
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  switch (stop_bits) {
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case TWOSTOPBITS:
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::STOP_BITS_TWO;
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case ONESTOPBIT:
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    default:
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return serial::STOP_BITS_ONE;
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// static
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> file_thread_message_loop) {
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return new SerialIoHandlerWin(file_thread_message_loop);
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandlerWin::PostOpen() {
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!comm_context_);
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!read_context_);
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(!write_context_);
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(),
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                       this);
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  comm_context_.reset(new base::MessageLoopForIO::IOContext());
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  comm_context_->handler = this;
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped));
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  read_context_.reset(new base::MessageLoopForIO::IOContext());
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  read_context_->handler = this;
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped));
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_context_.reset(new base::MessageLoopForIO::IOContext());
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  write_context_->handler = this;
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped));
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // immediately with any data that's available, even if there is none.
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // This is OK because we never issue a read request until WaitCommEvent
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // signals that data is available.
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  COMMTIMEOUTS timeouts = {0};
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  timeouts.ReadIntervalTimeout = MAXDWORD;
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) {
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCB config = {0};
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.DCBlength = sizeof(config);
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!GetCommState(file().GetPlatformFile(), &config)) {
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Setup some sane default state.
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fBinary = TRUE;
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fParity = FALSE;
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fAbortOnError = TRUE;
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fOutxCtsFlow = FALSE;
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fOutxDsrFlow = FALSE;
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fRtsControl = RTS_CONTROL_ENABLE;
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fDtrControl = DTR_CONTROL_ENABLE;
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fDsrSensitivity = FALSE;
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fOutX = FALSE;
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.fInX = FALSE;
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return SetCommState(file().GetPlatformFile(), &config) != 0;
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandlerWin::ReadImpl() {
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(pending_read_buffer());
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(file().IsValid());
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DWORD errors;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  COMSTAT status;
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ClearCommError(file().GetPlatformFile(), &errors, &status) ||
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      errors != 0) {
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetCommMask(file().GetPlatformFile(), EV_RXCHAR);
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  event_mask_ = 0;
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BOOL ok = ::WaitCommEvent(
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      file().GetPlatformFile(), &event_mask_, &comm_context_->overlapped);
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ok && GetLastError() != ERROR_IO_PENDING) {
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  is_comm_pending_ = true;
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandlerWin::WriteImpl() {
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(pending_write_buffer());
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(file().IsValid());
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  BOOL ok = ::WriteFile(file().GetPlatformFile(),
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        pending_write_buffer(),
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        pending_write_buffer_len(),
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        NULL,
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        &write_context_->overlapped);
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ok && GetLastError() != ERROR_IO_PENDING) {
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    QueueWriteCompleted(0, serial::SEND_ERROR_SYSTEM_ERROR);
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandlerWin::CancelReadImpl() {
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(file().IsValid());
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ::CancelIo(file().GetPlatformFile());
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandlerWin::CancelWriteImpl() {
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(file().IsValid());
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ::CancelIo(file().GetPlatformFile());
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)SerialIoHandlerWin::SerialIoHandlerWin(
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> file_thread_message_loop)
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : SerialIoHandler(file_thread_message_loop),
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      event_mask_(0),
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      is_comm_pending_(false) {
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
248116680a4aac90f2aa7413d9095a592090648e557Ben MurdochSerialIoHandlerWin::~SerialIoHandlerWin() {
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SerialIoHandlerWin::OnIOCompleted(
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    base::MessageLoopForIO::IOContext* context,
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DWORD bytes_transferred,
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DWORD error) {
255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(CalledOnValidThread());
256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (context == comm_context_) {
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (read_canceled()) {
258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ReadCompleted(bytes_transferred, read_cancel_reason());
259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
260116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else if (pending_read_buffer()) {
262116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      BOOL ok = ::ReadFile(file().GetPlatformFile(),
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           pending_read_buffer(),
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           pending_read_buffer_len(),
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           NULL,
266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           &read_context_->overlapped);
267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!ok && GetLastError() != ERROR_IO_PENDING) {
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (context == read_context_) {
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (read_canceled()) {
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ReadCompleted(bytes_transferred, read_cancel_reason());
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ReadCompleted(bytes_transferred,
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                    error == ERROR_SUCCESS
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        ? serial::RECEIVE_ERROR_NONE
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                        : serial::RECEIVE_ERROR_SYSTEM_ERROR);
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else if (context == write_context_) {
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(pending_write_buffer());
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (write_canceled()) {
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      WriteCompleted(0, write_cancel_reason());
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      WriteCompleted(0, serial::SEND_ERROR_SYSTEM_ERROR);
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      WriteCompleted(bytes_transferred,
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     error == ERROR_SUCCESS ? serial::SEND_ERROR_NONE
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                            : serial::SEND_ERROR_SYSTEM_ERROR);
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NOTREACHED() << "Invalid IOContext";
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandlerWin::ConfigurePort(
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const serial::ConnectionOptions& options) {
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCB config = {0};
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.DCBlength = sizeof(config);
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!GetCommState(file().GetPlatformFile(), &config)) {
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (options.bitrate)
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config.BaudRate = BitrateToSpeedConstant(options.bitrate);
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (options.data_bits != serial::DATA_BITS_NONE)
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config.ByteSize = DataBitsEnumToConstant(options.data_bits);
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (options.parity_bit != serial::PARITY_BIT_NONE)
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config.Parity = ParityBitEnumToConstant(options.parity_bit);
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (options.stop_bits != serial::STOP_BITS_NONE)
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config.StopBits = StopBitsEnumToConstant(options.stop_bits);
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (options.has_cts_flow_control) {
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (options.cts_flow_control) {
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config.fOutxCtsFlow = TRUE;
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config.fRtsControl = RTS_CONTROL_HANDSHAKE;
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config.fOutxCtsFlow = FALSE;
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config.fRtsControl = RTS_CONTROL_ENABLE;
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return SetCommState(file().GetPlatformFile(), &config) != 0;
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandlerWin::Flush() const {
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return PurgeComm(file().GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) !=
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         0;
328116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdochserial::DeviceControlSignalsPtr SerialIoHandlerWin::GetControlSignals() const {
331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DWORD status;
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!GetCommModemStatus(file().GetPlatformFile(), &status)) {
333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return serial::DeviceControlSignalsPtr();
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New());
337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  signals->dcd = (status & MS_RLSD_ON) != 0;
338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  signals->cts = (status & MS_CTS_ON) != 0;
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  signals->dsr = (status & MS_DSR_ON) != 0;
340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  signals->ri = (status & MS_RING_ON) != 0;
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return signals.Pass();
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
344116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool SerialIoHandlerWin::SetControlSignals(
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const serial::HostControlSignals& signals) {
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (signals.has_dtr) {
347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!EscapeCommFunction(file().GetPlatformFile(),
348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            signals.dtr ? SETDTR : CLRDTR)) {
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
352116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (signals.has_rts) {
353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!EscapeCommFunction(file().GetPlatformFile(),
354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            signals.rts ? SETRTS : CLRRTS)) {
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdochserial::ConnectionInfoPtr SerialIoHandlerWin::GetPortInfo() const {
362116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCB config = {0};
363116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config.DCBlength = sizeof(config);
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!GetCommState(file().GetPlatformFile(), &config)) {
365116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return serial::ConnectionInfoPtr();
366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
367116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  serial::ConnectionInfoPtr info(serial::ConnectionInfo::New());
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  info->bitrate = SpeedConstantToBitrate(config.BaudRate);
369116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  info->data_bits = DataBitsConstantToEnum(config.ByteSize);
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  info->parity_bit = ParityBitConstantToEnum(config.Parity);
371116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  info->stop_bits = StopBitsConstantToEnum(config.StopBits);
372116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  info->cts_flow_control = config.fOutxCtsFlow != 0;
373116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return info.Pass();
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // For COM numbers less than 9, CreateFile is called with a string such as
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added.
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (port_name.length() > std::string("COM9").length())
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return std::string("\\\\.\\").append(port_name);
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return port_name;
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace device
386