/*
	Dedicated to the ioctl system call, MON 54.
*/

/* $Header$ */

#include	"sysidf.h"
#include	"v7ioctl.h"
#include	"global.h"
#include	"mem.h"
#include	"warn.h"

#include	<sgtty.h>

#ifdef	V7IOCTL				/* define the proper V7 requests */

#define	V7IOGETP	(('t'<<8)|8)
#define	V7IOSETP	(('t'<<8)|9)
#define	V7IOSETN	(('t'<<8)|10)
#define	V7IOEXCL	(('t'<<8)|13)
#define	V7IONXCL	(('t'<<8)|14)
#define	V7IOHPCL	(('t'<<8)|2)
#define	V7IOFLUSH	(('t'<<8)|16)

#define	V7IOSETC	(('t'<<8)|17)
#define	V7IOGETC	(('t'<<8)|18)

#endif	V7IOCTL


/************************************************************************
 * do_ioctl handles all ioctl system calls. It is called by the		*
 * moncall() routine, case 54.  It was too big to leave it there.	*
 * The ioctl system call is divided into 5 parts.			*
 * Ioctl's dealing with respectively:					*
 * sgttyb, tchars, local mode word, ltchars, and miscellaneous ioctl's.	*
 * Some of the sgttyb-calls are only possible under the new tty-driver.	*
 * All of these are to be found in the miscellaneous section.		*
 * do_ioctl() simply returns the value ioctl() would return itself.	*
 * (0 for success, -1 for failure)					*
 ***********************************************************************/

int do_ioctl(fd, req, addr)
	int fd, req;
	ptr addr;
{
	register long e;
	struct sgttyb sg_buf;

#ifdef	BSD_X				/* from system.h */
#ifndef	V7IOCTL
	char c;
	int mask;	/* will get ALIGNMENT problems with this one */
	long count;	/* might get ALIGNMENT problems with this one */
	int ldisc;	/* might get ALIGNMENT problems with this one */
	int pgrp;	/* might get ALIGNMENT problems with this one */
#endif	V7IOCTL

	struct tchars tc_buf;
#ifndef	V7IOCTL
	struct ltchars ltc_buf;
#endif	V7IOCTL
#endif	BSD_X


#ifdef	V7IOCTL
	switch (req) {			/* translate the V7 requests */
					/* and reject the non-V7 ones */
	case V7IOGETP:
		req = TIOCGETP;
		break;
	case V7IOSETP:
		req = TIOCSETP;
		break;
	case V7IOEXCL:
		req = TIOCEXCL;
		break;
	case V7IONXCL:
		req = TIOCNXCL;
		break;
	case V7IOHPCL:
		req = TIOCHPCL;
		break;
#ifdef	BSD_X				/* from system.h */
	case V7IOSETN:
		req = TIOCSETN;
		break;

	case V7IOSETC:
		req = TIOCSETC;
		break;
	case V7IOGETC:
		req = TIOCGETC;
		break;
#endif	BSD_X

	default:
		einval(WBADIOCTL);
		return (-1);			/* Fake return value */
	}

#endif	V7IOCTL


	switch (req) {

		/*************************************/
		/****** Struct sgttyb ioctl's ********/
		/*************************************/

	case TIOCGETP:
		/* Get fd's current param's and store at dsp2 */
		if (	(e = ioctl(fd, req, (char *) &sg_buf)) == -1
		||	!sgttyb2mem(addr, &sg_buf)
		) {
			e = -1;		/* errno already set */
		}
		break;

	case TIOCSETP:
#ifdef	BSD4_1				/* from system.h */
	case TIOCSETN:
#endif	BSD4_1
		/* set fd's parameters according to sgtty buffer	*/
		/* pointed to (addr), so first fill sg_buf properly.	*/
		if (	!mem2sgtty(addr, &sg_buf)
		||	(e = ioctl(fd, req, (char *) &sg_buf)) == -1
		) {
			e = -1;		/* errno already set */
		}
		break;

	case TIOCEXCL:
	case TIOCNXCL:
	case TIOCHPCL:
		/* These have no third argument. */
		e = ioctl(fd, req, (char *) 0);
		break;

#ifdef	BSD_X				/* from system.h */
		/*************************************/
		/****** Struct tchars ioctl's ********/
		/*************************************/

	case TIOCGETC:
		/* get special char's; store at addr */
		if (	(e = ioctl(fd, req, (char *) &tc_buf)) == -1
		||	!tchars2mem(addr, &tc_buf)
		) {
			e = -1;		/* errno already set */
		}
		break;

	case TIOCSETC:
		/* set special char's; load from addr */
		if (	!mem2tchars(addr, &tc_buf)
		||	(e = ioctl(fd, req, (char *) &tc_buf)) == -1
		) {
			e = -1;
		}
		break;

#ifndef	V7IOCTL
		/***************************************/
		/****** Local mode word ioctl's ********/
		/***************************************/

	case TIOCLBIS:	/* addr points to mask which is or-ed with lmw */
	case TIOCLBIC:	/* addr points to mask, ~mask & lmw is done */
	case TIOCLSET:	/* addr points to mask, lmw is replaced by it */
		if (memfault(addr, wsize)) {
			e = -1;
		}
		else {
			mask = mem_ldu(addr, wsize);
			e = ioctl(fd, req, (char *) &mask);
		}
		break;

	case TIOCLGET:	/* addr points to space, store lmw there */
		if (	memfault(addr, wsize)
		||	(e = ioctl(fd, req, (char *) &mask)) == -1
		) {
			e = -1;
		}
		else {
			mem_stn(addr, (long) mask, wsize);
		}
		break;

		/**************************************/
		/****** Struct ltchars ioctl's ********/
		/**************************************/

	case TIOCGLTC:
		/* get current ltc's; store at addr */
		if (	(e = ioctl(fd, req, (char *) &ltc_buf)) == -1
		||	!ltchars2mem(addr, &ltc_buf)
		) {
			e = -1;		/* errno already set */
		}
		break;

	case TIOCSLTC:
		/* set ltc_buf; load from addr */
		if (	!mem2ltchars(addr, &ltc_buf)
		||	(e = ioctl(fd, req, (char *) &ltc_buf)) == -1
		) {
			e = -1;
		}
		break;

		/*************************************/
		/****** Miscellaneous ioctl's ********/
		/*************************************/

	case TIOCGETD:
		/* Get line discipline, store at addr */
		if (	memfault(addr, wsize)
		||	(e = ioctl(fd, req, (char *) &ldisc)) == -1
		) {
			e = -1;
		}
		else {
			mem_stn(addr, (long) ldisc, wsize);
		}
		break;

	case TIOCSETD:
		/* Set line discipline, load from addr */
		if (memfault(addr, wsize)) {
			e = -1;
		}
		else {
			ldisc = (int) mem_ldu(addr, wsize);
			e = ioctl(fd, req, (char *) &ldisc);
		}
		break;

	/* The following are not standard vanilla 7 UNIX */
	case TIOCSBRK:	/* These have no argument */
	case TIOCCBRK:	/* They work on parts of struct sgttyb */
	case TIOCSDTR:
	case TIOCCDTR:
		e = ioctl(fd, req, (char *) 0);
		break;

	/* The following are used to set the line discipline */
	case OTTYDISC:
	case NETLDISC:
	case NTTYDISC:
		e = ioctl(fd, req, (char *) 0);
		break;

	case TIOCSTI:	/* addr = address of character */
		if (memfault(addr, 1L)) {
			e = -1;
		}
		else {
			c = (char) mem_ldu(addr, 1L);
			e = ioctl(fd, req, (char *) &c);
		}
		break;

	case TIOCGPGRP:
		/* store proc grp number of control term in addr */
		if (	memfault(addr, wsize)
		||	(e = ioctl(fd, req, (char *) &pgrp)) == -1
		) {
			e = -1;
		}
		else {
			mem_stn(addr, (long) pgrp, wsize);
		}
		break;

	case TIOCSPGRP:	/* addr is NO POINTER !! */
		e = ioctl(fd, req, (char *) addr);
		break;

	case FIONREAD:	/* do the ioctl, addr is long-int ptr now */
		if (	memfault(addr, wsize)
		||	(e = ioctl(fd, req, (char *) &count)) == -1
		) {
			e = -1;
		}
		else {
			mem_stn(addr, count, wsize);
		}
		break;

#endif	V7IOCTL
#endif	BSD_X

	default:
		einval(WBADIOCTL);
		e = -1;			/* Fake return value */
		break;
	}
	return (e);
}
