Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / device / serial / serial_io_handler_posix.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 "device/serial/serial_io_handler_posix.h"
6
7 #include <sys/ioctl.h>
8 #include <termios.h>
9
10 #include "base/posix/eintr_wrapper.h"
11
12 #if defined(OS_LINUX)
13 #include <linux/serial.h>
14 #if defined(OS_CHROMEOS)
15 #include "base/bind.h"
16 #include "base/sys_info.h"
17 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/dbus/permission_broker_client.h"
19 #endif  // defined(OS_CHROMEOS)
20 #endif  // defined(OS_LINUX)
21
22 namespace {
23
24 // Convert an integral bit rate to a nominal one. Returns |true|
25 // if the conversion was successful and |false| otherwise.
26 bool BitrateToSpeedConstant(int bitrate, speed_t* speed) {
27 #define BITRATE_TO_SPEED_CASE(x) \
28   case x:                        \
29     *speed = B##x;               \
30     return true;
31   switch (bitrate) {
32     BITRATE_TO_SPEED_CASE(0)
33     BITRATE_TO_SPEED_CASE(50)
34     BITRATE_TO_SPEED_CASE(75)
35     BITRATE_TO_SPEED_CASE(110)
36     BITRATE_TO_SPEED_CASE(134)
37     BITRATE_TO_SPEED_CASE(150)
38     BITRATE_TO_SPEED_CASE(200)
39     BITRATE_TO_SPEED_CASE(300)
40     BITRATE_TO_SPEED_CASE(600)
41     BITRATE_TO_SPEED_CASE(1200)
42     BITRATE_TO_SPEED_CASE(1800)
43     BITRATE_TO_SPEED_CASE(2400)
44     BITRATE_TO_SPEED_CASE(4800)
45     BITRATE_TO_SPEED_CASE(9600)
46     BITRATE_TO_SPEED_CASE(19200)
47     BITRATE_TO_SPEED_CASE(38400)
48 #if defined(OS_POSIX) && !defined(OS_MACOSX)
49     BITRATE_TO_SPEED_CASE(57600)
50     BITRATE_TO_SPEED_CASE(115200)
51     BITRATE_TO_SPEED_CASE(230400)
52     BITRATE_TO_SPEED_CASE(460800)
53     BITRATE_TO_SPEED_CASE(576000)
54     BITRATE_TO_SPEED_CASE(921600)
55 #endif
56     default:
57       return false;
58   }
59 #undef BITRATE_TO_SPEED_CASE
60 }
61
62 // Convert a known nominal speed into an integral bitrate. Returns |true|
63 // if the conversion was successful and |false| otherwise.
64 bool SpeedConstantToBitrate(speed_t speed, int* bitrate) {
65 #define SPEED_TO_BITRATE_CASE(x) \
66   case B##x:                     \
67     *bitrate = x;                \
68     return true;
69   switch (speed) {
70     SPEED_TO_BITRATE_CASE(0)
71     SPEED_TO_BITRATE_CASE(50)
72     SPEED_TO_BITRATE_CASE(75)
73     SPEED_TO_BITRATE_CASE(110)
74     SPEED_TO_BITRATE_CASE(134)
75     SPEED_TO_BITRATE_CASE(150)
76     SPEED_TO_BITRATE_CASE(200)
77     SPEED_TO_BITRATE_CASE(300)
78     SPEED_TO_BITRATE_CASE(600)
79     SPEED_TO_BITRATE_CASE(1200)
80     SPEED_TO_BITRATE_CASE(1800)
81     SPEED_TO_BITRATE_CASE(2400)
82     SPEED_TO_BITRATE_CASE(4800)
83     SPEED_TO_BITRATE_CASE(9600)
84     SPEED_TO_BITRATE_CASE(19200)
85     SPEED_TO_BITRATE_CASE(38400)
86 #if defined(OS_POSIX) && !defined(OS_MACOSX)
87     SPEED_TO_BITRATE_CASE(57600)
88     SPEED_TO_BITRATE_CASE(115200)
89     SPEED_TO_BITRATE_CASE(230400)
90     SPEED_TO_BITRATE_CASE(460800)
91     SPEED_TO_BITRATE_CASE(576000)
92     SPEED_TO_BITRATE_CASE(921600)
93 #endif
94     default:
95       return false;
96   }
97 #undef SPEED_TO_BITRATE_CASE
98 }
99
100 bool SetCustomBitrate(base::PlatformFile file,
101                       struct termios* config,
102                       int bitrate) {
103 #if defined(OS_LINUX)
104   struct serial_struct serial;
105   if (ioctl(file, TIOCGSERIAL, &serial) < 0) {
106     return false;
107   }
108   serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
109   serial.custom_divisor = serial.baud_base / bitrate;
110   if (serial.custom_divisor < 1) {
111     serial.custom_divisor = 1;
112   }
113   cfsetispeed(config, B38400);
114   cfsetospeed(config, B38400);
115   return ioctl(file, TIOCSSERIAL, &serial) >= 0;
116 #elif defined(OS_MACOSX)
117   speed_t speed = static_cast<speed_t>(bitrate);
118   cfsetispeed(config, speed);
119   cfsetospeed(config, speed);
120   return true;
121 #else
122   return false;
123 #endif
124 }
125
126 }  // namespace
127
128 namespace device {
129
130 // static
131 scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
132     scoped_refptr<base::MessageLoopProxy> file_thread_message_loop,
133     scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) {
134   return new SerialIoHandlerPosix(file_thread_message_loop,
135                                   ui_thread_message_loop);
136 }
137
138 void SerialIoHandlerPosix::RequestAccess(
139     const std::string& port,
140     scoped_refptr<base::MessageLoopProxy> file_message_loop,
141     scoped_refptr<base::MessageLoopProxy> ui_message_loop) {
142 #if defined(OS_LINUX) && defined(OS_CHROMEOS)
143   if (base::SysInfo::IsRunningOnChromeOS()) {
144     chromeos::PermissionBrokerClient* client =
145         chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
146     if (!client) {
147       DVLOG(1) << "Could not get permission_broker client.";
148       OnRequestAccessComplete(port, false /* failure */);
149       return;
150     }
151     // PermissionBrokerClient should be called on the UI thread.
152     ui_message_loop->PostTask(
153         FROM_HERE,
154         base::Bind(
155             &chromeos::PermissionBrokerClient::RequestPathAccess,
156             base::Unretained(client),
157             port,
158             -1,
159             base::Bind(&SerialIoHandler::OnRequestAccessComplete, this, port)));
160   } else {
161     OnRequestAccessComplete(port, true /* success */);
162     return;
163   }
164 #else
165   OnRequestAccessComplete(port, true /* success */);
166 #endif  // defined(OS_LINUX) && defined(OS_CHROMEOS)
167 }
168
169 void SerialIoHandlerPosix::ReadImpl() {
170   DCHECK(CalledOnValidThread());
171   DCHECK(pending_read_buffer());
172   DCHECK(file().IsValid());
173
174   EnsureWatchingReads();
175 }
176
177 void SerialIoHandlerPosix::WriteImpl() {
178   DCHECK(CalledOnValidThread());
179   DCHECK(pending_write_buffer());
180   DCHECK(file().IsValid());
181
182   EnsureWatchingWrites();
183 }
184
185 void SerialIoHandlerPosix::CancelReadImpl() {
186   DCHECK(CalledOnValidThread());
187   is_watching_reads_ = false;
188   file_read_watcher_.StopWatchingFileDescriptor();
189   QueueReadCompleted(0, read_cancel_reason());
190 }
191
192 void SerialIoHandlerPosix::CancelWriteImpl() {
193   DCHECK(CalledOnValidThread());
194   is_watching_writes_ = false;
195   file_write_watcher_.StopWatchingFileDescriptor();
196   QueueWriteCompleted(0, write_cancel_reason());
197 }
198
199 SerialIoHandlerPosix::SerialIoHandlerPosix(
200     scoped_refptr<base::MessageLoopProxy> file_thread_message_loop,
201     scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop)
202     : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop),
203       is_watching_reads_(false),
204       is_watching_writes_(false) {
205 }
206
207 SerialIoHandlerPosix::~SerialIoHandlerPosix() {
208 }
209
210 void SerialIoHandlerPosix::OnFileCanReadWithoutBlocking(int fd) {
211   DCHECK(CalledOnValidThread());
212   DCHECK_EQ(fd, file().GetPlatformFile());
213
214   if (pending_read_buffer()) {
215     int bytes_read = HANDLE_EINTR(read(file().GetPlatformFile(),
216                                        pending_read_buffer(),
217                                        pending_read_buffer_len()));
218     if (bytes_read < 0) {
219       if (errno == ENXIO) {
220         ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST);
221       } else {
222         ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
223       }
224     } else if (bytes_read == 0) {
225       ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST);
226     } else {
227       ReadCompleted(bytes_read, serial::RECEIVE_ERROR_NONE);
228     }
229   } else {
230     // Stop watching the fd if we get notifications with no pending
231     // reads or writes to avoid starving the message loop.
232     is_watching_reads_ = false;
233     file_read_watcher_.StopWatchingFileDescriptor();
234   }
235 }
236
237 void SerialIoHandlerPosix::OnFileCanWriteWithoutBlocking(int fd) {
238   DCHECK(CalledOnValidThread());
239   DCHECK_EQ(fd, file().GetPlatformFile());
240
241   if (pending_write_buffer()) {
242     int bytes_written = HANDLE_EINTR(write(file().GetPlatformFile(),
243                                            pending_write_buffer(),
244                                            pending_write_buffer_len()));
245     if (bytes_written < 0) {
246       WriteCompleted(0, serial::SEND_ERROR_SYSTEM_ERROR);
247     } else {
248       WriteCompleted(bytes_written, serial::SEND_ERROR_NONE);
249     }
250   } else {
251     // Stop watching the fd if we get notifications with no pending
252     // writes to avoid starving the message loop.
253     is_watching_writes_ = false;
254     file_write_watcher_.StopWatchingFileDescriptor();
255   }
256 }
257
258 void SerialIoHandlerPosix::EnsureWatchingReads() {
259   DCHECK(CalledOnValidThread());
260   DCHECK(file().IsValid());
261   if (!is_watching_reads_) {
262     is_watching_reads_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
263         file().GetPlatformFile(),
264         true,
265         base::MessageLoopForIO::WATCH_READ,
266         &file_read_watcher_,
267         this);
268   }
269 }
270
271 void SerialIoHandlerPosix::EnsureWatchingWrites() {
272   DCHECK(CalledOnValidThread());
273   DCHECK(file().IsValid());
274   if (!is_watching_writes_) {
275     is_watching_writes_ =
276         base::MessageLoopForIO::current()->WatchFileDescriptor(
277             file().GetPlatformFile(),
278             true,
279             base::MessageLoopForIO::WATCH_WRITE,
280             &file_write_watcher_,
281             this);
282   }
283 }
284
285 bool SerialIoHandlerPosix::ConfigurePort(
286     const serial::ConnectionOptions& options) {
287   struct termios config;
288   tcgetattr(file().GetPlatformFile(), &config);
289   if (options.bitrate) {
290     speed_t bitrate_opt = B0;
291     if (BitrateToSpeedConstant(options.bitrate, &bitrate_opt)) {
292       cfsetispeed(&config, bitrate_opt);
293       cfsetospeed(&config, bitrate_opt);
294     } else {
295       // Attempt to set a custom speed.
296       if (!SetCustomBitrate(
297               file().GetPlatformFile(), &config, options.bitrate)) {
298         return false;
299       }
300     }
301   }
302   if (options.data_bits != serial::DATA_BITS_NONE) {
303     config.c_cflag &= ~CSIZE;
304     switch (options.data_bits) {
305       case serial::DATA_BITS_SEVEN:
306         config.c_cflag |= CS7;
307         break;
308       case serial::DATA_BITS_EIGHT:
309       default:
310         config.c_cflag |= CS8;
311         break;
312     }
313   }
314   if (options.parity_bit != serial::PARITY_BIT_NONE) {
315     switch (options.parity_bit) {
316       case serial::PARITY_BIT_EVEN:
317         config.c_cflag |= PARENB;
318         config.c_cflag &= ~PARODD;
319         break;
320       case serial::PARITY_BIT_ODD:
321         config.c_cflag |= (PARODD | PARENB);
322         break;
323       case serial::PARITY_BIT_NO:
324       default:
325         config.c_cflag &= ~(PARODD | PARENB);
326         break;
327     }
328   }
329   if (options.stop_bits != serial::STOP_BITS_NONE) {
330     switch (options.stop_bits) {
331       case serial::STOP_BITS_TWO:
332         config.c_cflag |= CSTOPB;
333         break;
334       case serial::STOP_BITS_ONE:
335       default:
336         config.c_cflag &= ~CSTOPB;
337         break;
338     }
339   }
340   if (options.has_cts_flow_control) {
341     if (options.cts_flow_control) {
342       config.c_cflag |= CRTSCTS;
343     } else {
344       config.c_cflag &= ~CRTSCTS;
345     }
346   }
347   return tcsetattr(file().GetPlatformFile(), TCSANOW, &config) == 0;
348 }
349
350 bool SerialIoHandlerPosix::PostOpen() {
351   struct termios config;
352   tcgetattr(file().GetPlatformFile(), &config);
353
354   // Set flags for 'raw' operation
355   config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG);
356   config.c_iflag &=
357       ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
358   config.c_oflag &= ~OPOST;
359
360   // CLOCAL causes the system to disregard the DCD signal state.
361   // CREAD enables reading from the port.
362   config.c_cflag |= (CLOCAL | CREAD);
363
364   return tcsetattr(file().GetPlatformFile(), TCSANOW, &config) == 0;
365 }
366
367 bool SerialIoHandlerPosix::Flush() const {
368   return tcflush(file().GetPlatformFile(), TCIOFLUSH) == 0;
369 }
370
371 serial::DeviceControlSignalsPtr SerialIoHandlerPosix::GetControlSignals()
372     const {
373   int status;
374   if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) {
375     return serial::DeviceControlSignalsPtr();
376   }
377
378   serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New());
379   signals->dcd = (status & TIOCM_CAR) != 0;
380   signals->cts = (status & TIOCM_CTS) != 0;
381   signals->dsr = (status & TIOCM_DSR) != 0;
382   signals->ri = (status & TIOCM_RI) != 0;
383   return signals.Pass();
384 }
385
386 bool SerialIoHandlerPosix::SetControlSignals(
387     const serial::HostControlSignals& signals) {
388   int status;
389
390   if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) {
391     return false;
392   }
393
394   if (signals.has_dtr) {
395     if (signals.dtr) {
396       status |= TIOCM_DTR;
397     } else {
398       status &= ~TIOCM_DTR;
399     }
400   }
401
402   if (signals.has_rts) {
403     if (signals.rts) {
404       status |= TIOCM_RTS;
405     } else {
406       status &= ~TIOCM_RTS;
407     }
408   }
409
410   return ioctl(file().GetPlatformFile(), TIOCMSET, &status) == 0;
411 }
412
413 serial::ConnectionInfoPtr SerialIoHandlerPosix::GetPortInfo() const {
414   struct termios config;
415   if (tcgetattr(file().GetPlatformFile(), &config) == -1) {
416     return serial::ConnectionInfoPtr();
417   }
418   serial::ConnectionInfoPtr info(serial::ConnectionInfo::New());
419   speed_t ispeed = cfgetispeed(&config);
420   speed_t ospeed = cfgetospeed(&config);
421   if (ispeed == ospeed) {
422     int bitrate = 0;
423     if (SpeedConstantToBitrate(ispeed, &bitrate)) {
424       info->bitrate = bitrate;
425     } else if (ispeed > 0) {
426       info->bitrate = static_cast<int>(ispeed);
427     }
428   }
429   if ((config.c_cflag & CSIZE) == CS7) {
430     info->data_bits = serial::DATA_BITS_SEVEN;
431   } else if ((config.c_cflag & CSIZE) == CS8) {
432     info->data_bits = serial::DATA_BITS_EIGHT;
433   } else {
434     info->data_bits = serial::DATA_BITS_NONE;
435   }
436   if (config.c_cflag & PARENB) {
437     info->parity_bit = (config.c_cflag & PARODD) ? serial::PARITY_BIT_ODD
438                                                  : serial::PARITY_BIT_EVEN;
439   } else {
440     info->parity_bit = serial::PARITY_BIT_NO;
441   }
442   info->stop_bits =
443       (config.c_cflag & CSTOPB) ? serial::STOP_BITS_TWO : serial::STOP_BITS_ONE;
444   info->cts_flow_control = (config.c_cflag & CRTSCTS) != 0;
445   return info.Pass();
446 }
447
448 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
449   return port_name;
450 }
451
452 }  // namespace device