mirror of
https://github.com/UzixLS/picocom.git
synced 2025-07-19 07:21:18 +03:00
Moved native tty term_ops to ttylocal.c
Also, for better separation, the modem_XXX operations now communicate using term.[ch] pin names (MCTL_xxx), not system pin names (TIOCM_xxx).
This commit is contained in:
6
Makefile
6
Makefile
@ -48,18 +48,20 @@ linenoise-1.0/linenoise.o : linenoise-1.0/linenoise.c linenoise-1.0/linenoise.h
|
||||
## Comment these in to enable RFC2217 support
|
||||
#CPPFLAGS += -DUSE_RFC2217
|
||||
#OBJS += tn2217.o
|
||||
#tn2217.o : tn2217.c tn2217.h tncomport.h fdio.h termint.h
|
||||
#tn2217.o : tn2217.c tn2217.h tncomport.h fdio.h termint.h term.h
|
||||
|
||||
## Comment this IN to remove help strings (saves ~ 4-6 Kb).
|
||||
#CPPFLAGS += -DNO_HELP
|
||||
|
||||
|
||||
OBJS += picocom.o term.o fdio.o split.o custbaud.o termios2.o custbaud_bsd.o
|
||||
OBJS += picocom.o term.o ttylocal.o fdio.o split.o \
|
||||
custbaud.o termios2.o custbaud_bsd.o
|
||||
picocom : $(OBJS)
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
|
||||
|
||||
picocom.o : picocom.c term.h fdio.h split.h custbaud.h tn2217.h
|
||||
term.o : term.c term.h termint.h termios2.h custbaud_bsd.h custbaud.h
|
||||
ttylocal.o : ttylocal.c term.h termint.h termios2.h custbaud_bsd.h custbaud.h
|
||||
split.o : split.c split.h
|
||||
fdio.o : fdio.c fdio.h
|
||||
termios2.o : termios2.c termios2.h termbits2.h custbaud.h
|
||||
|
280
term.c
280
term.c
@ -56,26 +56,11 @@
|
||||
#define CMSPAR 0
|
||||
#endif
|
||||
|
||||
/* On these systems, use the TIOCM[BIS|BIC|GET] ioctls to manipulate
|
||||
* the modem control lines (DTR / RTS) */
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || defined(__DragonFly__) || \
|
||||
defined(__APPLE__)
|
||||
#define USE_IOCTL
|
||||
#endif
|
||||
#ifdef USE_IOCTL
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "custbaud.h"
|
||||
#ifdef USE_CUSTOM_BAUD
|
||||
#include CUSTOM_BAUD_HEAD
|
||||
#endif
|
||||
|
||||
/* Time to wait for UART to clear after a drain (in usec). */
|
||||
#define DRAIN_DELAY 200000
|
||||
|
||||
#include "term.h"
|
||||
#include "termint.h"
|
||||
|
||||
@ -85,223 +70,8 @@ static int term_initted;
|
||||
|
||||
static struct term_s term[MAX_TERMS];
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
static int
|
||||
local_init(struct term_s *t)
|
||||
{
|
||||
int rval = 0;
|
||||
const char *n;
|
||||
|
||||
do { /* dummy */
|
||||
if ( ! isatty(t->fd) ) {
|
||||
term_errno = TERM_EISATTY;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
if ( ! t->name ) {
|
||||
n = ttyname(t->fd);
|
||||
if ( n ) t->name = strdup(n);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
local_tcgetattr(struct term_s *t, struct termios *termios_out)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = tcgetattr(t->fd, termios_out);
|
||||
if ( r < 0 ) term_errno = TERM_EGETATTR;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
local_tcsetattr(struct term_s *t, int when, const struct termios *termios)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
r = tcsetattr(t->fd, when, termios);
|
||||
} while ( r < 0 && errno == EINTR );
|
||||
if ( r < 0 ) term_errno = TERM_ESETATTR;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef USE_IOCTL
|
||||
|
||||
static int
|
||||
local_modem_get(struct term_s *t, int *modem_out)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = ioctl(t->fd, TIOCMGET, modem_out);
|
||||
if ( r < 0 ) term_errno = TERM_EGETMCTL;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
local_modem_bis(struct term_s *t, const int *modem)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = ioctl(t->fd, TIOCMBIS, modem);
|
||||
if ( r < 0 ) term_errno = TERM_ESETMCTL;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
local_modem_bic(struct term_s *t, const int *modem)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = ioctl(t->fd, TIOCMBIC, modem);
|
||||
if ( r < 0 ) term_errno = TERM_ESETMCTL;
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* of USE_IOCTL */
|
||||
|
||||
static int
|
||||
local_send_break(struct term_s *t)
|
||||
{
|
||||
int r;
|
||||
do {
|
||||
r = tcsendbreak(t->fd, 0);
|
||||
} while (r < 0 && errno == EINTR );
|
||||
if ( r < 0 ) term_errno = TERM_EBREAK;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
local_flush(struct term_s *t, int selector)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = tcflush(t->fd, selector);
|
||||
if ( r < 0 ) term_errno = TERM_EFLUSH;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
local_fake_flush(struct term_s *t)
|
||||
{
|
||||
struct termios tio, tio_orig;
|
||||
int term_errno_hold = 0, errno_hold = 0;
|
||||
int r, rval = 0;
|
||||
|
||||
do { /* dummy */
|
||||
/* Get current termios */
|
||||
r = t->ops->tcgetattr(t, &tio);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
tio_orig = tio;
|
||||
/* Set flow-control to none */
|
||||
tio.c_cflag &= ~(CRTSCTS);
|
||||
tio.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
/* Apply termios */
|
||||
r = t->ops->tcsetattr(t, TCSANOW, &tio);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
/* Wait for output to drain. Without flow-control this should
|
||||
complete in finite time. */
|
||||
r = t->ops->drain(t);
|
||||
if ( r < 0 ) {
|
||||
term_errno_hold = term_errno;
|
||||
errno_hold = errno;
|
||||
rval = -1;
|
||||
/* continue */
|
||||
}
|
||||
/* Reset flow-control to original setting. */
|
||||
r = t->ops->tcsetattr(t, TCSANOW, &tio_orig);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
if ( term_errno_hold ) {
|
||||
term_errno = term_errno_hold;
|
||||
errno = errno_hold;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
local_drain(struct term_s *t)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
#ifdef __BIONIC__
|
||||
/* See: http://dan.drown.org/android/src/gdb/no-tcdrain */
|
||||
r = ioctl(t->fd, TCSBRK, 1);
|
||||
#else
|
||||
r = tcdrain(t->fd);
|
||||
#endif
|
||||
} while ( r < 0 && errno == EINTR);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_EDRAIN;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Give some time to the UART to transmit everything. Some
|
||||
systems and / or drivers corrupt the last character(s) if
|
||||
the port is immediately reconfigured, even after a
|
||||
drain. (I guess, drain does not wait for everything to
|
||||
actually be transitted on the wire). */
|
||||
if ( DRAIN_DELAY ) usleep(DRAIN_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
local_read(struct term_s *t, void *buf, unsigned bufsz)
|
||||
{
|
||||
int r;
|
||||
r = read(t->fd, buf, bufsz);
|
||||
if ( r < 0 ) term_errno = TERM_EINPUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
local_write(struct term_s *t, const void *buf, unsigned bufsz)
|
||||
{
|
||||
int r;
|
||||
r = write(t->fd, buf, bufsz);
|
||||
if ( r < 0 ) term_errno = TERM_EOUTPUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct term_ops local_term_ops = {
|
||||
.init = local_init,
|
||||
.fini = NULL,
|
||||
.tcgetattr = local_tcgetattr,
|
||||
.tcsetattr = local_tcsetattr,
|
||||
#ifdef USE_IOCTL
|
||||
.modem_get = local_modem_get,
|
||||
.modem_bis = local_modem_bis,
|
||||
.modem_bic = local_modem_bic,
|
||||
#else
|
||||
.modem_get = NULL,
|
||||
.modem_bis = NULL,
|
||||
.modem_bic = NULL,
|
||||
#endif
|
||||
.send_break = local_send_break,
|
||||
.flush = local_flush,
|
||||
.fake_flush = local_fake_flush,
|
||||
.drain = local_drain,
|
||||
.read = local_read,
|
||||
.write = local_write,
|
||||
};
|
||||
/* defined and initialized in ttylocal.c */
|
||||
extern struct term_ops ttylocal_term_ops;
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
@ -772,7 +542,7 @@ term_add (int fd, const char *name, const struct term_ops *ops)
|
||||
}
|
||||
|
||||
if ( ! ops )
|
||||
ops = &local_term_ops;
|
||||
ops = &ttylocal_term_ops;
|
||||
|
||||
t = term_new(fd, name, ops);
|
||||
if ( ! t ) {
|
||||
@ -1569,7 +1339,7 @@ term_pulse_dtr (int fd)
|
||||
}
|
||||
|
||||
if ( t->ops->modem_bic && t->ops->modem_bis ) {
|
||||
int opins = TIOCM_DTR;
|
||||
int opins = MCTL_DTR;
|
||||
|
||||
r = t->ops->modem_bic(t, &opins);
|
||||
if ( r < 0 ) {
|
||||
@ -1636,46 +1406,28 @@ set_pins (int fd, int raise, int pins)
|
||||
return rol(t, &pins);
|
||||
}
|
||||
|
||||
int term_raise_dtr(int fd) { return set_pins(fd, 1, TIOCM_DTR); }
|
||||
int term_lower_dtr(int fd) { return set_pins(fd, 0, TIOCM_DTR); }
|
||||
int term_raise_rts(int fd) { return set_pins(fd, 1, TIOCM_RTS); }
|
||||
int term_lower_rts(int fd) { return set_pins(fd, 0, TIOCM_RTS); }
|
||||
int term_raise_dtr(int fd) { return set_pins(fd, 1, MCTL_DTR); }
|
||||
int term_lower_dtr(int fd) { return set_pins(fd, 0, MCTL_DTR); }
|
||||
int term_raise_rts(int fd) { return set_pins(fd, 1, MCTL_RTS); }
|
||||
int term_lower_rts(int fd) { return set_pins(fd, 0, MCTL_RTS); }
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
int
|
||||
term_get_mctl (int fd)
|
||||
{
|
||||
int mctl;
|
||||
int r, mctl;
|
||||
struct term_s *t;
|
||||
|
||||
do { /* dummy */
|
||||
t = term_find(fd);
|
||||
if ( ! t ) return -1;
|
||||
|
||||
t = term_find(fd);
|
||||
if ( ! t ) {
|
||||
mctl = -1;
|
||||
break;
|
||||
}
|
||||
if ( ! t->ops->modem_get ) {
|
||||
return MCTL_UNAVAIL;
|
||||
}
|
||||
|
||||
if ( t->ops->modem_get ) {
|
||||
int r, pmctl;
|
||||
|
||||
r = t->ops->modem_get(t, &pmctl);
|
||||
if (r < 0) {
|
||||
mctl = -1;
|
||||
break;
|
||||
}
|
||||
mctl = 0;
|
||||
if (pmctl & TIOCM_DTR) mctl |= MCTL_DTR;
|
||||
if (pmctl & TIOCM_DSR) mctl |= MCTL_DSR;
|
||||
if (pmctl & TIOCM_CD) mctl |= MCTL_DCD;
|
||||
if (pmctl & TIOCM_RTS) mctl |= MCTL_RTS;
|
||||
if (pmctl & TIOCM_CTS) mctl |= MCTL_CTS;
|
||||
if (pmctl & TIOCM_RI) mctl |= MCTL_RI;
|
||||
} else {
|
||||
mctl = MCTL_UNAVAIL;
|
||||
}
|
||||
} while(0);
|
||||
r = t->ops->modem_get(t, &mctl);
|
||||
if (r < 0) return -1;
|
||||
|
||||
return mctl;
|
||||
}
|
||||
|
61
tn2217.c
61
tn2217.c
@ -55,10 +55,9 @@
|
||||
#include "tncomport.h"
|
||||
#include "tn2217.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/telnet.h>
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
/* Disable debugging code altogether */
|
||||
#define DEBUG 0
|
||||
#define DB(fl, ...) /* nothing */
|
||||
@ -230,17 +229,13 @@ repr_modem(int m)
|
||||
static char out[256];
|
||||
|
||||
snprintf(out, sizeof out,
|
||||
"<%s%s%s%s%s%s%s%s%s>",
|
||||
(m & TIOCM_LE) ? ",dsr": "",
|
||||
(m & TIOCM_DTR) ? ",dtr": "",
|
||||
(m & TIOCM_RTS) ? ",rts": "",
|
||||
(m & TIOCM_ST) ? ",st" : "",
|
||||
(m & TIOCM_SR) ? ",sr" : "",
|
||||
(m & TIOCM_CTS) ? ",cts": "",
|
||||
(m & TIOCM_CD) ? ",cd" : "",
|
||||
(m & TIOCM_RI) ? ",ri" : "",
|
||||
(m & TIOCM_DSR) ? ",dsr": ""
|
||||
);
|
||||
"<%s%s%s%s%s%s>",
|
||||
(m & MCTL_DTR) ? ",dtr":"",
|
||||
(m & MCTL_DSR) ? ",dsr":"",
|
||||
(m & MCTL_DCD) ? ",dcd":"",
|
||||
(m & MCTL_RTS) ? ",rts":"",
|
||||
(m & MCTL_CTS) ? ",cts":"",
|
||||
(m & MCTL_RI) ? ",ri":"");
|
||||
if (out[1] == ',') {
|
||||
out[1] = '<';
|
||||
return &out[1];
|
||||
@ -740,7 +735,7 @@ comport_send_set_dtr(struct term_s *t, int modem)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
if (modem & TIOCM_DTR)
|
||||
if (modem & MCTL_DTR)
|
||||
val = COMPORT_CONTROL_DTR_ON;
|
||||
else
|
||||
val = COMPORT_CONTROL_DTR_OFF;
|
||||
@ -753,7 +748,7 @@ comport_send_set_rts(struct term_s *t, int modem)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
if (modem & TIOCM_RTS)
|
||||
if (modem & MCTL_RTS)
|
||||
val = COMPORT_CONTROL_RTS_ON;
|
||||
else
|
||||
val = COMPORT_CONTROL_RTS_OFF;
|
||||
@ -965,8 +960,8 @@ comport_recv_cmd(struct term_s *t, unsigned char cmd,
|
||||
/* DTR changes and COMPORT_CONTROL_DTR_REQUEST reply */
|
||||
case COMPORT_CONTROL_DTR_ON:
|
||||
case COMPORT_CONTROL_DTR_OFF:
|
||||
val = (data[0] == COMPORT_CONTROL_DTR_ON) ? TIOCM_DTR : 0;
|
||||
*modem &= ~TIOCM_DTR;
|
||||
val = (data[0] == COMPORT_CONTROL_DTR_ON) ? MCTL_DTR : 0;
|
||||
*modem &= ~MCTL_DTR;
|
||||
*modem |= val;
|
||||
DB(DB_CMP, "[received: COMPORT SET_CONTROL: %d: dtr=%u]\r\n",
|
||||
data[0], !!val);
|
||||
@ -974,8 +969,8 @@ comport_recv_cmd(struct term_s *t, unsigned char cmd,
|
||||
/* RTS changes and COMPORT_CONTROL_RTS_REQUEST reply */
|
||||
case COMPORT_CONTROL_RTS_ON:
|
||||
case COMPORT_CONTROL_RTS_OFF:
|
||||
val = (data[0] == COMPORT_CONTROL_RTS_ON) ? TIOCM_RTS : 0;
|
||||
*modem &= ~TIOCM_RTS;
|
||||
val = (data[0] == COMPORT_CONTROL_RTS_ON) ? MCTL_RTS : 0;
|
||||
*modem &= ~MCTL_RTS;
|
||||
*modem |= val;
|
||||
DB(DB_CMP, "[received: COMPORT SET_CONTROL: %d: rts=%u]\r\n",
|
||||
data[0], !!val);
|
||||
@ -991,12 +986,12 @@ comport_recv_cmd(struct term_s *t, unsigned char cmd,
|
||||
/* Updates are masked by COMPORT_SET_MODEMSTATE_MASK elsewhere */
|
||||
if (datalen >= 1) {
|
||||
val = 0;
|
||||
if (data[0] & COMPORT_MODEM_CD) val |= TIOCM_CD;
|
||||
if (data[0] & COMPORT_MODEM_RI) val |= TIOCM_RI;
|
||||
if (data[0] & COMPORT_MODEM_DSR) val |= TIOCM_DSR;
|
||||
if (data[0] & COMPORT_MODEM_CTS) val |= TIOCM_CTS;
|
||||
if (data[0] & COMPORT_MODEM_CD) val |= MCTL_DCD;
|
||||
if (data[0] & COMPORT_MODEM_RI) val |= MCTL_RI;
|
||||
if (data[0] & COMPORT_MODEM_DSR) val |= MCTL_DSR;
|
||||
if (data[0] & COMPORT_MODEM_CTS) val |= MCTL_CTS;
|
||||
DB(DB_CMP, "[received: COMPORT MODEMSTATE: %s]\r\n", repr_modem(val));
|
||||
*modem &= ~(TIOCM_CD|TIOCM_RI|TIOCM_DSR|TIOCM_CTS);
|
||||
*modem &= ~(MCTL_DCD|MCTL_RI|MCTL_DSR|MCTL_CTS);
|
||||
*modem |= val;
|
||||
}
|
||||
break;
|
||||
@ -1037,7 +1032,7 @@ tn2217_init(struct term_s *t)
|
||||
cfsetispeed(&s->termios, B0); /* This means "same as ospeed" */
|
||||
|
||||
/* Normally DTR and RTS are asserted, but an update can change that */
|
||||
s->modem = TIOCM_DTR | TIOCM_RTS;
|
||||
s->modem = MCTL_DTR | MCTL_RTS;
|
||||
|
||||
/* Start the negotiations. */
|
||||
r = opt_will(t, TELOPT_BINARY);
|
||||
@ -1106,15 +1101,15 @@ tn2217_modem_bis(struct term_s *t, const int *modem)
|
||||
s->modem |= *modem;
|
||||
|
||||
if (s->can_comport) {
|
||||
if (*modem & TIOCM_DTR) {
|
||||
r = comport_send_set_dtr(t, TIOCM_DTR);
|
||||
if (*modem & MCTL_DTR) {
|
||||
r = comport_send_set_dtr(t, MCTL_DTR);
|
||||
if (r < 0) return r;
|
||||
}
|
||||
if (*modem & TIOCM_RTS) {
|
||||
r = comport_send_set_rts(t, TIOCM_RTS);
|
||||
if (*modem & MCTL_RTS) {
|
||||
r = comport_send_set_rts(t, MCTL_RTS);
|
||||
if (r < 0) return r;
|
||||
}
|
||||
} else if (*modem & (TIOCM_DTR|TIOCM_RTS))
|
||||
} else if (*modem & (MCTL_DTR|MCTL_RTS))
|
||||
s->set_modem = 1;
|
||||
|
||||
return 0;
|
||||
@ -1131,15 +1126,15 @@ tn2217_modem_bic(struct term_s *t, const int *modem)
|
||||
s->modem &= ~*modem;
|
||||
|
||||
if (s->can_comport) {
|
||||
if (*modem & TIOCM_DTR) {
|
||||
if (*modem & MCTL_DTR) {
|
||||
r = comport_send_set_dtr(t, 0);
|
||||
if ( r < 0 ) return r;
|
||||
}
|
||||
if (*modem & TIOCM_RTS) {
|
||||
if (*modem & MCTL_RTS) {
|
||||
r = comport_send_set_rts(t, 0);
|
||||
if ( r < 0 ) return r;
|
||||
}
|
||||
} else if (*modem & (TIOCM_DTR|TIOCM_RTS))
|
||||
} else if (*modem & (MCTL_DTR|MCTL_RTS))
|
||||
s->set_modem = 1;
|
||||
|
||||
return 0;
|
||||
|
312
ttylocal.c
Normal file
312
ttylocal.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* vi: set sw=4 ts=4:
|
||||
*
|
||||
* ttylocal.c
|
||||
*
|
||||
* General purpose terminal handling library. Local (native) tty
|
||||
* handling.
|
||||
*
|
||||
* by Nick Patavalis (npat@efault.net)
|
||||
*
|
||||
* 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 the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
/* On these systems, use the TIOCM[BIS|BIC|GET] ioctls to manipulate
|
||||
* the modem control lines (DTR / RTS) */
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || defined(__DragonFly__) || \
|
||||
defined(__APPLE__)
|
||||
#define USE_IOCTL
|
||||
#endif
|
||||
#ifdef USE_IOCTL
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "custbaud.h"
|
||||
#ifdef USE_CUSTOM_BAUD
|
||||
#include CUSTOM_BAUD_HEAD
|
||||
#endif
|
||||
|
||||
/* Time to wait for UART to clear after a drain (in usec). */
|
||||
#define DRAIN_DELAY 200000
|
||||
|
||||
#include "term.h"
|
||||
#include "termint.h"
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
static int
|
||||
ttylocal_init(struct term_s *t)
|
||||
{
|
||||
int rval = 0;
|
||||
const char *n;
|
||||
|
||||
do { /* dummy */
|
||||
if ( ! isatty(t->fd) ) {
|
||||
term_errno = TERM_EISATTY;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
if ( ! t->name ) {
|
||||
n = ttyname(t->fd);
|
||||
if ( n ) t->name = strdup(n);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_tcgetattr(struct term_s *t, struct termios *termios_out)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = tcgetattr(t->fd, termios_out);
|
||||
if ( r < 0 ) term_errno = TERM_EGETATTR;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_tcsetattr(struct term_s *t, int when, const struct termios *termios)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
r = tcsetattr(t->fd, when, termios);
|
||||
} while ( r < 0 && errno == EINTR );
|
||||
if ( r < 0 ) term_errno = TERM_ESETATTR;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef USE_IOCTL
|
||||
|
||||
static int
|
||||
sys2term (int sys)
|
||||
{
|
||||
int term = 0;
|
||||
if (sys & TIOCM_DTR) term |= MCTL_DTR;
|
||||
if (sys & TIOCM_DSR) term |= MCTL_DSR;
|
||||
if (sys & TIOCM_CD) term |= MCTL_DCD;
|
||||
if (sys & TIOCM_RTS) term |= MCTL_RTS;
|
||||
if (sys & TIOCM_CTS) term |= MCTL_CTS;
|
||||
if (sys & TIOCM_RI) term |= MCTL_RI;
|
||||
return term;
|
||||
}
|
||||
|
||||
static int
|
||||
term2sys (int term)
|
||||
{
|
||||
int sys = 0;
|
||||
if (term & MCTL_DTR) sys |= TIOCM_DTR;
|
||||
if (term & MCTL_DSR) sys |= TIOCM_DSR;
|
||||
if (term & MCTL_DCD) sys |= TIOCM_CD;
|
||||
if (term & MCTL_RTS) sys |= TIOCM_RTS;
|
||||
if (term & MCTL_CTS) sys |= TIOCM_CTS;
|
||||
if (term & MCTL_RI) sys |= TIOCM_RI;
|
||||
return sys;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_modem_get(struct term_s *t, int *pins)
|
||||
{
|
||||
int r, syspins;
|
||||
|
||||
r = ioctl(t->fd, TIOCMGET, &syspins);
|
||||
if ( r < 0 ) { term_errno = TERM_EGETMCTL; return r; }
|
||||
*pins = sys2term(syspins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_modem_bis(struct term_s *t, const int *pins)
|
||||
{
|
||||
int r, syspins;
|
||||
|
||||
syspins = term2sys(*pins);
|
||||
r = ioctl(t->fd, TIOCMBIS, &syspins);
|
||||
if ( r < 0 ) term_errno = TERM_ESETMCTL;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_modem_bic(struct term_s *t, const int *pins)
|
||||
{
|
||||
int r, syspins;
|
||||
|
||||
syspins = term2sys(*pins);
|
||||
r = ioctl(t->fd, TIOCMBIC, &syspins);
|
||||
if ( r < 0 ) term_errno = TERM_ESETMCTL;
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* of USE_IOCTL */
|
||||
|
||||
static int
|
||||
ttylocal_send_break(struct term_s *t)
|
||||
{
|
||||
int r;
|
||||
do {
|
||||
r = tcsendbreak(t->fd, 0);
|
||||
} while (r < 0 && errno == EINTR );
|
||||
if ( r < 0 ) term_errno = TERM_EBREAK;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_flush(struct term_s *t, int selector)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = tcflush(t->fd, selector);
|
||||
if ( r < 0 ) term_errno = TERM_EFLUSH;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_fake_flush(struct term_s *t)
|
||||
{
|
||||
struct termios tio, tio_orig;
|
||||
int term_errno_hold = 0, errno_hold = 0;
|
||||
int r, rval = 0;
|
||||
|
||||
do { /* dummy */
|
||||
/* Get current termios */
|
||||
r = t->ops->tcgetattr(t, &tio);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
tio_orig = tio;
|
||||
/* Set flow-control to none */
|
||||
tio.c_cflag &= ~(CRTSCTS);
|
||||
tio.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
/* Apply termios */
|
||||
r = t->ops->tcsetattr(t, TCSANOW, &tio);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
/* Wait for output to drain. Without flow-control this should
|
||||
complete in finite time. */
|
||||
r = t->ops->drain(t);
|
||||
if ( r < 0 ) {
|
||||
term_errno_hold = term_errno;
|
||||
errno_hold = errno;
|
||||
rval = -1;
|
||||
/* continue */
|
||||
}
|
||||
/* Reset flow-control to original setting. */
|
||||
r = t->ops->tcsetattr(t, TCSANOW, &tio_orig);
|
||||
if ( r < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
if ( term_errno_hold ) {
|
||||
term_errno = term_errno_hold;
|
||||
errno = errno_hold;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
ttylocal_drain(struct term_s *t)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
#ifdef __BIONIC__
|
||||
/* See: http://dan.drown.org/android/src/gdb/no-tcdrain */
|
||||
r = ioctl(t->fd, TCSBRK, 1);
|
||||
#else
|
||||
r = tcdrain(t->fd);
|
||||
#endif
|
||||
} while ( r < 0 && errno == EINTR);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_EDRAIN;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Give some time to the UART to transmit everything. Some
|
||||
systems and / or drivers corrupt the last character(s) if
|
||||
the port is immediately reconfigured, even after a
|
||||
drain. (I guess, drain does not wait for everything to
|
||||
actually be transitted on the wire). */
|
||||
if ( DRAIN_DELAY ) usleep(DRAIN_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ttylocal_read(struct term_s *t, void *buf, unsigned bufsz)
|
||||
{
|
||||
int r;
|
||||
r = read(t->fd, buf, bufsz);
|
||||
if ( r < 0 ) term_errno = TERM_EINPUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ttylocal_write(struct term_s *t, const void *buf, unsigned bufsz)
|
||||
{
|
||||
int r;
|
||||
r = write(t->fd, buf, bufsz);
|
||||
if ( r < 0 ) term_errno = TERM_EOUTPUT;
|
||||
return r;
|
||||
}
|
||||
|
||||
const struct term_ops ttylocal_term_ops = {
|
||||
.init = ttylocal_init,
|
||||
.fini = NULL,
|
||||
.tcgetattr = ttylocal_tcgetattr,
|
||||
.tcsetattr = ttylocal_tcsetattr,
|
||||
#ifdef USE_IOCTL
|
||||
.modem_get = ttylocal_modem_get,
|
||||
.modem_bis = ttylocal_modem_bis,
|
||||
.modem_bic = ttylocal_modem_bic,
|
||||
#else
|
||||
.modem_get = NULL,
|
||||
.modem_bis = NULL,
|
||||
.modem_bic = NULL,
|
||||
#endif
|
||||
.send_break = ttylocal_send_break,
|
||||
.flush = ttylocal_flush,
|
||||
.fake_flush = ttylocal_fake_flush,
|
||||
.drain = ttylocal_drain,
|
||||
.read = ttylocal_read,
|
||||
.write = ttylocal_write,
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
Reference in New Issue
Block a user