#include "serial.h"
#include <fcntl.h>
#include <sys/types.h>
-
-/* Note: HAVE_SELECT is not yet defined on all the systems which could
- define it. The USE_ALARM_TIMEOUT code seems to work OK, though, so
- it doesn't really matter. */
-#if !defined (HAVE_SELECT)
-#if defined (HAVE_TERMIO)
-#define USE_TERMIO_TIMEOUT 1
-#else
-#define USE_ALARM_TIMEOUT 1
-#endif
-#endif
-
-#if defined (HAVE_SELECT)
#include <sys/time.h>
-#endif
-#ifdef USE_ALARM_TIMEOUT
-#include <signal.h>
-#endif
#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
#define HAVE_SGTTY
#ifdef HAVE_TERMIOS
#include <termios.h>
#include <unistd.h>
+
+struct hardwire_ttystate
+{
+ struct termios termios;
+};
#endif
+
#ifdef HAVE_TERMIO
-#include <sys/termio.h>
+#include <termio.h>
+
+struct hardwire_ttystate
+{
+ struct termio termio;
+};
#endif
+
#ifdef HAVE_SGTTY
#include <sgtty.h>
+
+struct hardwire_ttystate
+{
+ struct sgttyb sgttyb;
+};
#endif
+static int hardwire_open PARAMS ((serial_t scb, const char *name));
+static void hardwire_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int hardwire_readchar PARAMS ((serial_t scb, int timeout));
+static int rate_to_code PARAMS ((int rate));
+static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate));
+static int hardwire_write PARAMS ((serial_t scb, const char *str, int len));
+static void hardwire_restore PARAMS ((serial_t scb));
+static void hardwire_close PARAMS ((serial_t scb));
+static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb));
+static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
/* Open up a real live device for serial I/O */
static int
return 0;
}
-static void
-hardwire_raw(scb)
+static int
+get_tty_state(scb, state)
serial_t scb;
+ struct hardwire_ttystate *state;
{
#ifdef HAVE_TERMIOS
- struct termios termios;
+ return tcgetattr(scb->fd, &state->termios);
+#endif
- if (tcgetattr(scb->fd, &termios))
- {
- fprintf(stderr, "tcgetattr failed: %s\n", safe_strerror(errno));
- }
+#ifdef HAVE_TERMIO
+ return ioctl (scb->fd, TCGETA, &state->termio);
+#endif
- termios.c_iflag = 0;
- termios.c_oflag = 0;
- termios.c_lflag = 0;
- termios.c_cflag &= ~(CSIZE|PARENB);
- termios.c_cflag |= CS8;
- termios.c_cc[VMIN] = 0;
- termios.c_cc[VTIME] = 0;
+#ifdef HAVE_SGTTY
+ return ioctl (scb->fd, TIOCGETP, &state->sgttyb);
+#endif
+}
- if (tcsetattr(scb->fd, TCSANOW, &termios))
- {
- fprintf(stderr, "tcsetattr failed: %s\n", safe_strerror(errno));
- }
+static int
+set_tty_state(scb, state)
+ serial_t scb;
+ struct hardwire_ttystate *state;
+{
+ int err;
+
+#ifdef HAVE_TERMIOS
+ return tcsetattr(scb->fd, TCSANOW, &state->termios);
#endif
#ifdef HAVE_TERMIO
- struct termio termio;
+ return ioctl (scb->fd, TCSETA, &state->termio);
+#endif
- if (ioctl (scb->fd, TCGETA, &termio))
- {
- fprintf(stderr, "TCGETA failed: %s\n", safe_strerror(errno));
- }
+#ifdef HAVE_SGTTY
+ return ioctl (scb->fd, TIOCSETP, &state->sgttyb);
+#endif
+}
- termio.c_iflag = 0;
- termio.c_oflag = 0;
- termio.c_lflag = 0;
- termio.c_cflag &= ~(CSIZE|PARENB);
- termio.c_cflag |= CS8;
- termio.c_cc[VMIN] = 0;
- termio.c_cc[VTIME] = 0;
+static serial_ttystate
+hardwire_get_tty_state(scb)
+ serial_t scb;
+{
+ struct hardwire_ttystate *state;
- if (ioctl (scb->fd, TCSETA, &termio))
- {
- fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
- }
-#endif
+ state = (struct hardwire_ttystate *)xmalloc(sizeof *state);
-#ifdef HAVE_SGTTY
- struct sgttyb sgttyb;
+ if (get_tty_state(scb, state))
+ return NULL;
- if (ioctl (scb->fd, TIOCGETP, &sgttyb))
- fprintf(stderr, "TIOCGETP failed: %s\n", safe_strerror(errno));
+ return (serial_ttystate)state;
+}
- sgttyb.sg_flags |= RAW | ANYP;
- sgttyb.sg_flags &= ~(CBREAK | ECHO);
+static int
+hardwire_set_tty_state(scb, ttystate)
+ serial_t scb;
+ serial_ttystate ttystate;
+{
+ struct hardwire_ttystate *state;
- if (ioctl (scb->fd, TIOCSETP, &sgttyb))
- fprintf(stderr, "TIOCSETP failed: %s\n", safe_strerror(errno));
-#endif
+ state = (struct hardwire_ttystate *)ttystate;
+
+ return set_tty_state(scb, state);
}
-#ifdef USE_ALARM_TIMEOUT
-/* Called when SIGALRM sent. */
static void
-remote_timer ()
+hardwire_raw(scb)
+ serial_t scb;
{
-}
+ struct hardwire_ttystate state;
+
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_iflag = 0;
+ state.termios.c_oflag = 0;
+ state.termios.c_lflag = 0;
+ state.termios.c_cflag &= ~(CSIZE|PARENB);
+ state.termios.c_cflag |= CS8;
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = 0;
#endif
-/* Read a character with user-specified timeout. TIMEOUT is number of seconds
- to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
- char if successful. Returns -2 if timeout expired, EOF if line dropped
- dead, or -3 for any other error (see errno in that case). */
+#ifdef HAVE_TERMIO
+ state.termio.c_iflag = 0;
+ state.termio.c_oflag = 0;
+ state.termio.c_lflag = 0;
+ state.termio.c_cflag &= ~(CSIZE|PARENB);
+ state.termio.c_cflag |= CS8;
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_SGTTY
+ state.sgttyb.sg_flags |= RAW | ANYP;
+ state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
+#endif
+
+ scb->current_timeout = 0;
+
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+}
+
+/* Wait for input on scb, with timeout seconds. Returns 0 on success,
+ otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+ For termio{s}, we actually just setup VTIME if necessary, and let the
+ timeout occur in the read() in hardwire_read().
+ */
static int
-hardwire_readchar(scb, timeout)
+wait_for(scb, timeout)
serial_t scb;
int timeout;
{
- if (scb->bufcnt-- > 0)
- return *scb->bufp++;
+ int numfds;
-#ifdef HAVE_SELECT
- {
- int numfds;
- struct timeval tv;
- fd_set readfds;
-
- FD_ZERO (&readfds);
+#ifdef HAVE_SGTTY
+ struct timeval tv;
+ fd_set readfds;
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ FD_ZERO (&readfds);
- FD_SET(scb->fd, &readfds);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
- if (timeout >= 0)
- numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+ FD_SET(scb->fd, &readfds);
+
+ if (timeout >= 0)
+ numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+
+ if (numfds <= 0)
+ if (numfds == 0)
+ return SERIAL_TIMEOUT;
else
- numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+ return SERIAL_ERROR; /* Got an error from select or poll */
+
+ return 0;
- if (numfds <= 0)
- if (numfds == 0)
- return SERIAL_TIMEOUT;
- else
- return SERIAL_ERROR; /* Got an error from select */
+#endif /* HAVE_SGTTY */
- scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
- }
-#endif /* HAVE_SELECT. */
+#if defined HAVE_TERMIO || defined HAVE_TERMIOS
+ if (timeout == scb->current_timeout)
+ return 0;
-#ifdef USE_TERMIO_TIMEOUT
{
- struct termio termio;
+ struct hardwire_ttystate state;
- if (ioctl (scb->fd, TCGETA, &termio))
- {
- fprintf(stderr, "TCGETA failed: %s\n", safe_strerror(errno));
- }
+ if (get_tty_state(scb, &state))
+ fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
- termio.c_cc[VTIME] = timeout * 10;
+#ifdef HAVE_TERMIOS
+ state.termios.c_cc[VTIME] = timeout * 10;
+#endif
- if (ioctl (scb->fd, TCSETA, &termio))
- {
- fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
- }
+#ifdef HAVE_TERMIO
+ state.termio.c_cc[VTIME] = timeout * 10;
+#endif
- scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
- if (scb->bufcnt == 0)
- /* Can this also mean end of file? Does "end of file" have any
- meaning with ICANON clear? */
- return SERIAL_TIMEOUT;
- }
-#endif /* USE_TERMIO_TIMEOUT. */
+ scb->current_timeout = timeout;
-#ifdef USE_ALARM_TIMEOUT
- {
- void (*old_sigalrm_handler) ();
- int save_errno;
-#ifndef NO_SIGINTERRUPT
- /* Cause SIGARLM to make read fail with EINTR. */
- if (siginterrupt (SIGALRM, 1) != 0)
- fprintf (stderr, "siginterrupt failed: %s\n", safe_strerror (errno));
-#endif
+ if (set_tty_state (scb, &state))
+ fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
- old_sigalrm_handler = (void (*) ()) signal (SIGALRM, remote_timer);
- if (old_sigalrm_handler == (void (*) ()) -1)
- fprintf (stderr, "signal failed: %s\n", safe_strerror (errno));
-
- alarm (timeout);
- scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
- save_errno = errno;
- alarm (0);
- signal (SIGALRM, old_sigalrm_handler);
- if (scb->bufcnt < 0 && errno == EINTR)
- {
- return SERIAL_TIMEOUT;
- }
+ return 0;
}
-#endif /* USE_ALARM_TIMEOUT */
+#endif /* HAVE_TERMIO || HAVE_TERMIOS */
+}
+
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns -2 if timeout expired, EOF if line dropped
+ dead, or -3 for any other error (see errno in that case). */
+
+static int
+hardwire_readchar(scb, timeout)
+ serial_t scb;
+ int timeout;
+{
+ int status;
+
+ if (scb->bufcnt-- > 0)
+ return *scb->bufp++;
+
+ status = wait_for(scb, timeout);
+
+ if (status < 0)
+ return status;
+
+ scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
if (scb->bufcnt <= 0)
if (scb->bufcnt == 0)
- return SERIAL_EOF; /* 0 chars means end of file */
+ return SERIAL_TIMEOUT; /* 0 chars means timeout [may need to
+ distinguish between EOF & timeouts
+ someday] */
else
return SERIAL_ERROR; /* Got an error from read */
serial_t scb;
int rate;
{
-#ifdef HAVE_TERMIOS
- struct termios termios;
+ struct hardwire_ttystate state;
- if (tcgetattr (scb->fd, &termios))
+ if (get_tty_state(scb, &state))
return -1;
- cfsetospeed (&termios, rate_to_code (rate));
- cfsetispeed (&termios, rate_to_code (rate));
-
- if (tcsetattr (scb->fd, TCSANOW, &termios))
- return -1;
+#ifdef HAVE_TERMIOS
+ cfsetospeed (&state.termios, rate_to_code (rate));
+ cfsetispeed (&state.termios, rate_to_code (rate));
#endif
#ifdef HAVE_TERMIO
- struct termio termio;
-
- if (ioctl (scb->fd, TCGETA, &termio))
- return -1;
-
#ifndef CIBAUD
#define CIBAUD CBAUD
#endif
- termio.c_cflag &= ~(CBAUD | CIBAUD);
- termio.c_cflag |= rate_to_code (rate);
-
- if (ioctl (scb->fd, TCSETA, &termio))
- return -1;
+ state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+ state.termio.c_cflag |= rate_to_code (rate);
#endif
#ifdef HAVE_SGTTY
- struct sgttyb sgttyb;
-
- if (ioctl (scb->fd, TIOCGETP, &sgttyb))
- return -1;
-
- sgttyb.sg_ispeed = rate_to_code (rate);
- sgttyb.sg_ospeed = rate_to_code (rate);
-
- if (ioctl (scb->fd, TIOCSETP, &sgttyb))
- return -1;
+ state.sgttyb.sg_ispeed = rate_to_code (rate);
+ state.sgttyb.sg_ospeed = rate_to_code (rate);
#endif
- return 0;
+
+ return set_tty_state (scb, &state);
}
static int
return 0;
}
-static void
-hardwire_restore(scb)
- serial_t scb;
-{
-}
-
static void
hardwire_close(scb)
serial_t scb;
hardwire_readchar,
hardwire_write,
hardwire_raw,
- hardwire_restore,
- hardwire_setbaudrate
+ hardwire_get_tty_state,
+ hardwire_set_tty_state,
+ hardwire_setbaudrate,
};
+void
_initialize_ser_hardwire ()
{
serial_add_interface (&hardwire_ops);