FAS 2.08 async driver, part 2/4

Uwe Doering gemini at geminix.in-berlin.de
Mon Feb 4 09:17:00 AEST 1991


Submitted-by: gemini at geminix.in-berlin.de
Archive-name: fas208/part02

#!/bin/sh
# this is fas208.02 (part 2 of fas208)
# do not concatenate these parts, unpack them in order with /bin/sh
# file RELEASENOTES continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 2; 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 RELEASENOTES'
else
echo 'x - continuing file RELEASENOTES'
sed 's/^X//' << 'SHAR_EOF' >> 'RELEASENOTES' &&
X          port. See description preceding the asyopen function in
X          asy.c. Changed the behavior of ttyxx, too.
X
X          Added output hardware handshake support for DSR. Now you
X          can do handshake with CTS, DSR or both. Input hardware
X          handshake is on if you use at least one of the output
X          handshake signals.
X
X          More flexible support of additional interrupt registers
X          on mux boards. This is fully configurable now.
X
X          Added support for the CREAD flag. If not set, receiver
X          interrupts are still serviced, but the received characters
X          are simply thrown away. This is not as elegant as disabeling
X          the interrupts themselves, but with the already existing
X          driver it was the easiest way, and the most new-bugs-preventing,
X          too.
X
X          Added a lot of comments to the source so that the curious
X          user can understand why and how things are done.
X
X
X     Bug Fixes:
X
X          The hang-up-on-last-close flag (HUPCL) was ignored. DTR
X          was asserted regardless of this flag.
X
X          Made the detection of CTS and DCD more bullet-proof.
X          Especially because between a close and the next open of
X          a line, where interrupts are ignored, the software copys of
X          CTS and DCD must be set up propperly in the asyopen function
X          or the tty line would be blocked under certain circum-
X          stances. For similar reasons, there is also a setup in the
X          asyparam function.
X
X          Rewrote the input character processing function to work
X          according to the TERMIO(7) man page.
X
X          Changed the behavior of BREAK generation to let the
X          transmitter drain before TX is set to low.
X
X          Changed line hangup procedure so that the closing
X          process returns immediately and doesn't sleep during
X          the hangup delay/time. Instead, if an other process tries
X          to open the line while hangup is still in progress, this
X          process will sleep until hangup is competed.
X
X          With DOS Merge, on MicroPort V/386 3.0e the linker was
X          missing the function `init8250'. Reengineered this from
X          a disassembler listing of MicroPort's original driver and
X          modified it to work with the NS16550A 16-byte FIFO. This
X          funktion was added simply to be able to link the kernel.
X          DOS Merge's virtual COM ports are still unusable with this
X          release, though. To include this function, add a `-DMERGE'
X          to the CFLAGS line in your makefile.
X
X          Made a lot of other corrections and enhancements in both
X          speed and functionallity. As a result of all my effords
X          I think this driver is slightly faster, more versatile
X          and much more stable than the original release.
X
X     ------------------------------------------------------------
X          
X     release 1.1b Sat Nov 25, 1989
X
X     New Features:
X
X          Changed the minor device number scheme again.
X          There are now two main groups: The unblocked open
X          and the blocked open. Every group has four sub-modes
X          and an additional hardware handshake flag. All this
X          is coded in the higher four bits of the minor device
X          number. Because of this, the maximum of 32 ports was
X          reduced to 16 ports so that the port number fits into
X          the remaining lower four bits of the minor device number.
X          32 dumb ports in a single machine would have been overkill
X          anyway. For more details refer to the description in the
X          README file.
X
X     ------------------------------------------------------------
X          
X     release 2.00 Mon Nov 27, 1989
X
X     As this release differs so much from the original version I got,
X     I now declare this as independant from the original author
X     Jim Murray. This allows me to introduce new release levels
X     without wondering whether they will collide with Jim's releases.
X     Of course many credits to Jim for writing this software in the
X     first place. Without his driver as a base I never would have
X     been able to do such kernel driver development.
X
X     Bug Fixes:
X
X          If there were glitches on the hardware handshake lines
X          and the DCD line a getty on this port would sometimes
X          hang and become an immortal process. I think this was
X          because the output buffer wasn't flushed properly
X          on carrier loss. I hope I fixed this now. We'll see.
X
X     ------------------------------------------------------------
X          
X     release 2.01 Tue Nov 28, 1989
X
X     Did some cleanup in the source code.
X
X     I splitted the driver into two parts: The driver itself and
X     the file `space.c'.
X     `space.c' contains all data structures necessary to configure
X     the driver and is compiled at kernel link time. Therefore, if you
X     change your serial card configuration you simply change `space.c'
X     directly in the link kit directory and relink the kernel. No
X     driver recompilation or installation is necessary for this.
X     But note that whenever you use `make install' your setup in
X     the link kit directory is overwritten by the original `space.c'
X     file. Therefore, you should copy your new `space.c' back to
X     the source directory when you are finished with the configuration.
X
X     Renamed the package to `FAS Final Async Solution'. The following
X     files have been renamed:
X          asy.c          -> fas.c
X          asy.h          -> fas.h
X          asy_conf-xxxxx -> space-xxxxx
X
X     ISC 386/ix is supported now. There are separate makefiles
X     for uPort and ISC to cope with the differences in link kit
X     installation.
X
X     Bug Fixes:
X
X          `getty' still hung sometimes on a line with hardware
X          handshake. Tried to fix it this time.
X
X     ------------------------------------------------------------
X          
X     release 2.02 Thu Nov 30, 1989
X
X     Abandoned the distinction between space-xxxxx files with
X     and without hardware flow control because this is selected
X     by the minor device number now.
X
X     Bug Fixes:
X
X          Set the high and low water marks for hardware input flow
X          control to higher values than software flow control. This
X          gives precedence to software flow control if both methods
X          are used. These marks are self-adjusting and don't need to
X          be changed if some flavor of UNIX has a different buffer
X          size than the standard 256 characters. Before this change
X          concurrent use of both flow controls could cause trouble
X          with some high-speed modems. This is fixed now.
X
X          A flush read or write buffer request now also clears the
X          receiver or transmitter FIFO, respectively. An ioctl
X          call with a TCSETA* command clears the FIFOs, too.
X
X     ------------------------------------------------------------
X          
X     release 2.03 Fri Dec 01, 1989
X
X     Wrote an installation guide. The driver should be quite
X     easy to install now.
X
X     Added tty node configuration files for ISC.
X
X     Hardware input flow control is bound now to the level of the
X     receiver ring buffer instead of the UNIX input buffer. This
X     has the advantage that buffer size and trigger levels are
X     defined in the driver and therefore can be varied as needed.
X
X     New Features:
X
X          Added a boot time status message that shows the init
X          state of each port. This tells you immediately what
X          ports are found and initted by the driver. Useful to
X          determine hardware configuration problems. Look at
X          the description in the README file. Thanks to
X          Kritt Gierlewsen (kritt at einoed.UUCP) for this proposal.
X
X     ------------------------------------------------------------
X          
X     release 2.04 Thu Dec 07, 1989
X
X     Did some cleanup in the source.
X
X     Removed the FIFO clear from the ioctl function. We don't want
X     to do things there that aren't in the book.
X
X     An ioctl call that switches off the CLOCAL flag will create
X     a SIGHUP signal if the carrier is actually missing at this
X     time.
X
X     Every device is tested now quite thoroughly during initialization.
X     If the test fails the corresponding device keeps unconfigured.
X
X     ------------------------------------------------------------
X          
X     release 2.05 Sat Jan 13, 1990
X
X     This is the first public release of the FAS driver.
X
X     Special thanks to the sysops of my test sites, Axel Fischer
X     (fischer at utower.UUCP) and Kritt Gierlewsen (kritt at einoed.UUCP).
X
X     FAS is now an independant driver with its own driver name (`fas'),
X     major device number, link kit directory and other things necessary
X     for a driver. The original asy driver may or may not be linked
X     with the kernel. You only need it if you want to access some
X     serial devices via the virtual COM ports of the DOS emulator
X     (DosMerge or VP/ix) because the FAS driver doesn't have this
X     (really vendor dependant) feature.
X
X     The default prefix for tty device node names is `ttyF' now.
X     This prevents mix-ups with the device names of the original
X     asy driver.
X
X     Dropped the SYSV/AT support. I couldn't test the driver
X     for several release generations on uPort SYSV/AT, and because
X     there are not very much systems left with that flavor of UNIX
X     it doesn't make sense to try to maintain compatibility with it.
X     If someone really wants to use this driver on a 286 he has
X     to port it himself.
X
X     Improved the transmitter FIFO fill procedure. Now it will try
X     harder to fill the FIFO as much as possible to cut down on
X     transmitter interrupts.
X
X     Software input flow control (XON/XOFF) is controlled by the driver now.
X     It is bound to the level of the receiver ring buffer (as is hardware
X     flow control). As usual, it can be switched on and off by the
X     IXOFF flag in the termio(7) structure.
X
X     Changed and speeded up the ring buffer -> unix buffer processing.
X
X     For ISC, the getty lines for the inittab file are installed
X     by the makefile now.
X
X     The conditional compilation of the function `init8250' (for
X     DosMerge) is now controlled by a define in `fas.h'. The compiler
X     switch `-DMERGE' is not used any more.
X
X     Improved the documentation.
X
X     The signals used for modem control and hardware flow control are
X     fully configurable in the `space.c' file now. Look at `fas.h' for
X     possible macros and combinations.
X
X     There are some new modes for hardware flow control, for instance
X     HO_CTS_ON_DSR. This means that CTS is only looked at if DSR is on.
X     If DSR is off output is possible regardless of CTS. The underlying
X     assumption here is that we can expect proper handshake handling
X     only from devices that are in the ready state (indicated by DSR).
X     As a spin-off the problem with the hanging getty on lines with
X     turned-off terminals (mentioned in earlier releases) should be
X     gone if you use this new mode.
X
X     If the XCLUDE-Flag is availabe (SYSV 3.2 because of Xenix
X     compatibility) exclusive open of a device is possible.
X
X     The default size of the input ring buffer is now 5000 bytes.
X     This makes streaming input more likely even on loaded systems.
X
X     Bug Fixes:
X
X          The task state busy flag wasn't reset in some rare cases.
X          This could cause processes to become immortal while waiting
X          for the busy flag.
X
X          Under some special conditions an ioctl call with a TCSETA?
X          command could corrupt the last character in the transmitter
X          shift register. This is fixed now.
X
X          More fixing of the busy flag handling was necessary.
X          Co-ordinating several delayed tasks controlling this flag
X          is kind of tricky.
X
X          After a TCSETA* ioctl command we disable the transmitter
X          for 2 sec (measured from the last transmitted character)
X          if the character format and/or speed has changed. This
X          gives the receiving side some time to do the same changes.
X          This is kind of experimental. There may be applications that
X          suffer from this delay. You may change the #define ADAPT_TIME
X          in `fas.h' to a smaller value.
X
X     ------------------------------------------------------------
X          
X     release 2.06 Fri Mar 16, 1990
X
X     This should have been patch #3 for release 2.05, but there are
X     so many changes now that I decided to make it a new release.
X     Therefor, some of the changes are described in the 2.05 release
X     notes above but were never released to the public.
X
X     New Features:
X
X          There is a transmitter ring buffer now to make the output
X          less system load dependent. This really speeds things up
X          because the transmitter FIFO gets filled with more characters
X          at once. The buffer size depends on the actual baud rate to
X          prevent long output buffer drains at low speeds.
X
X          There are also bigger input buffers to make FAS more competitive
X          against "intelligent" cards.
X
X          Lots of speed improvements and many small changes.
X
X     Bug Fixes:
X
X          Fixed input/output buffer flush on carrier loss while close
X          is waiting for the output to drain.
X
X     ------------------------------------------------------------
X          
X     release 2.07 Tue Sep 18, 1990
X
X     This is a major redesign of the previous release. I put most of the
X     time consuming tasks in one function that is invoked asynchronously
X     by timeout calls. Inside this function most of the code runs at
X     a lower system priority level (spl5) than the interrupts. That
X     means that during character processing tty interrupts are allowed.
X     This is the main key to operation at 38400 bps on multiple ports
X     at the same time which is possible now with this release.
X
X     New Features:
X
X          FAS supports the VP/ix DOS emulator!
X          Now you can throw out the vendor's original driver even
X          if you like to have a serial mouse or modem access in DOS.
X          Read the paragraph about VP/ix in the README file.
X
X          The Intel i82510 port chip is supported. It has separate
X          4-character FIFOs for input and output. Although the
X          NS16550A is much better this chip is your second choice
X          if you can't get your hands on the National chips.
X          Thanks to Christian Seyb (cs at gold.UUCP) for sending me
X          patches and the necessary documentation for the Intel
X          chips.
X
X          There is an init sequence in `space.c'. You can put any
X          number of address-data pairs in a null terminated array
X          to program your serial card or other hardware before
X          FAS makes the first access to the ports. AST 4-port cards,
X          for instance, have an additional port that needs to be
X          written to with a certain bit pattern to allow shared
X          interrupts. If you need to read a port to achieve the
X          setting or resetting of flags as a side effect, this
X          is possible, too.
X
X          ESIX is officially supported now.
X
X          SCO UNIX is officially supported, too. FAS needs to be
X          compiled with the command line flag `-DSCO'. The makefile
X          for SCO takes care of that. Thanks to Walter Mecky
X          (walter at mecky.systemware.de) and Frank Simon
X          (terra at sol.north.de) for helping me in making the necessary
X          changes for SCO UNIX.
X
X          SCO Xenix 386 is also officially supported. FAS needs to be
X          compiled with the command line flag `-DXENIX'. The makefile
X          for SCO Xenix takes care of that. Thanks to Andreas
X          Steinmetzler (andreas at oil.UUCP) for doing the port.
X
X          If you have the RTSFLOW and CTSFLOW termio(7) flags,
X          hardware handshake can be controlled by them.
X          Note that enabling handware flow control via the
X          minor device number overrides these flags. If you
X          like to use them you need to create tty device nodes
X          with minor device numbers in which the bit for hardware
X          handshake is set to 0. Look at the description in the
X          README file for more details.
X          Note also that if you choose to use RTSFLOW and CTSFLOW
X          all your programs that do initial access to tty devices
X          (getty, uucico, cu, SLIP dialup program etc.) need to know
X          about these flags or hardware handshake will not be used.
X
X          The `O_EXCL' flag for the open(2) call is honored now.
X          This allowes exclusive access to an FAS device without
X          suffering from race conditions which could occure with
X          the termio(7) XCLUDE flag method.
X
X          The `fas_test_device' function returns a digit now that
X          indicates at which phase the test exited due to an error.
X          This error digit is displayed in the boot message. Thanks
X          to Brian Beattie (beattie at visenix.UUCP) for sending me
X          the necessary patches.
X
X     Bug Fixes:
X
X          Automatic input FIFO flush after unblocking the getty
X          open by the carrier or the unblock signal. This makes sure
X          that there is no chance that there are characters in the
X          FIFO that were received before the open got unblocked.
X
X          The sdevice entry for the AST 4-port card had a wrong
X          I/O address range (`s_fas-mux4'). This didn't affect FAS
X          but is checked by the kernel config program.
X
X          The gcc (GNU cc) support was removed because gcc's object
X          file wants to link in some "helpful" functions that aren't
X          contained in the kernel. But anyway, FAS is tuned so carefully
X          and depends on the optimization behaviour of the AT&T
X          standard C compiler that gcc won't have any advantages.
X
X          I changed the method with which the `fas_test_device' function
X          waits for certain events. The `delay' function was used
X          for that purpose but it turned out that with some flavors
X          of UNIX it is prohibited to use this function during the
X          xxinit phase of the boot process. Now a simple timeout loop
X          is used instead.
X
X          Removed the ADAPT_TIME mechanismn introduced in release 2.05.
X
X          The open() call now returns an `EBUSY' error number if the
X          device is already open and can't be opened in the desired
X          mode at this time.
X
X          The handling of the RING signal needed fixing. Unlike the other
X          three modem status lines RING generates an interrupt only at
X          the trailing edge.
X
X          No SIGHUP signal is sent any more if an ioctl call clears
X          the CLOCAL termio(7) flag while there is no carrier present.
X          SIGHUP is only sent if the actual DCD modem line drops.
X
X          The files *-mux4 were renamed to *-ast4 because this type of
X          card was originally developed by AST (AST 4-port card).
X
X     ------------------------------------------------------------
X          
X     release 2.08 Sun Feb 03, 1991
X
X     New Features:
X
X          Bell Tech/Intel UNIX 3.2 is supported.
X
X          SCO Xenix 286 is also supported now. Thanks to Nickolay Saukh
X          (nms at saukh.rd.jvd.su) for providing the patches.
X
X          The Bell Tech HUB-6 card can be used with FAS. Thanks to
X          Keith Walker (kew at cims2.UUCP) for the patches.
X
X          For AT&T derived flavors of UNIX there is a line automatically
X          added to the kernel description file that makes the adding
X          and removing of FAS possible via the `kconfig' program. Thanks
X          to John Adams (johna at grumpy.boston.ma.us) for this idea.
X
X          There is a mechanismn now that prevents excessive modem status
X          interrupts caused by crosstalking between wires or by a loose
X          cable.
X
X          You can disable the FIFOs in a UART by "oring" the macro
X          `NO_FIFO' to the base port address of this device. This is
X          useful for mouse devices where you need immediate response
X          to the mouse movement.
X
X          The meaning of the bit mapped part of the minor device
X          numbers has changed. Some rather useless functions were
X          removed in favor of more control over the hardware handshake
X          modes. Even systems where the SCO RTSFLOW/CTSFLOW termio(7)
X          flags are not available can now use half duplex hardware
X          flow control (selected via the minor device number).
X
X          The assignment of RS232C lines to certain FAS functions
X          is even more flexible now. This allows to connect two
X          UNIX systems (with FAS) via a null modem cable, running
X          a getty at both ends. For more details, read the paragraph
X          about CABLING in the README file.
X
X          A special handling of the NS16550A input FIFO was introduced.
X          This causes multiple receiver interrupts (on the same IRQ
X          line) to be synchronized so that only one interrupt is
X          necessary to process all receiving ports. This reduces the
X          interrupt handling overhead and therefor results in lower
X          CPU load for concurrent serial input at high speeds.
X
X          The `fas_event' function processes all scheduled events
X          for all units with one single call. Previously, every unit
X          launched its own timeout() call if there was work to
X          do. This could lead to up to 16 timeouts at the same time,
X          resulting in some timeout handling overhead. This overhead
X          is minimized now.
X
X     Bug Fixes:
X
X          There were two bugs that could cause a port to lock up,
X          resulting in an immortal process.
X
X          Almost any kernel sleep is killable now (at least with one or
X          two `kill -9'). Therefor, there should be no more immortal
X          processes. Even killing a process that is hanging in a
X          close-on-exit call is possible.
X
X          The meaning of the RTSFLOW/CTSFLOW termio(7) flags was converted
X          to what SCO had in mind (half duplex flow control). This is for
X          compatibility reasons. Full duplex RTS/CTS hardware flow control
X          is still possible via the minor device number method. Thanks to
X          Dmitry V. Volodin (dvv at hq.demos.su) for providing me with the
X          necessary knowledge.
X
X          If a process is already sleeping in a getty open it will only
X          unblock on DCD low->high. In particular, if in the meantime
X          the device was open for dialout and DCD is still present if
X          the getty open takes over again this won't unblock the getty
X          open any more.
X
X          And there were, as usual, a number of other small bug fixes.
SHAR_EOF
echo 'File RELEASENOTES is complete' &&
true || echo 'restore of RELEASENOTES failed'
rm -f _shar_wnt_.tmp
fi
# ============= config-ast4 ==============
if test -f 'config-ast4' -a X"$1" != X"-c"; then
	echo 'x - skipping config-ast4 (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config-ast4 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config-ast4' &&
X* its character device number 4
Xcharacter(4)
X
X* its name
Xprefix = fas
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
SHAR_EOF
true || echo 'restore of config-ast4 failed'
rm -f _shar_wnt_.tmp
fi
# ============= config-ast4c12 ==============
if test -f 'config-ast4c12' -a X"$1" != X"-c"; then
	echo 'x - skipping config-ast4c12 (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config-ast4c12 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config-ast4c12' &&
X* its character device number 4
Xcharacter(4)
X
X* its name
Xprefix = fas
X
X* The interrupt vectors handled by this controller
Xintvec = 9,4,3
X
X* its mask level
Xintpri = SPLTTY
X
X* the functions it supports
Xfunctions = init, open, close, read, write, ioctl, tty
SHAR_EOF
true || echo 'restore of config-ast4c12 failed'
rm -f _shar_wnt_.tmp
fi
# ============= config-c1-2 ==============
if test -f 'config-c1-2' -a X"$1" != X"-c"; then
	echo 'x - skipping config-c1-2 (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config-c1-2 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config-c1-2' &&
X* its character device number 4
Xcharacter(4)
X
X* its name
Xprefix = fas
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
SHAR_EOF
true || echo 'restore of config-c1-2 failed'
rm -f _shar_wnt_.tmp
fi
# ============= config-c1-3 ==============
if test -f 'config-c1-3' -a X"$1" != X"-c"; then
	echo 'x - skipping config-c1-3 (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config-c1-3 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config-c1-3' &&
X* its character device number 4
Xcharacter(4)
X
X* its name
Xprefix = fas
X
X* The interrupt vectors handled by this controller
Xintvec = 4,3,9
X
X* its mask level
Xintpri = SPLTTY
X
X* the functions it supports
Xfunctions = init, open, close, read, write, ioctl, tty
SHAR_EOF
true || echo 'restore of config-c1-3 failed'
rm -f _shar_wnt_.tmp
fi
# ============= config-hub6 ==============
if test -f 'config-hub6' -a X"$1" != X"-c"; then
	echo 'x - skipping config-hub6 (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting config-hub6 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'config-hub6' &&
X* its character device number 4
Xcharacter(4)
X
X* its name
Xprefix = fas
X
X* The interrupt vectors handled by this controller
Xintvec = 3
X
X* its mask level
Xintpri = SPLTTY
X
X* the functions it supports
Xfunctions = init, open, close, read, write, ioctl, tty
SHAR_EOF
true || echo 'restore of config-hub6 failed'
rm -f _shar_wnt_.tmp
fi
# ============= fas.c ==============
if test -f 'fas.c' -a X"$1" != X"-c"; then
	echo 'x - skipping fas.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting fas.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'fas.c' &&
X/* FAS Final Async Solution driver for 286/386 versions of system V UNIX */
X
X/* FAS was developed by
XUwe Doering             INET : gemini at geminix.in-berlin.de
XBillstedter Pfad 17 b   UUCP : ...!unido!fub!geminix.in-berlin.de!gemini
X1000 Berlin 20
XGermany
X*/
X
X#if !defined (M_I286)
X#ident	"@(#)fas.c	2.08"
X#endif
X
X/* Note: This source code was quite heavily optimized for speed. You
X         may wonder that register variables aren't used everywhere.
X         This is because there is an overhead in memory accesses
X         when using register variables. As you may know data accesses
X         usually need much more wait states on the memory bus than
X         code accesses (because of page or cache misses). Therefor,
X         saving some data accesses has higher priority than saving
X         code accesses.
X
X         You may also note some not very elegant constructions that
X         may be intentional because they are faster. If you want to
X         make style improvements you should check the assembler output
X         whether this wouldn't slow things down.
X
X         Decisions for speed optimization were based on assembler
X         listings produced by the standard UNIX V 3.X/386 C compiler.
X*/
X
X#if defined (XENIX)
X#include "fas.h"
X#else
X#include <sys/fas.h>
X#if !defined (NO_ASM)
X#include <sys/inline.h>
X#endif
X#endif
X
X#if defined (SCO) || defined (XENIX)
X#define asyputchar sioputchar
X#define asygetchar siogetchar
X#endif
X
X#if defined (XENIX) || defined (NO_ASM)
X#define intr_disable()	old_level = SPLINT ()
X#define intr_restore()	(void) splx (old_level)
X#define REGVAR
X#else
X/* This is a terrible ugly kludge to speed up the `inb' and `outb'
X   functions. I.e., originally, the `outb' inline function had an
X   overhead of four data memory accesses for parameter passing. This
X   parameter passing actually consumed more clock cycles than the
X   assembler `outb' command itself. Although this solution can't
X   prevent unnessessary register moves it limits them at least to
X   register to register moves that are much faster. You need a
X   line like the following in the declaration part of every
X   function that uses `inb' or `outb' calls:
X
X	REGVAR;
X
X   This hack should work with every compiler that knows about the
X   UNIX V 3.X/386 standard compiler's inline assembler directives.
X*/
X
Xasm	void loadal (val)
X{
X%reg	val;
X	movl	val,%eax
X%mem	val;
X	movb	val,%al
X}
X
Xasm	void loaddx (val)
X{
X%reg	val;
X	movl	val,%edx
X%mem	val;
X	movw	val,%dx
X}
X
Xasm	int outbyte ()
X{
X	outb	(%dx)
X}
X
Xasm	int inbyte ()
X{
X	xorl	%eax,%eax
X	inb	(%dx)
X}
X
X/* The port parameter of the `outb' macro must be one of the predefined
X   port macros from `fas.h' or a simple uint variable (no indirection
X   is allowed). Additionally, `fip' must be a register variable in the
X   functions where `outb' is used. This prevents the destruction of the
X   `eax' CPU register while loading the `edx' register with the port
X   address. This is highly compiler implementation specific.
X*/
X#define outb(port,val) (regvar = (val), loadal (regvar), regvar = (port), loaddx (regvar), outbyte ())
X
X#define inb(port) (regvar = (port), loaddx (regvar), inbyte ())
X
X#define REGVAR register uint	regvar
X
X/* This function inserts the address optimization assembler pseudo-op
X   wherever called.
X*/
X
Xasm	void optim ()
X{
X	.optim
X}
X
X/* This dummy function has nothing to do but to call optim so that
X   the `.optim' assembler pseudo-op will be included in the assembler
X   file. This must be the first of all functions.
X*/
X
X#if defined (OPTIM)	/* Define for uPort, ISC doesn't know about */
Xstatic void		/* `.optim', but has turned on optimization by */
Xdummy ()		/* default, so we don't need it there anyway. */
X{
X	optim ();
X}
X#endif
X#endif	/* XENIX || NO_ASM */
X
X/* functions provided by this driver */
Xint		fasinit ();
Xint		fasopen ();
Xint		fasclose ();
Xint		fasread ();
Xint		faswrite ();
Xint		fasioctl ();
Xint		fasintr ();
X#if defined (NEED_PUT_GETCHAR)
Xint		asyputchar ();
Xint		asygetchar ();
X#endif
X#if defined (NEED_INIT8250)
Xint		init8250 ();
X#endif
Xstatic int	fas_proc ();
Xstatic void	fas_param ();
Xstatic void	fas_fproc ();
Xstatic void	fas_mproc ();
Xstatic uint	fas_rproc ();
Xstatic void	fas_xproc ();
Xstatic void	fas_event ();
X#if defined (HAVE_VPIX)
Xstatic int	fas_vpix_sr ();
X#endif
Xstatic void	fas_rxfer ();
Xstatic void	fas_xxfer ();
Xstatic void	fas_ihlw_check ();
Xstatic void	fas_hdx_check ();
Xstatic void	fas_hangup ();
Xstatic void	fas_timeout ();
Xstatic void	fas_cmd ();
Xstatic void	fas_open_device ();
Xstatic void	fas_close_device ();
Xstatic uint	fas_make_ctl_val ();
Xstatic int	fas_test_device ();
X
X/* external functions used by this driver */
Xextern int	ttinit ();
Xextern int	ttiocom ();
Xextern int	ttyflush ();
Xextern int	SPLINT ();
Xextern int	SPLWRK ();
Xextern int	splx ();
Xextern int	sleep ();
Xextern int	wakeup ();
Xextern void	longjmp ();
Xextern int	signal ();
Xextern int	timeout ();
Xextern int	untimeout ();
Xextern int	printf ();
X#if defined (SCO) || defined (XENIX)
Xextern int	printcfg ();
X#endif
X#if defined (HAVE_VPIX)
Xextern int	fubyte ();
Xextern int	subyte ();
Xextern int	v86setint ();
X#endif
X#if defined (XENIX)
Xextern int	inb ();
Xextern int	outb ();
X#endif
X
X/* external data objects used by this driver */
Xextern int	tthiwat [];
X
X/* the following stuff is defined in space.c */
Xextern uint	fas_physical_units;
Xextern ulong	fas_port [];
Xextern uint	fas_vec [];
Xextern uint	fas_init_seq [];
Xextern uint	fas_mcb [];
Xextern ulong	fas_modem [];
Xextern ulong	fas_flow [];
Xextern uint	fas_ctl_port [];
Xextern uint	fas_ctl_val [];
Xextern uint	fas_int_ack_port [];
Xextern uint	fas_int_ack [];
Xextern struct fas_info	fas_info [];
Xextern struct tty	fas_tty [];
Xextern struct fas_info	*fas_info_ptr [];
Xextern struct tty	*fas_tty_ptr [];
X/* end of space.c references */
X
X/* fas_is_initted
X   Flag to indicate that we have been thru 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*/
Xstatic int	fas_is_initted = FALSE;
X
X/* event_scheduled
X   Flag to indicate that the event handler has been scheduled
X   via the timeout() function.
X*/
Xstatic int	event_scheduled = FALSE;
X
X/* array of pointers to the first fas_info structure for each
X   interrupt vector
X*/
Xstatic struct fas_info	*fas_first_int_user [NUM_INT_VECTORS];
X
X/* the values for the various baud rates */
Xstatic uint	fas_speeds [CBAUD + 1] =
X{	1,			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/* time for one character to completely leave the transmitter shift register */
Xstatic uint	fas_ctimes [CBAUD + 1] =
X{	1,		HZ*15/50+2,
X	HZ*15/75+2,	HZ*15/110+2,
X	HZ*30/269+2,	HZ*15/150+2,
X	HZ*15/200+2,	HZ*15/300+2,
X	HZ*15/600+2,	HZ*15/1200+2,
X	HZ*15/1800+2,	HZ*15/2400+2,
X	HZ*15/4800+2,	HZ*15/9600+2,
X	HZ*15/19200+2,	HZ*15/38400+2
X};
X
X/* dynamically adapt xmit buffer size to baud rate to prevent long buffer
X   drains at low speeds
X   These values are checked against boundaries and will be modified if
X   necessary before use. Checking is done in fas_param (). Drain time
X   is about 5 seconds with continuous character flow.
X*/
Xstatic uint	fas_xbuf_size [CBAUD + 1] =
X{	1,		50/2,
X	75/2,		110/2,
X	269/4,		150/2,
X	200/2,		300/2,
X	600/2,		1200/2,
X	1800/2,		2400/2,
X	4800/2,		9600/2,
X	19200/2,	38400/2
X};
X
X/* lookup table for minor device number -> open mode flags translation */
Xstatic uint	fas_open_modes [16] =
X{
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE
X							| OS_HWI_HANDSHAKE,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_CLOCAL | OS_HWO_HANDSHAKE
X							| OS_HDX_HANDSHAKE,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE
X						| OS_HWI_HANDSHAKE,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE,
X	OS_OPEN_FOR_DIALOUT | OS_FAKE_CARR_ON | OS_HWO_HANDSHAKE
X						| OS_HDX_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE
X							| OS_HWI_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE
X							| OS_HDX_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE
X						| OS_HWI_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE,
X	OS_OPEN_FOR_GETTY | OS_WAIT_OPEN | OS_HWO_HANDSHAKE
X						| OS_HDX_HANDSHAKE
X};
X
X/* The following defines are used to access multiplexed ports. */
X#define GET_PORT(port,num) \
X	((fip->device_flags.i & DF_CTL_EVERY)\
X			? (port)\
X			: (port) + (num))
X
X#define fas_first_ctl(fip,port) \
X	((void) (((fip)->device_flags.i & DF_CTL_FIRST)\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0))
X
X#define fas_ctl(fip,port) \
X	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0))
X
X#define fas_first_outb(fip,port,val) \
X	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0),\
X		(void) outb ((port).addr, (val)))
X
X#define fas_outb(fip,port,val) \
X	((void) (((fip)->device_flags.i & DF_CTL_EVERY)\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0),\
X		(void) outb ((port).addr, (val)))
X
X#define fas_first_inb(fip,port) \
X	((void) (((fip)->device_flags.i & (DF_CTL_FIRST | DF_CTL_EVERY))\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0),\
X		inb ((port).addr))
X
X#define fas_inb(fip,port) \
X	((void) (((fip)->device_flags.i & DF_CTL_EVERY)\
X			? outb (CTL_PORT, (port).p.ctl)\
X			: 0),\
X		inb ((port).addr))
X
X/* The following defines are used to take apart the minor device numbers. */
X#define GET_UNIT(dev)		((dev) & 0x0f)
X#define GET_OPEN_MODE(dev)	(fas_open_modes [((dev) >> 4) & 0x0f])
X
X/* lock device against concurrent use */
X#define get_device_lock(fip,prio) \
X{\
X	/* sleep while device is used by an other process */\
X	while ((fip)->device_flags.i & DF_DEVICE_LOCKED)\
X		(void) sleep ((caddr_t) &(fip)->device_flags.i, (prio));\
X	(fip)->device_flags.s |= DF_DEVICE_LOCKED;\
X}
X
X/* release device */
X#define release_device_lock(fip) \
X{\
X	(fip)->device_flags.s &= ~DF_DEVICE_LOCKED;\
X	/* wakeup the process that may wait for this device */\
X	(void) wakeup ((caddr_t) &(fip)->device_flags.i);\
X}
X
X/* schedule event */
X#define event_sched(fip,event) \
X{\
X	(fip)->event_flags.s |= (event);\
X	if (!event_scheduled)\
X	{\
X		event_scheduled = TRUE;\
X		(void) timeout (fas_event, (void *) NULL,\
X				(EVENT_TIME) * (HZ) / 1000);\
X	}\
X}
X
X/* fasinit
X   This routine checks for the presense of the devices in the fas_port
X   array and if the device is present tests and initializes it.
X   During the initialization if the device is determined to be an
X   NS16550A chip the DF_DEVICE_IS_NS16550A flag is set and the FIFOs will
X   be used. If the device is an i82510 chip the DF_DEVICE_IS_I82510 flag
X   is set and the device will be handled accordingly.
X*/
X
Xint
Xfasinit ()
X{
X	register struct fas_info	*fip;
X	register uint	unit;
X	uint	logical_units, port, *seq_ptr;
X	char	port_stat [MAX_UNITS + 1];
X	REGVAR;
X
X	if (fas_is_initted)
X		return (0);
X
X	fas_is_initted = TRUE;
X
X	/* execute the init sequence for the serial card */
X	for (seq_ptr = fas_init_seq; *seq_ptr; seq_ptr++)
X	{
X		port = *seq_ptr;
X		seq_ptr++;
X		if (*seq_ptr & READ_PORT)
X			(void) inb (port);
X		else
X			(void) outb (port, *seq_ptr);
X	}
X
X	/* setup the list of pointers to the tty structures */
X	for (unit = 0, logical_units = fas_physical_units * 2;
X		unit < logical_units; unit++)
X		fas_tty_ptr [unit] = &fas_tty [unit];
X
X	/* setup and initialize all serial ports */
X	for (unit = 0; unit < fas_physical_units; unit++)
X	{
X		fas_info_ptr [unit] = fip = &fas_info [unit];
X		port_stat [unit] = '-';
X		if (port = (uint) ((ushort) (fas_port [unit])))
X		{
X			/* check the int vector */
X			if (fas_vec [unit] >= NUM_INT_VECTORS)
X			{
X				port_stat [unit] = '>';
X				continue;
X			}
X
X			/* init all of its ports */
X			if (fas_ctl_port [unit])
X			{
X				fip->ctl_port = fas_ctl_port [unit];
X
X				if (fas_ctl_val [unit] & 0xff00)
X					fip->device_flags.s |= DF_CTL_EVERY;
X				else
X					fip->device_flags.s |= DF_CTL_FIRST;
X			}
X
X			fip->port_0.p.addr = GET_PORT (port, 0);
X			fip->port_1.p.addr = GET_PORT (port, 1);
X			fip->port_2.p.addr = GET_PORT (port, 2);
X			fip->port_3.p.addr = GET_PORT (port, 3);
X			fip->port_4.p.addr = GET_PORT (port, 4);
X			fip->port_5.p.addr = GET_PORT (port, 5);
X			fip->port_6.p.addr = GET_PORT (port, 6);
X			fip->port_0.p.ctl = fas_make_ctl_val (fip, unit, 0);
X			fip->port_1.p.ctl = fas_make_ctl_val (fip, unit, 1);
X			fip->port_2.p.ctl = fas_make_ctl_val (fip, unit, 2);
X			fip->port_3.p.ctl = fas_make_ctl_val (fip, unit, 3);
X			fip->port_4.p.ctl = fas_make_ctl_val (fip, unit, 4);
X			fip->port_5.p.ctl = fas_make_ctl_val (fip, unit, 5);
X			fip->port_6.p.ctl = fas_make_ctl_val (fip, unit, 6);
X			fip->vec = fas_vec [unit];
X			fip->modem.l = fas_modem [unit];
X			fip->flow.l = fas_flow [unit];
X
X			/* mask off invalid bits */
X			fip->modem.m.di &= MC_ANY_CONTROL;
X			fip->modem.m.eo &= MC_ANY_CONTROL;
X			fip->modem.m.ei &= MC_ANY_CONTROL;
X			fip->modem.m.ca &= MS_ANY_PRESENT;
X			fip->flow.m.ic &= MC_ANY_CONTROL;
X			fip->flow.m.oc &= MS_ANY_PRESENT;
X			fip->flow.m.oe &= MS_ANY_PRESENT;
X			fip->flow.m.hc &= MC_ANY_CONTROL;
X
X			fip->recv_ring_put_ptr = fip->recv_buffer;
X			fip->recv_ring_take_ptr = fip->recv_buffer;
X			fip->xmit_ring_put_ptr = fip->xmit_buffer;
X			fip->xmit_ring_take_ptr = fip->xmit_buffer;
X			fip->xmit_fifo_size = 1;
X
X			fip->ier = IE_NONE;	/* disable all ints */
X			fas_first_outb (fip, INT_ENABLE_PORT, fip->ier);
X
X			/* is there a serial chip ? */
X			if (fas_inb (fip, INT_ENABLE_PORT) != fip->ier)
X			{
X				port_stat [unit] = '?';
X				continue;	/* a hardware error */
X			}
X
X			/* test the chip thoroughly */
X			if ((port_stat [unit] = (fas_test_device (fip) + '0'))
X				!= '0')
X			{
X				continue;	/* a hardware error */
X			}
X
X			fip->lcr = 0;
X			fas_outb (fip, LINE_CTL_PORT, fip->lcr);
X			fip->mcr = fas_mcb [unit] | fip->modem.m.di;
X			fas_outb (fip, MDM_CTL_PORT, fip->mcr);
X
X			port_stat [unit] = '*';
X
X			/* let's see if it's an NS16550A */
X			fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_INIT_CMD);
X			if (!(~fas_inb (fip, INT_ID_PORT) & II_NS_FIFO_ENABLED))
X			{
X				fip->device_flags.s |= DF_DEVICE_IS_NS16550A;
X				fip->xmit_fifo_size = OUTPUT_NS_FIFO_SIZE;
X				port_stat [unit] = 'F';
X				fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X			}
X			else
X			{
X				fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
X				/* or is it an i82510 ? */
X				fas_outb (fip, I_BANK_PORT, I_BANK_2);
X				if (!(~fas_inb (fip, I_BANK_PORT) & I_BANK_2))
X				{
X					fip->device_flags.s |= DF_DEVICE_IS_I82510;
X					fip->xmit_fifo_size = OUTPUT_I_FIFO_SIZE;
X					port_stat [unit] = 'f';
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				}
X				fas_outb (fip, I_BANK_PORT, I_BANK_0);
X			}
X
X			/* disable FIFOs if requested in space.c */
X			if ((fas_port [unit] & NO_FIFO) && (fip->device_flags.i
X						& (DF_DEVICE_IS_NS16550A
X							| DF_DEVICE_IS_I82510)))
X			{
X				fip->device_flags.s &= ~(DF_DEVICE_IS_NS16550A
X							| DF_DEVICE_IS_I82510);
X				fip->xmit_fifo_size = 1;
X				port_stat [unit] = '+';
X			}
X
X			/* clear potential 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			if (port = fas_int_ack_port [fip->vec])
X				(void) outb (port, fas_int_ack [fip->vec]);
X
X			/* show that it is present and configured */
X			fip->device_flags.s |= DF_DEVICE_CONFIGURED;
X		}
X	}
X
X#if defined (NEED_PUT_GETCHAR)
X	fip = &fas_info [0];
X	fip->mcr &= ~fip->modem.m.di;
X	fip->mcr |= INITIAL_MDM_CONTROL;
X	fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
X
X	fip->lcr = INITIAL_LINE_CONTROL;
X	fas_outb (fip, LINE_CTL_PORT, fip->lcr | LC_ENABLE_DIVISOR);
X	fas_outb (fip, DIVISOR_LSB_PORT, INITIAL_BAUD_RATE);
X	fas_outb (fip, DIVISOR_MSB_PORT, (INITIAL_BAUD_RATE) >> 8);
X	fas_outb (fip, LINE_CTL_PORT, fip->lcr);
X#endif
X
X#if defined (SCO) || defined (XENIX)
X	for (unit = 0; unit < fas_physical_units; unit++)
X		(void) printcfg ("fas", (uint) ((ushort) (fas_port [unit])), 7,
X					fas_vec [unit], -1,
X					"unit=%d type=%c release=2.08.0",
X					unit, port_stat [unit]);
X#else
X	port_stat [unit] = '\0';
X	(void) printf ("\nFAS 2.08.0 async driver: Unit 0-%d init state is [%s]\n\n",
X			unit - 1,
X			port_stat);
X#endif
X	return (0);
X}
X
X/* Open a tty line. This function is called for every open, as opposed
X   to the fasclose function which is called only with the last close.
X*/
Xint
Xfasopen (dev, flag)
Xint	dev;
Xint	flag;
X{
X	register struct fas_info	*fip;
X	register struct tty		*ttyp;
X	register uint	open_mode;
X	uint	physical_unit;
X	int	old_level;
X
X	physical_unit = GET_UNIT (dev);
X
X	/* check for valid port number */
X	if (physical_unit >= fas_physical_units)
X	{
X		u.u_error = ENXIO;
X		return (-1);
X	}
X
X	fip = fas_info_ptr [physical_unit];
X
X	/* was the port present at init time ? */
X	if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
X	{
X		u.u_error = ENXIO;
X		return (-1);
X	}
X
X	open_mode = GET_OPEN_MODE (dev);
X
X	old_level = SPLINT ();
X	get_device_lock (fip, TTIPRI);
X
X	/* If this is a getty open, the device is already open for
X           dialout and the FNDELAY flag is not set, wait until device
X           is closed.
X	*/
X	while ((open_mode & OS_OPEN_FOR_GETTY)
X			&& (fip->o_state & OS_OPEN_FOR_DIALOUT)
X			&& !(flag & FNDELAY))
X	{
X		release_device_lock (fip);
X		(void) sleep ((caddr_t) &fip->o_state, TTIPRI);
X		get_device_lock (fip, TTIPRI);
X	}
X	
X	/* If the device is already open and another open uses a different
X	   open mode or if a getty open waits for carrier and doesn't allow
X	   parallel dialout opens, return with EBUSY error.
X	*/
X	if ((fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY)
X				? (OS_OPEN_STATES | OS_WAIT_OPEN)
X				: (OS_OPEN_STATES | OS_NO_DIALOUT)))
X		&& ((flag & FEXCL)
X			|| ((open_mode ^ fip->o_state) & (u.u_uid
X						? OS_TEST_MASK
X						: OS_SU_TEST_MASK))))
X	{
X		u.u_error = EBUSY;
X		release_device_lock (fip);
X		(void) splx (old_level);
X		return (-1);
X	}
X
X	/* disable subsequent opens */
X	if (flag & FEXCL)
X		open_mode |= OS_EXCLUSIVE_OPEN_1;
X
X	/* set up pointer to tty structure */
X	ttyp = (open_mode & OS_OPEN_FOR_GETTY)
X		? fas_tty_ptr [physical_unit + fas_physical_units]
X		: fas_tty_ptr [physical_unit];
X
X	/* things to do on first open only */
X	if (!(fip->o_state & ((open_mode & OS_OPEN_FOR_GETTY)
X				? (OS_OPEN_STATES | OS_WAIT_OPEN)
X				: OS_OPEN_STATES)))
X	{
X		/* init data structures */
X		fip->tty = ttyp;
X		(void) ttinit (ttyp);
X		ttyp->t_proc = fas_proc;
X		fip->po_state = fip->o_state;
X		fip->o_state = open_mode & ~OS_OPEN_STATES;
X#if defined (HAVE_VPIX)
X		/* initialize VP/ix related variables */
X		fip->v86_proc = (v86_t *) NULL;
X		fip->v86_intmask = 0;
X		fip->v86_ss.ss_start = CSTART;
X		fip->v86_ss.ss_stop = CSTOP;
X#endif
X		fas_open_device (fip);		/* open physical device */
X		fas_param (fip, HARD_INIT);	/* set up port registers */
X
X		/* allow pending tty interrupts */
X		(void) SPLWRK ();
X		(void) SPLINT ();
X	}
X
X	/* If getty open and the FNDELAY flag is not set,
X	   block and wait for carrier if device not yet open.
X	*/
X	if ((open_mode & OS_OPEN_FOR_GETTY) && !(flag & FNDELAY))
X	{
X		/* sleep while open for dialout or no carrier */
X		while ((fip->o_state & OS_OPEN_FOR_DIALOUT)
X			|| !(ttyp->t_state & (ISOPEN | CARR_ON)))
X		{
X			ttyp->t_state |= WOPEN;
X			release_device_lock (fip);
X			(void) sleep ((caddr_t) &ttyp->t_canq, TTIPRI);
X			get_device_lock (fip, TTIPRI);
X		}
X		ttyp->t_state &= ~WOPEN;
X	}
X
X	/* wakeup processes that are still sleeping in getty open */
X	if (ttyp->t_state & WOPEN)
X		(void) wakeup ((caddr_t) &ttyp->t_canq);
X
X	/* we need to flush the receiver with the first open */
X	if (!(fip->o_state & OS_OPEN_STATES))
X		fas_cmd (fip, ttyp, T_RFLUSH);
X
X	(*linesw [ttyp->t_line].l_open) (ttyp);
X
X	/* set open type flags */
X	fip->o_state = open_mode;
X
X	release_device_lock (fip);
X	(void) splx (old_level);
X	return (0);
X}
X
X/* Close a tty line. This is only called if there is no other
X   concurrent open left. A blocked getty open is not counted as
X   a concurrent open because in this state it isn't really open.
X*/
Xint
Xfasclose (dev)
Xint	dev;
X{
X	register struct fas_info	*fip;
X	register struct tty		*ttyp;
X	uint	physical_unit;
X	uint	open_mode;
X	int	old_level;
X	void	(*old_sigkill)();
X
X	physical_unit = GET_UNIT (dev);
X
X	fip = fas_info_ptr [physical_unit];
X
X	open_mode = GET_OPEN_MODE (dev);
X
X	/* set up pointer to tty structure */
X	ttyp = (open_mode & OS_OPEN_FOR_GETTY)
X		? fas_tty_ptr [physical_unit + fas_physical_units]
X		: fas_tty_ptr [physical_unit];
X	
X	old_level = SPLINT ();
X	get_device_lock (fip, TTIPRI);
X
X	/* wait for output buffer drain only if device was open */
X	if (ttyp->t_state & ISOPEN)
X	{
X		/* flush the output buffer immediately if the device
X		   has been shut down because of an error
X		*/
X		if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
X		{
X			(void) ttyflush (ttyp, FWRITE);
X		}
X		/* wait for buffer drain and catch interrupts */
X		while (ttyp->t_outq.c_cc || (ttyp->t_state & (BUSY | TIMEOUT)))
X		{
X			old_sigkill = u.u_signal [SIGKILL - 1];
X			/* allow kill signal if close on exit */
X			if (old_sigkill == SIG_IGN)
X				u.u_signal [SIGKILL - 1] = SIG_DFL;
X			ttyp->t_state |= TTIOW;
X			if (sleep ((caddr_t) &ttyp->t_oflag, TTOPRI | PCATCH))
X			{
X				/* caught signal */
X				ttyp->t_state &= ~TTIOW;
X				/* If close on exit, flush output buffer to
X				   allow completion of the fasclose() function.
X				   Otherwise, do the normal signal handling.
X				*/
X				if (old_sigkill == SIG_IGN)
X					(void) ttyflush (ttyp, FWRITE);
X				else
X				{
X					release_device_lock (fip);
X					(void) splx (old_level);
X					longjmp (u.u_qsav);
X				}
X			}
X			if (old_sigkill == SIG_IGN)
X				u.u_signal [SIGKILL - 1] = old_sigkill;
X		}
X	}
X
X	(*linesw [ttyp->t_line].l_close) (ttyp);
X
X	/* allow pending tty interrupts */
X	(void) SPLWRK ();
X	(void) SPLINT ();
X
X	if (open_mode & OS_OPEN_FOR_GETTY)
X	{
X		/* not waiting any more */
X		ttyp->t_state &= ~WOPEN;
X		if (!(fip->o_state & OS_OPEN_FOR_DIALOUT))
X		{
X			fas_close_device (fip);
X			fip->o_state = OS_DEVICE_CLOSED;
X		}
X		else
X			fip->po_state = OS_DEVICE_CLOSED;
X	}
X	else
X	{
X		fas_close_device (fip);
X		fip->o_state = OS_DEVICE_CLOSED;
X		/* If there is a waiting getty open on
X		   this port, reopen the physical device.
X		*/
X		if (fip->po_state & OS_WAIT_OPEN)
X		{
X			/* get the getty version of the
X			   tty structure
X			*/
X			fip->tty = fas_tty_ptr [physical_unit
X					+ fas_physical_units];
X			fip->o_state = fip->po_state;
X			fip->po_state = OS_DEVICE_CLOSED;
X#if defined (HAVE_VPIX)
X			/* initialize VP/ix related variables */
X			fip->v86_proc = (v86_t *) NULL;
X			fip->v86_intmask = 0;
X			fip->v86_ss.ss_start = CSTART;
X			fip->v86_ss.ss_stop = CSTOP;
X#endif
X			if (!(fip->device_flags.i & DF_DO_HANGUP))
X			{
X				fas_open_device (fip);
X				/* set up port registers */
X				fas_param (fip, HARD_INIT);
X			}
X		}
X		(void) wakeup ((caddr_t) &fip->o_state);
X	}
X
X	if (!(fip->device_flags.i & DF_DO_HANGUP))
X		release_device_lock (fip);
X
X	(void) splx (old_level);
X	return (0);
X}
X
X/* read characters from the input buffer */
Xint
Xfasread (dev)
Xint	dev;
X{
X	register struct fas_info	*fip;
X	register struct tty	*ttyp;
X	int	old_level;
X
X	fip = fas_info_ptr [GET_UNIT (dev)];
X
X	/* was the port present at init time ? */
X	if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
X	{
X		u.u_error = ENXIO;
X		return (-1);
X	}
X
X	ttyp = fip->tty;
X
X	(*linesw [ttyp->t_line].l_read) (ttyp);
X
X	old_level = SPLINT ();
X
X	/* schedule character transfer to UNIX buffer */
X	if (fip->recv_ring_cnt
X#if defined (HAVE_VPIX)
X		&& (((fip->iflag & DOSMODE)
X			? MAX_VPIX_FILL - MIN_READ_CHUNK
X			: MAX_UNIX_FILL - MIN_READ_CHUNK)
X				>= ttyp->t_rawq.c_cc)
X#else
X		&& ((MAX_UNIX_FILL - MIN_READ_CHUNK) >= ttyp->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	(void) splx (old_level);
X	return (0);
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
X	/* was the port present at init time ? */
X	if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
X	{
X		u.u_error = ENXIO;
X		return (-1);
X	}
X
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
X	/* was the port present at init time ? */
X	if (!(fip->device_flags.i & DF_DEVICE_CONFIGURED))
X	{
X		u.u_error = ENXIO;
X		return (-1);
X	}
X
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) | (uint) ((unchar) 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			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)))
SHAR_EOF
true || echo 'restore of fas.c failed'
fi
echo 'End of fas208 part 2'
echo 'File fas.c is continued in part 3'
echo 3 > _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