[comp.unix.microport] Replacement async driver with 16550 support

jjm@jjmhome.UUCP (Jim Murray) (05/07/89)

     This is a replacement async driver for 386 and 286 based unix systems
     that adds several features that are not supported by vendors drivers.
        1.  It supports the 16550 uart chips in full fifo mode.
        2.  It supports modem sharing for input and output.
            Microport almost supported this feature but none
            of the other vendors did.
        3.  It supports hardware flow control.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README asy.c asy.h asy_conf-c1-2 asy_conf-c1-2h
#   asy_conf-mux4 asy_conf-mux4h config-c1-2 config-mux4 makefile.v386
#   makefile.vat patchlevel.h
# Wrapped by jjm@jjmplay on Sat May  6 23:26:26 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(12194 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XWhat is this package:
X
X     This is a replacement async driver for 386 and 286 based unix systems
X     that adds several features that are not supported by vendors drivers.
X        1.  It supports the 16550 uart chips in full fifo mode.
X        2.  It supports modem sharing for input and output.
X            Microport almost supported this feature but none
X            of the other vendors did.
X        3.  It supports hardware flow control.
X
X
X     This started out as a replacement driver for my home system jjmhome
X     to allow me to take advantage of the new 16550 uart chips.  As I was
X     working on it I discovered that the current driver for system V/386
X     had a lot of problems with it.  I think that I have fixed most of
X     these and at least made the behavior consistent.  Once this driver
X     got out into beta test people wanted to try it on other systems and
X     with the help of too many people to mention I determined that this
X     driver will work on most of the 386 systems,  and microport sys V/AT.
X     This driver is slower than the SYS V/AT when used with the standard
X     uarts - so I only recommend it for AT machines when when the 16550
X     uart is installed.
X
X------------------------------------------------------------------------
X     
XA little about what it does:
X
X     This driver supports shared line usage by having two logical
X     devices sharing one physical line.  To those familiar with
X     Microport this is very similar.  For the other readers a
X     brief description follows.  For each line there are two
X     names.  For example for the first line the names are tty00
X     (minor device 0) and ttyM00 (minor device 128).  The tty00
X     is used for cu, kermit, and other programs that want to dial
X     out.  It ignores the modem signals and just goes to it.  The
X     ttyM00 line is strictly for getty.  When getty calls open on
X     ttyM00 the driver hangs the open until the modem asserts DCD
X     and then lets the open complete.  If cu opens tty00 while
X     getty is waiting for the open to complete the device is
X     given to cu and the getty open must wait for cu to finish
X     and then will again wait for DCD.  If cu tries to open the
X     tty00 line while getty has ttyM00 open cu will get an error.
X     If getty tries to open ttyM00 while cu has tty00 open the
X     getty open will just hang and wait for cu to close the line
X     and then wait for DCD.  To put it simply you should put up a
X     getty on ttyM00 with a -t 60 and use tty00 for cu and
X     uucico.
X
X     The modem devices ttyMxx is the minor device of ttyxx plus
X     128.  See the makefile for device names.
X
X------------------------------------------------------------------------
X
XA little about what it supports:
X
X     The driver supports and has been tested on many async cards
X     and mux boards.  It supports most combinations of shared
X     interrupts.  The current driver supports 16450, 16550 and
X     um82450.  It is also reported to work on the 8250B.  I
X     suspect that it will not work on some of the earlier 8250 and
X     8250A parts, due to various bugs and speed problems in these
X     early parts.  Since these parts have no place in an AT or other
X     high performance systems I did nothing to try to support them.
X     
X     Take a look at the various samples of asy_conf-xxxx for details
X     of how to set up for various devices.
X
X------------------------------------------------------------------------
X
XWhats in this package:
X     README         This file.
X
X     asy.h          The header file for the driver.
X
X     asy.c          The driver itself.
X
X     asy_conf-xxxxx These are samples of what asy_conf.h must look
X                    like.  You can either copy one of these to
X                    asy_conf.h use it as a template to create your
X                    own asy_conf.h.
X
X          asy_conf-c1-2  For com1 and com2.  Equivalent to the standard
X                         driver supplied by uport.
X
X          asy_conf-c1-2h For com1 and com2.  Equivalent to the standard
X                         driver supplied by uport but with hardware flow
X                         control turned on.
X
X          asy_conf-mux4  For the MU-440 four line mux board.
X
X          asy_conf-mux4h For the MU-440 four line mux board with
X                         hardware flow control truned on.
X
X     config-xxxxx   This is for SYS V/386 only.  You should pick the one
X                    that matches your configuration and copy it to config.
X
X          config-c1-2    For com1 and com2.  Equivalent to the standard
X                         driver supplied by uport.
X
X          config-mux4    For the MU-440 four line mux board.
X
X     makefile.v386  a makefile for SYS V/386 systems.  This is generic
X                    and should work for all configurations of lines
X                    and interrupts.
X
X     makefile.vat   a makefile for SYS V/AT systems.  I do not have
X                    SYS V/AT so this file was supplied to me by one
X                    of my early beta test sites.  It contains specific
X                    configuration information for 2 lines using int
X                    4 and 3 and devices tty0 tty1 ttyM0 and ttyM0.
X                    This will have to be edited for other combinations
X                    of lines and devices.
X
X     patchlevel.h   Just a reference file for future updates.
X                    
X------------------------------------------------------------------------
X
XWhat you will need to use this package:
X
X     You will need a one of the above mentioned systems with the
X     link kit and the software development package.
X
X------------------------------------------------------------------------
X
X
XRelease History:
X
X     beta.00 Feb 10, 1989
X
X          Initial beta release.
X
X     ------------------------------------------------------------
X
X     beta.01 Feb 14, 1989
X
X     New Features:
X          Added support for the 16550 uart fifo registers.
X
X     ------------------------------------------------------------
X
X     beta.02   Feb 22, 1989
X
X     New Features:
X          Added support for Microport SYS/V (286 version of unix).
X
X     Bug Fixes:
X          Fixed bug in asymintr that caused hangup on non modem
X          lines when any modem interrupt came in.
X
X     ------------------------------------------------------------
X
X     beta.03 Feb 23, 1989
X
X     New Features:
X
X          NONE
X
X     Bug Fixes:
X
X          Changed modem interrupt code to not look at the delta
X          bit on the uart but to actually look at the DCD bit
X          directly.  I believe there is a problem in some of the
X          older versions of the 8550 chip that forgets to set this
X          bit sometimes.  The 16450 and 16550 chips do not suffer
X          this problem.
X     
X     ------------------------------------------------------------
X
X     beta.04 Feb 25, 1989
X     beta.05 Mar 02, 1989
X
X          These were two experimental changes of little interest
X          to most people.  Both changes were backed out.  These
X          two versions were not generally released.
X
X     ------------------------------------------------------------
X
X     beta.06   Fri Mar 10 21:04:23 EST 1989
X
X     New Features this release.
X     
X          First.  With the help of the Telebit support people I
X          have been able to solve the problem with the TB+ not
X          resetting the port speed when a dialin hangs up.  The
X          problem is actually in the TB+ but fixable in the
X          driver.  The symptoms of the problem are that when a
X          person calls in at low speed and hangs up the port speed
X          is not reset to the firmware defaults.  Telebit informs
X          me that this is a bug in the firmware that was
X          discovered late in the production cycle.  The problem is
X          that the modem only resets on the on to off transition
X          of dtr and dtr is ignored while the modem is hanging up.
X          What happens is that carrier is dropped, the modem
X          starts to hang up and drops dcd.  The driver then turns
X          around and drops dtr.  The modem is still in the process
X          of hanging up at this time and misses the transition.
X          The fix is to delay 100msec after the dcd interrupt
X          before dropping dtr.  This has fixed the problem.
X          Telebit also informed me that it was only necessary to
X          drop dtr for 100msec so I have done that.  There are two
X          new parameters HANGUP_DELAY which is the delay time and
X          HANGUP_TIME which is the hangup time.  I suggest that
X          you leave the HANGUP_DELAY alone.  It sure wont hurt
X          anything on non TB systems and will solve the problem on
X          TB systems.  You may have to make HANGUP_TIME longer for
X          older modems.  I know of no modems that won't hangup
X          with 1 second so this should probably be the longest.
X
X          I have invented a new locking scheme get_device_lock and
X          release_device_lock to cover the hangup time.  This was
X          mostly a code cleanup but it does prevent the hangup
X          time from getting cut short by another process opening
X          the device again.
X
X          I rethought the masking issues again and removed some
X          more of the spltty() calls and made the remaining ones
X          cover much less code.  I am now satisfied that I am
X          masked about as little as possible.
X
X          Bug Fixes:
X
X          NONE
X
X     ------------------------------------------------------------
X
X     beta.07   Wed Apr 26, 1989
X
X     This was a special relase and not of general interest.
X
X     ------------------------------------------------------------
X
X     beta.08 Sat Apr 29, 1989
X
X     New Features this release:
X
X          First.  I have added support for the DFI MU-440 4 line
X          mux board.  This board is supposed to be a clone of the
X          AST 4 line mux board.  The documentation with this board
X          was virtually non existent so I had to guess at the use
X          of the interrupt port.  It can be read and it returns a
X          bitmap representing the uarts that interrupted.  I
X          elected to ignore this for now and just poll the uarts.
X          The reason I did this is that I do not understand the
X          hardware well enough to trust the flags.  I discovered
X          that one must write an 0x80 to the interrupt port to
X          enable interrupts from the card.  I discovered that
X          under some set of conditions this has to be re-enabled
X          at the end of an interrupt so I just do it every time.
X          This seems to work.  If anyone has further documentation
X          on how this card (or the AST card) works I would
X          appreciate hearing from you.
X
X          Second.  The driver now supports hardware flow control.
X          I elected to support this independently from xoff and
X          xon.  The hardware flow control really protects the
X          buffers in the modem and the buffers in the driver.  I
X          believe that this is the correct approach.  I have a bit
X          for each uart in the configuration that enables hw flow.
X
X          Third.  I split out the configuration information into a
X          separate include file so that I could supply several
X          different sample configurations with this package.
X
X
X     Bug Fixes:
X
X          A bug in shared interrupts that could cause loss of
X          interrupts in certain conditions has been fixed.
X
X     ------------------------------------------------------------
X
X     release 1.0 Sat May 6, 1989
X
X          First general release.
X          
X---------------------------------------------------------------------
X
XOutstand issues and crocks.
X
X     The only one at the moment is the lack of better documentation
X     for configuring the driver.
X
X--------------------------------------------------------------------
X
XGENERAL NOTES:
X
X     Now that the driver seems solid I plan to work on performance
X     issues.
X
X---
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
END_OF_FILE
if test 12194 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'asy.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy.c'\"
else
echo shar: Extracting \"'asy.c'\" \(19299 characters\)
sed "s/^X//" >'asy.c' <<'END_OF_FILE'
X/* Async driver for 386 and AT versions of system V UNIX */
X
X/* Written by
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
X*/
X
X/* RELEASE 1.00 */
X
X#if !defined (__GNUC__) && !defined (iAPX286)
X#include <sys/inline.h>
X#endif
X
X#include "asy.h"
X
X#include "asy_conf.h"
X
X#define NUM_LOGICAL_UNITS	(NUM_PHYSICAL_UNITS * 2)
X
X/* asy_is_initted   Flag to indicate that we have been thur init.
X   This is realy only necessary for systems that use asyputchar
X   and asygetchar but it doesn't hurt to have it anyway.
X */
Xuint	asy_is_initted = 0;
X
X/* the values for the various baud rates */
X
Xushort	asyspeeds [] =
X{	0,			BAUD_BASE/50,
X	BAUD_BASE/75,		BAUD_BASE/110,
X	(2*BAUD_BASE+134)/269,	BAUD_BASE/150,
X	BAUD_BASE/200,		BAUD_BASE/300,
X	BAUD_BASE/600,		BAUD_BASE/1200,
X	BAUD_BASE/1800,		BAUD_BASE/2400,
X	BAUD_BASE/4800,		BAUD_BASE/9600,
X	BAUD_BASE/19200,	BAUD_BASE/38400
X};
X
X/* array of structures to hold all info for a physical minor device */
Xstruct	asy_info	asy_info[NUM_PHYSICAL_UNITS];
X
X/* array of ttys for logical minor devices */
Xstruct	tty		asy_tty[NUM_LOGICAL_UNITS];
X
X/* array of linked lists of asy_info structures for each interrupt vector
X   this is filled in at init time
X */
Xstatic struct asy_info	*asy_vector_users[NUM_INT_VECTORS];
X
Xextern int	ttrstrt ();
X
Xint	asyinit ();
Xint	asyopen ();
Xint	asyclose ();
Xint	asyread ();
Xint	asywrite ();
Xint	asyioctl ();
Xint	asyparam ();
Xint	asyintr ();
Xint	asyxintr ();
Xint	asymintr ();
Xint	asyproc ();
Xstatic	void open_device();
Xstatic	void close_device();
Xstatic	void get_device_lock();
Xstatic	void release_device_lock();
X
X/* asyinit
X   This routine checks for the presense of the devices in the asy_port
X   array and if the device is present tests and initializes it.
X   During the initialization if the device is determined to be a
X   NS16550A chip has_fifo is set and the fifo will be used.
X*/
X
Xint
Xasyinit ()
X{
X	register struct asy_info	*aip;
X	uint	unit;
X	uint	port;
X
X	if (asy_is_initted)
X		return;
X
X	asy_is_initted = TRUE;
X
X	for (unit = 0; unit < NUM_PHYSICAL_UNITS; unit++)
X	{
X		aip = &asy_info[unit];
X		if ((port = asy_port[unit]) != 0)
X		{
X			/* init all of its ports */
X			aip->rec_data_port = port + RCV_DATA_OFFSET;
X			aip->xmt_data_port = port + XMT_DATA_OFFSET;
X			aip->int_ena_port = port + INT_ENABLE_OFFSET;
X			aip->int_id_port = port + INT_ID_OFFSET;
X			aip->fifo_ctrl_port = port + FIFO_CTL_OFFSET;
X			aip->line_ctrl_port = port + LINE_CTL_OFFSET;
X			aip->mdm_ctrl_port = port + MDM_CTL_OFFSET;
X			aip->line_stat_port = port + LINE_STATUS_OFFSET;
X			aip->mdm_stat_port = port + MDM_STATUS_OFFSET;
X			aip->div_lsb_port = port + DIVISOR_LSB_OFFSET;
X			aip->div_msb_port = port + DIVISOR_MSB_OFFSET;
X			aip->recv_ring_put_ptr = aip->recv_buffer;
X			aip->recv_ring_take_ptr = aip->recv_buffer;
X			aip->recv_ring_cnt = 0;
X			aip->hardware_hand_shake = asy_flow[unit];
X
X			aip->ier = 0;
X			outb (INT_ENABLE_PORT, aip->ier);/* disable all ints */
X			if (inb (INT_ENABLE_PORT) != aip->ier)
X				continue;	/* a hardware error */
X
X			aip->mcr = asy_mcb[unit] | (INITIAL_MDM_CONTROL);
X			outb (MDM_CTL_PORT, aip->mcr);
X
X			aip->lcr = INITIAL_LINE_CONTROL;
X			outb (LINE_CTL_PORT, aip->lcr | LC_ENABLE_DIVISOR);
X			outb (DIVISOR_LSB_PORT, INITIAL_BAUD_RATE);
X			outb (DIVISOR_MSB_PORT, (INITIAL_BAUD_RATE) >> 8);
X			outb (LINE_CTL_PORT, aip->lcr);
X
X			outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP);
X			if ((inb (INT_ID_PORT) & II_FIFO_ENABLED) == II_FIFO_ENABLED)
X			{ /* we have here a 16550 type chip */
X				aip->has_fifo = TRUE;
X			}
X			else
X			{
X				aip->has_fifo = FALSE;
X			}
X			/* clear and disable the fifo */
X			outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
X
X			/* clear potential interrupts */
X			inb (LINE_STATUS_PORT);
X			inb (MDM_STATUS_PORT);
X			inb (RCV_DATA_PORT);
X			inb (INT_ID_PORT);
X		/* show that it is present and configured */
X			aip->device_flags = DF_DEVICE_CONFIGURED;
X		/* link in as interrupt user */
X			aip->next_interrupt_user = asy_vector_users[asy_vec[unit]];
X			asy_vector_users[asy_vec[unit]] = aip;
X			if (asy_mux_port [asy_vec[unit]])
X			{
X				outb (asy_mux_port [asy_vec[unit]], 0x80);
X			}
X		}
X	}
X}
X
X/* Open a line */
X
X/* There are a few differneces between this and a normal serial
X   device.
X   1.  For each physical minor device there are two logical minor
X       devices.
X
X           The first device (ttyxx) acts like a normal device with
X	   CLOCAL set.  That is is ignores the state of DCD.
X
X	   The second device ttyM00 (minor device + 128) waits for
X	   dcd.  It will wait for any users of ttyxx to close before
X	   allowing the open to complete.  When this device is open
X	   tty00 can not be opened.
X*/
X
X
Xasyopen (dev, flag)
Xint	dev;
Xint	flag;
X{
X	register struct asy_info	*aip;
X	register struct tty		*ttyp;
X	int	opening_getty_version;
X	int	physical_unit;
X	int	old_level;
X
X	physical_unit = GET_UNIT (dev);
X
X	if (physical_unit >= NUM_PHYSICAL_UNITS)
X	{
X		u.u_error = ENXIO;
X		return;
X	}
X
X	aip = &asy_info[physical_unit];
X
X	if (!(aip->device_flags & DF_DEVICE_CONFIGURED))
X	{
X		u.u_error = ENXIO;
X		return;
X	}
X
X	opening_getty_version = DEV_FOR_GETTY (dev);
X
X	while (opening_getty_version && (aip->o_state & OS_OPEN_FOR_DIALOUT))
X	{
X		sleep ((caddr_t) &aip->o_state, TTIPRI);
X	}
X	
X	if (!opening_getty_version && (aip->o_state & OS_OPEN_FOR_GETTY))
X	{
X		u.u_error = EIO;
X		return;
X	}
X
X	if (opening_getty_version)
X		aip->tty = ttyp = &asy_tty[physical_unit + NUM_PHYSICAL_UNITS];
X	else
X		aip->tty = ttyp = &asy_tty[physical_unit];
X	
X	if (!(ttyp->t_state & (ISOPEN | WOPEN)))
X	{
X		ttinit (ttyp);
X		ttyp->t_proc = asyproc;
X		if (!opening_getty_version)
X			ttyp->t_cflag |= CLOCAL;
X		else
X			ttyp->t_cflag &= ~CLOCAL;
X	}
X
X	get_device_lock (aip);
X	if (!(aip->device_flags & DF_DEVICE_OPEN))
X		open_device(aip, opening_getty_version);
X	release_device_lock (aip);
X
X	old_level = spltty();
X
X	if ((inb (MDM_STATUS_PORT) & MS_DCD_PRESENT)
X	  || (ttyp->t_cflag & CLOCAL)
X	  || !opening_getty_version)
X		ttyp->t_state |= CARR_ON;
X	else
X		ttyp->t_state &= ~CARR_ON;
X
X	if (!(flag & FNDELAY))
X	{
X		while ((ttyp->t_state & CARR_ON) == 0) /* no carrier */
X		{
X			ttyp->t_state |= WOPEN;
X			if (sleep((caddr_t) &ttyp->t_canq, TTIPRI | PCATCH))
X			{
X				ttyp->t_state &= ~WOPEN;
X				if (!(aip->o_state & OS_OPEN_FOR_DIALOUT))
X					close_device (aip);
X				longjmp (u.u_qsav, 1);
X			}
X		}
X	}
X
X	(*linesw [ttyp->t_line].l_open) (ttyp);
X
X	if (opening_getty_version)
X		aip->o_state |= OS_OPEN_FOR_GETTY;
X	else
X		aip->o_state |= OS_OPEN_FOR_DIALOUT;
X
X	splx (old_level);
X}
X
X
Xasyclose (dev)
Xint	dev;
X{
X	register struct asy_info	*aip;
X	register struct tty		*ttyp;
X	int	closing_getty_version;
X	int	physical_unit;
X	int	old_level;
X
X	physical_unit = GET_UNIT (dev);
X
X	closing_getty_version = DEV_FOR_GETTY (dev);
X
X	aip = &asy_info[physical_unit];
X
X	if (closing_getty_version)
X		ttyp = &asy_tty[physical_unit + NUM_PHYSICAL_UNITS];
X	else
X		ttyp = &asy_tty[physical_unit];
X
X	(*linesw [ttyp->t_line].l_close) (ttyp);
X
X	old_level = spltty();
X	get_device_lock(aip);
X	
X	if (closing_getty_version)
X	{
X		ttyp->t_state &= ~WOPEN;	/* not waiting any more */
X		aip->o_state &= ~OS_OPEN_FOR_GETTY;
X		if (!aip->o_state & OS_OPEN_FOR_DIALOUT)
X			close_device (aip);
X	}
X	else
X	{
X		aip->o_state &= ~OS_OPEN_FOR_DIALOUT;
X		/* get the getty version of the tty structure */
X		aip->tty = &asy_tty[physical_unit + NUM_PHYSICAL_UNITS];
X		delay (HANGUP_DELAY);
X		close_device (aip);
X		delay (HANGUP_TIME); /* guarantee hangup */
X		if (aip->tty->t_state & WOPEN)
X			open_device(aip, TRUE);
X		wakeup ((caddr_t) &aip->o_state);
X	}
X	release_device_lock(aip);
X	splx (old_level);
X	return;
X}
X
Xasyread (dev)
Xint	dev;
X{
X	register struct asy_info	*aip;
X	register struct tty		*ttyp;
X
X	aip = &asy_info [GET_UNIT (dev)];
X
X	ttyp = aip->tty;
X
X	if ((aip->h_state & HWISTOP) && ttyp->t_rawq.c_cc < TTXOLO)
X	{
X		aip->mcr |= MC_SET_RTS;
X		outb (MDM_CTL_PORT, aip->mcr);
X		aip->h_state &= ~HWISTOP;
X	}
X			
X	(*linesw [ttyp->t_line].l_read) (ttyp);
X}
X
Xint
Xasywrite (dev)
Xint	dev;
X{
X	register struct tty	*ttyp;
X
X	ttyp = asy_info [GET_UNIT (dev)].tty;
X
X	(*linesw [ttyp->t_line].l_write) (ttyp);
X}
X
Xint
Xasyioctl (dev, cmd, arg3, arg4)
X	int	dev;
X	int	cmd;
X	union ioctl_arg	arg3;
X	int	arg4;
X{
X	register struct asy_info	*aip;
X
X	aip = &asy_info [GET_UNIT (dev)];
X
X	if (ttiocom (aip->tty, cmd, arg3, arg4))
X		asyparam (aip);
X}
X
Xint
Xasyparam (aip)
X	register struct asy_info	*aip;
X{
X	register struct tty	*ttyp;
X	short	divisor;
X	int	old_level;
X
X	old_level = spltty();
X
X	ttyp = aip->tty;
X
X	if ((ttyp->t_cflag & CBAUD) == B0)
X	{
X		aip->mcr &= ~MC_SET_DTR;
X		outb (MDM_CTL_PORT, aip->mcr);
X		splx (old_level);
X		return;
X	}
X
X	switch (ttyp->t_cflag & CSIZE)
X	{
X	default:
X	case CS8:
X		aip->lcr = LC_WORDLEN_8;
X		break;
X
X	case CS5:
X		aip->lcr = LC_WORDLEN_5;
X		break;
X
X	case CS6:
X		aip->lcr = LC_WORDLEN_6;
X		break;
X
X	case CS7:
X		aip->lcr = LC_WORDLEN_7;
X		break;
X	}
X
X	if (ttyp->t_cflag & CSTOPB)
X		aip->lcr |= LC_STOPBITS_LONG;
X
X	if (ttyp->t_cflag & PARENB)
X	{
X		aip->lcr |= LC_ENABLE_PARITY;
X
X		if (! (ttyp->t_cflag & PARODD))
X			aip->lcr |= LC_EVEN_PARITY;
X	}
X	divisor = asyspeeds [ttyp->t_cflag & CBAUD];
X	outb (LINE_CTL_PORT, aip->lcr | LC_ENABLE_DIVISOR);
X	outb (DIVISOR_LSB_PORT, (char) divisor);
X	outb (DIVISOR_MSB_PORT, (char) (divisor >> 8));
X	outb (LINE_CTL_PORT, aip->lcr);
X	splx (old_level);
X}
X
Xint
Xasyintr (vect)
X	int	vect;
X{
X	register struct asy_info	*aip;
X	int	done = FALSE;
X
X#if defined (iAPX286)
X	vect -= 32;
X#endif
X
X	/* I believe that the 8259 is set up for edge trigger therefore
X	   I must loop until I make a complete pass without getting
X	   any uarts that are interrupting
X	 */
X
X	while (!done)
X	{
X		done = TRUE;
X
X		for (aip = asy_vector_users[vect]; aip != NULL;
X				aip = aip->next_interrupt_user)
X		{
X			/* only ones that we expect ints from */
X			while (aip->ier)
X			{
X				unchar	int_id;
X				unchar	line_status;
X
X				int_id = inb (INT_ID_PORT);
X				if (int_id & 0x01)
X					break;
X
X				done = FALSE;	/* not done if we got one */
X				while ((line_status = inb (LINE_STATUS_PORT))
X					 & LS_RCV_INT)
X				{
X					ushort	charac;
X	
X					charac = (line_status & LS_RCV_INT) << 8;
X
X					if (line_status & LS_RCV_AVAIL)
X						charac |= inb (RCV_DATA_PORT);
X
X					if (aip->recv_ring_cnt != RECV_BUFF_SIZE)
X					{
X						*aip->recv_ring_put_ptr++ = charac;
X						aip->recv_ring_cnt++;
X						if (aip->recv_ring_put_ptr
X						 == &aip->recv_buffer[RECV_BUFF_SIZE])
X							aip->recv_ring_put_ptr
X								= &aip->recv_buffer[0];
X					}
X					else
X						aip->overruns++;
X				}
X				if ((line_status & LS_XMIT_AVAIL)
X					&& (aip->tty->t_state & BUSY))
X					asyxintr(aip);
X				if ((int_id & 7) == II_MODEM_STATE)
X					asymintr (aip);
X			}
X			if (aip->recv_ring_cnt)
X			{
X				asyrproc(aip);
X				if ((aip->hardware_hand_shake)
X				 && (aip->tty->t_rawq.c_cc > TTXOHI)
X				 && (!(aip->h_state & HWISTOP)) )
X				{
X					aip->h_state |= HWISTOP;
X					aip->mcr &= ~MC_SET_RTS;
X					outb (MDM_CTL_PORT, aip->mcr);
X				}
X				sysinfo.rcvint++;
X			}
X		}
X	}
X	/* clear the mux interrupt since we are about to scan all
X	   of the ports that share this interrupt vector
X	 */	
X
X	if (asy_mux_port [vect])
X	{
X		outb (asy_mux_port [vect], 0x80);
X	}
X}
X
Xint
Xasyxintr (aip)
X	register struct asy_info	*aip;
X{
X
X	register struct tty	*ttyp;
X
X	ttyp = aip->tty;
X	sysinfo.xmtint++;
X
X	if (aip->h_state & HWOSTOP)
X	{
X		ttyp->t_state &= ~(BUSY);
X	}
X	else if (ttyp->t_state & TTXON)
X	{
X#if STATISTICS
X		aip->tra_buckets[0]++;
X#endif
X		outb (XMT_DATA_PORT, CSTART);
X		ttyp->t_state &= ~TTXON;
X	}
X	else if (ttyp->t_state & TTXOFF) 
X	{
X#if STATISTICS
X		aip->tra_buckets[0]++;
X#endif
X		outb (XMT_DATA_PORT, CSTOP);
X		ttyp->t_state &= ~TTXOFF;
X	}
X	else
X	{
X		ttyp->t_state &= ~(BUSY);
X		asyproc (ttyp, T_OUTPUT);
X	}
X}
X
Xint
Xasymintr (aip)
X	register struct asy_info	*aip;
X{
X	register struct tty	*ttyp;
X	unchar	mdm_state;
X
X	ttyp = aip->tty;
X
X	sysinfo.mdmint++;
X
X	mdm_state = inb (MDM_STATUS_PORT);
X
X#if 0
X	printf ("MDM %x\n", mdm_state);
X#endif
X	
X	if (aip->hardware_hand_shake)
X	{
X		if (mdm_state & MS_CTS_PRESENT)
X		{
X			if (aip->h_state & HWOSTOP)
X			{
X				aip->h_state &= ~HWOSTOP;
X	                        asyproc (ttyp, T_OUTPUT);
X			}
X		}
X		else
X		{
X	                if (! (aip->h_state & HWOSTOP))
X			{
X				aip->h_state |= HWOSTOP;
X			}
X		}
X	}
X
X	if ((ttyp->t_cflag & CLOCAL) || (aip->o_state & OS_OPEN_FOR_DIALOUT))
X		return;
X
X	if (mdm_state & MS_DCD_PRESENT)
X	{
X		ttyp->t_state |= CARR_ON;
X		wakeup (&ttyp->t_canq);
X	}
X	else
X	{
X		if (ttyp->t_state & CARR_ON)
X		{
X			if (ttyp->t_state & ISOPEN)
X			{
X				signal (ttyp->t_pgrp, SIGHUP);
X				ttyflush (ttyp, FREAD | FWRITE);
X			}
X			ttyp->t_state &= ~ CARR_ON;
X		}
X	}
X}
X
Xasyrproc(aip)
X	register struct asy_info	*aip;
X{
X	register struct tty	*ttyp;
X	static char metta[4];
X	int	csize = 0;
X
X	ttyp = aip->tty;
X
X	if (ttyp->t_state & ISOPEN)
X	{
X#if STATISTICS
X		if (aip->recv_ring_cnt <= 16)
X			aip->rec_buckets[aip->recv_ring_cnt]++;
X		else
X			aip->rec_buckets[0]++;
X#endif
X
X		while (aip->recv_ring_cnt)
X		{
X			ushort	value;
X			unchar	status;
X			unchar	rchar;
X			unchar	ichar;
X
X			value = *aip->recv_ring_take_ptr++;
X			if (aip->recv_ring_take_ptr
X					 == &aip->recv_buffer[RECV_BUFF_SIZE])
X				aip->recv_ring_take_ptr = &aip->recv_buffer[0];
X
X			aip->recv_ring_cnt--;
X
X			ichar = rchar = (value & 0xFF);
X			status = (value >> 8);
X
X			if (ttyp->t_iflag & ISTRIP)
X				ichar &= 0x7F;
X
X			if ((status & LS_PARITY_ERROR)
X			  && !(ttyp->t_iflag & INPCK))
X				status &= ~LS_PARITY_ERROR;
X		
X			if (status & (LS_ANY_ERROR | LS_BREAK_DETECTED))
X			{
X				/* maybe this should be
X				  if (status & LS_RCV_AVAIL)
X				*/   
X				if (rchar
X				    && (ttyp->t_iflag & PARMRK)
X				    && !(ttyp->t_iflag & IGNPAR))
X				{
X					metta[csize++] = rchar;
X					metta[csize++] = 0;
X					metta[csize++] = 0xff;
X				}
X				else if (!(ttyp->t_iflag & IGNBRK))
X				{
X					if (ttyp->t_iflag & BRKINT)
X						(*linesw [ttyp->t_line].l_input)
X							 (ttyp, L_BREAK);
X					else if (ttyp->t_iflag & PARMRK)
X					{
X						metta[csize++] = rchar;
X						metta[csize++] = 0;
X						metta[csize++] = 0xff;
X					}
X					else
X						metta [csize++] = ichar;
X				}
X			}
X			else
X			{
X				if (ttyp->t_iflag & IXON)
X				{
X					if (ttyp->t_state & TTSTOP)
X					{
X						if ((ichar == CSTART)
X						 || (ttyp->t_iflag & IXANY))
X						      asyproc (ttyp, T_RESUME);
X					}
X					else
X					{
X						if (ichar == CSTOP)
X						     asyproc (ttyp, T_SUSPEND);
X					}
X					if ((ichar == CSTART)
X					     || (ichar == CSTOP))
X						continue;
X				}
X
X				if ((ichar == 0xff) && (ttyp->t_iflag & PARMRK))
X					metta [csize++] = ichar;
X				
X				metta [csize++] = ichar;
X
X			}
X
X			if (ttyp->t_rbuf.c_ptr == NULL)
X				continue;
X
X			while (csize)
X			{
X				*ttyp->t_rbuf.c_ptr++ = metta [--csize];
X				ttyp->t_rbuf.c_count--;
X				if (ttyp->t_rbuf.c_count == 0)
X				{
X					ttyp->t_rbuf.c_ptr -= ttyp->t_rbuf.c_size;
X					(*linesw [ttyp->t_line].l_input) (ttyp, L_BUF);
X					if (ttyp->t_rbuf.c_ptr == NULL)
X						break;
X				}
X			}
X		}
X		if (ttyp->t_rbuf.c_ptr != NULL)
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	else
X	{
X		aip->recv_ring_take_ptr = aip->recv_ring_put_ptr;
X		aip->recv_ring_cnt = 0;
X	}
X}
X
Xint
Xasyproc (ttyp, arg2)
X	register struct tty	*ttyp;
X
X	int	arg2;
X{
X	register struct asy_info	*aip;
X	int	old_level;
X	int	num_to_output;
X	int	physical_unit;
X
X	physical_unit = ttyp - &asy_tty[0];
X	if (physical_unit >= NUM_PHYSICAL_UNITS)
X		physical_unit -=NUM_PHYSICAL_UNITS;
X
X	aip = &asy_info[physical_unit];
X
X	old_level = spltty();
X
X	switch (arg2)
X	{
X	case T_TIME:
X		ttyp->t_state &= ~ TIMEOUT;
X		aip->lcr &= ~LC_SET_BREAK_LEVEL;
X		outb (LINE_CTL_PORT, aip->lcr);
X		goto start;
X
X	case T_WFLUSH:
X		ttyp->t_tbuf.c_size -= ttyp->t_tbuf.c_count;
X		ttyp->t_tbuf.c_count = 0;
X
X	case T_RESUME:
X		ttyp->t_state &= ~ TTSTOP;
X
X	case T_OUTPUT:
Xstart:
X		if (ttyp->t_state & (TTSTOP | BUSY | TIMEOUT)
X		 || (aip->h_state & HWOSTOP))
X			break;
X
X		if (ttyp->t_state & TTXON)
X		{
X#if STATISTICS
X			aip->tra_buckets[0]++;
X#endif
X			outb (XMT_DATA_PORT, CSTART);
X			ttyp->t_state &= ~TTXON;
X			ttyp->t_state |= (BUSY);
X			break;
X		}
X
X		if (ttyp->t_state & TTXOFF) 
X		{
X#if STATISTICS
X			aip->tra_buckets[0]++;
X#endif
X			outb (XMT_DATA_PORT, CSTOP);
X			ttyp->t_state &= ~TTXOFF;
X			ttyp->t_state |= (BUSY);
X			break;
X		}
X
X		/* check if tbuf is empty */
X		if ((ttyp->t_tbuf.c_ptr == NULL) || (ttyp->t_tbuf.c_count == 0))
X		{
X			if (ttyp->t_tbuf.c_ptr != NULL)
X				ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size;
X			if (! ((*linesw [ttyp->t_line].l_output) (ttyp) & CPRES))
X				break;
X		}
X
X		if (aip->has_fifo)	/* 16550 chip ? */
X			num_to_output = min (ttyp->t_tbuf.c_count,
X						OUTPUT_FIFO_SIZE);
X		else
X			num_to_output = 1;
X
X		ttyp->t_state |= (BUSY);
X#if STATISTICS
X		aip->tra_buckets[num_to_output]++;
X#endif
X		while (num_to_output--)
X		{
X			outb (XMT_DATA_PORT, *ttyp->t_tbuf.c_ptr++);
X			ttyp->t_tbuf.c_count--;
X		}
X		break;
X
X	case T_SUSPEND:
X		ttyp->t_state |= TTSTOP;
X		break;
X
X	case T_BLOCK:
X                ttyp->t_state &= ~TTXON;
X		ttyp->t_state |= TBLOCK;
X		ttyp->t_state |= TTXOFF;
X		goto start;
X
X	case T_RFLUSH:
X		if (! (ttyp->t_state & TBLOCK))
X			break;
X
X	case T_UNBLOCK:
X                ttyp->t_state &= ~ (TTXOFF | TBLOCK);
X		ttyp->t_state |= TTXON;
X		goto start;
X
X	case T_BREAK:
X		aip->lcr |= LC_SET_BREAK_LEVEL;
X		outb (LINE_CTL_PORT, aip->lcr);
X		ttyp->t_state |= TIMEOUT;
X		timeout (ttrstrt, ttyp, HZ / 4);	/* 250 msec	*/
X		break;
X
X	case T_SWTCH:
X		break;
X
X	case T_PARM:
X		asyparam (aip);
X		break;
X	}
X	splx(old_level);
X}
X
Xstatic void
Xget_device_lock(aip)
X	register struct asy_info	*aip;
X{
X	while (aip->device_flags & DF_DEVICE_LOCKED)
X	{
X		sleep((caddr_t) &aip->device_flags, PZERO -1);
X	}
X	aip->device_flags |= DF_DEVICE_LOCKED;
X}
X
Xstatic void
Xrelease_device_lock(aip)
X	register struct asy_info	*aip;
X{
X	aip->device_flags &= ~DF_DEVICE_LOCKED;
X	wakeup (&aip->device_flags);
X}
X
Xvoid
Xopen_device(aip, opening_getty_version)
X	register struct asy_info	*aip;
X	int	opening_getty_version;
X{
X	if (aip->has_fifo)
X	{
X		outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
X		outb (FIFO_CTL_PORT, STANDARD_FIFO_SETUP);
X	}
X	asyparam (aip);
X
X	aip->mcr |= (MC_SET_DTR | MC_SET_RTS);
X	outb (MDM_CTL_PORT, aip->mcr);
X
X	if (opening_getty_version)
X		aip->ier |= IE_GETTY_MODE;
X	else
X		aip->ier = IE_DIALOUT_MODE;
X
X	outb (INT_ENABLE_PORT, aip->ier);
X
X	aip->device_flags |= DF_DEVICE_OPEN;
X}
X
Xvoid
Xclose_device(aip)
X	register struct asy_info	*aip;
X{
X	aip->device_flags &= ~DF_DEVICE_OPEN;
X	aip->ier = 0;	/* disable all ints from uart */
X	aip->mcr &= ~(MC_SET_DTR | MC_SET_RTS);
X	outb (INT_ENABLE_PORT, aip->ier);
X	outb (MDM_CTL_PORT, aip->mcr);
X	if (aip->has_fifo)
X	{
X		outb (FIFO_CTL_PORT, STANDARD_FIFO_CLEAR);
X	}
X	return;
X}
X
X#if defined (NEED_PUT_GETCHAR)
X
Xint
Xasyputchar(arg1)
X	unchar	arg1;
X{
X	register struct	asy_info	*aip;
X
X	if (!asy_is_initted)
X		asyinit();
X
X	aip = &asy_info [0];
X	if (aip->device_flags & DF_DEVICE_CONFIGURED)
X	{
X		while (!(inb (LINE_STATUS_PORT) & LS_XMIT_AVAIL))
X			;
X		outb (XMT_DATA_PORT, arg1);
X		if (arg1 == 10)
X			asyputchar(13);
X	}
X}
X
Xint
Xasygetchar()
X{
X	register struct	asy_info	*aip;
X
X	if (!asy_is_initted)
X		asyinit();
X
X	aip = &asy_info[0];
X	if ((aip->device_flags & DF_DEVICE_CONFIGURED)
X	  && (inb (LINE_STATUS_PORT) & LS_RCV_AVAIL))
X	{
X		return (inb (RCV_DATA_PORT));
X	}
X	else
X	{
X		return (-1);
X	}
X}
X#endif
END_OF_FILE
if test 19299 -ne `wc -c <'asy.c'`; then
    echo shar: \"'asy.c'\" unpacked with wrong size!
fi
# end of 'asy.c'
fi
if test -f 'asy.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy.h'\"
else
echo shar: Extracting \"'asy.h'\" \(7107 characters\)
sed "s/^X//" >'asy.h' <<'END_OF_FILE'
X/* asy.h */
X
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/signal.h>
X#include <sys/buf.h>
X#include <sys/iobuf.h>
X#include <sys/dir.h>
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#include <sys/termio.h>
X#include <sys/ioctl.h>
X
X#if defined (iAPX286)
Xtypedef unsigned char unchar;	/* V/AT does not define unchar in types */
X#define spltty spl7		/* V/AT does not have spltty */
X#endif
X
X/* STATISTICS says collect interrupt counts */
X#define STATISTICS 1
X
X#ifdef NDEBUG
X#define myassert(EX)
X#else
Xextern void printf();
X#define myassert(EX) if (EX) ; else printf("assert %s file = %s line = %d\n","EX", __FILE__, __LINE__)
X#endif
X
X#define	RESET	0
X#define	SET	1
X
X#if !defined (TRUE)
X#define	TRUE	(1)
X#endif
X#if !defined (FALSE)
X#define FALSE	(0)
X#endif
X
X/* The following two defines may have to be changed to fit your
X   local convention for device nodes.  They are defined here for
X   uport makeing the getty device minor device + 128
X*/
X#define GET_UNIT(dev)		((dev) & 0x1f)
X#define DEV_FOR_GETTY(dev)	(((dev) & 0x80) != 0)
X
X/* initial line control register.  Value will only be meaningfull for
X   asyputchar and asygetchar and they are only meaningufll 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 meaningfull for
X   asyputchar and asygetchar and they are only meaningufll 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.  Again this is realy
X   only meaningfull for asyputchar and asygetchar and then are only
X   meaningufll if NEED_PUT_GETCHAR is defined.
X*/
X#define INITIAL_MDM_CONTROL	0
X
X/* Uncomment the following line if you need asyputchar and asygetchar.
X   bell tech needs these.  Uport has them burried in the kd device.
X*/
X
X/* #define NEED_PUT_GETCHAR 1 */
X
X/****************************************************/
X/* Nothing past this line should have to be changed */
X/****************************************************/
X
X#define NUM_INT_VECTORS	16	/* sixteen vectors possible but only
X				   the first eight are normally used
X				*/
X
X/* define the states */
X#define	HWOSTOP	0x01
X#define HWISTOP 0x02
X
X/* define the device status flags */
X
X#define DF_DEVICE_CONFIGURED	0x01	/* device is not configured */
X#define DF_DEVICE_OPEN		0x02	/* physical device is open  */
X#define DF_DEVICE_LOCKED	0x04	/* physical device locked */
X
X/* Description of the NS16550 Asychronous Communications Element	*/
X
X#define RCV_DATA_OFFSET		0
X#define XMT_DATA_OFFSET		0
X#define INT_ENABLE_OFFSET	1
X#define INT_ID_OFFSET		2
X#define FIFO_CTL_OFFSET		2
X#define LINE_CTL_OFFSET		3
X#define MDM_CTL_OFFSET		4
X#define LINE_STATUS_OFFSET	5
X#define MDM_STATUS_OFFSET	6
X#define DIVISOR_LSB_OFFSET	0
X#define DIVISOR_MSB_OFFSET	1
X
X/* Define an easy way to refenence the absolute port addresses */
X
X#define RCV_DATA_PORT		(aip->rec_data_port)
X#define XMT_DATA_PORT		(aip->xmt_data_port)
X#define INT_ENABLE_PORT		(aip->int_ena_port)
X#define INT_ID_PORT		(aip->int_id_port)
X#define FIFO_CTL_PORT		(aip->fifo_ctrl_port)
X#define LINE_CTL_PORT		(aip->line_ctrl_port)
X#define MDM_CTL_PORT		(aip->mdm_ctrl_port)
X#define LINE_STATUS_PORT	(aip->line_stat_port)
X#define MDM_STATUS_PORT		(aip->mdm_stat_port)
X#define DIVISOR_LSB_PORT	(aip->div_lsb_port)
X#define DIVISOR_MSB_PORT	(aip->div_msb_port)
X
X/* Miscellaneous Constants:	*/
X
X#define BAUD_BASE	(1843200/16)	/* 115200 bps	*/
X#define HANGUP_DELAY	((HZ) / 10)	/* 100 msec */
X#define HANGUP_TIME	((HZ) / 10)	/* 100 msec */
X
X/* Modem Status Port		*/
X
X#define MS_CTS_CHANGED		0x01
X#define MS_DSR_CHANGED		0x02
X#define MS_RING_CHANGED		0x04
X#define MS_DCD_CHANGED		0x08
X#define MS_CTS_PRESENT		0x10
X#define MS_DSR_PRESENT		0x20
X#define MS_RING_PRESENT		0x40
X#define MS_DCD_PRESENT		0x80
X
X#define MS_ANY_CHANGE	(MS_CTS_CHANGED | MS_DSR_CHANGED | MS_RING_CHANGED | MS_DCD_CHANGED)
X
X/* interrupt enable port */
X#define	IE_RECV_DATA_AVAILABLE		0x01
X#define	IE_XMIT_HOLDING_BUFFER_EMPTY	0x02
X#define IE_LINE_STATUS			0x04
X#define IE_MODEM_STATUS			0x08
X
X#define IE_DIALOUT_MODE 		0x07
X#define IE_GETTY_MODE			0x0F
X
X/* Interrupt Id Port:		*/
X
X#define II_MODEM_STATE	0x00
X#define II_XMTD_CHAR	0x02
X#define II_RCVD_CHAR	0x04
X#define II_RCV_ERROR	0x06
X#define II_FIFO_TIMEOUT 0x08
X#define II_FIFO_ENABLED	0xC0
X
X/* Line Control Port:		*/
X
X#define	LC_WORDLEN_MASK		0x03
X#define	LC_WORDLEN_5		0x00
X#define	LC_WORDLEN_6		0x01
X#define	LC_WORDLEN_7		0x02
X#define	LC_WORDLEN_8		0x03
X#define LC_STOPBITS_LONG	0x04
X#define LC_ENABLE_PARITY	0x08
X#define LC_EVEN_PARITY		0x10
X#define LC_STICK_PARITY		0x20
X#define LC_SET_BREAK_LEVEL	0x40
X#define LC_ENABLE_DIVISOR	0x80
X
X/* Modem Control Port:		*/
X
X#define MC_SET_DTR		0x01
X#define MC_SET_RTS		0x02
X#define MC_SET_OUT1		0x04
X#define MC_SET_OUT2		0x08	/* tristates int line when false */
X#define MC_SET_LOOPBACK		0x10
X
X/* Line Status Port:		*/
X
X#define LS_RCV_AVAIL		0x01
X#define LS_OVERRUN		0x02
X#define LS_PARITY_ERROR		0x04
X#define LS_FRAMING_ERROR	0x08
X#define LS_BREAK_DETECTED	0x10
X#define LS_XMIT_AVAIL		0x20
X#define LS_XMIT_COMPLETE	0x40
X 
X#define LS_ANY_ERROR	(LS_OVERRUN | LS_PARITY_ERROR | LS_FRAMING_ERROR)
X#define LS_RCV_INT	(LS_ANY_ERROR | LS_RCV_AVAIL | LS_BREAK_DETECTED)
X
X#define	RECV_BUFF_SIZE	128
X
X/*
X   this structure contains everything one would like to know about
X   an open device.  There is one of these for each minor device.
X*/
X
Xstruct	asy_info
X{
X	struct	tty	*tty;	/* the tty structure */
X	struct	asy_info *next_interrupt_user;
X	unchar	mcr;		/* the modem control value */
X	unchar	lcr;		/* the line_control_register value */
X	unchar	ier;		/* interrupt enable register value */
X	ushort	o_state;	/* current open state */
X	unchar	device_flags;	/* flags about the device */
X	ushort	rec_data_port;	/* receive data port */
X	ushort	xmt_data_port;	/* transmit data port */
X	ushort	int_ena_port;	/* interrupt mask port */
X	ushort	int_id_port;	/* interrupt identification port */
X	ushort	fifo_ctrl_port;	/* fifo control port (16550 only) */
X	ushort	line_ctrl_port;
X	ushort	mdm_ctrl_port;
X	ushort	line_stat_port;
X	ushort	mdm_stat_port;
X	ushort	div_lsb_port;
X	ushort	div_msb_port;
X	unchar	has_fifo;	
X	unchar	hardware_hand_shake;
X	int	overruns;
X	int	sperious_interrupt;
X	int	h_state;
X	int	xmit_active;
X	uint	rec_buckets[17];
X	uint	tra_buckets[17];
X	ushort	*recv_ring_put_ptr;
X	ushort	*recv_ring_take_ptr;
X	short	recv_ring_cnt;
X	ushort	recv_buffer[RECV_BUFF_SIZE];
X};
X
X#define	FIFO_ENABLE	0x01
X#define	FIFO_CLR_RECV	0x02
X#define	FIFO_CLR_XMIT	0x04
X#define	FIFO_START_DMA	0x08
X#define FIFO_SIZE_1	0x00
X#define FIFO_SIZE_4	0x40
X#define FIFO_SIZE_8	0x80
X#define FIFO_SIZE_14	0xC0
X#define FIFO_SIZE_MASK	0xC0
X
X#define OUTPUT_FIFO_SIZE	16
X
X#define STANDARD_FIFO_CLEAR	(FIFO_CLR_RECV | FIFO_CLR_XMIT)
X#define STANDARD_FIFO_SETUP	(FIFO_SIZE_14 | FIFO_ENABLE)
X
X/* define the local open flags */
X#define OS_OPEN_FOR_DIALOUT		0x01
X#define OS_OPEN_FOR_GETTY		0x02
END_OF_FILE
if test 7107 -ne `wc -c <'asy.h'`; then
    echo shar: \"'asy.h'\" unpacked with wrong size!
fi
# end of 'asy.h'
fi
if test -f 'asy_conf-c1-2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy_conf-c1-2'\"
else
echo shar: Extracting \"'asy_conf-c1-2'\" \(2131 characters\)
sed "s/^X//" >'asy_conf-c1-2' <<'END_OF_FILE'
X
X/* Async device configureation file for 386 and AT versions of system V UNIX */
X
X/* This version is for the standard com1 and com2 ports.
X */
X 
X/* Written by
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
X*/
X
X/* This is the number of devices to be handled by this driver
X   if this number is changed the arrays in asy.c must be filled
X   in with the base port number and the interrupt vector
X*/
X#define NUM_PHYSICAL_UNITS	2
X
X/* array of base port addresses */
Xushort	asy_port [NUM_PHYSICAL_UNITS] =
X{
X	0x3f8,	0x2f8
X};
X
X/* array of interrupt vectors */
Xunchar	asy_vec [NUM_PHYSICAL_UNITS] =
X{
X	0x4,	0x3
X};
X
X/* modem control port info.  This value is ored into the modem control
X   value for each uart.  This is normaly used to force out2 which is
X   used to enable the interrupts form the standard com1 and com2 ports.
X   Several brands of cards have modes that allow them to work in compatable
X   mode like com1 and com2 or as a mux.  One of these cards is the MU-440
X   card by DFI.  When this card is used with the common interrupt out2
X   must not be set or there will be a fight on the buss.
X */
X
Xunchar asy_mcb [NUM_PHYSICAL_UNITS] =
X{
X	MC_SET_OUT2,	MC_SET_OUT2
X};
X
X/* array of hardware flow control flags
X   A non zero value indicates the the driver should use hardware
X   handshake on this line.
X */
Xunchar	asy_flow [NUM_PHYSICAL_UNITS] =
X{
X	0x0,	0x0
X};
X
X/* array of mux port addresses
X   Indexed by vector number a non zero value is a port address that
X   must be read from to get the interrupt vector.
X   The input value actually contains bits representing the uart that
X   interrupted but I can find no good documentation on these so I
X   have elected to poll the uarts.
X   This port also must be written to enable the interrupts.  This
X   acts similar to the out2 in the standard asy card.	
X   If you are not sure what to do here you should probably not set
X   any of these
X */
X
Xushort	asy_mux_port [NUM_INT_VECTORS] =
X{
X	0,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0
X};
END_OF_FILE
if test 2131 -ne `wc -c <'asy_conf-c1-2'`; then
    echo shar: \"'asy_conf-c1-2'\" unpacked with wrong size!
fi
# end of 'asy_conf-c1-2'
fi
if test -f 'asy_conf-c1-2h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy_conf-c1-2h'\"
else
echo shar: Extracting \"'asy_conf-c1-2h'\" \(2131 characters\)
sed "s/^X//" >'asy_conf-c1-2h' <<'END_OF_FILE'
X
X/* Async device configureation file for 386 and AT versions of system V UNIX */
X
X/* This version is for the standard com1 and com2 ports.
X */
X 
X/* Written by
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
X*/
X
X/* This is the number of devices to be handled by this driver
X   if this number is changed the arrays in asy.c must be filled
X   in with the base port number and the interrupt vector
X*/
X#define NUM_PHYSICAL_UNITS	2
X
X/* array of base port addresses */
Xushort	asy_port [NUM_PHYSICAL_UNITS] =
X{
X	0x3f8,	0x2f8
X};
X
X/* array of interrupt vectors */
Xunchar	asy_vec [NUM_PHYSICAL_UNITS] =
X{
X	0x4,	0x3
X};
X
X/* modem control port info.  This value is ored into the modem control
X   value for each uart.  This is normaly used to force out2 which is
X   used to enable the interrupts form the standard com1 and com2 ports.
X   Several brands of cards have modes that allow them to work in compatable
X   mode like com1 and com2 or as a mux.  One of these cards is the MU-440
X   card by DFI.  When this card is used with the common interrupt out2
X   must not be set or there will be a fight on the buss.
X */
X
Xunchar asy_mcb [NUM_PHYSICAL_UNITS] =
X{
X	MC_SET_OUT2,	MC_SET_OUT2
X};
X
X/* array of hardware flow control flags
X   A non zero value indicates the the driver should use hardware
X   handshake on this line.
X */
Xunchar	asy_flow [NUM_PHYSICAL_UNITS] =
X{
X	0x1,	0x1
X};
X
X/* array of mux port addresses
X   Indexed by vector number a non zero value is a port address that
X   must be read from to get the interrupt vector.
X   The input value actually contains bits representing the uart that
X   interrupted but I can find no good documentation on these so I
X   have elected to poll the uarts.
X   This port also must be written to enable the interrupts.  This
X   acts similar to the out2 in the standard asy card.	
X   If you are not sure what to do here you should probably not set
X   any of these
X */
X
Xushort	asy_mux_port [NUM_INT_VECTORS] =
X{
X	0,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0
X};
END_OF_FILE
if test 2131 -ne `wc -c <'asy_conf-c1-2h'`; then
    echo shar: \"'asy_conf-c1-2h'\" unpacked with wrong size!
fi
# end of 'asy_conf-c1-2h'
fi
if test -f 'asy_conf-mux4' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy_conf-mux4'\"
else
echo shar: Extracting \"'asy_conf-mux4'\" \(2233 characters\)
sed "s/^X//" >'asy_conf-mux4' <<'END_OF_FILE'
X
X/* Async device configureation file for 386 and AT versions of system V UNIX */
X
X/* This version is for the DFI MU440 mux board in expanded mode.  This board
X   is reported to be compatable with the AST 4-port card.
X */
X 
X/* Written by
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
X*/
X
X/* This is the number of devices to be handled by this driver
X   if this number is changed the arrays in asy.c must be filled
X   in with the base port number and the interrupt vector
X*/
X#define NUM_PHYSICAL_UNITS	4
X
X/* array of base port addresses */
Xushort	asy_port [NUM_PHYSICAL_UNITS] =
X{
X	0x2a0,	0x2a8,	0x2b0,	0x2b8
X};
X
X/* array of interrupt vectors */
Xunchar	asy_vec [NUM_PHYSICAL_UNITS] =
X{
X	0x4,	0x4,	0x4,	0x4
X};
X
X/* modem control port info.  This value is ored into the modem control
X   value for each uart.  This is normaly used to force out2 which is
X   used to enable the interrupts form the standard com1 and com2 ports.
X   Several brands of cards have modes that allow them to work in compatable
X   mode like com1 and com2 or as a mux.  One of these cards is the MU-440
X   card by DFI.  When this card is used with the common interrupt out2
X   must not be set or there will be a fight on the buss.
X */
X
Xunchar asy_mcb [NUM_PHYSICAL_UNITS] =
X{
X	0,	0,	0,	0
X};
X
X/* array of hardware flow control flags
X   A non zero value indicates the the driver should use hardware
X   handshake on this line.
X */
Xunchar	asy_flow [NUM_PHYSICAL_UNITS] =
X{
X	0x0,	0x0,	0x0,	0x0
X};
X
X/* array of mux port addresses
X   Indexed by vector number a non zero value is a port address that
X   must be read from to get the interrupt vector.
X   The input value actually contains bits representing the uart that
X   interrupted but I can find no good documentation on these so I
X   have elected to poll the uarts.
X   This port also must be written to enable the interrupts.  This
X   acts similar to the out2 in the standard asy card.	
X   If you are not sure what to do here you should probably not set
X   any of these
X */
X
Xushort	asy_mux_port [NUM_INT_VECTORS] =
X{
X	0,	0,	0,	0,
X	0x2bf,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0
X};
END_OF_FILE
if test 2233 -ne `wc -c <'asy_conf-mux4'`; then
    echo shar: \"'asy_conf-mux4'\" unpacked with wrong size!
fi
# end of 'asy_conf-mux4'
fi
if test -f 'asy_conf-mux4h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'asy_conf-mux4h'\"
else
echo shar: Extracting \"'asy_conf-mux4h'\" \(2233 characters\)
sed "s/^X//" >'asy_conf-mux4h' <<'END_OF_FILE'
X
X/* Async device configureation file for 386 and AT versions of system V UNIX */
X
X/* This version is for the DFI MU440 mux board in expanded mode.  This board
X   is reported to be compatable with the AST 4-port card.
X */
X 
X/* Written by
XJim Murray              encore!cloud9!jjmhome!jjm
X2 Mohawk Circle         harvard!m2c!jjmhome!jjm
XWestboro Mass 01581     jjm%jjmhome@m2c.m2c.org
XUSA                     voice (508) 366-2813
X*/
X
X/* This is the number of devices to be handled by this driver
X   if this number is changed the arrays in asy.c must be filled
X   in with the base port number and the interrupt vector
X*/
X#define NUM_PHYSICAL_UNITS	4
X
X/* array of base port addresses */
Xushort	asy_port [NUM_PHYSICAL_UNITS] =
X{
X	0x2a0,	0x2a8,	0x2b0,	0x2b8
X};
X
X/* array of interrupt vectors */
Xunchar	asy_vec [NUM_PHYSICAL_UNITS] =
X{
X	0x4,	0x4,	0x4,	0x4
X};
X
X/* modem control port info.  This value is ored into the modem control
X   value for each uart.  This is normaly used to force out2 which is
X   used to enable the interrupts form the standard com1 and com2 ports.
X   Several brands of cards have modes that allow them to work in compatable
X   mode like com1 and com2 or as a mux.  One of these cards is the MU-440
X   card by DFI.  When this card is used with the common interrupt out2
X   must not be set or there will be a fight on the buss.
X */
X
Xunchar asy_mcb [NUM_PHYSICAL_UNITS] =
X{
X	0,	0,	0,	0
X};
X
X/* array of hardware flow control flags
X   A non zero value indicates the the driver should use hardware
X   handshake on this line.
X */
Xunchar	asy_flow [NUM_PHYSICAL_UNITS] =
X{
X	0x1,	0x1,	0x1,	0x1
X};
X
X/* array of mux port addresses
X   Indexed by vector number a non zero value is a port address that
X   must be read from to get the interrupt vector.
X   The input value actually contains bits representing the uart that
X   interrupted but I can find no good documentation on these so I
X   have elected to poll the uarts.
X   This port also must be written to enable the interrupts.  This
X   acts similar to the out2 in the standard asy card.	
X   If you are not sure what to do here you should probably not set
X   any of these
X */
X
Xushort	asy_mux_port [NUM_INT_VECTORS] =
X{
X	0,	0,	0,	0,
X	0x2bf,	0,	0,	0,
X	0,	0,	0,	0,
X	0,	0,	0,	0
X};
END_OF_FILE
if test 2233 -ne `wc -c <'asy_conf-mux4h'`; then
    echo shar: \"'asy_conf-mux4h'\" unpacked with wrong size!
fi
# end of 'asy_conf-mux4h'
fi
if test -f 'config-c1-2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config-c1-2'\"
else
echo shar: Extracting \"'config-c1-2'\" \(253 characters\)
sed "s/^X//" >'config-c1-2' <<'END_OF_FILE'
X* its character device number 3
Xcharacter(3)
X
X* its name
Xprefix = asy
X
X* The interrupt vectors handled by this controller
Xintvec = 4,3
X
X* its mask level
Xintpri = SPLTTY
X
X* the functions it supports
Xfunctions = init, open, close, read, write, ioctl, tty
END_OF_FILE
if test 253 -ne `wc -c <'config-c1-2'`; then
    echo shar: \"'config-c1-2'\" unpacked with wrong size!
fi
# end of 'config-c1-2'
fi
if test -f 'config-mux4' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config-mux4'\"
else
echo shar: Extracting \"'config-mux4'\" \(251 characters\)
sed "s/^X//" >'config-mux4' <<'END_OF_FILE'
X* its character device number 3
Xcharacter(3)
X
X* its name
Xprefix = asy
X
X* The interrupt vectors handled by this controller
Xintvec = 4
X
X* its mask level
Xintpri = SPLTTY
X
X* the functions it supports
Xfunctions = init, open, close, read, write, ioctl, tty
END_OF_FILE
if test 251 -ne `wc -c <'config-mux4'`; then
    echo shar: \"'config-mux4'\" unpacked with wrong size!
fi
# end of 'config-mux4'
fi
if test -f 'makefile.v386' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.v386'\"
else
echo shar: Extracting \"'makefile.v386'\" \(512 characters\)
sed "s/^X//" >'makefile.v386' <<'END_OF_FILE'
XINCLSYS=/usr/include/sys
XINSDIR=/etc/atconf
X
XCFLAGS = -O -DINKERNEL
X
XOBJS = asy.o
X
Xasy.o:		asy.c \
X		asy.h \
X		asy_conf.h
X
Xasy_conf.h:
X	@echo "You must link asy_conf.h to the proper asy_conf-xxxxx file"
X	@false
X	
Xinstall:	asy.o	config
X	cp asy.o $(INSDIR)/modules/asy/asy.o
X	chmod 644 $(INSDIR)/modules/asy/asy.o
X	cp config $(INSDIR)/modules/asy/config
X	chmod 644 $(INSDIR)/modules/asy/config
X
Xconfig:
X	@echo "You must link config to the proper config-xxxxx file"
X	@false
X		
X
Xclean:
X	rm -f asy.o
X
Xclobber:	clean
X
END_OF_FILE
if test 512 -ne `wc -c <'makefile.v386'`; then
    echo shar: \"'makefile.v386'\" unpacked with wrong size!
fi
# end of 'makefile.v386'
fi
if test -f 'makefile.vat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.vat'\"
else
echo shar: Extracting \"'makefile.vat'\" \(1396 characters\)
sed "s/^X//" >'makefile.vat' <<'END_OF_FILE'
X
X# Replace the following line with the path to the linkkit subdirectory.
XLINKKIT=/usr/linkkit
X
XCFLAGS = -O -Ml -DiAPX286
X
XOBJS = asy.o
X
X# When make is executed, the object module is the only item that is built.
X# Installation has to be requested.
Xasy.o:		asy.c \
X		asy_conf.h \
X		asy.h
X	cc $(CFLAGS) -I$(LINKKIT) -c asy.c
X
X# Install the object module in lib0. This is the location for third party
X# device drivers. Don't bother trying to replace the Microport drivers. This
X# library will link in first and do the replacement for you.
Xinstall:	asy.o
X	ar rv $(LINKKIT)/lib0 asy.o
X
X# Make the appropriate changes to the master and dfile. This action only needs
X# to be performed once.
Xmaster:
X	sed -e '/^asy.*/s//asy	36,35	ocrwis	cot	asy	0	5	2/' < $(LINKKIT)/cf/master > /tmp/asy$$
X	mv /tmp/asy$$ $(LINKKIT)/cf/master
X	sed -e '/^asy.*/s//asy	0	2/' < $(LINKKIT)/cf/dfile.wini > /tmp/asy$$
X	mv /tmp/asy$$ $(LINKKIT)/cf/dfile.wini
X
X# Make the devices with the correct names in /dev. This will kill the
X# devices which Microport has provided. This step needs to be performed
X# only once.
Xdevices:
X	rm -f /dev/tty0 /dev/tty1 /dev/ttyM0 /dev/ttyM1
X	mknod /dev/tty0 c 5 0
X	mknod /dev/tty1 c 5 1
X	mknod /dev/ttyM0 c 5 128
X	mknod /dev/ttyM1 c 5 129
X
X# Just for fun. Make a kernel
Xkernel:
X	cd $(LINKKIT)/cf; make wini
X
X# And Oh boy, can't have a makefile without a clean
Xclean:
X	rm -f asy.o
X
Xclobber:	clean
X
END_OF_FILE
if test 1396 -ne `wc -c <'makefile.vat'`; then
    echo shar: \"'makefile.vat'\" unpacked with wrong size!
fi
# end of 'makefile.vat'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(37 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
Xrelease 1.00 release 1 patchlevel 00
END_OF_FILE
if test 37 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
echo shar: End of shell archive.
exit 0

-- 
Jim Murray              encore!cloud9!jjmhome!jjm
2 Mohawk Circle         harvard!m2c!jjmhome!jjm
Westboro Mass 01581     jjm%jjmhome@m2c.m2c.org
USA                     voice (508) 366-2813