1
/* $Id: drv_generic_serial.c 890 2008-08-31 18:27:53Z sonic74 $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_generic_serial.c $
4
* generic driver helper for serial and usbserial displays
6
* Copyright (C) 1999, 2000 Michael Reinelt <michael@reinelt.co.at>
7
* Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
9
* This file is part of LCD4Linux.
11
* LCD4Linux is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2, or (at your option)
16
* LCD4Linux is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
* int drv_generic_serial_open (char *section, char *driver, unsigned int flags)
32
* opens the serial port
34
* int drv_generic_serial_poll (char *string, int len)
35
* reads from the serial or USB port
38
* int drv_generic_serial_read (char *string, int len);
39
* reads from the serial or USB port
42
* void drv_generic_serial_write (char *string, int len);
43
* writes to the serial or USB port
45
* int drv_generic_serial_close (void);
46
* closes the serial port
61
#include <sys/types.h>
67
#include "drv_generic_serial.h"
70
extern int got_signal;
76
static int Device = -1;
79
#define LOCK "/var/lock/LCK..%s"
82
/****************************************/
83
/*** generic serial/USB communication ***/
84
/****************************************/
86
static pid_t drv_generic_serial_lock_port(const char *Port)
94
if (strncmp(Port, "/dev/", 5) == 0) {
95
port = strdup(Port + 5);
100
while ((p = strchr(port, '/')) != NULL) {
104
qprintf(lockfile, sizeof(lockfile), LOCK, port);
105
qprintf(tempfile, sizeof(tempfile), LOCK, "TMP.XXXXXX");
109
if ((fd = mkstemp(tempfile)) == -1) {
110
error("mkstemp(%s) failed: %s", tempfile, strerror(errno));
114
if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
115
error("fchmod(%s) failed: %s", tempfile, strerror(errno));
121
snprintf(buffer, sizeof(buffer), "%10d\n", (int) getpid());
122
len = strlen(buffer);
123
if (write(fd, buffer, len) != len) {
124
error("write(%s) failed: %s", tempfile, strerror(errno));
132
while (link(tempfile, lockfile) == -1) {
134
if (errno != EEXIST) {
135
error("link(%s, %s) failed: %s", tempfile, lockfile, strerror(errno));
140
if ((fd = open(lockfile, O_RDONLY)) == -1) {
142
continue; /* lockfile disappared */
143
error("open(%s) failed: %s", lockfile, strerror(errno));
148
len = read(fd, buffer, sizeof(buffer) - 1);
150
error("read(%s) failed: %s", lockfile, strerror(errno));
156
if (sscanf(buffer, "%d", &pid) != 1 || pid == 0) {
157
error("scan(%s) failed.", lockfile);
162
if (pid == getpid()) {
163
error("%s already locked by us. uh-oh...", lockfile);
168
if ((kill(pid, 0) == -1) && errno == ESRCH) {
169
error("removing stale lockfile %s", lockfile);
170
if (unlink(lockfile) == -1 && errno != ENOENT) {
171
error("unlink(%s) failed: %s", lockfile, strerror(errno));
186
static pid_t drv_generic_serial_unlock_port(const char *Port)
191
if (strncmp(Port, "/dev/", 5) == 0) {
192
port = strdup(Port + 5);
197
while ((p = strchr(port, '/')) != NULL) {
201
qprintf(lockfile, sizeof(lockfile), LOCK, port);
209
int drv_generic_serial_open(const char *section, const char *driver, const unsigned int flags)
213
struct termios portset;
215
Section = (char *) section;
216
Driver = (char *) driver;
218
Port = cfg_get(section, "Port", NULL);
219
if (Port == NULL || *Port == '\0') {
220
error("%s: no '%s.Port' entry from %s", Driver, section, cfg_source());
224
if (cfg_number(section, "Speed", 19200, 1200, 230400, &i) < 0)
257
error("%s: unsupported speed '%d' from %s", Driver, i, cfg_source());
261
info("%s: using port '%s' at %d baud", Driver, Port, i);
263
if ((pid = drv_generic_serial_lock_port(Port)) != 0) {
265
error("%s: port %s could not be locked", Driver, Port);
267
error("%s: port %s is locked by process %d", Driver, Port, pid);
271
fd = open(Port, O_RDWR | O_NOCTTY | O_NDELAY);
273
error("%s: open(%s) failed: %s", Driver, Port, strerror(errno));
274
drv_generic_serial_unlock_port(Port);
278
if (tcgetattr(fd, &portset) == -1) {
279
error("%s: tcgetattr(%s) failed: %s", Driver, Port, strerror(errno));
280
drv_generic_serial_unlock_port(Port);
285
portset.c_cflag |= flags;
286
cfsetispeed(&portset, Speed);
287
cfsetospeed(&portset, Speed);
288
if (tcsetattr(fd, TCSANOW, &portset) == -1) {
289
error("%s: tcsetattr(%s) failed: %s", Driver, Port, strerror(errno));
290
drv_generic_serial_unlock_port(Port);
299
int drv_generic_serial_poll(char *string, const int len)
304
ret = read(Device, string, len);
305
if (ret < 0 && errno != EAGAIN) {
306
error("%s: read(%s) failed: %s", Driver, Port, strerror(errno));
312
int drv_generic_serial_read(char *string, const int len)
316
count = len < 0 ? -len : len;
318
for (run = 0; run < 10; run++) {
319
ret = drv_generic_serial_poll(string, count);
320
if (ret >= 0 || errno != EAGAIN)
322
info("%s: read(%s): EAGAIN", Driver, Port);
326
if (ret > 0 && ret != count && len > 0) {
327
error("%s: partial read(%s): len=%d ret=%d", Driver, Port, len, ret);
334
void drv_generic_serial_write(const char *string, const int len)
336
static int error = 0;
340
error("%s: write to closed port %s failed!", Driver, Port);
344
for (run = 0; run < 10; run++) {
345
ret = write(Device, string, len);
346
if (ret >= 0 || errno != EAGAIN) {
349
/* EAGAIN: retry 10 times, emit message after 2nd retry */
351
info("%s: write(%s): EAGAIN #%d", Driver, Port, run);
357
error("%s: write(%s) failed: %s", Driver, Port, strerror(errno));
359
error("%s: too much errors, giving up", Driver);
362
} else if (ret != len) {
363
error("%s: partial write(%s): len=%d ret=%d", Driver, Port, len, ret);
371
int drv_generic_serial_close(void)
373
info("%s: closing port %s", Driver, Port);
375
drv_generic_serial_unlock_port(Port);