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