FAS 2.09 async driver, part 3/4

Uwe Doering gemini at geminix.in-berlin.de
Mon Jun 24 06:29:16 AEST 1991


Submitted-by: gemini at geminix.in-berlin.de
Archive-name: fas209/part03

#!/bin/sh
# this is fas209.03 (part 3 of fas209)
# do not concatenate these parts, unpack them in order with /bin/sh
# file fas.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 3; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping fas.c'
else
echo 'x - continuing file fas.c'
sed 's/^X//' << 'SHAR_EOF' >> 'fas.c' &&
X}
X
X/* write characters to the output buffer */
Xint
Xfaswrite (dev)
Xint	dev;
X{
X	register struct fas_info	*fip;
X	register struct tty	*ttyp;
X
X	fip = fas_info_ptr [GET_UNIT (dev)];
X	ttyp = fip->tty;
X
X	(*linesw [ttyp->t_line].l_write) (ttyp);
X	return (0);
X}
X
X/* process ioctl calls */
Xint
Xfasioctl (dev, cmd, arg3, arg4)
Xint	dev;
Xint	cmd;
Xunion ioctl_arg	arg3;
Xint	arg4;
X{
X	register struct fas_info	*fip;
X	register struct tty	*ttyp;
X	int	v86_cmd, v86_data;
X	int	old_level;
X	REGVAR;
X
X	fip = fas_info_ptr [GET_UNIT (dev)];
X	ttyp = fip->tty;
X
X	/* process ioctl commands */
X	switch (cmd)
X	{
X#if defined (HAVE_VPIX)
X		case AIOCINTTYPE:	/* set pseudorupt type */
X			switch (arg3.iarg)
X			{
X				case V86VI_KBD:
X				case V86VI_SERIAL0:
X				case V86VI_SERIAL1:
X					intr_disable ();
X					fip->v86_intmask = arg3.iarg;
X					intr_restore ();
X					break;
X
X				default:
X					intr_disable ();
X					fip->v86_intmask = V86VI_SERIAL0;
X					intr_restore ();
X					break;
X			}
X			break;
X
X		case AIOCDOSMODE:	/* enable dos mode */
X			if (!(fip->iflag & DOSMODE))
X			{
X				old_level = SPLINT ();
X				fip->v86_proc = u.u_procp->p_v86;
X				if (!(fip->v86_intmask))
X					fip->v86_intmask = V86VI_SERIAL0;
X				ttyp->t_iflag |= DOSMODE;
X				if (fip->v86_intmask != V86VI_KBD)
X					ttyp->t_cflag |= CLOCAL;
X				fas_param (fip, SOFT_INIT);
X				(void) splx (old_level);
X			}
X			u.u_r.r_reg.r_val1 = 0;
X			break;
X
X		case AIOCNONDOSMODE:	/* disable dos mode */
X			if (fip->iflag & DOSMODE)
X			{
X				old_level = SPLINT ();
X				fip->v86_proc = (v86_t *) NULL;
X				fip->v86_intmask = 0;
X				ttyp->t_iflag &= ~DOSMODE;
X				if (fip->flow_flags.i & FF_RXFER_STOPPED)
X				{
X					fip->flow_flags.s &= ~FF_RXFER_STOPPED;
X					/* schedule character transfer
X					   to UNIX buffer
X					*/
X					if (fip->recv_ring_cnt)
X						event_sched (fip, EF_DO_RXFER);
X				}
X				fip->lcr &= ~LC_SET_BREAK_LEVEL;
X				fas_param (fip, HARD_INIT);
X				(void) splx (old_level);
X			}
X			u.u_r.r_reg.r_val1 = 0;
X			break;
X
X		case AIOCSERIALOUT:	/* setup port registers for dos */
X			if ((fip->iflag & DOSMODE) && fip->v86_proc)
X			{
X				/* wait until output is done */
X				old_level = SPLINT ();
X				while (ttyp->t_outq.c_cc
X					|| (ttyp->t_state & (BUSY | TIMEOUT)))
X				{
X					ttyp->t_state |= TTIOW;
X					(void) sleep ((caddr_t) &ttyp->t_oflag,
X									TTOPRI);
X				}
X
X				/* block transmitter and wait until it is
X				   empty
X				*/
X				fip->device_flags.s |= DF_XMIT_LOCKED;
X				while (fip->device_flags.i & (DF_XMIT_BUSY
X							| DF_XMIT_BREAK
X							| DF_GUARD_TIMEOUT))
X					(void) sleep ((caddr_t) &fip->
X								device_flags.i,
X							PZERO - 1);
X				(void) splx (old_level);
X
X				/* get port write command */
X				v86_cmd = fubyte (arg3.cparg);
X				/* set divisor lsb requested */
X				if (v86_cmd & SIO_MASK(SO_DIVLLSB))
X				{
X					v86_data = fubyte (arg3.cparg
X								+ SO_DIVLLSB);
X					intr_disable ();
X					fas_first_outb (fip, LINE_CTL_PORT, fip->lcr
X							| LC_ENABLE_DIVISOR);
X					fas_outb (fip, DIVISOR_LSB_PORT, v86_data);
X					fas_outb (fip, LINE_CTL_PORT, fip->lcr
X							& ~LC_ENABLE_DIVISOR);
X					intr_restore ();
X				}
X				/* set divisor msb requested */
X				if (v86_cmd & SIO_MASK(SO_DIVLMSB))
X				{
X					v86_data = fubyte (arg3.cparg
X								+ SO_DIVLMSB);
X					intr_disable ();
X					fas_first_outb (fip, LINE_CTL_PORT, fip->lcr
X							| LC_ENABLE_DIVISOR);
X					fas_outb (fip, DIVISOR_MSB_PORT, v86_data);
X					fas_outb (fip, LINE_CTL_PORT, fip->lcr
X							& ~LC_ENABLE_DIVISOR);
X					intr_restore ();
X				}
X				/* set lcr requested */
X				if (v86_cmd & SIO_MASK(SO_LCR))
X				{
X					v86_data = fubyte (arg3.cparg + SO_LCR);
X					intr_disable ();
X					fip->lcr = v86_data
X							& ~LC_ENABLE_DIVISOR;
X					fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X					intr_restore ();
X				}
X				/* set mcr requested */
X				if (v86_cmd & SIO_MASK(SO_MCR))
X				{
X					v86_data = fubyte (arg3.cparg + SO_MCR);
X					old_level = SPLINT ();
X					/* virtual dtr processing */
X					if (v86_data & MC_SET_DTR)
X					{
X						fip->device_flags.s
X							|= DF_MODEM_ENABLED;
X						fip->mcr |= (fip->o_state
X								& OS_WAIT_OPEN)
X							? fip->modem.m.ei
X							: fip->modem.m.eo;
X					}
X					else
X					{
X						fip->device_flags.s
X							&= ~DF_MODEM_ENABLED;
X						fip->mcr &= (fip->o_state
X								& OS_WAIT_OPEN)
X							? ~fip->modem.m.ei
X							: ~fip->modem.m.eo;
X					}
X					/* virtual rts processing */
X					if (fip->flow_flags.i
X							& FF_HWI_HANDSHAKE)
X					{
X					  if (v86_data & MC_SET_RTS)
X					  {
X						if (fip->flow_flags.i
X							& FF_RXFER_STOPPED)
X						{
X						  fip->flow_flags.s
X							&= ~FF_RXFER_STOPPED;
X						  /* schedule character transfer
X						     to UNIX buffer
X						  */
X						  if (fip->recv_ring_cnt)
X							event_sched (fip,
X								EF_DO_RXFER);
X						}
X					  }
X					  else
X						fip->flow_flags.s
X							|= FF_RXFER_STOPPED;
X					}
X					else if (!(fip->flow_flags.i
X							& FF_HDX_HANDSHAKE))
X					{
X						if (v86_data & MC_SET_RTS)
X						{
X							fip->flow_flags.s
X							  |= FF_HDX_STARTED;
X							fip->mcr
X							  |= fip->flow.m.hc;
X						}
X						else
X						{
X							fip->flow_flags.s
X							  &= ~FF_HDX_STARTED;
X							fip->mcr
X							  &= ~fip->flow.m.hc;
X						}
X					}
X					fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X					(void) splx (old_level);
X				}
X
X				old_level = SPLINT ();
X				/* enable transmitter and restart output */
X				fip->device_flags.s &= ~DF_XMIT_LOCKED;
X				fas_xproc (fip);
X				(void) splx (old_level);
X			}
X			break;
X
X		case AIOCSERIALIN:	/* read port registers for dos */
X			if ((fip->iflag & DOSMODE) && fip->v86_proc)
X			{
X				v86_cmd = fubyte (arg3.cparg);
X				if (v86_cmd & SIO_MASK(SI_MSR))
X				{
X					(void) subyte (arg3.cparg + SI_MSR,
X							((fip->flow_flags.i
X							  & FF_HWO_HANDSHAKE)
X							? fip->msr
X							  | fip->flow.m.oc
X							  | fip->flow.m.oe
X							: fip->msr)
X							& MS_ANY_PRESENT);
X				}
X			}
X			break;
X
X		case AIOCSETSS:	/* set start/stop characters */
X			intr_disable ();
X			*((short *) (&fip->v86_ss)) = arg3.iarg;
X			intr_restore ();
X			break;
X
X		case AIOCINFO:	/* show what type of device we are */
X			u.u_r.r_reg.r_val1 = ('a' << 8) | GET_UNIT (dev);
X			break;
X#endif
X		default:	/* default ioctl processing */
X			/* if it is a TCSETA* command, call fas_param () */
X			if (ttiocom (ttyp, cmd, arg3, arg4))
X			{
X				old_level = SPLINT ();
X				fas_param (fip, SOFT_INIT);
X				(void) splx (old_level);
X			}
X			/* restart input if we are in cooked mode */
X			if (fip->recv_ring_cnt
X				&& (ttyp->t_line || (ttyp->t_lflag & ICANON)))
X			{
X				old_level = SPLINT ();
X				event_sched (fip, EF_DO_RXFER);
X				(void) splx (old_level);
X			}
X			break;
X	}
X	return (0);
X}
X
X/* pass fas commands to the fas multi-function procedure */
Xstatic int
Xfas_proc (ttyp, arg2)
Xstruct tty	*ttyp;
Xint	arg2;
X{
X	register uint	physical_unit;
X	int	old_level;
X
X	physical_unit = ttyp - &fas_tty [0];
X	if (physical_unit >= fas_physical_units)
X		physical_unit -= fas_physical_units;
X
X	old_level = SPLINT ();
X	fas_cmd (fas_info_ptr [physical_unit], ttyp, arg2);
X	(void) splx (old_level);
X	return (0);
X}
X
X/* set up a port according to the given termio structure */
Xstatic void
Xfas_param (fip, init_type)
Xregister struct	fas_info	*fip;
Xint	init_type;
X{
X	register uint	cflag;
X	uint	divisor;
X	int	xmit_ring_size;
X	REGVAR;
X
X	cflag = fip->tty->t_cflag;
X
X#if defined (HAVE_VPIX)
X	/* we don't set port registers if we are in dos mode */
X	if (fip->tty->t_iflag & DOSMODE)
X		goto setflags2;
X#endif
X	/* if soft init mode: don't set port registers if cflag didn't change */
X	if ((init_type == SOFT_INIT) && !((cflag ^ fip->cflag)
X						& (CBAUD | CSIZE | CSTOPB
X							| PARENB | PARODD)))
X		goto setflags;
X
X	/* lock transmitter and wait until it is empty */
X	fip->device_flags.s |= DF_XMIT_LOCKED;
X	while (fip->device_flags.i & (DF_XMIT_BUSY | DF_XMIT_BREAK
X							| DF_GUARD_TIMEOUT))
X		(void) sleep ((caddr_t) &fip->device_flags.i, PZERO - 1);
X
X	/* hangup line if it is baud rate 0, else enable line */
X	if ((cflag & CBAUD) == B0)
X	{
X		fip->mcr &= (fip->o_state & OS_WAIT_OPEN)
X				? ~fip->modem.m.ei
X				: ~fip->modem.m.eo;
X		fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X		fip->device_flags.s &= ~DF_MODEM_ENABLED;
X	}
X	else
X	{
X		if (!(fip->device_flags.i & DF_MODEM_ENABLED))
X		{
X			fip->mcr |= (fip->o_state & OS_WAIT_OPEN)
X					? fip->modem.m.ei
X					: fip->modem.m.eo;
X			fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X			fip->device_flags.s |= DF_MODEM_ENABLED;
X		}
X	}
X
X	/* don't change break flag */
X	fip->lcr &= LC_SET_BREAK_LEVEL;
X
X	/* set character size */
X	switch (cflag & CSIZE)
X	{
X	case CS5:
X		fip->lcr |= LC_WORDLEN_5;
X		break;
X
X	case CS6:
X		fip->lcr |= LC_WORDLEN_6;
X		break;
X
X	case CS7:
X		fip->lcr |= LC_WORDLEN_7;
X		break;
X
X	default:
X		fip->lcr |= LC_WORDLEN_8;
X		break;
X	}
X
X	/* set # of stop bits */
X	if (cflag & CSTOPB)
X		fip->lcr |= LC_STOPBITS_LONG;
X
X	/* set parity */
X	if (cflag & PARENB)
X	{
X		fip->lcr |= LC_ENABLE_PARITY;
X
X		if (!(cflag & PARODD))
X			fip->lcr |= LC_EVEN_PARITY;
X	}
X
X	/* set divisor registers only if baud rate is valid */
X	if ((cflag & CBAUD) != B0)
X	{
X		/* get counter divisor for selected baud rate */
X		divisor = fas_speeds [cflag & CBAUD];
X		/* set LCR and baud rate */
X		fas_first_outb (fip, LINE_CTL_PORT, fip->lcr
X							| LC_ENABLE_DIVISOR);
X		fas_outb (fip, DIVISOR_LSB_PORT, divisor);
X		fas_outb (fip, DIVISOR_MSB_PORT, divisor >> 8);
X	}
X
X	fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X
Xsetflags:
X	/* check dynamic xmit ring buffer size against boundaries,
X	   modify it if necessary and update the fas_info structure
X	*/
X	if ((cflag & CBAUD) != B0)
X	{
X		xmit_ring_size = fas_xbuf_size [cflag & CBAUD]
X					- tthiwat [cflag & CBAUD];
X		if (xmit_ring_size < MAX_OUTPUT_FIFO_SIZE * 2)
X		{
Xsetflags2:
X			xmit_ring_size = MAX_OUTPUT_FIFO_SIZE * 2;
X		}
X		if (xmit_ring_size > XMIT_BUFF_SIZE)
X			xmit_ring_size = XMIT_BUFF_SIZE;
X		fip->xmit_ring_size = xmit_ring_size;
X	}
X
X	/* setup character time for B0 mode */
X	fas_ctimes [B0] = fas_ctimes [cflag & CBAUD];
X
X	/* disable modem control signals if required by open mode */
X	if (fip->o_state & OS_CLOCAL)
X		cflag |= CLOCAL;
X
X	/* Select hardware handshake depending on the minor device
X	   number and the CTSFLOW and RTSFLOW flags (if they are
X	   available).
X	*/
X	fip->flow_flags.s &= ~(FF_HWO_HANDSHAKE
X				| FF_HWI_HANDSHAKE
X				| FF_HDX_HANDSHAKE);
X	if (fip->o_state & (OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE
X					| OS_HDX_HANDSHAKE))
X	{
X		if (fip->o_state & OS_HWO_HANDSHAKE)
X			fip->flow_flags.s |= FF_HWO_HANDSHAKE;
X		if (fip->o_state & OS_HWI_HANDSHAKE)
X			fip->flow_flags.s |= FF_HWI_HANDSHAKE;
X		if (fip->o_state & OS_HDX_HANDSHAKE)
X			fip->flow_flags.s |= FF_HDX_HANDSHAKE;
X	}
X	else
X	{
X#if defined (CTSFLOW)	/* SYSV 3.2 Xenix compatibility */
X		if ((cflag & (CTSFLOW | CLOCAL)) == CTSFLOW)
X			fip->flow_flags.s |= FF_HWO_HANDSHAKE;
X#endif
X#if defined (RTSFLOW)	/* SYSV 3.2 Xenix compatibility */
X		if ((cflag & (RTSFLOW | CLOCAL)) == RTSFLOW)
X			fip->flow_flags.s |= FF_HDX_HANDSHAKE;
X#endif
X	}
X
X	/* Determine whether to enable MSI, or not.
X	   Set the interrupt enable port accordingly.
X	*/
X#if defined (HAVE_VPIX)
X	if ((cflag & CLOCAL) && !(fip->flow_flags.i & FF_HWO_HANDSHAKE)
X		&& !(fip->tty->t_iflag & DOSMODE))
X#else
X	if ((cflag & CLOCAL) && !(fip->flow_flags.i & FF_HWO_HANDSHAKE))
X#endif
X	{
X		if (fip->device_flags.i & DF_MSI_ENABLED)
X		{
X			fip->ier &= ~IE_MODEM_STATUS;
X			fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X			fip->device_flags.s &= ~DF_MSI_ENABLED;
X		}
X	}
X	else
X	{
X		if (!(fip->device_flags.i & DF_MSI_ENABLED))
X		{
X			fip->new_msr &= ~MS_ANY_DELTA;
X			fip->ier |= IE_MODEM_STATUS;
X			fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X			fip->device_flags.s |= DF_MSI_ENABLED;
X		}
X	}
X
X	/* Fake the carrier detect state flag if CLOCAL mode or if
X	   requested by open mode.
X	*/
X	if (!(~fip->msr & fip->modem.m.ca)
X		|| (fip->o_state & OS_FAKE_CARR_ON)
X		|| (cflag & CLOCAL))
X		fip->tty->t_state |= CARR_ON;
X	else
X		fip->tty->t_state &= ~CARR_ON;
X
X#if defined (XCLUDE)	/* SYSV 3.2 Xenix compatibility */
X	/* Permit exclusive use of this device. */
X	if (cflag & XCLUDE)
X		fip->o_state |= OS_EXCLUSIVE_OPEN_2;
X	else
X		fip->o_state &= ~OS_EXCLUSIVE_OPEN_2;
X#endif
X
X	fip->cflag = cflag;
X	fip->iflag = fip->tty->t_iflag;
X
X	/* enable transmitter */
X	fip->device_flags.s &= ~DF_XMIT_LOCKED;
X
X	/* setup handshake flags */
X	fas_hdx_check (fip);
X	fas_ihlw_check (fip);
X	fas_fproc (fip, fip->new_msr);
X
X	/* restart output */
X	fas_xproc (fip);
X}
X
X/* Main fas interrupt handler. Actual character processing is splitted
X   into sub-functions.
X*/
Xint
Xfasintr (vect)
Xint	vect;
X{
X	register struct fas_info	*fip;
X	register uint	status;
X	struct fas_info	*old_fip;
X	int	done, drop_mode;
X	uint	port, old_recv_count;
X	REGVAR;
X
X	drop_mode = FALSE;
X
X	/* The 8259 interrupt controller is set up for edge trigger.
X	   Therefore, we must loop until we make a complete pass without
X	   getting any UARTs that are interrupting.
X	*/
X	do
X	{
X		done = TRUE;
X		fip = fas_first_int_user [vect];
X
X		/* loop through all users of this interrupt vector */
X		for (;; fip = fip->next_int_user)
X		{
X			if (!fip)
X				break;	/* all users done */
X
X			/* process only ports that we expect ints from
X			   and that actually need to be serviced
X			*/
Xfastloop:
X			if (fas_first_inb (fip, INT_ID_PORT)
X					& II_NO_INTS_PENDING)
X			{
X				/* restore the normal receiver trigger level */
X				if (fip->device_flags.i & DF_NS16550A_DROP_MODE)
X				{
X					fip->device_flags.s &=
X							~DF_NS16550A_DROP_MODE;
X					fas_outb (fip, NS_FIFO_CTL_PORT,
X							NS_FIFO_SETUP_CMD);
X				}
X				/* speed beats beauty */
X				fip = fip->next_int_user;
X				if (fip)
X					goto fastloop;
X				break;
X			}
X
X			/* restore the normal receiver trigger level */
X			if (fip->device_flags.i & DF_NS16550A_DROP_MODE)
X			{
X				fip->device_flags.s &= ~DF_NS16550A_DROP_MODE;
X				fas_outb (fip, NS_FIFO_CTL_PORT,
X							NS_FIFO_SETUP_CMD);
X			}
X
X			done = FALSE;	/* not done if we got an int */
X			old_recv_count = fip->recv_ring_cnt;
X
X			do
X			{
X				/* read in all the characters from the FIFO */
X				if ((status = fas_inb (fip, LINE_STATUS_PORT))
X							& LS_RCV_INT)
X				{
X				    if (!drop_mode && (fip->device_flags.i
X						& DF_DEVICE_IS_NS16550A))
X				    {
X					/* Drop receiver trigger levels to make
X					   sure that we will see all received
X					   characters in all NS16550A. This
X					   prevents multiple interrupts if we
X					   receive characters on more than one
X					   unit.
X					*/
X					old_fip = fip;
X					for (fip = fas_first_int_user [vect];
X						fip; fip = fip->next_int_user)
X					{
X					    if ((fip->device_flags.i
X							& DF_DEVICE_IS_NS16550A)
X						&& (fip != old_fip))
X					    {
X						fip->device_flags.s |=
X							DF_NS16550A_DROP_MODE;
X						fas_first_outb (fip,
X							NS_FIFO_CTL_PORT,
X							NS_FIFO_DROP_CMD);
X					    }
X					}
X					fip = old_fip;
X					drop_mode = TRUE;
X				    }
X				    status = fas_rproc (fip, status);
X				    sysinfo.rcvint++;
X				}
X
X				/* Is it a transmitter empty int ? */
X				if ((status & LS_XMIT_AVAIL)
X					&& (fip->device_flags.i & DF_XMIT_BUSY))
X				{
X					fip->device_flags.s &= ~DF_XMIT_BUSY;
X					fas_xproc (fip);
X					if (!(fip->device_flags.i
X							& DF_XMIT_BUSY))
X					{
X						fip->device_flags.s |=
X							DF_GUARD_TIMEOUT;
X						fip->timeout_idx =
X							timeout (
X							fas_timeout, fip,
X							fas_ctimes [fip->cflag
X								& CBAUD]);
X					}
X					sysinfo.xmtint++;
X				}
X
X				/* Has there been a polarity change on
X				   some of the modem lines ?
X				*/
X				if ((fip->device_flags.i & DF_MSI_ENABLED)
X					&& ((status = fas_inb (fip,
X							MDM_STATUS_PORT))
X						& MS_ANY_DELTA))
X				{
X					/* if the same modem status line
X					   is responsible for a modem status
X					   interrupt twice during two
X					   event scheduler runs, we disable
X					   modem status interrupts until we
X					   process this interrupt in the event
X					   scheduler
X					*/
X					if (status & fip->new_msr
X						& MS_ANY_DELTA)
X					{
X						fip->ier &= ~IE_MODEM_STATUS;
X						fas_outb (fip, INT_ENABLE_PORT,
X								fip->ier);
X						fip->device_flags.s
X							&= ~DF_MSI_ENABLED;
X					}
X					/* Do special RING line handling.
X					   RING generates an int only on the
X					   trailing edge.
X					*/
X					status = (status & ~MS_RING_PRESENT)
X						| (fip->new_msr
X							& MS_RING_PRESENT);
X					if (status & MS_RING_TEDGE)
X						status |= MS_RING_PRESENT;
X					if ((status ^ fip->new_msr)
X							& MS_ANY_PRESENT)
X					{
X						/* check hw flow flags */
X						fas_fproc (fip, status);
X						event_sched (fip, EF_DO_MPROC);
X					}
X					else
X						event_sched(fip,
X							EF_EMPTY_EVENT);
X					/* "or" the delta flags to prevent
X					   excessive modem status interrupts
X					*/
X					fip->new_msr = status
X							| (fip->new_msr
X								& MS_ANY_DELTA);
X					sysinfo.mdmint++;
X				}
X			} while (!(fas_inb (fip, INT_ID_PORT)
X						& II_NO_INTS_PENDING));
X
X			/* schedule character transfer to UNIX buffer */
X			if (fip->recv_ring_cnt
X				&& (fip->tty->t_line
X				|| (fip->tty->t_lflag & ICANON)
X#if defined (HAVE_VPIX)
X				|| ((((fip->iflag & DOSMODE)
X					? MAX_VPIX_FILL - MIN_READ_CHUNK
X					: MAX_UNIX_FILL - MIN_READ_CHUNK)
X						>= fip->tty->t_rawq.c_cc)
X#else
X				|| (((MAX_UNIX_FILL - MIN_READ_CHUNK)
X						>= fip->tty->t_rawq.c_cc)
X#endif
X				&& !(fip->flow_flags.i & FF_RXFER_STOPPED))))
X			{
X				event_sched (fip, EF_DO_RXFER);
X			}
X
X			/* check input buffer high/low water marks */
X			if (fip->recv_ring_cnt != old_recv_count)
X				fas_ihlw_check (fip);
X		}
X	} while (!done);
X
X	/* clear the shared interrupt since we have scanned all
X	   of the ports that share this interrupt vector
X	*/	
X	if (port = fas_int_ack_port [vect])
X		(void) outb (port, fas_int_ack [vect]);
X
X	return (0);
X}
X
X/* hardware flow control interrupt handler */
Xstatic void
Xfas_fproc (fip, mdm_status)
Xregister struct fas_info	*fip;
Xregister uint	mdm_status;
X{
X	/* Check the output flow control signals and set the state flag
X	   accordingly.
X	*/
X	if (!(~mdm_status & fip->flow.m.oc)
X		|| (~mdm_status & fip->flow.m.oe)
X		|| !(fip->flow_flags.i & FF_HWO_HANDSHAKE))
X	{
X		if (fip->flow_flags.i & FF_HWO_STOPPED)
X		{
X			fip->flow_flags.s &= ~FF_HWO_STOPPED;
X			fas_xproc (fip);
X		}
X	}
X	else
X		fip->flow_flags.s |= FF_HWO_STOPPED;
X}
X
X/* modem status handler */
Xstatic void
Xfas_mproc (fip)
Xregister struct fas_info	*fip;
X{
X	register struct tty	*ttyp;
X	register uint	mdm_status;
X	uint	vpix_status;
X	int	old_level;
X
X	ttyp = fip->tty;
X	mdm_status = fip->new_msr;
X	fip->new_msr &= ~MS_RING_PRESENT;
X
X	/* Check the carrier detect signal and set the state flags
X	   accordingly. Also, if not in clocal mode, send SIGHUP on
X	   carrier loss and flush the buffers.
X	*/
X	if (!(fip->cflag & CLOCAL))
X	{
X		if (!(~mdm_status & fip->modem.m.ca))
X		{
X			ttyp->t_state |= CARR_ON;
X			/* Unblock getty open only if it is ready to run. */
X			if ((ttyp->t_state & WOPEN)
X				&& (~fip->msr & fip->modem.m.ca))
X				(void) wakeup ((caddr_t) &ttyp->t_canq);
X		}
X		else
X		{
X			if (!(~fip->msr & fip->modem.m.ca))
X			{
X				ttyp->t_state &= ~CARR_ON;
X				old_level = SPLWRK ();
X				if (ttyp->t_pgrp && (ttyp->t_state & ISOPEN))
X					(void) signal (ttyp->t_pgrp, SIGHUP);
X				(void) ttyflush (ttyp, FREAD | FWRITE);
X				(void) splx (old_level);
X			}
X		}
X	}
X
X#if defined (HAVE_VPIX)
X	if (((fip->iflag & (DOSMODE | PARMRK))
X			== (DOSMODE | PARMRK))
X		&& (fip->v86_intmask != V86VI_KBD))
X	{
X		/* prepare status bits for VP/ix */
X		vpix_status = (((mdm_status ^ fip->msr) >> 4) & MS_ANY_DELTA)
X				| (mdm_status & (MS_CTS_PRESENT
X							| MS_DSR_PRESENT
X							| MS_DCD_PRESENT));
X		if (fip->flow_flags.i & FF_HWO_HANDSHAKE)
X		{
X			vpix_status &= ~((fip->flow.m.oc | fip->flow.m.oe)
X							>> 4);
X			vpix_status |= fip->flow.m.oc | fip->flow.m.oe;
X		}
X		/* send status bits to VP/ix */
X		if ((vpix_status & MS_ANY_DELTA)
X			&& fas_vpix_sr (fip, 2, vpix_status))
X			event_sched (fip, EF_DO_RXFER);
X	}
X#endif
X	fip->msr = mdm_status & ~MS_RING_PRESENT;
X}
X
X/* Receiver interrupt handler. Translates input characters to character
X   sequences as described in TERMIO(7) man page.
X*/
Xstatic uint
Xfas_rproc (fip, line_status)
Xregister struct fas_info	*fip;
Xuint	line_status;
X{
X	struct tty	*ttyp;
X	uint	charac;
X	register uint	csize;
X	unchar	metta [4];
X	REGVAR;
X
X	ttyp = fip->tty;
X
X	fas_first_ctl (fip, RCV_DATA_PORT);
X
X	/* Translate characters from FIFO according to the TERMIO(7)
X	   man page.
X	*/
X	do
X	{
X		charac = (line_status & LS_RCV_AVAIL)
X				? fas_inb (fip, RCV_DATA_PORT)
X				: 0;	/* was line status int only */
X
X		/* was there a receiver overrun? count them in a
X		   separate counter for each UART type
X		*/
X		if (line_status & LS_OVERRUN)
X		{
X			if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X				fas_overrun [2]++;
X			else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X				fas_overrun [1]++;
X			else
X				fas_overrun [0]++;
X		}
X
X		/* do we have to junk the character ? */
X		if (!(fip->cflag & CREAD)
X			|| ((ttyp->t_state & (ISOPEN | CARR_ON)) !=
X						(ISOPEN | CARR_ON)))
X		{
X			/* if there are FIFOs we take a short cut */
X			if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X				fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD
X							| NS_FIFO_CLR_RECV);
X			else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X			{
X				fas_outb (fip, I_BANK_PORT, I_BANK_1);
X				fas_outb (fip, I_RCM_PORT, I_FIFO_CLR_RECV);
X				fas_outb (fip, I_BANK_PORT, I_BANK_0);
X			}
X			continue;
X		}
X
X		csize = 0;
X
X		/* strip off 8th bit ? */
X		if (fip->iflag & ISTRIP)
X			charac &= 0x7f;
X
X		/* ignore parity errors ? */
X		if ((line_status & LS_PARITY_ERROR)
X			&& !(fip->iflag & INPCK))
X			line_status &= ~LS_PARITY_ERROR;
X
X		/* do we have some kind of character error ? */
X		if (line_status & (LS_PARITY_ERROR
X					| LS_FRAMING_ERROR
X					| LS_BREAK_DETECTED))
X		{
X#if defined (HAVE_VPIX)
X			if ((fip->iflag & (DOSMODE | PARMRK))
X					== (DOSMODE | PARMRK))
X			{
X				/* send status bits to VP/ix */
X				(void) fas_vpix_sr (fip, 1,
X					(line_status & (LS_PARITY_ERROR
X							| LS_FRAMING_ERROR
X							| LS_BREAK_DETECTED))
X						| LS_RCV_AVAIL
X						| LS_XMIT_AVAIL
X						| LS_XMIT_COMPLETE);
X				goto valid_char;
X			}
X#endif
X			/* is it a BREAK ? */
X			if (line_status & LS_BREAK_DETECTED)
X			{
X				if (!(fip->iflag & IGNBRK))
X					if (fip->iflag & BRKINT)
X					{
X						/* do BREAK interrupt */
X						event_sched (fip, EF_DO_BRKINT);
X					}
X					else
X					{
X						metta [csize] = 0;
X						csize++;
X						if (fip->iflag & PARMRK)
X						{
X							metta [csize] = 0;
X							csize++;
X							metta [csize] = 0xff;
X							csize++;
X						}
X					}
X			}
X			else if (!(fip->iflag & IGNPAR))
X				if (fip->iflag & PARMRK)
X				{
X					metta [csize] = charac;
X					csize++;
X					metta [csize] = 0;
X					csize++;
X					metta [csize] = 0xff;
X					csize++;
X				}
X				else
X				{
X					metta [csize] = 0;
X					csize++;
X				}
X		}
X		else
X		/* is there a character to process ? */
X		if (line_status & LS_RCV_AVAIL)
X		{
X			if (fip->iflag & IXON)
X			{
X				/* do output start/stop handling */
X				if (fip->flow_flags.i & FF_SWO_STOPPED)
X				{
X#if defined (HAVE_VPIX)
X					if ((charac == fip->v86_ss.ss_start)
X#else
X					if ((charac == CSTART)
X#endif
X						|| (fip->iflag & IXANY))
X					{
X						fip->flow_flags.s &=
X							~FF_SWO_STOPPED;
X						ttyp->t_state &= ~TTSTOP;
X						/* restart output */
X						fas_xproc (fip);
X					}
X				}
X				else
X				{
X#if defined (HAVE_VPIX)
X					if (charac == fip->v86_ss.ss_stop)
X#else
X					if (charac == CSTOP)
X#endif
X					{
X						fip->flow_flags.s |=
X							FF_SWO_STOPPED;
X						ttyp->t_state |= TTSTOP;
X					}
X				}
X				/* we don't put start/stop characters
X				   into the receiver buffer
X				*/
X#if defined (HAVE_VPIX)
X				if ((charac == fip->v86_ss.ss_start)
X					|| (charac == fip->v86_ss.ss_stop))
X#else
X				if ((charac == CSTART)
X					|| (charac == CSTOP))
X#endif
X					continue;
X			}
Xvalid_char:
X			if ((charac == 0xff) && (fip->iflag & PARMRK))
X			{
X				metta [csize] = 0xff;
X				csize++;
X				metta [csize] = 0xff;
X				csize++;
X			}
X			else
X			{
X				/* we take a short-cut if only one character
X				   has to be put into the receiver buffer
X				*/
X				if (fip->recv_ring_cnt < RECV_BUFF_SIZE)
X				{
X					fip->recv_ring_cnt++;
X					*fip->recv_ring_put_ptr = charac;
X					if (++fip->recv_ring_put_ptr
X						!= &fip->recv_buffer
X							[RECV_BUFF_SIZE])
X						continue;
X					fip->recv_ring_put_ptr =
X							&fip->recv_buffer [0];
X				}
X				continue;
X			}
X		}
X
X		if (!(csize) || (fip->recv_ring_cnt + csize > RECV_BUFF_SIZE))
X			continue;	/* nothing to put into recv buffer */
X
X		fip->recv_ring_cnt += csize;
X
X		/* store translation in ring buffer */
X		do
X		{
X			do
X			{
X				*fip->recv_ring_put_ptr = (metta - 1) [csize];
X				if (++fip->recv_ring_put_ptr
X					== &fip->recv_buffer [RECV_BUFF_SIZE])
X					break;
X			} while (--csize);
X			if (!csize)
X				break;
X			fip->recv_ring_put_ptr = &fip->recv_buffer [0];
X		} while (--csize);
X	} while ((line_status = fas_inb (fip, LINE_STATUS_PORT)) & LS_RCV_INT);
X
X	return (line_status);
X}
X
X/* Output characters to the transmitter register. */
Xstatic void
Xfas_xproc (fip)
Xregister struct fas_info	*fip;
X{
X	register uint	num_to_output;
X	REGVAR;
X
X	/* proceed only if transmitter is available */
X	if ((fip->device_flags.i & (DF_XMIT_BUSY | DF_XMIT_BREAK
X						| DF_XMIT_LOCKED))
X		|| (fip->flow_flags.i & FF_HWO_STOPPED))
X		goto sched;
X
X	num_to_output = fip->xmit_fifo_size;
X
X	/* handle XON/XOFF input flow control requests */
X	if (fip->flow_flags.i & FF_SW_FC_REQ)
X	{
X#if defined (HAVE_VPIX)
X		fas_first_outb (fip, XMT_DATA_PORT, (fip->flow_flags.i & FF_SWI_STOPPED)
X					? fip->v86_ss.ss_stop
X					: fip->v86_ss.ss_start);
X#else
X		fas_first_outb (fip, XMT_DATA_PORT, (fip->flow_flags.i & FF_SWI_STOPPED)
X					? CSTOP
X					: CSTART);
X#endif
X		fip->tty->t_state &= ~(TTXON | TTXOFF);
X		fip->device_flags.s |= DF_XMIT_BUSY;
X		fip->flow_flags.s &= ~FF_SW_FC_REQ;
X		/* disable guard timeout */
X		if (fip->device_flags.i & DF_GUARD_TIMEOUT)
X		{
X			fip->device_flags.s &= ~DF_GUARD_TIMEOUT;
X			(void) untimeout (fip->timeout_idx);
X		}
X		num_to_output--;
X	}
X
X	/* bail out if output is suspended by XOFF */
X	if (fip->flow_flags.i & FF_SWO_STOPPED)
X		goto sched;
X
X	/* Determine how many chars to put into the transmitter
X	   register.
X	*/
X	if (fip->xmit_ring_cnt < num_to_output)
X		num_to_output = fip->xmit_ring_cnt;
X
X	/* no characters available ? */
X	if (!num_to_output)
X		goto sched;
X
X	/* output characters */
X	fip->xmit_ring_cnt -= num_to_output;
X
X	fas_ctl (fip, XMT_DATA_PORT);
X
X	do
X	{
X		do
X		{
X			(void) outb (XMT_DATA_PORT.addr,
X					*fip->xmit_ring_take_ptr);
X			if (++fip->xmit_ring_take_ptr
X					== &fip->xmit_buffer [XMIT_BUFF_SIZE])
X				break;
X		} while (--num_to_output);
X		if (!num_to_output)
X			break;
X		fip->xmit_ring_take_ptr = &fip->xmit_buffer [0];
X	} while (--num_to_output);
X
X	/* signal that transmitter is busy now */
X	fip->device_flags.s |= DF_XMIT_BUSY;
X	/* disable guard timeout */
X	if (fip->device_flags.i & DF_GUARD_TIMEOUT)
X	{
X		fip->device_flags.s &= ~DF_GUARD_TIMEOUT;
X		(void) untimeout (fip->timeout_idx);
X	}
X
X	/* schedule fas_xxfer () if there are more characters to transfer
X	   into the transmitter ring buffer
X	*/
Xsched:
X	if ((fip->xmit_ring_size > fip->xmit_ring_cnt)
X		&& (fip->tty->t_outq.c_cc || fip->tty->t_tbuf.c_count))
X	{
X		event_sched (fip, EF_DO_XXFER);
X	}
X}
X
X/* Asynchronous event handler. Scheduled by functions that can't do the
X   processing themselves because of execution time restrictions.
X*/
Xstatic void
Xfas_event (dummy)
Xvoid	*dummy;
X{
X	register struct fas_info	*fip;
X	register uint	unit;
X	int	old_level;
X	REGVAR;
X
X	old_level = SPLINT ();
X
X	unit = 0;
X	fip = &fas_info [0];
X
X	/* loop through all fas_info structures */
X	for (;; fip++, unit++)
X	{
X		if (unit >= fas_physical_units)
X			break;	/* all structures done */
X
X		/* process only structures that actually need to
X		   be serviced
X		*/
Xfastloop2:
X		if (!fip->event_flags.i)
X		{
X			/* speed beats beauty */
X			fip++;
X			if (++unit < fas_physical_units)
X				goto fastloop2;
X			break;
X		}
X
X		/* empty event used to force execution of event_sched() */
X		if (fip->event_flags.i & EF_EMPTY_EVENT)
X		{
X			fip->event_flags.s &= ~EF_EMPTY_EVENT;
X		}
X
X		/* check the modem signals */
X		if (fip->event_flags.i & EF_DO_MPROC)
X		{
X			fip->event_flags.s &= ~EF_DO_MPROC;
X			fas_mproc (fip);
X		}
X
X		/* do the break interrupt */
X		if (fip->event_flags.i & EF_DO_BRKINT)
X		{
X			fip->event_flags.s &= ~EF_DO_BRKINT;
X			if (fip->tty->t_state & ISOPEN)
X			{
X				(void) SPLWRK ();
X				(*linesw [fip->tty->t_line].l_input)
X							(fip->tty, L_BREAK);
X				(void) SPLINT ();
X			}
X		}
X
X		/* transfer characters to the UNIX input buffer */
X		if (fip->event_flags.i & EF_DO_RXFER)
X		{
X			fip->event_flags.s &= ~EF_DO_RXFER;
X			if (!(fip->flow_flags.i & FF_RXFER_STOPPED))
X			{
X				(void) SPLWRK ();
X				fas_rxfer (fip);
X				(void) SPLINT ();
X				/* check input buffer high/low water marks */
X				fas_ihlw_check (fip);
X			}
X		}
X
X		/* transfer characters to the output ring buffer */
X		if (fip->event_flags.i & EF_DO_XXFER)
X		{
X			fip->event_flags.s &= ~EF_DO_XXFER;
X			(void) SPLWRK ();
X			fas_xxfer (fip);
X			(void) SPLINT ();
X			fas_hdx_check (fip);
X			/* output characters */
X			fas_xproc (fip);
X		}
X
X#if defined (HAVE_VPIX)
X		/* send pseudorupt to VP/ix */
X		if (fip->event_flags.i & EF_SIGNAL_VPIX)
X		{
X			fip->event_flags.s &= ~EF_SIGNAL_VPIX;
X			if ((fip->iflag & DOSMODE) && fip->v86_proc)
X			{
X				(void) SPLWRK ();
X				(void) v86setint (fip->v86_proc,
X							fip->v86_intmask);
X				(void) SPLINT ();
X			}
X		}
X#endif
X
X		if ((fip->device_flags.i & (DF_DEVICE_OPEN | DF_MSI_ENABLED))
X			== DF_DEVICE_OPEN)
X		{
X#if defined (HAVE_VPIX)
X			if (!(fip->cflag & CLOCAL)
X				|| (fip->flow_flags.i & FF_HWO_HANDSHAKE)
X				|| (fip->iflag & DOSMODE))
X#else
X			if (!(fip->cflag & CLOCAL)
X				|| (fip->flow_flags.i & FF_HWO_HANDSHAKE))
X#endif
X			{
X				/* re-enable modem status interrupts */
X				fip->new_msr &= ~MS_ANY_DELTA;
X				fip->ier |= IE_MODEM_STATUS;
X				fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X				fip->device_flags.s |= DF_MSI_ENABLED;
X			}
X		}
X
X		/* allow pending tty interrupts */
X		(void) SPLWRK ();
X		(void) SPLINT ();
X	}
X
X	event_scheduled = FALSE;
X
X	/* check whether there have been new requests in the mean time */
X	for (unit = 0, fip = &fas_info [0]; unit < fas_physical_units;
X							fip++, unit++)
X		if (fip->event_flags.i)
X		{
X			/* there is at least one new request, so
X			   schedule the next event processing
X			*/
X			event_scheduled = TRUE;
X			(void) timeout (fas_event, (void *) NULL,
X					(EVENT_TIME) * (HZ) / 1000);
X			break;
X		}
X
X	(void) splx (old_level);
X}
X
X#if defined (HAVE_VPIX)
X/* Send port status register to VP/ix */
Xstatic int
Xfas_vpix_sr (fip, token, status)
Xregister struct fas_info	*fip;
Xuint	token;
Xuint	status;
X{
X	if ((fip->recv_ring_cnt <= RECV_BUFF_SIZE - 3)
X		&& ((fip->tty->t_state & (ISOPEN | CARR_ON)) ==
X						(ISOPEN | CARR_ON)))
X	{
X		/* sent the character sequence 0xff, <token>, <status>
X		   to VP/ix
X		*/
X		fip->recv_ring_cnt += 3;
X
X		*fip->recv_ring_put_ptr = 0xff;
X		if (++fip->recv_ring_put_ptr
X				== &fip->recv_buffer [RECV_BUFF_SIZE])
X			fip->recv_ring_put_ptr
X				= &fip->recv_buffer [0];
X		*fip->recv_ring_put_ptr = token;
X		if (++fip->recv_ring_put_ptr
X				== &fip->recv_buffer [RECV_BUFF_SIZE])
X			fip->recv_ring_put_ptr
X				= &fip->recv_buffer [0];
X		*fip->recv_ring_put_ptr = status;
X		if (++fip->recv_ring_put_ptr
X				== &fip->recv_buffer [RECV_BUFF_SIZE])
X			fip->recv_ring_put_ptr
X				= &fip->recv_buffer [0];
X		return (TRUE);
X	}
X	return (FALSE);
X}
X#endif
X
X/* Receiver ring buffer -> UNIX buffer transfer function. */
Xstatic void
Xfas_rxfer (fip)
Xregister struct fas_info	*fip;
X{
X	register struct tty	*ttyp;
X	register int	num_to_xfer;
X	int	num_save;
X	int	old_level;
X
X	ttyp = fip->tty;
X
X	for (;;)
X	{
X		if (!fip->recv_ring_cnt || !ttyp->t_rbuf.c_ptr)
X			break;	/* no characters to transfer */
X
X		/* determine how many characters to transfer */
X		if (ttyp->t_line || (ttyp->t_lflag & ICANON))
X		{
X			num_to_xfer = fip->recv_ring_cnt;
X		}
X		else
X		{
X#if defined (HAVE_VPIX)
X			num_to_xfer = ((fip->iflag & DOSMODE)
X					? MAX_VPIX_FILL
X					: MAX_UNIX_FILL) - ttyp->t_rawq.c_cc;
X#else
X			num_to_xfer = MAX_UNIX_FILL - ttyp->t_rawq.c_cc;
X#endif
X
X			if (num_to_xfer < (int) MIN_READ_CHUNK)
X				break;	/* input buffer full */
X		}
X
X#if defined (HAVE_VPIX)
X		/* wakeup VP/ix */
X		if ((fip->iflag & DOSMODE) && !ttyp->t_rawq.c_cc)
X			event_sched (fip, EF_SIGNAL_VPIX);
X#endif
X
X		/* determine how many characters are in one contiguous block */
X		if (fip->recv_ring_cnt < (uint) num_to_xfer)
X			num_to_xfer = fip->recv_ring_cnt;
X		if (&fip->recv_buffer [RECV_BUFF_SIZE] - fip->recv_ring_take_ptr
X			< (uint) num_to_xfer)
X			num_to_xfer = &fip->recv_buffer [RECV_BUFF_SIZE]
X					- fip->recv_ring_take_ptr;
X		if (ttyp->t_rbuf.c_count < (uint) num_to_xfer)
X			num_to_xfer = ttyp->t_rbuf.c_count;
X
X		num_save = num_to_xfer;
X		ttyp->t_rbuf.c_count -= num_to_xfer;
X
X		/* do the transfer */
X		do
X		{
X			*ttyp->t_rbuf.c_ptr = *fip->recv_ring_take_ptr;
X			ttyp->t_rbuf.c_ptr++;
X			fip->recv_ring_take_ptr++;
X		} while (--num_to_xfer);
X
X		if (fip->recv_ring_take_ptr == &fip->recv_buffer [RECV_BUFF_SIZE])
X			fip->recv_ring_take_ptr = &fip->recv_buffer [0];
X
X		intr_disable ();
X		fip->recv_ring_cnt -= num_save;
X		intr_restore ();
X
X		ttyp->t_rbuf.c_ptr -= ttyp->t_rbuf.c_size
X					- ttyp->t_rbuf.c_count;
X		(*linesw [ttyp->t_line].l_input) (ttyp, L_BUF);
X	}
X}
X
X/* UNIX buffer -> transmitter ring buffer transfer function. */
Xstatic void
Xfas_xxfer (fip)
Xregister struct fas_info	*fip;
X{
X	register struct tty	*ttyp;
X	register int	num_to_xfer;
X	int	num_save;
X	int	old_level;
X
X	ttyp = fip->tty;
X
X	for (;;)
X	{
X		/* Check if tbuf is empty. If it is empty, reset buffer
X		   pointer and counter and get the next chunk of output
X		   characters.
X		*/
X		if (!ttyp->t_tbuf.c_ptr || !ttyp->t_tbuf.c_count)
X		{
X			if (ttyp->t_tbuf.c_ptr)
X				ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size;
X			if (!((*linesw [ttyp->t_line].l_output) (ttyp)
X					& CPRES))
X				break;
X		}
X
X		/* set the maximum character limit */
X		num_to_xfer = fip->xmit_ring_size - fip->xmit_ring_cnt;
X
X		/* Return if transmitter ring buffer is full. */
X		if (num_to_xfer < 1)
X			break;
X
X		/* Determine how many chars to transfer this time. */
X		if (&fip->xmit_buffer [XMIT_BUFF_SIZE] - fip->xmit_ring_put_ptr
X			< (uint) num_to_xfer)
X			num_to_xfer = &fip->xmit_buffer [XMIT_BUFF_SIZE]
X					- fip->xmit_ring_put_ptr;
X		if (ttyp->t_tbuf.c_count < (uint) num_to_xfer)
X			num_to_xfer = ttyp->t_tbuf.c_count;
X
X		num_save = num_to_xfer;
X		ttyp->t_tbuf.c_count -= num_to_xfer;
X		ttyp->t_state |= BUSY;
X
X		/* do the transfer */
X		do
X		{
X			*fip->xmit_ring_put_ptr = *ttyp->t_tbuf.c_ptr;
X			ttyp->t_tbuf.c_ptr++;
X			fip->xmit_ring_put_ptr++;
X		} while (--num_to_xfer);
X
X		if (fip->xmit_ring_put_ptr == &fip->xmit_buffer [XMIT_BUFF_SIZE])
X			fip->xmit_ring_put_ptr = &fip->xmit_buffer [0];
X
X		intr_disable ();
X		fip->xmit_ring_cnt += num_save;
X		intr_restore ();
X	}
X}
X
X/* Input buffer high/low water mark check. */
Xstatic void
Xfas_ihlw_check (fip)
Xregister struct fas_info	*fip;
X{
X	REGVAR;
X
X	if (fip->flow_flags.i & FF_HWI_STOPPED)
X	{
X		/* If input buffer level has dropped below
X		   the low water mark and input was stopped
X		   by hardware handshake, restart input.
X		*/
X		if (fip->recv_ring_cnt < HW_LOW_WATER)
X		{
X			fip->mcr |= fip->flow.m.ic;
X			fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X			fip->flow_flags.s &= ~FF_HWI_STOPPED;
X		}
X	}
X	else
X	{
X		/* If input buffer level has risen above the
X		   high water mark and input is not yet
X		   stopped, stop input by hardware handshake.
X		*/
X		if ((fip->flow_flags.i & FF_HWI_HANDSHAKE)
X			&& (fip->recv_ring_cnt > HW_HIGH_WATER))
X		{
X			fip->mcr &= ~fip->flow.m.ic;
X			fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X			fip->flow_flags.s |= FF_HWI_STOPPED;
X		}
X	}
X
X	if (fip->flow_flags.i & FF_SWI_STOPPED)
X	{
X		/* If input buffer level has dropped below
X		   the low water mark and input was stopped
X		   by XOFF, send XON to restart input.
X		*/
X		if (!(fip->iflag & IXOFF)
X			|| (fip->recv_ring_cnt < SW_LOW_WATER))
X		{
X			fip->flow_flags.s &= ~FF_SWI_STOPPED;
X			fip->flow_flags.s ^= FF_SW_FC_REQ;
X			if (fip->flow_flags.i & FF_SW_FC_REQ)
X			{
X				fip->tty->t_state |= TTXON | BUSY;
X				fas_hdx_check (fip);
X				fas_xproc (fip);
X			}
X			else
X			{
X				fip->tty->t_state &= ~TTXOFF;
X				if (!fip->xmit_ring_cnt
X					&& !(fip->device_flags.i
X						& (DF_XMIT_BUSY
X							| DF_GUARD_TIMEOUT
X							| DF_XMIT_BREAK)))
X				{
X					fip->tty->t_state &= ~BUSY;
X					fas_hdx_check (fip);
X				}
X			}
X		}
X	}
X	else
X	{
X		/* If input buffer level has risen above the
X		   high water mark and input is not yet
X		   stopped, send XOFF to stop input.
X		*/
X		if ((fip->iflag & IXOFF)
X			&& (fip->recv_ring_cnt > SW_HIGH_WATER))
X		{
X			fip->flow_flags.s |= FF_SWI_STOPPED;
X			fip->flow_flags.s ^= FF_SW_FC_REQ;
X			if (fip->flow_flags.i & FF_SW_FC_REQ)
X			{
X				fip->tty->t_state |= TTXOFF | BUSY;
X				fas_hdx_check (fip);
X				fas_xproc (fip);
X			}
X			else
X			{
X				fip->tty->t_state &= ~TTXON;
X				if (!fip->xmit_ring_cnt
X					&& !(fip->device_flags.i
X						& (DF_XMIT_BUSY
X							| DF_GUARD_TIMEOUT
X							| DF_XMIT_BREAK)))
X				{
X					fip->tty->t_state &= ~BUSY;
X					fas_hdx_check (fip);
X				}
X			}
X		}
X	}
X}
X
X/* Half-duplex hardware flow control check. */
Xstatic void
Xfas_hdx_check (fip)
Xregister struct fas_info	*fip;
X{
X	REGVAR;
X
X	/* don't interfere with hardware input handshake */
X	if (fip->flow_flags.i & FF_HWI_HANDSHAKE)
X		return;
X
X#if defined (HAVE_VPIX)
X	/* don't touch the mcr if we are in dos mode and hdx hardware
X	   handshake is disabled (dos handles the handshake line(s)
X	   on its own in this mode)
X	*/
X	if ((fip->iflag & DOSMODE) && !(fip->flow_flags.i & FF_HDX_HANDSHAKE))
X		return;
X#endif
X	if (fip->flow_flags.i & FF_HDX_STARTED)
X	{
X		/* If output buffer is empty signal the connected
X		   device that all output is done.
X		*/
X		if ((fip->flow_flags.i & FF_HDX_HANDSHAKE)
X			&& !(fip->tty->t_state & BUSY))
X		{
X			fip->mcr &= ~fip->flow.m.hc;
X			fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X			fip->flow_flags.s &= ~FF_HDX_STARTED;
X		}
X	}
X	else
X	{
X		/* If the output ring buffer contains characters
X		   and was previously empty signal the connected
X		   device that output is resumed.
X		*/
X		if (!(fip->flow_flags.i & FF_HDX_HANDSHAKE)
X			|| (fip->tty->t_state & BUSY))
X		{
X			fip->mcr |= fip->flow.m.hc;
X			fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X			fip->flow_flags.s |= FF_HDX_STARTED;
X		}
X	}
X}
X
X/* Handle hangup after last close */
Xstatic void
Xfas_hangup (fip)
Xregister struct fas_info	*fip;
X{
X	int	old_level;
X	REGVAR;
X
X	old_level = SPLINT ();
X
X	if (fip->device_flags.i & DF_DO_HANGUP)
X	{
X		/* do the hangup */
X		fip->mcr &= ~(fip->modem.m.ei
X				| fip->modem.m.eo);
X		fip->mcr |= fip->modem.m.di;
X		fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X		fip->device_flags.s &= ~(DF_MODEM_ENABLED | DF_DO_HANGUP);
X		(void) timeout (fas_hangup, fip, (HANGUP_TIME) * (HZ) / 1000);
X	}
X	else
X	{
X		/* If there was a waiting getty open on this
X		   port, reopen the physical device.
X		*/
X		if (fip->o_state & OS_WAIT_OPEN)
X		{
X			fas_open_device (fip);
X			fas_param (fip, HARD_INIT);	/* set up port regs */
X		}
X		release_device_lock (fip);
X	}
X	(void) splx (old_level);
X}
X
X/* main timeout function */
Xstatic void
Xfas_timeout (fip)
Xregister struct fas_info	*fip;
X{
X	int	old_level;
X	REGVAR;
X
X	old_level = SPLINT ();
X
X	/* handle break request */
X	if (fip->device_flags.i & DF_DO_BREAK)
X	{
X		/* set up break request flags */
X		fip->lcr |= LC_SET_BREAK_LEVEL;
X		fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X		fip->device_flags.s &= ~(DF_DO_BREAK | DF_GUARD_TIMEOUT);
X		(void) timeout (fas_timeout, fip, (BREAK_TIME) * (HZ) / 1000);
X		(void) splx (old_level);
X		return;
X	}
X
X	/* reset break state */
X	if ((fip->device_flags.i & DF_XMIT_BREAK)
X		&& (fip->lcr & LC_SET_BREAK_LEVEL))
X	{
X		fip->lcr &= ~LC_SET_BREAK_LEVEL;
X		fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X		fip->device_flags.s |= DF_GUARD_TIMEOUT;
X		fip->timeout_idx = timeout (fas_timeout, fip,
X					fas_ctimes [fip->cflag & CBAUD]);
X		(void) splx (old_level);
X		return;
X	}
X
X	fip->device_flags.s &= ~(DF_GUARD_TIMEOUT | DF_XMIT_BREAK);
X
X	if (!fip->xmit_ring_cnt && !(fip->device_flags.i & DF_XMIT_BUSY))
X	{
X		fip->tty->t_state &= ~BUSY;
X		fas_hdx_check (fip);
X	}
X
X	event_sched (fip, EF_DO_XXFER);
X
X	(void) wakeup ((caddr_t) &(fip)->device_flags.i);
X	(void) splx (old_level);
X}
X
X/* Several functions for flow control, character output and special event
X   requests and handling.
X*/
Xstatic void
Xfas_cmd (fip, ttyp, arg2)
Xregister struct fas_info	*fip;
Xregister struct tty	*ttyp;
Xint	arg2;
X{
X	REGVAR;
X
X	switch (arg2)
X	{
X	case T_TIME:	/* timeout */
X		ttyp->t_state &= ~TIMEOUT;
X		goto start_output;
X
X	case T_OUTPUT:	/* output characters to the transmitter */
X		if (fip->xmit_ring_size > fip->xmit_ring_cnt)
X		{
Xstart_output:
X			event_sched (fip, EF_DO_XXFER);
X		}
X		break;
X
X	case T_SUSPEND:	/* suspend character output */
X		fip->flow_flags.s |= FF_SWO_STOPPED;
X		ttyp->t_state |= TTSTOP;
X		break;
X
X	case T_RESUME:	/* restart character output */
X		fip->flow_flags.s &= ~FF_SWO_STOPPED;
X		ttyp->t_state &= ~TTSTOP;
X		fas_xproc (fip);
X		break;
X
X	case T_BLOCK:	/* stop character input, request XOFF */
X		ttyp->t_state |= TBLOCK;
X		break;	/* note: we do our own XON/XOFF */
X
X	case T_UNBLOCK:	/* restart character input, request XON */
X		ttyp->t_state &= ~TBLOCK;
X		break;	/* note: we do our own XON/XOFF */
X
X	case T_RFLUSH:	/* flush input buffers and restart input */
X		if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X			fas_first_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD
X						| NS_FIFO_CLR_RECV);
X		else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X		{
X			fas_first_outb (fip, I_BANK_PORT, I_BANK_1);
X			fas_outb (fip, I_RCM_PORT, I_FIFO_CLR_RECV);
X			fas_outb (fip, I_BANK_PORT, I_BANK_0);
X		}
X
X		fip->recv_ring_take_ptr = fip->recv_ring_put_ptr;
X		fip->recv_ring_cnt = 0;
X		ttyp->t_state &= ~TBLOCK;
X
X		fas_ihlw_check (fip);
X		break;
X
X	case T_WFLUSH:	/* flush output buffer and restart output */
X		if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X			fas_first_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD
X						| NS_FIFO_CLR_XMIT);
X		else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X		{
X			fas_first_outb (fip, I_BANK_PORT, I_BANK_1);
X			fas_outb (fip, I_TCM_PORT, I_FIFO_CLR_XMIT);
X			fas_outb (fip, I_BANK_PORT, I_BANK_0);
X		}
X
X		fip->xmit_ring_take_ptr = fip->xmit_ring_put_ptr;
X		fip->xmit_ring_cnt = 0;
X
X		fip->flow_flags.s &= ~FF_SWO_STOPPED;
X		ttyp->t_state &= ~TTSTOP;
X
X		if (ttyp->t_tbuf.c_ptr)
X			ttyp->t_tbuf.c_ptr += ttyp->t_tbuf.c_count;
X		ttyp->t_tbuf.c_count = 0;
X
X		if (!(fip->device_flags.i & (DF_XMIT_BUSY | DF_GUARD_TIMEOUT
X						| DF_XMIT_BREAK)))
X		{
X			ttyp->t_state &= ~BUSY;
X			fas_hdx_check (fip);
X			goto start_output;
X		}
X		break;
X
X	case T_BREAK:	/* do a break on the transmitter line */
X		fip->device_flags.s |= DF_XMIT_BREAK;
X		ttyp->t_state |= BUSY;
X		fas_hdx_check (fip);
X		if (fip->device_flags.i & (DF_XMIT_BUSY | DF_GUARD_TIMEOUT))
X		{
X			fip->device_flags.s |= DF_DO_BREAK;
X		}
X		else
X		{
X			/* set up break request flags */
X			fip->lcr |= LC_SET_BREAK_LEVEL;
X			fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X			(void) timeout (fas_timeout, fip, (BREAK_TIME) * (HZ)
X								/ 1000);
X		}
X		break;
X
X	case T_PARM:	/* set up the port according to the termio structure */
X		fas_param (fip, SOFT_INIT);
X		break;
X
X	case T_SWTCH:	/* handle layer switch request */
X		break;
X	}
X}
X
X/* open device physically */
Xstatic void
Xfas_open_device (fip)
Xregister struct fas_info	*fip;
X{
X	REGVAR;
X
X	/* if already open, set up the mcr register only */
X	if (fip->device_flags.i & DF_DEVICE_OPEN)
X		goto setmcr;
X
X	/* init some variables */
X	fip->device_flags.s &= DF_DEVICE_CONFIGURED | DF_DEVICE_IS_NS16550A
X				| DF_DEVICE_IS_I82510 | DF_DEVICE_LOCKED
X				| DF_CTL_FIRST | DF_CTL_EVERY;
X	fip->flow_flags.s = 0;
X	fip->event_flags.s = 0;
X	fip->cflag = 0;
X	fip->iflag = 0;
X	fip->recv_ring_take_ptr = fip->recv_ring_put_ptr;
X	fip->recv_ring_cnt = 0;
X	fip->xmit_ring_take_ptr = fip->xmit_ring_put_ptr;
X	fip->xmit_ring_cnt = 0;
X
X	/* hook into the interrupt users chain */
X	fip->next_int_user = fas_first_int_user [fip->vec];
X	if (fip->next_int_user)
X		fip->next_int_user->prev_int_user = fip;
X	fas_first_int_user [fip->vec] = fip;
X	fip->prev_int_user = (struct fas_info *) NULL;
X
X	fip->lcr = 0;
X	fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
X
X	/* clear and disable FIFOs */
X	if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X		fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X	else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X	{
X		fas_outb (fip, I_BANK_PORT, I_BANK_1);
X		fas_outb (fip, I_TCM_PORT, I_FIFO_CLR_XMIT);
X		fas_outb (fip, I_RCM_PORT, I_FIFO_CLR_RECV);
X		fas_outb (fip, I_BANK_PORT, I_BANK_2);
X		fas_outb (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD);
X		fas_outb (fip, I_BANK_PORT, I_BANK_0);
X	}
X
X	/* clear interrupts */
X	(void) fas_inb (fip, MDM_STATUS_PORT);
X	(void) fas_inb (fip, RCV_DATA_PORT);
X	(void) fas_inb (fip, RCV_DATA_PORT);
X	(void) fas_inb (fip, LINE_STATUS_PORT);
X	(void) fas_inb (fip, INT_ID_PORT);
X
X	/* enable FIFOs */
X	if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X		fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD);
X	else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X	{
X		fas_outb (fip, I_BANK_PORT, I_BANK_2);
X		fas_outb (fip, I_IDM_PORT, I_FIFO_SETUP_CMD);
X		fas_outb (fip, I_BANK_PORT, I_BANK_0);
X	}
X
X	fip->msr = fip->new_msr = fas_inb (fip, MDM_STATUS_PORT)
X					& (MS_CTS_PRESENT
X						| MS_DSR_PRESENT
X						| MS_DCD_PRESENT);
X
X	fip->ier = IE_INIT_MODE;	/* enable UART interrupts */
X	fas_outb (fip, INT_ENABLE_PORT, fip->ier);
X
Xsetmcr:
X	/* set up modem and flow control lines */
X	fip->mcr &= ~(fip->modem.m.di
X			| fip->modem.m.ei
X			| fip->modem.m.eo
X			| fip->flow.m.ic
X			| fip->flow.m.hc);
X
X	fip->mcr |= (fip->o_state & OS_WAIT_OPEN)
X			? fip->modem.m.ei
X			: fip->modem.m.eo;
X
X	if (fip->o_state & OS_HWI_HANDSHAKE)
X		fip->mcr |= fip->flow.m.ic;
X	else if (!(fip->o_state & OS_HDX_HANDSHAKE))
X	{
X		fip->flow_flags.s |= FF_HDX_STARTED;
X		fip->mcr |= fip->flow.m.hc;
X	}
X
X	fas_outb (fip, MDM_CTL_PORT, fip->mcr);
X
X	fip->device_flags.s |= DF_DEVICE_OPEN | DF_MODEM_ENABLED;
X}
X
X/* close device physically */
Xstatic void
Xfas_close_device (fip)
Xregister struct fas_info	*fip;
X{
X	REGVAR;
X
X	fip->ier = IE_NONE;	/* disable UART interrupts */
X	fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X
X	/* drop flow control lines */
X	fip->mcr &= (fip->o_state & OS_HWI_HANDSHAKE)
X		? ~fip->flow.m.ic
X		: ~fip->flow.m.hc;
X	fas_outb (fip, MDM_CTL_PORT, fip->mcr);
X
X	/* clear and disable FIFOs */
X	if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X		fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X	else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X	{
X		fas_outb (fip, I_BANK_PORT, I_BANK_1);
X		fas_outb (fip, I_TCM_PORT, I_FIFO_CLR_XMIT);
X		fas_outb (fip, I_RCM_PORT, I_FIFO_CLR_RECV);
X		fas_outb (fip, I_BANK_PORT, I_BANK_2);
X		fas_outb (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD);
X		fas_outb (fip, I_BANK_PORT, I_BANK_0);
X	}
X
X	/* reset break level */
X	fip->lcr &= ~LC_SET_BREAK_LEVEL;
X	fas_outb (fip, LINE_CTL_PORT, fip->lcr);
X
X	/* clear some variables */
X	fip->device_flags.s &= ~DF_DEVICE_OPEN;
X	fip->event_flags.s = 0;
X
X	/* unhook from interrupt users chain */
X	if (fip->prev_int_user)
X		fip->prev_int_user->next_int_user = fip->next_int_user;
X	else
X		fas_first_int_user [fip->vec] = fip->next_int_user;
X	if (fip->next_int_user)
X		fip->next_int_user->prev_int_user = fip->prev_int_user;
X
X	if (fip->cflag & HUPCL)
X	{
X		/* request hangup */
X		fip->device_flags.s |= DF_DO_HANGUP;
X		(void) timeout (fas_hangup, fip, (HANGUP_DELAY) * (HZ) / 1000);
X	}
X}
X
X/* compute the port access control value */
Xstatic uint
Xfas_make_ctl_val (fip, unit, num)
Xregister struct fas_info	*fip;
Xuint	unit;
Xuint	num;
X{
X	register uint	mask, val;
X	uint	i;
X
X	if (fip->device_flags.i & DF_CTL_FIRST)
X		return (fas_ctl_val [unit]);
X
X	if (fip->device_flags.i & DF_CTL_EVERY)
X	{
X		for (i = 0, mask = fas_ctl_val [unit],
X				val = fas_ctl_val [unit] << 8; i < 8; i++)
X		{
X			if (mask & 0x100)
X			{
X				if (num & 0x01)
X					val ^= 0x100;
X				num >>= 1;
X			}
X			mask >>= 1;
X			val >>= 1;
X		}
X		return (val);
X	}
X	return (0);
X}
X
X/* test device thoroughly */
Xstatic int
Xfas_test_device (fip)
Xregister struct fas_info	*fip;
X{
X	register unchar	*cptr;
X	int	done;
X	uint	delay_count, i;
X	static uint	lcrval [3] =
X	{
X		LC_WORDLEN_8,
X		LC_WORDLEN_8 | LC_ENABLE_PARITY,
X		LC_WORDLEN_8 | LC_ENABLE_PARITY | LC_EVEN_PARITY
X	};
X	REGVAR;
X
X	/* make sure FIFO is off */
X	fas_first_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X	fas_outb (fip, I_BANK_PORT, I_BANK_2);
X	fas_outb (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD);
X	fas_outb (fip, I_BANK_PORT, I_BANK_0);
X
X	/* set counter divisor */
X	fas_outb (fip, LINE_CTL_PORT, LC_ENABLE_DIVISOR);
X	fas_outb (fip, DIVISOR_LSB_PORT, fas_speeds [B38400]);
X	fas_outb (fip, DIVISOR_MSB_PORT, fas_speeds [B38400] >> 8);
X	fas_outb (fip, LINE_CTL_PORT, 0);
X
X	/* switch to local loopback */
X	fas_outb (fip, MDM_CTL_PORT, MC_SET_LOOPBACK);
X
X	done = 0;
X
X	/* wait until the transmitter register is empty */
X	for (delay_count = 20000;
X		delay_count && (~fas_inb (fip, LINE_STATUS_PORT)
X				& (LS_XMIT_AVAIL | LS_XMIT_COMPLETE));
X		delay_count--)
X		;
X
X	if (!delay_count)
X		done = 1;
X
X	if (!done)
X	{
X		/* clear flags */
X		(void) fas_inb (fip, RCV_DATA_PORT);
X		(void) fas_inb (fip, RCV_DATA_PORT);
X		(void) fas_inb (fip, LINE_STATUS_PORT);
X
X		/* make sure there are no more characters in the
X		   receiver register
X		*/
X		for (delay_count = 20000;
X			delay_count && !(fas_inb (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL);
X			delay_count--)
X			;
X
X		if (delay_count)
X			(void) fas_inb (fip, RCV_DATA_PORT);
X
X		/* test pattern */
X		cptr = (unchar *) "\
X\377\125\252\045\244\0\
X\377\125\252\045\244\0\
X\377\125\252\045\244\0\
X\377\125\252\045\244\0\
X\377\125\252\045\244\0\0";
X
X		do
X		{
X			for (i = 0; i < 3; i++)
X			{
X				/* test transmitter and receiver
X				   with different line settings
X				*/
X				fas_outb (fip, LINE_CTL_PORT, lcrval [i]);
X
X				/* wait until the transmitter register
X				   is empty
X				*/
X				for (delay_count = 20000;
X					delay_count && (~fas_inb (fip, LINE_STATUS_PORT)
X							& (LS_XMIT_AVAIL
X							  | LS_XMIT_COMPLETE));
X					delay_count--)
X					;
X
X				if (!delay_count)
X				{
X					done = 2;
X					break;
X				}
X
X				/* send test pattern */
X				fas_outb (fip, XMT_DATA_PORT, *cptr);
X
X				/* wait until the test pattern is received */
X				for (delay_count = 20000;
X					delay_count && ((fas_inb (fip, LINE_STATUS_PORT)
X								& LS_RCV_INT)
X							!= LS_RCV_AVAIL);
X					delay_count--)
X					;
X
X				if (!delay_count)
X				{
X					done = 3;
X					break;
X				}
X
X				/* check test pattern */
X				if (fas_inb (fip, RCV_DATA_PORT) != *cptr)
X				{
X					done = 4;
X					break;
X				}
X			}
X
X			if (done)
X				break;
X		} while (*((ushort *) (cptr++)));
X	}
X
X	if (!done)
X	{
X		/* wait until the transmitter register is empty */
X		for (delay_count = 20000;
X			delay_count && (~fas_inb (fip, LINE_STATUS_PORT)
X					& (LS_XMIT_AVAIL | LS_XMIT_COMPLETE));
X			delay_count--)
X			;
X
X		if (!delay_count)
X			done = 5;
X	}
X
X	if (!done)
X	{
X		/* test pattern */
X		cptr = (unchar *) "\
X\005\142\012\237\006\130\011\257\017\361\0\017\
X\005\142\012\237\006\130\011\257\017\361\0\017\
X\005\142\012\237\006\130\011\257\017\361\0\017\
X\005\142\012\237\006\130\011\257\017\361\0\017\
X\005\142\012\237\006\130\011\257\017\361\0\017\0\0";
X
X		/* clear delta bits */
X		(void) fas_inb (fip, MDM_STATUS_PORT);
X
X		for (; *((ushort *) cptr); cptr += 2)
X		{
X			/* test modem control and status lines */
X			fas_outb (fip, MDM_CTL_PORT, *cptr | MC_SET_LOOPBACK);
X			if (fas_inb (fip, MDM_STATUS_PORT) != *(cptr + 1))
X			{
X				done = 6;
X				break;
X			}
X		}
X	}
X
X	/* switch back to normal operation */
X	fas_outb (fip, MDM_CTL_PORT, 0);
X
X	return (done);
X}
X
X#if defined (NEED_PUT_GETCHAR)
X
Xint
Xasyputchar (arg1)
Xunchar	arg1;
X{
X	register struct	fas_info	*fip;
X	REGVAR;
X
X	if (!fas_is_initted)
X		(void) fasinit ();
X
X	fip = &fas_info [0];
X	if (fip->device_flags.i & DF_DEVICE_CONFIGURED)
X	{
X		fas_ctl (fip, LINE_STATUS_PORT);
X		while (!(inb (LINE_STATUS_PORT.addr) & LS_XMIT_AVAIL))
X			;
X		fas_outb (fip, XMT_DATA_PORT, arg1);
X		if (arg1 == 10)
X			(void) asyputchar (13);
X	}
X	return (0);
X}
X
Xint
Xasygetchar ()
X{
X	register struct	fas_info	*fip;
X	REGVAR;
X
X	if (!fas_is_initted)
X		(void) fasinit ();
X
X	fip = &fas_info [0];
X	if ((fip->device_flags.i & DF_DEVICE_CONFIGURED)
X		&& (fas_first_inb (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL))
X		return (fas_inb (fip, RCV_DATA_PORT));
X	else
X		return (-1);
X}
X#endif
X
X#if defined (NEED_INIT8250)
X
X/* reset the requested port to be used directly by a DOS process */
Xint
Xinit8250 (port, ier)
Xushort	port, ier;	/* ier not used in this stub */
X{
X	register struct fas_info	*fip;
X	register uint	physical_unit;
X	int	old_level;
X	REGVAR;
X
X	/* See if the port address matches a port that is used by
X	   the fas driver.
X	*/
X	for (physical_unit = 0; physical_unit < fas_physical_units;
X			physical_unit++)
X		if (port == (ushort) (fas_port [physical_unit]))
X			break;
X
X	if (physical_unit >= fas_physical_units)
X		return (-1);	/* port didn't match */
X
X	fip = fas_info_ptr [physical_unit];
X
X	old_level = SPLINT ();
X
X	fip->ier = IE_NONE;
X	fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X
X	fip->mcr &= ~(fip->flow.m.ic | fip->flow.m.hc);
X	fas_outb (fip, MDM_CTL_PORT, fip->mcr);
X
X	if (fip->device_flags.i & DF_DEVICE_IS_NS16550A)
X		fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X	else if (fip->device_flags.i & DF_DEVICE_IS_I82510)
X	{
X		fas_outb (fip, I_BANK_PORT, I_BANK_1);
X		fas_outb (fip, I_TCM_PORT, I_FIFO_CLR_XMIT);
X		fas_outb (fip, I_RCM_PORT, I_FIFO_CLR_RECV);
X		fas_outb (fip, I_BANK_PORT, I_BANK_2);
X		fas_outb (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD);
X		fas_outb (fip, I_BANK_PORT, I_BANK_0);
X	}
X
X	(void) fas_inb (fip, MDM_STATUS_PORT);
X	(void) fas_inb (fip, RCV_DATA_PORT);
X	(void) fas_inb (fip, RCV_DATA_PORT);
X	(void) fas_inb (fip, LINE_STATUS_PORT);
X	(void) fas_inb (fip, INT_ID_PORT);
X	(void) splx (old_level);
X	return (0);
X}
X#endif
SHAR_EOF
echo 'File fas.c is complete' &&
true || echo 'restore of fas.c failed'
rm -f _shar_wnt_.tmp
fi
# ============= fas.h ==============
if test -f 'fas.h' -a X"$1" != X"-c"; then
	echo 'x - skipping fas.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting fas.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'fas.h' &&
X/* This file contains various defines for the FAS async driver.
X   If you change anything here you have to recompile the driver module.
X*/
X
X#if !defined (M_I286)
X#ident	"@(#)fas.h	2.09"
X#endif
X
X/* Uncomment the following line if you need asyputchar and asygetchar.
X   This is only required if you link the kernel without the original
X   asy driver and these functions aren't provided by any other kernel
X   module.
X*/
X/* #define NEED_PUT_GETCHAR	/* */
X
X/* Uncomment the following line if you have VP/ix support in the
X   kernel.
X*/
X/* #define HAVE_VPIX	/* */
X
X/* Uncomment the following line if you need init8250. DosMerge needs
X   this function, but only if you link the kernel without the original
X   asy driver.
X*/
X/* #define NEED_INIT8250	/* */
X
X#if defined (VPIX)
X#undef VPIX
X#endif
X
X#if defined (HAVE_VPIX)
X#define VPIX
X#endif
X
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/buf.h>
X#include <sys/dir.h>
X#if defined (XENIX)
X#include <sys/page.h>
X#include <sys/seg.h>
X#endif
X#include <sys/user.h>
X#include <sys/errno.h>
X#include <sys/tty.h>
X#include <sys/conf.h>
X#include <sys/sysinfo.h>
X#include <sys/file.h>
X#if !defined (XENIX)
X#include <sys/termio.h>
X#endif
X#include <sys/ioctl.h>
X#include <macros.h>
X#if defined (HAVE_VPIX)
X#if !defined (XENIX)
X#include <sys/tss.h>
X#include <sys/immu.h>
X#include <sys/region.h>
X#endif
X#include <sys/proc.h>
X#include <sys/v86.h>
X#endif
X
X#if defined (XENIX)
Xtypedef unsigned char	unchar;
Xtypedef unsigned long	ulong;
X/*
X**	Union for use by all device handler ioctl routines.
X*/
Xunion ioctl_arg {
X	struct termio	*stparg;	/* ptr to termio struct */
X	char		*cparg;		/* ptr to character */
X	char		carg;		/* character */
X	int		*iparg;		/* ptr to integer */
X	int		iarg;		/* integer */
X	long            *lparg;         /* ptr to long */
X	long            larg;           /* long */
X};
X#endif
X
X#if defined (TRUE)
X#undef TRUE
X#endif
X#define	TRUE	(1)
X
X#if defined (FALSE)
X#undef FALSE
X#endif
X#define FALSE	(0)
X
X/* Initial line control register.  Value will only be meaningful for
X   asyputchar and asygetchar and they are only meaningful if
X   NEED_PUT_GETCHAR is defined.
X*/
X#define	INITIAL_LINE_CONTROL	LC_WORDLEN_8
X
X/* Initial baud rate.  Value will only be meaningful for
X   asyputchar and asygetchar and they are only meaningful if
X   NEED_PUT_GETCHAR is defined.
X*/
X#define INITIAL_BAUD_RATE	(BAUD_BASE/9600)
X
X/* Initial modem control register.  This should probably not have to
X   be touched.  It is here because some terminals used as the console
X   require one or more of the modem signals set. It is only meaningful
X   for asyputchar and asygetchar and they are only meaningful if
X   NEED_PUT_GETCHAR is defined.
X*/
X#define INITIAL_MDM_CONTROL	0
X
X/****************************************************/
X/* Nothing past this line should have to be changed */
X/****************************************************/
X
X#define NUM_INT_VECTORS	32	/* number of possible int vectors, but
X				   only the first eight are normally used
X				*/
X
X#define MAX_UNITS	16	/* we will only use that many units */
X
X/* Miscellaneous Constants */
X
X#define BAUD_BASE	(1843200 / 16)	/* 115200 bps */
X#define HANGUP_DELAY	500		/* in milli-seconds */
X#define HANGUP_TIME	1000		/* in milli-seconds */
X#define BREAK_TIME	250		/* in milli-seconds */
X#define EVENT_TIME	20		/* in milli-seconds */
X#if defined (M_I286)
X#define	RECV_BUFF_SIZE	1000		/* receiver ring buffer size (MAX) */
X#define SW_LOW_WATER	500	/* 50% MAX	sw flow control */
X#define SW_HIGH_WATER	800	/* 80% MAX	 trigger levels */
X#define HW_LOW_WATER	700	/* MAX - 300	hw flow control */
X#define HW_HIGH_WATER	900	/* MAX - 100	 trigger levels */
X#define XMIT_BUFF_SIZE	500		/* transmitter ring buffer size */
X#else
X#define	RECV_BUFF_SIZE	5000		/* receiver ring buffer size (MAX) */
X#define SW_LOW_WATER	2500	/* 50% MAX	sw flow control */
X#define SW_HIGH_WATER	4000	/* 80% MAX	 trigger levels */
X#define HW_LOW_WATER	4200	/* MAX - 800	hw flow control */
X#define HW_HIGH_WATER	4700	/* MAX - 300	 trigger levels */
X#define XMIT_BUFF_SIZE	2500		/* transmitter ring buffer size */
X#endif
X#define MAX_UNIX_FILL	(TTYHOG)	/* read buffer max UNIX fill level */
X#define MAX_VPIX_FILL	64		/* read buffer max VP/ix fill level */
X#define MIN_READ_CHUNK	32		/* must be <= MAX_????_FILL/2 */
X#define READ_PORT	0x0100		/* read command for fas_init_seq */
X#define NO_FIFO		0x10000		/* force FIFOs off */
X#define SOFT_INIT	0		/* init registers if cflag changed */
X#define HARD_INIT	1		/* init registers w/o checking cflag */
X#if defined (XENIX)
X#define SPLWRK		spl5		/* SPL for character processing */
X#define SPLINT		spl7		/* SPL to disable FAS interrupts */
SHAR_EOF
true || echo 'restore of fas.h failed'
fi
echo 'End of fas209 part 3'
echo 'File fas.h is continued in part 4'
echo 4 > _shar_seq_.tmp
exit 0
-- 
Uwe Doering  |  INET : gemini at geminix.in-berlin.de
Berlin       |----------------------------------------------------------------
Germany      |  UUCP : ...!unido!fub!geminix.in-berlin.de!gemini



More information about the Comp.unix.sysv386 mailing list