/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* This is a new line.c, which consists of line.c and culine.c
* merged together.
*/
#include "uucp.h"
static struct sg_spds {
int sp_val,
sp_name;
} spds[] = {
{ 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},
#ifdef EXTA
{19200, EXTA},
#endif
#ifdef B19200
{19200, B19200},
#endif
#ifdef B38400
{38400, B38400},
#endif
{57600, B57600},
{76800, B76800},
{115200, B115200},
{153600, B153600},
{230400, B230400},
{307200, B307200},
{460800, B460800},
{921600, B921600},
{0, 0}
};
#define PACKSIZE 64
#define HEADERSIZE 6
GLOBAL int
packsize = PACKSIZE,
xpacksize = PACKSIZE;
#define SNDFILE 'S'
#define RCVFILE 'R'
#define RESET 'X'
#ifdef PKSPEEDUP
GLOBAL int linebaudrate; /* for speedup hook in pk1.c */
#endif /* PKSPEEDUP */
static int Saved_line; /* was savline() successful? */
static int Saved_termios; /* was termios saved? */
GLOBAL int
Oddflag = 0, /* Default is no parity */
Evenflag = 0, /* Default is no parity */
Duplex = 1, /* Default is full duplex */
Terminal = 0, /* Default is no terminal */
term_8bit = -1, /* Default to terminal setting or 8 bit */
line_8bit = -1; /* Default is same as terminal */
static char *P_PARITY = "Parity option error\r\n";
#ifdef ATTSVTTY
static struct termio Savettyb;
static struct termios Savettybs;
/*
* set speed/echo/mode...
* tty -> terminal name
* spwant -> speed
* type -> type
*
* if spwant == 0, speed is untouched
* type is unused, but needed for compatibility
*
* return:
* none
*/
/*ARGSUSED*/
GLOBAL void
fixline(tty, spwant, type)
int tty, spwant, type;
{
register struct sg_spds *ps;
struct termio ttbuf;
struct termios ttbufs;
int speed = -1;
int i, istermios, ospeed;
DEBUG(6, "fixline(%d, ", tty);
DEBUG(6, "%d)\n", spwant);
if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
return;
} else {
ttbufs.c_lflag = ttbuf.c_lflag;
ttbufs.c_oflag = ttbuf.c_oflag;
ttbufs.c_iflag = ttbuf.c_iflag;
ttbufs.c_cflag = ttbuf.c_cflag;
for (i = 0; i < NCC; i++)
ttbufs.c_cc[i] = ttbuf.c_cc[i];
}
}
if (spwant > 0) {
for (ps = spds; ps->sp_val; ps++)
if (ps->sp_val == spwant) {
speed = ps->sp_name;
break;
}
if (speed < 0)
DEBUG(5, "speed (%d) not supported\n", spwant);
ASSERT(speed >= 0, "BAD SPEED", "", spwant);
ttbufs.c_cflag &= 0xffff0000;
cfsetospeed(&ttbufs, speed);
} else { /* determine the current speed setting */
ospeed = cfgetospeed(&ttbufs);
ttbufs.c_cflag &= 0xffff0000;
cfsetospeed(&ttbufs, ospeed);
for (ps = spds; ps->sp_val; ps++)
if (ps->sp_name == ospeed) {
spwant = ps->sp_val;
break;
}
}
/*
* In order to prevent attempts at split speed, all baud rate
* bitfields should be cleared. Thus cfsetispeed is used to
* set the speed to zero.
*/
(void) cfsetispeed(&ttbufs, 0);
ttbufs.c_iflag &= 0xffff0000;
ttbufs.c_oflag &= 0xffff0000;
ttbufs.c_lflag &= 0xffff0000;
#ifdef PKSPEEDUP
linebaudrate = spwant;
#endif /* PKSPEEDUP */
#ifdef NO_MODEM_CTRL
/* CLOCAL may cause problems on pdp11s with DHs */
if (type == D_DIRECT) {
DEBUG(4, "fixline - direct\n%s", "");
ttbufs.c_cflag |= CLOCAL;
} else
#endif /* NO_MODEM_CTRL */
ttbufs.c_cflag &= ~CLOCAL;
if (!EQUALS(Progname, "uucico")) {
/* set attributes associated with -h, -t, -e, and -o options */
ttbufs.c_iflag = (IGNPAR | IGNBRK | IXON | IXOFF);
ttbufs.c_cc[VEOF] = '\1';
ttbufs.c_cflag |= (CREAD | (speed ? HUPCL : 0));
if (line_8bit) {
ttbufs.c_cflag |= CS8;
ttbufs.c_iflag &= ~ISTRIP;
} else {
if (Evenflag) { /* even parity -e */
ttbufs.c_cflag &= ~PARODD;
} else if (Oddflag) { /* odd parity -o */
ttbufs.c_cflag |= PARODD;
}
ttbufs.c_cflag |= CS7|PARENB;
ttbufs.c_iflag |= ISTRIP;
}
if (!Duplex) /* half duplex -h */
ttbufs.c_iflag &= ~(IXON | IXOFF);
if (Terminal) /* -t */
ttbufs.c_oflag |= (OPOST | ONLCR);
} else { /* non-uucico */
ttbufs.c_cflag |= (CS8 | CREAD | (speed ? HUPCL : 0));
ttbufs.c_cc[VMIN] = HEADERSIZE;
ttbufs.c_cc[VTIME] = 1;
}
if (istermios < 0) {
ttbuf.c_lflag = ttbufs.c_lflag;
ttbuf.c_oflag = ttbufs.c_oflag;
ttbuf.c_iflag = ttbufs.c_iflag;
ttbuf.c_cflag = ttbufs.c_cflag;
for (i = 0; i < NCC; i++)
ttbuf.c_cc[i] = ttbufs.c_cc[i];
ASSERT((*Ioctl)(tty, TCSETAW, &ttbuf) >= 0,
"RETURN FROM fixline ioctl", "", errno);
} else {
ASSERT((*Ioctl)(tty, TCSETSW, &ttbufs) >= 0,
"RETURN FROM fixline ioctl", "", errno);
}
}
GLOBAL void
sethup(dcf)
int dcf;
{
struct termio ttbuf;
if ((*Ioctl)(dcf, TCGETA, &ttbuf) != 0)
return;
if (!(ttbuf.c_cflag & HUPCL)) {
ttbuf.c_cflag |= HUPCL;
(void) (*Ioctl)(dcf, TCSETAW, &ttbuf);
}
}
GLOBAL void
ttygenbrk(fn)
register int fn;
{
if (isatty(fn))
(void) (*Ioctl)(fn, TCSBRK, 0);
}
/*
* optimize line setting for sending or receiving files
* return:
* none
*/
GLOBAL void
setline(type)
register char type;
{
static struct termio tbuf;
static struct termios tbufs;
int i, vtime, istermios, ospeed;
DEBUG(2, "setline - %c\n", type);
if ((istermios = (*Ioctl)(Ifn, TCGETS, &tbufs)) < 0) {
if ((*Ioctl)(Ifn, TCGETA, &tbuf) != 0) {
return;
} else {
tbufs.c_lflag = tbuf.c_lflag;
tbufs.c_oflag = tbuf.c_oflag;
tbufs.c_iflag = tbuf.c_iflag;
tbufs.c_cflag = tbuf.c_cflag;
for (i = 0; i < NCC; i++)
tbufs.c_cc[i] = tbuf.c_cc[i];
}
}
switch (type) {
case RCVFILE:
ospeed = cfgetospeed(&tbufs);
switch (ospeed) {
#ifdef B19200
case B19200:
#else
#ifdef EXTA
case EXTA:
#endif
#endif
#ifdef B38400
case B38400:
#endif
case B57600:
case B76800:
case B115200:
case B153600:
case B230400:
case B307200:
case B460800:
case B921600:
case B9600:
vtime = 1;
break;
case B4800:
vtime = 4;
break;
default:
vtime = 8;
break;
}
if (tbufs.c_cc[VMIN] != packsize ||
tbufs.c_cc[VTIME] != vtime) {
tbufs.c_cc[VMIN] = packsize;
tbufs.c_cc[VTIME] = vtime;
if (istermios < 0) {
tbuf.c_lflag = tbufs.c_lflag;
tbuf.c_oflag = tbufs.c_oflag;
tbuf.c_iflag = tbufs.c_iflag;
tbuf.c_cflag = tbufs.c_cflag;
for (i = 0; i < NCC; i++)
tbuf.c_cc[i] = tbufs.c_cc[i];
if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
DEBUG(4, "setline Ioctl failed errno=%d\n",
errno);
} else {
if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
DEBUG(4,
"setline Ioctl failed errno=%d\n",
errno);
}
}
break;
case SNDFILE:
case RESET:
if (tbufs.c_cc[VMIN] != HEADERSIZE) {
tbufs.c_cc[VMIN] = HEADERSIZE;
if (istermios < 0) {
tbuf.c_lflag = tbufs.c_lflag;
tbuf.c_oflag = tbufs.c_oflag;
tbuf.c_iflag = tbufs.c_iflag;
tbuf.c_cflag = tbufs.c_cflag;
for (i = 0; i < NCC; i++)
tbuf.c_cc[i] = tbufs.c_cc[i];
if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
DEBUG(4,
"setline Ioctl failed errno=%d\n",
errno);
} else {
if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
DEBUG(4,
"setline Ioctl failed errno=%d\n",
errno);
}
}
break;
}
}
GLOBAL int
savline()
{
if ((Saved_termios = (*Ioctl)(0, TCGETS, &Savettybs)) < 0) {
if ((*Ioctl)(0, TCGETA, &Savettyb) != 0) {
Saved_line = FALSE;
} else {
Saved_line = TRUE;
Savettyb.c_cflag =
(Savettyb.c_cflag & ~CS8) | CS7 | PARENB;
Savettyb.c_oflag |= OPOST;
Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
}
} else {
Saved_line = TRUE;
Savettybs.c_cflag = (Savettybs.c_cflag & ~CS8) | CS7 | PARENB;
Savettybs.c_oflag |= OPOST;
Savettybs.c_lflag |= (ISIG|ICANON|ECHO);
}
return (0);
}
#ifdef SYTEK
/*
* sytfixline(tty, spwant) set speed/echo/mode...
* int tty, spwant;
*
* return codes: none
*/
GLOBAL void
sytfixline(tty, spwant)
int tty, spwant;
{
struct termio ttbuf;
struct termios ttbufs;
struct sg_spds *ps;
int speed = -1;
int i, ret, istermios;
if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
return;
} else {
ttbufs.c_lflag = ttbuf.c_lflag;
ttbufs.c_oflag = ttbuf.c_oflag;
ttbufs.c_iflag = ttbuf.c_iflag;
ttbufs.c_cflag = ttbuf.c_cflag;
for (i = 0; i < NCC; i++)
ttbufs.c_cc[i] = ttbuf.c_cc[i];
}
}
for (ps = spds; ps->sp_val >= 0; ps++)
if (ps->sp_val == spwant)
speed = ps->sp_name;
DEBUG(4, "sytfixline - speed= %d\n", speed);
ASSERT(speed >= 0, "BAD SPEED", "", spwant);
ttbufs.c_iflag &= 0xffff0000;
ttbufs.c_oflag &= 0xffff0000;
ttbufs.c_lflag &= 0xffff0000;
ttbufs.c_cflag &= 0xffff0000;
cfsetospeed(&ttbufs, speed);
ttbufs.c_cflag |= (CS8|CLOCAL);
ttbufs.c_cc[VMIN] = 6;
ttbufs.c_cc[VTIME] = 1;
if (istermios < 0) {
ttbuf.c_lflag = ttbufs.c_lflag;
ttbuf.c_oflag = ttbufs.c_oflag;
ttbuf.c_iflag = ttbufs.c_iflag;
ttbuf.c_cflag = ttbufs.c_cflag;
for (i = 0; i < NCC; i++)
ttbuf.c_cc[i] = ttbufs.c_cc[i];
ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
} else
ret = (*Ioctl)(tty, TCSETAWS &ttbufs);
ASSERT(ret >= 0, "RETURN FROM sytfixline", "", ret);
}
GLOBAL void
sytfix2line(tty)
int tty;
{
struct termio ttbuf;
int ret;
if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0)
return;
ttbuf.c_cflag &= ~CLOCAL;
ttbuf.c_cflag |= CREAD|HUPCL;
ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
ASSERT(ret >= 0, "RETURN FROM sytfix2line", "", ret);
}
#endif /* SYTEK */
GLOBAL int
restline()
{
if (Saved_line == TRUE) {
if (Saved_termios < 0)
return ((*Ioctl)(0, TCSETAW, &Savettyb));
else
return ((*Ioctl)(0, TCSETSW, &Savettybs));
}
return (0);
}
#else /* !ATTSVTTY */
static struct sgttyb Savettyb;
/*
* fixline(tty, spwant, type) set speed/echo/mode...
* int tty, spwant;
*
* if spwant == 0, speed is untouched
* type is unused, but needed for compatibility
*
* return codes: none
*/
/*ARGSUSED*/
GLOBAL void
fixline(tty, spwant, type)
int tty, spwant, type;
{
struct sgttyb ttbuf;
struct sg_spds *ps;
int speed = -1;
DEBUG(6, "fixline(%d, ", tty);
DEBUG(6, "%d)\n", spwant);
if ((*Ioctl)(tty, TIOCGETP, &ttbuf) != 0)
return;
if (spwant > 0) {
for (ps = spds; ps->sp_val; ps++)
if (ps->sp_val == spwant) {
speed = ps->sp_name;
break;
}
ASSERT(speed >= 0, "BAD SPEED", "", spwant);
ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
} else {
for (ps = spds; ps->sp_val; ps++)
if (ps->sp_name == ttbuf.sg_ispeed) {
spwant = ps->sp_val;
break;
}
ASSERT(spwant >= 0, "BAD SPEED", "", ttbuf.sg_ispeed);
}
ttbuf.sg_flags = (ANYP | RAW);
#ifdef PKSPEEDUP
linebaudrate = spwant;
#endif /* PKSPEEDUP */
(void) (*Ioctl)(tty, TIOCSETP, &ttbuf);
(void) (*Ioctl)(tty, TIOCHPCL, STBNULL);
(void) (*Ioctl)(tty, TIOCEXCL, STBNULL);
}
GLOBAL void
sethup(dcf)
int dcf;
{
if (isatty(dcf))
(void) (*Ioctl)(dcf, TIOCHPCL, STBNULL);
}
/*
* genbrk send a break
*
* return codes; none
*/
GLOBAL void
ttygenbrk(fn)
{
if (isatty(fn)) {
(void) (*Ioctl)(fn, TIOCSBRK, 0);
#ifndef V8
nap(HZ/10); /* 0.1 second break */
(void) (*Ioctl)(fn, TIOCCBRK, 0);
#endif
}
}
/*
* V7 and RT aren't smart enough for this -- linebaudrate is the best
* they can do.
*/
/*ARGSUSED*/
GLOBAL void
setline(dummy) { }
GLOBAL int
savline()
{
if ((*Ioctl)(0, TIOCGETP, &Savettyb) != 0)
Saved_line = FALSE;
else {
Saved_line = TRUE;
Savettyb.sg_flags |= ECHO;
Savettyb.sg_flags &= ~RAW;
}
return (0);
}
GLOBAL int
restline()
{
if (Saved_line == TRUE)
return ((*Ioctl)(0, TIOCSETP, &Savettyb));
return (0);
}
#endif