/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: sgtty.c 1.9 90/06/28 $"

/* 
 * tty line discipline 0:
 * old sgtty support.
 */

/* $Log:	sgtty.c,v $
 */


#include "sys/param.h"
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/mutex.h"
#include "sys/intctl.h"
#include "sys/session.h"
#include "sys/stream.h"
#include "sys/termio.h"
#include "sys/errno.h"
#include "sys/debug.h"
#include "sys/cmn_err.h"
#include "sys/ttold.h"
#include "sys/eucioctl.h"
#include "sys/ld0.h"

/*
 * takes a termios structure and creats a sgttyb ioctl message.
 */
termios_getp(termios, mp)
struct termios	*termios;
mblk_t	*mp;
{
	struct	iocblk	*iocp;
	mblk_t		*cont;
	struct	termios	tmptermios;

	tmptermios = *termios;
	cont = mp->b_cont;
	iocp = (struct iocblk *)mp->b_rptr;

	ASSERT_DEBUG(cont->b_datap->db_lim - cont->b_datap->db_base > sizeof(struct sgttyb),"termios struct too small");

	cont->b_rptr = cont->b_datap->db_base;
	termios_to_sgttyb(&tmptermios, (struct sgttyb *)cont->b_rptr);
	cont->b_wptr = cont->b_rptr + sizeof(struct sgttyb);
	iocp->ioc_count = sizeof(struct sgttyb);
}


/*
 * Convert sgttyb message to a termios message.
 */
int
sgtty_setp(q,mp,tp)
queue_t	*q;
mblk_t	*mp;
struct  ld *tp;
{
	struct	sgttyb	tmpsgttyb;
	struct  termios *termios;
	struct	iocblk	*iocp;
	mblk_t		*cont;
	spl_t		spl;

	cont = mp->b_cont;
	iocp = (struct iocblk *)mp->b_rptr;

	tmpsgttyb = *(struct sgttyb *)cont->b_rptr;
	if ((cont->b_datap->db_lim - cont->b_datap->db_base) <= sizeof( struct termios)) {
		freemsg(cont);
		if ((mp->b_cont = allocb(sizeof(struct termios), BPRI_MED)) == NULL) {
			mp->b_datap->db_type = M_IOCNAK; 
			iocp->ioc_error = ENOSR;
			iocp->ioc_count = 0;
			qreply(q, mp);
			return (1);
		}
		cont = mp->b_cont;
	} else
		cont->b_rptr = cont->b_datap->db_base;

	/*
	 * Initialize the termios structure from the current
	 * terminal settings (the equivalent of performing a
	 * tcgetattr).
	 */
	termios = (struct termios *)cont->b_rptr;
        spl = p_lock(&tp->ld_lock, SPLSTR);
	ld0_termios_get(tp, termios);
        v_lock(&tp->ld_lock, spl);

	/*
	 * Convert the sgttyb structure to a termios structure.
	 */
	sgttyb_to_termios(&tmpsgttyb, termios);

	/*
	 * Convert the message.
	 */
	cont->b_wptr = cont->b_rptr + sizeof(struct termios);
	iocp->ioc_count = sizeof(struct termios);
	iocp->ioc_cmd = TCSETP;
	return (0);
}



/*
 * converts a termios structure into a sgttyb structure
 */

static
termios_to_sgttyb(termios, sgttyb)
struct	termios	*termios;
struct	sgttyb	*sgttyb;
{
	int	flag;

	sgttyb->sg_ispeed = termios->c_cflag&CBAUD;
	sgttyb->sg_ospeed = sgttyb->sg_ispeed;
	sgttyb->sg_erase = termios->c_cc[VERASE];
	sgttyb->sg_kill = termios->c_cc[VKILL]; 
	flag = 0; 
	if (termios->c_cflag & HUPCL)
		flag |= O_HUPCL; 
	if (!(termios->c_lflag & ICANON))
		flag |= O_RAW; 
	if (termios->c_lflag & XCASE)
		flag |= O_LCASE; 
	if (termios->c_lflag & ECHO)
		flag |= O_ECHO; 
	if (!(termios->c_lflag & ECHOK))
		flag |= O_NOAL; 
	if (termios->c_cflag & PARODD)
		flag |= O_ODDP; 
	else if (termios->c_iflag & INPCK)
		flag |= O_EVENP; 
	else
		flag |= O_ODDP | O_EVENP; 

	if (termios->c_oflag & ONLCR) {
		flag |= O_CRMOD; 
		if (termios->c_oflag & CR1)
			flag |= O_CR1; 
		if (termios->c_oflag & CR2)
			flag |= O_CR2; 
	} else {
		if (termios->c_oflag & CR1)
			flag |= O_NL1; 
		if (termios->c_oflag & CR2)
			 flag |= O_NL2; 
	}

	if ((termios->c_oflag & TABDLY) == TAB3)
		flag |= O_XTABS; 
	else if (termios->c_oflag & TAB1)
		flag |= O_TBDELAY; 
	if (termios->c_oflag & FFDLY)
		flag |= O_VTDELAY; 
	if (termios->c_oflag & BSDLY)
		flag |= O_BSDELAY; 
	sgttyb->sg_flags = flag; 
}

/*
 * converts a sgttyb structure into a termios structure.
 */
static
sgttyb_to_termios(sgttyb, termios)
struct	sgttyb	*sgttyb;
struct	termios	*termios;
{
	int	flag;


	termios->c_cflag &= ~CBAUD;
	termios->c_cflag |= (sgttyb->sg_ispeed&CBAUD)|CREAD;
	if ((sgttyb->sg_ispeed&CBAUD) == B110)
		termios->c_cflag |= CSTOPB;
	termios->c_cc[VERASE] = sgttyb->sg_erase;
	termios->c_cc[VKILL] = sgttyb->sg_kill;
	flag = sgttyb->sg_flags;

	if (flag & O_HUPCL)
		termios->c_cflag |= HUPCL;
	if (flag & O_XTABS)
		termios->c_oflag |= TAB3;
	if (flag & O_TBDELAY)
		termios->c_oflag |= TAB1;
	if (flag & O_LCASE) {
		termios->c_iflag |= IUCLC;
		termios->c_oflag |= OLCUC;
		termios->c_lflag |= XCASE;
	}
	if (flag & O_ECHO)
		termios->c_lflag |= ECHO;
	if (!(flag & O_NOAL))
		termios->c_lflag |= ECHOK;
	if (flag & O_CRMOD) {
		termios->c_iflag |= ICRNL;
		termios->c_oflag |= ONLCR;
		if (flag & O_CR1)
			termios->c_oflag |= CR1;
		if (flag & O_CR2)
			termios->c_oflag |= ONOCR | CR2;
	} else {
		termios->c_oflag |= ONLRET;
		if (flag & O_NL1)
			termios->c_oflag |= CR1;
		if (flag & O_NL2)
			termios->c_oflag |= CR2;
	}
	if (flag & O_RAW) {
		termios->c_cc[VMIN] = 1;
		termios->c_cc[VTIME] = 6;
		termios->c_iflag &= ~(ICRNL | IUCLC);
		termios->c_cflag |= CS8;
	} else {
		termios->c_cc[VEOF] = CEOF;
		termios->c_cc[VEOL] = 0;
		termios->c_cc[VEOL2] = 0;
		termios->c_iflag |= BRKINT | IGNPAR | ISTRIP | IXON | IXANY;
		termios->c_oflag |= OPOST;
		termios->c_cflag &= ~CSIZE;
		termios->c_cflag |= CS8;
		termios->c_lflag |= ICANON | ISIG;
	}
	termios->c_iflag |= INPCK;
	if (flag & O_ODDP)
		if (flag & O_EVENP)
			termios->c_iflag &= ~INPCK;
		else
			termios->c_cflag |= PARODD;
	if (flag & O_VTDELAY)
		termios->c_oflag |= FFDLY;
	if (flag & O_BSDELAY)
		termios->c_oflag |= BSDLY;
}
