OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [ser-unix.c] - Diff between revs 105 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 105 Rev 1765
/* Serial interface for local (hardwired) serial ports on Un*x like systems
/* Serial interface for local (hardwired) serial ports on Un*x like systems
   Copyright 1992-1994, 1998-2000 Free Software Foundation, Inc.
   Copyright 1992-1994, 1998-2000 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
   Boston, MA 02111-1307, USA.  */
 
 
#include "defs.h"
#include "defs.h"
#include "serial.h"
#include "serial.h"
#include "ser-unix.h"
#include "ser-unix.h"
 
 
#include <fcntl.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/types.h>
#include "terminal.h"
#include "terminal.h"
#include "gdb_wait.h"
#include "gdb_wait.h"
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/time.h>
 
 
#include "gdb_string.h"
#include "gdb_string.h"
#include "event-loop.h"
#include "event-loop.h"
 
 
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
 
 
struct hardwire_ttystate
struct hardwire_ttystate
  {
  {
    struct termios termios;
    struct termios termios;
  };
  };
#endif /* termios */
#endif /* termios */
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
 
 
/* It is believed that all systems which have added job control to SVR3
/* 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
   (e.g. sco) have also added termios.  Even if not, trying to figure out
   all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty
   all the variations (TIOCGPGRP vs. TCGETPGRP, etc.) would be pretty
   bewildering.  So we don't attempt it.  */
   bewildering.  So we don't attempt it.  */
 
 
struct hardwire_ttystate
struct hardwire_ttystate
  {
  {
    struct termio termio;
    struct termio termio;
  };
  };
#endif /* termio */
#endif /* termio */
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
struct hardwire_ttystate
struct hardwire_ttystate
  {
  {
    struct sgttyb sgttyb;
    struct sgttyb sgttyb;
    struct tchars tc;
    struct tchars tc;
    struct ltchars ltc;
    struct ltchars ltc;
    /* Line discipline flags.  */
    /* Line discipline flags.  */
    int lmode;
    int lmode;
  };
  };
#endif /* sgtty */
#endif /* sgtty */
 
 
static int hardwire_open (serial_t scb, const char *name);
static int hardwire_open (serial_t scb, const char *name);
static void hardwire_raw (serial_t scb);
static void hardwire_raw (serial_t scb);
static int wait_for (serial_t scb, int timeout);
static int wait_for (serial_t scb, int timeout);
static int hardwire_readchar (serial_t scb, int timeout);
static int hardwire_readchar (serial_t scb, int timeout);
static int do_hardwire_readchar (serial_t scb, int timeout);
static int do_hardwire_readchar (serial_t scb, int timeout);
static int generic_readchar (serial_t scb, int timeout, int (*do_readchar) (serial_t scb, int timeout));
static int generic_readchar (serial_t scb, int timeout, int (*do_readchar) (serial_t scb, int timeout));
static int rate_to_code (int rate);
static int rate_to_code (int rate);
static int hardwire_setbaudrate (serial_t scb, int rate);
static int hardwire_setbaudrate (serial_t scb, int rate);
static void hardwire_close (serial_t scb);
static void hardwire_close (serial_t scb);
static int get_tty_state (serial_t scb, struct hardwire_ttystate * state);
static int get_tty_state (serial_t scb, struct hardwire_ttystate * state);
static int set_tty_state (serial_t scb, struct hardwire_ttystate * state);
static int set_tty_state (serial_t scb, struct hardwire_ttystate * state);
static serial_ttystate hardwire_get_tty_state (serial_t scb);
static serial_ttystate hardwire_get_tty_state (serial_t scb);
static int hardwire_set_tty_state (serial_t scb, serial_ttystate state);
static int hardwire_set_tty_state (serial_t scb, serial_ttystate state);
static int hardwire_noflush_set_tty_state (serial_t, serial_ttystate,
static int hardwire_noflush_set_tty_state (serial_t, serial_ttystate,
                                                   serial_ttystate);
                                                   serial_ttystate);
static void hardwire_print_tty_state (serial_t, serial_ttystate, struct ui_file *);
static void hardwire_print_tty_state (serial_t, serial_ttystate, struct ui_file *);
static int hardwire_drain_output (serial_t);
static int hardwire_drain_output (serial_t);
static int hardwire_flush_output (serial_t);
static int hardwire_flush_output (serial_t);
static int hardwire_flush_input (serial_t);
static int hardwire_flush_input (serial_t);
static int hardwire_send_break (serial_t);
static int hardwire_send_break (serial_t);
static int hardwire_setstopbits (serial_t, int);
static int hardwire_setstopbits (serial_t, int);
 
 
static int do_unix_readchar (serial_t scb, int timeout);
static int do_unix_readchar (serial_t scb, int timeout);
static timer_handler_func push_event;
static timer_handler_func push_event;
static handler_func fd_event;
static handler_func fd_event;
static void reschedule (serial_t scb);
static void reschedule (serial_t scb);
 
 
void _initialize_ser_hardwire (void);
void _initialize_ser_hardwire (void);
 
 
extern int (*ui_loop_hook) (int);
extern int (*ui_loop_hook) (int);
 
 
/* Open up a real live device for serial I/O */
/* Open up a real live device for serial I/O */
 
 
static int
static int
hardwire_open (serial_t scb, const char *name)
hardwire_open (serial_t scb, const char *name)
{
{
  scb->fd = open (name, O_RDWR);
  scb->fd = open (name, O_RDWR);
  if (scb->fd < 0)
  if (scb->fd < 0)
    return -1;
    return -1;
 
 
  return 0;
  return 0;
}
}
 
 
static int
static int
get_tty_state (serial_t scb, struct hardwire_ttystate *state)
get_tty_state (serial_t scb, struct hardwire_ttystate *state)
{
{
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  if (tcgetattr (scb->fd, &state->termios) < 0)
  if (tcgetattr (scb->fd, &state->termios) < 0)
    return -1;
    return -1;
 
 
  return 0;
  return 0;
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  if (ioctl (scb->fd, TCGETA, &state->termio) < 0)
  if (ioctl (scb->fd, TCGETA, &state->termio) < 0)
    return -1;
    return -1;
  return 0;
  return 0;
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0)
  if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0)
  if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0)
  if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
  if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
    return -1;
    return -1;
 
 
  return 0;
  return 0;
#endif
#endif
}
}
 
 
static int
static int
set_tty_state (serial_t scb, struct hardwire_ttystate *state)
set_tty_state (serial_t scb, struct hardwire_ttystate *state)
{
{
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0)
  if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0)
    return -1;
    return -1;
 
 
  return 0;
  return 0;
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  if (ioctl (scb->fd, TCSETA, &state->termio) < 0)
  if (ioctl (scb->fd, TCSETA, &state->termio) < 0)
    return -1;
    return -1;
  return 0;
  return 0;
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0)
  if (ioctl (scb->fd, TIOCSETN, &state->sgttyb) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCSETC, &state->tc) < 0)
  if (ioctl (scb->fd, TIOCSETC, &state->tc) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCSLTC, &state->ltc) < 0)
  if (ioctl (scb->fd, TIOCSLTC, &state->ltc) < 0)
    return -1;
    return -1;
  if (ioctl (scb->fd, TIOCLSET, &state->lmode) < 0)
  if (ioctl (scb->fd, TIOCLSET, &state->lmode) < 0)
    return -1;
    return -1;
 
 
  return 0;
  return 0;
#endif
#endif
}
}
 
 
static serial_ttystate
static serial_ttystate
hardwire_get_tty_state (serial_t scb)
hardwire_get_tty_state (serial_t scb)
{
{
  struct hardwire_ttystate *state;
  struct hardwire_ttystate *state;
 
 
  state = (struct hardwire_ttystate *) xmalloc (sizeof *state);
  state = (struct hardwire_ttystate *) xmalloc (sizeof *state);
 
 
  if (get_tty_state (scb, state))
  if (get_tty_state (scb, state))
    return NULL;
    return NULL;
 
 
  return (serial_ttystate) state;
  return (serial_ttystate) state;
}
}
 
 
static int
static int
hardwire_set_tty_state (serial_t scb, serial_ttystate ttystate)
hardwire_set_tty_state (serial_t scb, serial_ttystate ttystate)
{
{
  struct hardwire_ttystate *state;
  struct hardwire_ttystate *state;
 
 
  state = (struct hardwire_ttystate *) ttystate;
  state = (struct hardwire_ttystate *) ttystate;
 
 
  return set_tty_state (scb, state);
  return set_tty_state (scb, state);
}
}
 
 
static int
static int
hardwire_noflush_set_tty_state (serial_t scb,
hardwire_noflush_set_tty_state (serial_t scb,
                                serial_ttystate new_ttystate,
                                serial_ttystate new_ttystate,
                                serial_ttystate old_ttystate)
                                serial_ttystate old_ttystate)
{
{
  struct hardwire_ttystate new_state;
  struct hardwire_ttystate new_state;
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate;
  struct hardwire_ttystate *state = (struct hardwire_ttystate *) old_ttystate;
#endif
#endif
 
 
  new_state = *(struct hardwire_ttystate *) new_ttystate;
  new_state = *(struct hardwire_ttystate *) new_ttystate;
 
 
  /* Don't change in or out of raw mode; we don't want to flush input.
  /* 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
     termio and termios have no such restriction; for them flushing input
     is separate from setting the attributes.  */
     is separate from setting the attributes.  */
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  if (state->sgttyb.sg_flags & RAW)
  if (state->sgttyb.sg_flags & RAW)
    new_state.sgttyb.sg_flags |= RAW;
    new_state.sgttyb.sg_flags |= RAW;
  else
  else
    new_state.sgttyb.sg_flags &= ~RAW;
    new_state.sgttyb.sg_flags &= ~RAW;
 
 
  /* I'm not sure whether this is necessary; the manpage just mentions
  /* I'm not sure whether this is necessary; the manpage just mentions
     RAW not CBREAK.  */
     RAW not CBREAK.  */
  if (state->sgttyb.sg_flags & CBREAK)
  if (state->sgttyb.sg_flags & CBREAK)
    new_state.sgttyb.sg_flags |= CBREAK;
    new_state.sgttyb.sg_flags |= CBREAK;
  else
  else
    new_state.sgttyb.sg_flags &= ~CBREAK;
    new_state.sgttyb.sg_flags &= ~CBREAK;
#endif
#endif
 
 
  return set_tty_state (scb, &new_state);
  return set_tty_state (scb, &new_state);
}
}
 
 
static void
static void
hardwire_print_tty_state (serial_t scb,
hardwire_print_tty_state (serial_t scb,
                          serial_ttystate ttystate,
                          serial_ttystate ttystate,
                          struct ui_file *stream)
                          struct ui_file *stream)
{
{
  struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
  struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
  int i;
  int i;
 
 
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
  fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
                    (int) state->termios.c_iflag,
                    (int) state->termios.c_iflag,
                    (int) state->termios.c_oflag);
                    (int) state->termios.c_oflag);
  fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n",
  fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n",
                    (int) state->termios.c_cflag,
                    (int) state->termios.c_cflag,
                    (int) state->termios.c_lflag);
                    (int) state->termios.c_lflag);
#if 0
#if 0
  /* This not in POSIX, and is not really documented by those systems
  /* This not in POSIX, and is not really documented by those systems
     which have it (at least not Sun).  */
     which have it (at least not Sun).  */
  fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line);
  fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line);
#endif
#endif
  fprintf_filtered (stream, "c_cc: ");
  fprintf_filtered (stream, "c_cc: ");
  for (i = 0; i < NCCS; i += 1)
  for (i = 0; i < NCCS; i += 1)
    fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]);
    fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]);
  fprintf_filtered (stream, "\n");
  fprintf_filtered (stream, "\n");
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
  fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
                    state->termio.c_iflag, state->termio.c_oflag);
                    state->termio.c_iflag, state->termio.c_oflag);
  fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
  fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
                    state->termio.c_cflag, state->termio.c_lflag,
                    state->termio.c_cflag, state->termio.c_lflag,
                    state->termio.c_line);
                    state->termio.c_line);
  fprintf_filtered (stream, "c_cc: ");
  fprintf_filtered (stream, "c_cc: ");
  for (i = 0; i < NCC; i += 1)
  for (i = 0; i < NCC; i += 1)
    fprintf_filtered (stream, "0x%x ", state->termio.c_cc[i]);
    fprintf_filtered (stream, "0x%x ", state->termio.c_cc[i]);
  fprintf_filtered (stream, "\n");
  fprintf_filtered (stream, "\n");
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  fprintf_filtered (stream, "sgttyb.sg_flags = 0x%x.\n",
  fprintf_filtered (stream, "sgttyb.sg_flags = 0x%x.\n",
                    state->sgttyb.sg_flags);
                    state->sgttyb.sg_flags);
 
 
  fprintf_filtered (stream, "tchars: ");
  fprintf_filtered (stream, "tchars: ");
  for (i = 0; i < (int) sizeof (struct tchars); i++)
  for (i = 0; i < (int) sizeof (struct tchars); i++)
    fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->tc)[i]);
    fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->tc)[i]);
  fprintf_filtered ("\n");
  fprintf_filtered ("\n");
 
 
  fprintf_filtered (stream, "ltchars: ");
  fprintf_filtered (stream, "ltchars: ");
  for (i = 0; i < (int) sizeof (struct ltchars); i++)
  for (i = 0; i < (int) sizeof (struct ltchars); i++)
    fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->ltc)[i]);
    fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->ltc)[i]);
  fprintf_filtered (stream, "\n");
  fprintf_filtered (stream, "\n");
 
 
  fprintf_filtered (stream, "lmode:  0x%x\n", state->lmode);
  fprintf_filtered (stream, "lmode:  0x%x\n", state->lmode);
#endif
#endif
}
}
 
 
/* Wait for the output to drain away, as opposed to flushing (discarding) it */
/* Wait for the output to drain away, as opposed to flushing (discarding) it */
 
 
static int
static int
hardwire_drain_output (serial_t scb)
hardwire_drain_output (serial_t scb)
{
{
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  return tcdrain (scb->fd);
  return tcdrain (scb->fd);
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  return ioctl (scb->fd, TCSBRK, 1);
  return ioctl (scb->fd, TCSBRK, 1);
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  /* Get the current state and then restore it using TIOCSETP,
  /* Get the current state and then restore it using TIOCSETP,
     which should cause the output to drain and pending input
     which should cause the output to drain and pending input
     to be discarded. */
     to be discarded. */
  {
  {
    struct hardwire_ttystate state;
    struct hardwire_ttystate state;
    if (get_tty_state (scb, &state))
    if (get_tty_state (scb, &state))
      {
      {
        return (-1);
        return (-1);
      }
      }
    else
    else
      {
      {
        return (ioctl (scb->fd, TIOCSETP, &state.sgttyb));
        return (ioctl (scb->fd, TIOCSETP, &state.sgttyb));
      }
      }
  }
  }
#endif
#endif
}
}
 
 
static int
static int
hardwire_flush_output (serial_t scb)
hardwire_flush_output (serial_t scb)
{
{
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  return tcflush (scb->fd, TCOFLUSH);
  return tcflush (scb->fd, TCOFLUSH);
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  return ioctl (scb->fd, TCFLSH, 1);
  return ioctl (scb->fd, TCFLSH, 1);
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  /* This flushes both input and output, but we can't do better.  */
  /* This flushes both input and output, but we can't do better.  */
  return ioctl (scb->fd, TIOCFLUSH, 0);
  return ioctl (scb->fd, TIOCFLUSH, 0);
#endif
#endif
}
}
 
 
static int
static int
hardwire_flush_input (serial_t scb)
hardwire_flush_input (serial_t scb)
{
{
  ser_unix_flush_input (scb);
  ser_unix_flush_input (scb);
 
 
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  return tcflush (scb->fd, TCIFLUSH);
  return tcflush (scb->fd, TCIFLUSH);
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  return ioctl (scb->fd, TCFLSH, 0);
  return ioctl (scb->fd, TCFLSH, 0);
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  /* This flushes both input and output, but we can't do better.  */
  /* This flushes both input and output, but we can't do better.  */
  return ioctl (scb->fd, TIOCFLUSH, 0);
  return ioctl (scb->fd, TIOCFLUSH, 0);
#endif
#endif
}
}
 
 
static int
static int
hardwire_send_break (serial_t scb)
hardwire_send_break (serial_t scb)
{
{
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  return tcsendbreak (scb->fd, 0);
  return tcsendbreak (scb->fd, 0);
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  return ioctl (scb->fd, TCSBRK, 0);
  return ioctl (scb->fd, TCSBRK, 0);
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  {
  {
    int status;
    int status;
    struct timeval timeout;
    struct timeval timeout;
 
 
    status = ioctl (scb->fd, TIOCSBRK, 0);
    status = ioctl (scb->fd, TIOCSBRK, 0);
 
 
    /* Can't use usleep; it doesn't exist in BSD 4.2.  */
    /* 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
    /* Note that if this select() is interrupted by a signal it will not wait
       the full length of time.  I think that is OK.  */
       the full length of time.  I think that is OK.  */
    timeout.tv_sec = 0;
    timeout.tv_sec = 0;
    timeout.tv_usec = 250000;
    timeout.tv_usec = 250000;
    select (0, 0, 0, 0, &timeout);
    select (0, 0, 0, 0, &timeout);
    status = ioctl (scb->fd, TIOCCBRK, 0);
    status = ioctl (scb->fd, TIOCCBRK, 0);
    return status;
    return status;
  }
  }
#endif
#endif
}
}
 
 
static void
static void
hardwire_raw (serial_t scb)
hardwire_raw (serial_t scb)
{
{
  struct hardwire_ttystate state;
  struct hardwire_ttystate state;
 
 
  if (get_tty_state (scb, &state))
  if (get_tty_state (scb, &state))
    fprintf_unfiltered (gdb_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
#ifdef HAVE_TERMIOS
  state.termios.c_iflag = 0;
  state.termios.c_iflag = 0;
  state.termios.c_oflag = 0;
  state.termios.c_oflag = 0;
  state.termios.c_lflag = 0;
  state.termios.c_lflag = 0;
  state.termios.c_cflag &= ~(CSIZE | PARENB);
  state.termios.c_cflag &= ~(CSIZE | PARENB);
  state.termios.c_cflag |= CLOCAL | CS8;
  state.termios.c_cflag |= CLOCAL | CS8;
  state.termios.c_cc[VMIN] = 0;
  state.termios.c_cc[VMIN] = 0;
  state.termios.c_cc[VTIME] = 0;
  state.termios.c_cc[VTIME] = 0;
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  state.termio.c_iflag = 0;
  state.termio.c_iflag = 0;
  state.termio.c_oflag = 0;
  state.termio.c_oflag = 0;
  state.termio.c_lflag = 0;
  state.termio.c_lflag = 0;
  state.termio.c_cflag &= ~(CSIZE | PARENB);
  state.termio.c_cflag &= ~(CSIZE | PARENB);
  state.termio.c_cflag |= CLOCAL | CS8;
  state.termio.c_cflag |= CLOCAL | CS8;
  state.termio.c_cc[VMIN] = 0;
  state.termio.c_cc[VMIN] = 0;
  state.termio.c_cc[VTIME] = 0;
  state.termio.c_cc[VTIME] = 0;
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  state.sgttyb.sg_flags |= RAW | ANYP;
  state.sgttyb.sg_flags |= RAW | ANYP;
  state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
  state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
#endif
#endif
 
 
  scb->current_timeout = 0;
  scb->current_timeout = 0;
 
 
  if (set_tty_state (scb, &state))
  if (set_tty_state (scb, &state))
    fprintf_unfiltered (gdb_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,
/* Wait for input on scb, with timeout seconds.  Returns 0 on success,
   otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
   otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
 
 
   For termio{s}, we actually just setup VTIME if necessary, and let the
   For termio{s}, we actually just setup VTIME if necessary, and let the
   timeout occur in the read() in hardwire_read().
   timeout occur in the read() in hardwire_read().
 */
 */
 
 
/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
   ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
   ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
   flushed. . */
   flushed. . */
 
 
/* NOTE: cagney/1999-09-30: Much of the code below is dead.  The only
/* NOTE: cagney/1999-09-30: Much of the code below is dead.  The only
   possible values of the TIMEOUT parameter are ONE and ZERO.
   possible values of the TIMEOUT parameter are ONE and ZERO.
   Consequently all the code that tries to handle the possability of
   Consequently all the code that tries to handle the possability of
   an overflowed timer is unnecessary. */
   an overflowed timer is unnecessary. */
 
 
static int
static int
wait_for (serial_t scb, int timeout)
wait_for (serial_t scb, int timeout)
{
{
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  {
  {
    struct timeval tv;
    struct timeval tv;
    fd_set readfds;
    fd_set readfds;
 
 
    FD_ZERO (&readfds);
    FD_ZERO (&readfds);
 
 
    tv.tv_sec = timeout;
    tv.tv_sec = timeout;
    tv.tv_usec = 0;
    tv.tv_usec = 0;
 
 
    FD_SET (scb->fd, &readfds);
    FD_SET (scb->fd, &readfds);
 
 
    while (1)
    while (1)
      {
      {
        int numfds;
        int numfds;
 
 
        if (timeout >= 0)
        if (timeout >= 0)
          numfds = select (scb->fd + 1, &readfds, 0, 0, &tv);
          numfds = select (scb->fd + 1, &readfds, 0, 0, &tv);
        else
        else
          numfds = select (scb->fd + 1, &readfds, 0, 0, 0);
          numfds = select (scb->fd + 1, &readfds, 0, 0, 0);
 
 
        if (numfds <= 0)
        if (numfds <= 0)
          if (numfds == 0)
          if (numfds == 0)
            return SERIAL_TIMEOUT;
            return SERIAL_TIMEOUT;
          else if (errno == EINTR)
          else if (errno == EINTR)
            continue;
            continue;
          else
          else
            return SERIAL_ERROR;        /* Got an error from select or poll */
            return SERIAL_ERROR;        /* Got an error from select or poll */
 
 
        return 0;
        return 0;
      }
      }
  }
  }
#endif /* HAVE_SGTTY */
#endif /* HAVE_SGTTY */
 
 
#if defined HAVE_TERMIO || defined HAVE_TERMIOS
#if defined HAVE_TERMIO || defined HAVE_TERMIOS
  if (timeout == scb->current_timeout)
  if (timeout == scb->current_timeout)
    return 0;
    return 0;
 
 
  scb->current_timeout = timeout;
  scb->current_timeout = timeout;
 
 
  {
  {
    struct hardwire_ttystate state;
    struct hardwire_ttystate state;
 
 
    if (get_tty_state (scb, &state))
    if (get_tty_state (scb, &state))
      fprintf_unfiltered (gdb_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
#ifdef HAVE_TERMIOS
    if (timeout < 0)
    if (timeout < 0)
      {
      {
        /* No timeout.  */
        /* No timeout.  */
        state.termios.c_cc[VTIME] = 0;
        state.termios.c_cc[VTIME] = 0;
        state.termios.c_cc[VMIN] = 1;
        state.termios.c_cc[VMIN] = 1;
      }
      }
    else
    else
      {
      {
        state.termios.c_cc[VMIN] = 0;
        state.termios.c_cc[VMIN] = 0;
        state.termios.c_cc[VTIME] = timeout * 10;
        state.termios.c_cc[VTIME] = timeout * 10;
        if (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
            /* If c_cc is an 8-bit signed character, we can't go
               bigger than this.  If it is always unsigned, we could use
               bigger than this.  If it is always unsigned, we could use
               25.  */
               25.  */
 
 
            scb->current_timeout = 12;
            scb->current_timeout = 12;
            state.termios.c_cc[VTIME] = scb->current_timeout * 10;
            state.termios.c_cc[VTIME] = scb->current_timeout * 10;
            scb->timeout_remaining = timeout - scb->current_timeout;
            scb->timeout_remaining = timeout - scb->current_timeout;
          }
          }
      }
      }
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
    if (timeout < 0)
    if (timeout < 0)
      {
      {
        /* No timeout.  */
        /* No timeout.  */
        state.termio.c_cc[VTIME] = 0;
        state.termio.c_cc[VTIME] = 0;
        state.termio.c_cc[VMIN] = 1;
        state.termio.c_cc[VMIN] = 1;
      }
      }
    else
    else
      {
      {
        state.termio.c_cc[VMIN] = 0;
        state.termio.c_cc[VMIN] = 0;
        state.termio.c_cc[VTIME] = timeout * 10;
        state.termio.c_cc[VTIME] = timeout * 10;
        if (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
            /* If c_cc is an 8-bit signed character, we can't go
               bigger than this.  If it is always unsigned, we could use
               bigger than this.  If it is always unsigned, we could use
               25.  */
               25.  */
 
 
            scb->current_timeout = 12;
            scb->current_timeout = 12;
            state.termio.c_cc[VTIME] = scb->current_timeout * 10;
            state.termio.c_cc[VTIME] = scb->current_timeout * 10;
            scb->timeout_remaining = timeout - scb->current_timeout;
            scb->timeout_remaining = timeout - scb->current_timeout;
          }
          }
      }
      }
#endif
#endif
 
 
    if (set_tty_state (scb, &state))
    if (set_tty_state (scb, &state))
      fprintf_unfiltered (gdb_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;
    return 0;
  }
  }
#endif /* HAVE_TERMIO || HAVE_TERMIOS */
#endif /* HAVE_TERMIO || HAVE_TERMIOS */
}
}
 
 
/* Read a character with user-specified timeout.  TIMEOUT is number of seconds
/* 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
   to wait, or -1 to wait forever.  Use timeout of 0 to effect a poll.  Returns
   char if successful.  Returns SERIAL_TIMEOUT if timeout expired, EOF if line
   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).  */
   dropped dead, or SERIAL_ERROR for any other error (see errno in that case).  */
 
 
/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
/* FIXME: cagney/1999-09-16: Don't replace this with the equivalent
   ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
   ser_unix*() until the old TERMIOS/SGTTY/... timer code has been
   flushed. */
   flushed. */
 
 
/* NOTE: cagney/1999-09-16: This function is not identical to
/* NOTE: cagney/1999-09-16: This function is not identical to
   ser_unix_readchar() as part of replacing it with ser_unix*()
   ser_unix_readchar() as part of replacing it with ser_unix*()
   merging will be required - this code handles the case where read()
   merging will be required - this code handles the case where read()
   times out due to no data while ser_unix_readchar() doesn't expect
   times out due to no data while ser_unix_readchar() doesn't expect
   that. */
   that. */
 
 
static int
static int
do_hardwire_readchar (serial_t scb, int timeout)
do_hardwire_readchar (serial_t scb, int timeout)
{
{
  int status, delta;
  int status, delta;
  int detach = 0;
  int detach = 0;
 
 
  if (timeout > 0)
  if (timeout > 0)
    timeout++;
    timeout++;
 
 
  /* We have to be able to keep the GUI alive here, so we break the original
  /* We have to be able to keep the GUI alive here, so we break the original
     timeout into steps of 1 second, running the "keep the GUI alive" hook
     timeout into steps of 1 second, running the "keep the GUI alive" hook
     each time through the loop.
     each time through the loop.
     Also, timeout = 0 means to poll, so we just set the delta to 0, so we
     Also, timeout = 0 means to poll, so we just set the delta to 0, so we
     will only go through the loop once. */
     will only go through the loop once. */
 
 
  delta = (timeout == 0 ? 0 : 1);
  delta = (timeout == 0 ? 0 : 1);
  while (1)
  while (1)
    {
    {
 
 
      /* N.B. The UI may destroy our world (for instance by calling
      /* N.B. The UI may destroy our world (for instance by calling
         remote_stop,) in which case we want to get out of here as
         remote_stop,) in which case we want to get out of here as
         quickly as possible.  It is not safe to touch scb, since
         quickly as possible.  It is not safe to touch scb, since
         someone else might have freed it.  The ui_loop_hook signals that
         someone else might have freed it.  The ui_loop_hook signals that
         we should exit by returning 1. */
         we should exit by returning 1. */
 
 
      if (ui_loop_hook)
      if (ui_loop_hook)
        detach = ui_loop_hook (0);
        detach = ui_loop_hook (0);
 
 
      if (detach)
      if (detach)
        return SERIAL_TIMEOUT;
        return SERIAL_TIMEOUT;
 
 
      scb->timeout_remaining = (timeout < 0 ? timeout : timeout - delta);
      scb->timeout_remaining = (timeout < 0 ? timeout : timeout - delta);
      status = wait_for (scb, delta);
      status = wait_for (scb, delta);
 
 
      if (status < 0)
      if (status < 0)
        return status;
        return status;
 
 
      status = read (scb->fd, scb->buf, BUFSIZ);
      status = read (scb->fd, scb->buf, BUFSIZ);
 
 
      if (status <= 0)
      if (status <= 0)
        {
        {
          if (status == 0)
          if (status == 0)
            {
            {
              /* Zero characters means timeout (it could also be EOF, but
              /* Zero characters means timeout (it could also be EOF, but
                 we don't (yet at least) distinguish).  */
                 we don't (yet at least) distinguish).  */
              if (scb->timeout_remaining > 0)
              if (scb->timeout_remaining > 0)
                {
                {
                  timeout = scb->timeout_remaining;
                  timeout = scb->timeout_remaining;
                  continue;
                  continue;
                }
                }
              else if (scb->timeout_remaining < 0)
              else if (scb->timeout_remaining < 0)
                continue;
                continue;
              else
              else
                return SERIAL_TIMEOUT;
                return SERIAL_TIMEOUT;
            }
            }
          else if (errno == EINTR)
          else if (errno == EINTR)
            continue;
            continue;
          else
          else
            return SERIAL_ERROR;        /* Got an error from read */
            return SERIAL_ERROR;        /* Got an error from read */
        }
        }
 
 
      scb->bufcnt = status;
      scb->bufcnt = status;
      scb->bufcnt--;
      scb->bufcnt--;
      scb->bufp = scb->buf;
      scb->bufp = scb->buf;
      return *scb->bufp++;
      return *scb->bufp++;
    }
    }
}
}
 
 
static int
static int
hardwire_readchar (serial_t scb, int timeout)
hardwire_readchar (serial_t scb, int timeout)
{
{
  return generic_readchar (scb, timeout, do_hardwire_readchar);
  return generic_readchar (scb, timeout, do_hardwire_readchar);
}
}
 
 
 
 
#ifndef B19200
#ifndef B19200
#define B19200 EXTA
#define B19200 EXTA
#endif
#endif
 
 
#ifndef B38400
#ifndef B38400
#define B38400 EXTB
#define B38400 EXTB
#endif
#endif
 
 
/* Translate baud rates from integers to damn B_codes.  Unix should
/* Translate baud rates from integers to damn B_codes.  Unix should
   have outgrown this crap years ago, but even POSIX wouldn't buck it.  */
   have outgrown this crap years ago, but even POSIX wouldn't buck it.  */
 
 
static struct
static struct
{
{
  int rate;
  int rate;
  int code;
  int code;
}
}
baudtab[] =
baudtab[] =
{
{
  {
  {
    50, B50
    50, B50
  }
  }
  ,
  ,
  {
  {
    75, B75
    75, B75
  }
  }
  ,
  ,
  {
  {
    110, B110
    110, B110
  }
  }
  ,
  ,
  {
  {
    134, B134
    134, B134
  }
  }
  ,
  ,
  {
  {
    150, B150
    150, B150
  }
  }
  ,
  ,
  {
  {
    200, B200
    200, B200
  }
  }
  ,
  ,
  {
  {
    300, B300
    300, B300
  }
  }
  ,
  ,
  {
  {
    600, B600
    600, B600
  }
  }
  ,
  ,
  {
  {
    1200, B1200
    1200, B1200
  }
  }
  ,
  ,
  {
  {
    1800, B1800
    1800, B1800
  }
  }
  ,
  ,
  {
  {
    2400, B2400
    2400, B2400
  }
  }
  ,
  ,
  {
  {
    4800, B4800
    4800, B4800
  }
  }
  ,
  ,
  {
  {
    9600, B9600
    9600, B9600
  }
  }
  ,
  ,
  {
  {
    19200, B19200
    19200, B19200
  }
  }
  ,
  ,
  {
  {
    38400, B38400
    38400, B38400
  }
  }
  ,
  ,
#ifdef B57600
#ifdef B57600
  {
  {
    57600, B57600
    57600, B57600
  }
  }
  ,
  ,
#endif
#endif
#ifdef B115200
#ifdef B115200
  {
  {
    115200, B115200
    115200, B115200
  }
  }
  ,
  ,
#endif
#endif
#ifdef B230400
#ifdef B230400
  {
  {
    230400, B230400
    230400, B230400
  }
  }
  ,
  ,
#endif
#endif
#ifdef B460800
#ifdef B460800
  {
  {
    460800, B460800
    460800, B460800
  }
  }
  ,
  ,
#endif
#endif
  {
  {
    -1, -1
    -1, -1
  }
  }
  ,
  ,
};
};
 
 
static int
static int
rate_to_code (int rate)
rate_to_code (int rate)
{
{
  int i;
  int i;
 
 
  for (i = 0; baudtab[i].rate != -1; i++)
  for (i = 0; baudtab[i].rate != -1; i++)
    if (rate == baudtab[i].rate)
    if (rate == baudtab[i].rate)
      return baudtab[i].code;
      return baudtab[i].code;
 
 
  return -1;
  return -1;
}
}
 
 
static int
static int
hardwire_setbaudrate (serial_t scb, int rate)
hardwire_setbaudrate (serial_t scb, int rate)
{
{
  struct hardwire_ttystate state;
  struct hardwire_ttystate state;
 
 
  if (get_tty_state (scb, &state))
  if (get_tty_state (scb, &state))
    return -1;
    return -1;
 
 
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  cfsetospeed (&state.termios, rate_to_code (rate));
  cfsetospeed (&state.termios, rate_to_code (rate));
  cfsetispeed (&state.termios, rate_to_code (rate));
  cfsetispeed (&state.termios, rate_to_code (rate));
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
#ifndef CIBAUD
#ifndef CIBAUD
#define CIBAUD CBAUD
#define CIBAUD CBAUD
#endif
#endif
 
 
  state.termio.c_cflag &= ~(CBAUD | CIBAUD);
  state.termio.c_cflag &= ~(CBAUD | CIBAUD);
  state.termio.c_cflag |= rate_to_code (rate);
  state.termio.c_cflag |= rate_to_code (rate);
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  state.sgttyb.sg_ispeed = rate_to_code (rate);
  state.sgttyb.sg_ispeed = rate_to_code (rate);
  state.sgttyb.sg_ospeed = rate_to_code (rate);
  state.sgttyb.sg_ospeed = rate_to_code (rate);
#endif
#endif
 
 
  return set_tty_state (scb, &state);
  return set_tty_state (scb, &state);
}
}
 
 
static int
static int
hardwire_setstopbits (scb, num)
hardwire_setstopbits (scb, num)
     serial_t scb;
     serial_t scb;
     int num;
     int num;
{
{
  struct hardwire_ttystate state;
  struct hardwire_ttystate state;
  int newbit;
  int newbit;
 
 
  if (get_tty_state (scb, &state))
  if (get_tty_state (scb, &state))
    return -1;
    return -1;
 
 
  switch (num)
  switch (num)
    {
    {
    case SERIAL_1_STOPBITS:
    case SERIAL_1_STOPBITS:
      newbit = 0;
      newbit = 0;
      break;
      break;
    case SERIAL_1_AND_A_HALF_STOPBITS:
    case SERIAL_1_AND_A_HALF_STOPBITS:
    case SERIAL_2_STOPBITS:
    case SERIAL_2_STOPBITS:
      newbit = 1;
      newbit = 1;
      break;
      break;
    default:
    default:
      return 1;
      return 1;
    }
    }
 
 
#ifdef HAVE_TERMIOS
#ifdef HAVE_TERMIOS
  if (!newbit)
  if (!newbit)
    state.termios.c_cflag &= ~CSTOPB;
    state.termios.c_cflag &= ~CSTOPB;
  else
  else
    state.termios.c_cflag |= CSTOPB;    /* two bits */
    state.termios.c_cflag |= CSTOPB;    /* two bits */
#endif
#endif
 
 
#ifdef HAVE_TERMIO
#ifdef HAVE_TERMIO
  if (!newbit)
  if (!newbit)
    state.termio.c_cflag &= ~CSTOPB;
    state.termio.c_cflag &= ~CSTOPB;
  else
  else
    state.termio.c_cflag |= CSTOPB;     /* two bits */
    state.termio.c_cflag |= CSTOPB;     /* two bits */
#endif
#endif
 
 
#ifdef HAVE_SGTTY
#ifdef HAVE_SGTTY
  return 0;                      /* sgtty doesn't support this */
  return 0;                      /* sgtty doesn't support this */
#endif
#endif
 
 
  return set_tty_state (scb, &state);
  return set_tty_state (scb, &state);
}
}
 
 
static void
static void
hardwire_close (serial_t scb)
hardwire_close (serial_t scb)
{
{
  if (scb->fd < 0)
  if (scb->fd < 0)
    return;
    return;
 
 
  close (scb->fd);
  close (scb->fd);
  scb->fd = -1;
  scb->fd = -1;
}
}
 
 


/* Generic operations used by all UNIX/FD based serial interfaces. */
/* Generic operations used by all UNIX/FD based serial interfaces. */
 
 
serial_ttystate
serial_ttystate
ser_unix_nop_get_tty_state (serial_t scb)
ser_unix_nop_get_tty_state (serial_t scb)
{
{
  /* allocate a dummy */
  /* allocate a dummy */
  return (serial_ttystate) XMALLOC (int);
  return (serial_ttystate) XMALLOC (int);
}
}
 
 
int
int
ser_unix_nop_set_tty_state (serial_t scb, serial_ttystate ttystate)
ser_unix_nop_set_tty_state (serial_t scb, serial_ttystate ttystate)
{
{
  return 0;
  return 0;
}
}
 
 
void
void
ser_unix_nop_raw (serial_t scb)
ser_unix_nop_raw (serial_t scb)
{
{
  return;                       /* Always in raw mode */
  return;                       /* Always in raw mode */
}
}
 
 
/* Wait for input on scb, with timeout seconds.  Returns 0 on success,
/* Wait for input on scb, with timeout seconds.  Returns 0 on success,
   otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */
   otherwise SERIAL_TIMEOUT or SERIAL_ERROR. */
 
 
int
int
ser_unix_wait_for (serial_t scb, int timeout)
ser_unix_wait_for (serial_t scb, int timeout)
{
{
  int numfds;
  int numfds;
  struct timeval tv;
  struct timeval tv;
  fd_set readfds, exceptfds;
  fd_set readfds, exceptfds;
 
 
  FD_ZERO (&readfds);
  FD_ZERO (&readfds);
  FD_ZERO (&exceptfds);
  FD_ZERO (&exceptfds);
 
 
  tv.tv_sec = timeout;
  tv.tv_sec = timeout;
  tv.tv_usec = 0;
  tv.tv_usec = 0;
 
 
  FD_SET (scb->fd, &readfds);
  FD_SET (scb->fd, &readfds);
  FD_SET (scb->fd, &exceptfds);
  FD_SET (scb->fd, &exceptfds);
 
 
  while (1)
  while (1)
    {
    {
      if (timeout >= 0)
      if (timeout >= 0)
        numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
        numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
      else
      else
        numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
        numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
 
 
      if (numfds <= 0)
      if (numfds <= 0)
        {
        {
          if (numfds == 0)
          if (numfds == 0)
            return SERIAL_TIMEOUT;
            return SERIAL_TIMEOUT;
          else if (errno == EINTR)
          else if (errno == EINTR)
            continue;
            continue;
          else
          else
            return SERIAL_ERROR;        /* Got an error from select or poll */
            return SERIAL_ERROR;        /* Got an error from select or poll */
        }
        }
 
 
      return 0;
      return 0;
    }
    }
}
}
 
 
/* Read a character with user-specified timeout.  TIMEOUT is number of seconds
/* 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
   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
   char if successful.  Returns -2 if timeout expired, EOF if line dropped
   dead, or -3 for any other error (see errno in that case). */
   dead, or -3 for any other error (see errno in that case). */
 
 
static int
static int
do_unix_readchar (serial_t scb, int timeout)
do_unix_readchar (serial_t scb, int timeout)
{
{
  int status;
  int status;
  int delta;
  int delta;
 
 
  /* We have to be able to keep the GUI alive here, so we break the original
  /* We have to be able to keep the GUI alive here, so we break the original
     timeout into steps of 1 second, running the "keep the GUI alive" hook
     timeout into steps of 1 second, running the "keep the GUI alive" hook
     each time through the loop.
     each time through the loop.
 
 
     Also, timeout = 0 means to poll, so we just set the delta to 0, so we
     Also, timeout = 0 means to poll, so we just set the delta to 0, so we
     will only go through the loop once. timeout < 0 means to wait forever. */
     will only go through the loop once. timeout < 0 means to wait forever. */
 
 
  delta = (timeout <= 0 ? 0 : 1);
  delta = (timeout <= 0 ? 0 : 1);
  while (1)
  while (1)
    {
    {
 
 
      /* N.B. The UI may destroy our world (for instance by calling
      /* N.B. The UI may destroy our world (for instance by calling
         remote_stop,) in which case we want to get out of here as
         remote_stop,) in which case we want to get out of here as
         quickly as possible.  It is not safe to touch scb, since
         quickly as possible.  It is not safe to touch scb, since
         someone else might have freed it.  The ui_loop_hook signals that
         someone else might have freed it.  The ui_loop_hook signals that
         we should exit by returning 1. */
         we should exit by returning 1. */
 
 
      if (ui_loop_hook)
      if (ui_loop_hook)
        {
        {
          if (ui_loop_hook (0))
          if (ui_loop_hook (0))
            return SERIAL_TIMEOUT;
            return SERIAL_TIMEOUT;
        }
        }
 
 
      status = ser_unix_wait_for (scb, timeout < 0 ? timeout : delta);
      status = ser_unix_wait_for (scb, timeout < 0 ? timeout : delta);
      timeout -= delta;
      timeout -= delta;
 
 
      /* If we got an error back from wait_for, then we can return */
      /* If we got an error back from wait_for, then we can return */
 
 
      if (status == SERIAL_ERROR)
      if (status == SERIAL_ERROR)
        return status;
        return status;
 
 
      status = read (scb->fd, scb->buf, BUFSIZ);
      status = read (scb->fd, scb->buf, BUFSIZ);
 
 
      if (status <= 0)
      if (status <= 0)
        {
        {
          if (status == 0)
          if (status == 0)
            {
            {
              if (timeout != 0)
              if (timeout != 0)
                continue;
                continue;
              else
              else
                return SERIAL_TIMEOUT;  /* 0 chars means timeout [may need to
                return SERIAL_TIMEOUT;  /* 0 chars means timeout [may need to
                                           distinguish between EOF & timeouts
                                           distinguish between EOF & timeouts
                                           someday] */
                                           someday] */
            }
            }
          else if (errno == EINTR)
          else if (errno == EINTR)
            continue;
            continue;
          else
          else
            return SERIAL_ERROR;        /* Got an error from read */
            return SERIAL_ERROR;        /* Got an error from read */
        }
        }
 
 
      scb->bufcnt = status;
      scb->bufcnt = status;
      scb->bufcnt--;
      scb->bufcnt--;
      scb->bufp = scb->buf;
      scb->bufp = scb->buf;
      return *scb->bufp++;
      return *scb->bufp++;
    }
    }
}
}
 
 
/* Perform operations common to both old and new readchar. */
/* Perform operations common to both old and new readchar. */
 
 
/* Return the next character from the input FIFO.  If the FIFO is
/* Return the next character from the input FIFO.  If the FIFO is
   empty, call the SERIAL specific routine to try and read in more
   empty, call the SERIAL specific routine to try and read in more
   characters.
   characters.
 
 
   Initially data from the input FIFO is returned (fd_event()
   Initially data from the input FIFO is returned (fd_event()
   pre-reads the input into that FIFO.  Once that has been emptied,
   pre-reads the input into that FIFO.  Once that has been emptied,
   further data is obtained by polling the input FD using the device
   further data is obtained by polling the input FD using the device
   specific readchar() function.  Note: reschedule() is called after
   specific readchar() function.  Note: reschedule() is called after
   every read.  This is because there is no guarentee that the lower
   every read.  This is because there is no guarentee that the lower
   level fd_event() poll_event() code (which also calls reschedule())
   level fd_event() poll_event() code (which also calls reschedule())
   will be called. */
   will be called. */
 
 
static int
static int
generic_readchar (serial_t scb, int timeout,
generic_readchar (serial_t scb, int timeout,
                  int (do_readchar) (serial_t scb, int timeout))
                  int (do_readchar) (serial_t scb, int timeout))
{
{
  int ch;
  int ch;
  if (scb->bufcnt > 0)
  if (scb->bufcnt > 0)
    {
    {
      ch = *scb->bufp;
      ch = *scb->bufp;
      scb->bufcnt--;
      scb->bufcnt--;
      scb->bufp++;
      scb->bufp++;
    }
    }
  else if (scb->bufcnt < 0)
  else if (scb->bufcnt < 0)
    {
    {
      /* Some errors/eof are are sticky. */
      /* Some errors/eof are are sticky. */
      ch = scb->bufcnt;
      ch = scb->bufcnt;
    }
    }
  else
  else
    {
    {
      ch = do_readchar (scb, timeout);
      ch = do_readchar (scb, timeout);
      if (ch < 0)
      if (ch < 0)
        {
        {
          switch ((enum serial_rc) ch)
          switch ((enum serial_rc) ch)
            {
            {
            case SERIAL_EOF:
            case SERIAL_EOF:
            case SERIAL_ERROR:
            case SERIAL_ERROR:
              /* Make the error/eof stick. */
              /* Make the error/eof stick. */
              scb->bufcnt = ch;
              scb->bufcnt = ch;
              break;
              break;
            case SERIAL_TIMEOUT:
            case SERIAL_TIMEOUT:
              scb->bufcnt = 0;
              scb->bufcnt = 0;
              break;
              break;
            }
            }
        }
        }
    }
    }
  reschedule (scb);
  reschedule (scb);
  return ch;
  return ch;
}
}
 
 
int
int
ser_unix_readchar (serial_t scb, int timeout)
ser_unix_readchar (serial_t scb, int timeout)
{
{
  return generic_readchar (scb, timeout, do_unix_readchar);
  return generic_readchar (scb, timeout, do_unix_readchar);
}
}
 
 
int
int
ser_unix_nop_noflush_set_tty_state (serial_t scb,
ser_unix_nop_noflush_set_tty_state (serial_t scb,
                                    serial_ttystate new_ttystate,
                                    serial_ttystate new_ttystate,
                                    serial_ttystate old_ttystate)
                                    serial_ttystate old_ttystate)
{
{
  return 0;
  return 0;
}
}
 
 
void
void
ser_unix_nop_print_tty_state (serial_t scb,
ser_unix_nop_print_tty_state (serial_t scb,
                              serial_ttystate ttystate,
                              serial_ttystate ttystate,
                              struct ui_file *stream)
                              struct ui_file *stream)
{
{
  /* Nothing to print.  */
  /* Nothing to print.  */
  return;
  return;
}
}
 
 
int
int
ser_unix_nop_setbaudrate (serial_t scb, int rate)
ser_unix_nop_setbaudrate (serial_t scb, int rate)
{
{
  return 0;                      /* Never fails! */
  return 0;                      /* Never fails! */
}
}
 
 
int
int
ser_unix_nop_setstopbits (serial_t scb, int num)
ser_unix_nop_setstopbits (serial_t scb, int num)
{
{
  return 0;                      /* Never fails! */
  return 0;                      /* Never fails! */
}
}
 
 
int
int
ser_unix_write (serial_t scb, const char *str, int len)
ser_unix_write (serial_t scb, const char *str, int len)
{
{
  int cc;
  int cc;
 
 
  while (len > 0)
  while (len > 0)
    {
    {
      cc = write (scb->fd, str, len);
      cc = write (scb->fd, str, len);
 
 
      if (cc < 0)
      if (cc < 0)
        return 1;
        return 1;
      len -= cc;
      len -= cc;
      str += cc;
      str += cc;
    }
    }
  return 0;
  return 0;
}
}
 
 
int
int
ser_unix_nop_flush_output (serial_t scb)
ser_unix_nop_flush_output (serial_t scb)
{
{
  return 0;
  return 0;
}
}
 
 
int
int
ser_unix_flush_input (serial_t scb)
ser_unix_flush_input (serial_t scb)
{
{
  if (scb->bufcnt >= 0)
  if (scb->bufcnt >= 0)
    {
    {
      scb->bufcnt = 0;
      scb->bufcnt = 0;
      scb->bufp = scb->buf;
      scb->bufp = scb->buf;
      return 0;
      return 0;
    }
    }
  else
  else
    return SERIAL_ERROR;
    return SERIAL_ERROR;
}
}
 
 
int
int
ser_unix_nop_send_break (serial_t scb)
ser_unix_nop_send_break (serial_t scb)
{
{
  return 0;
  return 0;
}
}
 
 
int
int
ser_unix_nop_drain_output (serial_t scb)
ser_unix_nop_drain_output (serial_t scb)
{
{
  return 0;
  return 0;
}
}
 
 
 
 


/* Event handling for ASYNC serial code.
/* Event handling for ASYNC serial code.
 
 
   At any time the SERIAL device either: has an empty FIFO and is
   At any time the SERIAL device either: has an empty FIFO and is
   waiting on a FD event; or has a non-empty FIFO/error condition and
   waiting on a FD event; or has a non-empty FIFO/error condition and
   is constantly scheduling timer events.
   is constantly scheduling timer events.
 
 
   ASYNC only stops pestering its client when it is de-async'ed or it
   ASYNC only stops pestering its client when it is de-async'ed or it
   is told to go away. */
   is told to go away. */
 
 
/* Value of scb->async_state: */
/* Value of scb->async_state: */
enum {
enum {
  /* >= 0 (TIMER_SCHEDULED) */
  /* >= 0 (TIMER_SCHEDULED) */
  /* The ID of the currently scheduled timer event. This state is
  /* The ID of the currently scheduled timer event. This state is
     rarely encountered.  Timer events are one-off so as soon as the
     rarely encountered.  Timer events are one-off so as soon as the
     event is delivered the state is shanged to NOTHING_SCHEDULED. */
     event is delivered the state is shanged to NOTHING_SCHEDULED. */
  FD_SCHEDULED = -1,
  FD_SCHEDULED = -1,
  /* The fd_event() handler is scheduled.  It is called when ever the
  /* The fd_event() handler is scheduled.  It is called when ever the
     file descriptor becomes ready. */
     file descriptor becomes ready. */
  NOTHING_SCHEDULED = -2
  NOTHING_SCHEDULED = -2
  /* Either no task is scheduled (just going into ASYNC mode) or a
  /* Either no task is scheduled (just going into ASYNC mode) or a
     timer event has just gone off and the current state has been
     timer event has just gone off and the current state has been
     forced into nothing scheduled. */
     forced into nothing scheduled. */
};
};
 
 
/* Identify and schedule the next ASYNC task based on scb->async_state
/* Identify and schedule the next ASYNC task based on scb->async_state
   and scb->buf* (the input FIFO).  A state machine is used to avoid
   and scb->buf* (the input FIFO).  A state machine is used to avoid
   the need to make redundant calls into the event-loop - the next
   the need to make redundant calls into the event-loop - the next
   scheduled task is only changed when needed. */
   scheduled task is only changed when needed. */
 
 
static void
static void
reschedule (serial_t scb)
reschedule (serial_t scb)
{
{
  if (SERIAL_IS_ASYNC_P (scb))
  if (SERIAL_IS_ASYNC_P (scb))
    {
    {
      int next_state;
      int next_state;
      switch (scb->async_state)
      switch (scb->async_state)
        {
        {
        case FD_SCHEDULED:
        case FD_SCHEDULED:
          if (scb->bufcnt == 0)
          if (scb->bufcnt == 0)
            next_state = FD_SCHEDULED;
            next_state = FD_SCHEDULED;
          else
          else
            {
            {
              delete_file_handler (scb->fd);
              delete_file_handler (scb->fd);
              next_state = create_timer (0, push_event, scb);
              next_state = create_timer (0, push_event, scb);
            }
            }
          break;
          break;
        case NOTHING_SCHEDULED:
        case NOTHING_SCHEDULED:
          if (scb->bufcnt == 0)
          if (scb->bufcnt == 0)
            {
            {
              add_file_handler (scb->fd, fd_event, scb);
              add_file_handler (scb->fd, fd_event, scb);
              next_state = FD_SCHEDULED;
              next_state = FD_SCHEDULED;
            }
            }
          else
          else
            {
            {
              next_state = create_timer (0, push_event, scb);
              next_state = create_timer (0, push_event, scb);
            }
            }
          break;
          break;
        default: /* TIMER SCHEDULED */
        default: /* TIMER SCHEDULED */
          if (scb->bufcnt == 0)
          if (scb->bufcnt == 0)
            {
            {
              delete_timer (scb->async_state);
              delete_timer (scb->async_state);
              add_file_handler (scb->fd, fd_event, scb);
              add_file_handler (scb->fd, fd_event, scb);
              next_state = FD_SCHEDULED;
              next_state = FD_SCHEDULED;
            }
            }
          else
          else
            next_state = scb->async_state;
            next_state = scb->async_state;
          break;
          break;
        }
        }
      if (SERIAL_DEBUG_P (scb))
      if (SERIAL_DEBUG_P (scb))
        {
        {
          switch (next_state)
          switch (next_state)
            {
            {
            case FD_SCHEDULED:
            case FD_SCHEDULED:
              if (scb->async_state != FD_SCHEDULED)
              if (scb->async_state != FD_SCHEDULED)
                fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n",
                fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n",
                                    scb->fd);
                                    scb->fd);
              break;
              break;
            default: /* TIMER SCHEDULED */
            default: /* TIMER SCHEDULED */
              if (scb->async_state == FD_SCHEDULED)
              if (scb->async_state == FD_SCHEDULED)
                fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n",
                fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n",
                                    scb->fd);
                                    scb->fd);
              break;
              break;
            }
            }
        }
        }
      scb->async_state = next_state;
      scb->async_state = next_state;
    }
    }
}
}
 
 
/* FD_EVENT: This is scheduled when the input FIFO is empty (and there
/* FD_EVENT: This is scheduled when the input FIFO is empty (and there
   is no pending error).  As soon as data arrives, it is read into the
   is no pending error).  As soon as data arrives, it is read into the
   input FIFO and the client notified.  The client should then drain
   input FIFO and the client notified.  The client should then drain
   the FIFO using readchar().  If the FIFO isn't immediatly emptied,
   the FIFO using readchar().  If the FIFO isn't immediatly emptied,
   push_event() is used to nag the client until it is. */
   push_event() is used to nag the client until it is. */
 
 
static void
static void
fd_event (int error, void *context)
fd_event (int error, void *context)
{
{
  serial_t scb = context;
  serial_t scb = context;
  if (error != 0)
  if (error != 0)
    {
    {
      scb->bufcnt = SERIAL_ERROR;
      scb->bufcnt = SERIAL_ERROR;
    }
    }
  else if (scb->bufcnt == 0)
  else if (scb->bufcnt == 0)
    {
    {
      /* Prime the input FIFO.  The readchar() function is used to
      /* Prime the input FIFO.  The readchar() function is used to
         pull characters out of the buffer.  See also
         pull characters out of the buffer.  See also
         generic_readchar(). */
         generic_readchar(). */
      int nr;
      int nr;
      do
      do
        {
        {
          nr = read (scb->fd, scb->buf, BUFSIZ);
          nr = read (scb->fd, scb->buf, BUFSIZ);
        }
        }
      while (nr == -1 && errno == EINTR);
      while (nr == -1 && errno == EINTR);
      if (nr == 0)
      if (nr == 0)
        {
        {
          scb->bufcnt = SERIAL_EOF;
          scb->bufcnt = SERIAL_EOF;
        }
        }
      else if (nr > 0)
      else if (nr > 0)
        {
        {
          scb->bufcnt = nr;
          scb->bufcnt = nr;
          scb->bufp = scb->buf;
          scb->bufp = scb->buf;
        }
        }
      else
      else
        {
        {
          scb->bufcnt = SERIAL_ERROR;
          scb->bufcnt = SERIAL_ERROR;
        }
        }
    }
    }
  scb->async_handler (scb, scb->async_context);
  scb->async_handler (scb, scb->async_context);
  reschedule (scb);
  reschedule (scb);
}
}
 
 
/* PUSH_EVENT: The input FIFO is non-empty (or there is a pending
/* PUSH_EVENT: The input FIFO is non-empty (or there is a pending
   error).  Nag the client until all the data has been read.  In the
   error).  Nag the client until all the data has been read.  In the
   case of errors, the client will need to close or de-async the
   case of errors, the client will need to close or de-async the
   device before naging stops. */
   device before naging stops. */
 
 
static void
static void
push_event (void *context)
push_event (void *context)
{
{
  serial_t scb = context;
  serial_t scb = context;
  scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */
  scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */
  scb->async_handler (scb, scb->async_context);
  scb->async_handler (scb, scb->async_context);
  /* re-schedule */
  /* re-schedule */
  reschedule (scb);
  reschedule (scb);
}
}
 
 
/* Put the SERIAL device into/out-of ASYNC mode.  */
/* Put the SERIAL device into/out-of ASYNC mode.  */
 
 
void
void
ser_unix_async (serial_t scb,
ser_unix_async (serial_t scb,
                int async_p)
                int async_p)
{
{
  if (async_p)
  if (async_p)
    {
    {
      /* Force a re-schedule. */
      /* Force a re-schedule. */
      scb->async_state = NOTHING_SCHEDULED;
      scb->async_state = NOTHING_SCHEDULED;
      if (SERIAL_DEBUG_P (scb))
      if (SERIAL_DEBUG_P (scb))
        fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
        fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
                            scb->fd);
                            scb->fd);
      reschedule (scb);
      reschedule (scb);
    }
    }
  else
  else
    {
    {
      if (SERIAL_DEBUG_P (scb))
      if (SERIAL_DEBUG_P (scb))
        fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n",
        fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n",
                            scb->fd);
                            scb->fd);
      /* De-schedule what ever tasks are currently scheduled. */
      /* De-schedule what ever tasks are currently scheduled. */
      switch (scb->async_state)
      switch (scb->async_state)
        {
        {
        case FD_SCHEDULED:
        case FD_SCHEDULED:
          delete_file_handler (scb->fd);
          delete_file_handler (scb->fd);
          break;
          break;
        NOTHING_SCHEDULED:
        NOTHING_SCHEDULED:
          break;
          break;
        default: /* TIMER SCHEDULED */
        default: /* TIMER SCHEDULED */
          delete_timer (scb->async_state);
          delete_timer (scb->async_state);
          break;
          break;
        }
        }
    }
    }
}
}
 
 
void
void
_initialize_ser_hardwire (void)
_initialize_ser_hardwire (void)
{
{
  struct serial_ops *ops = XMALLOC (struct serial_ops);
  struct serial_ops *ops = XMALLOC (struct serial_ops);
  memset (ops, sizeof (struct serial_ops), 0);
  memset (ops, sizeof (struct serial_ops), 0);
  ops->name = "hardwire";
  ops->name = "hardwire";
  ops->next = 0;
  ops->next = 0;
  ops->open = hardwire_open;
  ops->open = hardwire_open;
  ops->close = hardwire_close;
  ops->close = hardwire_close;
  /* FIXME: Don't replace this with the equivalent ser_unix*() until
  /* FIXME: Don't replace this with the equivalent ser_unix*() until
     the old TERMIOS/SGTTY/... timer code has been flushed. cagney
     the old TERMIOS/SGTTY/... timer code has been flushed. cagney
     1999-09-16. */
     1999-09-16. */
  ops->readchar = hardwire_readchar;
  ops->readchar = hardwire_readchar;
  ops->write = ser_unix_write;
  ops->write = ser_unix_write;
  ops->flush_output = hardwire_flush_output;
  ops->flush_output = hardwire_flush_output;
  ops->flush_input = hardwire_flush_input;
  ops->flush_input = hardwire_flush_input;
  ops->send_break = hardwire_send_break;
  ops->send_break = hardwire_send_break;
  ops->go_raw = hardwire_raw;
  ops->go_raw = hardwire_raw;
  ops->get_tty_state = hardwire_get_tty_state;
  ops->get_tty_state = hardwire_get_tty_state;
  ops->set_tty_state = hardwire_set_tty_state;
  ops->set_tty_state = hardwire_set_tty_state;
  ops->print_tty_state = hardwire_print_tty_state;
  ops->print_tty_state = hardwire_print_tty_state;
  ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
  ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
  ops->setbaudrate = hardwire_setbaudrate;
  ops->setbaudrate = hardwire_setbaudrate;
  ops->setstopbits = hardwire_setstopbits;
  ops->setstopbits = hardwire_setstopbits;
  ops->drain_output = hardwire_drain_output;
  ops->drain_output = hardwire_drain_output;
  ops->async = ser_unix_async;
  ops->async = ser_unix_async;
  serial_add_interface (ops);
  serial_add_interface (ops);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.