gemini@geminix.in-berlin.de (Uwe Doering) (02/04/91)
Submitted-by: gemini@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@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@utower.UUCP) and Kritt Gierlewsen (kritt@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@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@mecky.systemware.de) and Frank Simon X (terra@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@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@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@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@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@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@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@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@geminix.in-berlin.de Berlin |---------------------------------------------------------------- Germany | UUCP : ...!unido!fub!geminix.in-berlin.de!gemini