## Automatically generated incremental diff
## From:   linux-2.2.21-pre4
## To:     linux-2.2.21-rc1
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.2.21-pre4/Documentation/Configure.help linux-2.2.21-rc1/Documentation/Configure.help
--- linux-2.2.21-pre4/Documentation/Configure.help	Fri Nov  2 08:39:05 2001
+++ linux-2.2.21-rc1/Documentation/Configure.help	Tue Mar 12 04:35:08 2002
@@ -5927,6 +5927,21 @@
   of the Cisco HDLC/PPP driver (syncppp.c).
   The SyncLink WAN driver (in character devices) must also be enabled.
 
+FarSync T-Series support
+CONFIG_FARSYNC
+  This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
+  from FarSite Communications Ltd.
+  Synchronous communication is supported on all ports at speeds up to
+  8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want)
+  say M here and read Documentation/modules.txt.
+  The module will be called farsync.o and if you want the module to be
+  automatically loaded when the interface is reference then you should
+  add "alias syncX farsync" to /etc/conf.modules for each interface,
+  where X is 0, 1, 2, ...
+
 Frame Relay (DLCI) support
 CONFIG_DLCI
   This is support for the frame relay protocol; frame relay is a fast
diff -urN linux-2.2.21-pre4/MAINTAINERS linux-2.2.21-rc1/MAINTAINERS
--- linux-2.2.21-pre4/MAINTAINERS	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/MAINTAINERS	Tue Mar 12 04:35:08 2002
@@ -1045,12 +1045,12 @@
 S:	Maintained
 
 USB OV511 DRIVER
-P:     Mark McClelland
-M:     mmcclelland@delphi.com
-L:     linux-usb-users@lists.sourceforge.net
-L:     linux-usb-devel@lists.sourceforge.net
-W:     http://alpha.dyndns.org/ov511/
-S:     Maintained
+P:	Mark McClelland
+M:	mmcclell@bigfoot.com
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://alpha.dyndns.org/ov511/
+S:	Maintained
 
 USB PEGASUS DRIVER
 P:	Petko Manolov
diff -urN linux-2.2.21-pre4/Makefile linux-2.2.21-rc1/Makefile
--- linux-2.2.21-pre4/Makefile	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/Makefile	Tue Mar 12 04:35:09 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 21
-EXTRAVERSION = pre4
+EXTRAVERSION = rc1
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.21-pre4/arch/i386/kernel/bluesmoke.c linux-2.2.21-rc1/arch/i386/kernel/bluesmoke.c
--- linux-2.2.21-pre4/arch/i386/kernel/bluesmoke.c	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/arch/i386/kernel/bluesmoke.c	Tue Mar 12 04:35:09 2002
@@ -164,7 +164,7 @@
 	if(l&(1<<8))
 		wrmsr(0x17b, 0xffffffff, 0xffffffff);
 	banks = l&0xff;
-	for(i=0;i<banks;i++)
+	for(i=1;i<banks;i++)
 	{
 		wrmsr(0x400+4*i, 0xffffffff, 0xffffffff); 
 	}
diff -urN linux-2.2.21-pre4/arch/i386/kernel/setup.c linux-2.2.21-rc1/arch/i386/kernel/setup.c
--- linux-2.2.21-pre4/arch/i386/kernel/setup.c	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/arch/i386/kernel/setup.c	Tue Mar 12 04:35:09 2002
@@ -1232,6 +1232,9 @@
 				break;
 		}
 	}
+
+	if ( p )
+		strcpy(c->x86_model_id, p);
 }
 
 struct cpu_model_info {
diff -urN linux-2.2.21-pre4/arch/i386/kernel/traps.c linux-2.2.21-rc1/arch/i386/kernel/traps.c
--- linux-2.2.21-pre4/arch/i386/kernel/traps.c	Fri Nov  2 08:39:05 2001
+++ linux-2.2.21-rc1/arch/i386/kernel/traps.c	Tue Mar 12 04:35:09 2002
@@ -359,6 +359,7 @@
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
 {
 	unsigned int condition;
+	unsigned long eip = regs->eip;
 	struct task_struct *tsk = current;
 
 	if (regs->eflags & VM_MASK)
@@ -366,6 +367,10 @@
 
 	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
 
+	/* If the user set TF, it's simplest to clear it right away. */
+	if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK))
+		goto clear_TF;
+
 	/* Ensure the debug status register is visible to ptrace (or the process itself) */
 	tsk->tss.debugreg[6] = condition;
 
diff -urN linux-2.2.21-pre4/drivers/net/Config.in linux-2.2.21-rc1/drivers/net/Config.in
--- linux-2.2.21-pre4/drivers/net/Config.in	Fri Nov  2 08:39:07 2001
+++ linux-2.2.21-rc1/drivers/net/Config.in	Tue Mar 12 04:35:09 2002
@@ -304,6 +304,10 @@
 #
 tristate 'SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP
 
+# FarSite Communications' cards
+
+tristate 'FarSync T-Series X.21 (and V.35/V.24) cards' CONFIG_FARSYNC
+
 #
 # Lan Media's board. Currently 1000, 1200, 5200, 5245
 #
diff -urN linux-2.2.21-pre4/drivers/net/Makefile linux-2.2.21-rc1/drivers/net/Makefile
--- linux-2.2.21-pre4/drivers/net/Makefile	Fri Nov  2 08:39:07 2001
+++ linux-2.2.21-rc1/drivers/net/Makefile	Tue Mar 12 04:35:09 2002
@@ -1004,6 +1004,16 @@
   endif
 endif
 
+ifeq ($(CONFIG_FARSYNC),y)
+L_OBJS += farsync.o
+CONFIG_SYNCPPP_BUILTIN=y
+else
+  ifeq ($(CONFIG_FARSYNC),m)
+  M_OBJS += farsync.o
+  CONFIG_SYNCPPP_MODULE=y
+  endif
+endif
+
 # If anything built-in uses Z85230, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 
diff -urN linux-2.2.21-pre4/drivers/net/farsync.c linux-2.2.21-rc1/drivers/net/farsync.c
--- linux-2.2.21-pre4/drivers/net/farsync.c	Wed Dec 31 16:00:00 1969
+++ linux-2.2.21-rc1/drivers/net/farsync.c	Tue Mar 12 04:35:09 2002
@@ -0,0 +1,1945 @@
+/*
+ *      FarSync X21 driver for Linux (2.2.x kernel version)
+ *
+ *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
+ *
+ *      Copyright (C) 2001 FarSite Communications Ltd.
+ *      www.farsite.co.uk
+ *
+ *      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.
+ *
+ *      File:   kernel2.2/farsync.c
+ *      Author: R.J.Dunlop      <bob.dunlop@farsite.co.uk>
+ */
+/*      Revision History
+ *      $Log: farsync.c,v $
+ *      Revision 1.10  2002/01/03 16:49:54  kevinc
+ *      Two issues fixed with one stone
+ *      1) Typo so that four port cards detected
+ *      2) increment card count when cards are detected
+ *      This second problems fixes the module unload/load problem
+ *
+ *      Revision 1.9  2001/09/10 11:13:52  rjd
+ *      Correct ioctl parameter checking for security problem highlighted on
+ *      kernel developer list.
+ *
+ *      Revision 1.8  2001/08/21 11:44:57  rjd
+ *      Brought code into line with that used for the official 2.4.9 kernel
+ *
+ *      Revision 1.7  2001/07/03 15:55:51  rjd
+ *      First non-beta version.
+ *      Started preparations for the generic-HDLC version.
+ *
+ *      Revision 1.6  2001/05/29 09:03:28  rjd
+ *      Improved carrier detection handling and removed interrupt loop
+ *      optimisation as unused.
+ *
+ *      Revision 1.5  2001/05/11 12:13:08  rjd
+ *      Corrections to printing macros for later compilers.
+ *      Fixed MTU changing code.
+ *
+ *      Revision 1.4  2001/05/10 08:26:30  rjd
+ *      Added configurable MTU support
+ *
+ *      Revision 1.3  2001/05/02 09:29:20  rjd
+ *      Reboot with noisy lines causing Opps fixed.
+ *      Tx buffer reordering problem fixed.
+ *      Port configuration code simplified.
+ *
+ *      Revision 1.2  2001/04/05 16:36:24  rjd
+ *      Corrected module compilation and upgraded to SMC version 11
+ *
+ *      Revision 1.1.1.1  2001/03/30 13:46:42  rjd
+ *      Import after first Beta shipped.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "syncppp.h"
+#include "farsync.h"
+
+
+/*
+ *      2.4.x compatability macros
+ *
+ *      This driver is effectivly a backport of the 2.4.x kernel driver to the
+ *      2.2.x kernel. Differences are enough that I think trying to use one
+ *      source would have become increasingly difficult and I wanted a clean
+ *      2.4 implementation. However some things can be made compatable via a
+ *      few simple macros.
+ */
+#define netif_wake_queue(dev)       clear_bit(0, &dev->tbusy)
+#define netif_stop_queue(dev)       set_bit(0, &dev->tbusy)
+#define netif_start_queue(dev)      do { dev->tbusy = 0; dev->interrupt = 0; \
+                                        dev->start = 1; } while (0)
+#define netif_carrier_ok(dev)       ((dev)->flags & IFF_RUNNING )
+#define netif_carrier_on(dev)       ((dev)->flags |= IFF_RUNNING )
+#define netif_carrier_off(dev)      ((dev)->flags &= ~IFF_RUNNING )
+
+#define pci_resource_start(dev,bar) ((dev)->base_address[bar] & ~0x00000001)
+
+
+/*
+ *      Module info
+ */
+MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
+MODULE_DESCRIPTION("FarSync T-Series X21 driver. FarSite Communications Ltd.");
+
+EXPORT_NO_SYMBOLS;
+
+
+/*      Driver configuration and global parameters
+ *      ==========================================
+ */
+
+/*      Maximum number of cards supported
+ */
+#define FST_MAX_CARDS           8
+
+/*      Number of ports (per card) supported
+ */
+#define FST_MAX_PORTS           4
+
+
+/*      PCI vendor and device IDs
+ */
+#define FSC_PCI_VENDOR_ID       0x1619  /* FarSite Communications Ltd */
+#define T2P_PCI_DEVICE_ID       0x0400  /* T2P X21 2 port card */
+#define T4P_PCI_DEVICE_ID       0x0440  /* T4P X21 4 port card */
+
+
+/*      Default parameters for the link
+ */
+#define FST_TX_QUEUE_LEN        100     /* At 8Mbps a longer queue length is
+                                         * useful, the syncppp module forces
+                                         * this down assuming a slower line I
+                                         * guess.
+                                         */
+#define FST_MAX_MTU             8000    /* Huge but possible */
+#define FST_DEF_MTU             1500    /* Common sane value */
+
+#define FST_TX_TIMEOUT          (2*HZ)
+
+
+#ifdef ARPHRD_RAWHDLC
+#define ARPHRD_MYTYPE   ARPHRD_RAWHDLC  /* Raw frames */
+#else
+#define ARPHRD_MYTYPE   ARPHRD_HDLC     /* Cisco-HDLC (keepalives etc) */
+#endif
+
+
+/*      Card shared memory layout
+ *      =========================
+ */
+#pragma pack(1)
+
+/*      This information is derived in part from the FarSite FarSync Smc.h
+ *      file. Unfortunately various name clashes and the non-portability of the
+ *      bit field declarations in that file have meant that I have chosen to
+ *      recreate the information here.
+ *
+ *      The SMC (Shared Memory Configuration) has a version number that is
+ *      incremented every time there is a significant change. This number can
+ *      be used to check that we have not got out of step with the firmware
+ *      contained in the .CDE files.
+ */
+#define SMC_VERSION 11
+
+#define FST_MEMSIZE 0x100000    /* Size of card memory (1Mb) */
+
+#define SMC_BASE 0x00002000L    /* Base offset of the shared memory window main
+                                 * configuration structure */
+#define BFM_BASE 0x00010000L    /* Base offset of the shared memory window DMA
+                                 * buffers */
+
+#define LEN_TX_BUFFER 8192      /* Size of packet buffers */
+#define LEN_RX_BUFFER 8192
+
+#define LEN_SMALL_TX_BUFFER 256 /* Size of obsolete buffs used for DOS diags */
+#define LEN_SMALL_RX_BUFFER 256
+
+#define NUM_TX_BUFFER 2         /* Must be power of 2. Fixed by firmware */
+#define NUM_RX_BUFFER 8
+
+/* Interrupt retry time in milliseconds */
+#define INT_RETRY_TIME 2
+
+
+/*      The Am186CH/CC processors support a SmartDMA mode using circular pools
+ *      of buffer descriptors. The structure is almost identical to that used
+ *      in the LANCE Ethernet controllers. Details available as PDF from the
+ *      AMD web site: http://www.amd.com/products/epd/processors/\
+ *                    2.16bitcont/3.am186cxfa/a21914/21914.pdf
+ */
+struct txdesc {                 /* Transmit descriptor */
+        volatile u16 ladr;      /* Low order address of packet. This is a
+                                 * linear address in the Am186 memory space
+                                 */
+        volatile u8  hadr;      /* High order address. Low 4 bits only, high 4
+                                 * bits must be zero
+                                 */
+        volatile u8  bits;      /* Status and config */
+        volatile u16 bcnt;      /* 2s complement of packet size in low 15 bits.
+                                 * Transmit terminal count interrupt enable in
+                                 * top bit.
+                                 */
+                 u16 unused;    /* Not used in Tx */
+};
+
+struct rxdesc {                 /* Receive descriptor */
+        volatile u16 ladr;      /* Low order address of packet */
+        volatile u8  hadr;      /* High order address */
+        volatile u8  bits;      /* Status and config */
+        volatile u16 bcnt;      /* 2s complement of buffer size in low 15 bits.
+                                 * Receive terminal count interrupt enable in
+                                 * top bit.
+                                 */
+        volatile u16 mcnt;      /* Message byte count (15 bits) */
+};
+
+/* Convert a length into the 15 bit 2's complement */
+/* #define cnv_bcnt(len)   (( ~(len) + 1 ) & 0x7FFF ) */
+/* Since we need to set the high bit to enable the completion interrupt this
+ * can be made a lot simpler
+ */
+#define cnv_bcnt(len)   (-(len))
+
+/* Status and config bits for the above */
+#define DMA_OWN         0x80            /* SmartDMA owns the descriptor */
+#define TX_STP          0x02            /* Tx: start of packet */
+#define TX_ENP          0x01            /* Tx: end of packet */
+#define RX_ERR          0x40            /* Rx: error (OR of next 4 bits) */
+#define RX_FRAM         0x20            /* Rx: framing error */
+#define RX_OFLO         0x10            /* Rx: overflow error */
+#define RX_CRC          0x08            /* Rx: CRC error */
+#define RX_HBUF         0x04            /* Rx: buffer error */
+#define RX_STP          0x02            /* Rx: start of packet */
+#define RX_ENP          0x01            /* Rx: end of packet */
+
+
+/* Interrupts from the card are caused by various events and these are presented
+ * in a circular buffer as several events may be processed on one physical int
+ */
+#define MAX_CIRBUFF     32
+
+struct cirbuff {
+        u8 rdindex;             /* read, then increment and wrap */
+        u8 wrindex;             /* write, then increment and wrap */
+        u8 evntbuff[MAX_CIRBUFF];
+};
+
+/* Interrupt event codes.
+ * Where appropriate the two low order bits indicate the port number
+ */
+#define CTLA_CHG        0x18    /* Control signal changed */
+#define CTLB_CHG        0x19
+#define CTLC_CHG        0x1A
+#define CTLD_CHG        0x1B
+
+#define INIT_CPLT       0x20    /* Initialisation complete */
+#define INIT_FAIL       0x21    /* Initialisation failed */
+
+#define ABTA_SENT       0x24    /* Abort sent */
+#define ABTB_SENT       0x25
+#define ABTC_SENT       0x26
+#define ABTD_SENT       0x27
+
+#define TXA_UNDF        0x28    /* Transmission underflow */
+#define TXB_UNDF        0x29
+#define TXC_UNDF        0x2A
+#define TXD_UNDF        0x2B
+
+
+/* Port physical configuration. See farsync.h for field values */
+struct port_cfg {
+        u16  lineInterface;     /* Physical interface type */
+        u8   x25op;             /* Unused at present */
+        u8   internalClock;     /* 1 => internal clock, 0 => external */
+        u32  lineSpeed;         /* Speed in bps */
+};
+
+/* Finally sling all the above together into the shared memory structure.
+ * Sorry it's a hodge podge of arrays, structures and unused bits, it's been
+ * evolving under NT for some time so I guess we're stuck with it.
+ * The structure starts at offset SMC_BASE.
+ * See farsync.h for some field values.
+ */
+struct fst_shared {
+                                /* DMA descriptor rings */
+        struct rxdesc rxDescrRing[FST_MAX_PORTS][NUM_RX_BUFFER];
+        struct txdesc txDescrRing[FST_MAX_PORTS][NUM_TX_BUFFER];
+
+                                /* Obsolete small buffers */
+        u8  smallRxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_SMALL_RX_BUFFER];
+        u8  smallTxBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_SMALL_TX_BUFFER];
+
+        u8  taskStatus;         /* 0x00 => initialising, 0x01 => running,
+                                 * 0xFF => halted
+                                 */
+
+        u8  interruptHandshake; /* Set to 0x01 by adapter to signal interrupt,
+                                 * set to 0xEE by host to acknowledge interrupt
+                                 */
+
+        u16 smcVersion;         /* Must match SMC_VERSION */
+
+        u32 smcFirmwareVersion; /* 0xIIVVRRBB where II = product ID, VV = major
+                                 * version, RR = revision and BB = build
+                                 */
+
+        u16 txa_done;           /* Obsolete completion flags */
+        u16 rxa_done;
+        u16 txb_done;
+        u16 rxb_done;
+        u16 txc_done;
+        u16 rxc_done;
+        u16 txd_done;
+        u16 rxd_done;
+
+        u16 mailbox[4];         /* Diagnostics mailbox. Not used */
+
+        struct cirbuff interruptEvent;  /* interrupt causes */
+
+        u32 v24IpSts[FST_MAX_PORTS];    /* V.24 control input status */
+        u32 v24OpSts[FST_MAX_PORTS];    /* V.24 control output status */
+
+        struct port_cfg portConfig[FST_MAX_PORTS];
+
+        u16 clockStatus[FST_MAX_PORTS]; /* lsb: 0=> present, 1=> absent */
+
+        u16 cableStatus;                /* lsb: 0=> present, 1=> absent */
+
+        u16 txDescrIndex[FST_MAX_PORTS]; /* transmit descriptor ring index */
+        u16 rxDescrIndex[FST_MAX_PORTS]; /* receive descriptor ring index */
+
+        u16 portMailbox[FST_MAX_PORTS][2];      /* command, modifier */
+        u16 cardMailbox[4];                     /* Not used */
+
+                                /* Number of times that card thinks the host has
+                                 * missed an interrupt by not acknowledging
+                                 * within 2mS (I guess NT has problems)
+                                 */
+        u32 interruptRetryCount;
+
+                                /* Driver private data used as an ID. We'll not
+                                 * use this on Linux I'd rather keep such things
+                                 * in main memory rather than on the PCI bus
+                                 */
+        u32 portHandle[FST_MAX_PORTS];
+
+                                /* Count of Tx underflows for stats */
+        u32 transmitBufferUnderflow[FST_MAX_PORTS];
+
+                                /* Debounced V.24 control input status */
+        u32 v24DebouncedSts[FST_MAX_PORTS];
+
+                                /* Adapter debounce timers. Don't touch */
+        u32 ctsTimer[FST_MAX_PORTS];
+        u32 ctsTimerRun[FST_MAX_PORTS];
+        u32 dcdTimer[FST_MAX_PORTS];
+        u32 dcdTimerRun[FST_MAX_PORTS];
+
+        u32 numberOfPorts;      /* Number of ports detected at startup */
+
+        u16 _reserved[64];
+
+        u16 cardMode;           /* Bit-mask to enable features:
+                                 * Bit 0: 1 enables LED identify mode
+                                 */
+
+        u16 portScheduleOffset;
+
+        u32 endOfSmcSignature;  /* endOfSmcSignature MUST be the last member of
+                                 * the structure and marks the end of the shared
+                                 * memory. Adapter code initializes its value as
+                                 * END_SIG.
+                                 */
+};
+
+/* endOfSmcSignature value */
+#define END_SIG                 0x12345678
+
+/* Mailbox values. (portMailbox) */
+#define NOP             0       /* No operation */
+#define ACK             1       /* Positive acknowledgement to PC driver */
+#define NAK             2       /* Negative acknowledgement to PC driver */
+#define STARTPORT       3       /* Start an HDLC port */
+#define STOPPORT        4       /* Stop an HDLC port */
+#define ABORTTX         5       /* Abort the transmitter for a port */
+#define SETV24O         6       /* Set V24 outputs */
+
+
+/* Larger buffers are positioned in memory at offset BFM_BASE */
+struct buf_window {
+        u8 txBuffer[FST_MAX_PORTS][NUM_TX_BUFFER][LEN_TX_BUFFER];
+        u8 rxBuffer[FST_MAX_PORTS][NUM_RX_BUFFER][LEN_RX_BUFFER];
+};
+
+/* Calculate offset of a buffer object within the shared memory window */
+#define BUF_OFFSET(X)   ((unsigned int)&(((struct buf_window *)BFM_BASE)->X))
+
+#pragma pack()
+
+
+/*      Device driver private information
+ *      =================================
+ */
+/*      Per port (line or channel) information
+ */
+struct fst_port_info {
+        void                   *if_ptr; /* Some drivers describe this as a
+                                         * general purpose pointer. However if
+                                         * using syncPPP it has a very specific
+                                         * purpose: it must be the first item in
+                                         * the structure pointed to by dev->priv
+                                         * and must in turn point to the
+                                         * associated ppp_device structure.
+                                         */
+        struct fst_card_info   *card;   /* Card we're associated with */
+        int                     index;  /* Port index on the card */
+        int                     proto;  /* Protocol we are running */
+        int                     hwif;   /* Line hardware (lineInterface copy) */
+        int                     run;    /* Port is running */
+        int                     rxpos;  /* Next Rx buffer to use */
+        int                     txpos;  /* Next Tx buffer to use */
+        int                     txipos; /* Next Tx buffer to check for free */
+        int                     txcnt;  /* Count of Tx buffers in use */
+        struct device           *dev;   /* Kernel network device entry */
+        struct net_device_stats stats;  /* Standard statistics */
+        struct ppp_device       pppdev; /* Link to syncPPP */
+        char name[8];                   /* syncXX\0 == 7 */
+};
+
+/*      Per card information
+ */
+struct fst_card_info {
+        char          *mem;             /* Card memory mapped to kernel space */
+        char          *ctlmem;          /* Control memory for PCI cards */
+        unsigned int   phys_mem;        /* Physical memory window address */
+        unsigned int   phys_ctlmem;     /* Physical control memory address */
+        unsigned int   irq;             /* Interrupt request line number */
+        unsigned int   nports;          /* Number of serial ports */
+        unsigned int   type;            /* Type index of card */
+        unsigned int   state;           /* State of card */
+        spinlock_t     card_lock;       /* Lock for SMP access */
+        unsigned short pci_conf;        /* PCI card config in I/O space */
+                                        /* Per port info */
+        struct fst_port_info ports[ FST_MAX_PORTS ];
+};
+
+                                        /* Pointers to allocated storage info */
+static struct fst_card_info *fst_card_info[ FST_MAX_CARDS ];
+static int fst_ncards = 0;              /* Number of cards we have detected */
+
+
+
+/*
+ *      Shared memory window access macros
+ *
+ *      We have a nice memory based structure above, which could be directly
+ *      mapped on i386 but might not work on other architectures unless we use
+ *      the readb,w,l and writeb,w,l macros. Unfortunately these macros take
+ *      physical offsets so we have to convert. The only saving grace is that
+ *      this should all collapse back to a simple indirection eventually.
+ */
+#define WIN_OFFSET(X)   ((long)&(((struct fst_shared *)SMC_BASE)->X))
+
+#define FST_RDB(C,E)    readb ((C)->mem + WIN_OFFSET(E))
+#define FST_RDW(C,E)    readw ((C)->mem + WIN_OFFSET(E))
+#define FST_RDL(C,E)    readl ((C)->mem + WIN_OFFSET(E))
+
+#define FST_WRB(C,E,B)  writeb ((B), (C)->mem + WIN_OFFSET(E))
+#define FST_WRW(C,E,W)  writew ((W), (C)->mem + WIN_OFFSET(E))
+#define FST_WRL(C,E,L)  writel ((L), (C)->mem + WIN_OFFSET(E))
+
+
+/*
+ *      Debug support
+ */
+#if FST_DEBUG
+
+static int fst_debug_mask = { FST_DEBUG };
+
+/* Most common debug activity is to print something if the corresponding bit
+ * is set in the debug mask. Note: this uses a non-ANSI extension in GCC to
+ * support variable numbers of macro parameters. The inverted if prevents us
+ * eating someone else's else clause.
+ */
+#define dbg(F,fmt,A...) if ( ! ( fst_debug_mask & (F))) \
+                                ; \
+                        else \
+                                printk ( KERN_DEBUG FST_NAME ": " fmt, ## A )
+
+#else
+# define dbg(X...)      /* NOP */
+#endif
+
+
+/*      Printing short cuts
+ */
+#define printk_err(fmt,A...)    printk ( KERN_ERR     FST_NAME ": " fmt, ## A )
+#define printk_warn(fmt,A...)   printk ( KERN_WARNING FST_NAME ": " fmt, ## A )
+#define printk_info(fmt,A...)   printk ( KERN_INFO    FST_NAME ": " fmt, ## A )
+
+
+/*      Card control functions
+ *      ======================
+ */
+/*      Place the processor in reset state
+ *
+ * Used to be a simple write to card control space but a glitch in the latest
+ * AMD Am186CH processor means that we now have to do it by asserting and de-
+ * asserting the PLX chip PCI Adapter Software Reset. Bit 30 in CNTRL register
+ * at offset 0x50.
+ */
+static inline void
+fst_cpureset ( struct fst_card_info *card )
+{
+        unsigned int regval;
+
+        regval = inl ( card->pci_conf + 0x50 );
+
+        outl ( regval |  0x40000000, card->pci_conf + 0x50 );
+        outl ( regval & ~0x40000000, card->pci_conf + 0x50 );
+}
+
+/*      Release the processor from reset
+ */
+static inline void
+fst_cpurelease ( struct fst_card_info *card )
+{
+        (void) readb ( card->ctlmem );
+}
+
+/*      Clear the cards interrupt flag
+ */
+static inline void
+fst_clear_intr ( struct fst_card_info *card )
+{
+        /* Poke the appropriate PLX chip register (same as enabling interrupts)
+         */
+        outw ( 0x0543, card->pci_conf + 0x4C );
+}
+
+/*      Disable card interrupts
+ */
+static inline void
+fst_disable_intr ( struct fst_card_info *card )
+{
+        outw ( 0x0000, card->pci_conf + 0x4C );
+}
+
+
+/*      Issue a Mailbox command for a port.
+ *      Note we issue them on a fire and forget basis, not expecting to see an
+ *      error and not waiting for completion.
+ */
+static void
+fst_issue_cmd ( struct fst_port_info *port, unsigned short cmd )
+{
+        struct fst_card_info *card;
+        unsigned short mbval;
+        unsigned long flags;
+        int safety;
+
+        card = port->card;
+        spin_lock_irqsave ( &card->card_lock, flags );
+        mbval = FST_RDW ( card, portMailbox[port->index][0]);
+
+        safety = 0;
+        /* Wait for any previous command to complete */
+        while ( mbval > NAK )
+        {
+                spin_unlock_irqrestore ( &card->card_lock, flags );
+                schedule_timeout ( 1 );
+                spin_lock_irqsave ( &card->card_lock, flags );
+
+                if ( ++safety > 1000 )
+                {
+                        printk_err ("Mailbox safety timeout\n");
+                        break;
+                }
+
+                mbval = FST_RDW ( card, portMailbox[port->index][0]);
+        }
+        if ( safety > 0 )
+        {
+                dbg ( DBG_CMD,"Mailbox clear after %d jiffies\n", safety );
+        }
+        if ( mbval == NAK )
+        {
+                dbg ( DBG_CMD,"issue_cmd: previous command was NAK'd\n");
+        }
+
+        FST_WRW ( card, portMailbox[port->index][0], cmd );
+
+        if ( cmd == ABORTTX || cmd == STARTPORT )
+        {
+                port->txpos  = 0;
+                port->txipos = 0;
+                port->txcnt  = 0;
+        }
+
+        spin_unlock_irqrestore ( &card->card_lock, flags );
+}
+
+
+/*      Port output signals control
+ */
+static inline void
+fst_op_raise ( struct fst_port_info *port, unsigned int outputs )
+{
+        outputs |= FST_RDL ( port->card, v24OpSts[port->index]);
+        FST_WRL ( port->card, v24OpSts[port->index], outputs );
+
+        if ( port->run )
+                fst_issue_cmd ( port, SETV24O );
+}
+
+static inline void
+fst_op_lower ( struct fst_port_info *port, unsigned int outputs )
+{
+        outputs = ~outputs & FST_RDL ( port->card, v24OpSts[port->index]);
+        FST_WRL ( port->card, v24OpSts[port->index], outputs );
+
+        if ( port->run )
+                fst_issue_cmd ( port, SETV24O );
+}
+
+
+/*
+ *      Setup port Rx buffers
+ */
+static void
+fst_rx_config ( struct fst_port_info *port )
+{
+        int i;
+        int pi;
+        unsigned int offset;
+        unsigned long flags;
+        struct fst_card_info *card;
+
+        pi   = port->index;
+        card = port->card;
+        spin_lock_irqsave ( &card->card_lock, flags );
+        for ( i = 0 ; i < NUM_RX_BUFFER ; i++ )
+        {
+                offset = BUF_OFFSET ( rxBuffer[pi][i][0]);
+
+                FST_WRW ( card, rxDescrRing[pi][i].ladr, (u16) offset );
+                FST_WRB ( card, rxDescrRing[pi][i].hadr, (u8)( offset >> 16 ));
+                FST_WRW ( card, rxDescrRing[pi][i].bcnt,
+                                        cnv_bcnt ( LEN_RX_BUFFER ));
+                FST_WRW ( card, rxDescrRing[pi][i].mcnt, 0 );
+                FST_WRB ( card, rxDescrRing[pi][i].bits, DMA_OWN );
+        }
+        port->rxpos  = 0;
+        spin_unlock_irqrestore ( &card->card_lock, flags );
+}
+
+
+/*
+ *      Setup port Tx buffers
+ */
+static void
+fst_tx_config ( struct fst_port_info *port )
+{
+        int i;
+        int pi;
+        unsigned int offset;
+        unsigned long flags;
+        struct fst_card_info *card;
+
+        pi   = port->index;
+        card = port->card;
+        spin_lock_irqsave ( &card->card_lock, flags );
+        for ( i = 0 ; i < NUM_TX_BUFFER ; i++ )
+        {
+                offset = BUF_OFFSET ( txBuffer[pi][i][0]);
+
+                FST_WRW ( card, txDescrRing[pi][i].ladr, (u16) offset );
+                FST_WRB ( card, txDescrRing[pi][i].hadr, (u8)( offset >> 16 ));
+                FST_WRW ( card, txDescrRing[pi][i].bcnt, 0 );
+                FST_WRB ( card, txDescrRing[pi][i].bits, 0 );
+        }
+        port->txpos  = 0;
+        port->txipos = 0;
+        port->txcnt  = 0;
+        spin_unlock_irqrestore ( &card->card_lock, flags );
+}
+
+
+/*      Control signal change interrupt event
+ */
+static void
+fst_intr_ctlchg ( struct fst_card_info *card, struct fst_port_info *port )
+{
+        int signals;
+
+        signals = FST_RDL ( card, v24DebouncedSts[port->index]);
+
+        if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE : IPSTS_DCD ))
+        {
+                if ( ! netif_carrier_ok ( port->dev ))
+                {
+                        dbg ( DBG_INTR,"DCD active\n");
+
+                        /* Poke sPPP to renegotiate */
+                        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
+                        {
+                                sppp_reopen ( port->dev );
+                        }
+
+                        netif_carrier_on ( port->dev );
+                }
+        }
+        else
+        {
+                if ( netif_carrier_ok ( port->dev ))
+                {
+                        dbg ( DBG_INTR,"DCD lost\n");
+                        netif_carrier_off ( port->dev );
+                }
+        }
+}
+
+
+/*      Rx complete interrupt
+ */
+static void
+fst_intr_rx ( struct fst_card_info *card, struct fst_port_info *port )
+{
+        unsigned char dmabits;
+        int pi;
+        int rxp;
+        unsigned short len;
+        struct sk_buff *skb;
+        int i;
+
+
+        /* Check we have a buffer to process */
+        pi  = port->index;
+        rxp = port->rxpos;
+        dmabits = FST_RDB ( card, rxDescrRing[pi][rxp].bits );
+        if ( dmabits & DMA_OWN )
+        {
+                dbg ( DBG_RX | DBG_INTR,"intr_rx: No buffer port %d pos %d\n",
+                                        pi, rxp );
+                return;
+        }
+
+        /* Get buffer length */
+        len = FST_RDW ( card, rxDescrRing[pi][rxp].mcnt );
+        /* Discard the CRC */
+        len -= 2;
+
+        /* Check buffer length and for other errors. We insist on one packet
+         * in one buffer. This simplifies things greatly and since we've
+         * allocated 8K it shouldn't be a real world limitation
+         */
+        dbg ( DBG_RX,"intr_rx: %d,%d: flags %x len %d\n", pi, rxp, dmabits,
+                                        len );
+        if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 )
+        {
+                port->stats.rx_errors++;
+
+                /* Update error stats and discard buffer */
+                if ( dmabits & RX_OFLO )
+                {
+                        port->stats.rx_fifo_errors++;
+                }
+                if ( dmabits & RX_CRC )
+                {
+                        port->stats.rx_crc_errors++;
+                }
+                if ( dmabits & RX_FRAM )
+                {
+                        port->stats.rx_frame_errors++;
+                }
+                if ( dmabits == ( RX_STP | RX_ENP ))
+                {
+                        port->stats.rx_length_errors++;
+                }
+
+                /* Discard buffer descriptors until we see the end of packet
+                 * marker
+                 */
+                i = 0;
+                while (( dmabits & ( DMA_OWN | RX_ENP )) == 0 )
+                {
+                        FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
+                        if ( ++rxp >= NUM_RX_BUFFER )
+                                rxp = 0;
+                        if ( ++i > NUM_RX_BUFFER )
+                        {
+                                dbg ( DBG_ASS,"intr_rx: Discarding more bufs"
+                                                " than we have\n");
+                                break;
+                        }
+                        dmabits = FST_RDB ( card, rxDescrRing[pi][rxp].bits );
+                }
+
+                /* Discard the terminal buffer */
+                if ( ! ( dmabits & DMA_OWN ))
+                {
+                        FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
+                        if ( ++rxp >= NUM_RX_BUFFER )
+                                rxp = 0;
+                }
+                port->rxpos = rxp;
+                return;
+        }
+
+        /* Allocate SKB */
+        if (( skb = dev_alloc_skb ( len )) == NULL )
+        {
+                dbg ( DBG_RX,"intr_rx: can't allocate buffer\n");
+
+                port->stats.rx_dropped++;
+
+                /* Return descriptor to card */
+                FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
+
+                if ( ++rxp >= NUM_RX_BUFFER )
+                        port->rxpos = 0;
+                else
+                        port->rxpos = rxp;
+                return;
+        }
+
+        memcpy_fromio ( skb_put ( skb, len ),
+                                card->mem + BUF_OFFSET ( rxBuffer[pi][rxp][0]),
+                                len );
+
+        /* Reset buffer descriptor */
+        FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
+        if ( ++rxp >= NUM_RX_BUFFER )
+                port->rxpos = 0;
+        else
+                port->rxpos = rxp;
+
+        /* Update stats */
+        port->stats.rx_packets++;
+        port->stats.rx_bytes += len;
+
+        /* Push upstream */
+        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
+        {
+                /* Mark for further processing by sPPP module */
+                skb->protocol = htons ( ETH_P_WAN_PPP );
+        }
+        else
+        {
+                /* DEC customer specific protocol (since nothing defined for
+                 * marking raw data), at least one other driver uses this value
+                 * for this purpose.
+                 */
+                skb->protocol = htons ( ETH_P_CUST );
+                skb->pkt_type = PACKET_HOST;
+        }
+        skb->mac.raw = skb->data;
+        skb->dev = port->dev;
+        netif_rx ( skb );
+}
+
+
+/*
+ *      The interrupt service routine
+ *      Dev_id is our fst_card_info pointer
+ */
+static void
+fst_intr ( int irq, void *dev_id, struct pt_regs *regs )
+{
+        struct fst_card_info *card;
+        struct fst_port_info *port;
+        int rdidx;                      /* Event buffer indices */
+        int wridx;
+        int event;                      /* Actual event for processing */
+        int pi;
+
+        if (( card = dev_id ) == NULL )
+        {
+                dbg ( DBG_INTR,"intr: spurious %d\n", irq );
+                return;
+        }
+
+        dbg ( DBG_INTR,"intr: %d %p\n", irq, card );
+
+        spin_lock ( &card->card_lock );
+
+        /* Clear and reprime the interrupt source */
+        fst_clear_intr ( card );
+
+        /* Set the software acknowledge */
+        FST_WRB ( card, interruptHandshake, 0xEE );
+
+        /* Drain the event queue */
+        rdidx = FST_RDB ( card, interruptEvent.rdindex );
+        wridx = FST_RDB ( card, interruptEvent.wrindex );
+        while ( rdidx != wridx )
+        {
+                event = FST_RDB ( card, interruptEvent.evntbuff[rdidx]);
+
+                port = &card->ports[event & 0x03];
+
+                dbg ( DBG_INTR,"intr: %x\n", event );
+
+                switch ( event )
+                {
+                case CTLA_CHG:
+                case CTLB_CHG:
+                case CTLC_CHG:
+                case CTLD_CHG:
+                        if ( port->run && port->dev != NULL )
+                                fst_intr_ctlchg ( card, port );
+                        break;
+
+                case ABTA_SENT:
+                case ABTB_SENT:
+                case ABTC_SENT:
+                case ABTD_SENT:
+                        dbg ( DBG_TX,"Abort complete port %d\n", event & 0x03 );
+                        break;
+
+                case TXA_UNDF:
+                case TXB_UNDF:
+                case TXC_UNDF:
+                case TXD_UNDF:
+                        /* Difficult to see how we'd get this given that we
+                         * always load up the entire packet for DMA.
+                         */
+                        dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 );
+
+                        port->stats.tx_errors++;
+                        port->stats.tx_fifo_errors++;
+                        break;
+
+                case INIT_CPLT:
+                        dbg ( DBG_INIT,"Card init OK intr\n");
+                        break;
+
+                case INIT_FAIL:
+                        dbg ( DBG_INIT,"Card init FAILED intr\n");
+                        card->state = FST_IFAILED;
+                        break;
+
+                default:
+                        printk_err ("intr: unknown card event code. ignored\n");
+                        break;
+                }
+
+                /* Bump and wrap the index */
+                if ( ++rdidx >= MAX_CIRBUFF )
+                        rdidx = 0;
+        }
+        FST_WRB ( card, interruptEvent.rdindex, rdidx );
+
+        for ( pi = 0, port = card->ports ; pi < card->nports ; pi++, port++ )
+        {
+                if ( port->dev == NULL || ! port->run )
+                        continue;
+
+                /* Check for rx completions */
+                while ( ! ( FST_RDB ( card, rxDescrRing[pi][port->rxpos].bits )
+                                                                & DMA_OWN ))
+                {
+                        fst_intr_rx ( card, port );
+                }
+
+                /* Check for Tx completions */
+                while ( port->txcnt > 0 && ! ( FST_RDB ( card,
+                        txDescrRing[pi][port->txipos].bits ) & DMA_OWN ))
+                {
+                        --port->txcnt;
+                        if ( ++port->txipos >= NUM_TX_BUFFER )
+                                port->txipos = 0;
+                        netif_wake_queue ( port->dev );
+                }
+        }
+
+        spin_unlock ( &card->card_lock );
+}
+
+
+/*      Check that the shared memory configuration is one that we can handle
+ *      and that some basic parameters are correct
+ */
+static void
+check_started_ok ( struct fst_card_info *card )
+{
+        int i;
+
+        /* Check structure version and end marker */
+        if ( FST_RDW ( card, smcVersion ) != SMC_VERSION )
+        {
+                printk_err ("Bad shared memory version %d expected %d\n",
+                                FST_RDW ( card, smcVersion ), SMC_VERSION );
+                card->state = FST_BADVERSION;
+                return;
+        }
+        if ( FST_RDL ( card, endOfSmcSignature ) != END_SIG )
+        {
+                printk_err ("Missing shared memory signature\n");
+                card->state = FST_BADVERSION;
+                return;
+        }
+        /* Firmware status flag, 0x00 = initialising, 0x01 = OK, 0xFF = fail */
+        if (( i = FST_RDB ( card, taskStatus )) == 0x01 )
+        {
+                card->state = FST_RUNNING;
+        }
+        else if ( i == 0xFF )
+        {
+                printk_err ("Firmware initialisation failed. Card halted\n");
+                card->state = FST_HALTED;
+                return;
+        }
+        else if ( i != 0x00 )
+        {
+                printk_err ("Unknown firmware status 0x%x\n", i );
+                card->state = FST_HALTED;
+                return;
+        }
+
+        /* Finally check the number of ports reported by firmware against the
+         * number we assumed at card detection. Should never happen with
+         * existing firmware etc so we just report it for the moment.
+         */
+        if ( FST_RDL ( card, numberOfPorts ) != card->nports )
+        {
+                printk_warn ("Port count mismatch."
+                                " Firmware thinks %d we say %d\n",
+                                FST_RDL ( card, numberOfPorts ), card->nports );
+        }
+}
+
+
+static int
+fst_change_mtu ( struct device *dev, int new_mtu )
+{
+        if ( new_mtu < 128 || new_mtu > FST_MAX_MTU )
+                return -EINVAL;
+        dev->mtu = new_mtu;
+        return 0;
+}
+
+
+/* Sooner or later you can't avoid a forward declaration */
+static int fst_ioctl ( struct device *dev, struct ifreq *ifr, int cmd );
+
+static int
+switch_proto ( struct fst_port_info *port, int new_proto )
+{
+        int err;
+        int orig_mtu;
+        struct device *dev;
+
+        dev = port->dev;
+
+        /* Turn off sPPP module ? */
+        if (( new_proto != FST_HDLC && new_proto != FST_PPP )
+                && ( port->proto == FST_HDLC || port->proto == FST_PPP ))
+        {
+                sppp_close ( port->pppdev.dev );
+                sppp_detach ( port->pppdev.dev );
+
+                /* Reset some fields overwritten by sPPP */
+                dev->hard_header     = NULL;
+                dev->rebuild_header  = NULL;
+                dev->tx_queue_len    = FST_TX_QUEUE_LEN;
+                dev->type            = ARPHRD_MYTYPE;
+                dev->addr_len        = 0;
+                dev->hard_header_len = 0;
+                dev->do_ioctl        = fst_ioctl;
+                dev->change_mtu      = fst_change_mtu;
+                dev->flags           = IFF_POINTOPOINT|IFF_NOARP;
+
+                return 0;
+        }
+
+        /* Turn on sPPP ? */
+        if (( new_proto == FST_HDLC || new_proto == FST_PPP )
+                && ( port->proto != FST_HDLC && port->proto != FST_PPP ))
+        {
+                orig_mtu = dev->mtu;
+
+                /* Attach to sync PPP module */
+                port->pppdev.dev = dev;
+                sppp_attach ( &port->pppdev );
+
+                if ( orig_mtu < dev->mtu )
+                        dev->change_mtu ( dev, orig_mtu );
+
+                /* Claw back the ioctl routine. We promise to be good and call
+                 * the sync PPP routines once we've eliminated our functions.
+                 */
+                dev->do_ioctl = fst_ioctl;
+
+                /* Set the mode */
+                if ( new_proto == FST_HDLC )
+                {
+                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
+                                                                SPPPIOCCISCO );
+                }
+                else
+                {
+                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
+                                                                SPPPIOCPPP );
+                }
+
+                /* Open the device */
+                if ( err == 0 )
+                {
+                        (void) sppp_open ( port->dev );
+                }
+
+                return err;
+        }
+
+        /* Switch sPPP mode to that desired */
+        err = 0;
+        if ( new_proto == FST_HDLC && port->pppdev.dev != NULL )
+        {
+                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCCISCO );
+        }
+        else if ( new_proto == FST_PPP && port->pppdev.dev != NULL )
+        {
+                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCPPP );
+        }
+
+        /* Anything else is switching from one raw mode to another which is
+         * basically a NOP
+         */
+
+        return err;
+}
+
+
+static int
+set_conf_from_info ( struct fst_card_info *card, struct fst_port_info *port,
+                struct fstioc_info *info )
+{
+        int err;
+
+        /* Set things according to the user set valid flags */
+        err = 0;
+        if ( info->valid & FSTVAL_PROTO )
+        {
+                if ( port->proto != info->proto )
+                {
+                        err = switch_proto ( port, info->proto );
+                        if ( err == 0 )
+                                port->proto = info->proto;
+                }
+        }
+        if ( info->valid & FSTVAL_CABLE )
+        {
+                FST_WRB ( card, portConfig[port->index].lineInterface,
+                                        info->lineInterface );
+                port->hwif = info->lineInterface;
+        }
+        if ( info->valid & FSTVAL_SPEED )
+        {
+                FST_WRL ( card, portConfig[port->index].lineSpeed,
+                                        info->lineSpeed );
+                FST_WRB ( card, portConfig[port->index].internalClock,
+                                        info->internalClock );
+        }
+        if ( info->valid & FSTVAL_MODE )
+        {
+                FST_WRW ( card, cardMode, info->cardMode );
+        }
+#if FST_DEBUG
+        if ( info->valid & FSTVAL_DEBUG )
+        {
+                fst_debug_mask = info->debug;
+        }
+#endif
+
+        return err;
+}
+
+static void
+gather_conf_info ( struct fst_card_info *card, struct fst_port_info *port,
+                struct fstioc_info *info )
+{
+        int i;
+
+        memset ( info, 0, sizeof ( struct fstioc_info ));
+
+        i = port->index;
+        info->nports = card->nports;
+        info->type   = card->type;
+        info->state  = card->state;
+        info->proto  = port->proto;
+        info->index  = i;
+#if FST_DEBUG
+        info->debug  = fst_debug_mask;
+#endif
+
+        /* Only mark information as valid if card is running.
+         * Copy the data anyway in case it is useful for diagnostics
+         */
+        info->valid
+                = (( card->state == FST_RUNNING ) ? FSTVAL_ALL : FSTVAL_CARD )
+#if FST_DEBUG
+                | FSTVAL_DEBUG
+#endif
+                ;
+
+        info->lineInterface = FST_RDW ( card, portConfig[i].lineInterface );
+        info->internalClock = FST_RDB ( card, portConfig[i].internalClock );
+        info->lineSpeed     = FST_RDL ( card, portConfig[i].lineSpeed );
+        info->v24IpSts      = FST_RDL ( card, v24IpSts[i] );
+        info->v24OpSts      = FST_RDL ( card, v24OpSts[i] );
+        info->clockStatus   = FST_RDW ( card, clockStatus[i] );
+        info->cableStatus   = FST_RDW ( card, cableStatus );
+        info->cardMode      = FST_RDW ( card, cardMode );
+        info->smcFirmwareVersion  = FST_RDL ( card, smcFirmwareVersion );
+}
+
+
+static int
+fst_ioctl ( struct device *dev, struct ifreq *ifr, int cmd )
+{
+        struct fst_card_info *card;
+        struct fst_port_info *port;
+        struct fstioc_write wrthdr;
+        struct fstioc_info info;
+        unsigned long flags;
+
+        dbg ( DBG_IOCTL,"ioctl: %x, %p\n", cmd, ifr->ifr_data );
+
+        port = dev->priv;
+        card = port->card;
+
+        if ( !capable ( CAP_NET_ADMIN ))
+                return -EPERM;
+
+        switch ( cmd )
+        {
+        case FSTCPURESET:
+                fst_cpureset ( card );
+                card->state = FST_RESET;
+                return 0;
+
+        case FSTCPURELEASE:
+                fst_cpurelease ( card );
+                card->state = FST_STARTING;
+                return 0;
+
+        case FSTWRITE:                  /* Code write (download) */
+
+                /* First copy in the header with the length and offset of data
+                 * to write
+                 */
+                if ( ifr->ifr_data == NULL )
+                {
+                        return -EINVAL;
+                }
+                if ( copy_from_user ( &wrthdr, ifr->ifr_data,
+                                        sizeof ( struct fstioc_write )))
+                {
+                        return -EFAULT;
+                }
+
+                /* Sanity check the parameters. We don't support partial writes
+                 * when going over the top
+                 */
+                if ( wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE
+                                || wrthdr.size + wrthdr.offset > FST_MEMSIZE )
+                {
+                        return -ENXIO;
+                }
+
+                /* Now copy the data to the card.
+                 * This will probably break on some architectures.
+                 * I'll fix it when I have something to test on.
+                 */
+                if ( copy_from_user ( card->mem + wrthdr.offset,
+                                ifr->ifr_data + sizeof ( struct fstioc_write ),
+                                wrthdr.size ))
+                {
+                        return -EFAULT;
+                }
+
+                /* Writes to the memory of a card in the reset state constitute
+                 * a download
+                 */
+                if ( card->state == FST_RESET )
+                {
+                        card->state = FST_DOWNLOAD;
+                }
+                return 0;
+
+        case FSTGETCONF:
+
+                /* If card has just been started check the shared memory config
+                 * version and marker
+                 */
+                if ( card->state == FST_STARTING )
+                {
+                        check_started_ok ( card );
+
+                        /* If everything checked out enable card interrupts */
+                        if ( card->state == FST_RUNNING )
+                        {
+                                spin_lock_irqsave ( &card->card_lock, flags );
+                                fst_clear_intr ( card );
+                                FST_WRB ( card, interruptHandshake, 0xEE );
+                                spin_unlock_irqrestore ( &card->card_lock,
+                                                                flags );
+                        }
+                }
+
+                if ( ifr->ifr_data == NULL )
+                {
+                        return -EINVAL;
+                }
+
+                gather_conf_info ( card, port, &info );
+
+                if ( copy_to_user ( ifr->ifr_data, &info, sizeof ( info )))
+                {
+                        return -EFAULT;
+                }
+                return 0;
+
+        case FSTSETCONF:
+
+                if ( copy_from_user ( &info,  ifr->ifr_data, sizeof ( info )))
+                {
+                        return -EFAULT;
+                }
+
+                return set_conf_from_info ( card, port, &info );
+
+        default:
+                /* Not one of ours. Pass it through to sPPP package */
+                if ( port->proto == FST_HDLC || port->proto == FST_PPP )
+                        return sppp_do_ioctl ( dev, ifr, cmd );
+                else
+                        return -EINVAL;
+        }
+}
+
+
+static void
+fst_openport ( struct fst_port_info *port )
+{
+        int signals;
+
+        /* Only init things if card is actually running. This allows open to
+         * succeed for downloads etc.
+         */
+        if ( port->card->state == FST_RUNNING )
+        {
+                if ( port->run )
+                {
+                        dbg ( DBG_OPEN,"open: found port already running\n");
+
+                        fst_issue_cmd ( port, STOPPORT );
+                        port->run = 0;
+                }
+
+                fst_rx_config ( port );
+                fst_tx_config ( port );
+                fst_op_raise ( port, OPSTS_RTS | OPSTS_DTR );
+
+                fst_issue_cmd ( port, STARTPORT );
+                port->run = 1;
+
+                signals = FST_RDL ( port->card, v24DebouncedSts[port->index]);
+                if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE
+                                                      : IPSTS_DCD ))
+                        netif_carrier_on ( port->dev );
+                else
+                        netif_carrier_off ( port->dev );
+        }
+}
+
+static void
+fst_closeport ( struct fst_port_info *port )
+{
+        if ( port->card->state == FST_RUNNING )
+        {
+                if ( port->run )
+                {
+                        port->run = 0;
+                        fst_op_lower ( port, OPSTS_RTS | OPSTS_DTR );
+
+                        fst_issue_cmd ( port, STOPPORT );
+                }
+                else
+                {
+                        dbg ( DBG_OPEN,"close: port not running\n");
+                }
+        }
+}
+
+
+static int
+fst_open ( struct device *dev )
+{
+        struct fst_card_info *card;
+        struct fst_port_info *port;
+        int orig_mtu;
+        int err;
+
+        MOD_INC_USE_COUNT;
+
+        port = dev->priv;
+        card = port->card;
+
+        switch ( port->proto )
+        {
+        case FST_HDLC:
+        case FST_PPP:
+                orig_mtu = dev->mtu;
+
+                /* Attach to sync PPP module */
+                port->pppdev.dev = dev;
+                sppp_attach ( &port->pppdev );
+
+                if ( orig_mtu < dev->mtu )
+                        dev->change_mtu ( dev, orig_mtu );
+
+                /* Claw back the ioctl routine. We promise to be good and call
+                 * the sync PPP routines once we've eliminated our functions.
+                 */
+                dev->do_ioctl = fst_ioctl;
+
+                err = sppp_do_ioctl ( dev, NULL, port->proto == FST_HDLC
+                                                ? SPPPIOCCISCO : SPPPIOCPPP );
+                if ( err )
+                {
+                        sppp_detach ( dev );
+                        MOD_DEC_USE_COUNT;
+                        return err;
+                }
+
+                err = sppp_open ( dev );
+                if ( err )
+                {
+                        sppp_detach ( dev );
+                        MOD_DEC_USE_COUNT;
+                        return err;
+                }
+                break;
+
+        case FST_MONITOR:
+        case FST_RAW:
+                break;
+
+        default:
+                dbg ( DBG_OPEN,"open: Unknown proto %d\n", port->proto );
+                break;
+        }
+
+        fst_openport ( port );
+
+        netif_wake_queue ( dev );
+        return 0;
+}
+
+static int
+fst_close ( struct device *dev )
+{
+        struct fst_port_info *port;
+
+        port = dev->priv;
+
+        dev->start = 0;
+        netif_stop_queue ( dev );
+        switch ( port->proto )
+        {
+        case FST_HDLC:
+        case FST_PPP:
+                sppp_close ( dev );
+                sppp_detach ( dev );
+                break;
+
+        case FST_MONITOR:
+        case FST_RAW:
+                break;
+
+        default:
+                dbg ( DBG_OPEN,"close: Unknown proto %d\n", port->proto );
+                break;
+        }
+
+        fst_closeport ( port );
+
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+
+#if 0
+static void
+fst_tx_timeout ( struct device *dev )
+{
+        struct fst_port_info *port;
+
+        dbg ( DBG_INTR | DBG_TX,"tx_timeout\n");
+
+        port = dev->priv;
+
+        port->stats.tx_errors++;
+        port->stats.tx_aborted_errors++;
+
+        if ( port->txcnt > 0 )
+                fst_issue_cmd ( port, ABORTTX );
+
+        dev->trans_start = jiffies;
+        netif_wake_queue ( dev );
+}
+#endif
+
+
+static int
+fst_start_xmit ( struct sk_buff *skb, struct device *dev )
+{
+        struct fst_card_info *card;
+        struct fst_port_info *port;
+        unsigned char dmabits;
+        unsigned long flags;
+        int pi;
+        int txp;
+
+        port = dev->priv;
+        card = port->card;
+
+        /* Drop packet if in monitor (rx only) mode */
+        if ( port->proto == FST_MONITOR )
+        {
+                dev_kfree_skb ( skb );
+                return 0;
+        }
+
+        /* Drop packet with error if we don't have carrier */
+        if ( ! netif_carrier_ok ( dev ))
+        {
+                dev_kfree_skb ( skb );
+                port->stats.tx_errors++;
+                port->stats.tx_carrier_errors++;
+                return 0;
+        }
+
+        /* Drop it if it's too big! MTU failure ? */
+        if ( skb->len > LEN_TX_BUFFER )
+        {
+                dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len,
+                                                LEN_TX_BUFFER );
+                dev_kfree_skb ( skb );
+                port->stats.tx_errors++;
+                return 0;
+        }
+
+        /* Check we have a buffer */
+        pi = port->index;
+        spin_lock_irqsave ( &card->card_lock, flags );
+        txp = port->txpos;
+        dmabits = FST_RDB ( card, txDescrRing[pi][txp].bits );
+        if ( dmabits & DMA_OWN )
+        {
+                spin_unlock_irqrestore ( &card->card_lock, flags );
+                dbg ( DBG_TX,"Out of Tx buffers\n");
+                dev_kfree_skb ( skb );
+                port->stats.tx_errors++;
+                return 0;
+        }
+        if ( ++port->txpos >= NUM_TX_BUFFER )
+                port->txpos = 0;
+
+        if ( ++port->txcnt >= NUM_TX_BUFFER )
+                netif_stop_queue ( dev );
+
+        /* Release the card lock before we copy the data as we now have
+         * exclusive access to the buffer.
+         */
+        spin_unlock_irqrestore ( &card->card_lock, flags );
+
+        /* Enqueue the packet */
+        memcpy_toio ( card->mem + BUF_OFFSET ( txBuffer[pi][txp][0]),
+                                                skb->data, skb->len );
+        FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len ));
+        FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP );
+
+        port->stats.tx_packets++;
+        port->stats.tx_bytes += skb->len;
+
+        dev_kfree_skb ( skb );
+
+        dev->trans_start = jiffies;
+        return 0;
+}
+
+
+static struct net_device_stats *
+fst_get_stats ( struct device *dev )
+{
+        struct fst_port_info *port;
+
+        if (( port = dev->priv ) != NULL )
+                return &port->stats;
+        else
+                return NULL;
+}
+
+
+/*
+ *      Card setup having checked hardware resources.
+ *      Should be pretty bizarre if we get an error here (kernel memory
+ *      exhaustion is one possibility). If we do see a problem we report it
+ *      via a printk and leave the corresponding interface and all that follow
+ *      disabled.
+ */
+static char *type_strings[] = {
+        "no hardware",                  /* Should never be seen */
+        "FarSync T2P",
+        "FarSync T4P"
+};
+
+static void __init
+fst_init_card ( struct fst_card_info *card )
+{
+        int i;
+        int err;
+        struct device *dev;
+#ifndef MODULE
+        static int init_syncppp = 0;
+
+        if ( ! init_syncppp )
+        {
+                sync_ppp_init();
+                init_syncppp = 1;
+        }
+#endif
+
+        /* We're working on a number of ports based on the card ID. If the
+         * firmware detects something different later (should never happen)
+         * we'll have to revise it in some way then.
+         */
+        for ( i = 0 ; i < card->nports ; i++ )
+        {
+                card->ports[i].if_ptr = &card->ports[i].pppdev;
+                card->ports[i].card   = card;
+                card->ports[i].index  = i;
+                card->ports[i].proto  = FST_HDLC;
+                card->ports[i].run    = 0;
+
+                dev = kmalloc ( sizeof ( struct device ), GFP_KERNEL );
+                if ( dev == NULL )
+                {
+                        printk_err ("Cannot allocate net device for port %d\n",
+                                        i );
+                        /* No point going any further */
+                        card->nports = i;
+                        break;
+                }
+                memset ( dev, 0, sizeof ( struct device ));
+                card->ports[i].dev = dev;
+
+                dev->name = &card->ports[i].name[0];
+                if ( dev_alloc_name ( dev, FST_NDEV_NAME "%d") < 0 )
+                {
+                        printk_err ("Cannot allocate i/f name for port %d\n",
+                                        i );
+                        kfree ( dev );
+                        card->nports = i;
+                        break;
+                }
+
+                /* Fill in remainder of the net device info */
+                                /* Since this is a PCI setup this is purely
+                                 * informational. Give them the buffer addresses
+                                 * and basic card I/O.
+                                 */
+                dev->mem_start   = card->phys_mem
+                                 + BUF_OFFSET ( txBuffer[i][0][0]);
+                dev->mem_end     = card->phys_mem
+                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]);
+                dev->rmem_start  = card->phys_mem
+                                 + BUF_OFFSET ( rxBuffer[i][0][0]);
+                dev->rmem_end    = card->phys_mem
+                                 + BUF_OFFSET ( rxBuffer[i][NUM_RX_BUFFER][0]);
+                dev->base_addr   = card->pci_conf;
+                dev->irq         = card->irq;
+
+                dev->get_stats          = fst_get_stats;
+                dev->mtu                = FST_DEF_MTU;
+                dev->change_mtu         = fst_change_mtu;
+                dev->priv               = &card->ports[i];
+                dev->tx_queue_len       = FST_TX_QUEUE_LEN;
+                dev->type               = ARPHRD_MYTYPE;
+                dev->addr_len           = 0;
+                dev->open               = fst_open;
+                dev->stop               = fst_close;
+                dev->hard_start_xmit    = fst_start_xmit;
+                dev->do_ioctl           = fst_ioctl;
+#if 0
+                dev->watchdog_timeo     = FST_TX_TIMEOUT;
+                dev->tx_timeout         = fst_tx_timeout;
+#endif
+                dev->flags              = IFF_POINTOPOINT|IFF_NOARP;
+
+                dev_init_buffers ( dev );
+
+                if (( err = register_netdev ( dev )) < 0 )
+                {
+                        printk_err ("Cannot register %s (errno %d)\n",
+                                        dev->name, -err );
+                        kfree ( dev );
+                        card->nports = i;
+                        break;
+                }
+        }
+
+        spin_lock_init ( &card->card_lock );
+
+        printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n",
+                        card->ports[0].dev->name,
+                        card->ports[card->nports-1].dev->name,
+                        type_strings[card->type], card->irq, card->nports );
+}
+
+
+/*
+ *      Initialise card when detected.
+ *      Returns 0 to indicate success, or errno otherwise.
+ */
+static int __init
+fst_add_one ( struct pci_dev *pdev, int card_index )
+{
+        static int firsttime_done = 0;
+        struct fst_card_info *card;
+        int err = 0;
+
+        if ( ! firsttime_done )
+        {
+                printk ( KERN_INFO "FarSync X21 driver " FST_USER_VERSION
+                                " (c) 2001 FarSite Communications Ltd.\n");
+                firsttime_done = 1;
+        }
+
+        /* Allocate driver private data */
+        card = kmalloc ( sizeof ( struct fst_card_info ),  GFP_KERNEL);
+        if (card == NULL)
+        {
+                printk_err ("FarSync card found but insufficient memory for"
+                                " driver storage\n");
+                return -ENOMEM;
+        }
+        memset ( card, 0, sizeof ( struct fst_card_info ));
+
+        /* Record info we need*/
+        card->irq         = pdev->irq;
+        card->pci_conf    = pci_resource_start ( pdev, 1 );
+        card->phys_mem    = pci_resource_start ( pdev, 2 );
+        card->phys_ctlmem = pci_resource_start ( pdev, 3 );
+
+        if ( pdev->device == T2P_PCI_DEVICE_ID )
+        {
+                card->type   = FST_TYPE_T2P;
+                card->nports = 2;
+        }
+        else
+        {
+                card->type   = FST_TYPE_T4P;
+                card->nports = 4;
+        }
+
+        card->state       = FST_UNINIT;
+
+        dbg ( DBG_PCI,"type %d nports %d irq %d\n", card->type,
+                        card->nports, card->irq );
+        dbg ( DBG_PCI,"conf %04x mem %08x ctlmem %08x\n",
+                        card->pci_conf, card->phys_mem, card->phys_ctlmem );
+
+        /* Check we can get access to the I/O area */
+        if (( err = check_region ( card->pci_conf, 0x80 )) < 0 )
+        {
+                printk_err ("Unable to get config I/O @ 0x%04X\n",
+                                                card->pci_conf );
+                goto error_free_card;
+        }
+        request_region ( card->pci_conf, 0x80,"PLX config regs");
+#if 0
+        if ( ! request_mem_region ( card->phys_mem, FST_MEMSIZE,"Shared RAM"))
+        {
+                printk_err ("Unable to get main memory @ 0x%08X\n",
+                                                card->phys_mem );
+                err = -ENODEV;
+                goto error_release_io;
+        }
+        if ( ! request_mem_region ( card->phys_ctlmem, 0x10,"Control memory"))
+        {
+                printk_err ("Unable to get control memory @ 0x%08X\n",
+                                                card->phys_ctlmem );
+                err = -ENODEV;
+                goto error_release_mem;
+        }
+
+        /* Try to enable the device */
+        if (( err = pci_enable_device ( pdev )) != 0 )
+        {
+                printk_err ("Failed to enable card. Err %d\n", -err );
+                goto error_release_ctlmem;
+        }
+#endif
+
+        /* Get virtual addresses of memory regions */
+        if (( card->mem = ioremap ( card->phys_mem, FST_MEMSIZE )) == NULL )
+        {
+                printk_err ("Physical memory remap failed\n");
+                err = -ENODEV;
+                goto error_release_ctlmem;
+        }
+        if (( card->ctlmem = ioremap ( card->phys_ctlmem, 0x10 )) == NULL )
+        {
+                printk_err ("Control memory remap failed\n");
+                err = -ENODEV;
+                goto error_unmap_mem;
+        }
+        dbg ( DBG_PCI,"kernel mem %p, ctlmem %p\n", card->mem, card->ctlmem);
+
+        /* Reset the card's processor */
+        fst_cpureset ( card );
+        card->state = FST_RESET;
+
+        /* Register the interrupt handler */
+        if ( request_irq ( card->irq, fst_intr, SA_SHIRQ, FST_DEV_NAME, card ))
+        {
+
+                printk_err ("Unable to register interrupt %d\n", card->irq );
+                err = -ENODEV;
+                goto error_unmap_ctlmem;
+        }
+
+        /* Record driver data for later use */
+        fst_card_info[card_index] = card;
+
+        /* Remainder of card setup */
+        fst_init_card ( card );
+
+        return 0;                       /* Success */
+
+
+                                        /* Failure. Release resources */
+error_unmap_ctlmem:
+        iounmap ( card->ctlmem );
+
+error_unmap_mem:
+        iounmap ( card->mem );
+
+error_release_ctlmem:
+#if 0
+        release_mem_region ( card->phys_ctlmem, 0x10 );
+
+error_release_mem:
+        release_mem_region ( card->phys_mem, FST_MEMSIZE );
+
+error_release_io:
+#endif
+        release_region ( card->pci_conf, 0x80 );
+
+error_free_card:
+        kfree ( card );
+        return err;
+}
+
+
+int __init
+fst_init(void)
+{
+        struct pci_dev *pdev;
+        int err;
+
+        err = 0;
+
+        /* Minor problem with 2.4 compatability here. pci_register_driver()
+         * searches the device list once looking for and initialising cards
+         * with any matching ID from a table. Under 2.2 we would normally use
+         * pci_find_device() to search the list for each ID in turn. This would
+         * give us a different sequence of cards under the different versions
+         * which would be confusing for the user. The following code is an
+         * unwinding of pci_find_device() to better match the 2.4 sequence.
+         */
+        for ( pdev = pci_devices ; pdev != NULL ; pdev = pdev->next )
+        {
+                if ( pdev->vendor == FSC_PCI_VENDOR_ID
+                        && ( pdev->device == T2P_PCI_DEVICE_ID
+                                || pdev->device == T4P_PCI_DEVICE_ID ))
+                {
+                        err = fst_add_one ( pdev, fst_ncards );
+			fst_ncards++;
+                }
+        }
+
+        return err;
+}
+
+
+#ifdef MODULE
+/*
+ *      Cleanup and close down a card
+ */
+static void
+fst_remove_one ( struct fst_card_info *card )
+{
+        int i;
+
+        for ( i = 0 ; i < card->nports ; i++ )
+        {
+                unregister_netdev ( card->ports[i].dev );
+                kfree ( card->ports[i].dev );
+        }
+
+        fst_disable_intr ( card );
+        free_irq ( card->irq, card );
+
+        iounmap ( card->ctlmem );
+        iounmap ( card->mem );
+
+#if 0
+        release_mem_region ( card->phys_ctlmem, 0x10 );
+        release_mem_region ( card->phys_mem, FST_MEMSIZE );
+#endif
+        release_region ( card->pci_conf, 0x80 );
+
+        kfree ( card );
+}
+
+
+void
+cleanup_module ( void )
+{
+        while ( fst_ncards > 0 )
+        {
+                fst_remove_one ( fst_card_info[fst_ncards-1] );
+                fst_card_info[--fst_ncards] = NULL;
+        }
+}
+
+int
+init_module ( void )
+{
+        return fst_init ();
+}
+
+#endif  /* MODULE */
+
+/* End $Id: farsync.c,v 1.10 2002/01/03 16:49:54 kevinc Exp $ */
diff -urN linux-2.2.21-pre4/drivers/net/farsync.h linux-2.2.21-rc1/drivers/net/farsync.h
--- linux-2.2.21-pre4/drivers/net/farsync.h	Wed Dec 31 16:00:00 1969
+++ linux-2.2.21-rc1/drivers/net/farsync.h	Tue Mar 12 04:35:09 2002
@@ -0,0 +1,255 @@
+/*
+ *      FarSync X21 driver for Linux
+ *
+ *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
+ *
+ *      Copyright (C) 2001 FarSite Communications Ltd.
+ *      www.farsite.co.uk
+ *
+ *      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.
+ *
+ *      File:   farsync.h
+ *      Author: R.J.Dunlop      <bob.dunlop@farsite.co.uk>
+ *
+ *      For the most part this file only contains structures and information
+ *      that is visible to applications outside the driver. Shared memory
+ *      layout etc is internal to the driver and described within farsync.c.
+ *      Overlap exists in that the values used for some fields within the
+ *      ioctl interface extend into the cards firmware interface so values in
+ *      this file may not be changed arbitrarily.
+ */
+/*      Revision History
+ *      $Log: farsync.h,v $
+ *      Revision 1.9  2001/07/03 15:55:54  rjd
+ *      First non-beta version.
+ *      Started preparations for the generic-HDLC version.
+ *
+ *      Revision 1.8  2001/05/29 09:05:27  rjd
+ *      Improved startup carrier processing.
+ *      Removed interrupt loop optimistation as never used.
+ *      Added support of 2.4.5 kernel.
+ *
+ *      Revision 1.7  2001/05/10 08:27:43  rjd
+ *      Added configurable MTU support and RH7.1 installation patch
+ *
+ *      Revision 1.6  2001/05/02 09:30:22  rjd
+ *      Reboot with noisy lines causing Opps fixed.
+ *      Tx buffer reordering problem fixed.
+ *      Port configuration code simplified.
+ *
+ *      Revision 1.5  2001/05/01 09:59:43  rjd
+ *      Disable driver debug
+ *
+ *      Revision 1.4  2001/04/30 06:25:50  rjd
+ *      Correct CVS Log marker. Strip spurious white space.
+ *
+ */
+
+/*      What's in a name
+ *
+ *      The project name for this driver is Oscar. The driver is intended to be
+ *      used with the FarSite T-Series cards (T2P & T4P) running in the high
+ *      speed frame shifter mode. This is sometimes referred to as X.21 mode
+ *      which is a complete misnomer as the card continues to support V.24 and
+ *      V.35 as well as X.21.
+ *
+ *      A short common prefix is useful for routines within the driver to avoid
+ *      conflict with other similar drivers and I chosen to use "fst_" for this
+ *      purpose (FarSite T-series).
+ *
+ *      Finally the device driver needs a short network interface name. Since
+ *      "hdlc" is already in use I've chosen the even less informative "sync"
+ *      for the present.
+ */
+#define FST_NAME                "fst"           /* In debug/info etc */
+#define FST_NDEV_NAME           "sync"          /* For net interface */
+#define FST_DEV_NAME            "farsync"       /* For misc interfaces */
+
+
+/*      User version number
+ *
+ *      This version number is incremented with each official release of the
+ *      package and is a simplified number for normal user reference.
+ *      Individual files are tracked by the version control system and may
+ *      have individual versions (or IDs) that move much faster than the
+ *      the release version as individual updates are tracked.
+ */
+#define FST_USER_VERSION        "0.09"
+
+
+/*      Ioctl call command values
+ *
+ *      The first three private ioctls are used by the sync-PPP module,
+ *      allowing a little room for expansion we start our numbering at 10.
+ */
+#define FSTWRITE        (SIOCDEVPRIVATE+10)
+#define FSTCPURESET     (SIOCDEVPRIVATE+11)
+#define FSTCPURELEASE   (SIOCDEVPRIVATE+12)
+#define FSTGETCONF      (SIOCDEVPRIVATE+13)
+#define FSTSETCONF      (SIOCDEVPRIVATE+14)
+
+
+/*      FSTWRITE
+ *
+ *      Used to write a block of data (firmware etc) before the card is running
+ */
+struct fstioc_write {
+        unsigned int  size;
+        unsigned int  offset;
+        unsigned char data[0];
+};
+
+
+/*      FSTCPURESET and FSTCPURELEASE
+ *
+ *      These take no additional data.
+ *      FSTCPURESET forces the cards CPU into a reset state and holds it there.
+ *      FSTCPURELEASE releases the CPU from this reset state allowing it to run,
+ *      the reset vector should be setup before this ioctl is run.
+ */
+
+/*      FSTGETCONF and FSTSETCONF
+ *
+ *      Get and set a card/ports configuration.
+ *      In order to allow selective setting of items and for the kernel to
+ *      indicate a partial status response the first field "valid" is a bitmask
+ *      indicating which other fields in the structure are valid.
+ *      Many of the field names in this structure match those used in the
+ *      firmware shared memory configuration interface and come originally from
+ *      the NT header file Smc.h
+ *
+ *      When used with FSTGETCONF this structure should be zeroed before use.
+ *      This is to allow for possible future expansion when some of the fields
+ *      might be used to indicate a different (expanded) structure.
+ */
+struct fstioc_info {
+        unsigned int   valid;           /* Bits of structure that are valid */
+        unsigned int   nports;          /* Number of serial ports */
+        unsigned int   type;            /* Type index of card */
+        unsigned int   state;           /* State of card */
+        unsigned int   index;           /* Index of port ioctl was issued on */
+        unsigned int   smcFirmwareVersion;
+        unsigned short lineInterface;   /* Physical interface type */
+        unsigned char  proto;           /* Line protocol */
+        unsigned char  internalClock;   /* 1 => internal clock, 0 => external */
+        unsigned int   lineSpeed;       /* Speed in bps */
+        unsigned int   v24IpSts;        /* V.24 control input status */
+        unsigned int   v24OpSts;        /* V.24 control output status */
+        unsigned short clockStatus;     /* lsb: 0=> present, 1=> absent */
+        unsigned short cableStatus;     /* lsb: 0=> present, 1=> absent */
+        unsigned short cardMode;        /* lsb: LED id mode */
+        unsigned short debug;           /* Debug flags */
+};
+
+/* "valid" bitmask */
+#define FSTVAL_NONE     0x00000000      /* Nothing valid (firmware not running).
+                                         * Slight misnomer. In fact nports,
+                                         * type, state and index will be set
+                                         * based on hardware detected.
+                                         */
+#define FSTVAL_OMODEM   0x0000001F      /* First 5 bits correspond to the
+                                         * output status bits defined for
+                                         * v24OpSts
+                                         */
+#define FSTVAL_SPEED    0x00000020      /* internalClock, lineSpeed, clockStatus
+                                         */
+#define FSTVAL_CABLE    0x00000040      /* lineInterface, cableStatus */
+#define FSTVAL_IMODEM   0x00000080      /* v24IpSts */
+#define FSTVAL_CARD     0x00000100      /* nports, type, state, index,
+                                         * smcFirmwareVersion
+                                         */
+#define FSTVAL_PROTO    0x00000200      /* proto */
+#define FSTVAL_MODE     0x00000400      /* cardMode */
+#define FSTVAL_DEBUG    0x80000000      /* debug */
+#define FSTVAL_ALL      0x000007FF      /* Note: does not include DEBUG flag */
+
+/* "type" */
+#define FST_TYPE_NONE   0               /* Probably should never happen */
+#define FST_TYPE_T2P    1               /* T2P X21 2 port card */
+#define FST_TYPE_T4P    2               /* T4P X21 4 port card */
+
+/* "state" */
+#define FST_UNINIT      0               /* Raw uninitialised state following
+                                         * system startup */
+#define FST_RESET       1               /* Processor held in reset state */
+#define FST_DOWNLOAD    2               /* Card being downloaded */
+#define FST_STARTING    3               /* Released following download */
+#define FST_RUNNING     4               /* Processor running */
+#define FST_BADVERSION  5               /* Bad shared memory version detected */
+#define FST_HALTED      6               /* Processor flagged a halt */
+#define FST_IFAILED     7               /* Firmware issued initialisation failed
+                                         * interrupt
+                                         */
+/* "lineInterface" */
+#define V24             1
+#define X21             2
+#define V35             3
+
+/* "proto" */
+#define FST_HDLC        1               /* Cisco compatible HDLC */
+#define FST_PPP         2               /* Sync PPP */
+#define FST_MONITOR     3               /* Monitor only (raw packet reception) */
+#define FST_RAW         4               /* Two way raw packets */
+#define FST_GEN_HDLC    5               /* Using "Generic HDLC" module */
+
+/* "internalClock" */
+#define INTCLK          1
+#define EXTCLK          0
+
+/* "v24IpSts" bitmask */
+#define IPSTS_CTS       0x00000001      /* Clear To Send (Indicate for X.21) */
+#define IPSTS_INDICATE  IPSTS_CTS
+#define IPSTS_DSR       0x00000002      /* Data Set Ready (T2P Port A) */
+#define IPSTS_DCD       0x00000004      /* Data Carrier Detect */
+#define IPSTS_RI        0x00000008      /* Ring Indicator (T2P Port A) */
+#define IPSTS_TMI       0x00000010      /* Test Mode Indicator (Not Supported)*/
+
+/* "v24OpSts" bitmask */
+#define OPSTS_RTS       0x00000001      /* Request To Send (Control for X.21) */
+#define OPSTS_CONTROL   OPSTS_RTS
+#define OPSTS_DTR       0x00000002      /* Data Terminal Ready */
+#define OPSTS_DSRS      0x00000004      /* Data Signalling Rate Select (Not
+                                         * Supported) */
+#define OPSTS_SS        0x00000008      /* Select Standby (Not Supported) */
+#define OPSTS_LL        0x00000010      /* Maintenance Test (Not Supported) */
+
+/* "cardMode" bitmask */
+#define CARD_MODE_IDENTIFY      0x0001
+
+
+/*      Debug support
+ *
+ *      These should only be enabled for development kernels, production code
+ *      should define FST_DEBUG=0 in order to exclude the code.
+ *      Setting FST_DEBUG=1 will include all the debug code but in a disabled
+ *      state, use the FSTSETCONF ioctl to enable specific debug actions, or
+ *      FST_DEBUG can be set to prime the debug selection.
+ */
+#define FST_DEBUG       0x0000
+#if FST_DEBUG
+
+extern int fst_debug_mask;              /* Bit mask of actions to debug, bits
+                                         * listed below. Note: Bit 0 is used
+                                         * to trigger the inclusion of this
+                                         * code, without enabling any actions.
+                                         */
+#define DBG_INIT        0x0002          /* Card detection and initialisation */
+#define DBG_OPEN        0x0004          /* Open and close sequences */
+#define DBG_PCI         0x0008          /* PCI config operations */
+#define DBG_IOCTL       0x0010          /* Ioctls and other config */
+#define DBG_INTR        0x0020          /* Interrupt routines (be careful) */
+#define DBG_TX          0x0040          /* Packet transmission */
+#define DBG_RX          0x0080          /* Packet reception */
+#define DBG_CMD         0x0100          /* Port command issuing */
+
+#define DBG_ASS         0xFFFF          /* Assert like statements. Code that
+                                         * should never be reached, if you see
+                                         * one of these then I've been an ass
+                                         */
+#endif  /* FST_DEBUG */
+
+
+/* End $Id: farsync.h,v 1.9 2001/07/03 15:55:54 rjd Exp $ */
diff -urN linux-2.2.21-pre4/drivers/net/zlib.c linux-2.2.21-rc1/drivers/net/zlib.c
--- linux-2.2.21-pre4/drivers/net/zlib.c	Sun Mar 25 08:31:20 2001
+++ linux-2.2.21-rc1/drivers/net/zlib.c	Tue Mar 12 04:35:09 2002
@@ -3860,10 +3860,11 @@
                              &s->sub.trees.tb, z);
       if (t != Z_OK)
       {
-        ZFREE(z, s->sub.trees.blens);
         r = t;
-        if (r == Z_DATA_ERROR)
+        if (r == Z_DATA_ERROR) {
           s->mode = BADB;
+          ZFREE(z, s->sub.trees.blens);
+        }
         LEAVE
       }
       s->sub.trees.index = 0;
@@ -3928,14 +3929,16 @@
 #endif
         t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
                                   s->sub.trees.blens, &bl, &bd, &tl, &td, z);
-        ZFREE(z, s->sub.trees.blens);
         if (t != Z_OK)
         {
-          if (t == (uInt)Z_DATA_ERROR)
+          if (t == (uInt)Z_DATA_ERROR) {
             s->mode = BADB;
+            ZFREE(z, s->sub.trees.blens);
+          }
           r = t;
           LEAVE
         }
+        ZFREE(z, s->sub.trees.blens);
         Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
               inflate_hufts, sizeof(inflate_huft)));
         if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
diff -urN linux-2.2.21-pre4/drivers/pci/oldproc.c linux-2.2.21-rc1/drivers/pci/oldproc.c
--- linux-2.2.21-pre4/drivers/pci/oldproc.c	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/drivers/pci/oldproc.c	Tue Mar 12 04:35:09 2002
@@ -491,6 +491,8 @@
 	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
 	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon"),
 	DEVICE( TIMEDIA,	TIMEDIA_4008A, "Noname 4008A"),
+	DEVICE( FARSITE,	FARSYNC_T2P,	"FarSync T2P"),
+	DEVICE( FARSITE,	FARSYNC_T4P,	"FarSync T4P"),
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
@@ -857,6 +859,7 @@
 	      case PCI_VENDOR_ID_NVIDIA_SGS:	return "NVidia/SGS Thomson";
 	      case PCI_VENDOR_ID_CBOARDS:	return "ComputerBoards";
 	      case PCI_VENDOR_ID_TIMEDIA:	return "Timedia Technology";
+	      case PCI_VENDOR_ID_FARSITE:	return "FarSite Communications";
 	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
 	      case PCI_VENDOR_ID_COMPUTONE:	return "Computone Corporation";
 	      case PCI_VENDOR_ID_TEKRAM:	return "Tekram";
diff -urN linux-2.2.21-pre4/include/linux/fb.h linux-2.2.21-rc1/include/linux/fb.h
--- linux-2.2.21-pre4/include/linux/fb.h	Sun Mar 25 08:31:04 2001
+++ linux-2.2.21-rc1/include/linux/fb.h	Tue Mar 12 04:35:09 2002
@@ -404,7 +404,7 @@
 };
 
 
-/* drivers/char/fbmem.c */
+/* drivers/video/fbmem.c */
 extern int register_framebuffer(struct fb_info *fb_info);
 extern int unregister_framebuffer(const struct fb_info *fb_info);
 extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
diff -urN linux-2.2.21-pre4/include/linux/module.h linux-2.2.21-rc1/include/linux/module.h
--- linux-2.2.21-pre4/include/linux/module.h	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/include/linux/module.h	Tue Mar 12 04:35:09 2002
@@ -181,6 +181,7 @@
 	s	string
 */
 
+/* Dummy macro for 2.2/2.4 compatibility */
 #define MODULE_LICENSE(var)
 
 #define MODULE_PARM(var,type)			\
@@ -221,6 +222,7 @@
 #define MODULE_AUTHOR(name)
 #define MODULE_DESCRIPTION(desc)
 #define MODULE_SUPPORTED_DEVICE(name)
+#define MODULE_LICENSE(var)
 #define MODULE_PARM(var,type)
 #define MODULE_PARM_DESC(var,desc)
 #define THIS_MODULE		NULL
diff -urN linux-2.2.21-pre4/include/linux/pci.h linux-2.2.21-rc1/include/linux/pci.h
--- linux-2.2.21-pre4/include/linux/pci.h	Tue Mar 12 04:35:07 2002
+++ linux-2.2.21-rc1/include/linux/pci.h	Tue Mar 12 04:35:09 2002
@@ -1209,6 +1209,10 @@
 #define PCI_VENDOR_ID_ZOLTRIX		0x15b0
 #define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2BD0
 
+#define PCI_VENDOR_ID_FARSITE		0x1619
+#define PCI_DEVICE_ID_FARSYNC_T2P	0x0400
+#define PCI_DEVICE_ID_FARSYNC_T4P	0x0440
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
diff -urN linux-2.2.21-pre4/net/core/dev.c linux-2.2.21-rc1/net/core/dev.c
--- linux-2.2.21-pre4/net/core/dev.c	Fri Nov  2 08:39:16 2001
+++ linux-2.2.21-rc1/net/core/dev.c	Tue Mar 12 04:35:09 2002
@@ -100,6 +100,7 @@
 extern void n2_init(void);
 extern void c101_init(void);
 extern int wanxl_init(void);
+extern int fst_init(void);
 extern int cpc_init(void);
 extern void sync_ppp_init(void);
 
@@ -2099,6 +2100,9 @@
 #ifdef CONFIG_WANXL
 	wanxl_init();
 #endif
+#ifdef CONFIG_FARSYNC
+	fst_init();
+#endif
 #ifdef CONFIG_XPEED
 	xpdsl_init();
 #endif
