static char rcsid[] = "$Header: oct.c,v 820.1 86/12/04 19:55:59 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Central Data Octal Serial Board
 */

/*
 * History:
 * ========
 * 860324 jht	Made vo.c and oct.c work together for 4.2bsd Siemens BS2000;
 *		...Blocks in octopen() until voscan() sees that VG has data;
 *
 * 860416 jht	Make vo.c and oct.c work together for 4.2bsd cuSiemens;
 *		...Blocks instead in octread() until voscan() sees VG-data;
 *		...Made octopen(dev,openFlags C FNDELAY) ==> non-blocking;
 */

#define	BS2000_MODS

#include "oct.h"
#if	NOCT > 0

#ifdef	BS2000_MODS
/*
 * NOTE:  Valid uses BKBUFSIZ for the BS2000 Siemens' code:
 *
 * Siemens wants to transmit 2050 bytes using the VG-board
 * to handle the Century Data Octal Serial's USARTs at 9600 baud.
 *
 * C.f.,	 ../s32dev/{oct.c,vo.c}
 *		 ../sys/tty_bk.c
 *		 ../h/bk.h
 *
 * PRESUMPTIONS: 
 * -------------
 *	1) 1:1 map
 *
 *		from	 vo_tty[0-(NPORTS-1)]
 *		to	oct_tty[0-(NPORTS-1)],
 *
 *		wherewith voscan() wakes up octopen().
 *
 *	2) NPORTS==NLINE
 */
#endif	BS2000_MODS

#include "../h/param.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/conf.h"
#include "../h/file.h"
#include "../h/kernel.h"
#include "../h/pdma.h"
#include "../h/uio.h"
#include "../s32dev/mbvar.h"
#include "../s32dev/octreg.h"
#include "../s32/cpu.h"			/* M68020 busErr simulation */
#include "../s32/setjmp.h"		/* M68020 busErr simulation */

int	octprobe(), octattach();
struct	mb_device *octinfo[NOCT];
u_short	octstd[] = { 0x1a0, 0x1c0, 0 };	/* Device addr within MBIO space */
struct	mb_driver octdriver =
			{ 0, octprobe, 0, octattach, octstd, "oct", octinfo };

char oct_baud[] = { 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 10, 12, 14, 15, 15 };

struct	tty	oct_tty [NLINE * NOCT];
struct	pdma	oct_pdma[NLINE * NOCT];
struct	pdma	*oct_pdmap [NOCT];	/* Find oct_pdma by unit number */
int		oct_softCAR[NOCT];

#define ADDR(tp) ((struct ocdevice *)((struct pdma *)tp->t_addr)->p_addr)

/*ARGSUSED*/
octprobe(reg, intr, unit)
	caddr_t reg;
	int (*intr)();
{
	register i;
	register struct ocdevice *addr = (struct ocdevice *)reg;
	int octintr();

	if (intr != octintr)
		return 0;
	for (i = 0; i < NOCT; i++)
		if (octinfo[i] && octinfo[i]->md_alive &&
		    octinfo[i]->md_addr == reg)
			return 0;
	addr->occr = OCCR_NORMAL|OCCR_TXEN|OCCR_RTS;
#ifdef	M68020
	/*
	 * If this were a M68000/10, we would have evoked
	 * a normal busErr iff the device were not present,
	 * regardless of whether we were read-probing or write-probing.
	 * Normally, cvec==(2-1), and benigness would reign.
	 */
	flushWriteQueue();		/* Pause while onboard writeQ flushes */
#endif	M68020
	for (i = 100000; --i >= 0 && (addr->ocsr & OCSR_TXRDY) == 0;)
		;
	addr->occr = OCCR_NORMAL;
#ifdef	M68020
	/*
	 * If this were a M68000/10, we would have evoked
	 * a normal busErr iff the device were not present,
	 * regardless of whether we were read-probing or write-probing.
	 * Normally, cvec==(2-1), and benigness would reign.
	 */
	flushWriteQueue();		/* Pause while onboard writeQ flushes */
#endif	M68020
	if (i < 0)
		return 0;
	return sizeof (struct ocdevice);
}

/*ARGUSED*/
octattach(md)
	struct mb_device *md;
{
	register i;
	register struct pdma *dp = oct_pdma + md->md_unit * NLINE;
	register struct tty *tp = oct_tty + md->md_unit * NLINE;
	int octxint();
	int octscan();
	static char scan;

	oct_pdmap[md->md_unit] = dp;
	oct_softCAR[md->md_unit] = md->md_flags;
	for (i = 0; i < NLINE; i++, tp++, dp++) {
		/*
		 * Set up pdma data structures so stray interrupts
		 * won't crash the system.  The assembly code
		 * should call octxint() immediately which just
		 * turns off transmit interrupt.
		 * In any case, we turn the port off.
		 */
		tp->t_addr = (caddr_t)dp;
		dp->p_addr = (struct device *)((struct ocdevice *)
			md->md_addr + i);
		dp->p_mem = dp->p_end = 0;
		dp->p_fcn = octxint;
		dp->p_arg = (int)tp;
		ADDR(tp)->occr = OCCR_NORMAL;
#ifdef	M68020
		/*
		 * If this were a M68000/10, we would have evoked
		 * a normal busErr iff the device were not present,
		 * regardless of whether we were read-probing or write-probing.
		 * Normally, cvec==(2-1), and benign-ness would reign.
		 */
		flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	}
	if (!scan) {
		scan = 1;
		timeout(octscan, (caddr_t)0, hz);
	}
}

/*ARGSUSED*/
#ifdef	VALID_EFS	/* For lexical consistency with openi() */
octopen(dev, openFlags, fileMode)
	dev_t	dev;
	int	openFlags;	/* Flags from user's open(2) syscall	*/
	int	fileMode;	/* File mode as in  chmod(2) syscall	*/
#else	VALID_EFS

octopen(dev, openFlags)
	dev_t	dev;
	int	openFlags;	/* Flags from user's open(2) system call */
#endif	VALID_EFS
{
	int line = minor(dev);
	int unit = line / NLINE;
	register struct tty *tp = &cdevsw[major(dev)].d_ttys[line];
	int error;
	int octstart();

	if (unit >= NOCT || octinfo[unit] == 0 || !octinfo[unit]->md_alive)
		return ENXIO;
	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
		return EBUSY;
	if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0) {
		tp->t_oproc = octstart;
		tp->t_flags = EVENP|ODDP|ECHO|XTABS|CRMOD|CRTBS|CRTERA|CRTKIL|CTLECH;
		ttychars(tp);
		tp->t_ispeed = tp->t_ospeed = B9600;
		tp->t_line = NTTYDISC;
		ADDR(tp)->occr = OCCR_DTR|OCCR_RTS|OCCR_RXEN;
#ifdef	M68020
		flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
		octparam(tp);
	}
	(void) spl5();

#ifdef	BS2000_MODS
	/*
	 * For the Siemens BS2000 link,
	 * we also want to sleep() here in octopen()
	 * until we have the assertion
	 * of TS_CARR_ON "active line" indicated by voscan()
	 * when the VG-board actually has some data for the user.
	 *
	 * The only exception is direct request
	 * to not block here in open if FNDELAY is asserted. 
	 *
	 * Otherwise, the user would receive a (-1)
	 * from his yet-to-be-issued read(),
	 * because there really would have been no data ever transmitted.
	 * This would also break with R7.2x (4.1bsd) tradition.
	 *
	 * Without change, for nominal/direct Octal Serial accesses,
	 * octscan() still has the responsibility
	 * of asserting a logical "carrier-on" for our oct_tty[]
	 * as soon as the corresponding line(s) become active.
	 * 
	 * octscan() is invoked on a timeout() basis initiated
	 * by octattach().
	 */
#endif	BS2000_MODS
	while ((tp->t_state & TS_CARR_ON) == 0) {
		tp->t_state |= TS_WOPEN;
#ifdef	BS2000_MODS
		if (openFlags & FNDELAY) {
			/*
			 * Explicit request to NOT BLOCK
			 * during open -- 'cuSiemens',
			 * a version of cu232' is a case in point.
			 */
#ifdef	BLOCKING_RW
			/*
			 * NOTE:  We don't assert TS_CARR_ON at this point,
			 * since we want the opportunity
			 * to block in READ or WRITE,
			 * if TS_CARR_ON is not really (yet) asserted.
			 *
			 * The only problem with this scheme is if
			 * we have a "carrier lost".
			 * "Carrier lost" and never-any-carrier are,
			 * for practical purposes, indistinguishable.
			 */
#else	BLOCKING_RW
			/*
			 * This is could be an outright lie...
			 * bkread() says "carrier lost",
			 * meaning "never present",
			 * since we did not block on TS_CARR_ON
			 * in octread(), octwrite() or octopen().
			 */
			tp->t_state |= TS_CARR_ON;
#endif	BLOCKING_RW
			break;
		}
#endif	BS2000_MODS
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	}
	error = (*linesw[tp->t_line].l_open)(dev, tp);
#ifdef	BS2000_MODS
	/*
	 * If it is not us, then we PRESUME it to be the vo-driver.
	 * We ASSERT there is a 1:1 map between the vo_tty[] and oct_tty[],
	 * and make the vo-state our state for the corresponding minor(dev).
	 * This prevents conflicting line access originating from our side.
	 * We unwind this via octclose().
	 * BUG:  This stinks -- hands in each other's back pockets!...
	 */
	if (major(dev) != OCT_MAJOR) {
		extern	struct	tty	vo_tty[];

		oct_tty[minor(dev)].t_state	= vo_tty[minor(dev)].t_state;
	}
#endif	BS2000_MODS
	(void) spl0();
	return error;
}

octclose(dev)
	dev_t dev;
{
	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
	struct ocdevice *addr = ADDR(tp);
	int wakeme(); /* Called from timeout() */
	int error;

	(*linesw[tp->t_line].l_close)(tp);
	addr->occr &= ~OCCR_BRK;
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	error = ttyclose(tp);			/* drain output first */
#ifdef	BS2000_MODS
	/*
	 * Unwind the Siemens BS2000 nonsense connected
	 * with the vo-driver.
	 */
	if (major(dev) != OCT_MAJOR) {
		extern	struct	tty	vo_tty[];

		oct_tty[minor(dev)].t_state	= vo_tty[minor(dev)].t_state;

		/*
		** This little goodie is to give the VG time to flush
		** it's buffer before closing the device. This is 
		** needed to make line printers work.
		** WARNING: If line printer goes off line while we are
		** sleeping some characters might get lost!
		** 860521 -- chrisw
		*/
		timeout(wakeme,(caddr_t)&vo_tty[minor(dev)],2*hz);
		/* Note: this sleep can't be interrupted, it MUST timeout */
		sleep((caddr_t)&vo_tty[minor(dev)],PZERO-1);
	}
#endif	BS2000_MODS
	addr->occr &= ~(OCCR_DTR|OCCR_RTS|OCCR_RXEN);
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	return error;
}

octread(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];

#ifdef	BS2000
	/*
	 * NOTE:  There is a side effect in bkread(),
	 * to which this is a transfer, that must be handled:
	 *
	 * The 2nd parameter to uiomove(), t_inbuf, has a value
	 * of BKBUFSIZ(==4096), which is sufficient
	 * for the BS2000 code to work, the latter requiring 2050 bytes.
	 *
	 * t_inbuf is actually set in bkread().
	 * Also, you should verify the value of BKBUFSIZ in ../h/bk.h,
	 * rather than accept this hearsay.
	 *
	 */
#ifdef	BLOCKING_RW
	/*
	 * NOTE: We hang here if carrier is "lost";
	 * Or if carrier has never-been-present:
	 * Viz., FNDELAY'ing through a (non-blocking) octopen().
	 */
	while ((tp->t_state & TS_CARR_ON) == 0) {
		/*
		 * voscan() or octscan() will wake us up.
		 */
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	}
#endif	BLOCKING_RW
#endif	BS2000
	return (*linesw[tp->t_line].l_read)(tp, uio);
}

octwrite(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];

	return (*linesw[tp->t_line].l_write)(tp, uio);
}

/*
 * Pseudo-dma code.
 */
asm(".p_addr = 0");
asm(".p_mem = 4");
asm(".p_end = 8");
asm(".p_arg = 12");
asm(".p_fcn = 16");
asm(".p_size = 20");		/* sizeof (struct pdma) */
asm(".nline = 8");
asm(".ocdr = 1");
asm(".ocsr = 0");
asm(".txrdy = 0");		/* bit number of TXRDY */
asm(".rxrdy = 1");
asm("	.text ");
asm("	.globl	octintr");
asm("octintr:");
	asm("	movl	sp@(4),d0");
	asm("	moveml	#0x3030,sp@-");		/* d2, d3, a2, a3 */
	asm("	clrl	d2");
	asm("	movw	#.nline-1,d3");
	asm("	asll	#2,d0");
	asm("	movl	#oct_pdmap,a2");
	asm("	movl	a2@(0,d0:l),a2");
	asm(".loop:");
	asm("	movl	a2@(.p_addr),a3");
#ifdef	M68020
	asm("	tstl	0x20000	| Pause while onboard writeQ flushes");
	asm("	tstl	0x24000	| ...");
#endif	M68020
	asm("	btst	#.rxrdy,a3@(.ocsr)");
	asm("	beqs	.octintr0");
	asm("	movb	#1,d2");
	asm("	movl	a2@(.p_arg),sp@-");	/* call octrint */
	asm("	jsr	octrint");
	asm("	addql	#4,sp");
	asm(".octintr0:");
#ifdef	M68020
	asm("	tstl	0x20000	| Pause while onboard writeQ flushes");
	asm("	tstl	0x24000	| ...");
#endif	M68020
	asm("	btst	#.txrdy,a3@(.ocsr)");
	asm("	beqs	.octintr2");
	asm("	movb	#1,d2");
	asm("	movl	a2@(.p_mem),a0");	/* check pdma */
	asm("	cmpl	a2@(.p_end),a0");
	asm("	bcss	.octintr1");
	asm("	movl	a2@(.p_arg),sp@-");	/* call octxint */
	asm("	movl	a2@(.p_fcn),a0");
	asm("	jsr	a0@");
	asm("	addql	#4,sp");
	asm("	bras	.octintr2");
	asm(".octintr1:");
#ifdef	M68020
	asm("	tstl	0x20000	| Pause while onboard writeQ flushes");
	asm("	tstl	0x24000	| ...");
#endif	M68020
	asm("	movb	a0@+,a3@(.ocdr)");
	asm("	movl	a0,a2@(.p_mem)");
	asm(".octintr2:");
	asm("	addl	#.p_size,a2");
	asm("	dbra	d3,.loop");
	asm("	movl	d2,d0");
	asm("	moveml	sp@+,#0x0c0c");		/* a3, a2, d3, d2 */
	asm("	rts");

octrint(tp)
	register struct tty *tp;
{
	register struct ocdevice *addr = ADDR(tp);
	register c;

#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	while (addr->ocsr & OCSR_RXRDY) {
		c = addr->ocdr;
		if (addr->ocsr & OCSR_FE) {
			addr->occr |= OCCR_CLR;
			c = tp->t_flags & RAW ? 0 : tp->t_intrc;
		}
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
}

octxint(tp)
	register struct tty *tp;
{
	register struct pdma *dp = (struct pdma *)tp->t_addr;

#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	((struct ocdevice *)dp->p_addr)->occr &= ~OCCR_TXEN;
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	if ((tp->t_state & TS_BUSY) == 0) {
		printf("oct%d: spurious interrupt.\n", minor(tp->t_dev));
		return;
	}
	tp->t_state &= ~TS_BUSY;
	if (tp->t_state & TS_FLUSH)
		tp->t_state &= ~TS_FLUSH;
	else {
		ndflush(&tp->t_outq, dp->p_mem - tp->t_outq.c_cf);
		dp->p_end = dp->p_mem = 0;
	}
	(*linesw[tp->t_line].l_start)(tp);
}

octstart(tp)
	register struct tty *tp;
{
	register struct pdma *dp = (struct pdma *)tp->t_addr;
	register c, n;
	int ttrstrt();

	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
		return;
	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
		if (tp->t_state & TS_ASLEEP) {
			tp->t_state &= ~TS_ASLEEP;
			wakeup((caddr_t)&tp->t_outq);
		}
		if (tp->t_wsel) {
			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
			tp->t_wsel = 0;
			tp->t_state &= ~TS_WCOLL;
		}
	}
	if (tp->t_outq.c_cc == 0)
		return;
	if (tp->t_flags & (RAW|LITOUT))
		n = ndqb(&tp->t_outq, 0);
	else {
		n = ndqb(&tp->t_outq, 0x80);
		if (n == 0) {
			c = getc(&tp->t_outq);
			timeout(ttrstrt, (caddr_t)tp, (c & 0x7f) + 6);
			tp->t_state |= TS_TIMEOUT;
			return;
		}
	}
	c = getc(&tp->t_outq);
	n--;
	dp->p_mem = tp->t_outq.c_cf;
	dp->p_end = dp->p_mem + n;
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	((struct ocdevice *)dp->p_addr)->occr |= OCCR_TXEN;
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	((struct ocdevice *)dp->p_addr)->ocdr = c;
	tp->t_state |= TS_BUSY;
}

/*ARGSUSED*/
octstop(tp, flag)
	register struct tty *tp;
{
	register struct pdma *dp = (struct pdma *)tp->t_addr;
	int s = spl5();

	if (tp->t_state & TS_BUSY) {
		dp->p_end = dp->p_mem;
		if ((tp->t_state & TS_TTSTOP) == 0)
			tp->t_state |= TS_FLUSH;
	}
	splx(s);
}

octioctl(dev, cmd, data, flag)
	caddr_t data;
	dev_t dev;
{
	int line = minor(dev);
	register struct tty *tp = cdevsw[major(dev)].d_ttys + line;
	register struct ocdevice *addr = ADDR(tp);
	register i;
	int error;

	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
	if (error >= 0)
		return error;
	error = ttioctl(tp, cmd, data, flag);
	if (error > 0)
		return error;
	if (error == 0) {
		switch (cmd) {
		case TIOCSETN:
		case TIOCSETP:
		case TIOCSET:
		case TIOCBIS:
		case TIOCBIC:
		case TIOCLSET:
		case TIOCLBIS:
		case TIOCLBIC:
			octparam(tp);
			break;
		}
		return 0;
	}
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	switch (cmd) {
	case TIOCSBRK:
		addr->occr |= OCCR_BRK;
		break;
	case TIOCCBRK:
		addr->occr &= ~OCCR_BRK;
		break;
	case TIOCSDTR:
		addr->occr |= OCCR_DTR;
		break;
	case TIOCCDTR:
		addr->occr &= ~OCCR_DTR;
		break;
	case TIOCMODG:
		i = TIOCM_LE;
		if (addr->occr & OCCR_DTR)
			i |= TIOCM_DTR;
		if (addr->occr & OCCR_RTS)
			i |= TIOCM_RTS;
		if (addr->ocsr & OCSR_DSR)
			i |= TIOCM_CTS|TIOCM_DSR;
		if (addr->ocsr & OCSR_DCD)
			i |= TIOCM_CAR;
		*(int *)data = i;
		break;
	case TIOCMODS:
		spl7();
		i = *(int *)data;
		addr->occr = addr->occr & (OCCR_RXEN|OCCR_TXEN) |
			(i & TIOCM_DTR ? OCCR_DTR : 0) |
			(i & TIOCM_RTS ? OCCR_RTS : 0);
		spl0();
		break;
	case TIOCMGET:		/* not supported */
	case TIOCMSET:
	case TIOCMBIS:
	case TIOCMBIC:
	default:
		return ENOTTY;
	}
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	return 0;
}

octparam(tp)
	register struct tty *tp;
{
	register struct ocdevice *addr = ADDR(tp);
	register i;
	int s = spl5();

#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	i = addr->occr;			/* point to mr1 */
	i = OCMR1_NORMAL;
	switch (tp->t_ospeed) {
	case B110:
		i |= OCMR1_STOP2;
		break;
	case B134:
		i |= OCMR1_STOP1_5;
		break;
	default:
		i |= OCMR1_STOP1;
		break;
	}
	if (tp->t_flags&(RAW|LITOUT) || (tp->t_flags&ANYP) == 0)
		i |= OCMR1_LEN8;
	else {
		/* both EVENP|ODDP is not supported */
		i |= OCMR1_LEN7|OCMR1_PEN;
		if (tp->t_flags & EVENP)
			i |= OCMR1_PEVEN;
	}
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	addr->ocmr = i;						/* mr1 */
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	addr->ocmr = OCMR2_NORMAL | oct_baud[tp->t_ospeed];	/* mr2 */
#ifdef	M68020
	flushWriteQueue();	/* Pause while onboard writeQ flushes */
#endif	M68020
	splx(s);
}

octscan()
{
	register bit, *c;
	register struct tty *tp;

	for (tp = oct_tty, c = oct_softCAR; c < oct_softCAR + NOCT; c++)
		for (bit = 1; bit != 1 << NLINE; bit <<= 1, tp++) {
			if (tp->t_addr == 0)	/* not attached */
				continue;
#ifdef	M68020
			flushWriteQueue();	/* Pause while writeQ flushes */
#endif	M68020
#ifndef	BS2000_MODS
			if (*c & bit || ADDR(tp)->ocsr & (OCSR_DSR|OCSR_DCD)) {
				if ((tp->t_state & TS_CARR_ON) == 0) {
					wakeup((caddr_t)&tp->t_rawq);
					tp->t_state |= TS_CARR_ON;
				}
#else	BS2000_MODS
			 /*
			  * Allow any of DSR, DCD, or RXRDY to kick us loose.
			  * RXRDY being necessary for Valid's (sic) wiring,
			  * as well as nominal 3-wire RS232 hookups. 
			  *
			  * NOTE:  the 26[56]1 USARTs do NOT bring CTS
			  * out to a status register where you could get
			  * at it with software.
			  */
			if ((*c & bit)
			 || (ADDR(tp)->ocsr & (OCSR_DSR|OCSR_DCD|OCSR_RXRDY)))
			{
				/*
				 * octopen() sleep()-s on vo_tty[i].t_rawq
				 * until we assert "carrier-on".
				 *
				 * For the case of the Siemens BS2000,
				 * octscan() STILL has the responsibility
				 * of asserting logical "carrier-on"
				 * when the VG-managed line has become active.
				 * Hanging in read() would have done
				 * just as well...and not broken the long chain
				 * of tradition from R7.27 (4.1bsd)
				 */
				if ((tp->t_state & TS_CARR_ON) == 0) {
					/*
					 * NOTE:  I also fixed a race here:
					 */
					tp->t_state |= TS_CARR_ON;
					wakeup((caddr_t)&tp->t_rawq);
				}
			} else
				if (tp->t_state & TS_CARR_ON &&
				    (tp->t_flags & NOHANG) == 0) {
					if (tp->t_state&TS_ISOPEN) {
						gsignal(tp->t_pgrp, SIGHUP);
						gsignal(tp->t_pgrp, SIGCONT);
					}
					tp->t_state &= ~TS_CARR_ON;
				}
#ifdef	M68020
			flushWriteQueue();	/* Pause while writeQ flushes */
#endif	M68020
		}
	timeout(octscan, (caddr_t)0, 2 * hz);
}

wakeme(x)
caddr_t x;
{
	wakeup(x);
}
#endif	NOCT > 0
