]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.35pre6 2.0.35pre6
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:50 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:50 +0000 (15:11 -0500)
19 files changed:
arch/i386/kernel/entry.S
arch/i386/kernel/setup.c
arch/i386/kernel/traps.c
drivers/block/triton.c
drivers/char/README.stallion
drivers/char/istallion.c
drivers/char/stallion.c
fs/ext2/ialloc.c
fs/isofs/inode.c
include/linux/cd1400.h
include/linux/cdk.h
include/linux/comstats.h
include/linux/istallion.h
include/linux/sc26198.h [new file with mode: 0644]
include/linux/stallion.h
include/net/route.h
init/main.c
mm/vmscan.c
net/ipv4/route.c

index 12ae5a5b38f06f331324903e096e7718d720735e..6e21f9706961a12d2e10d6021c205d8c6fcf8abc 100644 (file)
@@ -374,6 +374,7 @@ ret_from_sys_call:
        jne signal_return
 2:     RESTORE_ALL
        ALIGN
+       .globl signal_return
 signal_return:
        movl %esp,%ecx
        pushl %ecx
index d22d4df26cf97a03079399a2d41e137bfe4a7a70..084cd21a1f46024fbf241b0776a7f69b0b6553d0 100644 (file)
@@ -50,7 +50,7 @@ char x86_vendor_id[13] = "unknown";
 
 unsigned char Cx86_step = 0;
 static const char *Cx86_type[] = {
-       "unknown", "1.3", "1.4", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
+       "unknown", "1.3", "1.4", "1.5", "1.6", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
        };
 
 char ignore_irq13 = 0;         /* set if exception 16 works */
index 7c580ba6d73d0e329f1f09018c99e5a1d68a5eab..19cbf8a1c373d74036d1b3529a88bac75ee7f389 100644 (file)
@@ -192,13 +192,36 @@ DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
 DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
 
+/* signal_return is directly after ret_from_sys_call in entry.S */
+asmlinkage void ret_from_sys_call(void)        __asm__("ret_from_sys_call");
+asmlinkage void signal_return(void)    __asm__("signal_return");
+
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
        if (regs->eflags & VM_MASK) {
                handle_vm86_fault((struct vm86_regs *) regs, error_code);
                return;
        }
-       die_if_kernel("general protection",regs,error_code);
+
+       /* 
+        * HACK HACK HACK  :)  Fixing the segment invalid on syscall return
+        * barfage for 2.0 has been put into the too-hard basket but having
+        * a user producing endless GPFs is unacceptable as well. - Paul G.
+        */
+       if ((regs->cs & 3) != 3) {
+               if (regs->eip >= (unsigned long)ret_from_sys_call &&
+                   regs->eip < (unsigned long)signal_return) {
+                       static int moancount = 0;
+                       if (moancount < 5) {
+                               printk(KERN_INFO "Ignoring GPF attempt from program \"%s\" (pid %d).\n",
+                                       current->comm, current->pid);
+                               moancount++;
+                       }
+                       do_exit(SIGSEGV);
+               }
+               else 
+                       die_if_kernel("general protection",regs,error_code);
+       }
        current->tss.error_code = error_code;
        current->tss.trap_no = 13;
        force_sig(SIGSEGV, current);    
index 60002fc342db3a8a603c88689f950a28fdef04a6..739b1b948be2b1ffcf7b694a2abc29535158ac19 100644 (file)
@@ -523,5 +523,5 @@ void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1,
        init_triton_dma(hwif1, bmiba + 0x08);
        return;
 abort:
-       printk("ide: Promise/33 not configured correctly (BIOS)\n");
+       printk(KERN_WARNING "ide: Promise/33 not configured correctly (BIOS)\n");
 }
index 361e3a95dbe40d32ca7a849ef9c2a942f5f13a87..18b39e00597764bb2d0f96b7ad78cc1ba7fad432 100644 (file)
 
-Stallion Multiport Serial Drivers
----------------------------------
+Stallion Multiport Serial Driver Readme
+---------------------------------------
 
-Version: 1.1.3
-Date:    23APR96
-Author:  Greg Ungerer (gerg@stallion.oz.au)
+Copyright (C) 1994-1998,  Stallion Technologies (support@stallion.com).
 
+Version:   5.4.4
+Date:      20MAR98
 
-1. INTRODUCTION
-
-There are two drivers that work with the different families of Stallion
-multiport serial boards. One is for the Stallion smart boards - that is
-EasyIO and EasyConnection 8/32, the other for the true Stallion intelligent
-multiport boards - EasyConnection 8/64, ONboard, Brumby and Stallion.
-
-If you are using any of the Stallion intelligent multiport boards (Brumby,
-ONboard, Stallion, EasyConnection 8/64) with Linux you will need to get the
-driver utility package. This package is available at most of the Linux
-archive sites (and on CD's that contain these archives). The file will be
-called stallion-X.X.X.tar.gz where X.X.X will be the version number. In
-particular this package contains the board embedded executable images that
-are required for these boards. It also contains the downloader program.
-These boards cannot be used without this.
-
-The following ftp sites (and their mirrors) definitely have the stallion
-driver utility package: ftp.stallion.com, tsx-11.mit.edu, sunsite.unc.edu.
 
-ftp.stallion.com:/drivers/ata5/Linux/stallion-1.1.2.tar.gz
-tsx-11.mit.edu:/pub/linux/BETA/serial/stallion/stallion-1.1.2.tar.gz
-sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-1.1.2.tar.gz
 
-If you are using the EasyIO or EasyConnection 8/32 boards then you don't
-need this package. Although it does have a handy script to create the
-/dev device nodes for these boards, and a serial stats display program.
+1. INTRODUCTION
 
-If you require DIP switch settings, EISA/MCA configuration files, or any
-other information related to Stallion boards then have a look at Stallion's
-web pages at http://www.stallion.com.
+This is a Linux driver for some of the Stallion Technologies range of
+multiport serial boards. There are really two drivers in this package.
+One is for the Stallion smart boards, the other for the true Stallion
+intelligent multiport boards.
+
+The drivers included in this package are intended as a replacement for
+those shipped with Linux kernel versions in the 2.0.X series. For later
+versions of the kernel (2.1.0 and above) use the driver source supplied
+with the kernel. The drivers in this package specifically add support
+for the most recent releases of Stallion hardware - which are not supported
+in the Stallion drivers supplied in the 2.0.X kernels. The drivers in this
+package do not support kernel versions earlier than 2.0.0.
+
+The other utilities supplied in this package can be used with Stallion
+drivers on any version of the kernel.
+
+If you have any trouble getting Stallion boards to work in Linux systems,
+please contact Stallion Technologies support department via email or phone.
+Contact information for Stallion Technologies offices is included in the
+file "Offices" contained in this distribution.
+
+Please note the disclaimers set out in the GNU general public license
+included with this driver package.
+
+All host driver source is included in this package, and is copyrighted under
+the GNU GPL. The board "firmware" code in this package is copyright Stallion
+Technologies (the files cdk.sys and 2681.sys).
+
+
+1.1 SMART MULTIPORT BOARD DRIVER
+
+This driver supports the EasyIO and EasyConnection 8/32 range of boards.
+These boards are not classic intelligent multiport boards, but are host
+based multiport boards that use Cirrus Logic CL-CD1400 UART's, or on
+newer versions of the hardware use the Signetics 26C198 UART. Both of
+these are high performance UART's with built in FIFO's, automatic flow
+control and a host of other features.
+
+The EasyIO range of cards comes in 4 forms, the EasyIO-4, EasyIO-8,
+EasyIO-8M and EasyIO-8-PCI. The first three are ISA based boards while
+the last is a PCI bus board. All of these are non-expandable, low cost,
+multiport boards with 4 or 8 RS-232C ports. Each ISA EasyIO board requires 8
+bytes of I/O address space and 1 interrupt. The PCI EasyIO board uses 64
+bytes of I/O address space and 1 interrupt. On EISA and PCI systems it is
+possible to share 1 interrupt between multiple boards. The EasyIO-4 has 10
+pin RJ connectors, and the EasyIO-8 comes with a dongle cable with either 10
+pin RJ connectors or DB-25 connectors. The EasyIO-8M has 6 pin RJ connectors.
+
+The EasyConnection 8/32 family of boards is a relatively low cost modular
+range of multiport serial boards. The EasyConnection 8/32 boards can be
+configured to have from 8 to 32 serial ports by plugging in external serial
+port modules that contain either 8 or 16 ports each. There is a wide range
+of external modules available that offer: DB-25 connectors, RJ-45 connectors
+(both with RS-232 D and E compatible drivers), and also RS-422 and RS-485
+ports. The EasyConnection 8/32 boards come in ISA, PCI and MCA bus versions.
+The board takes the form of a host adapter card, with an external connector
+cable that plugs into the external modules. The external modules just clip
+together to add ports (BTW, they are NOT hot pluggable). Each ISA
+EasyConnection 8/32 board requires two separate I/O address ranges, one two
+bytes in size and a secondary region of 32 bytes. Each PCI EasyConnection
+8/32 requires two regions of I/O address space, normally these will be
+automatically allocated by the system BIOS at power on time. Each MCA
+EasyConnection board requires one I/O address region 64 bytes in size. All
+board types also require one interrupt. On EISA systems multiple boards can
+share one interrupt. The secondary I/O range of the ISA board (the 32 byte
+range) can be shared between multiple boards on any bus type.
+
+The EasyConnection 8/64-PCI family is similar to the EasyConnection 8/32-PCI
+board, and uses the same external modules. It is supported by the smart
+board driver - not the intelligent board driver. It uses 2 regions of I/O
+address space, both 64 bytes in size, and 1 interrupt.
+
+
+
+1.2 INTELLIGENT MULTIPORT BOARD DRIVER
+
+This driver is for Stallion's range of true intelligent multiport boards.
+It supports the EasyConnection 8/64, ONboard and Brumby families of multiport
+boards. The EasyConnection 8/64 and ONboard boards come in ISA, EISA and
+Microchannel bus versions. The Brumby boards are only available in ISA
+versions. This driver can also work with the original Stallion board, but
+these are no longer supported by Stallion Technologies.
+
+The EasyConnection 8/64 family of boards is a medium cost, high performance,
+modular range of intelligent multiport serial boards. The EasyConnection 8/64
+boards can be configured to have from 8 to 64 serial ports by plugging in
+external serial port modules that contain either 8 or 16 ports each (these
+modules are the same used by the EasyConnection 8/32 board). There is a wide
+range of external modules available that offer: DB-25 connectors, RJ-45
+connectors (both with RS-232 D and E compatible drivers), and also RS-422 and
+RS-485 ports. The board takes the form of a host adapter card, with an external
+connector cable that plugs into the external modules. The external modules
+just clip together to add ports (BTW, they are NOT hot pluggable). Each
+EasyConnection 8/64 board requires 4 bytes of I/O address space and a region
+of memory space. The size of the memory region required depends on the exact
+board type. The EISA version requires 64 Kbytes of address space (that can
+reside anywhere in the 4 Gigabyte physical address space). The ISA and MCA
+boards require 4 Kbytes of address space (which must reside in the lower
+1 Mbyte of physical address space - typically in the c8000 to e0000 range).
+No interrupts are required. The physical memory region of multiple
+EasyConnection 8/64 boards can be shared, but each board must have a separate
+I/O address.
+
+The ONboard family of boards are traditional intelligent multiport serial
+boards. They are Stallion's older range of boards with a limited expansion
+capability. They come in 4, 8, 12, 16 and 32 port versions. The board uses
+the same base card (which has 4 ports on it) and is expanded to more ports via
+a mezzanine board that attaches directly onto the base card. External panels
+plug into the ONboard providing RS-232C ports with DB-25 plugs. An RS-422
+DB-25 dual interface panel is also available. The ISA and microchannel
+ONboards require 16 bytes of I/O address space and 64K bytes of memory
+space. The memory space can be anywhere in the 16 Mbyte ISA bus address
+range. No interrupt is required. The EISA ONboard requires 64 Kbytes of
+memory space that can be anywhere in the 4 Gigabyte physical address space.
+All ONboard boards can share their memory region with other ONboards (or
+EasyConnection 8/64 boards).
+
+The Brumby family of boards are traditional, low cost intelligent multiport
+serial boards. They are non-expandable and come in 4, 8 and 16 port versions.
+They are only available for the ISA bus. The serial ports are all on DB-25
+"dongle" cables that attach to the rear of the board. Each Brumby board
+requires 16 bytes of I/O address space and 16 Kbytes of memory space. No
+interrupts are required.
+
+The original Stallion boards are old. They went out of production some years
+back and are no longer supported. They offer limited expandability and are
+available in 8 or 16 port configurations. An external panel houses 16 RS-232C
+ports with DB-9 connectors. They require 16 bytes of I/O address space, and
+either 64K or 128K of memory space. No interrupt is required.
+
+That's the boards supported by the second driver. The ONboard, Brumby and
+Stallion boards are Stallion's older range of intelligent multiports - so
+there are lots of them around. They only support a maximum baud rate of
+38400. The EasyConnection 8/64 is a true high performance intelligent
+multiport board, having much greater throughput than any of Stallion's
+older boards. It also supports speeds up to 460800 baud.
+
+
+1.3 HOW TO GET BOARDS
+
+Stallion Technologies has offices all over the world, as well as many more
+distributors and resellers. To find out about local availability please
+contact the nearest Stallion office and they can give you all the information
+you need. Look in the "Offices" file in the driver package for a current list
+of Stallion Technologies offices.
+
+Another good source of information about the Stallion range of boards and
+local availability is on the Stallion Web page. Check it out at
+http://www.stallion.com.
 
 
 
 2. INSTALLATION
 
+This version of the driver is intended for kernel versions 2.0.0 and later.
+It will not work on earlier kernel versions, due to kernel interface changes.
+(Note that older versions of these drivers do work on older kernels.)
+If you are using a more recent development kernel (versions 2.1.X and
+greater) you should use the Stallion drivers supplied with that kernel,
+they are more up to date.
+
 The drivers can be used as loadable modules or compiled into the kernel.
-You can choose which when doing a "make config" on the kernel.
+Depending on which form of driver loading you decide to use, the installation
+procedure will be a little different.
 
 All ISA, EISA and MCA boards that you want to use need to be entered into
-the driver(s) configuration structures. All PCI boards will be automatically
+the driver(s) configuration structures. PCI boards will be automatically
 detected when you load the driver - so they do not need to be entered into
 the driver(s) configuration structure. (Note that kernel PCI BIOS32 support
 is required to use PCI boards.)
@@ -54,45 +185,135 @@ is required to use PCI boards.)
 Entering ISA, EISA and MCA boards into the driver(s) configuration structure
 involves editing the driver(s) source file. It's pretty easy if you follow
 the instructions below. Both drivers can support up to 4 boards. The smart
-card driver (the stallion.c driver) supports any combination of EasyIO and
-EasyConnection 8/32 boards (up to a total of 4). The intelligent driver
-supports any combination of ONboards, Brumbys, Stallions and EasyConnection
-8/64 boards (up to a total of 4).
+card driver supports any combination of EasyIO, EasyConnection 8/32 and
+EasyConnection 8/64-PCI boards (up to a total of 4). The intelligent driver
+supports any combination of ONboards, Brumbys, Stallions and
+EasyConnection 8/64 boards (up to a total of 4).
+
 
-To set up the driver(s) for the boards that you want to use you need to
-edit the appropriate driver file and add configuration entries.
+2.1 LOADABLE MODULE DRIVERS
 
-If using EasyIO or EasyConnection 8/32 ISA or MCA boards, do:
+You will need the gcc compiler and make installed on your system to make the
+driver modules. You will also need to have the kernel source on the system,
+and have at least done a "make config" and "make dep" on it. (If you haven't
+done this before then you may want to read the kernel source README file,
+usually found in /usr/src/linux.)
+
+To build the driver modules:
+1. Setup the driver configuration for the boards. If using EasyIO or
+   EasyConnection 8/32 ISA or MCA boards, do:
    vi stallion.c
       - find the definition of the stl_brdconf array (of structures)
         near the top of the file
       - modify this to match the boards you are going to install
        (the comments before this structure should help)
       - save and exit
-
-If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do:
+   If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do:
    vi istallion.c
       - find the definition of the stli_brdconf array (of structures)
         near the top of the file
       - modify this to match the boards you are going to install
        (the comments before this structure should help)
       - save and exit
+2. cp stallion.h cd1400.h sc26198.h /usr/include/linux/include/linux
+   cp istallion.h cdk.h comstats.h /usr/include/linux/include/linux
+3. make modules
+   This will compile the driver modules, as stallion and istallion.
+
+The stallion module is the EasyIO, EasyConnection 8/32 and
+EasyConnection 8/64-PCI driver, the istallion module is the ONboard,
+Brumby, Stallion and EasyConnection 8/64 driver.
+
+To load up the smart board driver use:
+    insmod ./stallion
+This will load the EasyIO and EasyConnection 8/32 driver. It will output a
+message to say that it loaded and print the driver version number. It
+will also print out whether it found the configured boards or not. (These
+messages may appear in your /var/adm/messages file depending on how the
+klogd and syslogd daemons are setup on your system).
+
+To load the intelligent board driver use:
+    insmod ./istallion
+It will output similar messages to the smart board driver.
+
+
+2.2 STATIC DRIVERS (KERNEL LINKED)
+
+You will need to build a new kernel to link in the Stallion drivers. The first
+thing you need is to have the full kernel source. Most people will have this.
+The following assumes that the kernel source is in /usr/src/linux.
+
+To install the drivers:
+1. cp stallion.c istallion.c /usr/src/linux/drivers/char
+   cp stallion.h cd1400.h sc26198.h /usr/include/linux/include/linux
+   cp istallion.h cdk.h comstats.h /usr/include/linux/include/linux
+2. cd /usr/src/linux/drivers/char
+3. Setup the driver configuration for the boards. If using EasyIO,
+   EasyConnection 8/32 or EasyConnection 8/64-PCI boards, do:
+   vi stallion.c
+      - find the definition of the stl_brdconf array (of structures)
+        near the top of the file
+      - modify this to match the boards you are going to install
+       (the comments before this structure should help)
+      - save and exit
+   If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do:
+   vi istallion.c
+      - find the definition of the stli_brdconf array (of structures)
+        near the top of the file
+      - modify this to match the boards you are going to install
+       (the comments before this structure should help)
+      - save and exit
+4. cd /usr/src/linux
+5. build a new kernel - if you haven't done this before you may want to
+   read the README file in /usr/src/linux.
+
+Once you have a new kernel built, reboot to start it up. On startup the
+driver will output a message to say it is operational (with the driver
+version number). It will also print out if it could find the boards listed
+in its configuration structure or not.
 
-Once you have set up the board configurations then you are ready to build
-the kernel or modules.
 
-When the new kernel is booted, or the loadable module loaded then the
-driver will emit some kernel trace messages about whether the configured
-boards where detected or not. Depending on how your system logger is set
-up these may come out on the console, or just be logged to
-/var/adm/messages. You should check the messages to confirm that all is well.
+2.3 INTELLIGENT DRIVER OPERATION
+
+The intelligent boards also need to have their "firmware" code downloaded
+to them. This is done via a user level application supplied in the driver
+package called "stlload". Compile this program where ever you dropped the
+package files, by typing "make". In its simplest form you can then type
+    ./stlload -i cdk.sys
+in this directory and that will download board 0 (assuming board 0 is an
+EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do:
+    ./stlload -i 2681.sys
 
+Normally you would want all boards to be downloaded as part of the standard
+system startup. To achieve this, add one of the lines above into the
+/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add
+the "-b <brd-number>" option to the line. You will need to download code for
+every board. You should probably move the stlload program into a system
+directory, such as /usr/sbin. Also, the default location of the cdk.sys image
+file in the stlload down-loader is /usr/lib/stallion. Create that directory
+and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put
+them anyway). As an example your /etc/rc.d/rc.S file might have the
+following lines added to it (if you had 3 boards):
+    /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys
+    /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys
+    /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys
 
-2.1 SHARING INTERRUPTS
+The image files cdk.sys and 2681.sys are specific to the board types. The
+cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly
+the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards.
+If you load the wrong image file into a board it will fail to start up, and
+of course the ports will not be operational!
 
-It is possible to share interrupts between multiple EasyIO and
-EasyConnection 8/32 boards in an EISA system. To do this you will need to
-do a couple of things:
+If you are using the module version of the driver you might want to put the
+insmod calls in the startup script as well (before the download lines
+obviously).
+
+
+2.4 SHARING INTERRUPTS
+
+As mentioned in the introduction, it is possible to share interrupts between
+multiple EasyIO and EasyConnection 8/32 boards in an EISA system. To do this
+you will need to do a couple of things:
 
 1. When entering the board resources into the stallion.c file you need to
    mark the boards as using level triggered interrupts. Do this by replacing
@@ -109,17 +330,17 @@ do a couple of things:
    that are sharing interrupts. The Stallion EasyIO and EasyConnection 8/32
    EISA configuration files required are supplied by Stallion Technologies
    on the DOS Utilities floppy (usually supplied in the box with the board
-   when purchased. If not, you can pick it up from Stallion's FTP site,
-   ftp.stallion.com). You will need to edit the board resources to choose
-   level triggered interrupts, and make sure to set each board's interrupt
-   to the same IRQ number.
+   when purchased. If not, you can pick it up from Stallion's FTP site
+   ftp.stallion.com or web site http://www.stallion.com). You will need to
+   edit the board resources to choose level triggered interrupts, and make
+   sure to set each board's interrupt to the same IRQ number.
 
 You must complete both the above steps for this to work. When you reboot
 or load the driver your EasyIO and EasyConnection 8/32 boards will be
 sharing interrupts.
 
 
-2.2 USING HIGH SHARED MEMORY
+2.5 USING HIGH SHARED MEMORY
 
 The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of
 using shared memory addresses above the usual 640K - 1Mb range. The ONboard
@@ -128,75 +349,52 @@ ISA and the Stallion boards can be programmed to use memory addresses up to
 ONboard/E can be programmed for memory addresses up to 4Gb (the EISA bus
 addressing limit).
 
-The higher than 1Mb memory addresses are fully supported by this driver.
-Just enter the address as you normally would for a lower than 1Mb address
-(in the drivers board configuration structure).
+The istallion driver offers direct support for these higher memory regions.
+To use them just enter the high memory address as if it were a low memory
+address (in the driver board configuration structure).
+
 
+2.6 LINUX KERNEL VERSIONS 2.1.X
 
+There may be some minor differences between the driver source code in this
+package and that in the Linux kernel source. This will be due to changes
+needed in the drivers so that they work correctly on newer kernels. The
+driver source included in this package is intended for use with 2.0.X
+series kernels. If you have a kernel version 2.1.0 or later then use the
+source provided with the kernel - it will be more up to date. Stallion
+Technologies regularly submits the latest driver source to be included in
+the new kernel source releases.
 
-2.3 TROUBLE SHOOTING
+
+2.7 TROUBLE SHOOTING
 
 If a board is not found by the driver but is actually in the system then the
 most likely problem is that the I/O address is wrong. Change it in the driver
-stallion.c or istallion.c configuration structure and rebuild the kernel or
-modules, or change it on the board. On EasyIO and EasyConnection 8/32 boards
-the IRQ is software programmable, so if there is a conflict you may need to
-change the IRQ used for a board in the stallion.c configuration structure.
-There are no interrupts to worry about for ONboard, Brumby, Stallion or
-EasyConnection 8/64 boards. The memory region on EasyConnection 8/64 and
-ONboard boards is software programmable, but not on the Brumbys or Stallions.
+stallion.c or istallion.c configuration structure and rebuild the kernel
+or modules, or change it on the board. On EasyIO and EasyConnection 8/32
+boards the IRQ is software programmable, so if there is a conflict you may
+need to change the IRQ used for a board in the stallion.c configuration
+structure. There are no interrupts to worry about for ONboard, Brumby,
+Stallion or EasyConnection 8/64 boards. The memory region on EasyConnection
+8/64 and ONboard boards is software programmable, but not on the Brumbys or
+Stallions.
 
 
 
 3. USING THE DRIVERS
 
-3.1 INTELLIGENT DRIVER OPERATION
-
-The intelligent boards also need to have their "firmware" code downloaded
-to them. This is done via a user level application supplied in the driver
-package called "stlload". Compile this program where ever you dropped the
-package files, by typing "make". In its simplest form you can then type
-    ./stlload -i cdk.sys
-in this directory and that will download board 0 (assuming board 0 is an
-EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do:
-    ./stlload -i 2681.sys
-
-Normally you would want all boards to be downloaded as part of the standard
-system startup. To achieve this, add one of the lines above into the
-/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add
-the "-b <brd-number>" option to the line. You will need to download code for
-every board. You should probably move the stlload program into a system
-directory, such as /usr/sbin. Also, the default location of the cdk.sys image
-file in the stlload down-loader is /usr/lib/stallion. Create that directory
-and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put
-them anyway). As an example your /etc/rc.d/rc.S file might have the
-following lines added to it (if you had 3 boards):
-    /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys
-    /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys
-    /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys
-
-The image files cdk.sys and 2681.sys are specific to the board types. The
-cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly
-the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards.
-If you load the wrong image file into a board it will fail to start up, and
-of course the ports will not be operational!
-
-If you are using the modularized version of the driver you might want to put
-the insmod calls in the startup script as well (before the download lines
-obviously).
-
-
-3.2 USING THE SERIAL PORTS
-
 Once the driver is installed you will need to setup some device nodes to
-access the serial ports. The simplest method is to use the stallion utility
-"mkdevnods" script. It will automatically create all possible device entries
-required for all 4 boards. This will create the normal serial port devices as
-/dev/ttyE# where # is the port number starting from 0. A bank of 64 minor
-device numbers is allocated to each board, so the first port on the second
-board is port 64, etc. A set of callout type devices is also created. They
-are created as the devices /dev/cue# where # is the same as for the ttyE
-devices.
+access the serial ports. Use the supplied "mkdevnods" script to automatically
+create all required device entries for one board. This will create the normal
+serial port devices as /dev/ttyE# where # is the port number starting from 0.
+A set of callout type devices is also created. They are created as the devices
+/dev/cue# where # is the same as for the ttyE devices.
+
+A bank of 64 minor device numbers is allocated to each board. To create
+device nodes for ports on multiple boards supply a number of boards argument
+to the "mkdevnods" script. For example to create nodes for four boards use
+"mkdevnods 4". This means that the first port on the second board is port 64,
+the first port on the third board is 128, etc.
 
 For the most part the Stallion driver tries to emulate the standard PC system
 COM ports and the standard Linux serial driver. The idea is that you should
@@ -214,9 +412,18 @@ COM ports. Most importantly "stty" works as expected and "setserial" can be
 also be used (excepting the ability to auto-configure the I/O and IRQ
 addresses of boards). Higher baud rates are supported in the usual fashion
 through setserial or using the CBAUDEX extensions. Note that the EasyIO and
-EasyConnection (all types) support 57600 and 115200 baud. The older boards
-including ONboard, Brumby and the original Stallion support a maximum baud
-rate of 38400.
+EasyConnection (all types) support 57600 and 115200 baud, and the newer XP
+versions also support 230400 and 460800 baud. The older boards including
+ONboard, Brumby and the original Stallion support a maximum baud rate of
+38400.
+
+This driver should work with anything that works on standard Linux serial
+ports. Having said that, it has been used on at least the following types of
+"things" under Linux:
+    a) standard dumb terminals (using agetty, getty)
+    b) serial mice (under X)
+    c) modems (using cu, uucp, minicom, seyon, uugetty)
+    d) slip and ppp connections
 
 If you are unfamiliar with how to use serial ports, then get the Serial-HOWTO
 by Greg Hankins. It will explain everything you need to know!
@@ -225,6 +432,11 @@ by Greg Hankins. It will explain everything you need to know!
 
 4. NOTES
 
+The major device numbers used by this driver are conformant with the Linux
+Device Registry, so they shouldn't clash with any other devices. Also the
+device naming scheme is the "standard" used by most Linux serial port
+devices.
+
 You can use both drivers at once if you have a mix of board types installed
 in a system. However to do this you will need to change the major numbers
 used by one of the drivers. Currently both drivers use major numbers 24, 25
@@ -234,20 +446,17 @@ major numbers. For example, you could change the istallion.c driver to use
 major numbers 60, 61 and 62. You will also need to create device nodes with
 different names for the ports, for example ttyF# and cuf#.
 
-The original Stallion board is no longer supported by Stallion Technologies.
-Although it is known to work with the istallion driver.
-
 Finding a free physical memory address range can be a problem. The older
 boards like the Stallion and ONboard need large areas (64K or even 128K), so
 they can be very difficult to get into a system. If you have 16 Mb of RAM
 then you have no choice but to put them somewhere in the 640K -> 1Mb range.
 ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some
-systems. If you have an original Stallion board, "V4.0" or Rev.O, then you
-need a 64K memory address space, so again 0xd0000 and 0xe0000 are good.
-Older Stallion boards are a much bigger problem. They need 128K of address
-space and must be on a 128K boundary. If you don't have a VGA card then
-0xc0000 might be usable - there is really no other place you can put them
-below 1Mb.
+systems. If you have an original Stallion board, "V4.0" or Rev.O,
+then you need a 64K memory address space, so again 0xd0000 and 0xe0000 are
+good. Older Stallion boards are a much bigger problem. They need 128K of
+address space and must be on a 128K boundary. If you don't have a VGA card
+then 0xc0000 might be usable - there is really no other place you can put
+them below 1Mb.
 
 Both the ONboard and old Stallion boards can use higher memory addresses as
 well, but you must have less than 16Mb of RAM to be able to use them. Usual
@@ -265,19 +474,48 @@ them can be used then the high memory support to use the really high address
 ranges is the best option. Typically the 2Gb range is convenient for them,
 and gets them well out of the way.
 
+There is a new utility program included called "stlstty". Most people
+will not need to use this. If you have an ONboard/16 which has partial
+signals on the upper 12 ports then this program can be used to set the
+upper ports to have modem control instead of hardware flow control. Use
+the "mapcts maprts" flag options to this utility on the port(s) that you
+wish to do this mapping on, eg
+    ./stlstty maprts mapcts < /dev/cue0
+This enables RTS to act like DTR and CTS to act like DCD on the specified
+port.
+
 The ports of the EasyIO-8M board do not have DCD or DTR signals. So these
-ports cannot be used as real modem devices. Generally, when using these
+ports cannot be used as real modem devices. Generally when using these
 ports you should only use the cueX devices.
 
-The driver utility package contains a couple of very useful programs. One 
-is a serial port statistics collection and display program - very handy
-for solving serial port problems. The other is an extended option setting
-program that works with the intelligent boards.
+There is another new utility in this package that reports statistics on
+the serial ports. You will need to have the curses libray installed on
+your system to build it.
+
+To build the statistics display program type:
+    make stlstats
+Once compiled simply run it (you will need to be root) and it will display
+a port sumary for the first board and panel installed. Use the digits to
+select different board numbers, or 'n' to cycle through the panels on a
+board. To look at detailed port information then hit 'p', that will display
+detailed port 0 information. Use the digits and letters 'a' through 'f' to
+select the different ports (on this board and panel).
+
+
+
+5. ACKNOWLEDGEMENTS
+
+This driver is loosely based on code written by Theodore T'so, Linus
+Torvalds, and others, so a big thanks to them all.
 
 
 
-5. DISCLAIMER
+6. DISCLAIMER
 
-I do not speak for Stallion Technologies in any capacity, officially or
-unofficially.
+The information contained in this document is believed to be accurate and
+reliable. However, no responsibility is assumed by Stallion Technologies
+Pty. Ltd. for its use, nor any infringements of patents or other rights
+of third parties resulting from its use. Stallion Technologies reserves
+the right to modify the design of its products and will endeavour to change
+the information in manuals and accompanying documentation accordingly.
 
index 2cc26a90f5765d599913c6c4fad11be4ec4eb3df..5773ba4a87573955cba09aad9079939e2751b8f8 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     istallion.c  -- stallion intelligent multiport serial driver.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This code is loosely based on the Linux serial driver, written by
@@ -73,6 +74,8 @@
 #define BRD_ECPE       24
 #define        BRD_ECPMC       25
 #define        BRD_ECHPCI      26
+#define        BRD_ECH64PCI    27
+#define        BRD_EASYIOPCI   28
 
 #define        BRD_BRUMBY      BRD_BRUMBY4
 
  *     boards can share the same shared memory address space. No interrupt
  *     is required for this board type.
  *     Another example:
+ *             { BRD_ECPE, 0x5000, 0, 0x80000000, 0, 0 },
+ *     This line will configure an EasyConnection 8/64 EISA in slot 5 and
+ *     shared memory address of 0x80000000 (2 GByte). Multiple
+ *     EasyConnection 8/64 EISA boards can share the same shared memory
+ *     address space. No interrupt is required for this board type.
+ *     Another example:
  *             { BRD_ONBOARD, 0x240, 0, 0xd0000, 0, 0 },
  *     This line will configure an ONboard (ISA type) at io address 240,
  *     and shared memory address of d0000. Multiple ONboards can share
@@ -156,8 +165,8 @@ static int  stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
  *     Define our local driver identity first. Set up stuff to deal with
  *     all the local structures required by a serial tty driver.
  */
-static char    *stli_drvname = "Stallion Intelligent Multiport Serial Driver";
-static char    *stli_drvversion = "1.1.3";
+static char    *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
+static char    *stli_drvversion = "5.4.4";
 static char    *stli_serialname = "ttyE";
 static char    *stli_calloutname = "cue";
 
@@ -281,6 +290,8 @@ static char *stli_brdnames[] = {
        "EC8/64-EI",
        "EC8/64-MC",
        "EC8/32-PCI",
+       "EC8/64-PCI",
+       "EasyIO-PCI",
 };
 
 /*
@@ -436,6 +447,7 @@ int         stli_eisaprobe = STLI_EISAPROBE;
 #define        ECH_PNLSTATUS   2
 #define        ECH_PNL16PORT   0x20
 #define        ECH_PNLIDMASK   0x07
+#define        ECH_PNLXPID     0x40
 #define        ECH_PNLINTRPEND 0x80
 
 /*
@@ -473,9 +485,9 @@ int         stli_eisaprobe = STLI_EISAPROBE;
 /*
  *     Define the maximal baud rate, and the default baud base for ports.
  */
-#define        STL_MAXBAUD     230400
+#define        STL_MAXBAUD     460800
 #define        STL_BAUDBASE    115200
-#define        STL_CLOSEDELAY  50
+#define        STL_CLOSEDELAY  (5 * HZ / 10)
 
 /*****************************************************************************/
 
@@ -492,7 +504,7 @@ int         stli_eisaprobe = STLI_EISAPROBE;
  */
 static unsigned int    stli_baudrates[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
 };
 
 /*****************************************************************************/
@@ -530,19 +542,16 @@ static void       stli_start(struct tty_struct *tty);
 static void    stli_flushbuffer(struct tty_struct *tty);
 static void    stli_hangup(struct tty_struct *tty);
 
-static int     stli_initbrds(void);
 static int     stli_brdinit(stlibrd_t *brdp);
-static int     stli_initecp(stlibrd_t *brdp);
-static int     stli_initonb(stlibrd_t *brdp);
-static int     stli_eisamemprobe(stlibrd_t *brdp);
-static int     stli_findeisabrds(void);
-static int     stli_initports(stlibrd_t *brdp);
 static int     stli_startbrd(stlibrd_t *brdp);
+static int     stli_memopen(struct inode *ip, struct file *fp);
+static void    stli_memclose(struct inode *ip, struct file *fp);
 static int     stli_memread(struct inode *ip, struct file *fp, char *buf, int count);
 static int     stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int count);
 static int     stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static void    stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp);
 static void    stli_poll(unsigned long arg);
-static int     stli_hostcmd(stlibrd_t *brdp, int channr);
+static int     stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
 static int     stli_initopen(stlibrd_t *brdp, stliport_t *portp);
 static int     stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
 static int     stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
@@ -561,6 +570,7 @@ static void stli_getserial(stliport_t *portp, struct serial_struct *sp);
 static int     stli_setserial(stliport_t *portp, struct serial_struct *sp);
 static int     stli_getbrdstats(combrd_t *bp);
 static int     stli_getportstats(stliport_t *portp, comstats_t *cp);
+static int     stli_portcmdstats(stliport_t *portp);
 static int     stli_clrportstats(stliport_t *portp, comstats_t *cp);
 static int     stli_getportstruct(unsigned long arg);
 static int     stli_getbrdstruct(unsigned long arg);
@@ -601,6 +611,13 @@ static void        stli_stalreset(stlibrd_t *brdp);
 
 static stliport_t *stli_getport(int brdnr, int panelnr, int portnr);
 
+static inline int      stli_initbrds(void);
+static inline int      stli_initecp(stlibrd_t *brdp);
+static inline int      stli_initonb(stlibrd_t *brdp);
+static inline int      stli_findeisabrds(void);
+static inline int      stli_eisamemprobe(stlibrd_t *brdp);
+static inline int      stli_initports(stlibrd_t *brdp);
+
 /*****************************************************************************/
 
 /*
@@ -617,8 +634,8 @@ static struct file_operations       stli_fsiomem = {
        NULL,
        stli_memioctl,
        NULL,
-       NULL,
-       NULL,
+       stli_memopen,
+       stli_memclose,
        NULL
 };
 
@@ -678,7 +695,8 @@ void cleanup_module()
        printk("cleanup_module()\n");
 #endif
 
-       printk(KERN_INFO "Unloading %s: version %s\n", stli_drvname, stli_drvversion);
+       printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
+               stli_drvversion);
 
        save_flags(flags);
        cli();
@@ -695,12 +713,14 @@ void cleanup_module()
        i = tty_unregister_driver(&stli_serial);
        j = tty_unregister_driver(&stli_callout);
        if (i || j) {
-               printk("STALLION: failed to un-register tty driver, errno=%d,%d\n", -i, -j);
+               printk("STALLION: failed to un-register tty driver, "
+                       "errno=%d,%d\n", -i, -j);
                restore_flags(flags);
                return;
        }
        if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-               printk("STALLION: failed to un-register serial memory device, errno=%d\n", -i);
+               printk("STALLION: failed to un-register serial memory device, "
+                       "errno=%d\n", -i);
 
        if (stli_tmpwritebuf != (char *) NULL)
                kfree_s(stli_tmpwritebuf, STLI_TXBUFSIZE);
@@ -722,10 +742,8 @@ void cleanup_module()
 
                if (brdp->memaddr >= 0x100000)
                        vfree(brdp->membase);
-               if ((brdp->brdtype == BRD_ECP) || (brdp->brdtype == BRD_ECPE) || (brdp->brdtype == BRD_ECPMC))
-                       release_region(brdp->iobase, ECP_IOSIZE);
-               else
-                       release_region(brdp->iobase, ONB_IOSIZE);
+               if (brdp->iosize > 0)
+                       release_region(brdp->iobase, brdp->iosize);
                kfree_s(brdp, sizeof(stlibrd_t));
                stli_brds[i] = (stlibrd_t *) NULL;
        }
@@ -756,7 +774,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        int             brdnr, portnr, rc;
 
 #if DEBUG
-       printk("stli_open(tty=%x,filp=%x): device=%x\n", (int) tty, (int) filp, tty->device);
+       printk("stli_open(tty=%x,filp=%x): device=%x\n", (int) tty,
+               (int) filp, tty->device);
 #endif
 
        minordev = MINOR(tty->device);
@@ -778,6 +797,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
        if (portp->devnr < 1)
                return(-ENODEV);
 
+       MOD_INC_USE_COUNT;
+
 /*
  *     Check if this port is in the middle of closing. If so then wait
  *     until it is closed then return error status based on flag settings.
@@ -842,10 +863,10 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
                        return(-EBUSY);
                if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
                        if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
-                                       (portp->session != current->session))
+                           (portp->session != current->session))
                                return(-EBUSY);
                        if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
-                                       (portp->pgrp != current->pgrp))
+                           (portp->pgrp != current->pgrp))
                                return(-EBUSY);
                }
                portp->flags |= ASYNC_CALLOUT_ACTIVE;
@@ -892,10 +913,14 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        save_flags(flags);
        cli();
        if (tty_hung_up_p(filp)) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
+       if ((tty->count == 1) && (portp->refcount != 1))
+               portp->refcount = 1;
        if (portp->refcount-- > 1) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
@@ -916,10 +941,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
        tty->closing = 1;
-       if (test_bit(ST_TXBUSY, &portp->state)) {
-               if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-                       tty_wait_until_sent(tty, portp->closing_wait);
-       }
+       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, portp->closing_wait);
 
        portp->flags &= ~ASYNC_INITIALIZED;
        brdp = stli_brds[portp->brdnr];
@@ -929,7 +952,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
                if (test_bit(ST_CMDING, &portp->state))
                        set_bit(ST_DOSIGS, &portp->state);
                else
-                       stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+                       stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig,
+                               sizeof(asysigs_t), 0);
        }
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
@@ -940,7 +964,6 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
        stli_flushbuffer(tty);
 
        tty->closing = 0;
-       tty->driver_data = (void *) NULL;
        portp->tty = (struct tty_struct *) NULL;
 
        if (portp->openwaitcnt) {
@@ -949,8 +972,10 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
                wake_up_interruptible(&portp->open_wait);
        }
 
-       portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
+               ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
+       MOD_DEC_USE_COUNT;
        restore_flags(flags);
 }
 
@@ -981,23 +1006,27 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
        memset(&nt, 0, sizeof(asynotify_t));
        nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK);
        nt.signal = SG_DCD;
-       if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt, sizeof(asynotify_t), 0)) < 0)
+       if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt,
+           sizeof(asynotify_t), 0)) < 0)
                return(rc);
 
        tty = portp->tty;
        if (tty == (struct tty_struct *) NULL)
                return(-ENODEV);
        stli_mkasyport(portp, &aport, tty->termios);
-       if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0)
+       if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
+           sizeof(asyport_t), 0)) < 0)
                return(rc);
 
        set_bit(ST_GETSIGS, &portp->state);
-       if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0)
+       if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig,
+           sizeof(asysigs_t), 1)) < 0)
                return(rc);
        if (clear_bit(ST_GETSIGS, &portp->state))
                portp->sigs = stli_mktiocm(portp->asig.sigvalue);
        stli_mkasysigs(&portp->asig, 1, 1);
-       if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0)
+       if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
+           sizeof(asysigs_t), 0)) < 0)
                return(rc);
 
        return(0);
@@ -1021,7 +1050,8 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
        int                     rc;
 
 #if DEBUG
-       printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, (int) portp, (int) arg, wait);
+       printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
+               (int) brdp, (int) portp, (int) arg, wait);
 #endif
 
 /*
@@ -1054,8 +1084,8 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
        cp->openarg = arg;
        cp->open = 1;
        hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       hdrp->slavereq |= portp->reqbit;
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx;
+       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+               portp->portidx;
        *bits |= portp->portbit;
        EBRDDISABLE(brdp);
 
@@ -1101,7 +1131,8 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
        int                     rc;
 
 #if DEBUG
-       printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, (int) portp, (int) arg, wait);
+       printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
+               (int) brdp, (int) portp, (int) arg, wait);
 #endif
 
        save_flags(flags);
@@ -1129,8 +1160,8 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
        cp->closearg = arg;
        cp->close = 1;
        hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       hdrp->slavereq |= portp->reqbit;
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx;
+       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+               portp->portidx;
        *bits |= portp->portbit;
        EBRDDISABLE(brdp);
 
@@ -1173,7 +1204,9 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v
        unsigned long   flags;
 
 #if DEBUG
-       printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback);
+       printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
+               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
+               (int) arg, size, copyback);
 #endif
 
        save_flags(flags);
@@ -1243,7 +1276,7 @@ static int stli_setport(stliport_t *portp)
 static void stli_delay(int len)
 {
 #if DEBUG
-       printk("stl_delay(len=%d)\n", len);
+       printk("stli_delay(len=%d)\n", len);
 #endif
        if (len > 0) {
                current->state = TASK_INTERRUPTIBLE;
@@ -1265,7 +1298,8 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
        int             rc, doclocal;
 
 #if DEBUG
-       printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n", (int) brdp, (int) portp, (int) filp);
+       printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n",
+               (int) brdp, (int) portp, (int) filp);
 #endif
 
        rc = 0;
@@ -1282,16 +1316,18 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
        save_flags(flags);
        cli();
        portp->openwaitcnt++;
-       if (portp->refcount > 0)
+       if (! tty_hung_up_p(filp))
                portp->refcount--;
 
        for (;;) {
                if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) {
                        stli_mkasysigs(&portp->asig, 1, 1);
-                       if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0)
+                       if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
+                           &portp->asig, sizeof(asysigs_t), 0)) < 0)
                                break;
                }
-               if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) {
+               if (tty_hung_up_p(filp) ||
+                   ((portp->flags & ASYNC_INITIALIZED) == 0)) {
                        if (portp->flags & ASYNC_HUP_NOTIFY)
                                rc = -EBUSY;
                        else
@@ -1299,8 +1335,8 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
                        break;
                }
                if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
-                               ((portp->flags & ASYNC_CLOSING) == 0) &&
-                               (doclocal || (portp->sigs & TIOCM_CD))) {
+                   ((portp->flags & ASYNC_CLOSING) == 0) &&
+                   (doclocal || (portp->sigs & TIOCM_CD))) {
                        break;
                }
                if (current->signal & ~current->blocked) {
@@ -1338,10 +1374,12 @@ static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
        unsigned long           flags;
 
 #if DEBUG
-       printk("stli_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", (int) tty, from_user, (int) buf, count);
+       printk("stli_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
+               (int) tty, from_user, (int) buf, count);
 #endif
 
-       if ((tty == (struct tty_struct *) NULL) || (stli_tmpwritebuf == (char *) NULL))
+       if ((tty == (struct tty_struct *) NULL) ||
+           (stli_tmpwritebuf == (char *) NULL))
                return(0);
        if (tty == stli_txcooktty)
                stli_flushchars(tty);
@@ -1375,7 +1413,8 @@ static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
                tail = (unsigned int) ap->txq.tail;
                if (tail != ((unsigned int) ap->txq.tail))
                        tail = (unsigned int) ap->txq.tail;
-               len = (head >= tail) ? (portp->txsize - (head - tail) - 1) : (tail - head - 1);
+               len = (head >= tail) ? (portp->txsize - (head - tail) - 1) :
+                       (tail - head - 1);
                count = MIN(len, count);
                EBRDDISABLE(brdp);
 
@@ -1430,8 +1469,8 @@ static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
                        ap->changed.data &= ~DT_TXEMPTY;
        }
        hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       hdrp->slavereq |= portp->reqbit;
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx;
+       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+               portp->portidx;
        *bits |= portp->portbit;
        set_bit(ST_TXBUSY, &portp->state);
 
@@ -1562,8 +1601,8 @@ static void stli_flushchars(struct tty_struct *tty)
                        ap->changed.data &= ~DT_TXEMPTY;
        }
        hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       hdrp->slavereq |= portp->reqbit;
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx;
+       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+               portp->portidx;
        *bits |= portp->portbit;
        set_bit(ST_TXBUSY, &portp->state);
 
@@ -1729,12 +1768,14 @@ static int stli_setserial(stliport_t *portp, struct serial_struct *sp)
        memcpy_fromfs(&sio, sp, sizeof(struct serial_struct));
        if (!suser()) {
                if ((sio.baud_base != portp->baud_base) ||
-                               (sio.close_delay != portp->close_delay) ||
-                               ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK)))
+                   (sio.close_delay != portp->close_delay) ||
+                   ((sio.flags & ~ASYNC_USR_MASK) !=
+                   (portp->flags & ~ASYNC_USR_MASK)))
                        return(-EPERM);
        } 
 
-       portp->flags = (portp->flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK);
+       portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+               (sio.flags & ASYNC_USR_MASK);
        portp->baud_base = sio.baud_base;
        portp->close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
@@ -1755,7 +1796,8 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
        int             rc;
 
 #if DEBUG
-       printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", (int) tty, (int) file, cmd, (int) arg);
+       printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
+               (int) tty, (int) file, cmd, (int) arg);
 #endif
 
        if (tty == (struct tty_struct *) NULL)
@@ -1769,6 +1811,12 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
        if (brdp == (stlibrd_t *) NULL)
                return(0);
 
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                       return(-EIO);
+       }
+
        rc = 0;
 
        switch (cmd) {
@@ -1777,7 +1825,8 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                        tty_wait_until_sent(tty, 0);
                        if (! arg) {
                                val = 250;
-                               rc = stli_cmdwait(brdp, portp, A_BREAK, &val, sizeof(unsigned long), 0);
+                               rc = stli_cmdwait(brdp, portp, A_BREAK, &val,
+                                       sizeof(unsigned long), 0);
                        }
                }
                break;
@@ -1785,72 +1834,98 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                if ((rc = tty_check_change(tty)) == 0) {
                        tty_wait_until_sent(tty, 0);
                        val = (arg ? (arg * 100) : 250);
-                       rc = stli_cmdwait(brdp, portp, A_BREAK, &val, sizeof(unsigned long), 0);
+                       rc = stli_cmdwait(brdp, portp, A_BREAK, &val,
+                               sizeof(unsigned long), 0);
                }
                break;
        case TIOCGSOFTCAR:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0)
-                       put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg);
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(long))) == 0)
+                       put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+                               (unsigned long *) arg);
                break;
        case TIOCSSOFTCAR:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0);
+                       tty->termios->c_cflag =
+                               (tty->termios->c_cflag & ~CLOCAL) |
+                               (arg ? CLOCAL : 0);
                }
                break;
        case TIOCMGET:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
-                       if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(unsigned int))) == 0) {
+                       if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
+                           &portp->asig, sizeof(asysigs_t), 1)) < 0)
                                return(rc);
                        val = stli_mktiocm(portp->asig.sigvalue);
                        put_fs_long(val, (unsigned long *) arg);
                }
                break;
        case TIOCMBIS:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1));
-                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+                       stli_mkasysigs(&portp->asig,
+                               ((arg & TIOCM_DTR) ? 1 : -1),
+                               ((arg & TIOCM_RTS) ? 1 : -1));
+                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
+                               &portp->asig, sizeof(asysigs_t), 0);
                }
                break;
        case TIOCMBIC:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1));
-                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+                       stli_mkasysigs(&portp->asig,
+                               ((arg & TIOCM_DTR) ? 0 : -1),
+                               ((arg & TIOCM_RTS) ? 0 : -1));
+                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
+                               &portp->asig, sizeof(asysigs_t), 0);
                }
                break;
        case TIOCMSET:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0));
-                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+                       stli_mkasysigs(&portp->asig,
+                               ((arg & TIOCM_DTR) ? 1 : 0),
+                               ((arg & TIOCM_RTS) ? 1 : 0));
+                       rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
+                               &portp->asig, sizeof(asysigs_t), 0);
                }
                break;
        case TIOCGSERIAL:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(struct serial_struct))) == 0)
                        stli_getserial(portp, (struct serial_struct *) arg);
                break;
        case TIOCSSERIAL:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
-                       rc = stli_setserial(portp, (struct serial_struct *) arg);
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(struct serial_struct))) == 0)
+                       rc = stli_setserial(portp, (struct serial_struct *)arg);
                break;
        case STL_GETPFLAG:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(unsigned long))) == 0)
                        put_fs_long(portp->pflag, (unsigned long *) arg);
                break;
        case STL_SETPFLAG:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(unsigned long))) == 0) {
                        portp->pflag = get_fs_long((unsigned long *) arg);
                        stli_setport(portp);
                }
                break;
        case COM_GETPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
                        rc = stli_getportstats(portp, (comstats_t *) arg);
                break;
        case COM_CLRPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
                        rc = stli_clrportstats(portp, (comstats_t *) arg);
                break;
        case TIOCSERCONFIG:
@@ -1898,13 +1973,15 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
                return;
 
        tiosp = tty->termios;
-       if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
+       if ((tiosp->c_cflag == old->c_cflag) &&
+           (tiosp->c_iflag == old->c_iflag))
                return;
 
        stli_mkasyport(portp, &aport, tiosp);
        stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
        stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
-       stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
+       stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
+               sizeof(asysigs_t), 0);
        if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0))
                tty->hw_stopped = 0;
        if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
@@ -1996,7 +2073,7 @@ static void stli_stop(struct tty_struct *tty)
        memset(&actrl, 0, sizeof(asyctrl_t));
        actrl.txctrl = CT_STOPFLOW;
 #if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t));
+       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 #endif
 }
 
@@ -2030,7 +2107,7 @@ static void stli_start(struct tty_struct *tty)
        memset(&actrl, 0, sizeof(asyctrl_t));
        actrl.txctrl = CT_STARTFLOW;
 #if 0
-       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t));
+       stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
 #endif
 }
 
@@ -2104,7 +2181,8 @@ static void stli_hangup(struct tty_struct *tty)
                        set_bit(ST_DOFLUSHTX, &portp->state);
                        set_bit(ST_DOFLUSHRX, &portp->state);
                } else {
-                       stli_sendcmd(brdp, portp, A_SETSIGNALSF, &portp->asig, sizeof(asysigs_t), 0);
+                       stli_sendcmd(brdp, portp, A_SETSIGNALSF,
+                               &portp->asig, sizeof(asysigs_t), 0);
                }
        }
        restore_flags(flags);
@@ -2112,7 +2190,6 @@ static void stli_hangup(struct tty_struct *tty)
        clear_bit(ST_TXBUSY, &portp->state);
        clear_bit(ST_RXSTOP, &portp->state);
        set_bit(TTY_IO_ERROR, &tty->flags);
-       tty->driver_data = (void *) NULL;
        portp->tty = (struct tty_struct *) NULL;
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
        portp->refcount = 0;
@@ -2164,12 +2241,14 @@ static void stli_flushbuffer(struct tty_struct *tty)
                        ftype |= FLUSHRX;
                        clear_bit(ST_DOFLUSHRX, &portp->state);
                }
-               stli_sendcmd(brdp, portp, A_FLUSH, &ftype, sizeof(unsigned long), 0);
+               stli_sendcmd(brdp, portp, A_FLUSH, &ftype,
+                       sizeof(unsigned long), 0);
        }
        restore_flags(flags);
 
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
                (tty->ldisc.write_wakeup)(tty);
 }
 
@@ -2193,7 +2272,9 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
        unsigned long           flags;
 
 #if DEBUG
-       printk("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback);
+       printk("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
+               "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
+               (int) arg, size, copyback);
 #endif
 
        save_flags(flags);
@@ -2217,8 +2298,8 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
        cp->status = 0;
        cp->cmd = cmd;
        hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-       hdrp->slavereq |= portp->reqbit;
-       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx;
+       bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+               portp->portidx;
        *bits |= portp->portbit;
        set_bit(ST_CMDING, &portp->state);
        EBRDDISABLE(brdp);
@@ -2307,7 +2388,8 @@ static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
        int     cmd;
 
        if (test_bit(ST_DOSIGS, &portp->state)) {
-               if (test_bit(ST_DOFLUSHTX, &portp->state) && test_bit(ST_DOFLUSHRX, &portp->state))
+               if (test_bit(ST_DOFLUSHTX, &portp->state) &&
+                   test_bit(ST_DOFLUSHRX, &portp->state))
                        cmd = A_SETSIGNALSF;
                else if (test_bit(ST_DOFLUSHTX, &portp->state))
                        cmd = A_SETSIGNALSFTX;
@@ -2318,11 +2400,13 @@ static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
                clear_bit(ST_DOFLUSHTX, &portp->state);
                clear_bit(ST_DOFLUSHRX, &portp->state);
                clear_bit(ST_DOSIGS, &portp->state);
-               memcpy((void *) &(cp->args[0]), (void *) &portp->asig, sizeof(asysigs_t));
+               memcpy((void *) &(cp->args[0]), (void *) &portp->asig,
+                       sizeof(asysigs_t));
                cp->status = 0;
                cp->cmd = cmd;
                set_bit(ST_CMDING, &portp->state);
-       } else if (test_bit(ST_DOFLUSHTX, &portp->state) || test_bit(ST_DOFLUSHRX, &portp->state)) {
+       } else if (test_bit(ST_DOFLUSHTX, &portp->state) ||
+           test_bit(ST_DOFLUSHRX, &portp->state)) {
                cmd = ((test_bit(ST_DOFLUSHTX, &portp->state)) ? FLUSHTX : 0);
                cmd |= ((test_bit(ST_DOFLUSHRX, &portp->state)) ? FLUSHRX : 0);
                clear_bit(ST_DOFLUSHTX, &portp->state);
@@ -2342,15 +2426,17 @@ static inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
  *     enabled and interrupts off when called. Notice that by servicing the
  *     read data last we don't need to change the shared memory pointer
  *     during processing (which is a slow IO operation).
+ *     Return value indicates if this port is still awaiting actions from
+ *     the slave (like open, command, or even TX data being sent). If 0
+ *     then port is still busy, otherwise no longer busy.
  */
 
-static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
+static inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
 {
        volatile cdkasy_t       *ap;
        volatile cdkctrl_t      *cp;
        struct tty_struct       *tty;
        asynotify_t             nt;
-       stliport_t              *portp;
        unsigned long           oldsigs;
        int                     rc, donerx;
 
@@ -2358,7 +2444,6 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
        printk("stli_hostcmd(brdp=%x,channr=%d)\n", (int) brdp, channr);
 #endif
 
-       portp = brdp->ports[(channr - 1)];
        ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
        cp = &ap->ctrl;
 
@@ -2402,7 +2487,8 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
                        if (rc > 0)
                                rc--;
                        if (portp->argp != (void *) NULL) {
-                               memcpy(portp->argp, (void *) &(cp->args[0]), portp->argsize);
+                               memcpy(portp->argp, (void *) &(cp->args[0]),
+                                       portp->argsize);
                                portp->argp = (void *) NULL;
                        }
                        cp->status = 0;
@@ -2429,12 +2515,14 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
                        oldsigs = portp->sigs;
                        portp->sigs = stli_mktiocm(nt.sigvalue);
                        clear_bit(ST_GETSIGS, &portp->state);
-                       if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
+                       if ((portp->sigs & TIOCM_CD) &&
+                           ((oldsigs & TIOCM_CD) == 0))
                                wake_up_interruptible(&portp->open_wait);
-                       if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
+                       if ((oldsigs & TIOCM_CD) &&
+                           ((portp->sigs & TIOCM_CD) == 0)) {
                                if (portp->flags & ASYNC_CHECK_CD) {
                                        if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
-                                                       (portp->flags & ASYNC_CALLOUT_NOHUP))) {
+                                           (portp->flags & ASYNC_CALLOUT_NOHUP))) {
                                                if (tty != (struct tty_struct *) NULL)
                                                        queue_task_irq_off(&portp->tqhangup, &tq_scheduler);
                                        }
@@ -2446,7 +2534,8 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
                        clear_bit(ST_TXBUSY, &portp->state);
                if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
                        if (tty != (struct tty_struct *) NULL) {
-                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+                               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                                   tty->ldisc.write_wakeup) {
                                        (tty->ldisc.write_wakeup)(tty);
                                        EBRDENABLE(brdp);
                                }
@@ -2460,12 +2549,10 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
                                        tty->flip.count++;
                                        *tty->flip.flag_buf_ptr++ = TTY_BREAK;
                                        *tty->flip.char_buf_ptr++ = 0;
-#ifndef MODULE
                                        if (portp->flags & ASYNC_SAK) {
                                                do_SAK(tty);
                                                EBRDENABLE(brdp);
                                        }
-#endif
                                        tty_schedule_flip(tty);
                                }
                        }
@@ -2490,7 +2577,74 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
                stli_read(brdp, portp);
        }
 
-       return(0);
+       return((test_bit(ST_OPENING, &portp->state) ||
+               test_bit(ST_CLOSING, &portp->state) ||
+               test_bit(ST_CMDING, &portp->state) ||
+               test_bit(ST_TXBUSY, &portp->state) ||
+               test_bit(ST_RXING, &portp->state)) ? 0 : 1);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Service all ports on a particular board. Assumes that the boards
+ *     shared memory is enabled, and that the page pointer is pointed
+ *     at the cdk header structure.
+ */
+
+static inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
+{
+       stliport_t      *portp;
+       unsigned char   hostbits[(STL_MAXCHANS / 8) + 1];
+       unsigned char   slavebits[(STL_MAXCHANS / 8) + 1];
+       unsigned char   *slavep;
+       int             bitpos, bitat, bitsize;
+       int             channr, nrdevs, slavebitchange;
+
+       bitsize = brdp->bitsize;
+       nrdevs = brdp->nrdevs;
+
+/*
+ *     Check if slave wants any service. Basically we try to do as
+ *     little work as possible here. There are 2 levels of service
+ *     bits. So if there is nothing to do we bail early. We check
+ *     8 service bits at a time in the inner loop, so we can bypass
+ *     the lot if none of them want service.
+ */
+       memcpy(&hostbits[0], (((unsigned char *) hdrp) + brdp->hostoffset),
+               bitsize);
+
+       memset(&slavebits[0], 0, bitsize);
+       slavebitchange = 0;
+
+       for (bitpos = 0; (bitpos < bitsize); bitpos++) {
+               if (hostbits[bitpos] == 0)
+                       continue;
+               channr = bitpos * 8;
+               for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) {
+                       if (hostbits[bitpos] & bitat) {
+                               portp = brdp->ports[(channr - 1)];
+                               if (stli_hostcmd(brdp, portp)) {
+                                       slavebitchange++;
+                                       slavebits[bitpos] |= bitat;
+                               }
+                       }
+               }
+       }
+
+/*
+ *     If any of the ports are no longer busy then update them in the
+ *     slave request bits. We need to do this after, since a host port
+ *     service may initiate more slave requests.
+ */
+       if (slavebitchange) {
+               hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+               slavep = ((unsigned char *) hdrp) + brdp->slaveoffset;
+               for (bitpos = 0; (bitpos < bitsize); bitpos++) {
+                       if (slavebits[bitpos])
+                               slavep[bitpos] &= ~slavebits[bitpos];
+               }
+       }
 }
 
 /*****************************************************************************/
@@ -2507,12 +2661,8 @@ static inline int stli_hostcmd(stlibrd_t *brdp, int channr)
 static void stli_poll(unsigned long arg)
 {
        volatile cdkhdr_t       *hdrp;
-       unsigned char           bits[(STL_MAXCHANS / 8) + 1];
-       unsigned char           hostreq, slavereq;
-       stliport_t              *portp;
        stlibrd_t               *brdp;
-       int                     bitpos, bitat, bitsize;
-       int                     brdnr, channr, nrdevs;
+       int                     brdnr;
 
        stli_timerlist.expires = STLI_TIMEOUT;
        add_timer(&stli_timerlist);
@@ -2529,67 +2679,8 @@ static void stli_poll(unsigned long arg)
 
                EBRDENABLE(brdp);
                hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
-               hostreq = hdrp->hostreq;
-               slavereq = hdrp->slavereq;
-               bitsize = brdp->bitsize;
-               nrdevs = brdp->nrdevs;
-
-/*
- *             Check if slave wants any service. Basically we try to do as
- *             little work as possible here. There are 2 levels of service
- *             bits. So if there is nothing to do we bail early. We check
- *             8 service bits at a time in the inner loop, so we can bypass
- *             the lot if none of them want service.
- */
-               if (hostreq) {
-                       memcpy(&bits[0], (((unsigned char *) hdrp) + brdp->hostoffset), bitsize);
-
-                       for (bitpos = 0; (bitpos < bitsize); bitpos++) {
-                               if (bits[bitpos] == 0)
-                                       continue;
-                               channr = bitpos * 8;
-                               for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) {
-                                       if (bits[bitpos] & bitat) {
-                                               stli_hostcmd(brdp, channr);
-                                       }
-                               }
-                       }
-               }
-
-/*
- *             Check if any of the out-standing host commands have completed.
- *             It is a bit unfortunate that we need to check stuff that we
- *             initiated!  This ain't pretty, but it needs to be fast.
- */
-               if (slavereq) {
-                       slavereq = 0;
-                       hostreq = 0;
-                       memcpy(&bits[0], (((unsigned char *) hdrp) + brdp->slaveoffset), bitsize);
-
-                       for (bitpos = 0; (bitpos < bitsize); bitpos++) {
-                               if (bits[bitpos] == 0)
-                                       continue;
-                               channr = bitpos * 8;
-                               for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) {
-                                       if (bits[bitpos] & bitat) {
-                                               portp = brdp->ports[(channr - 1)];
-                                               if (test_bit(ST_OPENING, &portp->state) ||
-                                                               test_bit(ST_CLOSING, &portp->state) ||
-                                                               test_bit(ST_CMDING, &portp->state) ||
-                                                               test_bit(ST_TXBUSY, &portp->state)) {
-                                                       slavereq |= portp->reqbit;
-                                               } else {
-                                                       bits[bitpos] &= ~bitat;
-                                                       hostreq++;
-                                               }
-                                       }
-                               }
-                       }
-                       hdrp->slavereq = slavereq;
-                       if (hostreq)
-                               memcpy((((unsigned char *) hdrp) + brdp->slaveoffset), &bits[0], bitsize);
-               }
-
+               if (hdrp->hostreq)
+                       stli_brdpoll(brdp, hdrp);
                EBRDDISABLE(brdp);
        }
 }
@@ -2604,7 +2695,8 @@ static void stli_poll(unsigned long arg)
 static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
 {
 #if DEBUG
-       printk("stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n", (int) portp, (int) pp, (int) tiosp);
+       printk("stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n",
+               (int) portp, (int) pp, (int) tiosp);
 #endif
 
        memset(pp, 0, sizeof(asyport_t));
@@ -2615,7 +2707,7 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
        pp->baudout = tiosp->c_cflag & CBAUD;
        if (pp->baudout & CBAUDEX) {
                pp->baudout &= ~CBAUDEX;
-               if ((pp->baudout < 1) || (pp->baudout > 2))
+               if ((pp->baudout < 1) || (pp->baudout > 5))
                        tiosp->c_cflag &= ~CBAUDEX;
                else
                        pp->baudout += 15;
@@ -2706,7 +2798,10 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
 /*
  *     Transfer any persistent flags into the asyport structure.
  */
-       pp->pflag = portp->pflag;
+       pp->pflag = (portp->pflag & 0xffff);
+       pp->vmin = (portp->pflag & P_RXIMIN) ? 1 : 0;
+       pp->vtime = (portp->pflag & P_RXITIME) ? 1 : 0;
+       pp->cc[1] = (portp->pflag & P_RXTHOLD) ? 1 : 0;
 }
 
 /*****************************************************************************/
@@ -2765,7 +2860,7 @@ static long stli_mktiocm(unsigned long sigvalue)
  *     we need to do here is set up the appropriate per port data structures.
  */
 
-static int stli_initports(stlibrd_t *brdp)
+static inline int stli_initports(stlibrd_t *brdp)
 {
        stliport_t      *portp;
        int             i, panelnr, panelport;
@@ -2855,11 +2950,14 @@ static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
        unsigned char   val;
 
 #if DEBUG
-       printk("stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset);
+       printk("stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
+               (int) offset);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
                val = 0;
        } else {
@@ -2942,11 +3040,14 @@ static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line
        unsigned char   val;
 
 #if DEBUG
-       printk("stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, (int) offset, line);
+       printk("stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n",
+               (int) brdp, (int) offset, line);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
                val = 0;
        } else {
@@ -2996,7 +3097,9 @@ static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line
        unsigned char   val;
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
                val = 0;
        } else {
@@ -3071,11 +3174,14 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
        void    *ptr;
 
 #if DEBUG
-       printk("stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset);
+       printk("stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
+               (int) offset);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
        } else {
                ptr = brdp->membase + (offset % ONB_ATPAGESIZE);
@@ -3158,11 +3264,14 @@ static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
        unsigned char   val;
 
 #if DEBUG
-       printk("stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, (int) offset, line);
+       printk("stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n",
+               (int) brdp, (int) offset, line);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
                val = 0;
        } else {
@@ -3224,11 +3333,14 @@ static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
        unsigned char   val;
 
 #if DEBUG
-       printk("stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset);
+       printk("stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
+               (int) offset);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
                val = 0;
        } else {
@@ -3282,11 +3394,14 @@ static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
        void    *ptr;
 
 #if DEBUG
-       printk("stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset);
+       printk("stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
+               (int) offset);
 #endif
 
        if (offset > brdp->memsize) {
-               printk("STALLION: shared memory pointer=%x out of range at line=%d(%d), brd=%d\n", (int) offset, line, __LINE__, brdp->brdnr);
+               printk("STALLION: shared memory pointer=%x out of range at "
+                       "line=%d(%d), brd=%d\n", (int) offset, line,
+                       __LINE__, brdp->brdnr);
                ptr = 0;
        } else {
                ptr = brdp->membase + (offset % STAL_PAGESIZE);
@@ -3319,12 +3434,13 @@ static void stli_stalreset(stlibrd_t *brdp)
  *     board types.
  */
 
-static int stli_initecp(stlibrd_t *brdp)
+static inline int stli_initecp(stlibrd_t *brdp)
 {
        cdkecpsig_t     sig;
        cdkecpsig_t     *sigsp;
        unsigned int    status, nxtid;
-       int             panelnr;
+       char            *name;
+       int             panelnr, nrports;
 
 #if DEBUG
        printk("stli_initecp(brdp=%x)\n", (int) brdp);
@@ -3336,6 +3452,11 @@ static int stli_initecp(stlibrd_t *brdp)
        if ((brdp->iobase == 0) || (brdp->memaddr == 0))
                return(-ENODEV);
 
+       brdp->iosize = ECP_IOSIZE;
+       if (check_region(brdp->iobase, brdp->iosize))
+               printk("STALLION: Warning, unit %d I/O address %x conflicts "
+                       "with another device\n", brdp->brdnr, brdp->iobase);
+
 /*
  *     Based on the specific board type setup the common vars to access
  *     and enable shared memory. Set all board specific information now
@@ -3353,6 +3474,7 @@ static int stli_initecp(stlibrd_t *brdp)
                brdp->getmemptr = stli_ecpgetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_ecpreset;
+               name = "serial(EC8/64)";
                break;
 
        case BRD_ECPE:
@@ -3366,6 +3488,7 @@ static int stli_initecp(stlibrd_t *brdp)
                brdp->getmemptr = stli_ecpeigetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_ecpeireset;
+               name = "serial(EC8/64-EI)";
                break;
 
        case BRD_ECPMC:
@@ -3379,6 +3502,7 @@ static int stli_initecp(stlibrd_t *brdp)
                brdp->getmemptr = stli_ecpmcgetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_ecpmcreset;
+               name = "serial(EC8/64-MCA)";
                break;
 
        default:
@@ -3410,10 +3534,11 @@ static int stli_initecp(stlibrd_t *brdp)
        EBRDDISABLE(brdp);
 
 #if 0
-       printk("%s(%d): sig-> magic=%x romver=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n",
+       printk("%s(%d): sig-> magic=%x rom=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n",
                __FILE__, __LINE__, (int) sig.magic, sig.romver, sig.panelid[0],
-               (int) sig.panelid[1], (int) sig.panelid[2], (int) sig.panelid[3],
-               (int) sig.panelid[4], (int) sig.panelid[5], (int) sig.panelid[6],
+               (int) sig.panelid[1], (int) sig.panelid[2],
+               (int) sig.panelid[3], (int) sig.panelid[4],
+               (int) sig.panelid[5], (int) sig.panelid[6],
                (int) sig.panelid[7]);
 #endif
 
@@ -3428,20 +3553,18 @@ static int stli_initecp(stlibrd_t *brdp)
                status = sig.panelid[nxtid];
                if ((status & ECH_PNLIDMASK) != nxtid)
                        break;
-               if (status & ECH_PNL16PORT) {
-                       brdp->panels[panelnr] = 16;
-                       brdp->nrports += 16;
-                       nxtid += 2;
-               } else {
-                       brdp->panels[panelnr] = 8;
-                       brdp->nrports += 8;
-                       nxtid++;
-               }
+
                brdp->panelids[panelnr] = status;
+               nrports = (status & ECH_PNL16PORT) ? 16 : 8;
+               if ((nrports == 16) && ((status & ECH_PNLXPID) == 0))
+                       nxtid++;
+               brdp->panels[panelnr] = nrports;
+               brdp->nrports += nrports;
+               nxtid++;
                brdp->nrpanels++;
        }
 
-       request_region(brdp->iobase, ECP_IOSIZE, "serial(ECP)");
+       request_region(brdp->iobase, brdp->iosize, name);
        brdp->state |= BST_FOUND;
        return(0);
 }
@@ -3453,10 +3576,11 @@ static int stli_initecp(stlibrd_t *brdp)
  *     This handles only these board types.
  */
 
-static int stli_initonb(stlibrd_t *brdp)
+static inline int stli_initonb(stlibrd_t *brdp)
 {
        cdkonbsig_t     sig;
        cdkonbsig_t     *sigsp;
+       char            *name;
        int             i;
 
 #if DEBUG
@@ -3469,6 +3593,11 @@ static int stli_initonb(stlibrd_t *brdp)
        if ((brdp->iobase == 0) || (brdp->memaddr == 0))
                return(-ENODEV);
 
+       brdp->iosize = ONB_IOSIZE;
+       if (check_region(brdp->iobase, brdp->iosize))
+               printk("STALLION: Warning, unit %d I/O address %x conflicts "
+                       "with another device\n", brdp->brdnr, brdp->iobase);
+
 /*
  *     Based on the specific board type setup the common vars to access
  *     and enable shared memory. Set all board specific information now
@@ -3494,6 +3623,7 @@ static int stli_initonb(stlibrd_t *brdp)
                        brdp->enabval = ONB_MEMENABHI;
                else
                        brdp->enabval = ONB_MEMENABLO;
+               name = "serial(ONBoard)";
                break;
 
        case BRD_ONBOARDE:
@@ -3507,6 +3637,7 @@ static int stli_initonb(stlibrd_t *brdp)
                brdp->getmemptr = stli_onbegetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_onbereset;
+               name = "serial(ONBoard/E)";
                break;
 
        case BRD_BRUMBY4:
@@ -3522,6 +3653,7 @@ static int stli_initonb(stlibrd_t *brdp)
                brdp->getmemptr = stli_bbygetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_bbyreset;
+               name = "serial(Brumby)";
                break;
 
        case BRD_STALLION:
@@ -3535,6 +3667,7 @@ static int stli_initonb(stlibrd_t *brdp)
                brdp->getmemptr = stli_stalgetmemptr;
                brdp->intr = stli_ecpintr;
                brdp->reset = stli_stalreset;
+               name = "serial(Stallion)";
                break;
 
        default:
@@ -3572,7 +3705,7 @@ static int stli_initonb(stlibrd_t *brdp)
 #endif
 
        if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) ||
-                       (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3))
+           (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3))
                return(-ENODEV);
 
 /*
@@ -3591,7 +3724,7 @@ static int stli_initonb(stlibrd_t *brdp)
        }
        brdp->panels[0] = brdp->nrports;
 
-       request_region(brdp->iobase, ONB_IOSIZE, "serial(ONB/BBY)");
+       request_region(brdp->iobase, brdp->iosize, name);
        brdp->state |= BST_FOUND;
        return(0);
 }
@@ -3626,14 +3759,16 @@ static int stli_startbrd(stlibrd_t *brdp)
        nrdevs = hdrp->nrdevs;
 
 #if 0
-       printk("%s(%d): CDK version %d.%d.%d --> nrdevs=%d memp=%x hostp=%x slavep=%x\n",
+       printk("%s(%d): CDK version %d.%d.%d --> "
+               "nrdevs=%d memp=%x hostp=%x slavep=%x\n",
                 __FILE__, __LINE__, hdrp->ver_release, hdrp->ver_modification,
                 hdrp->ver_fix, nrdevs, (int) hdrp->memp, (int) hdrp->hostp,
                 (int) hdrp->slavep);
 #endif
 
        if (nrdevs < (brdp->nrports + 1)) {
-               printk("STALLION: slave failed to allocate memory for all devices, devices=%d\n", nrdevs);
+               printk("STALLION: slave failed to allocate memory for all "
+                       "devices, devices=%d\n", nrdevs);
                brdp->nrports = nrdevs - 1;
        }
        brdp->nrdevs = nrdevs;
@@ -3671,6 +3806,8 @@ static int stli_startbrd(stlibrd_t *brdp)
                portp->portbit = (unsigned char) (0x1 << (i % 8));
        }
 
+       hdrp->slavereq = 0xff;
+
 /*
  *     For each port setup a local copy of the RX and TX buffer offsets
  *     and sizes. We do this separate from the above, because we need to
@@ -3743,20 +3880,27 @@ static int stli_brdinit(stlibrd_t *brdp)
        case BRD_ECH:
        case BRD_ECHMC:
        case BRD_ECHPCI:
-               printk("STALLION: %s board type not supported in this driver\n", stli_brdnames[brdp->brdtype]);
+               printk("STALLION: %s board type not supported in this driver\n",
+                       stli_brdnames[brdp->brdtype]);
                return(ENODEV);
        default:
-               printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
+               printk("STALLION: unit=%d is unknown board type=%d\n",
+                       brdp->brdnr, brdp->brdtype);
                return(ENODEV);
        }
 
        if ((brdp->state & BST_FOUND) == 0) {
-               printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr);
+               printk("STALLION: %s board not found, unit=%d io=%x mem=%x\n",
+                       stli_brdnames[brdp->brdtype], brdp->brdnr,
+                       brdp->iobase, (int) brdp->memaddr);
                return(ENODEV);
        }
 
        stli_initports(brdp);
-       printk("STALLION: %s found, unit=%d io=%x mem=%x nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports);
+       printk("STALLION: %s found, unit=%d io=%x mem=%x "
+               "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
+               brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
+               brdp->nrpanels, brdp->nrports);
        return(0);
 }
 
@@ -3767,7 +3911,7 @@ static int stli_brdinit(stlibrd_t *brdp)
  *     might be. This is a bit if hack, but it is the best we can do.
  */
 
-static int stli_eisamemprobe(stlibrd_t *brdp)
+static inline int stli_eisamemprobe(stlibrd_t *brdp)
 {
        cdkecpsig_t     ecpsig, *ecpsigp;
        cdkonbsig_t     onbsig, *onbsigp;
@@ -3820,15 +3964,19 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
                                continue;
                }
                if (brdp->brdtype == BRD_ECPE) {
-                       ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp, CDK_SIGADDR, __LINE__);
+                       ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp,
+                               CDK_SIGADDR, __LINE__);
                        memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
                        if (ecpsig.magic == ECP_MAGIC)
                                foundit = 1;
                } else {
-                       onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp, CDK_SIGADDR, __LINE__);
+                       onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp,
+                               CDK_SIGADDR, __LINE__);
                        memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
-                       if ((onbsig.magic0 == ONB_MAGIC0) && (onbsig.magic1 == ONB_MAGIC1) &&
-                                       (onbsig.magic2 == ONB_MAGIC2) && (onbsig.magic3 == ONB_MAGIC3))
+                       if ((onbsig.magic0 == ONB_MAGIC0) &&
+                           (onbsig.magic1 == ONB_MAGIC1) &&
+                           (onbsig.magic2 == ONB_MAGIC2) &&
+                           (onbsig.magic3 == ONB_MAGIC3))
                                foundit = 1;
                }
                if (brdp->memaddr >= 0x100000)
@@ -3849,7 +3997,9 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
        if (! foundit) {
                brdp->memaddr = 0;
                brdp->membase = 0;
-               printk("STALLION: failed to probe shared memory region for %s in EISA slot=%d\n", stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
+               printk("STALLION: failed to probe shared memory region for "
+                       "%s in EISA slot=%d\n", stli_brdnames[brdp->brdtype],
+                       (brdp->iobase >> 12));
                return(-ENODEV);
        }
        return(0);
@@ -3867,7 +4017,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
  *     do is go probing around in the usual places hoping we can find it.
  */
 
-static int stli_findeisabrds()
+static inline int stli_findeisabrds()
 {
        stlibrd_t       *brdp;
        unsigned int    iobase, eid;
@@ -3915,7 +4065,8 @@ static int stli_findeisabrds()
  *             info table.
  */
                if (stli_nrbrds >= STL_MAXBRDS) {
-                       printk("STALLION: no room for more probed boards, maximum supported %d\n", STL_MAXBRDS);
+                       printk("STALLION: no room for more probed boards, "
+                               "maximum supported %d\n", STL_MAXBRDS);
                        break;
                }
 
@@ -3925,7 +4076,8 @@ static int stli_findeisabrds()
  */
                brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
                if (brdp == (stlibrd_t *) NULL) {
-                       printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+                       printk("STALLION: failed to allocate memory "
+                               "(size=%d)\n", sizeof(stlibrd_t));
                        return(-ENOMEM);
                }
                memset(brdp, 0, sizeof(stlibrd_t));
@@ -3956,7 +4108,7 @@ static int stli_findeisabrds()
  *     can find.
  */
 
-static int stli_initbrds()
+static inline int stli_initbrds()
 {
        stlibrd_t       *brdp, *nxtbrdp;
        stlconf_t       *confp;
@@ -3967,7 +4119,8 @@ static int stli_initbrds()
 #endif
 
        if (stli_nrbrds > STL_MAXBRDS) {
-               printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
+               printk("STALLION: too many boards in configuration table, "
+                       "truncating to %d\n", STL_MAXBRDS);
                stli_nrbrds = STL_MAXBRDS;
        }
 
@@ -3979,7 +4132,8 @@ static int stli_initbrds()
                confp = &stli_brdconf[i];
                brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t));
                if (brdp == (stlibrd_t *) NULL) {
-                       printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlibrd_t));
+                       printk("STALLION: failed to allocate memory "
+                               "(size=%d)\n", sizeof(stlibrd_t));
                        return(-ENOMEM);
                }
                memset(brdp, 0, sizeof(stlibrd_t));
@@ -4013,7 +4167,9 @@ static int stli_initbrds()
                                nxtbrdp = stli_brds[j];
                                if (nxtbrdp == (stlibrd_t *) NULL)
                                        continue;
-                               if ((brdp->membase >= nxtbrdp->membase) && (brdp->membase <= (nxtbrdp->membase + nxtbrdp->memsize - 1))) {
+                               if ((brdp->membase >= nxtbrdp->membase) &&
+                                   (brdp->membase <= (nxtbrdp->membase +
+                                   nxtbrdp->memsize - 1))) {
                                        stli_shared++;
                                        break;
                                }
@@ -4053,7 +4209,8 @@ static int stli_memread(struct inode *ip, struct file *fp, char *buf, int count)
        int             brdnr, size, n;
 
 #if DEBUG
-       printk("stli_memread(ip=%x,fp=%x,buf=%x,count=%d)\n", (int) ip, (int) fp, (int) buf, count);
+       printk("stli_memread(ip=%x,fp=%x,buf=%x,count=%d)\n", (int) ip,
+               (int) fp, (int) buf, count);
 #endif
 
        brdnr = MINOR(ip->i_rdev);
@@ -4103,7 +4260,8 @@ static int stli_memwrite(struct inode *ip, struct file *fp, const char *buf, int
        int             brdnr, size, n;
 
 #if DEBUG
-       printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%x)\n", (int) ip, (int) fp, (int) buf, count);
+       printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%x)\n", (int) ip,
+               (int) fp, (int) buf, count);
 #endif
 
        brdnr = MINOR(ip->i_rdev);
@@ -4205,31 +4363,28 @@ static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
  *     what port to get stats for (used through board control device).
  */
 
-static int stli_getportstats(stliport_t *portp, comstats_t *cp)
+static int stli_portcmdstats(stliport_t *portp)
 {
        unsigned long   flags;
        stlibrd_t       *brdp;
        int             rc;
 
-       if (portp == (stliport_t *) NULL) {
-               memcpy_fromfs(&stli_comstats, cp, sizeof(comstats_t));
-               portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port);
-               if (portp == (stliport_t *) NULL)
-                       return(-ENODEV);
-       }
+       memset(&stli_comstats, 0, sizeof(comstats_t));
 
+       if (portp == (stliport_t *) NULL)
+               return(-ENODEV);
        brdp = stli_brds[portp->brdnr];
        if (brdp == (stlibrd_t *) NULL)
                return(-ENODEV);
 
        if (brdp->state & BST_STARTED) {
-               if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS, &stli_cdkstats, sizeof(asystats_t), 1)) < 0)
+               if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS,
+                   &stli_cdkstats, sizeof(asystats_t), 1)) < 0)
                        return(rc);
        } else {
                memset(&stli_cdkstats, 0, sizeof(asystats_t));
        }
 
-       memset(&stli_comstats, 0, sizeof(comstats_t));
        stli_comstats.brd = portp->brdnr;
        stli_comstats.panel = portp->panelnr;
        stli_comstats.port = portp->portnr;
@@ -4272,6 +4427,37 @@ static int stli_getportstats(stliport_t *portp, comstats_t *cp)
        stli_comstats.hwid = stli_cdkstats.hwid;
        stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals);
 
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the port stats structure to user app. A NULL port struct
+ *     pointer passed in means that we need to find out from the app
+ *     what port to get stats for (used through board control device).
+ */
+
+static int stli_getportstats(stliport_t *portp, comstats_t *cp)
+{
+       stlibrd_t       *brdp;
+       int             rc;
+
+       if (portp == (stliport_t *) NULL) {
+               memcpy_fromfs(&stli_comstats, cp, sizeof(comstats_t));
+               portp = stli_getport(stli_comstats.brd, stli_comstats.panel,
+                       stli_comstats.port);
+               if (portp == (stliport_t *) NULL)
+                       return(-ENODEV);
+       }
+
+       brdp = stli_brds[portp->brdnr];
+       if (brdp == (stlibrd_t *) NULL)
+               return(-ENODEV);
+
+       if ((rc = stli_portcmdstats(portp)) < 0)
+               return(rc);
+
        memcpy_tofs(cp, &stli_comstats, sizeof(comstats_t));
        return(0);
 }
@@ -4289,7 +4475,8 @@ static int stli_clrportstats(stliport_t *portp, comstats_t *cp)
 
        if (portp == (stliport_t *) NULL) {
                memcpy_fromfs(&stli_comstats, cp, sizeof(comstats_t));
-               portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port);
+               portp = stli_getport(stli_comstats.brd, stli_comstats.panel,
+                       stli_comstats.port);
                if (portp == (stliport_t *) NULL)
                        return(-ENODEV);
        }
@@ -4353,6 +4540,26 @@ static int stli_getbrdstruct(unsigned long arg)
 
 /*****************************************************************************/
 
+/*
+ *     Memory device open code. Need to keep track of opens and close
+ *     for module handling.
+ */
+
+static int stli_memopen(struct inode *ip, struct file *fp)
+{
+       MOD_INC_USE_COUNT;
+       return(0);
+}
+
+/*****************************************************************************/
+
+static void stli_memclose(struct inode *ip, struct file *fp)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+/*****************************************************************************/
+
 /*
  *     The "staliomem" device is also required to do some special operations on
  *     the board. We need to be able to send an interrupt to the board,
@@ -4365,7 +4572,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
        int             brdnr, rc, done;
 
 #if DEBUG
-       printk("stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg);
+       printk("stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip,
+               (int) fp, cmd, (int) arg);
 #endif
 
 /*
@@ -4376,27 +4584,34 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
        switch (cmd) {
        case COM_GETPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
-                       rc = stli_getportstats((stliport_t *) NULL, (comstats_t *) arg);
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
+                       rc = stli_getportstats((stliport_t *) NULL,
+                               (comstats_t *) arg);
                done++;
                break;
        case COM_CLRPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
-                       rc = stli_clrportstats((stliport_t *) NULL, (comstats_t *) arg);
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
+                       rc = stli_clrportstats((stliport_t *) NULL,
+                               (comstats_t *) arg);
                done++;
                break;
        case COM_GETBRDSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(combrd_t))) == 0)
                        rc = stli_getbrdstats((combrd_t *) arg);
                done++;
                break;
        case COM_READPORT:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stliport_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(stliport_t))) == 0)
                        rc = stli_getportstruct(arg);
                done++;
                break;
        case COM_READBOARD:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlibrd_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(stlibrd_t))) == 0)
                        rc = stli_getbrdstruct(arg);
                done++;
                break;
@@ -4450,7 +4665,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
 
 int stli_init()
 {
-       printk(KERN_INFO "%s: version %s\n", stli_drvname, stli_drvversion);
+       printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
 
        stli_initbrds();
 
@@ -4459,10 +4674,12 @@ int stli_init()
  */
        stli_tmpwritebuf = (char *) stli_memalloc(STLI_TXBUFSIZE);
        if (stli_tmpwritebuf == (char *) NULL)
-               printk("STALLION: failed to allocate memory (size=%d)\n", STLI_TXBUFSIZE);
+               printk("STALLION: failed to allocate memory (size=%d)\n",
+                       STLI_TXBUFSIZE);
        stli_txcookbuf = (char *) stli_memalloc(STLI_TXBUFSIZE);
        if (stli_txcookbuf == (char *) NULL)
-               printk("STALLION: failed to allocate memory (size=%d)\n", STLI_TXBUFSIZE);
+               printk("STALLION: failed to allocate memory (size=%d)\n",
+                       STLI_TXBUFSIZE);
 
 /*
  *     Set up a character driver for the shared memory region. We need this
index c58a1f205724bd10e85620bacadca7dae1684771..9c1a932f2bc0f55fe52a51510751ca83688518f2 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     stallion.c  -- stallion multiport serial driver.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This code is loosely based on the Linux serial driver, written by
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/cd1400.h>
+#include <linux/sc26198.h>
 #include <linux/comstats.h>
 #include <linux/stallion.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
-#include <linux/config.h>      /* for CONFIG_PCI */
+#include <linux/config.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 /*****************************************************************************/
 
 /*
- *     Define different board types. At the moment I have only declared
- *     those boards that this driver supports. But I will use the standard
- *     "assigned" board numbers. In the future this driver will support
- *     some of the other Stallion boards. Currently supported boards are
- *     abbreviated as EIO = EasyIO and ECH = EasyConnection 8/32.
+ *     Define different board types. Use the standard Stallion "assigned"
+ *     board numbers. Boards supported in this driver are abbreviated as
+ *     EIO = EasyIO and ECH = EasyConnection 8/32.
  */
 #define        BRD_EASYIO      20
 #define        BRD_ECH         21
 #define        BRD_ECHMC       22
 #define        BRD_ECHPCI      26
+#define        BRD_ECH64PCI    27
+#define        BRD_EASYIOPCI   28
 
 /*
  *     Define a configuration structure to hold the board configuration.
@@ -126,12 +128,11 @@ static int        stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
 #define        STL_DRVTYPCALLOUT       2
 
 /*
- *     I haven't really decided (or measured) what TX buffer size gives
- *     a good balance between performance and memory usage. These seem
- *     to work pretty well...
+ *     Set the TX buffer size. Bigger is better, but we don't want
+ *     to chew too much memory with buffers!
  */
-#define        STL_TXBUFLOW            256
-#define        STL_TXBUFSIZE           2048
+#define        STL_TXBUFLOW            512
+#define        STL_TXBUFSIZE           4096
 
 /*****************************************************************************/
 
@@ -139,8 +140,8 @@ static int  stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
  *     Define our local driver identity first. Set up stuff to deal with
  *     all the local structures required by a serial tty driver.
  */
-static char    *stl_drvname = "Stallion Multiport Serial Driver";
-static char    *stl_drvversion = "1.1.3";
+static char    *stl_drvtitle = "Stallion Multiport Serial Driver";
+static char    *stl_drvversion = "5.4.4";
 static char    *stl_serialname = "ttyE";
 static char    *stl_calloutname = "cue";
 
@@ -184,6 +185,11 @@ static combrd_t            stl_brdstats;
 static stlbrd_t                stl_dummybrd;
 static stlport_t       stl_dummyport;
 
+/*
+ *     Define global place to put buffer overflow characters.
+ */
+static char            stl_unwanted[SC26198_RXFIFOSIZE];
+
 /*
  *     Keep track of what interrupts we have requested for us.
  *     We don't need to request an interrupt twice if it is being
@@ -198,7 +204,7 @@ static stlbrd_t             *stl_brds[STL_MAXBRDS];
 
 /*
  *     Per board state flags. Used with the state field of the board struct.
- *     Not really much here yet!
+ *     Not really much here!
  */
 #define        BRD_FOUND       0x1
 
@@ -210,6 +216,7 @@ static stlbrd_t             *stl_brds[STL_MAXBRDS];
 #define        ASYI_TXBUSY     1
 #define        ASYI_TXLOW      2
 #define        ASYI_DCDCHANGE  3
+#define        ASYI_TXFLOWED   4
 
 /*
  *     Define an array of board names as printable strings. Handy for
@@ -243,23 +250,33 @@ static char       *stl_brdnames[] = {
        (char *) NULL,
        (char *) NULL,
        "EC8/32-PCI",
+       "EC8/64-PCI",
+       "EasyIO-PCI",
 };
 
 /*****************************************************************************/
 
 /*
  *     Hardware ID bits for the EasyIO and ECH boards. These defines apply
- *     to the directly accessible io ports of these boards (not the cd1400
- *     uarts - they are in cd1400.h).
+ *     to the directly accessible io ports of these boards (not the uarts -
+ *     they are in cd1400.h and sc26198.h).
  */
 #define        EIO_8PORTRS     0x04
 #define        EIO_4PORTRS     0x05
 #define        EIO_8PORTDI     0x00
 #define        EIO_8PORTM      0x06
+#define        EIO_MK3         0x03
 #define        EIO_IDBITMASK   0x07
+
+#define        EIO_BRDMASK     0xf0
+#define        ID_BRD4         0x10
+#define        ID_BRD8         0x20
+#define        ID_BRD16        0x30
+
 #define        EIO_INTRPEND    0x08
 #define        EIO_INTEDGE     0x00
 #define        EIO_INTLEVEL    0x08
+#define        EIO_0WS         0x10
 
 #define        ECH_ID          0xa0
 #define        ECH_IDBITMASK   0xe0
@@ -278,24 +295,10 @@ static char       *stl_brdnames[] = {
 #define        ECH_PNLSTATUS   2
 #define        ECH_PNL16PORT   0x20
 #define        ECH_PNLIDMASK   0x07
+#define        ECH_PNLXPID     0x40
 #define        ECH_PNLINTRPEND 0x80
-#define        ECH_ADDR2MASK   0x1e0
-
-#define        EIO_CLK         25000000
-#define        EIO_CLK8M       20000000
-#define        ECH_CLK         EIO_CLK
-
-/*
- *     Define the offsets within the register bank for all io registers.
- *     These io address offsets are common to both the EIO and ECH.
- */
-#define        EREG_ADDR       0
-#define        EREG_DATA       4
-#define        EREG_RXACK      5
-#define        EREG_TXACK      6
-#define        EREG_MDACK      7
 
-#define        EREG_BANKSIZE   8
+#define        ECH_ADDR2MASK   0x1e0
 
 /*
  *     Define the vector mapping bits for the programmable interrupt board
@@ -326,18 +329,51 @@ static unsigned char      stl_vecmap[] = {
                outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE),   \
                        stl_brds[(brdnr)]->ioctrl);
 
+#define        STL_CD1400MAXBAUD       230400
+#define        STL_SC26198MAXBAUD      460800
+
+#define        STL_BAUDBASE            115200
+#define        STL_CLOSEDELAY          (5 * HZ / 10)
+
+/*****************************************************************************/
+
+#ifdef CONFIG_PCI
+
 /*
- *     Define the cd1400 baud rate clocks. These are used when calculating
- *     what clock and divisor to use for the required baud rate. Also
- *     define the maximum baud rate allowed, and the default base baud.
+ *     Define the Stallion PCI vendor and device IDs.
  */
-static int     stl_cd1400clkdivs[] = {
-       CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4
+#ifndef        PCI_VENDOR_ID_STALLION
+#define        PCI_VENDOR_ID_STALLION          0x124d
+#endif
+#ifndef PCI_DEVICE_ID_ECHPCI832
+#define        PCI_DEVICE_ID_ECHPCI832         0x0000
+#endif
+#ifndef PCI_DEVICE_ID_ECHPCI864
+#define        PCI_DEVICE_ID_ECHPCI864         0x0002
+#endif
+#ifndef PCI_DEVICE_ID_EIOPCI
+#define        PCI_DEVICE_ID_EIOPCI            0x0003
+#endif
+
+/*
+ *     Define structure to hold all Stallion PCI boards.
+ */
+typedef struct stlpcibrd {
+       unsigned short          vendid;
+       unsigned short          devid;
+       int                     brdtype;
+} stlpcibrd_t;
+
+static stlpcibrd_t     stl_pcibrds[] = {
+       { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI },
+       { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI },
+       { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI },
+       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI },
 };
 
-#define        STL_MAXBAUD     230400
-#define        STL_BAUDBASE    115200
-#define        STL_CLOSEDELAY  50
+static int     stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t);
+
+#endif
 
 /*****************************************************************************/
 
@@ -349,16 +385,14 @@ static int        stl_cd1400clkdivs[] = {
 
 /*
  *     Define a baud rate table that converts termios baud rate selector
- *     into the actual baud rate value. All baud rate calculates are based
- *     on the actual baud rate required.
+ *     into the actual baud rate value. All baud rate calculations are
+ *     based on the actual baud rate required.
  */
 static unsigned int    stl_baudrates[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
 };
 
-/*****************************************************************************/
-
 /*
  *     Define some handy local macros...
  */
@@ -392,15 +426,15 @@ static void       stl_unthrottle(struct tty_struct *tty);
 static void    stl_stop(struct tty_struct *tty);
 static void    stl_start(struct tty_struct *tty);
 static void    stl_flushbuffer(struct tty_struct *tty);
+static void    stl_waituntilsent(struct tty_struct *tty, int timeout);
 static void    stl_hangup(struct tty_struct *tty);
+static int     stl_memopen(struct inode *ip, struct file *fp);
+static void    stl_memclose(struct inode *ip, struct file *fp);
 static int     stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
 
-static int     stl_initbrds(void);
 static int     stl_brdinit(stlbrd_t *brdp);
-static int     stl_initeio(stlbrd_t *brdp);
-static int     stl_initech(stlbrd_t *brdp);
 static int     stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int     stl_mapirq(int irq);
+static int     stl_mapirq(int irq, char *name);
 static void    stl_getserial(stlport_t *portp, struct serial_struct *sp);
 static int     stl_setserial(stlport_t *portp, struct serial_struct *sp);
 static int     stl_getbrdstats(combrd_t *bp);
@@ -408,28 +442,212 @@ static int       stl_getportstats(stlport_t *portp, comstats_t *cp);
 static int     stl_clrportstats(stlport_t *portp, comstats_t *cp);
 static int     stl_getportstruct(unsigned long arg);
 static int     stl_getbrdstruct(unsigned long arg);
-static void    stl_setreg(stlport_t *portp, int regnr, int value);
-static int     stl_getreg(stlport_t *portp, int regnr);
-static int     stl_updatereg(stlport_t *portp, int regnr, int value);
-static void    stl_setport(stlport_t *portp, struct termios *tiosp);
-static int     stl_getsignals(stlport_t *portp);
-static void    stl_setsignals(stlport_t *portp, int dtr, int rts);
-static void    stl_ccrwait(stlport_t *portp);
-static void    stl_enablerxtx(stlport_t *portp, int rx, int tx);
-static void    stl_startrxtx(stlport_t *portp, int rx, int tx);
-static void    stl_disableintrs(stlport_t *portp);
-static void    stl_sendbreak(stlport_t *portp, long len);
 static int     stl_waitcarrier(stlport_t *portp, struct file *filp);
 static void    stl_delay(int len);
 static void    stl_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void    stl_eiointr(stlbrd_t *brdp);
+static void    stl_echatintr(stlbrd_t *brdp);
+static void    stl_echmcaintr(stlbrd_t *brdp);
+static void    stl_echpciintr(stlbrd_t *brdp);
+static void    stl_echpci64intr(stlbrd_t *brdp);
 static void    stl_offintr(void *private);
 static void    *stl_memalloc(int len);
 static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
 
+static inline int      stl_initbrds(void);
+static inline int      stl_initeio(stlbrd_t *brdp);
+static inline int      stl_initech(stlbrd_t *brdp);
+
 #ifdef CONFIG_PCI
-static int     stl_findpcibrds(void);
+static inline int      stl_findpcibrds(void);
+static inline int      stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr);
 #endif
 
+/*
+ *     CD1400 uart specific handling functions.
+ */
+static void    stl_cd1400setreg(stlport_t *portp, int regnr, int value);
+static int     stl_cd1400getreg(stlport_t *portp, int regnr);
+static int     stl_cd1400updatereg(stlport_t *portp, int regnr, int value);
+static int     stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
+static void    stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
+static void    stl_cd1400setport(stlport_t *portp, struct termios *tiosp);
+static int     stl_cd1400getsignals(stlport_t *portp);
+static void    stl_cd1400setsignals(stlport_t *portp, int dtr, int rts);
+static void    stl_cd1400ccrwait(stlport_t *portp);
+static void    stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx);
+static void    stl_cd1400startrxtx(stlport_t *portp, int rx, int tx);
+static void    stl_cd1400disableintrs(stlport_t *portp);
+static void    stl_cd1400sendbreak(stlport_t *portp, long len);
+static void    stl_cd1400flowctrl(stlport_t *portp, int state);
+static void    stl_cd1400sendflow(stlport_t *portp, int state);
+static void    stl_cd1400flush(stlport_t *portp);
+static int     stl_cd1400datastate(stlport_t *portp);
+static void    stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase);
+static void    stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase);
+static void    stl_cd1400txisr(stlpanel_t *panelp, int ioaddr);
+static void    stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr);
+static void    stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr);
+
+/*
+ *     SC26198 uart specific handling functions.
+ */
+static void    stl_sc26198setreg(stlport_t *portp, int regnr, int value);
+static int     stl_sc26198getreg(stlport_t *portp, int regnr);
+static int     stl_sc26198updatereg(stlport_t *portp, int regnr, int value);
+static int     stl_sc26198getglobreg(stlport_t *portp, int regnr);
+static int     stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
+static void    stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
+static void    stl_sc26198setport(stlport_t *portp, struct termios *tiosp);
+static int     stl_sc26198getsignals(stlport_t *portp);
+static void    stl_sc26198setsignals(stlport_t *portp, int dtr, int rts);
+static void    stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx);
+static void    stl_sc26198startrxtx(stlport_t *portp, int rx, int tx);
+static void    stl_sc26198disableintrs(stlport_t *portp);
+static void    stl_sc26198sendbreak(stlport_t *portp, long len);
+static void    stl_sc26198flowctrl(stlport_t *portp, int state);
+static void    stl_sc26198sendflow(stlport_t *portp, int state);
+static void    stl_sc26198flush(stlport_t *portp);
+static int     stl_sc26198datastate(stlport_t *portp);
+static void    stl_sc26198wait(stlport_t *portp);
+static void    stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty);
+static void    stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase);
+static void    stl_sc26198txisr(stlport_t *port);
+static void    stl_sc26198rxisr(stlport_t *port, unsigned int iack);
+static void    stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch);
+static void    stl_sc26198rxbadchars(stlport_t *portp);
+static void    stl_sc26198otherisr(stlport_t *port, unsigned int iack);
+
+/*****************************************************************************/
+
+/*
+ *     Generic UART support structure.
+ */
+typedef struct uart {
+       int     (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp);
+       void    (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
+       void    (*setport)(stlport_t *portp, struct termios *tiosp);
+       int     (*getsignals)(stlport_t *portp);
+       void    (*setsignals)(stlport_t *portp, int dtr, int rts);
+       void    (*enablerxtx)(stlport_t *portp, int rx, int tx);
+       void    (*startrxtx)(stlport_t *portp, int rx, int tx);
+       void    (*disableintrs)(stlport_t *portp);
+       void    (*sendbreak)(stlport_t *portp, long len);
+       void    (*flowctrl)(stlport_t *portp, int state);
+       void    (*sendflow)(stlport_t *portp, int state);
+       void    (*flush)(stlport_t *portp);
+       int     (*datastate)(stlport_t *portp);
+       void    (*intr)(stlpanel_t *panelp, unsigned int iobase);
+} uart_t;
+
+/*
+ *     Define some macros to make calling these functions nice and clean.
+ */
+#define        stl_panelinit           (* ((uart_t *) panelp->uartp)->panelinit)
+#define        stl_portinit            (* ((uart_t *) portp->uartp)->portinit)
+#define        stl_setport             (* ((uart_t *) portp->uartp)->setport)
+#define        stl_getsignals          (* ((uart_t *) portp->uartp)->getsignals)
+#define        stl_setsignals          (* ((uart_t *) portp->uartp)->setsignals)
+#define        stl_enablerxtx          (* ((uart_t *) portp->uartp)->enablerxtx)
+#define        stl_startrxtx           (* ((uart_t *) portp->uartp)->startrxtx)
+#define        stl_disableintrs        (* ((uart_t *) portp->uartp)->disableintrs)
+#define        stl_sendbreak           (* ((uart_t *) portp->uartp)->sendbreak)
+#define        stl_flowctrl            (* ((uart_t *) portp->uartp)->flowctrl)
+#define        stl_sendflow            (* ((uart_t *) portp->uartp)->sendflow)
+#define        stl_flush               (* ((uart_t *) portp->uartp)->flush)
+#define        stl_datastate           (* ((uart_t *) portp->uartp)->datastate)
+
+/*****************************************************************************/
+
+/*
+ *     CD1400 UART specific data initialization.
+ */
+static uart_t stl_cd1400uart = {
+       stl_cd1400panelinit,
+       stl_cd1400portinit,
+       stl_cd1400setport,
+       stl_cd1400getsignals,
+       stl_cd1400setsignals,
+       stl_cd1400enablerxtx,
+       stl_cd1400startrxtx,
+       stl_cd1400disableintrs,
+       stl_cd1400sendbreak,
+       stl_cd1400flowctrl,
+       stl_cd1400sendflow,
+       stl_cd1400flush,
+       stl_cd1400datastate,
+       stl_cd1400eiointr
+};
+
+/*
+ *     Define the offsets within the register bank of a cd1400 based panel.
+ *     These io address offsets are common to the EasyIO board as well.
+ */
+#define        EREG_ADDR       0
+#define        EREG_DATA       4
+#define        EREG_RXACK      5
+#define        EREG_TXACK      6
+#define        EREG_MDACK      7
+
+#define        EREG_BANKSIZE   8
+
+#define        CD1400_CLK      25000000
+#define        CD1400_CLK8M    20000000
+
+/*
+ *     Define the cd1400 baud rate clocks. These are used when calculating
+ *     what clock and divisor to use for the required baud rate. Also
+ *     define the maximum baud rate allowed, and the default base baud.
+ */
+static int     stl_cd1400clkdivs[] = {
+       CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4
+};
+
+/*****************************************************************************/
+
+/*
+ *     SC26198 UART specific data initization.
+ */
+static uart_t stl_sc26198uart = {
+       stl_sc26198panelinit,
+       stl_sc26198portinit,
+       stl_sc26198setport,
+       stl_sc26198getsignals,
+       stl_sc26198setsignals,
+       stl_sc26198enablerxtx,
+       stl_sc26198startrxtx,
+       stl_sc26198disableintrs,
+       stl_sc26198sendbreak,
+       stl_sc26198flowctrl,
+       stl_sc26198sendflow,
+       stl_sc26198flush,
+       stl_sc26198datastate,
+       stl_sc26198intr
+};
+
+/*
+ *     Define the offsets within the register bank of a sc26198 based panel.
+ */
+#define        XP_DATA         0
+#define        XP_ADDR         1
+#define        XP_MODID        2
+#define        XP_STATUS       2
+#define        XP_IACK         3
+
+#define        XP_BANKSIZE     4
+
+/*
+ *     Define the sc26198 baud rate table. Offsets within the table
+ *     represent the actual baud rate selector of sc26198 registers.
+ */
+static unsigned int    sc26198_baudtable[] = {
+       50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600,
+       4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200,
+       230400, 460800, 921600
+};
+
+#define        SC26198_NRBAUDS         (sizeof(sc26198_baudtable) / sizeof(unsigned int))
+
 /*****************************************************************************/
 
 /*
@@ -444,8 +662,8 @@ static struct file_operations       stl_fsiomem = {
        NULL,
        stl_memioctl,
        NULL,
-       NULL,
-       NULL,
+       stl_memopen,
+       stl_memclose,
        NULL
 };
 
@@ -487,7 +705,8 @@ void cleanup_module()
        printk("cleanup_module()\n");
 #endif
 
-       printk(KERN_INFO "Unloading %s: version %s\n", stl_drvname, stl_drvversion);
+       printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
+               stl_drvversion);
 
        save_flags(flags);
        cli();
@@ -501,12 +720,14 @@ void cleanup_module()
        i = tty_unregister_driver(&stl_serial);
        j = tty_unregister_driver(&stl_callout);
        if (i || j) {
-               printk("STALLION: failed to un-register tty driver, errno=%d,%d\n", -i, -j);
+               printk("STALLION: failed to un-register tty driver, "
+                       "errno=%d,%d\n", -i, -j);
                restore_flags(flags);
                return;
        }
        if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-               printk("STALLION: failed to un-register serial memory device, errno=%d\n", -i);
+               printk("STALLION: failed to un-register serial memory device, "
+                       "errno=%d\n", -i);
 
        if (stl_tmpwritebuf != (char *) NULL)
                kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE);
@@ -515,33 +736,24 @@ void cleanup_module()
                brdp = stl_brds[i];
                for (j = 0; (j < STL_MAXPANELS); j++) {
                        panelp = brdp->panels[j];
-                       if (panelp != (stlpanel_t *) NULL) {
-                               for (k = 0; (k < STL_PORTSPERPANEL); k++) {
-                                       portp = panelp->ports[k];
-                                       if (portp != (stlport_t *) NULL) {
-                                               if (portp->tty != (struct tty_struct *) NULL)
-                                                       stl_hangup(portp->tty);
-                                               if (portp->tx.buf != (char *) NULL)
-                                                       kfree_s(portp->tx.buf, STL_TXBUFSIZE);
-                                               kfree_s(portp, sizeof(stlport_t));
-                                       }
-                               }
-                               kfree_s(panelp, sizeof(stlpanel_t));
+                       if (panelp == (stlpanel_t *) NULL)
+                               continue;
+                       for (k = 0; (k < STL_PORTSPERPANEL); k++) {
+                               portp = panelp->ports[k];
+                               if (portp == (stlport_t *) NULL)
+                                       continue;
+                               if (portp->tty != (struct tty_struct *) NULL)
+                                       stl_hangup(portp->tty);
+                               if (portp->tx.buf != (char *) NULL)
+                                       kfree_s(portp->tx.buf, STL_TXBUFSIZE);
+                               kfree_s(portp, sizeof(stlport_t));
                        }
-                       
+                       kfree_s(panelp, sizeof(stlpanel_t));
                }
 
-               if (brdp->brdtype == BRD_ECH) {
-                       release_region(brdp->ioaddr1, 2);
-                       release_region(brdp->ioaddr2, 32);
-               } else if (brdp->brdtype == BRD_ECHPCI) {
-                       release_region(brdp->ioaddr1, 4);
-                       release_region(brdp->ioaddr2, 8);
-               } else if (brdp->brdtype == BRD_ECHMC) {
-                       release_region(brdp->ioaddr1, 64);
-               } else if (brdp->brdtype == BRD_EASYIO) {
-                       release_region(brdp->ioaddr1, 8);
-               }
+               release_region(brdp->ioaddr1, brdp->iosize1);
+               if (brdp->iosize2 > 0)
+                       release_region(brdp->ioaddr2, brdp->iosize2);
 
                kfree_s(brdp, sizeof(stlbrd_t));
                stl_brds[i] = (stlbrd_t *) NULL;
@@ -576,7 +788,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        int             brdnr, panelnr, portnr, rc;
 
 #if DEBUG
-       printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, (int) filp, tty->device);
+       printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty,
+               (int) filp, tty->device);
 #endif
 
        minordev = MINOR(tty->device);
@@ -603,6 +816,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
        if (portp == (stlport_t *) NULL)
                return(-ENODEV);
 
+       MOD_INC_USE_COUNT;
+
 /*
  *     On the first open of the device setup the port hardware, and
  *     initialize the per port data structure.
@@ -651,10 +866,10 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
                        return(-EBUSY);
                if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
                        if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
-                                       (portp->session != current->session))
+                           (portp->session != current->session))
                                return(-EBUSY);
                        if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
-                                       (portp->pgrp != current->pgrp))
+                           (portp->pgrp != current->pgrp))
                                return(-EBUSY);
                }
                portp->flags |= ASYNC_CALLOUT_ACTIVE;
@@ -712,13 +927,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
        save_flags(flags);
        cli();
        portp->openwaitcnt++;
-       if (portp->refcount > 0)
+       if (! tty_hung_up_p(filp))
                portp->refcount--;
 
        for (;;) {
                if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0)
                        stl_setsignals(portp, 1, 1);
-               if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) {
+               if (tty_hung_up_p(filp) ||
+                   ((portp->flags & ASYNC_INITIALIZED) == 0)) {
                        if (portp->flags & ASYNC_HUP_NOTIFY)
                                rc = -EBUSY;
                        else
@@ -726,8 +942,8 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
                        break;
                }
                if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
-                               ((portp->flags & ASYNC_CLOSING) == 0) &&
-                               (doclocal || (portp->sigs & TIOCM_CD))) {
+                   ((portp->flags & ASYNC_CLOSING) == 0) &&
+                   (doclocal || (portp->sigs & TIOCM_CD))) {
                        break;
                }
                if (current->signal & ~current->blocked) {
@@ -763,10 +979,14 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
        save_flags(flags);
        cli();
        if (tty_hung_up_p(filp)) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
+       if ((tty->count == 1) && (portp->refcount != 1))
+               portp->refcount = 1;
        if (portp->refcount-- > 1) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
@@ -781,14 +1001,14 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
 
 /*
  *     May want to wait for any data to drain before closing. The BUSY
- *     flag keeps track of whether we are still sending or not - it allows
- *     for the FIFO in the cd1400.
+ *     flag keeps track of whether we are still sending or not - it is
+ *     very accurate for the cd1400, not quite so for the sc26198.
+ *     (The sc26198 has no "end-of-data" interrupt only empty FIFO)
  */
        tty->closing = 1;
-       if (test_bit(ASYI_TXBUSY, &portp->istate)) {
-               if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-                       tty_wait_until_sent(tty, portp->closing_wait);
-       }
+       if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, portp->closing_wait);
+       stl_waituntilsent(tty, (HZ / 2));
 
        portp->flags &= ~ASYNC_INITIALIZED;
        stl_disableintrs(portp);
@@ -808,7 +1028,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
                (tty->ldisc.flush_buffer)(tty);
 
        tty->closing = 0;
-       tty->driver_data = (void *) NULL;
        portp->tty = (struct tty_struct *) NULL;
 
        if (portp->openwaitcnt) {
@@ -817,8 +1036,10 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
                wake_up_interruptible(&portp->open_wait);
        }
 
-       portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
+               ASYNC_CLOSING);
        wake_up_interruptible(&portp->close_wait);
+       MOD_DEC_USE_COUNT;
        restore_flags(flags);
 }
 
@@ -858,10 +1079,12 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char
        char            *head, *tail;
 
 #if DEBUG
-       printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", (int) tty, from_user, (int) buf, count);
+       printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
+               (int) tty, from_user, (int) buf, count);
 #endif
 
-       if ((tty == (struct tty_struct *) NULL) || (stl_tmpwritebuf == (char *) NULL))
+       if ((tty == (struct tty_struct *) NULL) ||
+           (stl_tmpwritebuf == (char *) NULL))
                return(0);
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
@@ -983,7 +1206,8 @@ static void stl_flushchars(struct tty_struct *tty)
                return;
 
 #if 0
-       if (tty->stopped || tty->hw_stopped || (portp->tx.head == portp->tx.tail))
+       if (tty->stopped || tty->hw_stopped ||
+           (portp->tx.head == portp->tx.tail))
                return;
 #endif
        stl_startrxtx(portp, -1, 1);
@@ -1066,7 +1290,6 @@ static void stl_getserial(stlport_t *portp, struct serial_struct *sp)
 #endif
 
        memset(&sio, 0, sizeof(struct serial_struct));
-       sio.type = PORT_CIRRUS;
        sio.line = portp->portnr;
        sio.port = portp->ioaddr;
        sio.flags = portp->flags;
@@ -1074,8 +1297,14 @@ static void stl_getserial(stlport_t *portp, struct serial_struct *sp)
        sio.close_delay = portp->close_delay;
        sio.closing_wait = portp->closing_wait;
        sio.custom_divisor = portp->custom_divisor;
-       sio.xmit_fifo_size = CD1400_TXFIFOSIZE;
        sio.hub6 = 0;
+       if (portp->uartp == &stl_cd1400uart) {
+               sio.type = PORT_CIRRUS;
+               sio.xmit_fifo_size = CD1400_TXFIFOSIZE;
+       } else {
+               sio.type = PORT_UNKNOWN;
+               sio.xmit_fifo_size = SC26198_TXFIFOSIZE;
+       }
 
        brdp = stl_brds[portp->brdnr];
        if (brdp != (stlbrd_t *) NULL)
@@ -1103,12 +1332,14 @@ static int stl_setserial(stlport_t *portp, struct serial_struct *sp)
        memcpy_fromfs(&sio, sp, sizeof(struct serial_struct));
        if (!suser()) {
                if ((sio.baud_base != portp->baud_base) ||
-                               (sio.close_delay != portp->close_delay) ||
-                               ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK)))
+                   (sio.close_delay != portp->close_delay) ||
+                   ((sio.flags & ~ASYNC_USR_MASK) !=
+                   (portp->flags & ~ASYNC_USR_MASK)))
                        return(-EPERM);
        } 
 
-       portp->flags = (portp->flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK);
+       portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+               (sio.flags & ASYNC_USR_MASK);
        portp->baud_base = sio.baud_base;
        portp->close_delay = sio.close_delay;
        portp->closing_wait = sio.closing_wait;
@@ -1126,7 +1357,8 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
        int             rc;
 
 #if DEBUG
-       printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", (int) tty, (int) file, cmd, (int) arg);
+       printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
+               (int) tty, (int) file, cmd, (int) arg);
 #endif
 
        if (tty == (struct tty_struct *) NULL)
@@ -1135,6 +1367,12 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
        if (portp == (stlport_t *) NULL)
                return(-ENODEV);
 
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                       return(-EIO);
+       }
+
        rc = 0;
 
        switch (cmd) {
@@ -1152,53 +1390,69 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                }
                break;
        case TIOCGSOFTCAR:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0)
-                       put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg);
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(long))) == 0)
+                       put_fs_long(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+                               (unsigned long *) arg);
                break;
        case TIOCSSOFTCAR:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0);
+                       tty->termios->c_cflag =
+                               (tty->termios->c_cflag & ~CLOCAL) |
+                               (arg ? CLOCAL : 0);
                }
                break;
        case TIOCMGET:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(unsigned int))) == 0) {
                        val = (unsigned long) stl_getsignals(portp);
                        put_fs_long(val, (unsigned long *) arg);
                }
                break;
        case TIOCMBIS:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1));
+                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : -1),
+                               ((arg & TIOCM_RTS) ? 1 : -1));
                }
                break;
        case TIOCMBIC:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1));
+                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 0 : -1),
+                               ((arg & TIOCM_RTS) ? 0 : -1));
                }
                break;
        case TIOCMSET:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(long))) == 0) {
                        arg = get_fs_long((unsigned long *) arg);
-                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0));
+                       stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : 0),
+                               ((arg & TIOCM_RTS) ? 1 : 0));
                }
                break;
        case TIOCGSERIAL:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(struct serial_struct))) == 0)
                        stl_getserial(portp, (struct serial_struct *) arg);
                break;
        case TIOCSSERIAL:
-               if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
+               if ((rc = verify_area(VERIFY_READ, (void *) arg,
+                   sizeof(struct serial_struct))) == 0)
                        rc = stl_setserial(portp, (struct serial_struct *) arg);
                break;
        case COM_GETPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
                        rc = stl_getportstats(portp, (comstats_t *) arg);
                break;
        case COM_CLRPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
                        rc = stl_clrportstats(portp, (comstats_t *) arg);
                break;
        case TIOCSERCONFIG:
@@ -1234,11 +1488,13 @@ static void stl_settermios(struct tty_struct *tty, struct termios *old)
                return;
 
        tiosp = tty->termios;
-       if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
+       if ((tiosp->c_cflag == old->c_cflag) &&
+           (tiosp->c_iflag == old->c_iflag))
                return;
 
        stl_setport(portp, tiosp);
-       stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), -1);
+       stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0),
+               -1);
        if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) {
                tty->hw_stopped = 0;
                stl_start(tty);
@@ -1257,7 +1513,6 @@ static void stl_settermios(struct tty_struct *tty, struct termios *old)
 static void stl_throttle(struct tty_struct *tty)
 {
        stlport_t       *portp;
-       unsigned long   flags;
 
 #if DEBUG
        printk("stl_throttle(tty=%x)\n", (int) tty);
@@ -1268,24 +1523,7 @@ static void stl_throttle(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return;
-
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       if (tty->termios->c_iflag & IXOFF) {
-               stl_ccrwait(portp);
-               stl_setreg(portp, CCR, CCR_SENDSCHR2);
-               portp->stats.rxxoff++;
-               stl_ccrwait(portp);
-       }
-       if (tty->termios->c_cflag & CRTSCTS) {
-               stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) & 0xf0));
-               stl_setreg(portp, MSVR2, 0);
-               portp->stats.rxrtsoff++;
-       }
-       BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       stl_flowctrl(portp, 0);
 }
 
 /*****************************************************************************/
@@ -1297,7 +1535,6 @@ static void stl_throttle(struct tty_struct *tty)
 static void stl_unthrottle(struct tty_struct *tty)
 {
        stlport_t       *portp;
-       unsigned long   flags;
 
 #if DEBUG
        printk("stl_unthrottle(tty=%x)\n", (int) tty);
@@ -1308,30 +1545,7 @@ static void stl_unthrottle(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return;
-
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       if (tty->termios->c_iflag & IXOFF) {
-               stl_ccrwait(portp);
-               stl_setreg(portp, CCR, CCR_SENDSCHR1);
-               portp->stats.rxxon++;
-               stl_ccrwait(portp);
-       }
-/*
- *     Question: should we return RTS to what it was before? It may have
- *     been set by an ioctl... Suppose not, since if you have hardware
- *     flow control set then it is pretty silly to go and set the RTS line
- *     by hand.
- */
-       if (tty->termios->c_cflag & CRTSCTS) {
-               stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD));
-               stl_setreg(portp, MSVR2, MSVR2_RTS);
-               portp->stats.rxrtson++;
-       }
-       BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+       stl_flowctrl(portp, 1);
 }
 
 /*****************************************************************************/
@@ -1354,7 +1568,6 @@ static void stl_stop(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return;
-
        stl_startrxtx(portp, -1, 0);
 }
 
@@ -1377,7 +1590,6 @@ static void stl_start(struct tty_struct *tty)
        portp = tty->driver_data;
        if (portp == (stlport_t *) NULL)
                return;
-
        stl_startrxtx(portp, -1, 1);
 }
 
@@ -1417,7 +1629,6 @@ static void stl_hangup(struct tty_struct *tty)
                portp->tx.head = (char *) NULL;
                portp->tx.tail = (char *) NULL;
        }
-       tty->driver_data = (void *) NULL;
        portp->tty = (struct tty_struct *) NULL;
        portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
        portp->refcount = 0;
@@ -1429,7 +1640,6 @@ static void stl_hangup(struct tty_struct *tty)
 static void stl_flushbuffer(struct tty_struct *tty)
 {
        stlport_t       *portp;
-       unsigned long   flags;
 
 #if DEBUG
        printk("stl_flushbuffer(tty=%x)\n", (int) tty);
@@ -1441,439 +1651,183 @@ static void stl_flushbuffer(struct tty_struct *tty)
        if (portp == (stlport_t *) NULL)
                return;
 
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       stl_ccrwait(portp);
-       stl_setreg(portp, CCR, CCR_TXFLUSHFIFO);
-       stl_ccrwait(portp);
-       portp->tx.tail = portp->tx.head;
-       BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
-
+       stl_flush(portp);
        wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
                (tty->ldisc.write_wakeup)(tty);
 }
 
 /*****************************************************************************/
 
-/*
- *     These functions get/set/update the registers of the cd1400 UARTs.
- *     Access to the cd1400 registers is via an address/data io port pair.
- *     (Maybe should make this inline...)
- */
-
-static int stl_getreg(stlport_t *portp, int regnr)
+static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 {
-       outb((regnr + portp->uartaddr), portp->ioaddr);
-       return(inb(portp->ioaddr + EREG_DATA));
-}
+       stlport_t       *portp;
+       unsigned long   tend;
 
-static void stl_setreg(stlport_t *portp, int regnr, int value)
-{
-       outb((regnr + portp->uartaddr), portp->ioaddr);
-       outb(value, portp->ioaddr + EREG_DATA);
-}
+#if DEBUG
+       printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout);
+#endif
 
-static int stl_updatereg(stlport_t *portp, int regnr, int value)
-{
-       outb((regnr + portp->uartaddr), portp->ioaddr);
-       if (inb(portp->ioaddr + EREG_DATA) != value) {
-               outb(value, portp->ioaddr + EREG_DATA);
-               return(1);
+       if (tty == (struct tty_struct *) NULL)
+               return;
+       portp = tty->driver_data;
+       if (portp == (stlport_t *) NULL)
+               return;
+
+       if (timeout == 0)
+               timeout = HZ;
+       tend = jiffies + timeout;
+
+       while (stl_datastate(portp)) {
+               if (current->signal & ~current->blocked)
+                       break;
+               stl_delay(2);
+               if (jiffies >= tend)
+                       break;
        }
-       return(0);
 }
 
 /*****************************************************************************/
 
 /*
- *     Transmit interrupt handler. This has gotta be fast!  Handling TX
- *     chars is pretty simple, stuff as many as possible from the TX buffer
- *     into the cd1400 FIFO. Must also handle TX breaks here, since they
- *     are embedded as commands in the data stream. Oh no, had to use a goto!
- *     This could be optimized more, will do when I get time...
- *     In practice it is possible that interrupts are enabled but that the
- *     port has been hung up. Need to handle not having any TX buffer here,
- *     this is done by using the side effect that head and tail will also
- *     be NULL if the buffer has been freed.
+ *     All board interrupts are vectored through here first. This code then
+ *     calls off to the approrpriate board interrupt handlers.
  */
 
-static inline void stl_txisr(stlpanel_t *panelp, int ioaddr)
+static void stl_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
-       stlport_t       *portp;
-       int             len, stlen;
-       char            *head, *tail;
-       unsigned char   ioack, srer;
+       stlbrd_t        *brdp;
+       int             i;
 
 #if DEBUG
-       printk("stl_txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
+       printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);
 #endif
 
-       ioack = inb(ioaddr + EREG_TXACK);
-       if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPTX)) {
-               printk("STALLION: bad TX interrupt ack value=%x\n", ioack);
-               return;
+       for (i = 0; (i < stl_nrbrds); i++) {
+               if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
+                       continue;
+               if (brdp->state == 0)
+                       continue;
+               (* brdp->isr)(brdp);
        }
-       portp = panelp->ports[(ioack >> 3)];
+}
+
+/*****************************************************************************/
 
 /*
- *     Unfortunately we need to handle breaks in the data stream, since
- *     this is the only way to generate them on the cd1400. Do it now if
- *     a break is to be sent.
+ *     Interrupt service routine for EasyIO board types.
  */
-       if (portp->brklen != 0) {
-               if (portp->brklen > 0) {
-                       outb((TDR + portp->uartaddr), ioaddr);
-                       outb(ETC_CMD, (ioaddr + EREG_DATA));
-                       outb(ETC_STARTBREAK, (ioaddr + EREG_DATA));
-                       outb(ETC_CMD, (ioaddr + EREG_DATA));
-                       outb(ETC_DELAY, (ioaddr + EREG_DATA));
-                       outb(portp->brklen, (ioaddr + EREG_DATA));
-                       outb(ETC_CMD, (ioaddr + EREG_DATA));
-                       outb(ETC_STOPBREAK, (ioaddr + EREG_DATA));
-                       portp->brklen = -1;
-                       goto stl_txalldone;
-               } else {
-                       outb((COR2 + portp->uartaddr), ioaddr);
-                       outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA));
-                       portp->brklen = 0;
-               }
-       }
-
-       head = portp->tx.head;
-       tail = portp->tx.tail;
-       len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
-       if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
-               set_bit(ASYI_TXLOW, &portp->istate);
-               queue_task_irq_off(&portp->tqueue, &tq_scheduler);
-       }
 
-       if (len == 0) {
-               outb((SRER + portp->uartaddr), ioaddr);
-               srer = inb(ioaddr + EREG_DATA);
-               if (srer & SRER_TXDATA) {
-                       srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY;
-               } else {
-                       srer &= ~(SRER_TXDATA | SRER_TXEMPTY);
-                       clear_bit(ASYI_TXBUSY, &portp->istate);
-               }
-               outb(srer, (ioaddr + EREG_DATA));
-       } else {
-               len = MIN(len, CD1400_TXFIFOSIZE);
-               portp->stats.txtotal += len;
-               stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
-               outb((TDR + portp->uartaddr), ioaddr);
-               outsb((ioaddr + EREG_DATA), tail, stlen);
-               len -= stlen;
-               tail += stlen;
-               if (tail >= (portp->tx.buf + STL_TXBUFSIZE))
-                       tail = portp->tx.buf;
-               if (len > 0) {
-                       outsb((ioaddr + EREG_DATA), tail, len);
-                       tail += len;
-               }
-               portp->tx.tail = tail;
-       }
+static void stl_eiointr(stlbrd_t *brdp)
+{
+       stlpanel_t      *panelp;
+       unsigned int    iobase;
 
-stl_txalldone:
-       outb((EOSRR + portp->uartaddr), ioaddr);
-       outb(0, (ioaddr + EREG_DATA));
+       panelp = brdp->panels[0];
+       iobase = panelp->iobase;
+       while (inb(brdp->iostatus) & EIO_INTRPEND)
+               (* panelp->isr)(panelp, iobase);
 }
 
 /*****************************************************************************/
 
 /*
- *     Receive character interrupt handler. Determine if we have good chars
- *     or bad chars and then process appropriately. Good chars are easy
- *     just shove the lot into the RX buffer and set all status byte to 0.
- *     If a bad RX char then process as required. This routine needs to be
- *     fast!  In practice it is possible that we get an interrupt on a port
- *     that is closed. This can happen on hangups - since they completely
- *     shutdown a port not in user context. Need to handle this case.
+ *     Interrupt service routine for ECH-AT board types.
  */
 
-static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
+static void stl_echatintr(stlbrd_t *brdp)
 {
-       stlport_t               *portp;
-       struct tty_struct       *tty;
-       unsigned int            ioack, len, buflen;
-       unsigned char           status;
-       char                    ch;
-       static char             unwanted[CD1400_RXFIFOSIZE];
-
-#if DEBUG
-       printk("stl_rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
-#endif
+       stlpanel_t      *panelp;
+       unsigned int    ioaddr;
+       int             bnknr;
 
-       ioack = inb(ioaddr + EREG_RXACK);
-       if ((ioack & panelp->ackmask) != 0) {
-               printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
-               return;
-       }
-       portp = panelp->ports[(ioack >> 3)];
-       tty = portp->tty;
+       outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
 
-       if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
-               outb((RDCR + portp->uartaddr), ioaddr);
-               len = inb(ioaddr + EREG_DATA);
-               if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) ||
-                               ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
-                       outb((RDSR + portp->uartaddr), ioaddr);
-                       insb((ioaddr + EREG_DATA), &unwanted[0], len);
-                       portp->stats.rxlost += len;
-                       portp->stats.rxtotal += len;
-               } else {
-                       len = MIN(len, buflen);
-                       if (len > 0) {
-                               outb((RDSR + portp->uartaddr), ioaddr);
-                               insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len);
-                               memset(tty->flip.flag_buf_ptr, 0, len);
-                               tty->flip.flag_buf_ptr += len;
-                               tty->flip.char_buf_ptr += len;
-                               tty->flip.count += len;
-                               tty_schedule_flip(tty);
-                               portp->stats.rxtotal += len;
-                       }
-               }
-       } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) {
-               outb((RDSR + portp->uartaddr), ioaddr);
-               status = inb(ioaddr + EREG_DATA);
-               ch = inb(ioaddr + EREG_DATA);
-               if (status & ST_PARITY)
-                       portp->stats.rxparity++;
-               if (status & ST_FRAMING)
-                       portp->stats.rxframing++;
-               if (status & ST_OVERRUN)
-                       portp->stats.rxoverrun++;
-               if (status & ST_BREAK)
-                       portp->stats.rxbreaks++;
-               if (status & ST_SCHARMASK) {
-                       if ((status & ST_SCHARMASK) == ST_SCHAR1)
-                               portp->stats.txxon++;
-                       if ((status & ST_SCHARMASK) == ST_SCHAR2)
-                               portp->stats.txxoff++;
-                       goto stl_rxalldone;
-               }
-               if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) {
-                       if (portp->rxmarkmsk & status) {
-                               if (status & ST_BREAK) {
-                                       status = TTY_BREAK;
-#ifndef MODULE
-                                       if (portp->flags & ASYNC_SAK) {
-                                               do_SAK(tty);
-                                               BRDENABLE(portp->brdnr, portp->pagenr);
-                                       }
-#endif
-                               } else if (status & ST_PARITY) {
-                                       status = TTY_PARITY;
-                               } else if (status & ST_FRAMING) {
-                                       status = TTY_FRAME;
-                               } else if(status & ST_OVERRUN) {
-                                       status = TTY_OVERRUN;
-                               } else {
-                                       status = 0;
-                               }
-                       } else {
-                               status = 0;
-                       }
-                       if (tty->flip.char_buf_ptr != (char *) NULL) {
-                               if (tty->flip.count < TTY_FLIPBUF_SIZE) {
-                                       *tty->flip.flag_buf_ptr++ = status;
-                                       *tty->flip.char_buf_ptr++ = ch;
-                                       tty->flip.count++;
-                               }
-                               tty_schedule_flip(tty);
+       while (inb(brdp->iostatus) & ECH_INTRPEND) {
+               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+                       ioaddr = brdp->bnkstataddr[bnknr];
+                       if (inb(ioaddr) & ECH_PNLINTRPEND) {
+                               panelp = brdp->bnk2panel[bnknr];
+                               (* panelp->isr)(panelp, (ioaddr & 0xfffc));
                        }
                }
-       } else {
-               printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
-               return;
        }
 
-stl_rxalldone:
-       outb((EOSRR + portp->uartaddr), ioaddr);
-       outb(0, (ioaddr + EREG_DATA));
+       outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
 }
 
 /*****************************************************************************/
 
 /*
- *     Modem interrupt handler. The is called when the modem signal line
- *     (DCD) has changed state. Leave most of the work to the off-level
- *     processing routine.
+ *     Interrupt service routine for ECH-MCA board types.
  */
 
-static inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr)
+static void stl_echmcaintr(stlbrd_t *brdp)
 {
-       stlport_t       *portp;
-       unsigned int    ioack;
-       unsigned char   misr;
-
-#if DEBUG
-       printk("stl_mdmisr(panelp=%x)\n", (int) panelp);
-#endif
-
-       ioack = inb(ioaddr + EREG_MDACK);
-       if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) {
-               printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack);
-               return;
-       }
-       portp = panelp->ports[(ioack >> 3)];
-
-       outb((MISR + portp->uartaddr), ioaddr);
-       misr = inb(ioaddr + EREG_DATA);
-       if (misr & MISR_DCD) {
-               set_bit(ASYI_DCDCHANGE, &portp->istate);
-               queue_task_irq_off(&portp->tqueue, &tq_scheduler);
-               portp->stats.modem++;
+       stlpanel_t      *panelp;
+       unsigned int    ioaddr;
+       int             bnknr;
+
+       while (inb(brdp->iostatus) & ECH_INTRPEND) {
+               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+                       ioaddr = brdp->bnkstataddr[bnknr];
+                       if (inb(ioaddr) & ECH_PNLINTRPEND) {
+                               panelp = brdp->bnk2panel[bnknr];
+                               (* panelp->isr)(panelp, (ioaddr & 0xfffc));
+                       }
+               }
        }
-
-       outb((EOSRR + portp->uartaddr), ioaddr);
-       outb(0, (ioaddr + EREG_DATA));
 }
 
 /*****************************************************************************/
 
 /*
- *     Interrupt handler for EIO and ECH boards. This code ain't all that
- *     pretty, but the idea is to make it as fast as possible. This code is
- *     well suited to be assemblerized :-)  We don't use the general purpose
- *     register access functions here, for speed we will go strait to the
- *     io region.
+ *     Interrupt service routine for ECH-PCI board types.
  */
 
-static void stl_intr(int irq, void *dev_id, struct pt_regs *regs)
+static void stl_echpciintr(stlbrd_t *brdp)
 {
-       stlbrd_t        *brdp;
        stlpanel_t      *panelp;
-       unsigned char   svrtype;
-       int             i, panelnr, iobase;
-
-#if DEBUG
-       printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);
-#endif
-
-       panelp = (stlpanel_t *) NULL;
-       for (i = 0; (i < stl_nrbrds); ) {
-               if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) {
-                       i++;
-                       continue;
-               }
-               if (brdp->state == 0) {
-                       i++;
-                       continue;
-               }
-/*
- *             The following section of code handles the subtle differences
- *             between board types. It is sort of similar, but different
- *             enough to handle each separately.
- */
-               if (brdp->brdtype == BRD_EASYIO) {
-                       if ((inb(brdp->iostatus) & EIO_INTRPEND) == 0) {
-                               i++;
-                               continue;
-                       }
-                       panelp = brdp->panels[0];
-                       iobase = panelp->iobase;
-                       outb(SVRR, iobase);
-                       svrtype = inb(iobase + EREG_DATA);
-                       if (brdp->nrports > 4) {
-                               outb((SVRR + 0x80), iobase);
-                               svrtype |= inb(iobase + EREG_DATA);
-                       }
-               } else if (brdp->brdtype == BRD_ECH) {
-                       if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) {
-                               i++;
-                               continue;
-                       }
-                       outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
-                       for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
-                               panelp = brdp->panels[panelnr];
-                               iobase = panelp->iobase;
-                               if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                       break;
-                               if (panelp->nrports > 8) {
-                                       iobase += 0x8;
-                                       if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                               break;
-                               }
-                       }       
-                       if (panelnr >= brdp->nrpanels) {
-                               i++;
-                               continue;
-                       }
-                       outb(SVRR, iobase);
-                       svrtype = inb(iobase + EREG_DATA);
-                       outb((SVRR + 0x80), iobase);
-                       svrtype |= inb(iobase + EREG_DATA);
-               } else if (brdp->brdtype == BRD_ECHPCI) {
-                       iobase = brdp->ioaddr2;
-                       for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
-                               panelp = brdp->panels[panelnr];
-                               outb(panelp->pagenr, brdp->ioctrl);
-                               if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                       break;
-                               if (panelp->nrports > 8) {
-                                       outb((panelp->pagenr + 1), brdp->ioctrl);
-                                       if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                               break;
-                               }
-                       }       
-                       if (panelnr >= brdp->nrpanels) {
-                               i++;
-                               continue;
-                       }
-                       outb(SVRR, iobase);
-                       svrtype = inb(iobase + EREG_DATA);
-                       outb((SVRR + 0x80), iobase);
-                       svrtype |= inb(iobase + EREG_DATA);
-               } else if (brdp->brdtype == BRD_ECHMC) {
-                       if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) {
-                               i++;
-                               continue;
-                       }
-                       for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
-                               panelp = brdp->panels[panelnr];
-                               iobase = panelp->iobase;
-                               if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                       break;
-                               if (panelp->nrports > 8) {
-                                       iobase += 0x8;
-                                       if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND)
-                                               break;
-                               }
-                       }       
-                       if (panelnr >= brdp->nrpanels) {
-                               i++;
-                               continue;
+       unsigned int    ioaddr;
+       int             bnknr, recheck;
+
+       while (1) {
+               recheck = 0;
+               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+                       outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl);
+                       ioaddr = brdp->bnkstataddr[bnknr];
+                       if (inb(ioaddr) & ECH_PNLINTRPEND) {
+                               panelp = brdp->bnk2panel[bnknr];
+                               (* panelp->isr)(panelp, (ioaddr & 0xfffc));
+                               recheck++;
                        }
-                       outb(SVRR, iobase);
-                       svrtype = inb(iobase + EREG_DATA);
-                       outb((SVRR + 0x80), iobase);
-                       svrtype |= inb(iobase + EREG_DATA);
-               } else {
-                       printk("STALLION: unknown board type=%x\n", brdp->brdtype);
-                       i++;
-                       continue;
                }
+               if (! recheck)
+                       break;
+       }
+}
+
+/*****************************************************************************/
 
 /*
- *             We have determined what type of service is required for a
- *             port. From here on in the service of a port is the same no
- *             matter what the board type...
+ *     Interrupt service routine for ECH-8/64-PCI board types.
  */
-               if (svrtype & SVRR_RX)
-                       stl_rxisr(panelp, iobase);
-               if (svrtype & SVRR_TX)
-                       stl_txisr(panelp, iobase);
-               if (svrtype & SVRR_MDM)
-                       stl_mdmisr(panelp, iobase);
 
-               if (brdp->brdtype == BRD_ECH)
-                       outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
+static void stl_echpci64intr(stlbrd_t *brdp)
+{
+       stlpanel_t      *panelp;
+       unsigned int    ioaddr;
+       int             bnknr;
+
+       while (inb(brdp->ioctrl) & 0x1) {
+               for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+                       ioaddr = brdp->bnkstataddr[bnknr];
+                       if (inb(ioaddr) & ECH_PNLINTRPEND) {
+                               panelp = brdp->bnk2panel[bnknr];
+                               (* panelp->isr)(panelp, (ioaddr & 0xfffc));
+                       }
+               }
        }
 }
 
@@ -1890,6 +1844,7 @@ static void stl_offintr(void *private)
        unsigned int            oldsigs;
 
        portp = private;
+
 #if DEBUG
        printk("stl_offintr(portp=%x)\n", (int) portp);
 #endif
@@ -1901,7 +1856,8 @@ static void stl_offintr(void *private)
                return;
 
        if (test_bit(ASYI_TXLOW, &portp->istate)) {
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
                        (tty->ldisc.write_wakeup)(tty);
                wake_up_interruptible(&tty->write_wait);
        }
@@ -1914,7 +1870,7 @@ static void stl_offintr(void *private)
                if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
                        if (portp->flags & ASYNC_CHECK_CD) {
                                if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
-                                               (portp->flags & ASYNC_CALLOUT_NOHUP))) {
+                                   (portp->flags & ASYNC_CALLOUT_NOHUP))) {
                                        tty_hangup(tty);
                                }
                        }
@@ -1925,75 +1881,1218 @@ static void stl_offintr(void *private)
 /*****************************************************************************/
 
 /*
- *     Wait for the command register to be ready. We will poll this,
- *     since it won't usually take too long to be ready.
+ *     Map in interrupt vector to this driver. Check that we don't
+ *     already have this vector mapped, we might be sharing this
+ *     interrupt across multiple boards.
  */
 
-static void stl_ccrwait(stlport_t *portp)
+static int stl_mapirq(int irq, char *name)
 {
-       int     i;
+       int     rc, i;
 
-       for (i = 0; (i < CCR_MAXWAIT); i++) {
-               if (stl_getreg(portp, CCR) == 0) {
-                       return;
+#if DEBUG
+       printk("stl_mapirq(irq=%d,name=%s)\n", irq, name);
+#endif
+
+       rc = 0;
+       for (i = 0; (i < stl_numintrs); i++) {
+               if (stl_gotintrs[i] == irq)
+                       break;
+       }
+       if (i >= stl_numintrs) {
+               if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+                       printk("STALLION: failed to register interrupt "
+                               "routine for %s irq=%d\n", name, irq);
+                       rc = -ENODEV;
+               } else {
+                       stl_gotintrs[stl_numintrs++] = irq;
                }
        }
-
-       printk("STALLION: cd1400 device not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
+       return(rc);
 }
 
 /*****************************************************************************/
 
 /*
- *     Set up the cd1400 registers for a port based on the termios port
- *     settings.
+ *     Initialize all the ports on a panel.
  */
 
-static void stl_setport(stlport_t *portp, struct termios *tiosp)
+static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
 {
-       stlbrd_t        *brdp;
-       unsigned long   flags;
-       unsigned int    clkdiv, baudrate;
-       unsigned char   cor1, cor2, cor3;
-       unsigned char   cor4, cor5, ccr;
-       unsigned char   srer, sreron, sreroff;
-       unsigned char   mcor1, mcor2, rtpr;
-       unsigned char   clk, div;
+       stlport_t       *portp;
+       int             chipmask, i;
 
-       cor1 = 0;
-       cor2 = 0;
-       cor3 = 0;
-       cor4 = 0;
-       cor5 = 0;
-       ccr = 0;
-       rtpr = 0;
-       clk = 0;
-       div = 0;
-       mcor1 = 0;
-       mcor2 = 0;
-       sreron = 0;
-       sreroff = 0;
+#if DEBUG
+       printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
+#endif
 
-       brdp = stl_brds[portp->brdnr];
-       if (brdp == (stlbrd_t *) NULL)
-               return;
+       chipmask = stl_panelinit(brdp, panelp);
 
 /*
- *     Set up the RX char ignore mask with those RX error types we
- *     can ignore. We can get the cd1400 to help us out a little here,
- *     it will ignore parity errors and breaks for us.
+ *     All UART's are initialized (if found!). Now go through and setup
+ *     each ports data structures.
  */
-       portp->rxignoremsk = 0;
-       if (tiosp->c_iflag & IGNPAR) {
-               portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN);
-               cor1 |= COR1_PARIGNORE;
-       }
-       if (tiosp->c_iflag & IGNBRK) {
-               portp->rxignoremsk |= ST_BREAK;
-               cor4 |= COR4_IGNBRK;
+       for (i = 0; (i < panelp->nrports); i++) {
+               portp = (stlport_t *) stl_memalloc(sizeof(stlport_t));
+               if (portp == (stlport_t *) NULL) {
+                       printk("STALLION: failed to allocate memory "
+                               "(size=%d)\n", sizeof(stlport_t));
+                       break;
+               }
+               memset(portp, 0, sizeof(stlport_t));
+
+               portp->magic = STL_PORTMAGIC;
+               portp->portnr = i;
+               portp->brdnr = panelp->brdnr;
+               portp->panelnr = panelp->panelnr;
+               portp->uartp = panelp->uartp;
+               portp->clk = brdp->clk;
+               portp->baud_base = STL_BAUDBASE;
+               portp->close_delay = STL_CLOSEDELAY;
+               portp->closing_wait = 30 * HZ;
+               portp->normaltermios = stl_deftermios;
+               portp->callouttermios = stl_deftermios;
+               portp->tqueue.routine = stl_offintr;
+               portp->tqueue.data = portp;
+               portp->stats.brd = portp->brdnr;
+               portp->stats.panel = portp->panelnr;
+               portp->stats.port = portp->portnr;
+               panelp->ports[i] = portp;
+               stl_portinit(brdp, panelp, portp);
        }
 
-       portp->rxmarkmsk = ST_OVERRUN;
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Try to find and initialize an EasyIO board.
+ */
+
+static inline int stl_initeio(stlbrd_t *brdp)
+{
+       stlpanel_t      *panelp;
+       unsigned int    status;
+       char            *name;
+       int             rc;
+
+#if DEBUG
+       printk("stl_initeio(brdp=%x)\n", (int) brdp);
+#endif
+
+       brdp->ioctrl = brdp->ioaddr1 + 1;
+       brdp->iostatus = brdp->ioaddr1 + 2;
+
+       status = inb(brdp->iostatus);
+       if ((status & EIO_IDBITMASK) == EIO_MK3)
+               brdp->ioctrl++;
+
+/*
+ *     Handle board specific stuff now. The real difference is PCI
+ *     or not PCI.
+ */
+       if (brdp->brdtype == BRD_EASYIOPCI) {
+               brdp->iosize1 = 0x80;
+               brdp->iosize2 = 0x80;
+               name = "serial(EIO-PCI)";
+               outb(0x41, (brdp->ioaddr2 + 0x4c));
+       } else {
+               brdp->iosize1 = 8;
+               name = "serial(EIO)";
+               if ((brdp->irq < 0) || (brdp->irq > 15) ||
+                   (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+                       printk("STALLION: invalid irq=%d for brd=%d\n",
+                               brdp->irq, brdp->brdnr);
+                       return(-EINVAL);
+               }
+               outb((stl_vecmap[brdp->irq] | EIO_0WS |
+                       ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
+                       brdp->ioctrl);
+       }
+
+       if (check_region(brdp->ioaddr1, brdp->iosize1)) {
+               printk("STALLION: Warning, unit %d I/O address %x conflicts "
+                       "with another device\n", brdp->brdnr, brdp->ioaddr1);
+       }
+       if (brdp->iosize2 > 0) {
+               if (check_region(brdp->ioaddr2, brdp->iosize2)) {
+                       printk("STALLION: Warning, unit %d I/O address %x "
+                               "conflicts with another device\n",
+                               brdp->brdnr, brdp->ioaddr2);
+               }
+       }
+/*
+ *     Everything looks OK, so lets go ahead and probe for the hardware.
+ */
+       brdp->clk = CD1400_CLK;
+       brdp->isr = stl_eiointr;
+
+       switch (status & EIO_IDBITMASK) {
+       case EIO_8PORTM:
+               brdp->clk = CD1400_CLK8M;
+               /* fall thru */
+       case EIO_8PORTRS:
+       case EIO_8PORTDI:
+               brdp->nrports = 8;
+               break;
+       case EIO_4PORTRS:
+               brdp->nrports = 4;
+               break;
+       case EIO_MK3:
+               switch (status & EIO_BRDMASK) {
+               case ID_BRD4:
+                       brdp->nrports = 4;
+                       break;
+               case ID_BRD8:
+                       brdp->nrports = 8;
+                       break;
+               case ID_BRD16:
+                       brdp->nrports = 16;
+                       break;
+               default:
+                       return(-ENODEV);
+               }
+               break;
+       default:
+               return(-ENODEV);
+       }
+
+/*
+ *     We have verfied that the board is actually present, so now we
+ *     can complete the setup.
+ */
+       request_region(brdp->ioaddr1, brdp->iosize1, name);
+       if (brdp->iosize2 > 0)
+               request_region(brdp->ioaddr2, brdp->iosize2, name);
+
+       panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
+       if (panelp == (stlpanel_t *) NULL) {
+               printk("STALLION: failed to allocate memory (size=%d)\n",
+                       sizeof(stlpanel_t));
+               return(-ENOMEM);
+       }
+       memset(panelp, 0, sizeof(stlpanel_t));
+
+       panelp->magic = STL_PANELMAGIC;
+       panelp->brdnr = brdp->brdnr;
+       panelp->panelnr = 0;
+       panelp->nrports = brdp->nrports;
+       panelp->iobase = brdp->ioaddr1;
+       panelp->hwid = status;
+       if ((status & EIO_IDBITMASK) == EIO_MK3) {
+               panelp->uartp = (void *) &stl_sc26198uart;
+               panelp->isr = stl_sc26198intr;
+       } else {
+               panelp->uartp = (void *) &stl_cd1400uart;
+               panelp->isr = stl_cd1400eiointr;
+       }
+
+       brdp->panels[0] = panelp;
+       brdp->nrpanels = 1;
+       brdp->state |= BRD_FOUND;
+       brdp->hwid = status;
+       rc = stl_mapirq(brdp->irq, name);
+       return(rc);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Try to find an ECH board and initialize it. This code is capable of
+ *     dealing with all types of ECH board.
+ */
+
+static inline int stl_initech(stlbrd_t *brdp)
+{
+       stlpanel_t      *panelp;
+       unsigned int    status, nxtid, ioaddr, conflict;
+       int             panelnr, banknr, i;
+       char            *name;
+
+#if DEBUG
+       printk("stl_initech(brdp=%x)\n", (int) brdp);
+#endif
+
+       status = 0;
+       conflict = 0;
+
+/*
+ *     Set up the initial board register contents for boards. This varies a
+ *     bit between the different board types. So we need to handle each
+ *     separately. Also do a check that the supplied IRQ is good.
+ */
+       switch (brdp->brdtype) {
+
+       case BRD_ECH:
+               brdp->isr = stl_echatintr;
+               brdp->ioctrl = brdp->ioaddr1 + 1;
+               brdp->iostatus = brdp->ioaddr1 + 1;
+               status = inb(brdp->iostatus);
+               if ((status & ECH_IDBITMASK) != ECH_ID)
+                       return(-ENODEV);
+               if ((brdp->irq < 0) || (brdp->irq > 15) ||
+                   (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+                       printk("STALLION: invalid irq=%d for brd=%d\n",
+                               brdp->irq, brdp->brdnr);
+                       return(-EINVAL);
+               }
+               status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
+               status |= (stl_vecmap[brdp->irq] << 1);
+               outb((status | ECH_BRDRESET), brdp->ioaddr1);
+               brdp->ioctrlval = ECH_INTENABLE |
+                       ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
+               for (i = 0; (i < 10); i++)
+                       outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
+               brdp->iosize1 = 2;
+               brdp->iosize2 = 32;
+               name = "serial(EC8/32)";
+               outb(status, brdp->ioaddr1);
+               break;
+
+       case BRD_ECHMC:
+               brdp->isr = stl_echmcaintr;
+               brdp->ioctrl = brdp->ioaddr1 + 0x20;
+               brdp->iostatus = brdp->ioctrl;
+               status = inb(brdp->iostatus);
+               if ((status & ECH_IDBITMASK) != ECH_ID)
+                       return(-ENODEV);
+               if ((brdp->irq < 0) || (brdp->irq > 15) ||
+                   (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+                       printk("STALLION: invalid irq=%d for brd=%d\n",
+                               brdp->irq, brdp->brdnr);
+                       return(-EINVAL);
+               }
+               outb(ECHMC_BRDRESET, brdp->ioctrl);
+               outb(ECHMC_INTENABLE, brdp->ioctrl);
+               brdp->iosize1 = 64;
+               name = "serial(EC8/32-MC)";
+               break;
+
+       case BRD_ECHPCI:
+               brdp->isr = stl_echpciintr;
+               brdp->ioctrl = brdp->ioaddr1 + 2;
+               brdp->iosize1 = 4;
+               brdp->iosize2 = 8;
+               name = "serial(EC8/32-PCI)";
+               break;
+
+       case BRD_ECH64PCI:
+               brdp->isr = stl_echpci64intr;
+               brdp->ioctrl = brdp->ioaddr2 + 0x40;
+               outb(0x43, (brdp->ioaddr1 + 0x4c));
+               brdp->iosize1 = 0x80;
+               brdp->iosize2 = 0x80;
+               name = "serial(EC8/64-PCI)";
+               break;
+
+       default:
+               printk("STALLION: unknown board type=%d\n", brdp->brdtype);
+               return(-EINVAL);
+               break;
+       }
+
+/*
+ *     Check boards for possible IO address conflicts. We won't actually
+ *     do anything about it here, just issue a warning...
+ */
+       conflict = check_region(brdp->ioaddr1, brdp->iosize1) ?
+               brdp->ioaddr1 : 0;
+       if ((conflict == 0) && (brdp->iosize2 > 0))
+               conflict = check_region(brdp->ioaddr2, brdp->iosize2) ?
+                       brdp->ioaddr2 : 0;
+       if (conflict) {
+               printk("STALLION: Warning, unit %d I/O address %x conflicts "
+                       "with another device\n", brdp->brdnr, conflict);
+       }
+
+       request_region(brdp->ioaddr1, brdp->iosize1, name);
+       if (brdp->iosize2 > 0)
+               request_region(brdp->ioaddr2, brdp->iosize2, name);
+
+/*
+ *     Scan through the secondary io address space looking for panels.
+ *     As we find'em allocate and initialize panel structures for each.
+ */
+       brdp->clk = CD1400_CLK;
+       brdp->hwid = status;
+
+       ioaddr = brdp->ioaddr2;
+       banknr = 0;
+       panelnr = 0;
+       nxtid = 0;
+
+       for (i = 0; (i < STL_MAXPANELS); i++) {
+               if (brdp->brdtype == BRD_ECHPCI) {
+                       outb(nxtid, brdp->ioctrl);
+                       ioaddr = brdp->ioaddr2;
+               }
+               status = inb(ioaddr + ECH_PNLSTATUS);
+               if ((status & ECH_PNLIDMASK) != nxtid)
+                       break;
+               panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
+               if (panelp == (stlpanel_t *) NULL) {
+                       printk("STALLION: failed to allocate memory "
+                               "(size=%d)\n", sizeof(stlpanel_t));
+                       break;
+               }
+               memset(panelp, 0, sizeof(stlpanel_t));
+               panelp->magic = STL_PANELMAGIC;
+               panelp->brdnr = brdp->brdnr;
+               panelp->panelnr = panelnr;
+               panelp->iobase = ioaddr;
+               panelp->pagenr = nxtid;
+               panelp->hwid = status;
+               brdp->bnk2panel[banknr] = panelp;
+               brdp->bnkpageaddr[banknr] = nxtid;
+               brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS;
+
+               if (status & ECH_PNLXPID) {
+                       panelp->uartp = (void *) &stl_sc26198uart;
+                       panelp->isr = stl_sc26198intr;
+                       if (status & ECH_PNL16PORT) {
+                               panelp->nrports = 16;
+                               brdp->bnk2panel[banknr] = panelp;
+                               brdp->bnkpageaddr[banknr] = nxtid;
+                               brdp->bnkstataddr[banknr++] = ioaddr + 4 +
+                                       ECH_PNLSTATUS;
+                       } else {
+                               panelp->nrports = 8;
+                       }
+               } else {
+                       panelp->uartp = (void *) &stl_cd1400uart;
+                       panelp->isr = stl_cd1400echintr;
+                       if (status & ECH_PNL16PORT) {
+                               panelp->nrports = 16;
+                               panelp->ackmask = 0x80;
+                               if (brdp->brdtype != BRD_ECHPCI)
+                                       ioaddr += EREG_BANKSIZE;
+                               brdp->bnk2panel[banknr] = panelp;
+                               brdp->bnkpageaddr[banknr] = ++nxtid;
+                               brdp->bnkstataddr[banknr++] = ioaddr +
+                                       ECH_PNLSTATUS;
+                       } else {
+                               panelp->nrports = 8;
+                               panelp->ackmask = 0xc0;
+                       }
+               }
+
+               nxtid++;
+               ioaddr += EREG_BANKSIZE;
+               brdp->nrports += panelp->nrports;
+               brdp->panels[panelnr++] = panelp;
+               if ((brdp->brdtype != BRD_ECHPCI) &&
+                   (ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
+                       break;
+       }
+
+       brdp->nrpanels = panelnr;
+       brdp->nrbnks = banknr;
+       if (brdp->brdtype == BRD_ECH)
+               outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
+
+       brdp->state |= BRD_FOUND;
+       i = stl_mapirq(brdp->irq, name);
+       return(i);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Initialize and configure the specified board.
+ *     Scan through all the boards in the configuration and see what we
+ *     can find. Handle EIO and the ECH boards a little differently here
+ *     since the initial search and setup is very different.
+ */
+
+static int stl_brdinit(stlbrd_t *brdp)
+{
+       int     i;
+
+#if DEBUG
+       printk("stl_brdinit(brdp=%x)\n", (int) brdp);
+#endif
+
+       switch (brdp->brdtype) {
+       case BRD_EASYIO:
+       case BRD_EASYIOPCI:
+               stl_initeio(brdp);
+               break;
+       case BRD_ECH:
+       case BRD_ECHMC:
+       case BRD_ECHPCI:
+       case BRD_ECH64PCI:
+               stl_initech(brdp);
+               break;
+       default:
+               printk("STALLION: unit=%d is unknown board type=%d\n",
+                       brdp->brdnr, brdp->brdtype);
+               return(ENODEV);
+       }
+
+       stl_brds[brdp->brdnr] = brdp;
+       if ((brdp->state & BRD_FOUND) == 0) {
+               printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n",
+                       stl_brdnames[brdp->brdtype], brdp->brdnr,
+                       brdp->ioaddr1, brdp->irq);
+               return(ENODEV);
+       }
+
+       for (i = 0; (i < STL_MAXPANELS); i++)
+               if (brdp->panels[i] != (stlpanel_t *) NULL)
+                       stl_initports(brdp, brdp->panels[i]);
+
+       printk("STALLION: %s found, unit=%d io=%x irq=%d "
+               "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
+               brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
+               brdp->nrports);
+       return(0);
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_PCI
+
+/*
+ *     We have a Stallion board. Allocate a board structure and
+ *     initialize it. Read its IO and IRQ resources from PCI
+ *     configuration space.
+ */
+
+static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr)
+{
+       unsigned int    bar[4];
+       stlbrd_t        *brdp;
+       int             i, rc;
+       unsigned char   irq;
+
+#if DEBUG
+       printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
+               brdtype, busnr, devnr);
+#endif
+
+       brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
+       if (brdp == (stlbrd_t *) NULL) {
+               printk("STALLION: failed to allocate memory (size=%d)\n",
+                       sizeof(stlbrd_t));
+               return(-ENOMEM);
+       }
+
+       memset(brdp, 0, sizeof(stlbrd_t));
+       brdp->magic = STL_BOARDMAGIC;
+       brdp->brdnr = stl_nrbrds++;
+       brdp->brdtype = brdtype;
+
+/*
+ *     Read in all the BAR registers from this board. Different Stallion
+ *     boards use these in different ways, so we just read in the whole
+ *     lot and then figure out what is what later.
+ */
+       for (i = 0; (i < 4); i++) {
+               rc = pcibios_read_config_dword(busnr, devnr,
+                       (PCI_BASE_ADDRESS_0 + (i * 0x4)), &bar[i]);
+               if (rc) {
+                       printk("STALLION: failed to read BAR register %d "
+                               "from PCI board, errno=%x\n", i, rc);
+                       return(0);
+               }
+       }
+
+       rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq);
+       if (rc) {
+               printk("STALLION: failed to read INTERRUPT register "
+                       "from PCI board, errno=%x\n", rc);
+               return(0);
+       }
+
+#if DEBUG
+       printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
+               bar[0], bar[1], bar[2], bar[3], irq);
+#endif
+
+/*
+ *     We have all resources from the board, so lets setup the actual
+ *     board structure now.
+ */
+       switch (brdtype) {
+       case BRD_ECHPCI:
+               brdp->ioaddr2 = (bar[0] & PCI_BASE_ADDRESS_IO_MASK);
+               brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+               break;
+       case BRD_ECH64PCI:
+               brdp->ioaddr2 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
+               brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+               break;
+       case BRD_EASYIOPCI:
+               brdp->ioaddr1 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
+               brdp->ioaddr2 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+               break;
+       default:
+               printk("STALLION: unknown PCI board type=%d\n", brdtype);
+               break;
+       }
+
+       brdp->irq = irq;
+       stl_brdinit(brdp);
+
+       return(0);
+}
+
+
+/*****************************************************************************/
+
+/*
+ *     Find all Stallion PCI boards that might be installed. Initialize each
+ *     one as it is found.
+ */
+
+
+static inline int stl_findpcibrds()
+{
+       unsigned char   busnr, devnr;
+       unsigned short  class;
+       int             i, rc, brdtypnr;
+
+#if DEBUG
+       printk("stl_findpcibrds()\n");
+#endif
+
+       if (! pcibios_present())
+               return(0);
+
+       for (i = 0; (i < stl_nrpcibrds); i++) {
+               for (brdtypnr = 0; ; brdtypnr++) {
+
+                       rc = pcibios_find_device(stl_pcibrds[i].vendid,
+                               stl_pcibrds[i].devid, brdtypnr, &busnr, &devnr);
+                       if (rc)
+                               break;
+
+/*
+ *                     Check that we can handle more boards...
+ */
+                       if (stl_nrbrds >= STL_MAXBRDS) {
+                               printk("STALLION: too many boards found, "
+                                       "maximum supported %d\n", STL_MAXBRDS);
+                               i = stl_nrpcibrds;
+                               break;
+                       }
+
+/*
+ *                     Found a device on the PCI bus that has our vendor and
+ *                     device ID. Need to check now that it is really us.
+ */
+                       rc = pcibios_read_config_word(busnr, devnr,
+                               PCI_CLASS_DEVICE, &class);
+                       if (rc) {
+                               printk("STALLION: failed to read class type "
+                                       "from PCI board, errno=%x\n", rc);
+                               continue;
+                       }
+                       if (class == PCI_CLASS_STORAGE_IDE)
+                               continue;
+
+                       rc = stl_initpcibrd(stl_pcibrds[i].brdtype, busnr,
+                               devnr);
+                       if (rc)
+                               return(rc);
+               }
+       }
+
+       return(0);
+}
+
+#endif
+
+/*****************************************************************************/
+
+/*
+ *     Scan through all the boards in the configuration and see what we
+ *     can find. Handle EIO and the ECH boards a little differently here
+ *     since the initial search and setup is too different.
+ */
+
+static inline int stl_initbrds()
+{
+       stlbrd_t        *brdp;
+       stlconf_t       *confp;
+       int             i;
+
+#if DEBUG
+       printk("stl_initbrds()\n");
+#endif
+
+       if (stl_nrbrds > STL_MAXBRDS) {
+               printk("STALLION: too many boards in configuration table, "
+                       "truncating to %d\n", STL_MAXBRDS);
+               stl_nrbrds = STL_MAXBRDS;
+       }
+
+/*
+ *     Firstly scan the list of static boards configured. Allocate
+ *     resources and initialize the boards as found.
+ */
+       for (i = 0; (i < stl_nrbrds); i++) {
+               confp = &stl_brdconf[i];
+               brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
+               if (brdp == (stlbrd_t *) NULL) {
+                       printk("STALLION: failed to allocate memory "
+                               "(size=%d)\n", sizeof(stlbrd_t));
+                       return(-ENOMEM);
+               }
+               memset(brdp, 0, sizeof(stlbrd_t));
+
+               brdp->magic = STL_BOARDMAGIC;
+               brdp->brdnr = i;
+               brdp->brdtype = confp->brdtype;
+               brdp->ioaddr1 = confp->ioaddr1;
+               brdp->ioaddr2 = confp->ioaddr2;
+               brdp->irq = confp->irq;
+               brdp->irqtype = confp->irqtype;
+               stl_brdinit(brdp);
+       }
+
+#ifdef CONFIG_PCI
+/*
+ *     If the PCI BIOS support is compiled in then let's go looking for
+ *     ECH-PCI boards.
+ */
+       stl_findpcibrds();
+#endif
+
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the board stats structure to user app.
+ */
+
+static int stl_getbrdstats(combrd_t *bp)
+{
+       stlbrd_t        *brdp;
+       stlpanel_t      *panelp;
+       int             i;
+
+       memcpy_fromfs(&stl_brdstats, bp, sizeof(combrd_t));
+       if (stl_brdstats.brd >= STL_MAXBRDS)
+               return(-ENODEV);
+       brdp = stl_brds[stl_brdstats.brd];
+       if (brdp == (stlbrd_t *) NULL)
+               return(-ENODEV);
+
+       memset(&stl_brdstats, 0, sizeof(combrd_t));
+       stl_brdstats.brd = brdp->brdnr;
+       stl_brdstats.type = brdp->brdtype;
+       stl_brdstats.hwid = brdp->hwid;
+       stl_brdstats.state = brdp->state;
+       stl_brdstats.ioaddr = brdp->ioaddr1;
+       stl_brdstats.ioaddr2 = brdp->ioaddr2;
+       stl_brdstats.irq = brdp->irq;
+       stl_brdstats.nrpanels = brdp->nrpanels;
+       stl_brdstats.nrports = brdp->nrports;
+       for (i = 0; (i < brdp->nrpanels); i++) {
+               panelp = brdp->panels[i];
+               stl_brdstats.panels[i].panel = i;
+               stl_brdstats.panels[i].hwid = panelp->hwid;
+               stl_brdstats.panels[i].nrports = panelp->nrports;
+       }
+
+       memcpy_tofs(bp, &stl_brdstats, sizeof(combrd_t));
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Resolve the referenced port number into a port struct pointer.
+ */
+
+static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
+{
+       stlbrd_t        *brdp;
+       stlpanel_t      *panelp;
+
+       if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
+               return((stlport_t *) NULL);
+       brdp = stl_brds[brdnr];
+       if (brdp == (stlbrd_t *) NULL)
+               return((stlport_t *) NULL);
+       if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
+               return((stlport_t *) NULL);
+       panelp = brdp->panels[panelnr];
+       if (panelp == (stlpanel_t *) NULL)
+               return((stlport_t *) NULL);
+       if ((portnr < 0) || (portnr >= panelp->nrports))
+               return((stlport_t *) NULL);
+       return(panelp->ports[portnr]);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the port stats structure to user app. A NULL port struct
+ *     pointer passed in means that we need to find out from the app
+ *     what port to get stats for (used through board control device).
+ */
+
+static int stl_getportstats(stlport_t *portp, comstats_t *cp)
+{
+       unsigned char   *head, *tail;
+       unsigned long   flags;
+
+       if (portp == (stlport_t *) NULL) {
+               memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
+               portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
+                       stl_comstats.port);
+               if (portp == (stlport_t *) NULL)
+                       return(-ENODEV);
+       }
+
+       portp->stats.state = portp->istate;
+       portp->stats.flags = portp->flags;
+       portp->stats.hwid = portp->hwid;
+
+       portp->stats.ttystate = 0;
+       portp->stats.cflags = 0;
+       portp->stats.iflags = 0;
+       portp->stats.oflags = 0;
+       portp->stats.lflags = 0;
+       portp->stats.rxbuffered = 0;
+
+       save_flags(flags);
+       cli();
+       if (portp->tty != (struct tty_struct *) NULL) {
+               if (portp->tty->driver_data == portp) {
+                       portp->stats.ttystate = portp->tty->flags;
+                       portp->stats.rxbuffered = portp->tty->flip.count;
+                       if (portp->tty->termios != (struct termios *) NULL) {
+                               portp->stats.cflags = portp->tty->termios->c_cflag;
+                               portp->stats.iflags = portp->tty->termios->c_iflag;
+                               portp->stats.oflags = portp->tty->termios->c_oflag;
+                               portp->stats.lflags = portp->tty->termios->c_lflag;
+                       }
+               }
+       }
+       restore_flags(flags);
+
+       head = portp->tx.head;
+       tail = portp->tx.tail;
+       portp->stats.txbuffered = ((head >= tail) ? (head - tail) :
+               (STL_TXBUFSIZE - (tail - head)));
+
+       portp->stats.signals = (unsigned long) stl_getsignals(portp);
+
+       memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Clear the port stats structure. We also return it zeroed out...
+ */
+
+static int stl_clrportstats(stlport_t *portp, comstats_t *cp)
+{
+       if (portp == (stlport_t *) NULL) {
+               memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
+               portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
+                       stl_comstats.port);
+               if (portp == (stlport_t *) NULL)
+                       return(-ENODEV);
+       }
+
+       memset(&portp->stats, 0, sizeof(comstats_t));
+       portp->stats.brd = portp->brdnr;
+       portp->stats.panel = portp->panelnr;
+       portp->stats.port = portp->portnr;
+       memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the entire driver ports structure to a user app.
+ */
+
+static int stl_getportstruct(unsigned long arg)
+{
+       stlport_t       *portp;
+
+       memcpy_fromfs(&stl_dummyport, (void *) arg, sizeof(stlport_t));
+       portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr,
+                stl_dummyport.portnr);
+       if (portp == (stlport_t *) NULL)
+               return(-ENODEV);
+       memcpy_tofs((void *) arg, portp, sizeof(stlport_t));
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the entire driver board structure to a user app.
+ */
+
+static int stl_getbrdstruct(unsigned long arg)
+{
+       stlbrd_t        *brdp;
+
+       memcpy_fromfs(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t));
+       if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS))
+               return(-ENODEV);
+       brdp = stl_brds[stl_dummybrd.brdnr];
+       if (brdp == (stlbrd_t *) NULL)
+               return(-ENODEV);
+       memcpy_tofs((void *) arg, brdp, sizeof(stlbrd_t));
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Memory device open code. Need to keep track of opens and close
+ *     for module handling.
+ */
+
+static int stl_memopen(struct inode *ip, struct file *fp)
+{
+       MOD_INC_USE_COUNT;
+       return(0);
+}
+
+/*****************************************************************************/
+
+static void stl_memclose(struct inode *ip, struct file *fp)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+/*****************************************************************************/
+
+/*
+ *     The "staliomem" device is also required to do some special operations
+ *     on the board and/or ports. In this driver it is mostly used for stats
+ *     collection.
+ */
+
+static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+{
+       int     brdnr, rc;
+
+#if DEBUG
+       printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip,
+               (int) fp, cmd, (int) arg);
+#endif
+
+       brdnr = MINOR(ip->i_rdev);
+       if (brdnr >= STL_MAXBRDS)
+               return(-ENODEV);
+       rc = 0;
+
+       switch (cmd) {
+       case COM_GETPORTSTATS:
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
+                       rc = stl_getportstats((stlport_t *) NULL,
+                               (comstats_t *) arg);
+               break;
+       case COM_CLRPORTSTATS:
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(comstats_t))) == 0)
+                       rc = stl_clrportstats((stlport_t *) NULL,
+                               (comstats_t *) arg);
+               break;
+       case COM_GETBRDSTATS:
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(combrd_t))) == 0)
+                       rc = stl_getbrdstats((combrd_t *) arg);
+               break;
+       case COM_READPORT:
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(stlport_t))) == 0)
+                       rc = stl_getportstruct(arg);
+               break;
+       case COM_READBOARD:
+               if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+                   sizeof(stlbrd_t))) == 0)
+                       rc = stl_getbrdstruct(arg);
+               break;
+       default:
+               rc = -ENOIOCTLCMD;
+               break;
+       }
+
+       return(rc);
+}
+
+/*****************************************************************************/
+
+int stl_init(void)
+{
+       printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
+
+       stl_initbrds();
+
+/*
+ *     Allocate a temporary write buffer.
+ */
+       stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
+       if (stl_tmpwritebuf == (char *) NULL)
+               printk("STALLION: failed to allocate memory (size=%d)\n",
+                       STL_TXBUFSIZE);
+
+/*
+ *     Set up a character driver for per board stuff. This is mainly used
+ *     to do stats ioctls on the ports.
+ */
+       if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
+               printk("STALLION: failed to register serial board device\n");
+
+/*
+ *     Set up the tty driver structure and register us as a driver.
+ *     Also setup the callout tty device.
+ */
+       memset(&stl_serial, 0, sizeof(struct tty_driver));
+       stl_serial.magic = TTY_DRIVER_MAGIC;
+       stl_serial.name = stl_serialname;
+       stl_serial.major = STL_SERIALMAJOR;
+       stl_serial.minor_start = 0;
+       stl_serial.num = STL_MAXBRDS * STL_MAXPORTS;
+       stl_serial.type = TTY_DRIVER_TYPE_SERIAL;
+       stl_serial.subtype = STL_DRVTYPSERIAL;
+       stl_serial.init_termios = stl_deftermios;
+       stl_serial.flags = TTY_DRIVER_REAL_RAW;
+       stl_serial.refcount = &stl_refcount;
+       stl_serial.table = stl_ttys;
+       stl_serial.termios = stl_termios;
+       stl_serial.termios_locked = stl_termioslocked;
+       
+       stl_serial.open = stl_open;
+       stl_serial.close = stl_close;
+       stl_serial.write = stl_write;
+       stl_serial.put_char = stl_putchar;
+       stl_serial.flush_chars = stl_flushchars;
+       stl_serial.write_room = stl_writeroom;
+       stl_serial.chars_in_buffer = stl_charsinbuffer;
+       stl_serial.ioctl = stl_ioctl;
+       stl_serial.set_termios = stl_settermios;
+       stl_serial.throttle = stl_throttle;
+       stl_serial.unthrottle = stl_unthrottle;
+       stl_serial.stop = stl_stop;
+       stl_serial.start = stl_start;
+       stl_serial.hangup = stl_hangup;
+       stl_serial.flush_buffer = stl_flushbuffer;
+
+       stl_callout = stl_serial;
+       stl_callout.name = stl_calloutname;
+       stl_callout.major = STL_CALLOUTMAJOR;
+       stl_callout.subtype = STL_DRVTYPCALLOUT;
+
+       if (tty_register_driver(&stl_serial))
+               printk("STALLION: failed to register serial driver\n");
+       if (tty_register_driver(&stl_callout))
+               printk("STALLION: failed to register callout driver\n");
+
+       return(0);
+}
+
+/*****************************************************************************/
+/*                       CD1400 HARDWARE FUNCTIONS                           */
+/*****************************************************************************/
+
+/*
+ *     These functions get/set/update the registers of the cd1400 UARTs.
+ *     Access to the cd1400 registers is via an address/data io port pair.
+ *     (Maybe should make this inline...)
+ */
+
+static int stl_cd1400getreg(stlport_t *portp, int regnr)
+{
+       outb((regnr + portp->uartaddr), portp->ioaddr);
+       return(inb(portp->ioaddr + EREG_DATA));
+}
+
+static void stl_cd1400setreg(stlport_t *portp, int regnr, int value)
+{
+       outb((regnr + portp->uartaddr), portp->ioaddr);
+       outb(value, portp->ioaddr + EREG_DATA);
+}
+
+static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value)
+{
+       outb((regnr + portp->uartaddr), portp->ioaddr);
+       if (inb(portp->ioaddr + EREG_DATA) != value) {
+               outb(value, portp->ioaddr + EREG_DATA);
+               return(1);
+       }
+       return(0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Inbitialize the UARTs in a panel. We don't care what sort of board
+ *     these ports are on - since the port io registers are almost
+ *     identical when dealing with ports.
+ */
+
+static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
+{
+       unsigned int    gfrcr;
+       int             chipmask, i, j;
+       int             nrchips, uartaddr, ioaddr;
+
+#if DEBUG
+       printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
+#endif
+
+       BRDENABLE(panelp->brdnr, panelp->pagenr);
+
+/*
+ *     Check that each chip is present and started up OK.
+ */
+       chipmask = 0;
+       nrchips = panelp->nrports / CD1400_PORTS;
+       for (i = 0; (i < nrchips); i++) {
+               if (brdp->brdtype == BRD_ECHPCI) {
+                       outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
+                       ioaddr = panelp->iobase;
+               } else {
+                       ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
+               }
+               uartaddr = (i & 0x01) ? 0x080 : 0;
+               outb((GFRCR + uartaddr), ioaddr);
+               outb(0, (ioaddr + EREG_DATA));
+               outb((CCR + uartaddr), ioaddr);
+               outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
+               outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
+               outb((GFRCR + uartaddr), ioaddr);
+               for (j = 0; (j < CCR_MAXWAIT); j++) {
+                       if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
+                               break;
+               }
+               if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
+                       printk("STALLION: cd1400 not responding, "
+                               "brd=%d panel=%d chip=%d\n",
+                               panelp->brdnr, panelp->panelnr, i);
+                       continue;
+               }
+               chipmask |= (0x1 << i);
+               outb((PPR + uartaddr), ioaddr);
+               outb(PPR_SCALAR, (ioaddr + EREG_DATA));
+       }
+
+       BRDDISABLE(panelp->brdnr);
+       return(chipmask);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Initialize hardware specific port registers.
+ */
+
+static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
+{
+#if DEBUG
+       printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
+               (int) brdp, (int) panelp, (int) portp);
+#endif
+
+       if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
+           (portp == (stlport_t *) NULL))
+               return;
+
+       portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) ||
+               (portp->portnr < 8)) ? 0 : EREG_BANKSIZE);
+       portp->uartaddr = (portp->portnr & 0x04) << 5;
+       portp->pagenr = panelp->pagenr + (portp->portnr >> 3);
+
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400setreg(portp, LIVR, (portp->portnr << 3));
+       portp->hwid = stl_cd1400getreg(portp, GFRCR);
+       BRDDISABLE(portp->brdnr);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Wait for the command register to be ready. We will poll this,
+ *     since it won't usually take too long to be ready.
+ */
+
+static void stl_cd1400ccrwait(stlport_t *portp)
+{
+       int     i;
+
+       for (i = 0; (i < CCR_MAXWAIT); i++) {
+               if (stl_cd1400getreg(portp, CCR) == 0) {
+                       return;
+               }
+       }
+
+       printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n",
+               portp->portnr, portp->panelnr, portp->brdnr);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Set up the cd1400 registers for a port based on the termios port
+ *     settings.
+ */
+
+static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
+{
+       stlbrd_t        *brdp;
+       unsigned long   flags;
+       unsigned int    clkdiv, baudrate;
+       unsigned char   cor1, cor2, cor3;
+       unsigned char   cor4, cor5, ccr;
+       unsigned char   srer, sreron, sreroff;
+       unsigned char   mcor1, mcor2, rtpr;
+       unsigned char   clk, div;
+
+       cor1 = 0;
+       cor2 = 0;
+       cor3 = 0;
+       cor4 = 0;
+       cor5 = 0;
+       ccr = 0;
+       rtpr = 0;
+       clk = 0;
+       div = 0;
+       mcor1 = 0;
+       mcor2 = 0;
+       sreron = 0;
+       sreroff = 0;
+
+       brdp = stl_brds[portp->brdnr];
+       if (brdp == (stlbrd_t *) NULL)
+               return;
+
+/*
+ *     Set up the RX char ignore mask with those RX error types we
+ *     can ignore. We can get the cd1400 to help us out a little here,
+ *     it will ignore parity errors and breaks for us.
+ */
+       portp->rxignoremsk = 0;
+       if (tiosp->c_iflag & IGNPAR) {
+               portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN);
+               cor1 |= COR1_PARIGNORE;
+       }
+       if (tiosp->c_iflag & IGNBRK) {
+               portp->rxignoremsk |= ST_BREAK;
+               cor4 |= COR4_IGNBRK;
+       }
+
+       portp->rxmarkmsk = ST_OVERRUN;
        if (tiosp->c_iflag & (INPCK | PARMRK))
                portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING);
        if (tiosp->c_iflag & BRKINT)
@@ -2064,8 +3163,8 @@ static void stl_setport(stlport_t *portp, struct termios *tiosp)
                else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
                        baudrate = (portp->baud_base / portp->custom_divisor);
        }
-       if (baudrate > STL_MAXBAUD)
-               baudrate = STL_MAXBAUD;
+       if (baudrate > STL_CD1400MAXBAUD)
+               baudrate = STL_CD1400MAXBAUD;
 
        if (baudrate > 0) {
                for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
@@ -2107,159 +3206,390 @@ static void stl_setport(stlport_t *portp, struct termios *tiosp)
        }
 
 /*
- *     All register cd1400 register values calculated so go through and set
- *     them all up.
+ *     All cd1400 register values calculated so go through and set
+ *     them all up.
+ */
+
+#if DEBUG
+       printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+               portp->portnr, portp->panelnr, portp->brdnr);
+       printk("    cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
+               cor1, cor2, cor3, cor4, cor5);
+       printk("    mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
+               mcor1, mcor2, rtpr, sreron, sreroff);
+       printk("    tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
+       printk("    schr1=%x schr2=%x schr3=%x schr4=%x\n",
+               tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
+               tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
+#endif
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3));
+       srer = stl_cd1400getreg(portp, SRER);
+       stl_cd1400setreg(portp, SRER, 0);
+       if (stl_cd1400updatereg(portp, COR1, cor1))
+               ccr = 1;
+       if (stl_cd1400updatereg(portp, COR2, cor2))
+               ccr = 1;
+       if (stl_cd1400updatereg(portp, COR3, cor3))
+               ccr = 1;
+       if (ccr) {
+               stl_cd1400ccrwait(portp);
+               stl_cd1400setreg(portp, CCR, CCR_CORCHANGE);
+       }
+       stl_cd1400setreg(portp, COR4, cor4);
+       stl_cd1400setreg(portp, COR5, cor5);
+       stl_cd1400setreg(portp, MCOR1, mcor1);
+       stl_cd1400setreg(portp, MCOR2, mcor2);
+       if (baudrate > 0) {
+               stl_cd1400setreg(portp, TCOR, clk);
+               stl_cd1400setreg(portp, TBPR, div);
+               stl_cd1400setreg(portp, RCOR, clk);
+               stl_cd1400setreg(portp, RBPR, div);
+       }
+       stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]);
+       stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]);
+       stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]);
+       stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]);
+       stl_cd1400setreg(portp, RTPR, rtpr);
+       mcor1 = stl_cd1400getreg(portp, MSVR1);
+       if (mcor1 & MSVR1_DCD)
+               portp->sigs |= TIOCM_CD;
+       else
+               portp->sigs &= ~TIOCM_CD;
+       stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron));
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Set the state of the DTR and RTS signals.
+ */
+
+static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
+{
+       unsigned char   msvr1, msvr2;
+       unsigned long   flags;
+
+#if DEBUG
+       printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n",
+               (int) portp, dtr, rts);
+#endif
+
+       msvr1 = 0;
+       msvr2 = 0;
+       if (dtr > 0)
+               msvr1 = MSVR1_DTR;
+       if (rts > 0)
+               msvr2 = MSVR2_RTS;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       if (rts >= 0)
+               stl_cd1400setreg(portp, MSVR2, msvr2);
+       if (dtr >= 0)
+               stl_cd1400setreg(portp, MSVR1, msvr1);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Return the state of the signals.
+ */
+
+static int stl_cd1400getsignals(stlport_t *portp)
+{
+       unsigned char   msvr1, msvr2;
+       unsigned long   flags;
+       int             sigs;
+
+#if DEBUG
+       printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
+#endif
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       msvr1 = stl_cd1400getreg(portp, MSVR1);
+       msvr2 = stl_cd1400getreg(portp, MSVR2);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+
+       sigs = 0;
+       sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
+       sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
+       sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
+       sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
+#if 0
+       sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
+       sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
+#else
+       sigs |= TIOCM_DSR;
+#endif
+       return(sigs);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Enable/Disable the Transmitter and/or Receiver.
+ */
+
+static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
+{
+       unsigned char   ccr;
+       unsigned long   flags;
+
+#if DEBUG
+       printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n",
+               (int) portp, rx, tx);
+#endif
+       ccr = 0;
+
+       if (tx == 0)
+               ccr |= CCR_TXDISABLE;
+       else if (tx > 0)
+               ccr |= CCR_TXENABLE;
+       if (rx == 0)
+               ccr |= CCR_RXDISABLE;
+       else if (rx > 0)
+               ccr |= CCR_RXENABLE;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400ccrwait(portp);
+       stl_cd1400setreg(portp, CCR, ccr);
+       stl_cd1400ccrwait(portp);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Start/stop the Transmitter and/or Receiver.
  */
 
+static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
+{
+       unsigned char   sreron, sreroff;
+       unsigned long   flags;
+
 #if DEBUG
-       printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
-       printk("    cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5);
-       printk("    mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff);
-       printk("    tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
-       printk("    schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
+       printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n",
+               (int) portp, rx, tx);
 #endif
 
+       sreron = 0;
+       sreroff = 0;
+       if (tx == 0)
+               sreroff |= (SRER_TXDATA | SRER_TXEMPTY);
+       else if (tx == 1)
+               sreron |= SRER_TXDATA;
+       else if (tx >= 2)
+               sreron |= SRER_TXEMPTY;
+       if (rx == 0)
+               sreroff |= SRER_RXDATA;
+       else if (rx > 0)
+               sreron |= SRER_RXDATA;
+
        save_flags(flags);
        cli();
        BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x3));
-       srer = stl_getreg(portp, SRER);
-       stl_setreg(portp, SRER, 0);
-       if (stl_updatereg(portp, COR1, cor1))
-               ccr = 1;
-       if (stl_updatereg(portp, COR2, cor2))
-               ccr = 1;
-       if (stl_updatereg(portp, COR3, cor3))
-               ccr = 1;
-       if (ccr) {
-               stl_ccrwait(portp);
-               stl_setreg(portp, CCR, CCR_CORCHANGE);
-       }
-       stl_setreg(portp, COR4, cor4);
-       stl_setreg(portp, COR5, cor5);
-       stl_setreg(portp, MCOR1, mcor1);
-       stl_setreg(portp, MCOR2, mcor2);
-       if (baudrate > 0) {
-               stl_setreg(portp, TCOR, clk);
-               stl_setreg(portp, TBPR, div);
-               stl_setreg(portp, RCOR, clk);
-               stl_setreg(portp, RBPR, div);
-       }
-       stl_setreg(portp, SCHR1, tiosp->c_cc[VSTART]);
-       stl_setreg(portp, SCHR2, tiosp->c_cc[VSTOP]);
-       stl_setreg(portp, SCHR3, tiosp->c_cc[VSTART]);
-       stl_setreg(portp, SCHR4, tiosp->c_cc[VSTOP]);
-       stl_setreg(portp, RTPR, rtpr);
-       mcor1 = stl_getreg(portp, MSVR1);
-       if (mcor1 & MSVR1_DCD)
-               portp->sigs |= TIOCM_CD;
-       else
-               portp->sigs &= ~TIOCM_CD;
-       stl_setreg(portp, SRER, ((srer & ~sreroff) | sreron));
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400setreg(portp, SRER,
+               ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron));
        BRDDISABLE(portp->brdnr);
+       if (tx > 0)
+               set_bit(ASYI_TXBUSY, &portp->istate);
        restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Set the state of the DTR and RTS signals.
+ *     Disable all interrupts from this port.
  */
 
-static void stl_setsignals(stlport_t *portp, int dtr, int rts)
+static void stl_cd1400disableintrs(stlport_t *portp)
 {
-       unsigned char   msvr1, msvr2;
        unsigned long   flags;
 
 #if DEBUG
-       printk("stl_setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts);
+       printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
 #endif
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400setreg(portp, SRER, 0);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
 
-       msvr1 = 0;
-       msvr2 = 0;
-       if (dtr > 0)
-               msvr1 = MSVR1_DTR;
-       if (rts > 0)
-               msvr2 = MSVR2_RTS;
+/*****************************************************************************/
+
+static void stl_cd1400sendbreak(stlport_t *portp, long len)
+{
+       unsigned long   flags;
+
+#if DEBUG
+       printk("stl_cd1400sendbreak(portp=%x,len=%d)\n",
+               (int) portp, (int) len);
+#endif
 
        save_flags(flags);
        cli();
        BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       if (rts >= 0)
-               stl_setreg(portp, MSVR2, msvr2);
-       if (dtr >= 0)
-               stl_setreg(portp, MSVR1, msvr1);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400setreg(portp, COR2,
+               (stl_cd1400getreg(portp, COR2) | COR2_ETC));
+       stl_cd1400setreg(portp, SRER,
+               ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY));
        BRDDISABLE(portp->brdnr);
+       len = len / 5;
+       portp->brklen = (len > 255) ? 255 : len;
+       portp->stats.txbreaks++;
        restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Return the state of the signals.
+ *     Take flow control actions...
  */
 
-static int stl_getsignals(stlport_t *portp)
+static void stl_cd1400flowctrl(stlport_t *portp, int state)
 {
-       unsigned char   msvr1, msvr2;
-       unsigned long   flags;
-       int             sigs;
+       struct tty_struct       *tty;
+       unsigned long           flags;
 
 #if DEBUG
-       printk("stl_getsignals(portp=%x)\n", (int) portp);
+       printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state);
 #endif
 
+       if (portp == (stlport_t *) NULL)
+               return;
+       tty = portp->tty;
+       if (tty == (struct tty_struct *) NULL)
+               return;
+
        save_flags(flags);
        cli();
        BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       msvr1 = stl_getreg(portp, MSVR1);
-       msvr2 = stl_getreg(portp, MSVR2);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+
+       if (state) {
+               if (tty->termios->c_iflag & IXOFF) {
+                       stl_cd1400ccrwait(portp);
+                       stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1);
+                       portp->stats.rxxon++;
+                       stl_cd1400ccrwait(portp);
+               }
+/*
+ *             Question: should we return RTS to what it was before? It may
+ *             have been set by an ioctl... Suppose not, since if you have
+ *             hardware flow control set then it is pretty silly to go and
+ *             set the RTS line by hand.
+ */
+               if (tty->termios->c_cflag & CRTSCTS) {
+                       stl_cd1400setreg(portp, MCOR1,
+                               (stl_cd1400getreg(portp, MCOR1) |
+                               FIFO_RTSTHRESHOLD));
+                       stl_cd1400setreg(portp, MSVR2, MSVR2_RTS);
+                       portp->stats.rxrtson++;
+               }
+       } else {
+               if (tty->termios->c_iflag & IXOFF) {
+                       stl_cd1400ccrwait(portp);
+                       stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2);
+                       portp->stats.rxxoff++;
+                       stl_cd1400ccrwait(portp);
+               }
+               if (tty->termios->c_cflag & CRTSCTS) {
+                       stl_cd1400setreg(portp, MCOR1,
+                               (stl_cd1400getreg(portp, MCOR1) & 0xf0));
+                       stl_cd1400setreg(portp, MSVR2, 0);
+                       portp->stats.rxrtsoff++;
+               }
+       }
+
        BRDDISABLE(portp->brdnr);
-       sigs = 0;
-       sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
-       sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
-       sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
-       sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
-       sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
-       sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
        restore_flags(flags);
-       return(sigs);
 }
 
 /*****************************************************************************/
 
 /*
- *     Enable/Disable the Transmitter and/or Receiver.
+ *     Send a flow control character...
  */
 
-static void stl_enablerxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400sendflow(stlport_t *portp, int state)
+{
+       struct tty_struct       *tty;
+       unsigned long           flags;
+
+#if DEBUG
+       printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state);
+#endif
+
+       if (portp == (stlport_t *) NULL)
+               return;
+       tty = portp->tty;
+       if (tty == (struct tty_struct *) NULL)
+               return;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       if (state) {
+               stl_cd1400ccrwait(portp);
+               stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1);
+               portp->stats.rxxon++;
+               stl_cd1400ccrwait(portp);
+       } else {
+               stl_cd1400ccrwait(portp);
+               stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2);
+               portp->stats.rxxoff++;
+               stl_cd1400ccrwait(portp);
+       }
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
+
+/*****************************************************************************/
+
+static void stl_cd1400flush(stlport_t *portp)
 {
-       unsigned char   ccr;
        unsigned long   flags;
 
 #if DEBUG
-       printk("stl_enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
+       printk("stl_cd1400flush(portp=%x)\n", (int) portp);
 #endif
-       ccr = 0;
 
-       if (tx == 0)
-               ccr |= CCR_TXDISABLE;
-       else if (tx > 0)
-               ccr |= CCR_TXENABLE;
-       if (rx == 0)
-               ccr |= CCR_RXDISABLE;
-       else if (rx > 0)
-               ccr |= CCR_RXENABLE;
+       if (portp == (stlport_t *) NULL)
+               return;
 
        save_flags(flags);
        cli();
        BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       stl_ccrwait(portp);
-       stl_setreg(portp, CCR, ccr);
-       stl_ccrwait(portp);
+       stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+       stl_cd1400ccrwait(portp);
+       stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO);
+       stl_cd1400ccrwait(portp);
+       portp->tx.tail = portp->tx.head;
        BRDDISABLE(portp->brdnr);
        restore_flags(flags);
 }
@@ -2267,137 +3597,400 @@ static void stl_enablerxtx(stlport_t *portp, int rx, int tx)
 /*****************************************************************************/
 
 /*
- *     Start/stop the Transmitter and/or Receiver.
+ *     Return the current state of data flow on this port. This is only
+ *     really interresting when determining if data has fully completed
+ *     transmission or not... This is easy for the cd1400, it accurately
+ *     maintains the busy port flag.
+ */
+
+static int stl_cd1400datastate(stlport_t *portp)
+{
+#if DEBUG
+       printk("stl_cd1400datastate(portp=%x)\n", (int) portp);
+#endif
+
+       if (portp == (stlport_t *) NULL)
+               return(0);
+
+       return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Interrupt service routine for cd1400 EasyIO boards.
+ */
+
+static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
+{
+       unsigned char   svrtype;
+
+#if DEBUG
+       printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n",
+               (int) panelp, iobase);
+#endif
+
+       outb(SVRR, iobase);
+       svrtype = inb(iobase + EREG_DATA);
+       if (panelp->nrports > 4) {
+               outb((SVRR + 0x80), iobase);
+               svrtype |= inb(iobase + EREG_DATA);
+       }
+
+       if (svrtype & SVRR_RX)
+               stl_cd1400rxisr(panelp, iobase);
+       else if (svrtype & SVRR_TX)
+               stl_cd1400txisr(panelp, iobase);
+       else if (svrtype & SVRR_MDM)
+               stl_cd1400mdmisr(panelp, iobase);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Interrupt service routine for cd1400 panels.
+ */
+
+static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase)
+{
+       unsigned char   svrtype;
+
+#if DEBUG
+       printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp,
+               iobase);
+#endif
+
+       outb(SVRR, iobase);
+       svrtype = inb(iobase + EREG_DATA);
+       outb((SVRR + 0x80), iobase);
+       svrtype |= inb(iobase + EREG_DATA);
+       if (svrtype & SVRR_RX)
+               stl_cd1400rxisr(panelp, iobase);
+       else if (svrtype & SVRR_TX)
+               stl_cd1400txisr(panelp, iobase);
+       else if (svrtype & SVRR_MDM)
+               stl_cd1400mdmisr(panelp, iobase);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Transmit interrupt handler. This has gotta be fast!  Handling TX
+ *     chars is pretty simple, stuff as many as possible from the TX buffer
+ *     into the cd1400 FIFO. Must also handle TX breaks here, since they
+ *     are embedded as commands in the data stream. Oh no, had to use a goto!
+ *     This could be optimized more, will do when I get time...
+ *     In practice it is possible that interrupts are enabled but that the
+ *     port has been hung up. Need to handle not having any TX buffer here,
+ *     this is done by using the side effect that head and tail will also
+ *     be NULL if the buffer has been freed.
+ */
+
+static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr)
+{
+       stlport_t       *portp;
+       int             len, stlen;
+       char            *head, *tail;
+       unsigned char   ioack, srer;
+
+#if DEBUG
+       printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
+#endif
+
+       ioack = inb(ioaddr + EREG_TXACK);
+       if (((ioack & panelp->ackmask) != 0) ||
+           ((ioack & ACK_TYPMASK) != ACK_TYPTX)) {
+               printk("STALLION: bad TX interrupt ack value=%x\n", ioack);
+               return;
+       }
+       portp = panelp->ports[(ioack >> 3)];
+
+/*
+ *     Unfortunately we need to handle breaks in the data stream, since
+ *     this is the only way to generate them on the cd1400. Do it now if
+ *     a break is to be sent.
+ */
+       if (portp->brklen != 0) {
+               if (portp->brklen > 0) {
+                       outb((TDR + portp->uartaddr), ioaddr);
+                       outb(ETC_CMD, (ioaddr + EREG_DATA));
+                       outb(ETC_STARTBREAK, (ioaddr + EREG_DATA));
+                       outb(ETC_CMD, (ioaddr + EREG_DATA));
+                       outb(ETC_DELAY, (ioaddr + EREG_DATA));
+                       outb(portp->brklen, (ioaddr + EREG_DATA));
+                       outb(ETC_CMD, (ioaddr + EREG_DATA));
+                       outb(ETC_STOPBREAK, (ioaddr + EREG_DATA));
+                       portp->brklen = -1;
+                       goto stl_txalldone;
+               } else {
+                       outb((COR2 + portp->uartaddr), ioaddr);
+                       outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC),
+                               (ioaddr + EREG_DATA));
+                       portp->brklen = 0;
+               }
+       }
+
+       head = portp->tx.head;
+       tail = portp->tx.tail;
+       len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
+       if ((len == 0) || ((len < STL_TXBUFLOW) &&
+           (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
+               set_bit(ASYI_TXLOW, &portp->istate);
+               queue_task_irq_off(&portp->tqueue, &tq_scheduler);
+       }
+
+       if (len == 0) {
+               outb((SRER + portp->uartaddr), ioaddr);
+               srer = inb(ioaddr + EREG_DATA);
+               if (srer & SRER_TXDATA) {
+                       srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY;
+               } else {
+                       srer &= ~(SRER_TXDATA | SRER_TXEMPTY);
+                       clear_bit(ASYI_TXBUSY, &portp->istate);
+               }
+               outb(srer, (ioaddr + EREG_DATA));
+       } else {
+               len = MIN(len, CD1400_TXFIFOSIZE);
+               portp->stats.txtotal += len;
+               stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               outb((TDR + portp->uartaddr), ioaddr);
+               outsb((ioaddr + EREG_DATA), tail, stlen);
+               len -= stlen;
+               tail += stlen;
+               if (tail >= (portp->tx.buf + STL_TXBUFSIZE))
+                       tail = portp->tx.buf;
+               if (len > 0) {
+                       outsb((ioaddr + EREG_DATA), tail, len);
+                       tail += len;
+               }
+               portp->tx.tail = tail;
+       }
+
+stl_txalldone:
+       outb((EOSRR + portp->uartaddr), ioaddr);
+       outb(0, (ioaddr + EREG_DATA));
+}
+
+/*****************************************************************************/
+
+/*
+ *     Receive character interrupt handler. Determine if we have good chars
+ *     or bad chars and then process appropriately. Good chars are easy
+ *     just shove the lot into the RX buffer and set all status byte to 0.
+ *     If a bad RX char then process as required. This routine needs to be
+ *     fast!  In practice it is possible that we get an interrupt on a port
+ *     that is closed. This can happen on hangups - since they completely
+ *     shutdown a port not in user context. Need to handle this case.
  */
 
-static void stl_startrxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
 {
-       unsigned char   sreron, sreroff;
-       unsigned long   flags;
+       stlport_t               *portp;
+       struct tty_struct       *tty;
+       unsigned int            ioack, len, buflen;
+       unsigned char           status;
+       char                    ch;
 
 #if DEBUG
-       printk("stl_startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
+       printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
 #endif
 
-       sreron = 0;
-       sreroff = 0;
-       if (tx == 0)
-               sreroff |= (SRER_TXDATA | SRER_TXEMPTY);
-       else if (tx == 1)
-               sreron |= SRER_TXDATA;
-       else if (tx >= 2)
-               sreron |= SRER_TXEMPTY;
-       if (rx == 0)
-               sreroff |= SRER_RXDATA;
-       else if (rx > 0)
-               sreron |= SRER_RXDATA;
+       ioack = inb(ioaddr + EREG_RXACK);
+       if ((ioack & panelp->ackmask) != 0) {
+               printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+               return;
+       }
+       portp = panelp->ports[(ioack >> 3)];
+       tty = portp->tty;
 
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~sreroff) | sreron));
-       BRDDISABLE(portp->brdnr);
-       if (tx > 0)
-               set_bit(ASYI_TXBUSY, &portp->istate);
-       restore_flags(flags);
+       if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
+               outb((RDCR + portp->uartaddr), ioaddr);
+               len = inb(ioaddr + EREG_DATA);
+               if ((tty == (struct tty_struct *) NULL) ||
+                   (tty->flip.char_buf_ptr == (char *) NULL) ||
+                   ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+                       outb((RDSR + portp->uartaddr), ioaddr);
+                       insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
+                       portp->stats.rxlost += len;
+                       portp->stats.rxtotal += len;
+               } else {
+                       len = MIN(len, buflen);
+                       if (len > 0) {
+                               outb((RDSR + portp->uartaddr), ioaddr);
+                               insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len);
+                               memset(tty->flip.flag_buf_ptr, 0, len);
+                               tty->flip.flag_buf_ptr += len;
+                               tty->flip.char_buf_ptr += len;
+                               tty->flip.count += len;
+                               tty_schedule_flip(tty);
+                               portp->stats.rxtotal += len;
+                       }
+               }
+       } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) {
+               outb((RDSR + portp->uartaddr), ioaddr);
+               status = inb(ioaddr + EREG_DATA);
+               ch = inb(ioaddr + EREG_DATA);
+               if (status & ST_PARITY)
+                       portp->stats.rxparity++;
+               if (status & ST_FRAMING)
+                       portp->stats.rxframing++;
+               if (status & ST_OVERRUN)
+                       portp->stats.rxoverrun++;
+               if (status & ST_BREAK)
+                       portp->stats.rxbreaks++;
+               if (status & ST_SCHARMASK) {
+                       if ((status & ST_SCHARMASK) == ST_SCHAR1)
+                               portp->stats.txxon++;
+                       if ((status & ST_SCHARMASK) == ST_SCHAR2)
+                               portp->stats.txxoff++;
+                       goto stl_rxalldone;
+               }
+               if ((tty != (struct tty_struct *) NULL) &&
+                   ((portp->rxignoremsk & status) == 0)) {
+                       if (portp->rxmarkmsk & status) {
+                               if (status & ST_BREAK) {
+                                       status = TTY_BREAK;
+                                       if (portp->flags & ASYNC_SAK) {
+                                               do_SAK(tty);
+                                               BRDENABLE(portp->brdnr, portp->pagenr);
+                                       }
+                               } else if (status & ST_PARITY) {
+                                       status = TTY_PARITY;
+                               } else if (status & ST_FRAMING) {
+                                       status = TTY_FRAME;
+                               } else if(status & ST_OVERRUN) {
+                                       status = TTY_OVERRUN;
+                               } else {
+                                       status = 0;
+                               }
+                       } else {
+                               status = 0;
+                       }
+                       if (tty->flip.char_buf_ptr != (char *) NULL) {
+                               if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+                                       *tty->flip.flag_buf_ptr++ = status;
+                                       *tty->flip.char_buf_ptr++ = ch;
+                                       tty->flip.count++;
+                               }
+                               tty_schedule_flip(tty);
+                       }
+               }
+       } else {
+               printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+               return;
+       }
+
+stl_rxalldone:
+       outb((EOSRR + portp->uartaddr), ioaddr);
+       outb(0, (ioaddr + EREG_DATA));
 }
 
 /*****************************************************************************/
 
 /*
- *     Disable all interrupts from this port.
+ *     Modem interrupt handler. The is called when the modem signal line
+ *     (DCD) has changed state. Leave most of the work to the off-level
+ *     processing routine.
  */
 
-static void stl_disableintrs(stlport_t *portp)
+static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr)
 {
-       unsigned long   flags;
+       stlport_t       *portp;
+       unsigned int    ioack;
+       unsigned char   misr;
 
 #if DEBUG
-       printk("stl_disableintrs(portp=%x)\n", (int) portp);
+       printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp);
 #endif
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       stl_setreg(portp, SRER, 0);
-       BRDDISABLE(portp->brdnr);
-       restore_flags(flags);
+
+       ioack = inb(ioaddr + EREG_MDACK);
+       if (((ioack & panelp->ackmask) != 0) ||
+           ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) {
+               printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack);
+               return;
+       }
+       portp = panelp->ports[(ioack >> 3)];
+
+       outb((MISR + portp->uartaddr), ioaddr);
+       misr = inb(ioaddr + EREG_DATA);
+       if (misr & MISR_DCD) {
+               set_bit(ASYI_DCDCHANGE, &portp->istate);
+               queue_task_irq_off(&portp->tqueue, &tq_scheduler);
+               portp->stats.modem++;
+       }
+
+       outb((EOSRR + portp->uartaddr), ioaddr);
+       outb(0, (ioaddr + EREG_DATA));
 }
 
 /*****************************************************************************/
+/*                      SC26198 HARDWARE FUNCTIONS                           */
+/*****************************************************************************/
+
+/*
+ *     These functions get/set/update the registers of the sc26198 UARTs.
+ *     Access to the sc26198 registers is via an address/data io port pair.
+ *     (Maybe should make this inline...)
+ */
 
-static void stl_sendbreak(stlport_t *portp, long len)
+static int stl_sc26198getreg(stlport_t *portp, int regnr)
 {
-       unsigned long   flags;
+       outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
+       return(inb(portp->ioaddr + XP_DATA));
+}
 
-#if DEBUG
-       printk("stl_sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len);
-#endif
+static void stl_sc26198setreg(stlport_t *portp, int regnr, int value)
+{
+       outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
+       outb(value, (portp->ioaddr + XP_DATA));
+}
 
-       save_flags(flags);
-       cli();
-       BRDENABLE(portp->brdnr, portp->pagenr);
-       stl_setreg(portp, CAR, (portp->portnr & 0x03));
-       stl_setreg(portp, COR2, (stl_getreg(portp, COR2) | COR2_ETC));
-       stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY));
-       BRDDISABLE(portp->brdnr);
-       len = len / 5;
-       portp->brklen = (len > 255) ? 255 : len;
-       portp->stats.txbreaks++;
-       restore_flags(flags);
+static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value)
+{
+       outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
+       if (inb(portp->ioaddr + XP_DATA) != value) {
+               outb(value, (portp->ioaddr + XP_DATA));
+               return(1);
+       }
+       return(0);
 }
 
 /*****************************************************************************/
 
 /*
- *     Map in interrupt vector to this driver. Check that we don't
- *     already have this vector mapped, we might be sharing this
- *     interrupt across multiple boards.
+ *     Functions to get and set the sc26198 global registers.
  */
 
-static int stl_mapirq(int irq)
+static int stl_sc26198getglobreg(stlport_t *portp, int regnr)
 {
-       int     rc, i;
-
-#if DEBUG
-       printk("stl_mapirq(irq=%d)\n", irq);
-#endif
+       outb(regnr, (portp->ioaddr + XP_ADDR));
+       return(inb(portp->ioaddr + XP_DATA));
+}
 
-       rc = 0;
-       for (i = 0; (i < stl_numintrs); i++) {
-               if (stl_gotintrs[i] == irq)
-                       break;
-       }
-       if (i >= stl_numintrs) {
-               if (request_irq(irq, stl_intr, SA_INTERRUPT, stl_drvname, NULL) != 0) {
-                       printk("STALLION: failed to register interrupt routine for irq=%d\n", irq);
-                       rc = -ENODEV;
-               } else {
-                       stl_gotintrs[stl_numintrs++] = irq;
-               }
-       }
-       return(rc);
+#if 0
+static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value)
+{
+       outb(regnr, (portp->ioaddr + XP_ADDR));
+       outb(value, (portp->ioaddr + XP_DATA));
 }
+#endif
 
 /*****************************************************************************/
 
 /*
- *     Try to find and initialize all the ports on a panel. We don't care
- *     what sort of board these ports are on - since the port io registers
- *     are almost identical when dealing with ports.
+ *     Inbitialize the UARTs in a panel. We don't care what sort of board
+ *     these ports are on - since the port io registers are almost
+ *     identical when dealing with ports.
  */
 
-static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
+static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
 {
-       stlport_t       *portp;
-       unsigned int    chipmask;
-       unsigned int    gfrcr;
-       int             nrchips, uartaddr, ioaddr;
-       int             i, j;
+       int     chipmask, i;
+       int     nrchips, ioaddr;
 
 #if DEBUG
-       printk("stl_initports(panelp=%x)\n", (int) panelp);
+       printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n",
+               (int) brdp, (int) panelp);
 #endif
 
        BRDENABLE(panelp->brdnr, panelp->pagenr);
@@ -2406,773 +3999,959 @@ static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
  *     Check that each chip is present and started up OK.
  */
        chipmask = 0;
-       nrchips = panelp->nrports / CD1400_PORTS;
-       for (i = 0; (i < nrchips); i++) {
-               if (brdp->brdtype == BRD_ECHPCI) {
-                       outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
-                       ioaddr = panelp->iobase;
-               } else {
-                       ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
-               }
-               uartaddr = (i & 0x01) ? 0x080 : 0;
-               outb((GFRCR + uartaddr), ioaddr);
-               outb(0, (ioaddr + EREG_DATA));
-               outb((CCR + uartaddr), ioaddr);
-               outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
-               outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
-               outb((GFRCR + uartaddr), ioaddr);
-               for (j = 0; (j < CCR_MAXWAIT); j++) {
-                       if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
-                               break;
-               }
-               if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
-                       printk("STALLION: cd1400 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i);
-                       continue;
-               }
-               chipmask |= (0x1 << i);
-               outb((PPR + uartaddr), ioaddr);
-               outb(PPR_SCALAR, (ioaddr + EREG_DATA));
-       }
+       nrchips = (panelp->nrports + 4) / SC26198_PORTS;
+       if (brdp->brdtype == BRD_ECHPCI)
+               outb(panelp->pagenr, brdp->ioctrl);
 
-/*
- *     All cd1400's are initialized (if found!). Now go through and setup
- *     each ports data structures. Also init the LIVR register of cd1400
- *     for each port.
- */
-       ioaddr = panelp->iobase;
-       for (i = 0; (i < panelp->nrports); i++) {
-               if (brdp->brdtype == BRD_ECHPCI) {
-                       outb((panelp->pagenr + (i >> 3)), brdp->ioctrl);
-                       ioaddr = panelp->iobase;
-               } else {
-                       ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 3));
-               }
-               if ((chipmask & (0x1 << (i / 4))) == 0)
-                       continue;
-               portp = (stlport_t *) stl_memalloc(sizeof(stlport_t));
-               if (portp == (stlport_t *) NULL) {
-                       printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlport_t));
-                       break;
-               }
-               memset(portp, 0, sizeof(stlport_t));
-               portp->magic = STL_PORTMAGIC;
-               portp->portnr = i;
-               portp->brdnr = panelp->brdnr;
-               portp->panelnr = panelp->panelnr;
-               portp->ioaddr = ioaddr;
-               portp->uartaddr = (i & 0x04) << 5;
-               portp->pagenr = panelp->pagenr + (i >> 3);
-               portp->clk = brdp->clk;
-               portp->baud_base = STL_BAUDBASE;
-               portp->close_delay = STL_CLOSEDELAY;
-               portp->closing_wait = 30 * HZ;
-               portp->normaltermios = stl_deftermios;
-               portp->callouttermios = stl_deftermios;
-               portp->tqueue.routine = stl_offintr;
-               portp->tqueue.data = portp;
-               portp->stats.brd = portp->brdnr;
-               portp->stats.panel = portp->panelnr;
-               portp->stats.port = portp->portnr;
-               stl_setreg(portp, CAR, (i & 0x03));
-               stl_setreg(portp, LIVR, (i << 3));
-               portp->hwid = stl_getreg(portp, GFRCR);
-               panelp->ports[i] = portp;
+       for (i = 0; (i < nrchips); i++) {
+               ioaddr = panelp->iobase + (i * 4); 
+               outb(SCCR, (ioaddr + XP_ADDR));
+               outb(CR_RESETALL, (ioaddr + XP_DATA));
+               outb(TSTR, (ioaddr + XP_ADDR));
+               if (inb(ioaddr + XP_DATA) != 0) {
+                       printk("STALLION: sc26198 not responding, "
+                               "brd=%d panel=%d chip=%d\n",
+                               panelp->brdnr, panelp->panelnr, i);
+                       continue;
+               }
+               chipmask |= (0x1 << i);
+               outb(GCCR, (ioaddr + XP_ADDR));
+               outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA));
+               outb(WDTRCR, (ioaddr + XP_ADDR));
+               outb(0xff, (ioaddr + XP_DATA));
        }
 
        BRDDISABLE(panelp->brdnr);
-       return(0);
+       return(chipmask);
 }
 
 /*****************************************************************************/
 
 /*
- *     Try to find and initialize an EasyIO board.
+ *     Initialize hardware specific port registers.
  */
 
-static int stl_initeio(stlbrd_t *brdp)
+static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
 {
-       stlpanel_t      *panelp;
-       unsigned int    status;
-       int             rc;
-
 #if DEBUG
-       printk("stl_initeio(brdp=%x)\n", (int) brdp);
+       printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n",
+               (int) brdp, (int) panelp, (int) portp);
 #endif
 
-       brdp->ioctrl = brdp->ioaddr1 + 1;
-       brdp->iostatus = brdp->ioaddr1 + 2;
-       brdp->clk = EIO_CLK;
+       if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
+           (portp == (stlport_t *) NULL))
+               return;
 
-       status = inb(brdp->iostatus);
-       switch (status & EIO_IDBITMASK) {
-       case EIO_8PORTM:
-               brdp->clk = EIO_CLK8M;
-               /* fall thru */
-       case EIO_8PORTRS:
-       case EIO_8PORTDI:
-               brdp->nrports = 8;
+       portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4);
+       portp->uartaddr = (portp->portnr & 0x07) << 4;
+       portp->pagenr = panelp->pagenr;
+       portp->hwid = 0x1;
+
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS);
+       BRDDISABLE(portp->brdnr);
+}
+
+/*****************************************************************************/
+
+/*
+ *     Set up the sc26198 registers for a port based on the termios port
+ *     settings.
+ */
+
+static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
+{
+       stlbrd_t        *brdp;
+       unsigned long   flags;
+       unsigned int    baudrate;
+       unsigned char   mr0, mr1, mr2, clk;
+       unsigned char   imron, imroff, iopr, ipr;
+
+       mr0 = 0;
+       mr1 = 0;
+       mr2 = 0;
+       clk = 0;
+       iopr = 0;
+       imron = 0;
+       imroff = 0;
+
+       brdp = stl_brds[portp->brdnr];
+       if (brdp == (stlbrd_t *) NULL)
+               return;
+
+/*
+ *     Set up the RX char ignore mask with those RX error types we
+ *     can ignore.
+ */
+       portp->rxignoremsk = 0;
+       if (tiosp->c_iflag & IGNPAR)
+               portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING |
+                       SR_RXOVERRUN);
+       if (tiosp->c_iflag & IGNBRK)
+               portp->rxignoremsk |= SR_RXBREAK;
+
+       portp->rxmarkmsk = SR_RXOVERRUN;
+       if (tiosp->c_iflag & (INPCK | PARMRK))
+               portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING);
+       if (tiosp->c_iflag & BRKINT)
+               portp->rxmarkmsk |= SR_RXBREAK;
+
+/*
+ *     Go through the char size, parity and stop bits and set all the
+ *     option register appropriately.
+ */
+       switch (tiosp->c_cflag & CSIZE) {
+       case CS5:
+               mr1 |= MR1_CS5;
                break;
-       case EIO_4PORTRS:
-               brdp->nrports = 4;
+       case CS6:
+               mr1 |= MR1_CS6;
+               break;
+       case CS7:
+               mr1 |= MR1_CS7;
                break;
        default:
-               return(-ENODEV);
+               mr1 |= MR1_CS8;
+               break;
+       }
+
+       if (tiosp->c_cflag & CSTOPB)
+               mr2 |= MR2_STOP2;
+       else
+               mr2 |= MR2_STOP1;
+
+       if (tiosp->c_cflag & PARENB) {
+               if (tiosp->c_cflag & PARODD)
+                       mr1 |= (MR1_PARENB | MR1_PARODD);
+               else
+                       mr1 |= (MR1_PARENB | MR1_PAREVEN);
+       } else {
+               mr1 |= MR1_PARNONE;
        }
 
-       request_region(brdp->ioaddr1, 8, "serial(EIO)");
+       mr1 |= MR1_ERRBLOCK;
+
+/*
+ *     Set the RX FIFO threshold at 8 chars. This gives a bit of breathing
+ *     space for hardware flow control and the like. This should be set to
+ *     VMIN.
+ */
+       mr2 |= MR2_RXFIFOHALF;
 
 /*
- *     Check that the supplied IRQ is good and then use it to setup the
- *     programmable interrupt bits on EIO board. Also set the edge/level
- *     triggered interrupt bit.
+ *     Calculate the baud rate timers. For now we will just assume that
+ *     the input and output baud are the same. The sc26198 has a fixed
+ *     baud rate table, so only discrete baud rates possible.
  */
-       if ((brdp->irq < 0) || (brdp->irq > 15) ||
-                       (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
-               printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
-               return(-EINVAL);
+       baudrate = tiosp->c_cflag & CBAUD;
+       if (baudrate & CBAUDEX) {
+               baudrate &= ~CBAUDEX;
+               if ((baudrate < 1) || (baudrate > 5))
+                       tiosp->c_cflag &= ~CBAUDEX;
+               else
+                       baudrate += 15;
+       }
+       baudrate = stl_baudrates[baudrate];
+       if ((tiosp->c_cflag & CBAUD) == B38400) {
+               if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                       baudrate = 57600;
+               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                       baudrate = 115200;
+               else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+                       baudrate = (portp->baud_base / portp->custom_divisor);
        }
-       outb((stl_vecmap[brdp->irq] | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl);
+       if (baudrate > STL_SC26198MAXBAUD)
+               baudrate = STL_SC26198MAXBAUD;
 
-       panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
-       if (panelp == (stlpanel_t *) NULL) {
-               printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
-               return(-ENOMEM);
+       if (baudrate > 0) {
+               for (clk = 0; (clk < SC26198_NRBAUDS); clk++) {
+                       if (baudrate <= sc26198_baudtable[clk])
+                               break;
+               }
        }
-       memset(panelp, 0, sizeof(stlpanel_t));
 
-       panelp->magic = STL_PANELMAGIC;
-       panelp->brdnr = brdp->brdnr;
-       panelp->panelnr = 0;
-       panelp->nrports = brdp->nrports;
-       panelp->iobase = brdp->ioaddr1;
-       panelp->hwid = status;
-       brdp->panels[0] = panelp;
-       brdp->nrpanels = 1;
-       brdp->state |= BRD_FOUND;
-       brdp->hwid = status;
-       rc = stl_mapirq(brdp->irq);
-       return(rc);
+/*
+ *     Check what form of modem signaling is required and set it up.
+ */
+       if (tiosp->c_cflag & CLOCAL) {
+               portp->flags &= ~ASYNC_CHECK_CD;
+       } else {
+               iopr |= IOPR_DCDCOS;
+               imron |= IR_IOPORT;
+               portp->flags |= ASYNC_CHECK_CD;
+       }
+
+/*
+ *     Setup sc26198 enhanced modes if we can. In particular we want to
+ *     handle as much of the flow control as possible automatically. As
+ *     well as saving a few CPU cycles it will also greatly improve flow
+ *     control reliability.
+ */
+       if (tiosp->c_iflag & IXON) {
+               mr0 |= MR0_SWFTX | MR0_SWFT;
+               imron |= IR_XONXOFF;
+       } else {
+               imroff |= IR_XONXOFF;
+       }
+       if (tiosp->c_iflag & IXOFF)
+               mr0 |= MR0_SWFRX;
+
+       if (tiosp->c_cflag & CRTSCTS) {
+               mr2 |= MR2_AUTOCTS;
+               mr1 |= MR1_AUTORTS;
+       }
+
+/*
+ *     All sc26198 register values calculated so go through and set
+ *     them all up.
+ */
+
+#if DEBUG
+       printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+               portp->portnr, portp->panelnr, portp->brdnr);
+       printk("    mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
+       printk("    iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
+       printk("    schr1=%x schr2=%x schr3=%x schr4=%x\n",
+               tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
+               tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
+#endif
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, IMR, 0);
+       stl_sc26198updatereg(portp, MR0, mr0);
+       stl_sc26198updatereg(portp, MR1, mr1);
+       stl_sc26198setreg(portp, SCCR, CR_RXERRBLOCK);
+       stl_sc26198updatereg(portp, MR2, mr2);
+       stl_sc26198updatereg(portp, IOPIOR,
+               ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr));
+
+       if (baudrate > 0) {
+               stl_sc26198setreg(portp, TXCSR, clk);
+               stl_sc26198setreg(portp, RXCSR, clk);
+       }
+
+       stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]);
+       stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]);
+
+       ipr = stl_sc26198getreg(portp, IPR);
+       if (ipr & IPR_DCD)
+               portp->sigs &= ~TIOCM_CD;
+       else
+               portp->sigs |= TIOCM_CD;
+
+       portp->imr = (portp->imr & ~imroff) | imron;
+       stl_sc26198setreg(portp, IMR, portp->imr);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Try to find an ECH board and initialize it. This code is capable of
- *     dealing with all types of ECH board.
+ *     Set the state of the DTR and RTS signals.
  */
 
-static int stl_initech(stlbrd_t *brdp)
+static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
 {
-       stlpanel_t      *panelp;
-       unsigned int    status, nxtid;
-       int             panelnr, ioaddr, i;
+       unsigned char   iopioron, iopioroff;
+       unsigned long   flags;
 
 #if DEBUG
-       printk("stl_initech(brdp=%x)\n", (int) brdp);
+       printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n",
+               (int) portp, dtr, rts);
 #endif
 
-       status = 0;
+       iopioron = 0;
+       iopioroff = 0;
+       if (dtr == 0)
+               iopioroff |= IPR_DTR;
+       else if (dtr > 0)
+               iopioron |= IPR_DTR;
+       if (rts == 0)
+               iopioroff |= IPR_RTS;
+       else if (rts > 0)
+               iopioron |= IPR_RTS;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, IOPIOR,
+               ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron));
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
+
+/*****************************************************************************/
 
 /*
- *     Set up the initial board register contents for boards. This varies a
- *     bit between the different board types. So we need to handle each
- *     separately. Also do a check that the supplied IRQ is good.
+ *     Return the state of the signals.
  */
-       if (brdp->brdtype == BRD_ECH) {
-               brdp->ioctrl = brdp->ioaddr1 + 1;
-               brdp->iostatus = brdp->ioaddr1 + 1;
-               status = inb(brdp->iostatus);
-               if ((status & ECH_IDBITMASK) != ECH_ID)
-                       return(-ENODEV);
 
-               if ((brdp->irq < 0) || (brdp->irq > 15) ||
-                               (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
-                       printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
-                       return(-EINVAL);
-               }
-               status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
-               status |= (stl_vecmap[brdp->irq] << 1);
-               outb((status | ECH_BRDRESET), brdp->ioaddr1);
-               brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
-               outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
-               outb(status, brdp->ioaddr1);
+static int stl_sc26198getsignals(stlport_t *portp)
+{
+       unsigned char   ipr;
+       unsigned long   flags;
+       int             sigs;
 
-               request_region(brdp->ioaddr1, 2, "serial(EC8/32)");
-               request_region(brdp->ioaddr2, 32, "serial(EC8/32-secondary)");
-       } else if (brdp->brdtype == BRD_ECHMC) {
-               brdp->ioctrl = brdp->ioaddr1 + 0x20;
-               brdp->iostatus = brdp->ioctrl;
-               status = inb(brdp->iostatus);
-               if ((status & ECH_IDBITMASK) != ECH_ID)
-                       return(-ENODEV);
+#if DEBUG
+       printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
+#endif
 
-               if ((brdp->irq < 0) || (brdp->irq > 15) ||
-                               (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
-                       printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
-                       return(-EINVAL);
-               }
-               outb(ECHMC_BRDRESET, brdp->ioctrl);
-               outb(ECHMC_INTENABLE, brdp->ioctrl);
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       ipr = stl_sc26198getreg(portp, IPR);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
 
-               request_region(brdp->ioaddr1, 64, "serial(EC8/32-MC)");
-       } else if (brdp->brdtype == BRD_ECHPCI) {
-               brdp->ioctrl = brdp->ioaddr1 + 2;
-               request_region(brdp->ioaddr1, 4, "serial(EC8/32-PCI)");
-               request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)");
-       }
+       sigs = 0;
+       sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD;
+       sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS;
+       sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR;
+       sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS;
+       sigs |= TIOCM_DSR;
+       return(sigs);
+}
 
-       brdp->clk = ECH_CLK;
-       brdp->hwid = status;
+/*****************************************************************************/
 
 /*
- *     Scan through the secondary io address space looking for panels.
- *     As we find'em allocate and initialize panel structures for each.
+ *     Enable/Disable the Transmitter and/or Receiver.
  */
-       ioaddr = brdp->ioaddr2;
-       panelnr = 0;
-       nxtid = 0;
 
-       for (i = 0; (i < STL_MAXPANELS); i++) {
-               if (brdp->brdtype == BRD_ECHPCI) {
-                       outb(nxtid, brdp->ioctrl);
-                       ioaddr = brdp->ioaddr2;
-               }
-               status = inb(ioaddr + ECH_PNLSTATUS);
-               if ((status & ECH_PNLIDMASK) != nxtid)
-                       break;
-               panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
-               if (panelp == (stlpanel_t *) NULL) {
-                       printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
-                       break;
-               }
-               memset(panelp, 0, sizeof(stlpanel_t));
-               panelp->magic = STL_PANELMAGIC;
-               panelp->brdnr = brdp->brdnr;
-               panelp->panelnr = panelnr;
-               panelp->iobase = ioaddr;
-               panelp->pagenr = nxtid;
-               panelp->hwid = status;
-               if (status & ECH_PNL16PORT) {
-                       if ((brdp->nrports + 16) > 32)
-                               break;
-                       panelp->nrports = 16;
-                       panelp->ackmask = 0x80;
-                       brdp->nrports += 16;
-                       ioaddr += (EREG_BANKSIZE * 2);
-                       nxtid += 2;
-               } else {
-                       panelp->nrports = 8;
-                       panelp->ackmask = 0xc0;
-                       brdp->nrports += 8;
-                       ioaddr += EREG_BANKSIZE;
-                       nxtid++;
-               }
-               brdp->panels[panelnr++] = panelp;
-               brdp->nrpanels++;
-               if (ioaddr >= (brdp->ioaddr2 + 0x20))
-                       break;
-       }
+static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
+{
+       unsigned char   ccr;
+       unsigned long   flags;
 
-       if (brdp->brdtype == BRD_ECH)
-               outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
+#if DEBUG
+       printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n",
+               (int) portp, rx, tx);
+#endif
 
-       brdp->state |= BRD_FOUND;
-       i = stl_mapirq(brdp->irq);
-       return(i);
+       ccr = portp->crenable;
+       if (tx == 0)
+               ccr &= ~CR_TXENABLE;
+       else if (tx > 0)
+               ccr |= CR_TXENABLE;
+       if (rx == 0)
+               ccr &= ~CR_RXENABLE;
+       else if (rx > 0)
+               ccr |= CR_RXENABLE;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, SCCR, ccr);
+       BRDDISABLE(portp->brdnr);
+       portp->crenable = ccr;
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Initialize and configure the specified board.
- *     Scan through all the boards in the configuration and see what we
- *     can find. Handle EIO and the ECH boards a little differently here
- *     since the initial search and setup is too different.
+ *     Start/stop the Transmitter and/or Receiver.
  */
 
-static int stl_brdinit(stlbrd_t *brdp)
+static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
 {
-       int     i;
+       unsigned char   imr;
+       unsigned long   flags;
 
 #if DEBUG
-       printk("stl_brdinit(brdp=%x)\n", (int) brdp);
+       printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n",
+               (int) portp, rx, tx);
 #endif
 
-       switch (brdp->brdtype) {
-       case BRD_EASYIO:
-               stl_initeio(brdp);
-               break;
-       case BRD_ECH:
-       case BRD_ECHMC:
-       case BRD_ECHPCI:
-               stl_initech(brdp);
-               break;
-       default:
-               printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
-               return(ENODEV);
-       }
-
-       stl_brds[brdp->brdnr] = brdp;
-       if ((brdp->state & BRD_FOUND) == 0) {
-               printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq);
-               return(ENODEV);
-       }
-
-       for (i = 0; (i < STL_MAXPANELS); i++)
-               if (brdp->panels[i] != (stlpanel_t *) NULL)
-                       stl_initports(brdp, brdp->panels[i]);
+       imr = portp->imr;
+       if (tx == 0)
+               imr &= ~IR_TXRDY;
+       else if (tx == 1)
+               imr |= IR_TXRDY;
+       if (rx == 0)
+               imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG);
+       else if (rx > 0)
+               imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG;
 
-       printk("STALLION: %s found, unit=%d io=%x irq=%d nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports);
-       return(0);
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, IMR, imr);
+       BRDDISABLE(portp->brdnr);
+       portp->imr = imr;
+       if (tx > 0)
+               set_bit(ASYI_TXBUSY, &portp->istate);
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Find any ECH-PCI boards that might be installed. Initialize each
- *     one as it is found.
+ *     Disable all interrupts from this port.
  */
 
-#ifdef CONFIG_PCI
-
-static int stl_findpcibrds()
+static void stl_sc26198disableintrs(stlport_t *portp)
 {
-       stlbrd_t        *brdp;
-       unsigned char   busnr, devnr, irq;
-       unsigned short  class;
-       unsigned int    ioaddr;
-       int             i, rc;
+       unsigned long   flags;
 
 #if DEBUG
-       printk("stl_findpcibrds()\n");
+       printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
 #endif
 
-       if (pcibios_present()) {
-               for (i = 0; (i < STL_MAXBRDS); i++) {
-                       if (pcibios_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, i, &busnr, &devnr))
-                               break;
-
-/*
- *                     Found a device on the PCI bus that has our vendor and
- *                     device ID. Need to check now that it is really us.
- */
-                       if ((rc = pcibios_read_config_word(busnr, devnr, PCI_CLASS_DEVICE, &class))) {
-                               printk("STALLION: failed to read class type from PCI board, errno=%x\n", rc);
-                               continue;
-                       }
-                       if (class == PCI_CLASS_STORAGE_IDE)
-                               continue;
-
-                       if (stl_nrbrds >= STL_MAXBRDS) {
-                               printk("STALLION: too many boards found, maximum supported %d\n", STL_MAXBRDS);
-                               break;
-                       }
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       portp->imr = 0;
+       stl_sc26198setreg(portp, IMR, 0);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
 
-/*
- *                     We have a Stallion board. Allocate a board structure
- *                     and initialize it. Read its IO and IRQ resources
- *                     from conf space.
- */
-                       brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
-                       if (brdp == (stlbrd_t *) NULL) {
-                               printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
-                               return(-ENOMEM);
-                       }
-                       memset(brdp, 0, sizeof(stlbrd_t));
-                       brdp->magic = STL_BOARDMAGIC;
-                       brdp->brdnr = stl_nrbrds++;
-                       brdp->brdtype = BRD_ECHPCI;
+/*****************************************************************************/
 
-                       if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_0, &ioaddr))) {
-                               printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
-                               continue;
-                       }
-                       brdp->ioaddr2 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
+static void stl_sc26198sendbreak(stlport_t *portp, long len)
+{
+       unsigned long   flags;
 
-                       if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_1, &ioaddr))) {
-                               printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
-                               continue;
-                       }
-                       brdp->ioaddr1 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
 #if DEBUG
-                       printk("%s(%d): BAR0=%x BAR1=%x\n", __FILE__, __LINE__, brdp->ioaddr2, brdp->ioaddr1);
+       printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp,
+               (int) len);
 #endif
 
-                       if ((rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq))) {
-                               printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
-                               continue;
-                       }
-                       brdp->irq = irq;
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + (len / (1000 / HZ));
 
-                       stl_brdinit(brdp);
-               }
-       }
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
+       BRDDISABLE(portp->brdnr);
+       portp->stats.txbreaks++;
 
-       return(0);
-}
+       schedule();
 
-#endif
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
+}
 
 /*****************************************************************************/
 
 /*
- *     Scan through all the boards in the configuration and see what we
- *     can find. Handle EIO and the ECH boards a little differently here
- *     since the initial search and setup is too different.
+ *     Take flow control actions...
  */
 
-static int stl_initbrds()
+static void stl_sc26198flowctrl(stlport_t *portp, int state)
 {
-       stlbrd_t        *brdp;
-       stlconf_t       *confp;
-       int             i;
+       struct tty_struct       *tty;
+       unsigned long           flags;
+       unsigned char           mr0;
 
 #if DEBUG
-       printk("stl_initbrds()\n");
+       printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state);
 #endif
 
-       if (stl_nrbrds > STL_MAXBRDS) {
-               printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
-               stl_nrbrds = STL_MAXBRDS;
-       }
+       if (portp == (stlport_t *) NULL)
+               return;
+       tty = portp->tty;
+       if (tty == (struct tty_struct *) NULL)
+               return;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
 
+       if (state) {
+               if (tty->termios->c_iflag & IXOFF) {
+                       mr0 = stl_sc26198getreg(portp, MR0);
+                       stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+                       stl_sc26198setreg(portp, SCCR, CR_TXSENDXON);
+                       mr0 |= MR0_SWFRX;
+                       portp->stats.rxxon++;
+                       stl_sc26198wait(portp);
+                       stl_sc26198setreg(portp, MR0, mr0);
+               }
 /*
- *     Firstly scan the list of static boards configured. Allocate
- *     resources and initialize the boards as found.
+ *             Question: should we return RTS to what it was before? It may
+ *             have been set by an ioctl... Suppose not, since if you have
+ *             hardware flow control set then it is pretty silly to go and
+ *             set the RTS line by hand.
  */
-       for (i = 0; (i < stl_nrbrds); i++) {
-               confp = &stl_brdconf[i];
-               brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
-               if (brdp == (stlbrd_t *) NULL) {
-                       printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
-                       return(-ENOMEM);
+               if (tty->termios->c_cflag & CRTSCTS) {
+                       stl_sc26198setreg(portp, MR1,
+                               (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS));
+                       stl_sc26198setreg(portp, IOPIOR,
+                               (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS));
+                       portp->stats.rxrtson++;
+               }
+       } else {
+               if (tty->termios->c_iflag & IXOFF) {
+                       mr0 = stl_sc26198getreg(portp, MR0);
+                       stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+                       stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF);
+                       mr0 &= ~MR0_SWFRX;
+                       portp->stats.rxxoff++;
+                       stl_sc26198wait(portp);
+                       stl_sc26198setreg(portp, MR0, mr0);
+               }
+               if (tty->termios->c_cflag & CRTSCTS) {
+                       stl_sc26198setreg(portp, MR1,
+                               (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS));
+                       stl_sc26198setreg(portp, IOPIOR,
+                               (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS));
+                       portp->stats.rxrtsoff++;
                }
-               memset(brdp, 0, sizeof(stlbrd_t));
-
-               brdp->magic = STL_BOARDMAGIC;
-               brdp->brdnr = i;
-               brdp->brdtype = confp->brdtype;
-               brdp->ioaddr1 = confp->ioaddr1;
-               brdp->ioaddr2 = confp->ioaddr2;
-               brdp->irq = confp->irq;
-               brdp->irqtype = confp->irqtype;
-               stl_brdinit(brdp);
        }
 
-#ifdef CONFIG_PCI
-/*
- *     If the PCI BIOS support is compiled in then let's go looking for
- *     ECH-PCI boards.
- */
-       stl_findpcibrds();
-#endif
-
-       return(0);
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Return the board stats structure to user app.
+ *     Send a flow control character.
  */
 
-static int stl_getbrdstats(combrd_t *bp)
+static void stl_sc26198sendflow(stlport_t *portp, int state)
 {
-       stlbrd_t        *brdp;
-       stlpanel_t      *panelp;
-       int             i;
+       struct tty_struct       *tty;
+       unsigned long           flags;
+       unsigned char           mr0;
 
-       memcpy_fromfs(&stl_brdstats, bp, sizeof(combrd_t));
-       if (stl_brdstats.brd >= STL_MAXBRDS)
-               return(-ENODEV);
-       brdp = stl_brds[stl_brdstats.brd];
-       if (brdp == (stlbrd_t *) NULL)
-               return(-ENODEV);
+#if DEBUG
+       printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state);
+#endif
 
-       memset(&stl_brdstats, 0, sizeof(combrd_t));
-       stl_brdstats.brd = brdp->brdnr;
-       stl_brdstats.type = brdp->brdtype;
-       stl_brdstats.hwid = brdp->hwid;
-       stl_brdstats.state = brdp->state;
-       stl_brdstats.ioaddr = brdp->ioaddr1;
-       stl_brdstats.ioaddr2 = brdp->ioaddr2;
-       stl_brdstats.irq = brdp->irq;
-       stl_brdstats.nrpanels = brdp->nrpanels;
-       stl_brdstats.nrports = brdp->nrports;
-       for (i = 0; (i < brdp->nrpanels); i++) {
-               panelp = brdp->panels[i];
-               stl_brdstats.panels[i].panel = i;
-               stl_brdstats.panels[i].hwid = panelp->hwid;
-               stl_brdstats.panels[i].nrports = panelp->nrports;
-       }
+       if (portp == (stlport_t *) NULL)
+               return;
+       tty = portp->tty;
+       if (tty == (struct tty_struct *) NULL)
+               return;
 
-       memcpy_tofs(bp, &stl_brdstats, sizeof(combrd_t));
-       return(0);
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       if (state) {
+               mr0 = stl_sc26198getreg(portp, MR0);
+               stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+               stl_sc26198setreg(portp, SCCR, CR_TXSENDXON);
+               mr0 |= MR0_SWFRX;
+               portp->stats.rxxon++;
+               stl_sc26198wait(portp);
+               stl_sc26198setreg(portp, MR0, mr0);
+       } else {
+               mr0 = stl_sc26198getreg(portp, MR0);
+               stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+               stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF);
+               mr0 &= ~MR0_SWFRX;
+               portp->stats.rxxoff++;
+               stl_sc26198wait(portp);
+               stl_sc26198setreg(portp, MR0, mr0);
+       }
+       BRDDISABLE(portp->brdnr);
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
-/*
- *     Resolve the referenced port number into a port struct pointer.
- */
-
-static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
+static void stl_sc26198flush(stlport_t *portp)
 {
-       stlbrd_t        *brdp;
-       stlpanel_t      *panelp;
+       unsigned long   flags;
 
-       if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
-               return((stlport_t *) NULL);
-       brdp = stl_brds[brdnr];
-       if (brdp == (stlbrd_t *) NULL)
-               return((stlport_t *) NULL);
-       if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
-               return((stlport_t *) NULL);
-       panelp = brdp->panels[panelnr];
-       if (panelp == (stlpanel_t *) NULL)
-               return((stlport_t *) NULL);
-       if ((portnr < 0) || (portnr >= panelp->nrports))
-               return((stlport_t *) NULL);
-       return(panelp->ports[portnr]);
+#if DEBUG
+       printk("stl_sc26198flush(portp=%x)\n", (int) portp);
+#endif
+
+       if (portp == (stlport_t *) NULL)
+               return;
+
+       save_flags(flags);
+       cli();
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       stl_sc26198setreg(portp, SCCR, CR_TXRESET);
+       stl_sc26198setreg(portp, SCCR, portp->crenable);
+       BRDDISABLE(portp->brdnr);
+       portp->tx.tail = portp->tx.head;
+       restore_flags(flags);
 }
 
 /*****************************************************************************/
 
 /*
- *     Return the port stats structure to user app. A NULL port struct
- *     pointer passed in means that we need to find out from the app
- *     what port to get stats for (used through board control device).
+ *     Return the current state of data flow on this port. This is only
+ *     really interresting when determining if data has fully completed
+ *     transmission or not... The sc26198 interrupt scheme cannot
+ *     determine when all data has actually drained, so we need to
+ *     check the port statusy register to be sure.
  */
 
-static int stl_getportstats(stlport_t *portp, comstats_t *cp)
+static int stl_sc26198datastate(stlport_t *portp)
 {
-       unsigned char   *head, *tail;
        unsigned long   flags;
+       unsigned char   sr;
 
-       if (portp == (stlport_t *) NULL) {
-               memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
-               portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
-               if (portp == (stlport_t *) NULL)
-                       return(-ENODEV);
-       }
-
-       portp->stats.state = portp->istate;
-       portp->stats.flags = portp->flags;
-       portp->stats.hwid = portp->hwid;
+#if DEBUG
+       printk("stl_sc26198datastate(portp=%x)\n", (int) portp);
+#endif
 
-       portp->stats.ttystate = 0;
-       portp->stats.cflags = 0;
-       portp->stats.iflags = 0;
-       portp->stats.oflags = 0;
-       portp->stats.lflags = 0;
-       portp->stats.rxbuffered = 0;
+       if (portp == (stlport_t *) NULL)
+               return(0);
+       if (test_bit(ASYI_TXBUSY, &portp->istate))
+               return(1);
 
        save_flags(flags);
        cli();
-       if (portp->tty != (struct tty_struct *) NULL) {
-               if (portp->tty->driver_data == portp) {
-                       portp->stats.ttystate = portp->tty->flags;
-                       portp->stats.rxbuffered = portp->tty->flip.count;
-                       if (portp->tty->termios != (struct termios *) NULL) {
-                               portp->stats.cflags = portp->tty->termios->c_cflag;
-                               portp->stats.iflags = portp->tty->termios->c_iflag;
-                               portp->stats.oflags = portp->tty->termios->c_oflag;
-                               portp->stats.lflags = portp->tty->termios->c_lflag;
-                       }
-               }
-       }
+       BRDENABLE(portp->brdnr, portp->pagenr);
+       sr = stl_sc26198getreg(portp, SR);
+       BRDDISABLE(portp->brdnr);
        restore_flags(flags);
 
-       head = portp->tx.head;
-       tail = portp->tx.tail;
-       portp->stats.txbuffered = ((head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)));
+       return((sr & SR_TXEMPTY) ? 0 : 1);
+}
 
-       portp->stats.signals = (unsigned long) stl_getsignals(portp);
+/*****************************************************************************/
 
-       memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
-       return(0);
+/*
+ *     Delay for a small amount of time, to give the sc26198 a chance
+ *     to process a command...
+ */
+
+static void stl_sc26198wait(stlport_t *portp)
+{
+       int     i;
+
+#if DEBUG
+       printk("stl_sc26198wait(portp=%x)\n", (int) portp);
+#endif
+
+       if (portp == (stlport_t *) NULL)
+               return;
+
+       for (i = 0; (i < 20); i++)
+               stl_sc26198getglobreg(portp, TSTR);
 }
 
 /*****************************************************************************/
 
 /*
- *     Clear the port stats structure. We also return it zeroed out...
+ *     If we are TX flow controlled and in IXANY mode then we may
+ *     need to unflow control here. We gotta do this because of the
+ *     automatic flow control modes of the sc26198.
  */
 
-static int stl_clrportstats(stlport_t *portp, comstats_t *cp)
+static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty)
 {
-       if (portp == (stlport_t *) NULL) {
-               memcpy_fromfs(&stl_comstats, cp, sizeof(comstats_t));
-               portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
-               if (portp == (stlport_t *) NULL)
-                       return(-ENODEV);
-       }
-
-       memset(&portp->stats, 0, sizeof(comstats_t));
-       portp->stats.brd = portp->brdnr;
-       portp->stats.panel = portp->panelnr;
-       portp->stats.port = portp->portnr;
-       memcpy_tofs(cp, &portp->stats, sizeof(comstats_t));
-       return(0);
+       unsigned char   mr0;
+
+       mr0 = stl_sc26198getreg(portp, MR0);
+       stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+       stl_sc26198setreg(portp, SCCR, CR_HOSTXON);
+       stl_sc26198wait(portp);
+       stl_sc26198setreg(portp, MR0, mr0);
+       clear_bit(ASYI_TXFLOWED, &portp->istate);
 }
 
 /*****************************************************************************/
 
 /*
- *     Return the entire driver ports structure to a user app.
+ *     Interrupt service routine for sc26198 panels.
  */
 
-static int stl_getportstruct(unsigned long arg)
+static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
 {
        stlport_t       *portp;
+       unsigned int    iack;
 
-       memcpy_fromfs(&stl_dummyport, (void *) arg, sizeof(stlport_t));
-       portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr,
-                stl_dummyport.portnr);
-       if (portp == (stlport_t *) NULL)
-               return(-ENODEV);
-       memcpy_tofs((void *) arg, portp, sizeof(stlport_t));
-       return(0);
+/* 
+ *     Work around bug in sc26198 chip... Cannot have A6 address
+ *     line of UART high, else iack will be returned as 0.
+ */
+       outb(0, (iobase + 1));
+
+       iack = inb(iobase + XP_IACK);
+       portp = panelp->ports[(iack & IVR_CHANMASK) + ((iobase & 0x4) << 1)];
+
+       if (iack & IVR_RXDATA)
+               stl_sc26198rxisr(portp, iack);
+       else if (iack & IVR_TXDATA)
+               stl_sc26198txisr(portp);
+       else
+               stl_sc26198otherisr(portp, iack);
 }
 
 /*****************************************************************************/
 
 /*
- *     Return the entire driver board structure to a user app.
+ *     Transmit interrupt handler. This has gotta be fast!  Handling TX
+ *     chars is pretty simple, stuff as many as possible from the TX buffer
+ *     into the sc26198 FIFO.
+ *     In practice it is possible that interrupts are enabled but that the
+ *     port has been hung up. Need to handle not having any TX buffer here,
+ *     this is done by using the side effect that head and tail will also
+ *     be NULL if the buffer has been freed.
  */
 
-static int stl_getbrdstruct(unsigned long arg)
+static void stl_sc26198txisr(stlport_t *portp)
 {
-       stlbrd_t        *brdp;
+       unsigned int    ioaddr;
+       unsigned char   mr0;
+       int             len, stlen;
+       char            *head, *tail;
 
-       memcpy_fromfs(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t));
-       if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS))
-               return(-ENODEV);
-       brdp = stl_brds[stl_dummybrd.brdnr];
-       if (brdp == (stlbrd_t *) NULL)
-               return(-ENODEV);
-       memcpy_tofs((void *) arg, brdp, sizeof(stlbrd_t));
-       return(0);
+#if DEBUG
+       printk("stl_sc26198txisr(portp=%x)\n", (int) portp);
+#endif
+
+       ioaddr = portp->ioaddr;
+       head = portp->tx.head;
+       tail = portp->tx.tail;
+       len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
+       if ((len == 0) || ((len < STL_TXBUFLOW) &&
+           (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
+               set_bit(ASYI_TXLOW, &portp->istate);
+               queue_task_irq_off(&portp->tqueue, &tq_scheduler);
+       }
+
+       if (len == 0) {
+               outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR));
+               mr0 = inb(ioaddr + XP_DATA);
+               if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) {
+                       portp->imr &= ~IR_TXRDY;
+                       outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR));
+                       outb(portp->imr, (ioaddr + XP_DATA));
+                       clear_bit(ASYI_TXBUSY, &portp->istate);
+               } else {
+                       mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY);
+                       outb(mr0, (ioaddr + XP_DATA));
+               }
+       } else {
+               len = MIN(len, SC26198_TXFIFOSIZE);
+               portp->stats.txtotal += len;
+               stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+               outb(GTXFIFO, (ioaddr + XP_ADDR));
+               outsb((ioaddr + XP_DATA), tail, stlen);
+               len -= stlen;
+               tail += stlen;
+               if (tail >= (portp->tx.buf + STL_TXBUFSIZE))
+                       tail = portp->tx.buf;
+               if (len > 0) {
+                       outsb((ioaddr + XP_DATA), tail, len);
+                       tail += len;
+               }
+               portp->tx.tail = tail;
+       }
 }
 
 /*****************************************************************************/
 
 /*
- *     The "staliomem" device is also required to do some special operations
- *     on the board and/or ports. In this driver it is mostly used for stats
- *     collection.
+ *     Receive character interrupt handler. Determine if we have good chars
+ *     or bad chars and then process appropriately. Good chars are easy
+ *     just shove the lot into the RX buffer and set all status byte to 0.
+ *     If a bad RX char then process as required. This routine needs to be
+ *     fast!  In practice it is possible that we get an interrupt on a port
+ *     that is closed. This can happen on hangups - since they completely
+ *     shutdown a port not in user context. Need to handle this case.
  */
 
-static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
+static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
 {
-       int     brdnr, rc;
+       struct tty_struct       *tty;
+       unsigned int            len, buflen, ioaddr;
 
 #if DEBUG
-       printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg);
+       printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack);
 #endif
 
-       brdnr = MINOR(ip->i_rdev);
-       if (brdnr >= STL_MAXBRDS)
-               return(-ENODEV);
-       rc = 0;
-
-       switch (cmd) {
-       case COM_GETPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
-                       rc = stl_getportstats((stlport_t *) NULL, (comstats_t *) arg);
-               break;
-       case COM_CLRPORTSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
-                       rc = stl_clrportstats((stlport_t *) NULL, (comstats_t *) arg);
-               break;
-       case COM_GETBRDSTATS:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0)
-                       rc = stl_getbrdstats((combrd_t *) arg);
-               break;
-       case COM_READPORT:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlport_t))) == 0)
-                       rc = stl_getportstruct(arg);
-               break;
-       case COM_READBOARD:
-               if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlbrd_t))) == 0)
-                       rc = stl_getbrdstruct(arg);
-               break;
-       default:
-               rc = -ENOIOCTLCMD;
-               break;
+       tty = portp->tty;
+       ioaddr = portp->ioaddr;
+       outb(GIBCR, (ioaddr + XP_ADDR));
+       len = inb(ioaddr + XP_DATA) + 1;
+
+       if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
+               if ((tty == (struct tty_struct *) NULL) ||
+                   (tty->flip.char_buf_ptr == (char *) NULL) ||
+                   ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+                       outb(GRXFIFO, (ioaddr + XP_ADDR));
+                       insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
+                       portp->stats.rxlost += len;
+                       portp->stats.rxtotal += len;
+               } else {
+                       len = MIN(len, buflen);
+                       if (len > 0) {
+                               outb(GRXFIFO, (ioaddr + XP_ADDR));
+                               insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len);
+                               memset(tty->flip.flag_buf_ptr, 0, len);
+                               tty->flip.flag_buf_ptr += len;
+                               tty->flip.char_buf_ptr += len;
+                               tty->flip.count += len;
+                               tty_schedule_flip(tty);
+                               portp->stats.rxtotal += len;
+                       }
+               }
+       } else {
+               stl_sc26198rxbadchars(portp);
        }
 
-       return(rc);
+/*
+ *     If we are TX flow controlled and in IXANY mode then we may need
+ *     to unflow control here. We gotta do this because of the automatic
+ *     flow control modes of the sc26198.
+ */
+       if (test_bit(ASYI_TXFLOWED, &portp->istate)) {
+               if ((tty != (struct tty_struct *) NULL) &&
+                   (tty->termios != (struct termios *) NULL) &&
+                   (tty->termios->c_iflag & IXANY)) {
+                       stl_sc26198txunflow(portp, tty);
+               }
+       }
 }
 
 /*****************************************************************************/
 
-int stl_init(void)
+/*
+ *     Process an RX bad character.
+ */
+
+static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch)
 {
-       printk(KERN_INFO "%s: version %s\n", stl_drvname, stl_drvversion);
+       struct tty_struct       *tty;
+       unsigned int            ioaddr;
 
-       stl_initbrds();
+       tty = portp->tty;
+       ioaddr = portp->ioaddr;
+
+       if (status & SR_RXPARITY)
+               portp->stats.rxparity++;
+       if (status & SR_RXFRAMING)
+               portp->stats.rxframing++;
+       if (status & SR_RXOVERRUN)
+               portp->stats.rxoverrun++;
+       if (status & SR_RXBREAK)
+               portp->stats.rxbreaks++;
+
+       if ((tty != (struct tty_struct *) NULL) &&
+           ((portp->rxignoremsk & status) == 0)) {
+               if (portp->rxmarkmsk & status) {
+                       if (status & SR_RXBREAK) {
+                               status = TTY_BREAK;
+                               if (portp->flags & ASYNC_SAK) {
+                                       do_SAK(tty);
+                                       BRDENABLE(portp->brdnr, portp->pagenr);
+                               }
+                       } else if (status & SR_RXPARITY) {
+                               status = TTY_PARITY;
+                       } else if (status & SR_RXFRAMING) {
+                               status = TTY_FRAME;
+                       } else if(status & SR_RXOVERRUN) {
+                               status = TTY_OVERRUN;
+                       } else {
+                               status = 0;
+                       }
+               } else {
+                       status = 0;
+               }
+
+               if (tty->flip.char_buf_ptr != (char *) NULL) {
+                       if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+                               *tty->flip.flag_buf_ptr++ = status;
+                               *tty->flip.char_buf_ptr++ = ch;
+                               tty->flip.count++;
+                       }
+                       tty_schedule_flip(tty);
+               }
+
+               if (status == 0)
+                       portp->stats.rxtotal++;
+       }
+}
+
+/*****************************************************************************/
 
 /*
- *     Allocate a temporary write buffer.
+ *     Process all characters in the RX FIFO of the UART. Check all char
+ *     status bytes as well, and process as required. We need to check
+ *     all bytes in the FIFO, in case some more enter the FIFO while we
+ *     are here. To get the exact character error type we need to switch
+ *     into CHAR error mode (that is why we need to make sure we empty
+ *     the FIFO).
  */
-       stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
-       if (stl_tmpwritebuf == (char *) NULL)
-               printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE);
+
+static void stl_sc26198rxbadchars(stlport_t *portp)
+{
+       unsigned char   status, mr1;
+       char            ch;
 
 /*
- *     Set up a character driver for per board stuff. This is mainly used
- *     to do stats ioctls on the ports.
+ *     To get the precise error type for each character we must switch
+ *     back into CHAR error mode.
  */
-       if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
-               printk("STALLION: failed to register serial board device\n");
+       mr1 = stl_sc26198getreg(portp, MR1);
+       stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK));
+
+       while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) {
+               stl_sc26198setreg(portp, SCCR, CR_CLEARRXERR);
+               ch = stl_sc26198getreg(portp, RXFIFO);
+               stl_sc26198rxbadch(portp, status, ch);
+       }
 
 /*
- *     Set up the tty driver structure and register us as a driver.
- *     Also setup the callout tty device.
+ *     To get correct interrupt class we must switch back into BLOCK
+ *     error mode.
  */
-       memset(&stl_serial, 0, sizeof(struct tty_driver));
-       stl_serial.magic = TTY_DRIVER_MAGIC;
-       stl_serial.name = stl_serialname;
-       stl_serial.major = STL_SERIALMAJOR;
-       stl_serial.minor_start = 0;
-       stl_serial.num = STL_MAXBRDS * STL_MAXPORTS;
-       stl_serial.type = TTY_DRIVER_TYPE_SERIAL;
-       stl_serial.subtype = STL_DRVTYPSERIAL;
-       stl_serial.init_termios = stl_deftermios;
-       stl_serial.flags = TTY_DRIVER_REAL_RAW;
-       stl_serial.refcount = &stl_refcount;
-       stl_serial.table = stl_ttys;
-       stl_serial.termios = stl_termios;
-       stl_serial.termios_locked = stl_termioslocked;
-       
-       stl_serial.open = stl_open;
-       stl_serial.close = stl_close;
-       stl_serial.write = stl_write;
-       stl_serial.put_char = stl_putchar;
-       stl_serial.flush_chars = stl_flushchars;
-       stl_serial.write_room = stl_writeroom;
-       stl_serial.chars_in_buffer = stl_charsinbuffer;
-       stl_serial.ioctl = stl_ioctl;
-       stl_serial.set_termios = stl_settermios;
-       stl_serial.throttle = stl_throttle;
-       stl_serial.unthrottle = stl_unthrottle;
-       stl_serial.stop = stl_stop;
-       stl_serial.start = stl_start;
-       stl_serial.hangup = stl_hangup;
-       stl_serial.flush_buffer = stl_flushbuffer;
+       stl_sc26198setreg(portp, MR1, mr1);
+}
 
-       stl_callout = stl_serial;
-       stl_callout.name = stl_calloutname;
-       stl_callout.major = STL_CALLOUTMAJOR;
-       stl_callout.subtype = STL_DRVTYPCALLOUT;
+/*****************************************************************************/
 
-       if (tty_register_driver(&stl_serial))
-               printk("STALLION: failed to register serial driver\n");
-       if (tty_register_driver(&stl_callout))
-               printk("STALLION: failed to register callout driver\n");
+/*
+ *     Other interrupt handler. This includes modem signals, flow
+ *     control actions, etc. Most stuff is left to off-level interrupt
+ *     processing time.
+ */
 
-       return(0);
+static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack)
+{
+       unsigned char   cir, ipr, xisr;
+
+#if DEBUG
+       printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack);
+#endif
+
+       cir = stl_sc26198getglobreg(portp, CIR);
+
+       switch (cir & CIR_SUBTYPEMASK) {
+       case CIR_SUBCOS:
+               ipr = stl_sc26198getreg(portp, IPR);
+               if (ipr & IPR_DCDCHANGE) {
+                       set_bit(ASYI_DCDCHANGE, &portp->istate);
+                       queue_task_irq_off(&portp->tqueue, &tq_scheduler);
+                       portp->stats.modem++;
+               }
+               break;
+       case CIR_SUBXONXOFF:
+               xisr = stl_sc26198getreg(portp, XISR);
+               if (xisr & XISR_RXXONGOT) {
+                       set_bit(ASYI_TXFLOWED, &portp->istate);
+                       portp->stats.txxoff++;
+               }
+               if (xisr & XISR_RXXOFFGOT) {
+                       clear_bit(ASYI_TXFLOWED, &portp->istate);
+                       portp->stats.txxon++;
+               }
+               break;
+       case CIR_SUBBREAK:
+               stl_sc26198setreg(portp, SCCR, CR_BREAKRESET);
+               stl_sc26198rxbadchars(portp);
+               break;
+       default:
+               break;
+       }
 }
 
 /*****************************************************************************/
index 6e26244d64ee9d6d47c4361a71f092859d92c806..56d527a2516f7efb1474b32f663cb916f8171e03 100644 (file)
@@ -294,7 +294,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
        struct ext2_super_block * es;
 
        if (!dir || !(inode = get_empty_inode ()))
+       {
+               *err=-ENOMEM;
                return NULL;
+       }
        sb = dir->i_sb;
        inode->i_sb = sb;
        inode->i_flags = sb->s_flags;
index d7e2fc621c8b561d4d611c1d47cca2f628d678d3..902d011dfa9d1ca84c2463a491fcc91426a5ed9b 100644 (file)
@@ -597,7 +597,7 @@ int isofs_bmap(struct inode * inode,int block)
         * If we are beyond the end of this file, don't give out any
         * blocks.
         */
-       if( b_off > inode->i_size )
+       if( b_off >= inode->i_size )
          {
            off_t       max_legal_read_offset;
 
index b6e5b667bdc7efc9497c8655d806c6136dc902d6..d07d1e61a6fe187184095000e87e2fcd45279277 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     cd1400.h  -- cd1400 UART hardware info.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This program is free software; you can redistribute it and/or modify
index a3d0167912f8005794225d491a7e209db9fd15be..2180e433023c2ac6ae43149b7fc9660520c9213f 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     cdk.h  -- CDK interface definitions.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -303,6 +304,10 @@ typedef struct asyport {
 #define        P_DTRFOLLOW     0x20
 #define        P_FAKEDCD       0x40
 
+#define        P_RXIMIN        0x10000
+#define        P_RXITIME       0x20000
+#define        P_RXTHOLD       0x40000
+
 /*
  *     Define a structure to communicate serial port signal and data state
  *     information.
index 8f7591f387b55dac82ea79811e3b3cc077f8b845..066888599ae167b8625885f16a9b28c567e4b7a8 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     comstats.h  -- Serial Port Stats.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This program is free software; you can redistribute it and/or modify
index 1cf916ad47a458818d9243c1178539b09420873a..269ef88ba166f30f5202925e5f6d804ff5a2580e 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     istallion.h  -- stallion intelligent multiport serial driver.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -101,6 +102,7 @@ typedef struct stlibrd {
        int             nrports;
        int             nrdevs;
        unsigned int    iobase;
+       int             iosize;
        unsigned long   memaddr;
        void            *membase;
        int             memsize;
diff --git a/include/linux/sc26198.h b/include/linux/sc26198.h
new file mode 100644 (file)
index 0000000..38685e0
--- /dev/null
@@ -0,0 +1,533 @@
+/*****************************************************************************/
+
+/*
+ *     sc26198.h  -- SC26198 UART hardware info.
+ *
+ *     Copyright (C) 1995-1998  Stallion Technologies (support@stallion.oz.au).
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef        _SC26198_H
+#define        _SC26198_H
+/*****************************************************************************/
+
+/*
+ *     Define the number of async ports per sc26198 uart device.
+ */
+#define        SC26198_PORTS           8
+
+/*
+ *     Baud rate timing clocks. All derived from a master 14.7456 MHz clock.
+ */
+#define        SC26198_MASTERCLOCK     14745600L
+#define        SC26198_DCLK            (SC26198_MASTERCLOCK)
+#define        SC26198_CCLK            (SC26198_MASTERCLOCK / 2)
+#define        SC26198_BCLK            (SC26198_MASTERCLOCK / 4)
+
+/*
+ *     Define internal FIFO sizes for the 26198 ports.
+ */
+#define        SC26198_TXFIFOSIZE      16
+#define        SC26198_RXFIFOSIZE      16
+
+/*****************************************************************************/
+
+/*
+ *     Global register definitions. These registers are global to each 26198
+ *     device, not specific ports on it.
+ */
+#define        TSTR            0x0d
+#define        GCCR            0x0f
+#define        ICR             0x1b
+#define        WDTRCR          0x1d
+#define        IVR             0x1f
+#define        BRGTRUA         0x84
+#define        GPOSR           0x87
+#define        GPOC            0x8b
+#define        UCIR            0x8c
+#define        CIR             0x8c
+#define        BRGTRUB         0x8d
+#define        GRXFIFO         0x8e
+#define        GTXFIFO         0x8e
+#define        GCCR2           0x8f
+#define        BRGTRLA         0x94
+#define        GPOR            0x97
+#define        GPOD            0x9b
+#define        BRGTCR          0x9c
+#define        GICR            0x9c
+#define        BRGTRLB         0x9d
+#define        GIBCR           0x9d
+#define        GITR            0x9f
+
+/*
+ *     Per port channel registers. These are the register offsets within
+ *     the port address space, so need to have the port address (0 to 7)
+ *     inserted in bit positions 4:6.
+ */
+#define        MR0             0x00
+#define        MR1             0x01
+#define        IOPCR           0x02
+#define        BCRBRK          0x03
+#define        BCRCOS          0x04
+#define        BCRX            0x06
+#define        BCRA            0x07
+#define        XONCR           0x08
+#define        XOFFCR          0x09
+#define        ARCR            0x0a
+#define        RXCSR           0x0c
+#define        TXCSR           0x0e
+#define        MR2             0x80
+#define        SR              0x81
+#define SCCR           0x81
+#define        ISR             0x82
+#define        IMR             0x82
+#define        TXFIFO          0x83
+#define        RXFIFO          0x83
+#define        IPR             0x84
+#define        IOPIOR          0x85
+#define        XISR            0x86
+
+/*
+ *     For any given port calculate the address to use to access a specified
+ *     register. This is only used for unusual access, mostly this is done
+ *     through the assembler access routines.
+ */
+#define        SC26198_PORTREG(port,reg)       ((((port) & 0x07) << 4) | (reg))
+
+/*****************************************************************************/
+
+/*
+ *     Global configuration control register bit definitions.
+ */
+#define        GCCR_NOACK              0x00
+#define        GCCR_IVRACK             0x02
+#define        GCCR_IVRCHANACK         0x04
+#define        GCCR_IVRTYPCHANACK      0x06
+#define        GCCR_ASYNCCYCLE         0x00
+#define        GCCR_SYNCCYCLE          0x40
+
+/*****************************************************************************/
+
+/*
+ *     Mode register 0 bit definitions.
+ */
+#define        MR0_ADDRNONE            0x00
+#define        MR0_AUTOWAKE            0x01
+#define        MR0_AUTODOZE            0x02
+#define        MR0_AUTOWAKEDOZE        0x03
+#define        MR0_SWFNONE             0x00
+#define        MR0_SWFTX               0x04
+#define        MR0_SWFRX               0x08
+#define        MR0_SWFRXTX             0x0c
+#define        MR0_TXMASK              0x30
+#define        MR0_TXEMPTY             0x00
+#define        MR0_TXHIGH              0x10
+#define        MR0_TXHALF              0x20
+#define        MR0_TXRDY               0x00
+#define        MR0_ADDRNT              0x00
+#define        MR0_ADDRT               0x40
+#define        MR0_SWFNT               0x00
+#define        MR0_SWFT                0x80
+
+/*
+ *     Mode register 1 bit definitions.
+ */
+#define        MR1_CS5                 0x00
+#define        MR1_CS6                 0x01
+#define        MR1_CS7                 0x02
+#define        MR1_CS8                 0x03
+#define        MR1_PAREVEN             0x00
+#define        MR1_PARODD              0x04
+#define        MR1_PARENB              0x00
+#define        MR1_PARFORCE            0x08
+#define        MR1_PARNONE             0x10
+#define        MR1_PARSPECIAL          0x18
+#define        MR1_ERRCHAR             0x00
+#define        MR1_ERRBLOCK            0x20
+#define        MR1_ISRUNMASKED         0x00
+#define        MR1_ISRMASKED           0x40
+#define        MR1_AUTORTS             0x80
+
+/*
+ *     Mode register 2 bit definitions.
+ */
+#define        MR2_STOP1               0x00
+#define        MR2_STOP15              0x01
+#define        MR2_STOP2               0x02
+#define        MR2_STOP916             0x03
+#define        MR2_RXFIFORDY           0x00
+#define        MR2_RXFIFOHALF          0x04
+#define        MR2_RXFIFOHIGH          0x08
+#define        MR2_RXFIFOFULL          0x0c
+#define        MR2_AUTOCTS             0x10
+#define        MR2_TXRTS               0x20
+#define        MR2_MODENORM            0x00
+#define        MR2_MODEAUTOECHO        0x40
+#define        MR2_MODELOOP            0x80
+#define        MR2_MODEREMECHO         0xc0
+
+/*****************************************************************************/
+
+/*
+ *     Baud Rate Generator (BRG) selector values.
+ */
+#define        BRG_50                  0x00
+#define        BRG_75                  0x01
+#define        BRG_150                 0x02
+#define        BRG_200                 0x03
+#define        BRG_300                 0x04
+#define        BRG_450                 0x05
+#define        BRG_600                 0x06
+#define        BRG_900                 0x07
+#define        BRG_1200                0x08
+#define        BRG_1800                0x09
+#define        BRG_2400                0x0a
+#define        BRG_3600                0x0b
+#define        BRG_4800                0x0c
+#define        BRG_7200                0x0d
+#define        BRG_9600                0x0e
+#define        BRG_14400               0x0f
+#define        BRG_19200               0x10
+#define        BRG_28200               0x11
+#define        BRG_38400               0x12
+#define        BRG_57600               0x13
+#define        BRG_115200              0x14
+#define        BRG_230400              0x15
+#define        BRG_GIN0                0x16
+#define        BRG_GIN1                0x17
+#define        BRG_CT0                 0x18
+#define        BRG_CT1                 0x19
+#define        BRG_RX2TX316            0x1b
+#define        BRG_RX2TX31             0x1c
+
+#define        SC26198_MAXBAUD         921600
+
+/*****************************************************************************/
+
+/*
+ *     Command register command definitions.
+ */
+#define        CR_NULL                 0x04
+#define        CR_ADDRNORMAL           0x0c
+#define        CR_RXRESET              0x14
+#define        CR_TXRESET              0x1c
+#define        CR_CLEARRXERR           0x24
+#define        CR_BREAKRESET           0x2c
+#define        CR_TXSTARTBREAK         0x34
+#define        CR_TXSTOPBREAK          0x3c
+#define        CR_RTSON                0x44
+#define        CR_RTSOFF               0x4c
+#define        CR_ADDRINIT             0x5c
+#define        CR_RXERRBLOCK           0x6c
+#define        CR_TXSENDXON            0x84
+#define        CR_TXSENDXOFF           0x8c
+#define        CR_GANGXONSET           0x94
+#define        CR_GANGXOFFSET          0x9c
+#define        CR_GANGXONINIT          0xa4
+#define        CR_GANGXOFFINIT         0xac
+#define        CR_HOSTXON              0xb4
+#define        CR_HOSTXOFF             0xbc
+#define        CR_CANCELXOFF           0xc4
+#define        CR_ADDRRESET            0xdc
+#define        CR_RESETALLPORTS        0xf4
+#define        CR_RESETALL             0xfc
+
+#define        CR_RXENABLE             0x01
+#define        CR_TXENABLE             0x02
+
+/*****************************************************************************/
+
+/*
+ *     Channel status register.
+ */
+#define        SR_RXRDY                0x01
+#define        SR_RXFULL               0x02
+#define        SR_TXRDY                0x04
+#define        SR_TXEMPTY              0x08
+#define        SR_RXOVERRUN            0x10
+#define        SR_RXPARITY             0x20
+#define        SR_RXFRAMING            0x40
+#define        SR_RXBREAK              0x80
+
+#define        SR_RXERRS               (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN)
+
+/*****************************************************************************/
+
+/*
+ *     Interrupt status register and interrupt mask register bit definitions.
+ */
+#define        IR_TXRDY                0x01
+#define        IR_RXRDY                0x02
+#define        IR_RXBREAK              0x04
+#define        IR_XONXOFF              0x10
+#define        IR_ADDRRECOG            0x20
+#define        IR_RXWATCHDOG           0x40
+#define        IR_IOPORT               0x80
+
+/*****************************************************************************/
+
+/*
+ *     Interrupt vector register field definitions.
+ */
+#define        IVR_CHANMASK            0x07
+#define        IVR_TYPEMASK            0x18
+#define        IVR_CONSTMASK           0xc0
+
+#define        IVR_RXDATA              0x10
+#define        IVR_RXBADDATA           0x18
+#define        IVR_TXDATA              0x08
+#define        IVR_OTHER               0x00
+
+/*****************************************************************************/
+
+/*
+ *     BRG timer control register bit definitions.
+ */
+#define        BRGCTCR_DISABCLK0       0x00
+#define        BRGCTCR_ENABCLK0        0x08
+#define        BRGCTCR_DISABCLK1       0x00
+#define        BRGCTCR_ENABCLK1        0x80
+
+#define        BRGCTCR_0SCLK16         0x00
+#define        BRGCTCR_0SCLK32         0x01
+#define        BRGCTCR_0SCLK64         0x02
+#define        BRGCTCR_0SCLK128        0x03
+#define        BRGCTCR_0X1             0x04
+#define        BRGCTCR_0X12            0x05
+#define        BRGCTCR_0IO1A           0x06
+#define        BRGCTCR_0GIN0           0x07
+
+#define        BRGCTCR_1SCLK16         0x00
+#define        BRGCTCR_1SCLK32         0x10
+#define        BRGCTCR_1SCLK64         0x20
+#define        BRGCTCR_1SCLK128        0x30
+#define        BRGCTCR_1X1             0x40
+#define        BRGCTCR_1X12            0x50
+#define        BRGCTCR_1IO1B           0x60
+#define        BRGCTCR_1GIN1           0x70
+
+/*****************************************************************************/
+
+/*
+ *     Watch dog timer enable register.
+ */
+#define        WDTRCR_ENABALL          0xff
+
+/*****************************************************************************/
+
+/*
+ *     XON/XOFF interrupt status register.
+ */
+#define        XISR_TXCHARMASK         0x03
+#define        XISR_TXCHARNORMAL       0x00
+#define        XISR_TXWAIT             0x01
+#define        XISR_TXXOFFPEND         0x02
+#define        XISR_TXXONPEND          0x03
+
+#define        XISR_TXFLOWMASK         0x0c
+#define        XISR_TXNORMAL           0x00
+#define        XISR_TXSTOPPEND         0x04
+#define        XISR_TXSTARTED          0x08
+#define        XISR_TXSTOPPED          0x0c
+
+#define        XISR_RXFLOWMASK         0x30
+#define        XISR_RXFLOWNONE         0x00
+#define        XISR_RXXONSENT          0x10
+#define        XISR_RXXOFFSENT         0x20
+
+#define        XISR_RXXONGOT           0x40
+#define        XISR_RXXOFFGOT          0x80
+
+/*****************************************************************************/
+
+/*
+ *     Current interrupt register.
+ */
+#define        CIR_TYPEMASK            0xc0
+#define        CIR_TYPEOTHER           0x00
+#define        CIR_TYPETX              0x40
+#define        CIR_TYPERXGOOD          0x80
+#define        CIR_TYPERXBAD           0xc0
+
+#define        CIR_RXDATA              0x80
+#define        CIR_RXBADDATA           0x40
+#define        CIR_TXDATA              0x40
+
+#define        CIR_CHANMASK            0x07
+#define        CIR_CNTMASK             0x38
+
+#define        CIR_SUBTYPEMASK         0x38
+#define        CIR_SUBNONE             0x00
+#define        CIR_SUBCOS              0x08
+#define        CIR_SUBADDR             0x10
+#define        CIR_SUBXONXOFF          0x18
+#define        CIR_SUBBREAK            0x28
+
+/*****************************************************************************/
+
+/*
+ *     Global interrupting channel register.
+ */
+#define        GICR_CHANMASK           0x07
+
+/*****************************************************************************/
+
+/*
+ *     Global interrupting byte count register.
+ */
+#define        GICR_COUNTMASK          0x0f
+
+/*****************************************************************************/
+
+/*
+ *     Global interrupting type register.
+ */
+#define        GITR_RXMASK             0xc0
+#define        GITR_RXNONE             0x00
+#define        GITR_RXBADDATA          0x80
+#define        GITR_RXGOODDATA         0xc0
+#define        GITR_TXDATA             0x20
+
+#define        GITR_SUBTYPEMASK        0x07
+#define        GITR_SUBNONE            0x00
+#define        GITR_SUBCOS             0x01
+#define        GITR_SUBADDR            0x02
+#define        GITR_SUBXONXOFF         0x03
+#define        GITR_SUBBREAK           0x05
+
+/*****************************************************************************/
+
+/*
+ *     Input port change register.
+ */
+#define        IPR_CTS                 0x01
+#define        IPR_DTR                 0x02
+#define        IPR_RTS                 0x04
+#define        IPR_DCD                 0x08
+#define        IPR_CTSCHANGE           0x10
+#define        IPR_DTRCHANGE           0x20
+#define        IPR_RTSCHANGE           0x40
+#define        IPR_DCDCHANGE           0x80
+
+#define        IPR_CHANGEMASK          0xf0
+
+/*****************************************************************************/
+
+/*
+ *     IO port interrupt and output register.
+ */
+#define        IOPR_CTS                0x01
+#define        IOPR_DTR                0x02
+#define        IOPR_RTS                0x04
+#define        IOPR_DCD                0x08
+#define        IOPR_CTSCOS             0x10
+#define        IOPR_DTRCOS             0x20
+#define        IOPR_RTSCOS             0x40
+#define        IOPR_DCDCOS             0x80
+
+/*****************************************************************************/
+
+/*
+ *     IO port configuration register.
+ */
+#define        IOPCR_SETCTS            0x00
+#define        IOPCR_SETDTR            0x04
+#define        IOPCR_SETRTS            0x10
+#define        IOPCR_SETDCD            0x00
+
+#define        IOPCR_SETSIGS           (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD)
+
+/*****************************************************************************/
+
+/*
+ *     General purpose output select register.
+ */
+#define        GPORS_TXC1XA            0x08
+#define        GPORS_TXC16XA           0x09
+#define        GPORS_RXC16XA           0x0a
+#define        GPORS_TXC16XB           0x0b
+#define        GPORS_GPOR3             0x0c
+#define        GPORS_GPOR2             0x0d
+#define        GPORS_GPOR1             0x0e
+#define        GPORS_GPOR0             0x0f
+
+/*****************************************************************************/
+
+/*
+ *     General purpose output register.
+ */
+#define        GPOR_0                  0x01
+#define        GPOR_1                  0x02
+#define        GPOR_2                  0x04
+#define        GPOR_3                  0x08
+
+/*****************************************************************************/
+
+/*
+ *     General purpose output clock register.
+ */
+#define        GPORC_0NONE             0x00
+#define        GPORC_0GIN0             0x01
+#define        GPORC_0GIN1             0x02
+#define        GPORC_0IO3A             0x02
+
+#define        GPORC_1NONE             0x00
+#define        GPORC_1GIN0             0x04
+#define        GPORC_1GIN1             0x08
+#define        GPORC_1IO3C             0x0c
+
+#define        GPORC_2NONE             0x00
+#define        GPORC_2GIN0             0x10
+#define        GPORC_2GIN1             0x20
+#define        GPORC_2IO3E             0x20
+
+#define        GPORC_3NONE             0x00
+#define        GPORC_3GIN0             0x40
+#define        GPORC_3GIN1             0x80
+#define        GPORC_3IO3G             0xc0
+
+/*****************************************************************************/
+
+/*
+ *     General purpose output data register.
+ */
+#define        GPOD_0MASK              0x03
+#define        GPOD_0SET1              0x00
+#define        GPOD_0SET0              0x01
+#define        GPOD_0SETR0             0x02
+#define        GPOD_0SETIO3B           0x03
+
+#define        GPOD_1MASK              0x0c
+#define        GPOD_1SET1              0x00
+#define        GPOD_1SET0              0x04
+#define        GPOD_1SETR0             0x08
+#define        GPOD_1SETIO3D           0x0c
+
+#define        GPOD_2MASK              0x30
+#define        GPOD_2SET1              0x00
+#define        GPOD_2SET0              0x10
+#define        GPOD_2SETR0             0x20
+#define        GPOD_2SETIO3F           0x30
+
+#define        GPOD_3MASK              0xc0
+#define        GPOD_3SET1              0x00
+#define        GPOD_3SET0              0x40
+#define        GPOD_3SETR0             0x80
+#define        GPOD_3SETIO3H           0xc0
+
+/*****************************************************************************/
+#endif
index b1aa738bcd90cc784c7715d30703623eff1efb4f..35274488dadfc6a68bcdf886d1a9a6a12db807ff 100644 (file)
@@ -3,6 +3,7 @@
 /*
  *     stallion.h  -- stallion multiport serial driver.
  *
+ *     Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
  *     Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -30,6 +31,7 @@
  */
 #define        STL_MAXBRDS             4
 #define        STL_MAXPANELS           4
+#define        STL_MAXBANKS            8
 #define        STL_PORTSPERPANEL       16
 #define        STL_MAXPORTS            64
 #define        STL_MAXDEVS             (STL_MAXBRDS * STL_MAXPORTS)
@@ -65,7 +67,7 @@ typedef struct {
  *     is associated with, this makes it (fairly) easy to get back to the
  *     board/panel info for a port.
  */
-typedef struct {
+typedef struct stlport {
        unsigned long           magic;
        int                     portnr;
        int                     panelnr;
@@ -87,8 +89,11 @@ typedef struct {
        unsigned int            sigs;
        unsigned int            rxignoremsk;
        unsigned int            rxmarkmsk;
+       unsigned int            imr;
+       unsigned int            crenable;
        unsigned long           clk;
        unsigned long           hwid;
+       void                    *uartp;
        struct tty_struct       *tty;
        struct wait_queue       *open_wait;
        struct wait_queue       *close_wait;
@@ -99,34 +104,43 @@ typedef struct {
        stlrq_t                 tx;
 } stlport_t;
 
-typedef struct {
+typedef struct stlpanel {
        unsigned long   magic;
        int             panelnr;
        int             brdnr;
        int             pagenr;
        int             nrports;
        int             iobase;
+       void            *uartp;
+       void            (*isr)(struct stlpanel *panelp, unsigned int iobase);
        unsigned int    hwid;
        unsigned int    ackmask;
        stlport_t       *ports[STL_PORTSPERPANEL];
 } stlpanel_t;
 
-typedef struct {
+typedef struct stlbrd {
        unsigned long   magic;
        int             brdnr;
        int             brdtype;
        int             state;
        int             nrpanels;
        int             nrports;
+       int             nrbnks;
        int             irq;
        int             irqtype;
+       void            (*isr)(struct stlbrd *brdp);
        unsigned int    ioaddr1;
        unsigned int    ioaddr2;
+       unsigned int    iosize1;
+       unsigned int    iosize2;
        unsigned int    iostatus;
        unsigned int    ioctrl;
        unsigned int    ioctrlval;
        unsigned int    hwid;
        unsigned long   clk;
+       unsigned int    bnkpageaddr[STL_MAXBANKS];
+       unsigned int    bnkstataddr[STL_MAXBANKS];
+       stlpanel_t      *bnk2panel[STL_MAXBANKS];
        stlpanel_t      *panels[STL_MAXPANELS];
 } stlbrd_t;
 
index dc067900a4ee06ecc4d35338ad62e69cd4163150..7bf32d0aed6ff25823bb76851d172dcb6433845b 100644 (file)
@@ -131,12 +131,10 @@ extern __inline__ unsigned ip_rt_hash_code(__u32 addr)
 extern __inline__ void ip_rt_put(struct rtable * rt)
 #ifndef MODULE
 {
-       if (rt)
-               atomic_dec(&rt->rt_refcnt);
-
-       /* If this rtable entry is not in the cache, we'd better free it once the
-        * refcnt goes to zero, because nobody else will... */
-       if ( rt && (rt->rt_flags & RTF_NOTCACHED) && (!rt->rt_refcnt) )
+       /* If this rtable entry is not in the cache, we'd better free
+        * it once the refcnt goes to zero, because nobody else will.
+        */
+       if (rt&&atomic_dec_and_test(&rt->rt_refcnt)&&(rt->rt_flags&RTF_NOTCACHED))
                rt_free(rt);
 }
 #else
index c1c25ff857e149bcb39990b25021ee424ef73300..4bf6f9fd99586e304c6d15e8053967e01e7cdbb8 100644 (file)
@@ -610,6 +610,7 @@ static void parse_root_dev(char * line)
                const int num;
        } devices[] = {
                { "nfs",     0x00ff },
+               { "loop",    0x0700 },
                { "hda",     0x0300 },
                { "hdb",     0x0340 },
                { "hdc",     0x1600 },
index 5818cc5fa5f1c29351225f023526abb7eecf2e4b..dd6e6a966e7fa5683a2a0e77ffdc16009fbf767e 100644 (file)
@@ -265,14 +265,15 @@ static int swap_out_process(struct task_struct * p, int dma, int wait, int can_d
         * Go through process' page directory.
         */
        address = p->swap_address;
-       p->swap_address = 0;
 
        /*
         * Find the proper vm-area
         */
        vma = find_vma(p->mm, address);
-       if (!vma)
+       if (!vma) {
+               p->swap_address = 0;
                return 0;
+       }
        if (address < vma->vm_start)
                address = vma->vm_start;
 
index cc01dc7802f14820ee18d2b0d20e14230ce3db41..34b6ad86a518a36b9f844cc874abc893601698b1 100644 (file)
@@ -925,6 +925,15 @@ void rt_free(struct rtable * rt)
 static __inline__ void rt_kick_free_queue(void)
 {
        struct rtable *rt, **rtp;
+#if RT_CACHE_DEBUG >= 2
+       static int in = 0;
+
+       if(in) {
+               printk("Attempted multiple entry: rt_kick_free_queue\n");
+               return;
+       }
+       in++;
+#endif
 
        ip_rt_bh_mask &= ~RT_BH_FREE;
 
@@ -952,6 +961,9 @@ static __inline__ void rt_kick_free_queue(void)
                }
                rtp = &rt->rt_next;
        }
+#if RT_CACHE_DEBUG >= 2
+       in--;
+#endif
 }
 
 void ip_rt_run_bh()
@@ -974,8 +986,11 @@ void ip_rt_run_bh()
                        ip_rt_fast_unlock();
                }
 
-               if (ip_rt_bh_mask & RT_BH_FREE)
+               if (ip_rt_bh_mask & RT_BH_FREE) {
+                       ip_rt_fast_lock();
                        rt_kick_free_queue();
+                       ip_rt_fast_unlock();
+               }
        }
        restore_flags(flags);
 }
@@ -1528,12 +1543,10 @@ struct rtable * ip_rt_slow_route (__u32 daddr, int local, struct device *dev)
 
 void ip_rt_put(struct rtable * rt)
 {
-       if (rt)
-               atomic_dec(&rt->rt_refcnt);
-       
-       /* If this rtable entry is not in the cache, we'd better free it once the
-        * refcnt goes to zero, because nobody else will... */
-       if ( rt && (rt->rt_flags & RTF_NOTCACHED) && (!rt->rt_refcnt) )
+       /* If this rtable entry is not in the cache, we'd better free
+        * it once the refcnt goes to zero, because nobody else will.
+        */
+       if (rt&&atomic_dec_and_test(&rt->rt_refcnt)&&(rt->rt_flags&RTF_NOTCACHED))
                rt_free(rt);
 }