home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky comp.unix.sysv386:13240 comp.unix.xenix.sco:2697 alt.sources:1886
- Newsgroups: comp.unix.sysv386,comp.unix.xenix.sco,alt.sources
- Path: sparky!uunet!mcsun!Germany.EU.net!news.netmbx.de!zrz.tu-berlin.de!math.fu-berlin.de!fub!geminix.in-berlin.de!gemini
- From: gemini@geminix.in-berlin.de (Uwe Doering)
- Subject: FAS 2.10 async driver, part 3/5
- Organization: Private UNIX Site
- Date: Mon, 17 Aug 1992 11:38:06 GMT
- Message-ID: <F555HSC@geminix.in-berlin.de>
- Lines: 2304
-
- Submitted-by: gemini@geminix.in-berlin.de
- Archive-name: fas210/part03
-
- #!/bin/sh
- # this is fas210.03 (part 3 of fas210)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file config-ast4c12 continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 3; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping config-ast4c12'
- else
- echo 'x - continuing file config-ast4c12'
- sed 's/^X//' << 'SHAR_EOF' >> 'config-ast4c12' &&
- 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
- echo 'File config-ast4c12 is complete' &&
- true || echo 'restore of config-ast4c12 failed'
- rm -f _shar_wnt_.tmp
- fi
- # ============= config-c12 ==============
- if test -f 'config-c12' -a X"$1" != X"-c"; then
- echo 'x - skipping config-c12 (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting config-c12 (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'config-c12' &&
- 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-c12 failed'
- rm -f _shar_wnt_.tmp
- fi
- # ============= config-c123 ==============
- if test -f 'config-c123' -a X"$1" != X"-c"; then
- echo 'x - skipping config-c123 (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting config-c123 (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'config-c123' &&
- 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-c123 failed'
- rm -f _shar_wnt_.tmp
- fi
- # ============= config-digi8c1 ==============
- if test -f 'config-digi8c1' -a X"$1" != X"-c"; then
- echo 'x - skipping config-digi8c1 (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting config-digi8c1 (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'config-digi8c1' &&
- 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,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-digi8c1 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.10"
- X#endif
- X
- X/* Note: This source code has been quite heavily optimized for speed.
- X You 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). Therefore,
- 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 [34].X/386 C compiler.
- X*/
- X
- X#if defined (XENIX)
- X
- X#include "fas.h"
- X#if defined (__GNUC__) && !defined (NO_ASM)
- X#define outb(port,val) \
- X({\
- X __asm__ volatile ("outb %1,%0" : : "d" ((ushort) (port)), "a" ((unchar) (val)));\
- X})
- X
- X#define inb(port) \
- X({\
- X unchar __val;\
- X __asm__ volatile ("inb %1,%0" : "=a" (__val) : "d" ((ushort) (port)));\
- X __val;\
- X})
- X#endif /* __GNUC__ && !NO_ASM */
- X#define REGVAR
- X
- X#else /* XENIX */
- X
- X#include <sys/fas.h>
- X#if defined (__GNUC__)
- X#if !defined (NO_ASM)
- X#if defined (SCO)
- X#define outb(port,val) \
- X({\
- X __asm__ volatile ("outb %1,%0" : : "d" ((ushort) (port)), "a" ((unchar) (val)));\
- X})
- X
- X#define inb(port) \
- X({\
- X unchar __val;\
- X __asm__ volatile ("inb %1,%0" : "=a" (__val) : "d" ((ushort) (port)));\
- X __val;\
- X})
- X#else /* SCO */
- X#define outb(port,val) \
- X({\
- X __asm__ volatile ("outb (%0)" : : "d" ((ushort) (port)), "a" ((unchar) (val)));\
- X})
- X
- X#define inb(port) \
- X({\
- X unchar __val;\
- X __asm__ volatile ("inb (%1)" : "=a" (__val) : "d" ((ushort) (port)));\
- X __val;\
- X})
- X#endif /* SCO */
- X#endif /* !NO_ASM */
- X
- X#define REGVAR
- X#else /* __GNUC__ */
- X#if !defined (NO_ASM)
- X#include <sys/inline.h>
- X
- 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 [34].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 /* OPTIM */
- X#else /* !NO_ASM */
- X#define REGVAR
- X#endif /* !NO_ASM */
- X#endif /* __GNUC__ */
- X
- X#endif /* XENIX */
- X
- X#if defined (SCO) || defined (XENIX)
- X#define asyputchar sioputchar
- X#define asygetchar siogetchar
- X#endif
- 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_mproc ();
- Xstatic void fas_rproc ();
- Xstatic void fas_xproc ();
- Xstatic void fas_event ();
- X#if defined (HAVE_VPIX)
- Xstatic bool fas_vpix_sr ();
- X#endif
- Xstatic void fas_msi_disable ();
- Xstatic void fas_msi_enable ();
- Xstatic void fas_rdi_disable ();
- Xstatic void fas_rdi_enable ();
- Xstatic bool fas_rxfer ();
- Xstatic void fas_xxfer ();
- Xstatic void fas_hwi_start ();
- Xstatic void fas_hwi_stop ();
- Xstatic void fas_send_xon ();
- Xstatic void fas_send_xoff ();
- Xstatic void fas_hdx_start ();
- Xstatic void fas_hangup ();
- Xstatic void fas_timeout ();
- Xstatic void fas_cmd ();
- Xstatic void fas_open_device ();
- Xstatic void fas_close_device ();
- Xstatic void fas_pos_by_speed ();
- Xstatic uint fas_make_ctl_val ();
- Xstatic uint 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 ();
- X#if !defined (SVR4)
- Xextern int signal ();
- X#endif
- Xextern int timeout ();
- Xextern int untimeout ();
- X#if defined (SCO) || defined (XENIX)
- Xextern int printcfg ();
- X#else
- Xextern int printf ();
- X#endif
- X#if defined (HAVE_VPIX)
- Xextern int fubyte ();
- Xextern int subyte ();
- Xextern int v86setint ();
- X#endif
- X#if defined (NO_ASM) || (defined (XENIX) && !defined (__GNUC__))
- Xextern int inb ();
- Xextern int outb ();
- X#endif
- X
- X/* external data objects used by this driver */
- Xextern int tthiwat [];
- Xextern int ttlowat [];
- Xextern int ttyhog;
- X
- X/* the following stuff is defined in space.c */
- Xextern uint fas_physical_units;
- Xextern ulong fas_port [];
- Xextern uint fas_init_seq [];
- Xextern uint fas_int_ack_seq [];
- Xextern uint fas_mcb [];
- Xextern ulong fas_modem [];
- Xextern ulong fas_flow [];
- Xextern uint fas_ctl_port [];
- Xextern uint fas_ctl_val [];
- Xextern struct fas_internals fas_internals [];
- Xextern struct tty fas_tty [];
- Xextern struct fas_internals *fas_internals_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 bool 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 bool event_scheduled = FALSE;
- X
- X/* pointers to the first and last fas_internals structure of the
- X interrupt users chain
- X*/
- Xstatic struct fas_internals *fas_first_int_user, *fas_last_int_user;
- X
- X/* thresholds for the character transfer to the CLIST buffers */
- Xstatic uint max_unix_fill;
- X#if defined (HAVE_VPIX)
- Xstatic uint max_vpix_fill;
- X#endif
- Xstatic uint min_read_chunk;
- X
- X/* counters for receiver overruns, each UART type has its own counter
- X indexed by the device type
- X*/
- Xuint fas_overrun [NUMBER_OF_TYPES];
- X
- X/* counter for temporarily disabled modem status interrupts due
- X to noise on the modem status lines
- X*/
- Xuint fas_msi_noise;
- X
- X/* UNIX to FAS mapping of baud rates (normal speed) */
- Xstatic n_ushort fas_baud [CBAUD + 1] =
- X{ B38400, B50,
- X B75, B110,
- X B134, B150,
- X B200, B300,
- X B600, B1200,
- X B1800, B2400,
- X B4800, B9600,
- X B19200, B38400
- X};
- X
- X/* UNIX to FAS mapping of baud rates (high speed) */
- Xstatic n_ushort fas_hbaud [CBAUD + 1] =
- X{ B0, B50,
- X B75, B110,
- X B134, B150,
- X B200, B300,
- X B600, B1200,
- X B1800, B2400,
- X B4800, B9600,
- X B19200, BHIGHSPEED
- X};
- X
- X/* Note: The baud rate in fas_hbaud that is overridden by BHIGHSPEED
- X has to be entered at fas_baud [0] !
- X
- X Note also: If you want to use a speed different from B38400 for
- X BHIGHSPEED, you have to make sure that the tthiwat [] and
- X ttlowat [] values for that baud rate are high enough
- X to allow the CLIST function to keep the FAS transmit
- X buffer filled. Look at fasinit () on how to do that.
- X*/
- X
- X/* the divisor values for the various baud rates */
- X/* 57600 bps version */
- Xstatic n_ushort fas_speeds1 [CBAUD + 1] =
- X{ BAUD_BASE/57600, 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/* 115200 bps version */
- Xstatic n_ushort fas_speeds2 [CBAUD + 1] =
- X{ BAUD_BASE/115200, 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 */
- X/* 57600 bps version */
- Xstatic n_ushort fas_ctimes1 [CBAUD + 1] =
- X{ HZ*15/57600+2, 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/* time for one character to completely leave the transmitter shift register */
- X/* 115200 bps version */
- Xstatic n_ushort fas_ctimes2 [CBAUD + 1] =
- X{ HZ*15/115200+2, 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 2 seconds with continuous character flow.
- X*/
- X/* 57600 bps version */
- Xstatic n_ushort fas_xbuf_size1 [CBAUD + 1] =
- X{ 57600/5, 50/5,
- X 75/5, 110/5,
- X 269/10, 150/5,
- X 200/5, 300/5,
- X 600/5, 1200/5,
- X 1800/5, 2400/5,
- X 4800/5, 9600/5,
- X 19200/5, 38400/5
- X};
- X
- X/* 115200 bps version */
- Xstatic n_ushort fas_xbuf_size2 [CBAUD + 1] =
- X{ 115200/5, 50/5,
- X 75/5, 110/5,
- X 269/10, 150/5,
- X 200/5, 300/5,
- X 600/5, 1200/5,
- X 1800/5, 2400/5,
- X 4800/5, 9600/5,
- X 19200/5, 38400/5
- X};
- X
- X/* lookup table for minor device number -> open mode flags translation */
- Xstatic n_ushort 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_every_ctl(fip,port) \
- X ((void) (((fip)->device_flags.i & DF_CTL_EVERY)\
- 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_same_outb(fip,port,val) \
- 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#define fas_same_inb(fip,port) \
- 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, (caddr_t) NULL, 1);\
- 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 the device type is automatically determined
- X and the UART is handled according to its requirements.
- X*/
- X
- Xint
- Xfasinit ()
- X{
- X register struct fas_internals *fip;
- X register uint unit;
- X uint logical_units, port, *seq_ptr;
- X uint baud_rate;
- X int max_tthiwat, max_ttlowat;
- 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 /* kludge to make sure that the tty buffer high water levels
- X for fast baud rates are high enough to ensure max. throughput
- X */
- X for (baud_rate = B50, max_tthiwat = 0; baud_rate <= B38400; ++baud_rate)
- X {
- X if (tthiwat [baud_rate] >= max_tthiwat)
- X {
- X max_tthiwat = tthiwat [baud_rate];
- X max_ttlowat = ttlowat [baud_rate];
- X }
- X else
- X {
- X tthiwat [baud_rate] = max_tthiwat;
- X ttlowat [baud_rate] = max_ttlowat;
- X }
- X }
- X
- X /* initialize thresholds for the character transfer to
- X the CLIST buffers
- X */
- X max_unix_fill = ttyhog - 1;
- X min_read_chunk = (MIN_READ_CHUNK * 2 > max_unix_fill)
- X ? max_unix_fill / 2
- X : MIN_READ_CHUNK;
- X#if defined (HAVE_VPIX)
- X max_vpix_fill = (MAX_VPIX_FILL > max_unix_fill)
- X ? max_unix_fill
- X : MAX_VPIX_FILL;
- X if (min_read_chunk * 2 > max_vpix_fill)
- X min_read_chunk = max_vpix_fill / 2;
- X#endif
- X
- X /* execute the init sequence for the serial cards */
- X for (seq_ptr = &fas_init_seq [0]; *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_internals_ptr [unit] = fip = &fas_internals [unit];
- X port_stat [unit] = '-';
- X if (port = (uint) ((ushort) (fas_port [unit])))
- 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->modem.l = fas_modem [unit];
- X fip->flow.l = fas_flow [unit];
- X fip->po_state = fip->o_state = OS_DEVICE_CLOSED;
- 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 [0];
- X fip->recv_ring_take_ptr = &fip->recv_buffer [0];
- X fip->xmit_ring_put_ptr = &fip->xmit_buffer [0];
- X fip->xmit_ring_take_ptr = &fip->xmit_buffer [0];
- X
- X /* disable all ints */
- X fas_first_outb (fip, INT_ENABLE_PORT,
- X fip->ier = IE_NONE);
- X
- X /* is there a serial chip ? */
- X if (fas_same_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 (!(fas_port [unit] & NO_TEST)
- X && (port_stat [unit]
- X = (fas_test_device (fip) + '0'))
- X != '0')
- X continue; /* a hardware error */
- X
- X fas_outb (fip, LINE_CTL_PORT, fip->lcr = 0);
- X fas_outb (fip, MDM_CTL_PORT, fip->mcr
- X = fas_mcb [unit] | fip->modem.m.di);
- X
- X fip->device_type = TYPE_NS16450;
- X fip->xmit_fifo_size = 1;
- 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_type = TYPE_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_type = TYPE_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)
- X && (fip->device_type != TYPE_NS16450))
- X {
- X fip->device_type = TYPE_NS16450;
- 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 if (fas_inb (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL)
- X (void) fas_inb (fip, RCV_DATA_PORT);
- X fip->lsr = 0;
- X (void) fas_inb (fip, INT_ID_PORT);
- X
- X /* do we want a high speed port ? */
- X if (fas_port [unit] & HS_115200)
- X fip->device_flags.s |= DF_HIGH_SPEED | DF_115K;
- X else if (fas_port [unit] & HS_57600)
- X fip->device_flags.s |= DF_HIGH_SPEED;
- X
- X /* do we want the fdx meaning of CTSFLOW/RTSFLOW ? */
- X if (fas_port [unit] & NEW_CTSRTS)
- X fip->flow_flags.s |= FF_NEW_CTSRTS;
- X
- X /* show that it is present and configured */
- X fip->device_flags.s |= DF_DEVICE_CONFIGURED;
- X }
- X }
- X
- X /* execute the interrupt acknowledge sequence for the serial cards */
- X for (seq_ptr = &fas_int_ack_seq [0]; *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#if defined (NEED_PUT_GETCHAR)
- X fip = &fas_internals [0];
- X fip->mcr &= ~fip->modem.m.di;
- X fas_first_outb (fip, MDM_CTL_PORT, fip->mcr |= INITIAL_MDM_CONTROL);
- 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 -1, -1,
- X "unit=%d type=%c release=2.10.0",
- X unit, port_stat [unit]);
- X#else
- X port_stat [unit] = '\0';
- X (void) printf ("\nFAS 2.10.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 (called at SPL0)
- X*/
- Xint
- Xfasopen (dev, flag)
- Xint dev;
- Xint flag;
- X{
- X register struct fas_internals *fip;
- X register struct tty *ttyp;
- X register n_ushort open_mode;
- X uint unit;
- X bool have_lock;
- X int old_level;
- X
- X /* check for valid port number */
- X if ((unit = GET_UNIT (dev)) >= fas_physical_units)
- X {
- X u.u_error = ENXIO;
- X return (-1);
- X }
- X
- X fip = fas_internals_ptr [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 have_lock = FALSE;
- X old_level = SPLINT ();
- X
- X /* loop until we've got the device lock and, owning the lock, we've
- X checked whether the current open mode permits us to open the
- X device
- X */
- X for (;;)
- X {
- X /* If this is a getty open, the FNDELAY flag is not set,
- X and the device is already open for dialout, wait until
- X device is closed.
- X */
- X while ((open_mode & OS_OPEN_FOR_GETTY)
- X#if defined (FNONBLOCK)
- X && !(flag & (FNDELAY | FNONBLOCK))
- X#else
- X && !(flag & FNDELAY)
- X#endif
- X && (fip->o_state & OS_OPEN_FOR_DIALOUT))
- X {
- X if (have_lock)
- X {
- X release_device_lock (fip);
- X have_lock = FALSE;
- X }
- X (void) sleep ((caddr_t) &fip->o_state, TTIPRI);
- X }
- X
- X /* If the device is already open and another open uses a
- X different open mode or if a getty open waits for carrier
- X and doesn't allow parallel dialout opens, return with
- X 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 if (have_lock)
- X release_device_lock (fip);
- X (void) splx (old_level);
- X u.u_error = EBUSY;
- X return (-1);
- X }
- X
- X /* If device is already open and the FAPPEND flag is set,
- X flush the output buffers. This may be used to release
- X processes that got stuck in fasclose () during an
- X exit () call.
- X */
- X if ((fip->o_state & OS_OPEN_STATES) && (flag & FAPPEND))
- X {
- X flag &= ~FAPPEND; /* flush only once */
- X (void) SPLWRK ();
- X (void) ttyflush (fip->tty, FWRITE);
- X (void) SPLINT ();
- X }
- X
- X /* if we don't have the device lock, yet, try to get it */
- X if (!have_lock)
- X {
- X if (fip->device_flags.i & DF_DEVICE_LOCKED)
- X {
- X get_device_lock (fip, TTIPRI);
- X have_lock = TRUE;
- X /* we had to sleep for some time to get the
- X lock, therefore, re-check whether the
- X current open mode still permits us to
- X open the device
- X */
- X continue;
- X }
- X else
- X get_device_lock (fip, TTIPRI);
- X }
- X
- X break;
- 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 [unit + fas_physical_units]
- X : fas_tty_ptr [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 /* clear carrier of getty device */
- X if (fip->o_state & OS_WAIT_OPEN)
- X fip->tty->t_state &= ~CARR_ON;
- 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 fas_open_device (fip); /* open physical device */
- 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)
- X#if defined (FNONBLOCK)
- X && !(flag & (FNDELAY | FNONBLOCK)))
- X#else
- X && !(flag & FNDELAY))
- X#endif
- 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 ttyp->t_state &= ~WOPEN;
- X }
- X }
- X
- X /* we can't have concurrent ISOPEN and WOPEN states, so
- X wake up gettys as we are about to set the ISOPEN flag
- X */
- X if (ttyp->t_state & WOPEN)
- X (void) wakeup ((caddr_t) &ttyp->t_canq);
- 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 (called at SPL0)
- X*/
- Xint
- Xfasclose (dev)
- Xint dev;
- X{
- X register struct fas_internals *fip;
- X register struct tty *ttyp;
- X register n_ushort open_mode;
- X uint unit;
- X bool was_signal = FALSE;
- X int old_level;
- X
- X fip = fas_internals_ptr [unit = GET_UNIT (dev)];
- X
- X /* set up pointer to tty structure */
- X ttyp = ((open_mode = GET_OPEN_MODE (dev)) & OS_OPEN_FOR_GETTY)
- X ? fas_tty_ptr [unit + fas_physical_units]
- X : fas_tty_ptr [unit];
- X
- X old_level = SPLINT ();
- X get_device_lock (fip, PZERO - 1);
- X
- X if ((fip->o_state == OS_DEVICE_CLOSED)
- X || ((open_mode & OS_OPEN_FOR_GETTY)
- X && (fip->o_state & OS_OPEN_FOR_DIALOUT)
- X && (fip->po_state == OS_DEVICE_CLOSED)))
- X {
- X /* device is not open on the driver level */
- X release_device_lock (fip);
- X (void) splx (old_level);
- X return (0);
- X }
- X
- X if (!((open_mode & OS_OPEN_FOR_GETTY)
- X && (fip->o_state & OS_OPEN_FOR_DIALOUT)))
- X {
- X /* wait for buffer drain and catch interrupts */
- X while ((ttyp->t_state & CARR_ON) && (ttyp->t_outq.c_cc
- X || (ttyp->t_state & (BUSY | TIMEOUT))))
- X {
- X ttyp->t_state |= TTIOW;
- X if (sleep ((caddr_t) &ttyp->t_oflag, was_signal
- X ? PZERO - 1
- X : TTOPRI | PCATCH))
- X {
- X /* caught signal */
- X was_signal = TRUE;
- X ttyp->t_state &= ~TTIOW;
- X (void) SPLWRK ();
- X (void) ttyflush (ttyp, FWRITE);
- X (void) SPLINT ();
- X }
- 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->device_flags.i,
- X PZERO - 1);
- X
- X ttyp->t_state &= ~(WOPEN | CARR_ON);
- X /* disable receiver data interrupts */
- X if (fip->device_flags.i & DF_RDI_ENABLED)
- X fas_rdi_disable (fip);
- X /* re-link fas_internals structure */
- X fas_pos_by_speed (fip);
- X (void) SPLWRK ();
- X (void) ttyflush (ttyp, FREAD | FWRITE);
- X (void) SPLINT ();
- X }
- X else
- X ttyp->t_state &= ~(WOPEN | CARR_ON);
- X
- X (*linesw [ttyp->t_line].l_close) (ttyp);
- X
- X if (open_mode & OS_OPEN_FOR_GETTY)
- X {
- 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 /* a parallel dialout open is active */
- 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 [unit + fas_physical_units];
- X fip->o_state = fip->po_state;
- X fip->po_state = OS_DEVICE_CLOSED;
- X if (!(fip->device_flags.i & DF_DO_HANGUP))
- X fas_open_device (fip);
- X }
- X
- X /* wake up getty open (if any) */
- 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
- X if (was_signal)
- X#if defined (SVR4)
- X longjmp (&u.u_qsav);
- X#else
- X longjmp (u.u_qsav);
- X#endif
- X
- X return (0);
- X}
- X
- X/* Read characters from the input buffer.
- X (called at SPL0)
- X*/
- Xint
- Xfasread (dev)
- Xint dev;
- X{
- X register struct fas_internals *fip;
- X register struct tty *ttyp;
- X
- X fip = fas_internals_ptr [GET_UNIT (dev)];
- X ttyp = fip->tty;
- X
- X (*linesw [ttyp->t_line].l_read) (ttyp);
- X return (0);
- X}
- X
- X/* Write characters to the output buffer.
- X (called at SPL0)
- X*/
- Xint
- Xfaswrite (dev)
- Xint dev;
- X{
- X register struct fas_internals *fip;
- X register struct tty *ttyp;
- X
- X fip = fas_internals_ptr [GET_UNIT (dev)];
- X ttyp = fip->tty;
- X
- X (*linesw [ttyp->t_line].l_write) (ttyp);
- X return (0);
- X}
- X
- X/* Process ioctl calls.
- X (called at SPL0)
- X*/
- Xint
- Xfasioctl (dev, cmd, arg3, arg4)
- Xint dev;
- Xint cmd;
- Xunion ioctl_arg arg3;
- Xint arg4;
- X{
- X register struct fas_internals *fip;
- X register struct tty *ttyp;
- X int v86_cmd, v86_data;
- X int old_level;
- X REGVAR;
- X
- X fip = fas_internals_ptr [GET_UNIT (dev)];
- X ttyp = fip->tty;
- X
- X /* process ioctl commands */
- X switch (cmd)
- X {
- X#if defined (HAVE_VPIX)
- X case AIOCINTTYPE: /* set pseudorupt type */
- X switch (arg3.iarg)
- X {
- X case V86VI_KBD:
- X case V86VI_SERIAL0:
- X case V86VI_SERIAL1:
- X old_level = SPLINT ();
- X fip->v86_intmask = arg3.iarg;
- X (void) splx (old_level);
- X break;
- X
- X default:
- X old_level = SPLINT ();
- X fip->v86_intmask = V86VI_SERIAL0;
- X (void) splx (old_level);
- 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_rval1 = 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_rval1 = 0;
- X break;
- X
- X case AIOCSERIALOUT: /* setup port registers for dos */
- X if (fip->iflag & DOSMODE)
- 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 old_level = SPLINT ();
- 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 (void) splx (old_level);
- 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 old_level = SPLINT ();
- 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 (void) splx (old_level);
- X }
- X /* set lcr requested */
- X if (v86_cmd & SIO_MASK (SO_LCR))
- X {
- X v86_data = fubyte (arg3.cparg + SO_LCR);
- X old_level = SPLINT ();
- X fip->lcr = v86_data
- X & ~LC_ENABLE_DIVISOR;
- X fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);
- X (void) splx (old_level);
- 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 fip->mcr
- X |= fip->flow.m.hc;
- X else
- X fip->mcr
- X &= ~fip->flow.m.hc;
- 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)
- 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 old_level = SPLINT ();
- X fip->start_char =
- X ((struct termss *) &arg3.iarg)->ss_start;
- X fip->stop_char =
- X ((struct termss *) &arg3.iarg)->ss_stop;
- X (void) splx (old_level);
- X break;
- X
- X case AIOCINFO: /* show what type of device we are */
- X u.u_rval1 = ('a' << 8) | GET_UNIT (dev);
- X break;
- X#endif
- X#if defined (RTS_TOG)
- X case RTS_TOG: /* set hardware handshake output */
- X if (arg3.iarg == 0)
- X {
- X /* low level */
- X old_level = SPLINT ();
- X /* set hardware handshake output only if unused */
- X if (!(fip->flow_flags.i & (FF_HWI_HANDSHAKE
- X | FF_HDX_HANDSHAKE
- X | FF_DEF_HHO_LOW))
- X#if defined (HAVE_VPIX)
- X && !(fip->iflag & DOSMODE)
- X#endif
- X )
- X {
- X fas_first_outb (fip, MDM_CTL_PORT,
- X fip->mcr &= ~fip->flow.m.hc);
- X }
- X fip->flow_flags.s |= FF_DEF_HHO_LOW;
- X (void) splx (old_level);
- X }
- X else if (arg3.iarg == 1)
- X {
- X /* high level */
- X old_level = SPLINT ();
- X /* set hardware handshake output only if unused */
- X if ((fip->flow_flags.i & (FF_HWI_HANDSHAKE
- X | FF_HDX_HANDSHAKE
- X | FF_DEF_HHO_LOW))
- X == FF_DEF_HHO_LOW
- X#if defined (HAVE_VPIX)
- X && !(fip->iflag & DOSMODE)
- X#endif
- X )
- X {
- X fas_first_outb (fip, MDM_CTL_PORT,
- X fip->mcr |= fip->flow.m.hc);
- X }
- X fip->flow_flags.s &= ~FF_DEF_HHO_LOW;
- X (void) splx (old_level);
- X }
- X break;
- X#endif
- X default: /* default ioctl processing */
- X /* If it is a TCSETA* command, call fas_param ().
- X There is a bug in ttiocom with TCSELE. It
- X always tells the tty driver to reprogram the
- X port. This will cause lost input characters.
- X So we don't do it. SCO UNIX and Xenix use
- X IOC_SELECT instead of TCSELE!
- X */
- X#if defined (TCSELE)
- X if (ttiocom (ttyp, cmd, arg3, arg4) && cmd != TCSELE)
- X#else
- X#if defined (IOC_SELECT)
- X if (ttiocom (ttyp, cmd, arg3, arg4)
- X && cmd != IOC_SELECT)
- X#else
- X if (ttiocom (ttyp, cmd, arg3, arg4))
- X#endif
- X#endif
- X {
- X /* reprogram the port */
- X old_level = SPLINT ();
- X fas_param (fip, SOFT_INIT);
- X (void) splx (old_level);
- X }
- X /* restart input if we are in cooked mode */
- X if (fip->recv_ring_cnt
- X && (ttyp->t_line || (ttyp->t_lflag & ICANON)))
- X {
- X old_level = SPLINT ();
- X event_sched (fip, EF_DO_RXFER);
- X (void) splx (old_level);
- X }
- X break;
- X }
- X return (0);
- X}
- X
- X/* Pass FAS commands to the FAS multi-function procedure.
- X (called at SPL0)
- X*/
- Xstatic int
- Xfas_proc (ttyp, arg2)
- Xstruct tty *ttyp;
- Xint arg2;
- X{
- X register uint unit;
- X int old_level;
- X
- X unit = ttyp - &fas_tty [0];
- X if (unit >= fas_physical_units)
- X unit -= fas_physical_units;
- X
- X old_level = SPLINT ();
- X fas_cmd (fas_internals_ptr [unit], ttyp, arg2);
- X (void) splx (old_level);
- X return (0);
- X}
- X
- X/* Set up a port according to the given termio structure.
- X (called at >= SPLINT)
- X*/
- Xstatic void
- Xfas_param (fip, init_type)
- Xregister struct fas_internals *fip;
- Xint init_type;
- X{
- X register n_ushort cflag;
- X n_ushort fake_cflag;
- X n_ushort divisor;
- X int xmit_ring_size;
- X bool do_flush;
- X int old_level;
- X REGVAR;
- X
- X cflag = fip->tty->t_cflag;
- X fip->iflag = fip->tty->t_iflag;
- X do_flush = FALSE;
- X
- X#if defined (HAVE_VPIX)
- X /* we don't set port registers if we are in dos mode */
- X if (fip->iflag & DOSMODE)
- X {
- X /* This is a kludge. We don't know what baud rate
- X DOS will use. Therefore, we assume a rather low
- X one to be on the safe side.
- X */
- X cflag = (cflag & ~CBAUD) | B300;
- X goto setflags2;
- X }
- X#endif
- X /* Make sure that we have a valid baud rate. If we don't
- X get one, take the previous baud rate.
- X */
- X fake_cflag = (cflag & ~CBAUD)
- X | (((cflag & CBAUD) == B0)
- X ? (fip->cflag & CBAUD)
- X : (fip->device_flags.i & DF_HIGH_SPEED)
- X ? fas_hbaud [cflag & CBAUD]
- X : fas_baud [cflag & CBAUD]);
- X
- X /* if soft init mode: don't set port registers if cflag didn't change */
- X if ((init_type == SOFT_INIT)
- X && !((cflag ^ ((fip->cflag & ~CBAUD)
- X | ((fip->device_flags.i & DF_MODEM_ENABLED)
- X ? fas_baud [fip->cflag & CBAUD]
- X : B0)))
- X & (CBAUD | CSIZE | CSTOPB | PARENB | PARODD)))
- X {
- X cflag = fake_cflag;
- X goto setflags;
- X }
- X
- X /* hangup line if it is baud rate 0, else enable line */
- X if ((cflag & CBAUD) == B0)
- X {
- X if (fip->device_flags.i & DF_MODEM_ENABLED)
- X {
- X fip->mcr &= (fip->o_state & OS_WAIT_OPEN)
- X ? ~fip->modem.m.ei
- X : ~fip->modem.m.eo;
- X fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
- X fip->device_flags.s &= ~DF_MODEM_ENABLED;
- X }
- X }
- X else
- X {
- X if (!(fip->device_flags.i & DF_MODEM_ENABLED))
- X {
- X fip->mcr |= (fip->o_state & OS_WAIT_OPEN)
- X ? fip->modem.m.ei
- X : fip->modem.m.eo;
- X fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
- X fip->device_flags.s |= DF_MODEM_ENABLED;
- X }
- X }
- X
- X cflag = fake_cflag;
- X
- X /* don't change break flag */
- X fip->lcr &= LC_SET_BREAK_LEVEL;
- X
- X /* set character size */
- X switch (cflag & CSIZE)
- X {
- X case CS5:
- X fip->lcr |= LC_WORDLEN_5;
- X break;
- X
- X case CS6:
- X fip->lcr |= LC_WORDLEN_6;
- X break;
- X
- X case CS7:
- X fip->lcr |= LC_WORDLEN_7;
- X break;
- X
- X default:
- X fip->lcr |= LC_WORDLEN_8;
- X break;
- X }
- X
- X /* set # of stop bits */
- X if (cflag & CSTOPB)
- X fip->lcr |= LC_STOPBITS_LONG;
- X
- X /* set parity */
- X if (cflag & PARENB)
- X {
- X fip->lcr |= LC_ENABLE_PARITY;
- X
- X if (!(cflag & PARODD))
- X fip->lcr |= LC_EVEN_PARITY;
- X }
- X
- X /* set LCR and baud rate */
- X fas_first_outb (fip, LINE_CTL_PORT, fip->lcr | LC_ENABLE_DIVISOR);
- X fas_outb (fip, DIVISOR_LSB_PORT,
- X divisor = (fip->device_flags.i & DF_115K)
- X ? fas_speeds2 [cflag & CBAUD]
- X : fas_speeds1 [cflag & CBAUD]);
- X fas_outb (fip, DIVISOR_MSB_PORT, divisor >> 8);
- X fas_outb (fip, LINE_CTL_PORT, fip->lcr);
- X
- Xsetflags:
- X /* check dynamic xmit ring buffer size against boundaries,
- X modify it if necessary and update the fas_internals structure
- X */
- X if ((xmit_ring_size = ((fip->device_flags.i & DF_115K)
- X ? fas_xbuf_size2 [cflag & CBAUD]
- X : fas_xbuf_size1 [cflag & CBAUD])
- X - tthiwat [fas_baud [cflag & CBAUD]])
- X < MAX_OUTPUT_FIFO_SIZE * 2)
- X {
- Xsetflags2:
- X xmit_ring_size = MAX_OUTPUT_FIFO_SIZE * 2;
- X }
- X fip->xmit_ring_size = (xmit_ring_size > XMIT_BUFF_SIZE)
- X ? XMIT_BUFF_SIZE
- X : xmit_ring_size;
- X
- X /* disable modem control signals if required by open mode */
- X if (fip->o_state & OS_CLOCAL)
- X cflag |= CLOCAL;
- X
- X /* Select hardware handshake depending on the minor device
- X number and various termio flags (if they are available).
- X */
- X fip->flow_flags.s &= ~(FF_HWO_HANDSHAKE
- X | FF_HWI_HANDSHAKE
- X | FF_HDX_HANDSHAKE);
- X if (fip->o_state & (OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE
- X | OS_HDX_HANDSHAKE))
- X {
- X if (fip->o_state & OS_HWO_HANDSHAKE)
- X fip->flow_flags.s |= FF_HWO_HANDSHAKE;
- X if (fip->o_state & OS_HWI_HANDSHAKE)
- X fip->flow_flags.s |= FF_HWI_HANDSHAKE;
- X if (fip->o_state & OS_HDX_HANDSHAKE)
- X fip->flow_flags.s |= FF_HDX_HANDSHAKE;
- X }
- X else
- X {
- X#if defined (CTSXON) && defined (RTSXOFF) /* SysVr4 compatibility */
- X if (fip->iflag & CTSXON)
- X fip->flow_flags.s |= FF_HWO_HANDSHAKE;
- X if (fip->iflag & RTSXOFF)
- X fip->flow_flags.s |= FF_HWI_HANDSHAKE;
- X#else
- X#if defined (CTSFLOW) && defined (RTSFLOW) /* SCO Xenix compatibility */
- X if (!(cflag & CLOCAL) || (fip->flow_flags.i & FF_NEW_CTSRTS))
- X {
- X#if defined (CRTSFL) /* SCO UNIX 3.2.4 compatibility */
- X if ((cflag & (CRTSFL | CTSFLOW | RTSFLOW)) == CRTSFL)
- X fip->flow_flags.s |= FF_HWO_HANDSHAKE
- X | FF_HWI_HANDSHAKE;
- X else
- X#endif
- X {
- X if (cflag & CTSFLOW)
- X fip->flow_flags.s |= FF_HWO_HANDSHAKE;
- X if (cflag & RTSFLOW)
- X fip->flow_flags.s |= (fip->flow_flags.i
- X & FF_NEW_CTSRTS)
- X ? FF_HWI_HANDSHAKE
- X : FF_HDX_HANDSHAKE;
- X }
- X }
- X#endif
- X#endif
- X }
- X
- X /* Determine whether to enable MSI, or not.
- X Set the interrupt enable port accordingly.
- X */
- X#if defined (HAVE_VPIX)
- X if ((cflag & CLOCAL) && !(fip->flow_flags.i & FF_HWO_HANDSHAKE)
- X && !(fip->iflag & DOSMODE))
- X#else
- X if ((cflag & CLOCAL) && !(fip->flow_flags.i & FF_HWO_HANDSHAKE))
- X#endif
- X {
- X if (fip->device_flags.i & DF_MSI_ENABLED)
- X fas_msi_disable (fip);
- X }
- X else
- X {
- X if (!(fip->device_flags.i & DF_MSI_ENABLED))
- X fas_msi_enable (fip);
- X }
- X
- X /* Fake the carrier detect state flag if CLOCAL mode or if
- X requested by open mode.
- X */
- X if (!(~fip->msr & fip->modem.m.ca)
- X || (cflag & CLOCAL)
- X || ((fip->o_state & OS_FAKE_CARR_ON)
- X && (!(fip->o_state & OS_OPEN_STATES)
- X || (fip->tty->t_state & CARR_ON))))
- X fip->tty->t_state |= CARR_ON;
- X else if (fip->tty->t_state & CARR_ON)
- X {
- X fip->tty->t_state &= ~CARR_ON;
- X /* flush buffers on carrier drop */
- X do_flush = TRUE;
- X }
- X
- X if ((fip->tty->t_state & CARR_ON) && (cflag & CREAD))
- X {
- X /* enable receiver data interrupts */
- X if (!(fip->device_flags.i & DF_RDI_ENABLED))
- X fas_rdi_enable (fip);
- X }
- X else
- X {
- X /* disable receiver data interrupts */
- X if (fip->device_flags.i & DF_RDI_ENABLED)
- X fas_rdi_disable (fip);
- X }
- X
- X#if defined (XCLUDE) /* SYSV 3.2 Xenix compatibility */
- X /* Permit exclusive use of this device. */
- X if (cflag & XCLUDE)
- X fip->o_state |= OS_EXCLUSIVE_OPEN_2;
- X else
- X fip->o_state &= ~OS_EXCLUSIVE_OPEN_2;
- X#endif
- X
- X fip->cflag = cflag;
- X
- X /* re-link fas_internals structure */
- X fas_pos_by_speed (fip);
- X
- X /* flush buffers if necessary */
- X if (do_flush)
- X {
- X /* lock transmitter */
- X fip->device_flags.s |= DF_XMIT_LOCKED;
- X old_level = SPLWRK ();
- X (void) ttyflush (fip->tty, FREAD | FWRITE);
- X (void) splx (old_level);
- X /* enable transmitter */
- X fip->device_flags.s &= ~DF_XMIT_LOCKED;
- X }
- X
- X /* setup handshake flags */
- X#if defined (HAVE_VPIX)
- X if ((fip->flow_flags.i & (FF_HWI_HANDSHAKE | FF_HDX_HANDSHAKE))
- X || !(fip->iflag & DOSMODE))
- X#endif
- X {
- X /* clear flow control output bits */
- X fip->mcr &= ~(fip->flow.m.ic | fip->flow.m.hc);
- X fip->flow_flags.s &= ~(FF_HWI_STARTED | FF_HDX_STARTED);
- X
- X /* raise flow control bits if necessary */
- X if (fip->flow_flags.i & FF_HWI_HANDSHAKE)
- X {
- X if (fip->recv_ring_cnt < HW_LOW_WATER)
- X {
- X fip->mcr |= fip->flow.m.ic;
- X fip->flow_flags.s |= FF_HWI_STARTED;
- X }
- X }
- X else if (fip->flow_flags.i & FF_HDX_HANDSHAKE)
- X {
- X if (fip->tty->t_state & BUSY)
- X {
- X fip->mcr |= fip->flow.m.hc;
- X fip->flow_flags.s |= FF_HDX_STARTED;
- X }
- X }
- X else if (!(fip->flow_flags.i & FF_DEF_HHO_LOW))
- X fip->mcr |= fip->flow.m.hc;
- X
- X fas_first_outb (fip, MDM_CTL_PORT, fip->mcr);
- X }
- X
- X /* set hardware output flow control flags */
- X if (!(~fip->new_msr & fip->flow.m.oc)
- X || (~fip->new_msr & fip->flow.m.oe)
- X || !(fip->flow_flags.i & FF_HWO_HANDSHAKE))
- X fip->flow_flags.s &= ~FF_HWO_STOPPED;
- X else
- X fip->flow_flags.s |= FF_HWO_STOPPED;
- X
- X /* check software input flow control */
- X if (fip->flow_flags.i & FF_SWI_STOPPED)
- X {
- X if (!(fip->iflag & IXOFF)
- X || (fip->recv_ring_cnt < SW_LOW_WATER))
- X fas_send_xon (fip);
- X }
- X else
- X {
- X if ((fip->iflag & IXOFF)
- X && (fip->recv_ring_cnt > SW_HIGH_WATER))
- X fas_send_xoff (fip);
- X }
- X
- X /* restart output */
- X fas_xproc (fip);
- X}
- X
- X/* Main FAS interrupt handler. Actual character processing is splitted
- X into sub-functions.
- X (called at SPLINT)
- X*/
- Xint
- Xfasintr (vect)
- Xint vect;
- X{
- X register struct fas_internals *fip;
- X bool done, was_rint, was_xint, was_mint, do_xproc;
- X REGVAR;
- X
- X done = TRUE;
- X was_rint = was_xint = was_mint = FALSE;
- X
- X /* The 8259 interrupt controller is set up for edge trigger.
- X Therefore, we must loop until we make a complete pass without
- X getting any UARTs that are interrupting.
- X */
- X do
- X {
- X /* We need a short delay if the previous loop
- X had work to do. This is necessary to ensure
- X that even with fast CPUs the time where the
- X UART interrupt line is low between two
- X interrupts is long enough that the PIC
- X gets a proper edge to trigger a new
- X interrupt. Therefore, we read the IER of
- X the first int user because this doesn't
- X have any side effects and causes a delay
- X that is rather CPU speed independent.
- X I HATE BRAIN-DEAD HARDWARE !
- X */
- X
- X if (!(fip = fas_first_int_user))
- X break; /* false alarm: must be a spurious int */
- X
- X if (!done)
- X {
- X (void) fas_first_inb (fip, INT_ENABLE_PORT);
- X done = TRUE;
- X }
- X
- X /* Loop through all users of the interrupt users chain
- X and look for characters in the receiver buffer.
- X We poll the line status register regardless of
- X whether the UART has interrupted or not. This
- X synchronizes concurrently running receiver FIFOs
- X and dramatically reduces the overall interrupt
- X frequency.
- X */
- X for (; fip; fip = fip->next_int_user)
- X {
- X register n_unchar lstatus;
- Xfastloop1:
- X /* read in all the characters from the FIFO */
- X if (!(fip->device_flags.i & DF_RDI_ENABLED)
- X || (!(fip->lsr & LS_RCV_AVAIL)
- X && !((fip->lsr = lstatus
- X = fas_first_inb (fip,
- X LINE_STATUS_PORT),
- X lstatus)
- X & LS_RCV_AVAIL)))
- X {
- X /* speed beats beauty */
- X fip = fip->next_int_user;
- X if (fip)
- X goto fastloop1;
- X break;
- X }
- X
- X done = FALSE;
- X
- X /* do the character processing */
- X fas_rproc (fip);
- X
- X /* schedule character transfer to UNIX buffer */
- X if (!(fip->flow_flags.i & FF_RXFER_STOPPED))
- X event_sched (fip, EF_DO_RXFER);
- X
- X /* check input buffer high water marks */
- X if ((fip->recv_ring_cnt > HW_HIGH_WATER)
- X && (fip->flow_flags.i & (FF_HWI_HANDSHAKE
- X | FF_HWI_STARTED))
- X == (FF_HWI_HANDSHAKE | FF_HWI_STARTED))
- X {
- X fas_first_outb (fip, MDM_CTL_PORT,
- X fip->mcr &= ~fip->flow.m.ic);
- X fip->flow_flags.s &= ~FF_HWI_STARTED;
- X }
- X if ((fip->recv_ring_cnt > SW_HIGH_WATER)
- X && (fip->iflag & IXOFF)
- X && !(fip->flow_flags.i & FF_SWI_STOPPED))
- X fas_send_xoff (fip);
- X
- X was_rint = TRUE;
- X }
- X
- X /* loop through all users of the interrupt users chain
- X and look for interrupts
- X */
- X for (fip = fas_first_int_user; fip; fip = fip->next_int_user)
- X {
- Xfastloop2:
- X /* process only ports that have an interrupt
- X pending
- X */
- X if (fas_first_inb (fip, INT_ID_PORT)
- X & II_NO_INTS_PENDING)
- X {
- X /* speed beats beauty */
- X fip = fip->next_int_user;
- X if (fip)
- X goto fastloop2;
- X break;
- X }
- X
- X done = FALSE;
- X
- X {
- X register n_unchar mstatus;
- X
- X /* Has there been a polarity change on
- X some of the modem lines ?
- X */
- X if ((fip->device_flags.i & DF_MSI_ENABLED)
- X && ((mstatus = fas_inb (fip, MDM_STATUS_PORT))
- X & MS_ANY_DELTA))
- X {
- X /* if the same modem status line
- X is responsible for a modem status
- X interrupt twice during two
- X event scheduler runs, we disable
- X modem status interrupts until we
- X process this interrupt in the event
- X scheduler
- X */
- X if (mstatus & fip->new_msr & MS_ANY_DELTA)
- X {
- X fas_msi_disable (fip);
- X ++fas_msi_noise;
- X }
- X /* Do special RING line handling.
- X RING generates an int only on the
- X trailing edge.
- X */
- X mstatus = (mstatus & ~MS_RING_PRESENT)
- X | (fip->new_msr & MS_RING_PRESENT);
- X if (mstatus & MS_RING_TEDGE)
- X mstatus |= MS_RING_PRESENT;
- X if ((mstatus ^ fip->new_msr) & MS_ANY_PRESENT)
- X {
- X do_xproc = FALSE;
- X /* check hw flow flags */
- X if (!(~mstatus & fip->flow.m.oc)
- X || (~mstatus & fip->flow.m.oe)
- X || !(fip->flow_flags.i
- X & FF_HWO_HANDSHAKE))
- X {
- X if (fip->flow_flags.i & FF_HWO_STOPPED)
- X {
- X fip->flow_flags.s &=
- X ~FF_HWO_STOPPED;
- X do_xproc = TRUE;
- X }
- X }
- X else
- X fip->flow_flags.s |= FF_HWO_STOPPED;
- X /* check carrier detect
- X note: the actual carrier detect
- X processing is done in fas_mproc ()
- X */
- X if (!(fip->cflag & CLOCAL)
- X && (fip->tty->t_state & CARR_ON))
- X {
- X if (!(~mstatus & fip->modem.m.ca))
- X {
- X if (fip->flow_flags.i
- X & FF_CARR_STOPPED)
- X {
- X fip->flow_flags.s &=
- X ~FF_CARR_STOPPED;
- X do_xproc = TRUE;
- X }
- X }
- X else if (!(~fip->new_msr
- X & fip->modem.m.ca))
- X fip->flow_flags.s
- X |= FF_CARR_STOPPED;
- X }
- X if (do_xproc)
- X fas_xproc (fip);
- X event_sched (fip, EF_DO_MPROC);
- X }
- X else
- X event_sched (fip, EF_RESET_DELTA_BITS);
- X /* "or" the delta flags to prevent
- X excessive modem status interrupts
- X */
- X fip->new_msr = mstatus | (fip->new_msr
- X & MS_ANY_DELTA);
- X was_mint = TRUE;
- X }
- X }
- X
- X {
- X register n_unchar lstatus;
- X
- X /* Is it a transmitter empty int ? */
- X if ((fip->lsr = lstatus = fas_inb (fip,
- X LINE_STATUS_PORT),
- X lstatus)
- X & LS_XMIT_AVAIL)
- X {
- X if (fip->device_flags.i & DF_XMIT_BUSY)
- X {
- X fip->device_flags.s &= ~DF_XMIT_BUSY;
- X /* do the character processing */
- X fas_xproc (fip);
- X if (!(fip->device_flags.i & DF_XMIT_BUSY))
- X {
- X fip->device_flags.s |= DF_GUARD_TIMEOUT;
- X fip->timeout_idx = timeout (
- X fas_timeout,
- X (caddr_t) fip,
- X (fip->device_flags.i & DF_115K)
- X ? fas_ctimes2 [fip->cflag
- X & CBAUD]
- X : fas_ctimes1 [fip->cflag
- X & CBAUD]);
- X }
- X was_xint = TRUE;
- X }
- X }
- X }
- X }
- X
- X if (!done)
- X {
- X register uint *seq_ptr;
- X uint port;
- X
- X /* execute the interrupt acknowledge sequence for the
- X serial cards
- X */
- X seq_ptr = &fas_int_ack_seq [0];
- X if (*seq_ptr)
- X {
- X do
- 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 } while (*++seq_ptr);
- X }
- X }
- X } while (!done);
- X
- X /* provide statistical infos */
- X if (was_rint)
- X ++sysinfo.rcvint;
- X if (was_xint)
- X ++sysinfo.xmtint;
- X if (was_mint)
- X ++sysinfo.mdmint;
- X return (0);
- X}
- X
- X/* Modem status handler.
- X (called at SPLHI)
- X*/
- Xstatic void
- Xfas_mproc (fip)
- Xregister struct fas_internals *fip;
- X{
- X register n_unchar mdm_status;
- X int old_level;
- X
- X mdm_status = fip->new_msr;
- X fip->new_msr &= ~MS_RING_PRESENT;
- X
- X {
- X register struct tty *ttyp;
- X
- X ttyp = fip->tty;
- X
- X /* Check the carrier detect signal and set the state flags
- X accordingly. Also, if not in clocal mode, send SIGHUP on
- X carrier loss and flush the buffers.
- X */
- X if (!(fip->cflag & CLOCAL) && (ttyp->t_state & (WOPEN | ISOPEN)))
- X {
- X if (!(~mdm_status & fip->modem.m.ca))
- X {
- X /* Wake up getty open on carrier low->high. */
- X if (!(ttyp->t_state & CARR_ON))
- X {
- X if ((ttyp->t_state |= CARR_ON) & WOPEN)
- X (void) wakeup ((caddr_t) &ttyp->t_canq);
- X /* enable receiver data interrupts */
- X if ((fip->cflag & CREAD)
- X && !(fip->device_flags.i
- X & DF_RDI_ENABLED))
- X fas_rdi_enable (fip);
- X /* re-link fas_internals structure */
- X fas_pos_by_speed (fip);
- X }
- X }
- X else
- X {
- X if (!(~fip->msr & fip->modem.m.ca))
- X {
- X ttyp->t_state &= ~CARR_ON;
- X /* disable receiver data interrupts */
- X if (fip->device_flags.i & DF_RDI_ENABLED)
- X fas_rdi_disable (fip);
- X /* re-link fas_internals structure */
- X fas_pos_by_speed (fip);
- X old_level = SPLWRK ();
- X if (ttyp->t_pgrp)
- X {
- X (void) signal (ttyp->t_pgrp, SIGHUP);
- X#if defined (SIGCONT)
- X /* make sure processes are awake */
- X (void) signal (ttyp->t_pgrp, SIGCONT);
- X#endif
- X }
- X (void) ttyflush (ttyp, FREAD | FWRITE);
- X (void) splx (old_level);
- X }
- X }
- X }
- X }
- X
- X#if defined (HAVE_VPIX)
- X if (((fip->iflag & (DOSMODE | PARMRK))
- X == (DOSMODE | PARMRK))
- X && (fip->v86_intmask != V86VI_KBD))
- X {
- X register n_unchar vpix_status;
- SHAR_EOF
- true || echo 'restore of fas.c failed'
- fi
- echo 'End of fas210 part 3'
- echo 'File fas.c is continued in part 4'
- echo 4 > _shar_seq_.tmp
- exit 0
- --
- Uwe Doering | INET : gemini@geminix.in-berlin.de
- Berlin |----------------------------------------------------------------
- Germany | UUCP : ...!unido!fub!geminix.in-berlin.de!gemini
-