LIRC libraries
LinuxInfraredRemoteControl
serial.c
Go to the documentation of this file.
1 /****************************************************************************
2 ** serial.c ****************************************************************
3 ****************************************************************************
4 *
5 * common routines for hardware that uses the standard serial port driver
6 *
7 * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
8 *
9 */
10 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 
21 #ifndef LIRC_LOCKDIR
22 #define LIRC_LOCKDIR "/var/lock/lockdev"
23 #endif
24 
25 
26 #include <limits.h>
27 #include <poll.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <termios.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 
43 #if defined __linux__
44 #include <linux/serial.h> /* for 'struct serial_struct' to set custom
45  * baudrates */
46 #endif
47 
48 #include "lirc/lirc_log.h"
49 
50 static const logchannel_t logchannel = LOG_LIB;
51 
52 int tty_reset(int fd)
53 {
54  struct termios options;
55 
56  if (tcgetattr(fd, &options) == -1) {
57  log_trace("tty_reset(): tcgetattr() failed");
58  log_perror_debug("tty_reset()");
59  return 0;
60  }
61  cfmakeraw(&options);
62  if (tcsetattr(fd, TCSAFLUSH, &options) == -1) {
63  log_trace("tty_reset(): tcsetattr() failed");
64  log_perror_debug("tty_reset()");
65  return 0;
66  }
67  return 1;
68 }
69 
70 int tty_setrtscts(int fd, int enable)
71 {
72  struct termios options;
73 
74  if (tcgetattr(fd, &options) == -1) {
75  log_trace("%s: tcgetattr() failed", __func__);
76  log_perror_debug(__func__);
77  return 0;
78  }
79  if (enable)
80  options.c_cflag |= CRTSCTS;
81  else
82  options.c_cflag &= ~CRTSCTS;
83  if (tcsetattr(fd, TCSAFLUSH, &options) == -1) {
84  log_trace("%s: tcsetattr() failed", __func__);
85  log_perror_debug(__func__);
86  return 0;
87  }
88  return 1;
89 }
90 
91 int tty_setdtr(int fd, int enable)
92 {
93  int cmd, sts;
94 
95  if (ioctl(fd, TIOCMGET, &sts) < 0) {
96  log_trace("%s: ioctl(TIOCMGET) failed", __func__);
97  log_perror_debug(__func__);
98  return 0;
99  }
100  if (((sts & TIOCM_DTR) == 0) && enable) {
101  log_trace("%s: 0->1", __func__);
102  } else if ((!enable) && (sts & TIOCM_DTR)) {
103  log_trace("%s: 1->0", __func__);
104  }
105  if (enable)
106  cmd = TIOCMBIS;
107  else
108  cmd = TIOCMBIC;
109  sts = TIOCM_DTR;
110  if (ioctl(fd, cmd, &sts) < 0) {
111  log_trace("%s: ioctl(TIOCMBI(S|C)) failed", __func__);
112  log_perror_debug(__func__);
113  return 0;
114  }
115  return 1;
116 }
117 
118 int tty_setbaud(int fd, int baud)
119 {
120  struct termios options;
121  int speed;
122 
123 #if defined __linux__
124  int use_custom_divisor = 0;
125  struct serial_struct serinfo;
126 #endif
127 
128  switch (baud) {
129  case 300:
130  speed = B300;
131  break;
132  case 1200:
133  speed = B1200;
134  break;
135  case 2400:
136  speed = B2400;
137  break;
138  case 4800:
139  speed = B4800;
140  break;
141  case 9600:
142  speed = B9600;
143  break;
144  case 19200:
145  speed = B19200;
146  break;
147  case 38400:
148  speed = B38400;
149  break;
150  case 57600:
151  speed = B57600;
152  break;
153  case 115200:
154  speed = B115200;
155  break;
156 #ifdef B230400
157  case 230400:
158  speed = B230400;
159  break;
160 #endif
161 #ifdef B460800
162  case 460800:
163  speed = B460800;
164  break;
165 #endif
166 #ifdef B500000
167  case 500000:
168  speed = B500000;
169  break;
170 #endif
171 #ifdef B576000
172  case 576000:
173  speed = B576000;
174  break;
175 #endif
176 #ifdef B921600
177  case 921600:
178  speed = B921600;
179  break;
180 #endif
181 #ifdef B1000000
182  case 1000000:
183  speed = B1000000;
184  break;
185 #endif
186 #ifdef B1152000
187  case 1152000:
188  speed = B1152000;
189  break;
190 #endif
191 #ifdef B1500000
192  case 1500000:
193  speed = B1500000;
194  break;
195 #endif
196 #ifdef B2000000
197  case 2000000:
198  speed = B2000000;
199  break;
200 #endif
201 #ifdef B2500000
202  case 2500000:
203  speed = B2500000;
204  break;
205 #endif
206 #ifdef B3000000
207  case 3000000:
208  speed = B3000000;
209  break;
210 #endif
211 #ifdef B3500000
212  case 3500000:
213  speed = B3500000;
214  break;
215 #endif
216 #ifdef B4000000
217  case 4000000:
218  speed = B4000000;
219  break;
220 #endif
221  default:
222 #if defined __linux__
223  speed = B38400;
224  use_custom_divisor = 1;
225  break;
226 #else
227  log_trace("tty_setbaud(): bad baud rate %d", baud);
228  return 0;
229 #endif
230  }
231  if (tcgetattr(fd, &options) == -1) {
232  log_trace("tty_setbaud(): tcgetattr() failed");
233  log_perror_debug("tty_setbaud()");
234  return 0;
235  }
236  (void)cfsetispeed(&options, speed);
237  (void)cfsetospeed(&options, speed);
238  if (tcsetattr(fd, TCSAFLUSH, &options) == -1) {
239  log_trace("tty_setbaud(): tcsetattr() failed");
240  log_perror_debug("tty_setbaud()");
241  return 0;
242  }
243 #if defined __linux__
244  if (use_custom_divisor) {
245  if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
246  log_trace("tty_setbaud(): TIOCGSERIAL failed");
247  log_perror_debug("tty_setbaud()");
248  return 0;
249  }
250  serinfo.flags &= ~ASYNC_SPD_MASK;
251  serinfo.flags |= ASYNC_SPD_CUST;
252  serinfo.custom_divisor = serinfo.baud_base / baud;
253  if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) {
254  log_trace("tty_setbaud(): TIOCSSERIAL failed");
255  log_perror_debug("tty_setbaud()");
256  return 0;
257  }
258  }
259 #endif
260  return 1;
261 }
262 
263 int tty_setcsize(int fd, int csize)
264 {
265  struct termios options;
266  int size;
267 
268  switch (csize) {
269  case 5:
270  size = CS5;
271  break;
272  case 6:
273  size = CS6;
274  break;
275  case 7:
276  size = CS7;
277  break;
278  case 8:
279  size = CS8;
280  break;
281  default:
282  log_trace("tty_setcsize(): bad csize rate %d", csize);
283  return 0;
284  }
285  if (tcgetattr(fd, &options) == -1) {
286  log_trace("tty_setcsize(): tcgetattr() failed");
287  log_perror_debug("tty_setcsize()");
288  return 0;
289  }
290  options.c_cflag &= ~CSIZE;
291  options.c_cflag |= size;
292  if (tcsetattr(fd, TCSAFLUSH, &options) == -1) {
293  log_trace("tty_setcsize(): tcsetattr() failed");
294  log_perror_debug("tty_setcsize()");
295  return 0;
296  }
297  return 1;
298 }
299 
300 int tty_create_lock(const char* name)
301 {
302  char filename[FILENAME_MAX + 1];
303  char symlink[FILENAME_MAX + 1];
304  char cwd[FILENAME_MAX + 1];
305  const char* last;
306  const char* s;
307  char id[10 + 1 + 1];
308  int lock;
309  int len;
310 
311  strcpy(filename, LIRC_LOCKDIR "/LCK..");
312 
313  last = strrchr(name, '/');
314  if (last != NULL)
315  s = last + 1;
316  else
317  s = name;
318 
319  if (strlen(filename) + strlen(s) > FILENAME_MAX) {
320  log_error("invalid filename \"%s%s\"", filename, s);
321  return 0;
322  }
323  strcat(filename, s);
324 
325 tty_create_lock_retry:
326  len = snprintf(id, 10 + 1 + 1, "%10d\n", getpid());
327  if (len == -1) {
328  log_error("invalid pid \"%d\"", getpid());
329  return 0;
330  }
331  lock = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
332  if (lock == -1) {
333  log_perror_err("could not create lock file \"%s\"", filename);
334  lock = open(filename, O_RDONLY);
335  if (lock != -1) {
336  pid_t otherpid;
337 
338  id[10 + 1] = 0;
339  if (read(lock, id, 10 + 1) == 10 + 1 && read(lock, id, 1) == 0
340  && sscanf(id, "%d\n", &otherpid) > 0) {
341  if (kill(otherpid, 0) == -1 && errno == ESRCH) {
342  log_warn("detected stale lockfile %s", filename);
343  close(lock);
344  if (unlink(filename) != -1) {
345  log_warn("stale lockfile removed");
346  goto tty_create_lock_retry;
347  } else {
349  "could not remove stale lockfile");
350  }
351  return 0;
352  }
353  log_error("%s is locked by PID %d", name, otherpid);
354  } else {
355  log_error("invalid lockfile %s encountered", filename);
356  }
357  close(lock);
358  }
359  return 0;
360  }
361  if (write(lock, id, len) != len) {
362  log_perror_err("could not write pid to lock file");
363  close(lock);
364  if (unlink(filename) == -1)
365  log_perror_err("could not delete file \"%s\"", filename);
366  /* FALLTHROUGH */
367  return 0;
368  }
369  if (close(lock) == -1) {
370  log_perror_err("could not close lock file");
371  if (unlink(filename) == -1)
372  log_perror_err("could not delete file \"%s\"", filename);
373  /* FALLTHROUGH */
374  return 0;
375  }
376 
377  len = readlink(name, symlink, FILENAME_MAX);
378  if (len == -1) {
379  if (errno != EINVAL) { /* symlink */
380  log_perror_err("readlink() failed for \"%s\"", name);
381  if (unlink(filename) == -1) {
382  log_perror_err("could not delete file \"%s\"",
383  filename);
384  /* FALLTHROUGH */
385  }
386  return 0;
387  }
388  } else {
389  symlink[len] = 0;
390 
391  if (last) {
392  char dirname[FILENAME_MAX + 1];
393 
394  if (getcwd(cwd, FILENAME_MAX) == NULL) {
395  log_perror_err("getcwd() failed");
396  if (unlink(filename) == -1) {
398  "could not delete file \"%s\"",
399  filename);
400  /* FALLTHROUGH */
401  }
402  return 0;
403  }
404 
405  strcpy(dirname, name);
406  dirname[strlen(name) - strlen(last)] = 0;
407  if (chdir(dirname) == -1) {
409  "chdir() to \"%s\" failed", dirname);
410  if (unlink(filename) == -1) {
412  "could not delete file \"%s\"",
413  filename);
414  /* FALLTHROUGH */
415  }
416  return 0;
417  }
418  }
419  if (tty_create_lock(symlink) == -1) {
420  if (unlink(filename) == -1) {
422  "could not delete file \"%s\"", filename);
423  /* FALLTHROUGH */
424  }
425  return 0;
426  }
427  if (last) {
428  if (chdir(cwd) == -1) {
429  log_perror_err("chdir() to \"%s\" failed", cwd);
430  if (unlink(filename) == -1) {
432  "could not delete file \"%s\"",
433  filename);
434  /* FALLTHROUGH */
435  }
436  return 0;
437  }
438  }
439  }
440  return 1;
441 }
442 
444 {
445  DIR* dp;
446  struct dirent* ep;
447  int lock;
448  int len;
449  char id[20] = { '\0' };
450  char filename[FILENAME_MAX + 1];
451  long pid;
452  int retval = 1;
453 
454  dp = opendir(LIRC_LOCKDIR);
455  if (dp != NULL) {
456  while ((ep = readdir(dp))) {
457  if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) {
458  retval = 0;
459  continue;
460  }
461  strcpy(filename, LIRC_LOCKDIR "/");
462  if (strlen(filename) + strlen(ep->d_name) > FILENAME_MAX) {
463  retval = 0;
464  continue;
465  }
466  strcat(filename, ep->d_name);
467  if (strstr(filename, "LCK..") == NULL) {
468  log_debug("Ignoring non-LCK.. logfile %s",
469  filename);
470  retval = 0;
471  continue;
472  }
473  lock = open(filename, O_RDONLY);
474  if (lock == -1) {
475  retval = 0;
476  continue;
477  }
478  len = read(lock, id, sizeof(id) - 1);
479  close(lock);
480  if (len <= 0) {
481  retval = 0;
482  continue;
483  }
484  pid = strtol(id, NULL, 10);
485  if (pid == LONG_MIN || pid == LONG_MAX || pid == 0) {
486  log_debug("Can't parse lockfile %s (ignored)",
487  filename);
488  retval = 0;
489  continue;
490  }
491  if (pid == getpid()) {
492  if (unlink(filename) == -1) {
494  "could not delete file \"%s\"",
495  filename);
496  retval = 0;
497  continue;
498  }
499  }
500  }
501  closedir(dp);
502  } else {
503  log_error("could not open directory \"" LIRC_LOCKDIR "\"");
504  return 0;
505  }
506  return retval;
507 }
508 
509 int tty_set(int fd, int rts, int dtr)
510 {
511  int mask;
512 
513  mask = rts ? TIOCM_RTS : 0;
514  mask |= dtr ? TIOCM_DTR : 0;
515  if (ioctl(fd, TIOCMBIS, &mask) == -1) {
516  log_trace("tty_set(): ioctl() failed");
517  log_perror_warn("tty_set()");
518  return 0;
519  }
520  return 1;
521 }
522 
523 int tty_clear(int fd, int rts, int dtr)
524 {
525  int mask;
526 
527  mask = rts ? TIOCM_RTS : 0;
528  mask |= dtr ? TIOCM_DTR : 0;
529  if (ioctl(fd, TIOCMBIC, &mask) == -1) {
530  log_perror_debug("tty_clear()");
531  log_trace("tty_clear(): ioctl() failed");
532  return 0;
533  }
534  return 1;
535 }
536 
537 int tty_write(int fd, char byte)
538 {
539  if (write(fd, &byte, 1) != 1) {
540  log_trace("tty_write(): write() failed");
541  log_perror_debug("tty_write()");
542  return -1;
543  }
544  /* wait until the stop bit of Control Byte is sent
545  * (for 9600 baud rate, it takes about 100 msec */
546  usleep(100 * 1000);
547 
548  /* we don't wait because tcdrain() does this for us */
549  /* tcdrain(fd); */
550  /* FIXME! but unfortunately this does not seem to be
551  * implemented in 2.0.x kernels ... */
552  return 1;
553 }
554 
555 int tty_read(int fd, char* byte)
556 {
557  struct pollfd pfd = {.fd = fd, .events = POLLIN, .revents = 0};
558  int ret;
559 
560  ret = poll(&pfd, 1, 1000); /* 1 second timeout. */
561  if (ret == 0) {
562  log_error("tty_read(): timeout");
563  return -1; /* received nothing, bad */
564  } else if (ret != 1) {
565  log_perror_debug("tty_read(): poll() failed");
566  return -1;
567  }
568  if (read(fd, byte, 1) != 1) {
569  log_perror_debug("tty_read(): read() failed");
570  return -1;
571  }
572  return 1;
573 }
574 
575 int tty_write_echo(int fd, char byte)
576 {
577  char reply;
578 
579  if (tty_write(fd, byte) == -1)
580  return -1;
581  if (tty_read(fd, &reply) == -1)
582  return -1;
583  log_trace("sent: A%u D%01x reply: A%u D%01x", (((unsigned int)(unsigned char)byte) & 0xf0) >> 4,
584  ((unsigned int)(unsigned char)byte) & 0x0f, (((unsigned int)(unsigned char)reply) & 0xf0) >> 4,
585  ((unsigned int)(unsigned char)reply) & 0x0f);
586  if (byte != reply)
587  log_error("Command mismatch.");
588  return 1;
589 }
int tty_setrtscts(int fd, int enable)
Definition: serial.c:70
#define log_debug(fmt,...)
Definition: lirc_log.h:124
#define log_perror_debug(fmt,...)
Definition: lirc_log.h:99
int tty_setdtr(int fd, int enable)
Definition: serial.c:91
int tty_delete_lock(void)
Definition: serial.c:443
#define log_warn(fmt,...)
Definition: lirc_log.h:109
logchannel_t
Definition: lirc_log.h:53
int tty_reset(int fd)
Definition: serial.c:52
int tty_create_lock(const char *name)
Definition: serial.c:300
#define log_error(fmt,...)
Definition: lirc_log.h:104
int tty_write(int fd, char byte)
Definition: serial.c:537
int tty_clear(int fd, int rts, int dtr)
Definition: serial.c:523
int tty_setcsize(int fd, int csize)
Definition: serial.c:263
#define log_trace(fmt,...)
Definition: lirc_log.h:129
#define log_perror_err(fmt,...)
Definition: lirc_log.h:89
int tty_write_echo(int fd, char byte)
Definition: serial.c:575
int tty_read(int fd, char *byte)
Definition: serial.c:555
int tty_setbaud(int fd, int baud)
Definition: serial.c:118
#define log_perror_warn(fmt,...)
Definition: lirc_log.h:94
int tty_set(int fd, int rts, int dtr)
Definition: serial.c:509