#include "defs.h"
#include "serial.h"
#include "ser-unix.h"
#include <fcntl.h>
#include <sys/types.h>
#include "terminal.h"
#include <sys/socket.h>
#include <sys/time.h>
#include "gdb_string.h"
#include "event-loop.h"
#ifdef HAVE_TERMIOS
struct hardwire_ttystate
{
struct termios termios;
};
#endif
#ifdef HAVE_TERMIO
struct hardwire_ttystate
{
struct termio termio;
};
#endif
#ifdef HAVE_SGTTY
struct hardwire_ttystate
{
struct sgttyb sgttyb;
struct tchars tc;
struct ltchars ltc;
int lmode;
};
#endif
static int hardwire_open (struct serial *scb, const char *name);
static void hardwire_raw (struct serial *scb);
static int wait_for (struct serial *scb, int timeout);
static int hardwire_readchar (struct serial *scb, int timeout);
static int do_hardwire_readchar (struct serial *scb, int timeout);
static int generic_readchar (struct serial *scb, int timeout,
int (*do_readchar) (struct serial *scb,
int timeout));
static int rate_to_code (int rate);
static int hardwire_setbaudrate (struct serial *scb, int rate);
static void hardwire_close (struct serial *scb);
static int get_tty_state (struct serial *scb,
struct hardwire_ttystate * state);
static int set_tty_state (struct serial *scb,
struct hardwire_ttystate * state);
static serial_ttystate hardwire_get_tty_state (struct serial *scb);
static int hardwire_set_tty_state (struct serial *scb, serial_ttystate state);
static int hardwire_noflush_set_tty_state (struct serial *, serial_ttystate,
serial_ttystate);
static void hardwire_print_tty_state (struct serial *, serial_ttystate,
struct ui_file *);
static int hardwire_drain_output (struct serial *);
static int hardwire_flush_output (struct serial *);
static int hardwire_flush_input (struct serial *);
static int hardwire_send_break (struct serial *);
static int hardwire_setstopbits (struct serial *, int);
static int do_unix_readchar (struct serial *scb, int timeout);
static timer_handler_func push_event;
static handler_func fd_event;
static void reschedule (struct serial *scb);
void _initialize_ser_hardwire (void);
extern int (*ui_loop_hook) (int);
static int
hardwire_open (struct serial *scb, const char *name)
{
scb->fd = open (name, O_RDWR);
if (scb->fd < 0)
return -1;
return 0;
}
static int
get_tty_state (struct serial *scb, struct hardwire_ttystate *state)
{
#ifdef HAVE_TERMIOS
if (tcgetattr (scb->fd, &state->termios) < 0)
return -1;
return 0;
#endif
#ifdef HAVE_TERMIO
if (ioctl (scb->fd, TCGETA, &state->termio) < 0)
return -1;
return 0;
#endif
#ifdef HAVE_SGTTY
if (ioctl (scb->fd, TIOCGETP, &state->sgttyb) < 0)
return -1;
if (ioctl (scb->fd, TIOCGETC, &state->tc) < 0)
return -1;
if (ioctl (scb->fd, TIOCGLTC, &state->ltc) < 0)
return -1;
if (ioctl (scb->fd, TIOCLGET, &state->lmode) < 0)
return -1;
return 0;
#endif
}
static int
set_tty_state (struct serial *scb, struct hardwire_ttystate *state)
{
#ifdef HAVE_TERMIOS
if (tcsetattr (scb->fd, TCSANOW, &state->termios) < 0)
return -1;
return 0;
#endif
#ifdef HAVE_TERMIO
if (ioctl (scb->fd, TCSETA, &state->termio) < 0)
return -1;
return 0;
#endif
#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;
return 0;
#endif
}
static serial_ttystate
hardwire_get_tty_state (struct serial *scb)
{
struct hardwire_ttystate *state;
state = (struct hardwire_ttystate *) xmalloc (sizeof *state);
if (get_tty_state (scb, state))
return NULL;
return (serial_ttystate) state;
}
static int
hardwire_set_tty_state (struct serial *scb, serial_ttystate ttystate)
{
struct hardwire_ttystate *state;
state = (struct hardwire_ttystate *) ttystate;
return set_tty_state (scb, state);
}
static int
hardwire_noflush_set_tty_state (struct serial *scb,
serial_ttystate new_ttystate,
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_SGTTY
if (state->sgttyb.sg_flags & RAW)
new_state.sgttyb.sg_flags |= RAW;
else
new_state.sgttyb.sg_flags &= ~RAW;
if (state->sgttyb.sg_flags & CBREAK)
new_state.sgttyb.sg_flags |= CBREAK;
else
new_state.sgttyb.sg_flags &= ~CBREAK;
#endif
return set_tty_state (scb, &new_state);
}
static void
hardwire_print_tty_state (struct serial *scb,
serial_ttystate ttystate,
struct ui_file *stream)
{
struct hardwire_ttystate *state = (struct hardwire_ttystate *) ttystate;
int i;
#ifdef HAVE_TERMIOS
fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
(int) state->termios.c_iflag,
(int) state->termios.c_oflag);
fprintf_filtered (stream, "c_cflag = 0x%x, c_lflag = 0x%x\n",
(int) state->termios.c_cflag,
(int) state->termios.c_lflag);
#if 0
fprintf_filtered (stream, "c_line = 0x%x.\n", state->termios.c_line);
#endif
fprintf_filtered (stream, "c_cc: ");
for (i = 0; i < NCCS; i += 1)
fprintf_filtered (stream, "0x%x ", state->termios.c_cc[i]);
fprintf_filtered (stream, "\n");
#endif
#ifdef HAVE_TERMIO
fprintf_filtered (stream, "c_iflag = 0x%x, c_oflag = 0x%x,\n",
state->termio.c_iflag, state->termio.c_oflag);
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_line);
fprintf_filtered (stream, "c_cc: ");
for (i = 0; i < NCC; i += 1)
fprintf_filtered (stream, "0x%x ", state->termio.c_cc[i]);
fprintf_filtered (stream, "\n");
#endif
#ifdef HAVE_SGTTY
fprintf_filtered (stream, "sgttyb.sg_flags = 0x%x.\n",
state->sgttyb.sg_flags);
fprintf_filtered (stream, "tchars: ");
for (i = 0; i < (int) sizeof (struct tchars); i++)
fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->tc)[i]);
fprintf_filtered (stream, "\n");
fprintf_filtered (stream, "ltchars: ");
for (i = 0; i < (int) sizeof (struct ltchars); i++)
fprintf_filtered (stream, "0x%x ", ((unsigned char *) &state->ltc)[i]);
fprintf_filtered (stream, "\n");
fprintf_filtered (stream, "lmode: 0x%x\n", state->lmode);
#endif
}
static int
hardwire_drain_output (struct serial *scb)
{
#ifdef HAVE_TERMIOS
return tcdrain (scb->fd);
#endif
#ifdef HAVE_TERMIO
return ioctl (scb->fd, TCSBRK, 1);
#endif
#ifdef HAVE_SGTTY
{
struct hardwire_ttystate state;
if (get_tty_state (scb, &state))
{
return (-1);
}
else
{
return (ioctl (scb->fd, TIOCSETP, &state.sgttyb));
}
}
#endif
}
static int
hardwire_flush_output (struct serial *scb)
{
#ifdef HAVE_TERMIOS
return tcflush (scb->fd, TCOFLUSH);
#endif
#ifdef HAVE_TERMIO
return ioctl (scb->fd, TCFLSH, 1);
#endif
#ifdef HAVE_SGTTY
return ioctl (scb->fd, TIOCFLUSH, 0);
#endif
}
static int
hardwire_flush_input (struct serial *scb)
{
ser_unix_flush_input (scb);
#ifdef HAVE_TERMIOS
return tcflush (scb->fd, TCIFLUSH);
#endif
#ifdef HAVE_TERMIO
return ioctl (scb->fd, TCFLSH, 0);
#endif
#ifdef HAVE_SGTTY
return ioctl (scb->fd, TIOCFLUSH, 0);
#endif
}
static int
hardwire_send_break (struct serial *scb)
{
#ifdef HAVE_TERMIOS
return tcsendbreak (scb->fd, 0);
#endif
#ifdef HAVE_TERMIO
return ioctl (scb->fd, TCSBRK, 0);
#endif
#ifdef HAVE_SGTTY
{
int status;
struct timeval timeout;
status = ioctl (scb->fd, TIOCSBRK, 0);
timeout.tv_sec = 0;
timeout.tv_usec = 250000;
select (0, 0, 0, 0, &timeout);
status = ioctl (scb->fd, TIOCCBRK, 0);
return status;
}
#endif
}
static void
hardwire_raw (struct serial *scb)
{
struct hardwire_ttystate state;
if (get_tty_state (scb, &state))
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 |= CLOCAL | CS8;
state.termios.c_cc[VMIN] = 0;
state.termios.c_cc[VTIME] = 0;
#endif
#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 |= CLOCAL | 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_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", safe_strerror (errno));
}
static int
wait_for (struct serial *scb, int timeout)
{
#ifdef HAVE_SGTTY
while (1)
{
struct timeval tv;
fd_set readfds;
int numfds;
tv.tv_sec = timeout;
tv.tv_usec = 0;
FD_ZERO (&readfds);
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 if (errno == EINTR)
continue;
else
return SERIAL_ERROR;
return 0;
}
#endif
#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_unfiltered (gdb_stderr, "get_tty_state failed: %s\n", safe_strerror (errno));
#ifdef HAVE_TERMIOS
if (timeout < 0)
{
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)
{
scb->current_timeout = 12;
state.termios.c_cc[VTIME] = scb->current_timeout * 10;
scb->timeout_remaining = timeout - scb->current_timeout;
}
}
#endif
#ifdef HAVE_TERMIO
if (timeout < 0)
{
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)
{
scb->current_timeout = 12;
state.termio.c_cc[VTIME] = scb->current_timeout * 10;
scb->timeout_remaining = timeout - scb->current_timeout;
}
}
#endif
if (set_tty_state (scb, &state))
fprintf_unfiltered (gdb_stderr, "set_tty_state failed: %s\n", safe_strerror (errno));
return 0;
}
#endif
}
static int
do_hardwire_readchar (struct serial *scb, int timeout)
{
int status, delta;
int detach = 0;
if (timeout > 0)
timeout++;
delta = (timeout == 0 ? 0 : 1);
while (1)
{
if (ui_loop_hook)
detach = ui_loop_hook (0);
if (detach)
return SERIAL_TIMEOUT;
scb->timeout_remaining = (timeout < 0 ? timeout : timeout - delta);
status = wait_for (scb, delta);
if (status < 0)
return status;
status = read (scb->fd, scb->buf, BUFSIZ);
if (status <= 0)
{
if (status == 0)
{
if (scb->timeout_remaining > 0)
{
timeout = scb->timeout_remaining;
continue;
}
else if (scb->timeout_remaining < 0)
continue;
else
return SERIAL_TIMEOUT;
}
else if (errno == EINTR)
continue;
else
return SERIAL_ERROR;
}
scb->bufcnt = status;
scb->bufcnt--;
scb->bufp = scb->buf;
return *scb->bufp++;
}
}
static int
hardwire_readchar (struct serial *scb, int timeout)
{
return generic_readchar (scb, timeout, do_hardwire_readchar);
}
#ifndef B19200
#define B19200 EXTA
#endif
#ifndef B38400
#define B38400 EXTB
#endif
static struct
{
int rate;
int code;
}
baudtab[] =
{
{
50, B50
}
,
{
75, B75
}
,
{
110, B110
}
,
{
134, B134
}
,
{
150, B150
}
,
{
200, B200
}
,
{
300, B300
}
,
{
600, B600
}
,
{
1200, B1200
}
,
{
1800, B1800
}
,
{
2400, B2400
}
,
{
4800, B4800
}
,
{
9600, B9600
}
,
{
19200, B19200
}
,
{
38400, B38400
}
,
#ifdef B57600
{
57600, B57600
}
,
#endif
#ifdef B115200
{
115200, B115200
}
,
#endif
#ifdef B230400
{
230400, B230400
}
,
#endif
#ifdef B460800
{
460800, B460800
}
,
#endif
{
-1, -1
}
,
};
static int
rate_to_code (int rate)
{
int i;
for (i = 0; baudtab[i].rate != -1; i++)
{
if (rate == baudtab[i].rate)
return baudtab[i].code;
else
{
if (rate < baudtab[i].rate)
{
if (i)
{
warning ("Invalid baud rate %d. Closest values are %d and %d.",
rate, baudtab[i - 1].rate, baudtab[i].rate);
}
else
{
warning ("Invalid baud rate %d. Minimum value is %d.",
rate, baudtab[0].rate);
}
return -1;
}
}
}
warning ("Invalid baud rate %d. Maximum value is %d.",
rate, baudtab[i - 1].rate);
return -1;
}
static int
hardwire_setbaudrate (struct serial *scb, int rate)
{
struct hardwire_ttystate state;
int baud_code = rate_to_code (rate);
if (baud_code < 0)
{
errno = EINVAL;
return -1;
}
if (get_tty_state (scb, &state))
return -1;
#ifdef HAVE_TERMIOS
cfsetospeed (&state.termios, baud_code);
cfsetispeed (&state.termios, baud_code);
#endif
#ifdef HAVE_TERMIO
#ifndef CIBAUD
#define CIBAUD CBAUD
#endif
state.termio.c_cflag &= ~(CBAUD | CIBAUD);
state.termio.c_cflag |= baud_code;
#endif
#ifdef HAVE_SGTTY
state.sgttyb.sg_ispeed = baud_code;
state.sgttyb.sg_ospeed = baud_code;
#endif
return set_tty_state (scb, &state);
}
static int
hardwire_setstopbits (struct serial *scb, int num)
{
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;
#endif
#ifdef HAVE_TERMIO
if (!newbit)
state.termio.c_cflag &= ~CSTOPB;
else
state.termio.c_cflag |= CSTOPB;
#endif
#ifdef HAVE_SGTTY
return 0;
#endif
return set_tty_state (scb, &state);
}
static void
hardwire_close (struct serial *scb)
{
if (scb->fd < 0)
return;
close (scb->fd);
scb->fd = -1;
}
serial_ttystate
ser_unix_nop_get_tty_state (struct serial *scb)
{
return (serial_ttystate) XMALLOC (int);
}
int
ser_unix_nop_set_tty_state (struct serial *scb, serial_ttystate ttystate)
{
return 0;
}
void
ser_unix_nop_raw (struct serial *scb)
{
return;
}
int
ser_unix_wait_for (struct serial *scb, int timeout)
{
while (1)
{
int numfds;
struct timeval tv;
fd_set readfds, exceptfds;
tv.tv_sec = timeout;
tv.tv_usec = 0;
FD_ZERO (&readfds);
FD_ZERO (&exceptfds);
FD_SET (scb->fd, &readfds);
FD_SET (scb->fd, &exceptfds);
if (timeout >= 0)
numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, &tv);
else
numfds = select (scb->fd + 1, &readfds, 0, &exceptfds, 0);
if (numfds <= 0)
{
if (numfds == 0)
return SERIAL_TIMEOUT;
else if (errno == EINTR)
continue;
else
return SERIAL_ERROR;
}
return 0;
}
}
static int
do_unix_readchar (struct serial *scb, int timeout)
{
int status;
int delta;
delta = (timeout == 0 ? 0 : 1);
while (1)
{
if (ui_loop_hook)
{
if (ui_loop_hook (0))
return SERIAL_TIMEOUT;
}
status = ser_unix_wait_for (scb, delta);
if (timeout > 0)
timeout -= delta;
if (status != SERIAL_TIMEOUT)
{
break;
}
else if (timeout == 0)
{
status = SERIAL_TIMEOUT;
break;
}
}
if (status < 0)
return status;
while (1)
{
status = read (scb->fd, scb->buf, BUFSIZ);
if (status != -1 || errno != EINTR)
break;
}
if (status <= 0)
{
if (status == 0)
return SERIAL_TIMEOUT;
else
return SERIAL_ERROR;
}
scb->bufcnt = status;
scb->bufcnt--;
scb->bufp = scb->buf;
return *scb->bufp++;
}
static int
generic_readchar (struct serial *scb, int timeout,
int (do_readchar) (struct serial *scb, int timeout))
{
int ch;
if (scb->bufcnt > 0)
{
ch = *scb->bufp;
scb->bufcnt--;
scb->bufp++;
}
else if (scb->bufcnt < 0)
{
ch = scb->bufcnt;
}
else
{
ch = do_readchar (scb, timeout);
if (ch < 0)
{
switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
case SERIAL_ERROR:
scb->bufcnt = ch;
break;
case SERIAL_TIMEOUT:
scb->bufcnt = 0;
break;
}
}
}
reschedule (scb);
return ch;
}
int
ser_unix_readchar (struct serial *scb, int timeout)
{
return generic_readchar (scb, timeout, do_unix_readchar);
}
int
ser_unix_nop_noflush_set_tty_state (struct serial *scb,
serial_ttystate new_ttystate,
serial_ttystate old_ttystate)
{
return 0;
}
void
ser_unix_nop_print_tty_state (struct serial *scb,
serial_ttystate ttystate,
struct ui_file *stream)
{
return;
}
int
ser_unix_nop_setbaudrate (struct serial *scb, int rate)
{
return 0;
}
int
ser_unix_nop_setstopbits (struct serial *scb, int num)
{
return 0;
}
int
ser_unix_write (struct serial *scb, const char *str, int len)
{
int cc;
while (len > 0)
{
cc = write (scb->fd, str, len);
if (cc < 0)
return 1;
len -= cc;
str += cc;
}
return 0;
}
int
ser_unix_nop_flush_output (struct serial *scb)
{
return 0;
}
int
ser_unix_flush_input (struct serial *scb)
{
if (scb->bufcnt >= 0)
{
scb->bufcnt = 0;
scb->bufp = scb->buf;
return 0;
}
else
return SERIAL_ERROR;
}
int
ser_unix_nop_send_break (struct serial *scb)
{
return 0;
}
int
ser_unix_nop_drain_output (struct serial *scb)
{
return 0;
}
enum {
FD_SCHEDULED = -1,
NOTHING_SCHEDULED = -2
};
static void
reschedule (struct serial *scb)
{
if (serial_is_async_p (scb))
{
int next_state;
switch (scb->async_state)
{
case FD_SCHEDULED:
if (scb->bufcnt == 0)
next_state = FD_SCHEDULED;
else
{
delete_file_handler (scb->fd);
next_state = create_timer (0, push_event, scb);
}
break;
case NOTHING_SCHEDULED:
if (scb->bufcnt == 0)
{
add_file_handler (scb->fd, fd_event, scb);
next_state = FD_SCHEDULED;
}
else
{
next_state = create_timer (0, push_event, scb);
}
break;
default:
if (scb->bufcnt == 0)
{
delete_timer (scb->async_state);
add_file_handler (scb->fd, fd_event, scb);
next_state = FD_SCHEDULED;
}
else
next_state = scb->async_state;
break;
}
if (serial_debug_p (scb))
{
switch (next_state)
{
case FD_SCHEDULED:
if (scb->async_state != FD_SCHEDULED)
fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n",
scb->fd);
break;
default:
if (scb->async_state == FD_SCHEDULED)
fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n",
scb->fd);
break;
}
}
scb->async_state = next_state;
}
}
static void
fd_event (int error, void *context)
{
struct serial *scb = context;
if (error != 0)
{
scb->bufcnt = SERIAL_ERROR;
}
else if (scb->bufcnt == 0)
{
int nr;
do
{
nr = read (scb->fd, scb->buf, BUFSIZ);
}
while (nr == -1 && errno == EINTR);
if (nr == 0)
{
scb->bufcnt = SERIAL_EOF;
}
else if (nr > 0)
{
scb->bufcnt = nr;
scb->bufp = scb->buf;
}
else
{
scb->bufcnt = SERIAL_ERROR;
}
}
scb->async_handler (scb, scb->async_context);
reschedule (scb);
}
static void
push_event (void *context)
{
struct serial *scb = context;
scb->async_state = NOTHING_SCHEDULED;
scb->async_handler (scb, scb->async_context);
reschedule (scb);
}
void
ser_unix_async (struct serial *scb,
int async_p)
{
if (async_p)
{
scb->async_state = NOTHING_SCHEDULED;
if (serial_debug_p (scb))
fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
scb->fd);
reschedule (scb);
}
else
{
if (serial_debug_p (scb))
fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n",
scb->fd);
switch (scb->async_state)
{
case FD_SCHEDULED:
delete_file_handler (scb->fd);
break;
case NOTHING_SCHEDULED:
break;
default:
delete_timer (scb->async_state);
break;
}
}
}
void
_initialize_ser_hardwire (void)
{
struct serial_ops *ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "hardwire";
ops->next = 0;
ops->open = hardwire_open;
ops->close = hardwire_close;
ops->readchar = hardwire_readchar;
ops->write = ser_unix_write;
ops->flush_output = hardwire_flush_output;
ops->flush_input = hardwire_flush_input;
ops->send_break = hardwire_send_break;
ops->go_raw = hardwire_raw;
ops->get_tty_state = hardwire_get_tty_state;
ops->set_tty_state = hardwire_set_tty_state;
ops->print_tty_state = hardwire_print_tty_state;
ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
ops->setbaudrate = hardwire_setbaudrate;
ops->setstopbits = hardwire_setstopbits;
ops->drain_output = hardwire_drain_output;
ops->async = ser_unix_async;
serial_add_interface (ops);
}