Coherent4.2.10/i386/tioc.c

Compare this file to the similar file:
Show the results in this format:

/* $Header: /ker/i386/RCS/tioc.c,v 2.5 93/10/29 00:57:26 nigel Exp Locker: nigel $ */
/*
 * Convert COH286 tty ioctl's to Sys 5 compatible calls.
 *
 * $Log:	tioc.c,v $
 * Revision 2.5  93/10/29  00:57:26  nigel
 * R98 (aka 4.2 Beta) prior to removing System Global memory
 * 
 * Revision 2.4  93/08/19  10:38:10  nigel
 * r83 ioctl (), corefile, new headers
 * 
 * Revision 2.3  93/08/19  03:40:16  nigel
 * Nigel's R83
 */

#include <sys/types.h>
#include <sys/errno.h>
#include <sgtty.h>

#define	_KERNEL		1

#include <sys/mmu.h>

#define	OIOC_LOW	0100
#define OIOC_HIGH	0110

/*
 * Bits from COH286 sgttyb sg_flags field.
 */

#define	O_EVENP		0x0001	/* Allow even parity */
#define	O_ODDP		0x0002	/* Allow odd parity */
#define	O_CRMOD		0x0004	/* Map '\r' to '\n' */
#define	O_ECHO		0x0008	/* Echo input characters */
#define	O_LCASE		0x0010	/* Lowercase mapping on input */
#define	O_CBREAK	0x0020	/* Each input character causes wakeup */
#define	O_RAWIN		0x0040	/* 8-bit input raw */
#define	O_RAWOUT	0x0080	/* 8-bit output raw */
#define	O_TANDEM	0x0100	/* flow control protocol */
#define	O_XTABS		0x0200	/* Expand tabs to spaces */
#define	O_CRT		0x0400	/* CRT character erase */

#define	O_RAW	(O_RAWIN|O_RAWOUT)	/* Raw mode */

/*
 * Names for terminal speeds.
 */
#define	O_B0	0		/* Hangup if modem control enabled */
#define	O_B50	1		/* 50 bps */
#define	O_B75	2		/* 75 bps */
#define	O_B110	3		/* 110 bps */
#define	O_B134	4		/* 134.5 bps (IBM 2741) */
#define	O_B150	5		/* 150 bps */
#define	O_B200	6		/* 200 bps */
#define	O_B300	7		/* 300 bps */
#define	O_B600	8		/* 600 bps */
#define	O_B1200	9		/* 1200 bps */
#define	O_B1800	10		/* 1800 bps */
#define	O_B2000	11		/* 2000 bps */
#define	O_B2400	12		/* 2400 bps */
#define	O_B3600	13		/* 3600 bps */
#define	O_B4800	14		/* 4800 bps */
#define	O_B7200	15		/* 7200 bps */
#define	O_B9600	16		/* 9600 bps */
#define	O_B19200	17	/* 19200 bps */
#define	O_EXTA	18		/* External A (DH-11) */
#define	O_EXTB	19		/* External B (DH-11) */

static void to_s5_sgfld();
static void to_s5speed();
static void to_coh_sgfld();
static void to_cohspeed();

/*
 * Here are the COH286 values for tty ioctl's.
 * In cvtsgtty[] below, subtract 0100 from the 286 COH ioctl value to
 * index to the equivalent Sys V ioctl.
 *
 *	OIOCSETP	0100		 Terminal set modes (old stty) 
 *	OIOCGETP	0101		 Terminal get modes (old gtty) 
 *	OIOCSETC	0102		 Set characters 
 *	OIOCGETC	0103		 Get characters 
 *	OIOCSETN	0104		 Set modes w/o delay or out flush 
 *	OIOCEXCL	0105		 Set exclusive use 
 *	OIOCNXCL	0106		 Set non-exclusive use 
 *	OIOCHPCL	0107		 Hang up on last close 
 *	OIOCFLUSH	0110		 Flush characters in I/O queues 
 */
static unsigned short cvtsgtty[] = {
	TIOCSETP,
	TIOCGETP,
	TIOCSETC,
	TIOCGETC,
	TIOCSETN,
	TIOCEXCL,
	TIOCNXCL,
	TIOCHPCL,
	TIOCFLUSH
};

/*
 * tioc()
 *
 * This function is called by dioctl() whenever a 286 binary does an ioctl().
 * Its arguments are the arguments for to the ioctl, plus the local driver's
 * ioctl function, which should support S5 sgtty and termio commands.
 *
 * 1.  If com is COH 286 TIOC, translate it to S5 TIOC.
 * 2.  If translated com is TIOCSET[NP], convert sgttyb struct *vec to S5.
 * 3.  If translated com is TIOCGETP, point vec to a full S5 struct (COH 286
 *     sgttyb struct is 2 bytes shorter than S5 format).
 * 4.  Call driver's ioctl().
 * 5.  If just finished a converted TIOCGETP, convert back to COH 286 sgttyb.
 */

int
tioc (dev, com, vec, mode, credp, rvalp, iocfn)
int dev, com, mode, credp, rvalp, (*iocfn)();
caddr_t		vec;
{
	struct sgttyb sg;
	int my_com = com, old_getp = 0;
	caddr_t		my_vec = vec;
	int		space;

	if (com >= OIOC_LOW && com <= OIOC_HIGH && get_user_error () == 0) {

		my_com = cvtsgtty [com - OIOC_LOW];

		if (my_com == TIOCSETP || my_com == TIOCSETN) {
			ukcopy (vec, & sg, sizeof (struct sgttyb));
			sg.sg_flags &= 0xffff;
			to_s5_sgfld (& sg);
			my_vec = (caddr_t) & sg;
		}

		if (my_com == TIOCGETP) {
			old_getp = 1;
			my_vec = (caddr_t) & sg;
		}
	}

	/*
	 * NIGEL: I have tightened up the segment limits so that kucopy ()
	 * and ukcopy () no longer accept kernel addresses as user addresses;
	 * in this case, we really do want this to happen, so we use
	 * setspace () to allow access to kernel data space as user space.
	 */

	if (my_vec != vec)
		space = setspace (SEL_386_KD);

	(* iocfn) (dev, my_com, my_vec, mode, credp, rvalp);

	if (my_vec != vec)
		(void) setspace (space);

	if (old_getp && get_user_error () == 0) {
		to_coh_sgfld (my_vec);
		kucopy (my_vec, vec, sizeof (struct sgttyb) - 2);
	}

	return 0;
}


/*
 * to_s5_sgfld()
 *
 * Convert fields in a sgttyb struct from COH 286 format to Sys 5.
 */

static void to_s5_sgfld(sgp)
struct sgttyb * sgp;
{
	unsigned int f = sgp->sg_flags, g = 0;

	/*
	 * Convert sg_ispeed and sg_ospeed.
	 */

	to_s5speed (& sgp->sg_ispeed);
	to_s5speed (& sgp->sg_ospeed);

	/*
	 * Convert sg_flags.
	 *   f is old COH 286 flags.
	 *   g is new Sys V flags.
	 */
	if (f & O_EVENP)
		g |= EVENP;
	if (f & O_ODDP)
		g |= ODDP;
	if (f & O_CRMOD)
		g |= CRMOD;
	if (f & O_ECHO)
		g |= ECHO;
	if (f & O_LCASE)
		g |= LCASE;
	if (f & O_CBREAK)
		g |= CBREAK;	/* No CBREAK in Sys 5 sgtty. */
				/* Only one RAW bit in Sys 5 sgtty. */
	if ((f & O_RAWIN) != 0 && (f & O_RAWOUT) != 0)
		g |= RAW;
	if (f & O_RAWIN)
		g |= RAWIN;
	if (f & O_RAWOUT)
		g |= RAWOUT;
	if (f & O_TANDEM)
		g |= TANDEM;	/* No TANDEM in Sys 5 sgtty. */
	if (f & O_XTABS)
		g |= XTABS;
	if (f & O_CRT)
		g |= CRT;	/* No CRT in Sys 5 sgtty. */
	sgp->sg_flags = g;
}

/*
 * to_s5speed()
 *
 * Convert speed from COH286 to Sys5.
 * Here are the numbers:
 *	const.	COH286	Sys5
 *	B0	0	0
 *	B50	1	1
 *	B75	2	2
 *	B110	3	3
 *	B134	4	4
 *	B150	5	5
 *	B200	6	6
 *	B300	7	7
 *	B600	8	8
 *	B1200	9	9
 *	B1800	10	10
 *	B2000	11	-
 *	B2400	12	11
 *	B3600	13	-
 *	B4800	14	12
 *	B7200	15	-
 *	B9600	16	13
 *	B19200	17	14
 *	EXTA	18	14
 *	EXTB	19	15
 */
#define BADSPD	99

static void to_s5speed(speed)
unsigned char *speed;
{
	static char s5sp[]={B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,
		B1800,BADSPD,B2400,BADSPD,B4800,BADSPD,B9600,EXTA,EXTA,EXTB};

	if (* speed >= sizeof (s5sp))
		set_user_error (EINVAL);
	else if (s5sp [* speed] == BADSPD)
		set_user_error (EINVAL);
	else
		* speed = s5sp [* speed];
}

/*
 * to_coh_sgfld()
 *
 * Convert fields in a sgttyb struct from Sys V format to COH 286.
 */
static void to_coh_sgfld(sgp)
struct sgttyb * sgp;
{
	unsigned int f = sgp->sg_flags, g = 0;

	/*
	 * Convert sg_ispeed and sg_ospeed.
	 */

	to_cohspeed (& sgp->sg_ispeed);
	to_cohspeed (& sgp->sg_ospeed);

	/*
	 * Convert sg_flags.
	 *   f is old Sys V flags.
	 *   g is new COH 286 flags.
	 */
	if (f & EVENP)
		g |= O_EVENP;
	if (f & ODDP)
		g |= O_ODDP;
	if (f & CRMOD)
		g |= O_CRMOD;
	if (f & ECHO)
		g |= O_ECHO;
	if (f & LCASE)
		g |= O_LCASE;
	if (f & CBREAK)
		g |= O_CBREAK;	/* No CBREAK in Sys 5 sgtty. */
	if (f & RAWIN)		/* Only one RAW bit in Sys 5 sgtty. */
		g |= O_RAWIN;
	if (f & RAWOUT)
		g |= O_RAWOUT;
	if (f & TANDEM)
		g |= O_TANDEM;	/* No TANDEM in Sys 5 sgtty. */
	if (f & XTABS)
		g |= O_XTABS;
	if (f & CRT)
		g |= O_CRT;	/* No CRT in Sys 5 sgtty. */
	sgp->sg_flags = g;
}

static void to_cohspeed(speed)
unsigned char *speed;
{
	static char cohsp[]={
		O_B0, O_B50, O_B75, O_B110, O_B134, O_B150, O_B200,
		O_B300, O_B600, O_B1200, O_B1800, O_B2400, O_B4800, 
		O_B9600, O_EXTA, O_EXTB
	};

	if (* speed >= sizeof (cohsp))
		set_user_error (EINVAL);
	else
		* speed = cohsp [* speed];
}