/* Serial interface for local (hardwired) serial ports on Un*x like systems
- Copyright 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1992, 1993, 1994 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "serial.h"
#include <fcntl.h>
#include <sys/types.h>
-
-#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
-#define HAVE_SGTTY
+#include "terminal.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
#ifdef HAVE_TERMIOS
-#include <termios.h>
-#include <unistd.h>
struct hardwire_ttystate
{
struct termios termios;
- pid_t process_group;
};
#endif /* termios */
#ifdef HAVE_TERMIO
-#include <termio.h>
/* It is believed that all systems which have added job control to SVR3
(e.g. sco) have also added termios. Even if not, trying to figure out
too if it existed on all systems. */
#include <sys/time.h>
-#include <sgtty.h>
-
struct hardwire_ttystate
{
struct sgttyb sgttyb;
struct ltchars ltc;
/* Line discipline flags. */
int lmode;
-
-#ifdef SHORT_PGRP
- /* This is only used for the ultra. Does it have pid_t? */
- short process_group;
-#else
- int process_group;
-#endif
};
#endif /* sgtty */
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));
+/* FIXME: 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));
struct hardwire_ttystate *state;
{
#ifdef HAVE_TERMIOS
- pid_t new_process_group;
+ extern int errno;
if (tcgetattr(scb->fd, &state->termios) < 0)
return -1;
- if (!job_control)
- return 0;
-
- new_process_group = tcgetpgrp (scb->fd);
- if (new_process_group == (pid_t)-1)
- return -1;
- state->process_group = new_process_group;
return 0;
#endif
if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
return -1;
- if (!job_control)
- return 0;
-
- return ioctl (scb->fd, TIOCGPGRP, &state->process_group);
+ return 0;
#endif
}
if (tcsetattr(scb->fd, TCSANOW, &state->termios) < 0)
return -1;
- if (!job_control)
- return 0;
-
- return tcsetpgrp (scb->fd, state->process_group);
+ return 0;
#endif
#ifdef HAVE_TERMIO
#ifdef HAVE_SGTTY
if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0)
return -1;
+ if (ioctl (scb->fd, TIOCSETC, &state->tc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCSLTC, &state->ltc) < 0)
+ return -1;
+ if (ioctl (scb->fd, TIOCLSET, &state->lmode) < 0)
+ return -1;
- if (!job_control)
- return 0;
-
- return ioctl (scb->fd, TIOCSPGRP, &state->process_group);
+ return 0;
#endif
}
serial_ttystate old_ttystate;
{
struct hardwire_ttystate new_state;
+#ifdef HAVE_SGTTY
struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate;
+#endif
new_state = *(struct hardwire_ttystate *)new_ttystate;
-#ifdef HAVE_TERMIOS
- /* I'm not sure whether this is necessary; the manpage makes no mention
- of discarding input when switching to/from ICANON. */
- if (state->termios.c_lflag & ICANON)
- new_state.termios.c_lflag |= ICANON;
- else
- new_state.termios.c_lflag &= ~ICANON;
-#endif
-
-#ifdef HAVE_TERMIO
- /* I'm not sure whether this is necessary; the manpage makes no mention
- of discarding input when switching to/from ICANON. */
- if (state->termio.c_lflag & ICANON)
- new_state.termio.c_lflag |= ICANON;
- else
- new_state.termio.c_lflag &= ~ICANON;
-#endif
+ /* Don't change in or out of raw mode; we don't want to flush input.
+ termio and termios have no such restriction; for them flushing input
+ is separate from setting the attributes. */
#ifdef HAVE_SGTTY
if (state->sgttyb.sg_flags & RAW)
int i;
#ifdef HAVE_TERMIOS
- printf_filtered ("Process group = %d\n", state->process_group);
-
printf_filtered ("c_iflag = 0x%x, c_oflag = 0x%x,\n",
state->termios.c_iflag, state->termios.c_oflag);
printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x\n",
#endif
#ifdef HAVE_SGTTY
- printf_filtered ("Process group = %d\n", state->process_group);
-
printf_filtered ("sgttyb.sg_flags = 0x%x.\n", state->sgttyb.sg_flags);
printf_filtered ("tchars: ");
hardwire_flush_input (scb)
serial_t scb;
{
+ scb->bufcnt = 0;
+ scb->bufp = scb->buf;
+
#ifdef HAVE_TERMIOS
return tcflush (scb->fd, TCIFLUSH);
#endif
hardwire_send_break (scb)
serial_t scb;
{
- int status;
-
#ifdef HAVE_TERMIOS
return tcsendbreak (scb->fd, 0);
#endif
#endif
#ifdef HAVE_SGTTY
- status = ioctl (scb->fd, TIOCSBRK, 0);
- usleep (250000);
- status = ioctl (scb->fd, TIOCCBRK, 0);
- return status;
+ {
+ int status;
+ struct timeval timeout;
+
+ status = ioctl (scb->fd, TIOCSBRK, 0);
+
+ /* Can't use usleep; it doesn't exist in BSD 4.2. */
+ /* Note that if this select() is interrupted by a signal it will not wait
+ the full length of time. I think that is OK. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 250000;
+ select (0, 0, 0, 0, &timeout);
+ status = ioctl (scb->fd, TIOCCBRK, 0);
+ return status;
+ }
#endif
}
struct hardwire_ttystate state;
if (get_tty_state(scb, &state))
- fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+ fprintf_unfiltered(gdb_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_cflag |= CLOCAL | CS8;
state.termios.c_cc[VMIN] = 0;
state.termios.c_cc[VTIME] = 0;
#endif
state.termio.c_oflag = 0;
state.termio.c_lflag = 0;
state.termio.c_cflag &= ~(CSIZE|PARENB);
- state.termio.c_cflag |= CS8;
+ state.termio.c_cflag |= CLOCAL | CS8;
state.termio.c_cc[VMIN] = 0;
state.termio.c_cc[VTIME] = 0;
#endif
scb->current_timeout = 0;
if (set_tty_state (scb, &state))
- fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+ fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
}
/* Wait for input on scb, with timeout seconds. Returns 0 on success,
serial_t scb;
int timeout;
{
- int numfds;
+ scb->timeout_remaining = 0;
#ifdef HAVE_SGTTY
- struct timeval tv;
- fd_set readfds;
+ {
+ struct timeval tv;
+ fd_set readfds;
- FD_ZERO (&readfds);
+ FD_ZERO (&readfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
- FD_SET(scb->fd, &readfds);
+ FD_SET(scb->fd, &readfds);
- while (1)
- {
- 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 if (errno == EINTR)
- continue;
- else
- return SERIAL_ERROR; /* Got an error from select or poll */
-
- return 0;
- }
+ while (1)
+ {
+ int numfds;
+ 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 if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from select or poll */
+
+ return 0;
+ }
+ }
#endif /* HAVE_SGTTY */
#if defined HAVE_TERMIO || defined HAVE_TERMIOS
if (timeout == scb->current_timeout)
return 0;
+ scb->current_timeout = timeout;
+
{
struct hardwire_ttystate state;
if (get_tty_state(scb, &state))
- fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+ fprintf_unfiltered(gdb_stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
#ifdef HAVE_TERMIOS
- state.termios.c_cc[VTIME] = timeout * 10;
+ if (timeout < 0)
+ {
+ /* No timeout. */
+ state.termios.c_cc[VTIME] = 0;
+ state.termios.c_cc[VMIN] = 1;
+ }
+ else
+ {
+ state.termios.c_cc[VMIN] = 0;
+ state.termios.c_cc[VTIME] = timeout * 10;
+ if (state.termios.c_cc[VTIME] != timeout * 10)
+ {
+
+ /* If c_cc is an 8-bit signed character, we can't go
+ bigger than this. If it is always unsigned, we could use
+ 25. */
+
+ scb->current_timeout = 12;
+ state.termios.c_cc[VTIME] = scb->current_timeout * 10;
+ scb->timeout_remaining = timeout - scb->current_timeout;
+ }
+ }
#endif
#ifdef HAVE_TERMIO
- state.termio.c_cc[VTIME] = timeout * 10;
+ if (timeout < 0)
+ {
+ /* No timeout. */
+ state.termio.c_cc[VTIME] = 0;
+ state.termio.c_cc[VMIN] = 1;
+ }
+ else
+ {
+ state.termio.c_cc[VMIN] = 0;
+ state.termio.c_cc[VTIME] = timeout * 10;
+ if (state.termio.c_cc[VTIME] != timeout * 10)
+ {
+ /* If c_cc is an 8-bit signed character, we can't go
+ bigger than this. If it is always unsigned, we could use
+ 25. */
+
+ scb->current_timeout = 12;
+ state.termio.c_cc[VTIME] = scb->current_timeout * 10;
+ scb->timeout_remaining = timeout - scb->current_timeout;
+ }
+ }
#endif
- scb->current_timeout = timeout;
-
if (set_tty_state (scb, &state))
- fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
+ fprintf_unfiltered(gdb_stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
return 0;
}
/* 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). */
+ char if successful. Returns SERIAL_TIMEOUT if timeout expired, EOF if line
+ dropped dead, or SERIAL_ERROR for any other error (see errno in that case). */
static int
hardwire_readchar(scb, timeout)
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_TIMEOUT; /* 0 chars means timeout [may need to
- distinguish between EOF & timeouts
- someday] */
- else
- return SERIAL_ERROR; /* Got an error from read */
-
- scb->bufcnt--;
- scb->bufp = scb->buf;
- return *scb->bufp++;
+ while (1)
+ {
+ 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)
+ {
+ /* Zero characters means timeout (it could also be EOF, but
+ we don't (yet at least) distinguish). */
+ if (scb->timeout_remaining > 0)
+ {
+ timeout = scb->timeout_remaining;
+ continue;
+ }
+ else
+ return SERIAL_TIMEOUT;
+ }
+ else if (errno == EINTR)
+ continue;
+ else
+ return SERIAL_ERROR; /* Got an error from read */
+ }
+
+ scb->bufcnt--;
+ scb->bufp = scb->buf;
+ return *scb->bufp++;
+ }
}
#ifndef B19200
}
static int
-hardwire_set_process_group (scb, ttystate, group)
+hardwire_setstopbits(scb, num)
serial_t scb;
- serial_ttystate ttystate;
- int group;
+ int num;
{
-#if defined (HAVE_SGTTY) || defined (HAVE_TERMIOS)
- ((struct hardwire_ttystate *)ttystate)->process_group = group;
+ struct hardwire_ttystate state;
+ int newbit;
+
+ if (get_tty_state(scb, &state))
+ return -1;
+
+ switch (num)
+ {
+ case SERIAL_1_STOPBITS:
+ newbit = 0;
+ break;
+ case SERIAL_1_AND_A_HALF_STOPBITS:
+ case SERIAL_2_STOPBITS:
+ newbit = 1;
+ break;
+ default:
+ return 1;
+ }
+
+#ifdef HAVE_TERMIOS
+ if (!newbit)
+ state.termios.c_cflag &= ~CSTOPB;
+ else
+ state.termios.c_cflag |= CSTOPB; /* two bits */
#endif
- return 0;
+
+#ifdef HAVE_TERMIO
+ if (!newbit)
+ state.termio.c_cflag &= ~CSTOPB;
+ else
+ state.termio.c_cflag |= CSTOPB; /* two bits */
+#endif
+
+#ifdef HAVE_SGTTY
+ return 0; /* sgtty doesn't support this */
+#endif
+
+ return set_tty_state (scb, &state);
}
static int
hardwire_print_tty_state,
hardwire_noflush_set_tty_state,
hardwire_setbaudrate,
- hardwire_set_process_group
+ hardwire_setstopbits,
};
-int job_control;
-#if defined (HAVE_TERMIOS)
-#include <unistd.h>
-#endif
-
-/* This is here because this is where we figure out whether we (probably)
- have job control. Just using job_control only does part of it because
- setpgid or setpgrp might not exist on a system without job control.
- It might be considered misplaced (on the other hand, process groups and
- job control are closely related to ttys).
-
- For a more clean implementation, in libiberty, put a setpgid which merely
- calls setpgrp and a setpgrp which does nothing (any system with job control
- will have one or the other). */
-int
-gdb_setpgid ()
-{
- int retval = 0;
- if (job_control)
- {
-#if defined (NEED_POSIX_SETPGID) || defined (HAVE_TERMIOS)
- /* Do all systems with termios have setpgid? I hope so. */
- /* setpgid (0, 0) is supposed to work and mean the same thing as
- this, but on Ultrix 4.2A it fails with EPERM (and
- setpgid (getpid (), getpid ()) succeeds). */
- retval = setpgid (getpid (), getpid ());
-#else
-#if defined (TIOCGPGRP)
-#if defined(USG) && !defined(SETPGRP_ARGS)
- retval = setpgrp ();
-#else
- retval = setpgrp (getpid (), getpid ());
-#endif /* USG */
-#endif /* TIOCGPGRP. */
-#endif /* NEED_POSIX_SETPGID */
- }
- return retval;
-}
-
void
_initialize_ser_hardwire ()
{
serial_add_interface (&hardwire_ops);
-
- /* OK, figure out whether we have job control. */
-
-#if defined (HAVE_TERMIOS)
- /* Do all systems with termios have the POSIX way of identifying job
- control? I hope so. */
-#ifdef _POSIX_JOB_CONTROL
- job_control = 1;
-#else
- job_control = sysconf (_SC_JOB_CONTROL);
-#endif
-#endif /* termios */
-
-#ifdef HAVE_TERMIO
- /* See comment at top of file about trying to support process groups
- with termio. */
- job_control = 0;
-#endif /* termio */
-
-#ifdef HAVE_SGTTY
-#ifdef TIOCGPGRP
- job_control = 1;
-#else
- job_control = 0;
-#endif /* TIOCGPGRP */
-#endif /* sgtty */
-
}