/***+
* Makeraw(dev,path,ifl,ofl,cfl,lfl);
* MakeRaw(dev,path);
*     int dev;   -- Unix file descriptor.
*    char*path;  -- File name for messages.
*     int ifl,ofl,cfl,lfl;
*
* Tell the device driver to do raw I/O on the device.   Unfortunately,
* this  is  done  in different ways on different brands of Unix.  Make
* sure that your system is included somewhere in the  following  list.
* Note  that the BSD-like systems need the ldisc variable, which is in
* makesane.c, so you will have to link that routine with your program,
* too.   The  return value is the return value of the ioctl to set raw
* mode; <0 means failure.
*
* The *fl args, if nonzero, will be used for the four kinds of  flags.
* Normally,  we  want  all of them to be zero, which gives us the most
* raw data channel that Unix knows about, and the MakeRaw()  macro  is
* defined for that purpose.
*
* The path arg is used in diagnostics only.
*
* At  present,  there are three "styles" of terminal interface that we
* know how to  handle,  indicated  by  the  "termio",  "termios",  and
* "sgtty" header files.  Some systems have more than one of these, and
* you might want to make a special case in the #ifs below.
+***/

#include "local.h"
:1#include "V.h"
#include "sys_ioctl.h"
#if USE_termio
#	include "termio.h"
global	TERM raw_trm;
global	TERM sav_trm;
global	Flag got_trm;	/* In makesane.c */
#endif
#if USE_sgtty
#	include "sys_sgtty.h"
extern	int ldisc;	/* In makesane.c */
global	TERM sgttyb;
#endif
#if USE_termios
#include "termios.h"
global	TERM raw_trm;
global	TERM sav_trm;
global	Flag got_trm;	/* In makesane.c */
#endif
int  baudcode = 0;	/* CBAUD mask for termio ioctl (B1200, B9600, etc) */
int  baudrate = 0;	/* Numeric value of baud rate (1200, 9600, etc) */
int  modemfl = 1;	/* Is there a modem present on the port? */
Flag noxclfl = 1;	/* Suppress exclusive-use, if this system has it */

int  flowcontrol = 0;
unsigned ttytimeout = 1;	/* Timeout in 0.1 second quanta */
char *m_noraw = "%s	### Can't do raw I/O on file %d=\"%s\" [Err %d=%s]";

extern int errno;
extern int zero;

makeraw(dev,path,ifl,ofl,cfl,lfl)
	int   dev;		/* File number */
	char* path;
	int   ifl;
	int   ofl;
	int   cfl;
	int   lfl;
{	int   i=0;

:f	Fenter("makeraw");
	V4 "Called with dev=%d `%s' i=0%o o=0%o c=0%o l=0%o",
		dev,path,ifl,ofl,cfl,lfl D;
:2	P2 "%s	Set file %d=\"%s\" to raw mode.",Vtime(),dev,path D;
	errno = 0;

#if USE_termios 
#if defined(FREEBSD)
:4	V4 "Using termios raw mode on FREEBSD." D;
	raw_trm=sav_trm;
	if ((i = tcgetattr(dev, &sav_trm)) == -1) {
:2		V2 "tcgetattr(%d,&sav_trm) failed (Err %d=%s=%s",dev,Errinfo D;
		Fail;
	}
	got_trm = 1;
	cfmakeraw(&raw_trm);
	if ((i = tcsetattr(dev, TCSANOW, &raw_trm)) == -1) {
:2		V2 "Error %d from tcsetattr(%d, TCSANOW, &raw_trm)",i,dev D;
		Fail;
	}
:2	V2 "File %d should be raw now.",dev D;
#define GOT_info
#else
:4	V4 "Using termios raw mode." D;
	i = Ioctl(dev,TCGETS,&raw_trm);
:4	V4 "%d:\tcflag=%06o [old]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [old]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [old]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [old]",dev,raw_trm.c_oflag D;
:5	V5 "Ioctl(dev=%d,TCGETA=%d,&raw_trm=%08X)=%d",dev,TCGETS,&raw_trm,i D;
	if (baudcode)			/* Wipe out all of cflag but speed */
	     raw_trm.c_cflag  = baudcode;
	else raw_trm.c_cflag &= CBAUD;
	raw_trm.c_cflag |= cfl? cfl: CS8 | CREAD | HUPCL;
	raw_trm.c_iflag  = ifl? ifl: flowcontrol? (IXON | IXANY | IXOFF): 0;
	raw_trm.c_lflag  = lfl? lfl: 0;
	raw_trm.c_oflag  = ofl? ofl: 0;
	raw_trm.c_cc[4]  = 0;		/* Number of bytes to buffer up */
	raw_trm.c_cc[5]  = ttytimeout;	/* Timeout in 0.1 sec units */
:4	V4 "%d:\tcflag=%06o [new]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [new]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [new]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [new]",dev,raw_trm.c_oflag D;
	i = Ioctl(dev,TCSETS,&raw_trm);
#define GOT_info
#endif
#endif /* USE_termios */

#if USE_termio && defined(Linux)
:4	V4 "Sys/5 raw mode." D;
	i = Ioctl(dev,TCGETA,&raw_trm);
:4	V4 "%d:\tcflag=%06o [old]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [old]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [old]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [old]",dev,raw_trm.c_oflag D;
:5	V5 "Ioctl(dev=%d,TCGETA=%d,&raw_trm=%08X)=%d",dev,TCGETA,&raw_trm,i D;
	if (baudcode)			/* Wipe out all of cflag but speed */
	     raw_trm.c_cflag  = baudcode;
	else raw_trm.c_cflag &= CBAUD;
	raw_trm.c_cflag |= cfl? cfl: CS8 | CREAD | HUPCL;
	raw_trm.c_iflag  = ifl? ifl: flowcontrol? (IXON | IXANY | IXOFF): 0;
	raw_trm.c_lflag  = lfl? lfl: 0;
	raw_trm.c_oflag  = ofl? ofl: 0;
	raw_trm.c_cc[4]  = 0;		/* Number of bytes to buffer up */
	raw_trm.c_cc[5]  = ttytimeout;	/* Timeout in 0.1 sec units */
:4	V4 "%d:\tcflag=%06o [new]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [new]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [new]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [new]",dev,raw_trm.c_oflag D;
	i = Ioctl(dev,TCSETA,&raw_trm);
#endif	/*USE_termio+Linux*/
#ifdef TIOCNXCL
	if (noxclfl) {	/* Tell the driver to turn off exclusive use */
:2		P2 "%s	Disable exclusive use flag [TIOCNXCL]",Vtime() D;
:5		V5 "before Ioctl(%d,TIOCNXCL=%d,%06lX)",dev,TIOCNXCL,&zero D;
		errno = 0;
		i = Ioctl(dev,TIOCNXCL,&zero);
		if (i < 0)
:2			P2 "%s\t### Can't use TIOCNXCL [Err %d=%s]",Vtime(),Erreason D;
		V5 " after Ioctl(%d,TIOCNXCL=%d,%06lX)=%d [Err %d=%s]",
			dev,TIOCNXCL,&zero,i,Erreason D;
	}
#endif
#if USE_termio && defined(SYS5)
:4	V4 "Sys/5 raw mode." D;
	i = Ioctl(dev,TCGETA,&raw_trm);
:4	V4 "%d:\tcflag=%06o [old]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [old]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [old]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [old]",dev,raw_trm.c_oflag D;
:5	V5 "Ioctl(dev=%d,TCGETA=%d,&raw_trm=%08X)=%d",dev,TCGETA,&raw_trm,i D;
	if (baudcode)			/* Wipe out all of cflag but speed */
	     raw_trm.c_cflag  = baudcode;
	else raw_trm.c_cflag &= CBAUD;
	raw_trm.c_cflag |= cfl? cfl: CS8 | CREAD | HUPCL;
	raw_trm.c_iflag  = ifl? ifl: flowcontrol? (IXON | IXANY | IXOFF): 0;
	raw_trm.c_lflag  = lfl? lfl: 0;
	raw_trm.c_oflag  = ofl? ofl: 0;
	raw_trm.c_cc[4]  = 0;		/* Number of bytes to buffer up */
	raw_trm.c_cc[5]  = ttytimeout;	/* Timeout in 0.1 sec units */
:4	V4 "%d:\tcflag=%06o [new]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [new]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [new]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [new]",dev,raw_trm.c_oflag D;
	i = Ioctl(dev,TCSETA,&raw_trm);
#ifdef TIOCNXCL
	if (noxclfl) {	/* Tell the driver to turn off exclusive use */
:2		P2 "%s	Disable exclusive use flag [TIOCNXCL]",Vtime() D;
:5		V5 "before Ioctl(%d,TIOCNXCL=%d,%06lX)",dev,TIOCNXCL,&zero D;
		errno = 0;
		i = Ioctl(dev,TIOCNXCL,&zero);
		if (i < 0)
:2			P2 "%s\t### Can't use TIOCNXCL [Err %d=%s]",Vtime(),Erreason D;
		V5 " after Ioctl(%d,TIOCNXCL=%d,%06lX)=%d [Err %d=%s]",
			dev,TIOCNXCL,&zero,i,Erreason D;
	}
#endif
#endif
#if USE_termio && defined(SYS3)
:4	V4 "Sys/3 raw mode." D;
	i = Ioctl(dev,TCGETA,&raw_trm);
	raw_trm.c_cflag |= cfl? cfl: CS8 | CREAD | HUPCL;
	raw_trm.c_iflag  = ifl? ifl: flowcontrol? (IXON | IXANY | IXOFF): 0;
	raw_trm.c_lflag  = lfl? lfl: 0;
	raw_trm.c_oflag  = ofl? ofl: 0;
:5	V5 "\tcflag=%06o",raw_trm.c_cflag D;
:5	V5 "\tiflag=%06o",raw_trm.c_iflag D;
:5	V5 "\tlflag=%06o",raw_trm.c_lflag D;
:5	V5 "\toflag=%06o",raw_trm.c_oflag D;
	i = Ioctl(dev,TCSETA,&raw_trm);
#endif
#if USE_sgtty && defined(BSD)
:4	V4 "BSD raw mode." D;
	Ioctl(dev,TIOCSETD,&ldisc);
	i = Ioctl(dev,TIOCGETP,&sgttyb);
	sgttyb.sg_flags  =  RAW;
	errno = 0;
	i = Ioctl(dev,TIOCSETP,&sgttyb);
	if (errno) {
:2		P2 m_noraw,Vtime(),dev,path,Erreason D;
		Fail;
	}
#endif
#if USE_sgtty && defined(ULTRIX)	/* Ultrix is much like BSD */
:4	V4 "Ultrix raw mode." D;
#ifdef VAX
:5	V5 "VAX/Ultrix raw mode." D;
#endif
#ifdef PMAX
:5	V5 "PMAX/Ultrix raw mode." D;
#endif
	ldisc = NTTYDISC;
:3	V3 "Set file %d=%s to line discipline %d=NTTY",dev,path,ldisc D;
	Ioctl(dev,TIOCSETD,&ldisc);
#define GOT_info

	Ioctl(dev,TIOCGETP,&sgttyb);
	sgttyb.sg_flags  =  RAW;
/* 	sgttyb.sg_flags &= ~ANYP;	** From slattach - what did it do? */
	if (baudcode) {				/* Did caller set up a baud rate/mask? */
		sgttyb.sg_ispeed =
		sgttyb.sg_ospeed = baudcode;	/* Caller's baud rate */
	}
	V4 "Set sgttyb flags=0%o ispeed=ospeed=%d.",
		sgttyb.sg_flags,sgttyb.sg_ispeed D;
	errno = 0;
	Ioctl(dev,TIOCSETP,&sgttyb);
	if (errno) {
:2		P2 m_noraw,Vtime(),dev,path,Erreason D;
		Fail;
	}
#ifdef TIOCNXCL
	if (noxclfl) {	/* Tell the driver to turn off exclusive use */
:2		P2 "%s	Disable exclusive use flag [TIOCNXCL]",Vtime() D;
:5		V5 "before Ioctl(%d,TIOCNXCL=%d,%06lX)",dev,TIOCNXCL,&zero D;
		errno = 0;
		i = Ioctl(dev,TIOCNXCL,&zero);
		if (i < 0)
:2			P2 "%s\t### Can't use TIOCNXCL [Err %d=%s]",Vtime(),Erreason D;
		V5 " after Ioctl(%d,TIOCNXCL=%d,%06lX)=%d [Err %d=%s]",
			dev,TIOCNXCL,&zero,i,Erreason D;
	}
#endif
#ifdef TIOCMODEM
	if (modemfl) {	/* Tell the driver to handle modem signals */
:3		P3 "%s	Enable modem signals [TIOCMODEM]",Vtime() D;
:5		V5 "before Ioctl(%d,TIOCMODEM=%d,%06lX)",dev,TIOCMODEM,&zero D;
		errno = 0;
		i = Ioctl(dev,TIOCMODEM,&zero);
		V5 " after Ioctl(%d,TIOCMODEM=%d,%06lX)=%d [Err %d=%s]",
			dev,TIOCMODEM,&zero,i,Erreason D;
	}
#endif
/*	fcntl(dev,F_SETFL,FNDELAY);	/* Non-blocking I/O */
#endif

#if USE_termio && defined(POSIX)	/* Posix is much like Sys/V */
:4	V4 "POSIX/5 raw mode." D;
	i = Ioctl(dev,TCGETA,&raw_trm);
#define GOT_info
:4	V4 "%d:\tcflag=%06o [old]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [old]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [old]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [old]",dev,raw_trm.c_oflag D;
:5	V5 "Ioctl(dev=%d,TCGETA=%d,&raw_trm=%08X)=%d",dev,TCGETA,&raw_trm,i D;
	if (baudcode)			/* Wipe out all of cflag but speed */
	     raw_trm.c_cflag  = baudcode;
	else raw_trm.c_cflag &= CBAUD;
	raw_trm.c_cflag |= CS8 | CREAD | HUPCL;
	raw_trm.c_iflag  = flowcontrol? (IXON | IXANY | IXOFF): 0;
	raw_trm.c_lflag  = 0;
	raw_trm.c_oflag  = 0;
	raw_trm.c_cc[4]  = 0;		/* Number of bytes to buffer up */
	raw_trm.c_cc[5]  = ttytimeout;	/* Timeout in 0.1 sec units */
:4	V4 "%d:\tcflag=%06o [new]",dev,raw_trm.c_cflag D;
:4	V4 "%d:\tiflag=%06o [new]",dev,raw_trm.c_iflag D;
:4	V4 "%d:\tlflag=%06o [new]",dev,raw_trm.c_lflag D;
:4	V4 "%d:\toflag=%06o [new]",dev,raw_trm.c_oflag D;
	i = Ioctl(dev,TCSETA,&raw_trm);
#ifdef TIONEXCL
	if (noxclfl) {	/* Tell the driver to turn off exclusive use */
:3		P3 "%s	Disable exclusive use flag [TIONEXCL]",Vtime() D;
:5		V5 "before Ioctl(%d,TIONEXCL=%d,%06lX)",dev,TIONEXCL,&zero D;
		errno = 0;
		i = Ioctl(dev,TIONEXCL,&zero);
		V5 " after Ioctl(%d,TIONEXCL=%d,%06lX)=%d [Err %d=%s]",
			dev,TIONEXCL,&zero,i,Erreason D;
	}
#endif
#endif

#ifndef GOT_info
	V1 "### Don't  know how to get terminal info here ###" V;
#endif

:5	V5 "%d is now raw",dev D;
fail:
:f	Fexit;
	return(i);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Attempt to suppress any exclusive-use bits that may be set on the
* device.
*/
noxcl(dev,path)
	int  dev;
	char*path;
{	int r = -1; /* Return value */
:f	Fenter("noxcl");
#ifdef	TIOCNXCL
:2	P2 "%s\tDisable exclusive use flag [TIOCNXCL]",Vtime() D;
:5	V5 "before Ioctl(%d,TIOCNXCL=%d,%06lX)",dev,TIOCNXCL,&zero D;
	errno = 0;
	r = Ioctl(dev,TIOCNXCL,&zero);
:1	if (r < 0)
:1		P2 "%s\t### Can't use TIOCNXCL [Err %d=%s]",Vtime(),Erreason D;
:5	V5 " after Ioctl(%d,TIOCNXCL=%d,%06lX)=%d [Err %d=%s]",
:5		dev,TIOCNXCL,&zero,r,Erreason D;
#endif
#ifdef TIONEXCL
:3	P3 "%s\tDisable exclusive use flag [TIONEXCL]",Vtime() D;
:5	V5 "before Ioctl(%d,TIONEXCL=%d,%06lX)",dev,TIONEXCL,&zero D;
	errno = 0;
	i = Ioctl(dev,TIONEXCL,&zero);
	V5 " after Ioctl(%d,TIONEXCL=%d,%06lX)=%d [Err %d=%s]",
		dev,TIONEXCL,&zero,i,Erreason D;
#endif

:f	Fexit;
}
