Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / device / serial / serial_io_handler_win.cc
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
3 // found in the LICENSE file.
4
5 #include <windows.h>
6
7 #include "device/serial/serial_io_handler_win.h"
8
9 namespace device {
10
11 namespace {
12
13 int BitrateToSpeedConstant(int bitrate) {
14 #define BITRATE_TO_SPEED_CASE(x) \
15   case x:                        \
16     return CBR_##x;
17   switch (bitrate) {
18     BITRATE_TO_SPEED_CASE(110);
19     BITRATE_TO_SPEED_CASE(300);
20     BITRATE_TO_SPEED_CASE(600);
21     BITRATE_TO_SPEED_CASE(1200);
22     BITRATE_TO_SPEED_CASE(2400);
23     BITRATE_TO_SPEED_CASE(4800);
24     BITRATE_TO_SPEED_CASE(9600);
25     BITRATE_TO_SPEED_CASE(14400);
26     BITRATE_TO_SPEED_CASE(19200);
27     BITRATE_TO_SPEED_CASE(38400);
28     BITRATE_TO_SPEED_CASE(57600);
29     BITRATE_TO_SPEED_CASE(115200);
30     BITRATE_TO_SPEED_CASE(128000);
31     BITRATE_TO_SPEED_CASE(256000);
32     default:
33       // If the bitrate doesn't match that of one of the standard
34       // index constants, it may be provided as-is to the DCB
35       // structure, according to MSDN.
36       return bitrate;
37   }
38 #undef BITRATE_TO_SPEED_CASE
39 }
40
41 int DataBitsEnumToConstant(serial::DataBits data_bits) {
42   switch (data_bits) {
43     case serial::DATA_BITS_SEVEN:
44       return 7;
45     case serial::DATA_BITS_EIGHT:
46     default:
47       return 8;
48   }
49 }
50
51 int ParityBitEnumToConstant(serial::ParityBit parity_bit) {
52   switch (parity_bit) {
53     case serial::PARITY_BIT_EVEN:
54       return EVENPARITY;
55     case serial::PARITY_BIT_ODD:
56       return ODDPARITY;
57     case serial::PARITY_BIT_NO:
58     default:
59       return NOPARITY;
60   }
61 }
62
63 int StopBitsEnumToConstant(serial::StopBits stop_bits) {
64   switch (stop_bits) {
65     case serial::STOP_BITS_TWO:
66       return TWOSTOPBITS;
67     case serial::STOP_BITS_ONE:
68     default:
69       return ONESTOPBIT;
70   }
71 }
72
73 int SpeedConstantToBitrate(int speed) {
74 #define SPEED_TO_BITRATE_CASE(x) \
75   case CBR_##x:                  \
76     return x;
77   switch (speed) {
78     SPEED_TO_BITRATE_CASE(110);
79     SPEED_TO_BITRATE_CASE(300);
80     SPEED_TO_BITRATE_CASE(600);
81     SPEED_TO_BITRATE_CASE(1200);
82     SPEED_TO_BITRATE_CASE(2400);
83     SPEED_TO_BITRATE_CASE(4800);
84     SPEED_TO_BITRATE_CASE(9600);
85     SPEED_TO_BITRATE_CASE(14400);
86     SPEED_TO_BITRATE_CASE(19200);
87     SPEED_TO_BITRATE_CASE(38400);
88     SPEED_TO_BITRATE_CASE(57600);
89     SPEED_TO_BITRATE_CASE(115200);
90     SPEED_TO_BITRATE_CASE(128000);
91     SPEED_TO_BITRATE_CASE(256000);
92     default:
93       // If it's not one of the standard index constants,
94       // it should be an integral baud rate, according to
95       // MSDN.
96       return speed;
97   }
98 #undef SPEED_TO_BITRATE_CASE
99 }
100
101 serial::DataBits DataBitsConstantToEnum(int data_bits) {
102   switch (data_bits) {
103     case 7:
104       return serial::DATA_BITS_SEVEN;
105     case 8:
106     default:
107       return serial::DATA_BITS_EIGHT;
108   }
109 }
110
111 serial::ParityBit ParityBitConstantToEnum(int parity_bit) {
112   switch (parity_bit) {
113     case EVENPARITY:
114       return serial::PARITY_BIT_EVEN;
115     case ODDPARITY:
116       return serial::PARITY_BIT_ODD;
117     case NOPARITY:
118     default:
119       return serial::PARITY_BIT_NO;
120   }
121 }
122
123 serial::StopBits StopBitsConstantToEnum(int stop_bits) {
124   switch (stop_bits) {
125     case TWOSTOPBITS:
126       return serial::STOP_BITS_TWO;
127     case ONESTOPBIT:
128     default:
129       return serial::STOP_BITS_ONE;
130   }
131 }
132
133 }  // namespace
134
135 // static
136 scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
137     scoped_refptr<base::MessageLoopProxy> file_thread_message_loop,
138     scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) {
139   return new SerialIoHandlerWin(file_thread_message_loop,
140                                 ui_thread_message_loop);
141 }
142
143 bool SerialIoHandlerWin::PostOpen() {
144   DCHECK(!comm_context_);
145   DCHECK(!read_context_);
146   DCHECK(!write_context_);
147
148   base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(),
149                                                        this);
150
151   comm_context_.reset(new base::MessageLoopForIO::IOContext());
152   comm_context_->handler = this;
153   memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped));
154
155   read_context_.reset(new base::MessageLoopForIO::IOContext());
156   read_context_->handler = this;
157   memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped));
158
159   write_context_.reset(new base::MessageLoopForIO::IOContext());
160   write_context_->handler = this;
161   memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped));
162
163   // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete
164   // immediately with any data that's available, even if there is none.
165   // This is OK because we never issue a read request until WaitCommEvent
166   // signals that data is available.
167   COMMTIMEOUTS timeouts = {0};
168   timeouts.ReadIntervalTimeout = MAXDWORD;
169   if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) {
170     return false;
171   }
172
173   DCB config = {0};
174   config.DCBlength = sizeof(config);
175   if (!GetCommState(file().GetPlatformFile(), &config)) {
176     return false;
177   }
178   // Setup some sane default state.
179   config.fBinary = TRUE;
180   config.fParity = FALSE;
181   config.fAbortOnError = TRUE;
182   config.fOutxCtsFlow = FALSE;
183   config.fOutxDsrFlow = FALSE;
184   config.fRtsControl = RTS_CONTROL_ENABLE;
185   config.fDtrControl = DTR_CONTROL_ENABLE;
186   config.fDsrSensitivity = FALSE;
187   config.fOutX = FALSE;
188   config.fInX = FALSE;
189   return SetCommState(file().GetPlatformFile(), &config) != 0;
190 }
191
192 void SerialIoHandlerWin::ReadImpl() {
193   DCHECK(CalledOnValidThread());
194   DCHECK(pending_read_buffer());
195   DCHECK(file().IsValid());
196
197   DWORD errors;
198   COMSTAT status;
199   if (!ClearCommError(file().GetPlatformFile(), &errors, &status) ||
200       errors != 0) {
201     QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
202     return;
203   }
204
205   SetCommMask(file().GetPlatformFile(), EV_RXCHAR);
206
207   event_mask_ = 0;
208   BOOL ok = ::WaitCommEvent(
209       file().GetPlatformFile(), &event_mask_, &comm_context_->overlapped);
210   if (!ok && GetLastError() != ERROR_IO_PENDING) {
211     QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
212   }
213   is_comm_pending_ = true;
214 }
215
216 void SerialIoHandlerWin::WriteImpl() {
217   DCHECK(CalledOnValidThread());
218   DCHECK(pending_write_buffer());
219   DCHECK(file().IsValid());
220
221   BOOL ok = ::WriteFile(file().GetPlatformFile(),
222                         pending_write_buffer(),
223                         pending_write_buffer_len(),
224                         NULL,
225                         &write_context_->overlapped);
226   if (!ok && GetLastError() != ERROR_IO_PENDING) {
227     QueueWriteCompleted(0, serial::SEND_ERROR_SYSTEM_ERROR);
228   }
229 }
230
231 void SerialIoHandlerWin::CancelReadImpl() {
232   DCHECK(CalledOnValidThread());
233   DCHECK(file().IsValid());
234   ::CancelIo(file().GetPlatformFile());
235 }
236
237 void SerialIoHandlerWin::CancelWriteImpl() {
238   DCHECK(CalledOnValidThread());
239   DCHECK(file().IsValid());
240   ::CancelIo(file().GetPlatformFile());
241 }
242
243 SerialIoHandlerWin::SerialIoHandlerWin(
244     scoped_refptr<base::MessageLoopProxy> file_thread_message_loop,
245     scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop)
246     : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop),
247       event_mask_(0),
248       is_comm_pending_(false) {
249 }
250
251 SerialIoHandlerWin::~SerialIoHandlerWin() {
252 }
253
254 void SerialIoHandlerWin::OnIOCompleted(
255     base::MessageLoopForIO::IOContext* context,
256     DWORD bytes_transferred,
257     DWORD error) {
258   DCHECK(CalledOnValidThread());
259   if (context == comm_context_) {
260     if (read_canceled()) {
261       ReadCompleted(bytes_transferred, read_cancel_reason());
262     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
263       ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
264     } else if (pending_read_buffer()) {
265       BOOL ok = ::ReadFile(file().GetPlatformFile(),
266                            pending_read_buffer(),
267                            pending_read_buffer_len(),
268                            NULL,
269                            &read_context_->overlapped);
270       if (!ok && GetLastError() != ERROR_IO_PENDING) {
271         ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
272       }
273     }
274   } else if (context == read_context_) {
275     if (read_canceled()) {
276       ReadCompleted(bytes_transferred, read_cancel_reason());
277     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
278       ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
279     } else {
280       ReadCompleted(bytes_transferred,
281                     error == ERROR_SUCCESS
282                         ? serial::RECEIVE_ERROR_NONE
283                         : serial::RECEIVE_ERROR_SYSTEM_ERROR);
284     }
285   } else if (context == write_context_) {
286     DCHECK(pending_write_buffer());
287     if (write_canceled()) {
288       WriteCompleted(0, write_cancel_reason());
289     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
290       WriteCompleted(0, serial::SEND_ERROR_SYSTEM_ERROR);
291     } else {
292       WriteCompleted(bytes_transferred,
293                      error == ERROR_SUCCESS ? serial::SEND_ERROR_NONE
294                                             : serial::SEND_ERROR_SYSTEM_ERROR);
295     }
296   } else {
297     NOTREACHED() << "Invalid IOContext";
298   }
299 }
300
301 bool SerialIoHandlerWin::ConfigurePort(
302     const serial::ConnectionOptions& options) {
303   DCB config = {0};
304   config.DCBlength = sizeof(config);
305   if (!GetCommState(file().GetPlatformFile(), &config)) {
306     return false;
307   }
308   if (options.bitrate)
309     config.BaudRate = BitrateToSpeedConstant(options.bitrate);
310   if (options.data_bits != serial::DATA_BITS_NONE)
311     config.ByteSize = DataBitsEnumToConstant(options.data_bits);
312   if (options.parity_bit != serial::PARITY_BIT_NONE)
313     config.Parity = ParityBitEnumToConstant(options.parity_bit);
314   if (options.stop_bits != serial::STOP_BITS_NONE)
315     config.StopBits = StopBitsEnumToConstant(options.stop_bits);
316   if (options.has_cts_flow_control) {
317     if (options.cts_flow_control) {
318       config.fOutxCtsFlow = TRUE;
319       config.fRtsControl = RTS_CONTROL_HANDSHAKE;
320     } else {
321       config.fOutxCtsFlow = FALSE;
322       config.fRtsControl = RTS_CONTROL_ENABLE;
323     }
324   }
325   return SetCommState(file().GetPlatformFile(), &config) != 0;
326 }
327
328 bool SerialIoHandlerWin::Flush() const {
329   return PurgeComm(file().GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) !=
330          0;
331 }
332
333 serial::DeviceControlSignalsPtr SerialIoHandlerWin::GetControlSignals() const {
334   DWORD status;
335   if (!GetCommModemStatus(file().GetPlatformFile(), &status)) {
336     return serial::DeviceControlSignalsPtr();
337   }
338
339   serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New());
340   signals->dcd = (status & MS_RLSD_ON) != 0;
341   signals->cts = (status & MS_CTS_ON) != 0;
342   signals->dsr = (status & MS_DSR_ON) != 0;
343   signals->ri = (status & MS_RING_ON) != 0;
344   return signals.Pass();
345 }
346
347 bool SerialIoHandlerWin::SetControlSignals(
348     const serial::HostControlSignals& signals) {
349   if (signals.has_dtr) {
350     if (!EscapeCommFunction(file().GetPlatformFile(),
351                             signals.dtr ? SETDTR : CLRDTR)) {
352       return false;
353     }
354   }
355   if (signals.has_rts) {
356     if (!EscapeCommFunction(file().GetPlatformFile(),
357                             signals.rts ? SETRTS : CLRRTS)) {
358       return false;
359     }
360   }
361   return true;
362 }
363
364 serial::ConnectionInfoPtr SerialIoHandlerWin::GetPortInfo() const {
365   DCB config = {0};
366   config.DCBlength = sizeof(config);
367   if (!GetCommState(file().GetPlatformFile(), &config)) {
368     return serial::ConnectionInfoPtr();
369   }
370   serial::ConnectionInfoPtr info(serial::ConnectionInfo::New());
371   info->bitrate = SpeedConstantToBitrate(config.BaudRate);
372   info->data_bits = DataBitsConstantToEnum(config.ByteSize);
373   info->parity_bit = ParityBitConstantToEnum(config.Parity);
374   info->stop_bits = StopBitsConstantToEnum(config.StopBits);
375   info->cts_flow_control = config.fOutxCtsFlow != 0;
376   return info.Pass();
377 }
378
379 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
380   // For COM numbers less than 9, CreateFile is called with a string such as
381   // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added.
382   if (port_name.length() > std::string("COM9").length())
383     return std::string("\\\\.\\").append(port_name);
384
385   return port_name;
386 }
387
388 }  // namespace device