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