LIRC libraries LinuxInfraredRemoteControl

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Examples

- File List
- Globals

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
440 int tty_delete_lock(void)
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 }
tty_setrtscts
int tty_setrtscts(int fd, int enable)
Definition: serial.c:67
tty_setdtr
int tty_setdtr(int fd, int enable)
Definition: serial.c:88
tty_delete_lock
int tty_delete_lock(void)
Definition: serial.c:440
tty_reset
int tty_reset(int fd)
Definition: serial.c:49
tty_create_lock
int tty_create_lock(const char *name)
Definition: serial.c:297
tty_write
int tty_write(int fd, char byte)
Definition: serial.c:536
tty_clear
int tty_clear(int fd, int rts, int dtr)
Definition: serial.c:522
LOGPERROR
#define LOGPERROR(level, s)
Definition: lirc_log.h:83
tty_setcsize
int tty_setcsize(int fd, int csize)
Definition: serial.c:260
tty_write_echo
int tty_write_echo(int fd, char byte)
Definition: serial.c:574
tty_read
int tty_read(int fd, char *byte)
Definition: serial.c:554
tty_setbaud
int tty_setbaud(int fd, int baud)
Definition: serial.c:115
LOGPRINTF
#define LOGPRINTF(level, fmt, args...)
Definition: lirc_log.h:75
logperror
void logperror(loglevel_t prio, const char *fmt,...)
Definition: lirc_log.c:289
tty_set
int tty_set(int fd, int rts, int dtr)
Definition: serial.c:508