## Automatically generated incremental diff
## From:   linux-2.2.19-pre13
## To:     linux-2.2.19-pre14
## Robot:  $Id: make-incremental-diff,v 1.6 2001/12/04 04:41:15 hpa Exp $

diff -urN linux-2.2.19-pre13/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- linux-2.2.19-pre13/Documentation/ioctl-number.txt	Mon Dec  3 21:06:36 2001
+++ linux/Documentation/ioctl-number.txt	Mon Dec  3 21:07:19 2001
@@ -66,6 +66,7 @@
 0x22	all	scsi/sg.h
 'A'	all	linux/apm_bios.h
 'C'	all	linux/soundcard.h
+'D'	all	asm-s390/dasd.h
 'F'	all	linux/fb.h
 'I'	all	linux/isdn.h
 'K'	all	linux/kd.h
diff -urN linux-2.2.19-pre13/Documentation/isdn/00-INDEX linux/Documentation/isdn/00-INDEX
--- linux-2.2.19-pre13/Documentation/isdn/00-INDEX	Sun Dec 10 16:49:41 2000
+++ linux/Documentation/isdn/00-INDEX	Mon Dec  3 21:07:19 2001
@@ -38,3 +38,6 @@
 	- info on driver for Spellcaster cards.
 README.x25
     _ info for running X.25 over ISDN.
+README.hysdn
+        - info on driver for Hypercope active HYSDN cards
+ 
diff -urN linux-2.2.19-pre13/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon
--- linux-2.2.19-pre13/Documentation/isdn/README.eicon	Wed May  3 17:16:30 2000
+++ linux/Documentation/isdn/README.eicon	Mon Dec  3 21:07:19 2001
@@ -1,4 +1,4 @@
-$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $
+$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $
 
 (c) 1999,2000 Armin Schindler (mac@melware.de)
 (c) 1999,2000 Cytronics & Melware (info@melware.de)
@@ -40,6 +40,7 @@
 ------------------
 - DIVA Server BRI/PCI 2M
 - DIVA Server PRI/PCI 2M (9M 23M 30M)
+- DIVA Server 4BRI/PCI
 	supported functions of onboard DSPs:
 	- analog modem
 	- fax group 2/3 (Fax Class 2 commands)
@@ -78,6 +79,10 @@
 
 	eiconctrl [-d DriverId] load etsi
 
+Example for a BRI card with E-DSS1 Protocol with PtP configuration.
+
+	eiconctrl [-d DriverId] load etsi -n -t1 -s1
+
 
 Example for loading and starting a PRI card with E-DSS1 Protocol.
 
@@ -95,6 +100,18 @@
 the necessary D-Channel traces for isdnlog.
 
 
+FILECHECK:
+A part of the eicon driver source code files are provided
+by Eicon Technology. In order to get the best support from Eicon,
+these files are tested with a checksum, just to know if the files
+were modified. This does *not* mean, you are not allowed to modify the
+driver. If you want to improve the driver or you fix a bug, please do
+so and let me (or Eicon) know, about the necessary changes. So
+every user knows, if the driver he uses is modified or checked with
+Eicon files. When the driver has been loaded, in the syslog you will
+find something like "verified" or "modified" right after the version.
+
+
 Thanks to 
 	Deutsche Mailbox Saar-Lor-Lux GmbH
 	for sponsoring and testing fax
@@ -109,3 +126,4 @@
 Armin Schindler
 mac@melware.de
 http://www.melware.de
+
diff -urN linux-2.2.19-pre13/Documentation/isdn/README.fax linux/Documentation/isdn/README.fax
--- linux-2.2.19-pre13/Documentation/isdn/README.fax	Tue Jan  4 10:12:10 2000
+++ linux/Documentation/isdn/README.fax	Mon Dec  3 21:07:19 2001
@@ -24,6 +24,9 @@
 Eicon DIVA Server BRI/PCI
 	- full support with both B-channels.
 
+Eicon DIVA Server 4BRI/PCI
+	- full support with all B-channels.
+
 Eicon DIVA Server PRI/PCI
 	- full support on amount of B-channels
 		depending on DSPs on board.
diff -urN linux-2.2.19-pre13/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt
--- linux-2.2.19-pre13/Documentation/networking/vortex.txt	Mon Jan 22 12:52:34 1996
+++ linux/Documentation/networking/vortex.txt	Mon Dec  3 21:07:19 2001
@@ -1,35 +1,348 @@
+Documentation/networking/vortex.txt
+Andrew Morton <andrewm@uow.edu.au>
+18 Feb 2001
+
+
 This document describes the usage and errata of the 3Com "Vortex" device
-driver for Linux.
+driver for Linux, 3c59x.c.
+
+The driver was written by Donald Becker <becker@scyld.com>
+
+Don is no longer the prime maintainer of this version of the driver. 
+Please report problems to one or more of:
+
+  Andrew Morton <andrewm@uow.edu.au>
+  Netdev mailing list <netdev@oss.sgi.com>
+  Linux kernel mailing list <linux-kernel@vger.kernel.org>
+
+Please note the 'Reporting and Diagnosing Problems' section at the end
+of this file.
 
 This driver supports the following hardware:
-	3c590, 3c592, 3c595, 3c597
 
-When loaded as a module the following variables may be set:
- name	 type	description
- debug	 int	The debug message level, 0 (no messages) to 6 (wordy).
- options int[]	The media type override and card operation settings
-		(See list below.)
-
-An example of loading the vortex module is
-	insmod 3c59x.o debug=1 options=0,,12
-This sets the debug message level to minimal messages, sets the first card to
-the 10baseT transceiver, the second to the EEPROM-set transceiver, and the
-third card to operate in full-duplex mode using its 100baseTx transceiver.
-(Note: card ordering is set by the PCI BIOS.)
+	3c590 Vortex 10Mbps
+	3c592 EISA 10mbps Demon/Vortex
+	3c597 EISA Fast Demon/Vortex
+	3c595 Vortex 100baseTx
+	3c595 Vortex 100baseT4
+	3c595 Vortex 100base-MII
+	3Com Vortex
+	3c900 Boomerang 10baseT
+	3c900 Boomerang 10Mbps Combo
+	3c900 Cyclone 10Mbps Combo
+	3c900B-FL Cyclone 10base-FL
+	3c900 Cyclone 10Mbps TPO
+	3c900 Cyclone 10Mbps TPC
+	3c905 Boomerang 100baseTx
+	3c905 Boomerang 100baseT4
+	3c905B Cyclone 100baseTx
+	3c905B Cyclone 10/100/BNC
+	3c905B-FX Cyclone 100baseFx
+	3c905C Tornado
+	3c980 Cyclone
+	3cSOHO100-TX Hurricane
+	3c555 Laptop Hurricane
+	3c556 10/100 Mini PCI Adapter
+	3c556B Laptop Hurricane
+	3c575 Boomerang CardBus
+	3CCFE575 Cyclone CardBus
+	3CCFE656 Cyclone CardBus
+	3CCFEM656 Cyclone CardBus
+	3c575 series CardBus (unknown version)
+	3c450 HomePNA Tornado
+	3Com Boomerang (unknown version)
+
+Module parameters
+=================
+
+There are several parameters which may be provided to the driver when
+its module is loaded.  These are usually placed in /etc/modules.conf
+(used to be conf.modules).  Example:
+
+options 3c59x debug=3 rx_copybreak=300
+
+The supported parameters are:
+
+debug=N
+
+  Where N is a number from 0 to 7.  Anything above 3 produces a lot
+  of output in your system logs.  debug=1 is default.
+
+options=N1,N2,N3,...
 
-Possible media type settings
+  Each number in the list provides an option to the corresponding
+  network card.  So if you have two 3c905's and you wish to provide
+  them with option 0x204 you would use:
+
+    options=0x204,0x204
+
+  The individual options are composed of a number of bitfields which
+  have the following meanings:
+
+  ssible media type settings
 	0	10baseT
 	1	10Mbs AUI
 	2	undefined
 	3	10base2 (BNC)
 	4	100base-TX
 	5	100base-FX
-	6	MII (not yet available)
-	7	<Use default setting>
-	
-	8	Full-duplex bit
-		8 10baseT full-duplex
-		12 100baseTx full-duplex 
-	16	Bus-master enable bit (experimental use only!)
+	6	MII (Media Independent Interface)
+	7	Use default setting from EEPROM
+	8       Autonegotiate
+	9       External MII
+	10      Use default setting from EEPROM
+
+  When generating a value for the 'options' setting, the above media
+  selection values may be OR'ed (or added to) the following:
+
+  512  (0x200)	Force full duplex mode.
+  16   (0x10)	Bus-master enable bit (Old Vortex cards only)
+
+  For example:
+
+    insmod 3c59x options=0x204
+
+  will force full-duplex 100base-TX, rather than allowing the usual
+  autonegotiation.
+
+full_duplex=N1,N2,N3...
+
+  Similar to bit 9 of 'options'.  Forces the corresponding card into
+  full-duplex mode.  Please use this in preference to the `options'
+  parameter.
+
+  In fact, please don't use this at all! You're better off getting
+  autonegotiation working properly.
+
+rx_copybreak=M
+
+  The driver preallocates 32 full-sized (1536 byte) network buffers
+  for receiving.  When a packet arrives, the driver has to decide
+  whether to leave the packet in its full-sized buffer, or to allocate
+  a smaller buffer and copy the packet across into it.
+
+  This is a speed/space tradeoff.
+
+  The value of rx_copybreak is used to decide when to make the copy. 
+  If the packet size is less than rx_copybreak, the packet is copied. 
+  The default value for rx_copybreak is 200 bytes.
+
+max_interrupt_work=N
+
+  The driver's interrupt service routine can handle many receive and
+  transmit packets in a single invocation.  It does this in a loop. 
+  The value of max_interrupt_work governs how mnay times the interrupt
+  service routine will loop.  The default value is 32 loops.  If this
+  is exceeded the interrupt service routine gives up and generates a
+  warning message "eth0: Too much work in interrupt".
+
+compaq_ioaddr=N
+compaq_irq=N
+compaq_device_id=N
+
+  "Variables to work-around the Compaq PCI BIOS32 problem"....
+
+enable_wol=N1,N2,N3,...
+
+  Enable Wake-on-LAN support for the relevant interface.  Donald
+  Becker's `ether-wake' application may be used to wake suspended
+  machines.
+
+
+Media selection
+---------------
+
+A number of the older NICs such as the 3c590 and 3c900 series have
+10base2 and AUI interfaces.
+
+Prior to January, 2001 this driver would autoeselect the 10base2 or AUI
+port if it didn't detect activity on the 10baseT port.  It would then
+get stuck on the 10base2 port and a driver reload was necessary to
+switch back to 10baseT.  This behaviour could not be prevented with a
+module option override.
+
+Later (current) versions of the driver _do_ support locking of the
+media type.  So if you load the driver module with
+
+	modprobe 3c59x options=0
+
+it will permanently select the 10baseT port.  Automatic selection of
+other media types does not occur.
+
+
+Additional resources
+--------------------
 
 Details of the device driver implementation are at the top of the source file.
+
+Additional documentation is available at Don Becker's Linux Drivers site:
+
+  http://www.scyld.com/network/vortex.html
+
+Donald Becker's driver development site:
+
+     http://www.scyld.com/network
+
+Donald's vortex-diag program is useful for inspecting the NIC's state:
+
+     http://www.scyld.com/diag/#pci-diags
+
+Donald's mii-diag program may be used for inspecting and manipulating
+the NIC's Media Independent Interface subsystem:
+
+     http://www.scyld.com/diag/#mii-diag
+
+Donald's wake-on-LAN page:
+
+     http://www.scyld.com/expert/wake-on-lan.html
+
+3Com's documentation for many NICs, including the ones supported by
+this driver is available at 
+
+     http://support.3com.com/partners/developer/developer_form.html
+
+3Com's DOS-based application for setting up the NICs EEPROMs:
+
+	ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
+
+Driver updates and a detailed changelog for the modifications which
+were made for the 2.3/2,4 series kernel is available at
+
+     http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3
+
+
+Autonegotiation notes
+---------------------
+
+  The driver uses a one-minute heartbeat for adapting to changes in
+  the external LAN environment.  This means that when, for example, a
+  machine is unplugged from a hubbed 10baseT LAN plugged into a
+  switched 100baseT LAN, the throughput will be quite dreadful for up
+  to sixty seconds.  Be patient.
+
+  Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
+
+  On a side note, adding HAS_NWAY seems to share a problem with the
+  Cisco 6509 switch.  Specifically, you need to change the spanning
+  tree parameter for the port the machine is plugged into to 'portfast'
+  mode.  Otherwise, the negotiation fails.  This has been an issue
+  we've noticed for a while but haven't had the time to track down.
+
+  Cisco switches    (Jeff Busch <jbusch@deja.com>)
+
+    My "standard config" for ports to which PC's/servers connect directly:
+
+        interface FastEthernet0/N
+        description machinename
+        load-interval 30
+        spanning-tree portfast
+
+    If autonegotiation is a problem, you may need to specify "speed
+    100" and "duplex full" as well (or "speed 10" and "duplex half").
+
+    WARNING: DO NOT hook up hubs/switches/bridges to these
+    specially-configured ports! The switch will become very confused.
+
+
+Reporting and diagnosing problems
+---------------------------------
+
+Maintainers find that accurate and complete problem reports are
+invaluable in resolving driver problems.  We are frequently not able to
+reproduce problems and must rely on your patience and efforts to get to
+the bottom of the problem.
+
+If you believe you have a driver problem here are some of the
+steps you should take:
+
+- Is it really a driver problem?
+
+   Eliminate some variables: try different cards, different
+   computers, different cables, different ports on the switch/hub,
+   different versions of the kernel or ofthe driver, etc.
+
+- OK, it's a driver problem.
+
+   You need to generate a report.  Typically this is an email to the
+   maintainer and/or linux-net@vger.kernel.org.  The maintainer's
+   email address will be inthe driver source or in the MAINTAINERS file.
+
+- The contents of your report will vary a lot depending upon the
+  problem.  If it's a kernel crash then you should refer to the
+  REPORTING-BUGS file.
+
+  But for most problems it is useful to provide the following:
+
+   o Kernel version, driver version
+
+   o A copy of the banner message which the driver generates when
+     it is initialised.  For example:
+
+     eth0: 3Com PCI 3c905C Tornado at 0xa400,  00:50:da:6a:88:f0, IRQ 19
+     8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface.
+     MII transceiver found at address 24, status 782d.
+     Enabling bus-master transmits and whole-frame receives.
+
+   o If it is a PCI device, the relevant output from 'lspci -vx', eg:
+
+     00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74)
+             Subsystem: 3Com Corporation: Unknown device 9200
+             Flags: bus master, medium devsel, latency 32, IRQ 19
+             I/O ports at a400 [size=128]
+             Memory at db000000 (32-bit, non-prefetchable) [size=128]
+             Expansion ROM at <unassigned> [disabled] [size=128K]
+             Capabilities: [dc] Power Management version 2
+     00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00
+     10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00
+     20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10
+     30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a
+
+   o A description of the environment: 10baseT? 100baseT?
+     full/half duplex? switched or hubbed?
+
+   o Any additional module parameters which you may be providing to the driver.
+
+   o Any kernel logs which are produced.  The more the merrier. 
+     If this is a large file and you are sending your report to a
+     mailing list, mention that you have the logfile, but don't send
+     it.  If you're reporting direct to the maintainer then just send
+     it.
+
+     To ensure that all kernel logs are available, add the
+     following line to /etc/syslog.conf:
+
+         kern.* /var/log/messages
+
+     Then restart syslogd with:
+
+         /etc/rc.d/init.d/syslog restart
+
+     (The above may vary, depending upon which Linux distribution you use).
+
+    o If your problem is reproducible then that's great.  Try the
+      following:
+
+      1) Increase the debug level.  Usually this is done via:
+
+         a) modprobe driver.o debug=7
+         b) In /etc/conf.modules (or modules.conf):
+            options driver_name debug=7
+
+      2) Recreate the problem with the higher debug level,
+         send all logs to the maintainer.
+
+      3) Download you card's diagnostic tool from Donald
+         Backer's website http://www.scyld.com/diag.  Download
+         mii-diag.c as well.  Build these.
+
+         a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is
+            working correctly.  Save the output.
+
+         b) Run the above commands when the card is malfunctioning.  Send
+            both sets of output.
+
+Finally, please be patient and be prepared to do some work.  You may end up working on
+this problem for a week or more as the maintainer asks more questions, asks for more
+tests, asks for patches to be applied, etc.  At the end of it all, the problem may even
+remain unresolved.
+
diff -urN linux-2.2.19-pre13/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile
--- linux-2.2.19-pre13/arch/s390/kernel/Makefile	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/Makefile	Mon Dec  3 21:07:19 2001
@@ -18,16 +18,15 @@
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
-O_OBJS   := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
-            setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-            s390fpu.o s390io.o reipl.o debug.o s390_ext.o s390dyn.o \
-            s390mach.o 
+O_OBJS   := lowcore.o entry.o bitmap.o traps.o time.o \
+            setup.o sys_s390.o ptrace.o signal.o cpcmd.o \
+            s390fpu.o reipl.o s390mach.o 
 
-OX_OBJS  := s390_ksyms.o
+OX_OBJS  := debug.o ebcdic.o irq.o process.o s390_ext.o s390_ksyms.o s390dyn.o s390io.o
 MX_OBJS  :=
 
 ifdef CONFIG_SMP
-O_OBJS += smp.o
+OX_OBJS += smp.o
 endif
 
 ifeq ($(CONFIG_IEEEFPU_EMULATION),y)
diff -urN linux-2.2.19-pre13/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c
--- linux-2.2.19-pre13/arch/s390/kernel/cpcmd.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/cpcmd.c	Mon Dec  3 21:07:19 2001
@@ -22,10 +22,10 @@
         ASCEBC(obuffer,olen);
 
         if (response != NULL && rlen > 0) {
-                asm volatile ("LRA   2,0(0,%0)\n\t"
+                asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    4,%1\n\t"
                               "O     4,%4\n\t"
-                              "LRA   3,0(0,%2)\n\t"
+                              "LRA   3,0(%2)\n\t"
                               "LR    5,%3\n\t"
                               ".long 0x83240008 # Diagnose 83\n\t"
                               : /* no output */
@@ -34,7 +34,7 @@
                               : "2", "3", "4", "5" );
                 EBCASC(response, rlen);
         } else {
-                asm volatile ("LRA   2,0(0,%0)\n\t"
+                asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    3,%1\n\t"
                               ".long 0x83230008 # Diagnose 83\n\t"
                               : /* no output */
diff -urN linux-2.2.19-pre13/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- linux-2.2.19-pre13/arch/s390/kernel/debug.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/debug.c	Mon Dec  3 21:07:19 2001
@@ -10,48 +10,58 @@
  *    Bugreports to: <Linux390@de.ibm.com>
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
-#include <linux/vmalloc.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
-#include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
-#ifdef MODULE
 #include <linux/module.h>
-#endif
 
 #include <asm/debug.h>
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
-
-#if defined(CONFIG_ARCH_S390)
-#define DEBUG_PROC_HEADER_SIZE 38
-#endif
-
-#define ADD_BUFFER 1000
+#define DEBUG_PROLOG_ENTRY -1
 
 /* typedefs */
 
 typedef struct file_private_info {
-	loff_t len;			/* length of output in byte */
-	int size;			/* size of buffer for output */
-	char *data;			/* buffer for output */
-	debug_info_t *debug_info;	/* the debug information struct */
+	loff_t offset;			/* offset of last read in file */
+	int    act_area;                /* number of last formated area */
+	int    act_entry;               /* last formated entry (offset */
+                                        /* relative to beginning of last */
+                                        /* formated area) */ 
+	size_t act_entry_offset;        /* up to this offset we copied */
+					/* in last read the last formated */
+					/* entry to userland */
+	char   temp_buf[2048];		/* buffer for output */
+	debug_info_t *debug_info_org;   /* original debug information */
+	debug_info_t *debug_info_snap;	/* snapshot of debug information */
 	struct debug_view *view;	/* used view of debug info */
 } file_private_info_t;
 
+typedef struct
+{
+	char *string;
+	/* 
+	 * This assumes that all args are converted into longs 
+	 * on L/390 this is the case for all types of parameter 
+	 * except of floats, and long long (32 bit) 
+         *
+         */
+	long args[0];
+} debug_sprintf_entry;
+
+
 extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
 
 /* internal function prototyes */
 
 static int debug_init(void);
-static int debug_format_output(debug_info_t * debug_area, char *buf,
-			       int size, struct debug_view *view);
 static ssize_t debug_output(struct file *file, char *user_buf,
 			    size_t user_len, loff_t * offset);
 static ssize_t debug_input(struct file *file, const char *user_buf,
@@ -65,6 +75,7 @@
 			     struct file_operations *fops);
 static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
 					struct proc_dir_entry *entry);
+static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
 static int debug_prolog_level_fn(debug_info_t * id,
@@ -72,38 +83,34 @@
 static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
 				struct file *file, const char *user_buf,
 				size_t user_buf_size, loff_t * offset);
-static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
-			       char *out_buf, const char *in_buf);
-static int debug_ascii_format_fn(debug_info_t * id,
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+                                char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
 				 struct debug_view *view, char *out_buf,
 				 const char *in_buf);
-static int debug_ebcdic_format_fn(debug_info_t * id,
-				  struct debug_view *view, char *out_buf,
-				  const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+                         int area, debug_entry_t * entry, char *out_buf);
+
+static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+				   char *out_buf, debug_sprintf_entry *curr_event);
 
 /* globals */
 
-struct debug_view debug_ascii_view = {
-	"ascii",
+struct debug_view debug_raw_view = {
+	"raw",
 	NULL,
-	&debug_dflt_header_fn,
-	&debug_ascii_format_fn,
-	NULL
-};
-
-struct debug_view debug_ebcdic_view = {
-	"ebcdic",
+	&debug_raw_header_fn,
+	&debug_raw_format_fn,
 	NULL,
-	&debug_dflt_header_fn,
-	&debug_ebcdic_format_fn,
 	NULL
 };
 
-struct debug_view debug_hex_view = {
-	"hex",
+struct debug_view debug_hex_ascii_view = {
+	"hex_ascii",
 	NULL,
 	&debug_dflt_header_fn,
-	&debug_hex_format_fn,
+	&debug_hex_ascii_format_fn,
+	NULL,
 	NULL
 };
 
@@ -112,13 +119,26 @@
 	&debug_prolog_level_fn,
 	NULL,
 	NULL,
-	&debug_input_level_fn
+	&debug_input_level_fn,
+	NULL
+};
+
+struct debug_view debug_sprintf_view = {
+	"sprintf",
+	NULL,
+	&debug_dflt_header_fn,
+	(debug_format_proc_t*)&debug_sprintf_format_fn,
+	NULL,
+	NULL
 };
 
+
+unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
+
 /* static globals */
 
-static debug_info_t debug_areas[DEBUG_MAX_AREAS];
-static debug_info_t *free_area = 0;
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 static struct semaphore debug_lock = MUTEX;
 #else
@@ -143,10 +163,155 @@
 
 static struct proc_dir_entry *debug_proc_root_entry;
 
-
 /* functions */
 
 /*
+ * debug_info_alloc
+ * - alloc new debug-info
+ */
+
+static debug_info_t*  debug_info_alloc(char *name, int page_order,
+                                        int nr_areas, int buf_size)
+{
+	debug_info_t* rc;
+	int i;
+
+	/* alloc everything */
+
+	rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+	if(!rc)
+		goto fail_malloc_rc;
+	rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
+	if(!rc->active_entry)
+		goto fail_malloc_active_entry;
+	memset(rc->active_entry, 0, nr_areas * sizeof(int));
+	rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+						sizeof(debug_entry_t *),
+						GFP_ATOMIC);
+	if (!rc->areas)
+		goto fail_malloc_areas;
+	for (i = 0; i < nr_areas; i++) {
+		rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+								page_order);
+		if (!rc->areas[i]) {
+			for (i--; i >= 0; i--) {
+				free_pages((unsigned long) rc->areas[i],
+						page_order);
+			}
+			goto fail_malloc_areas2;
+		} else {
+			memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+		}
+	}
+
+	/* initialize members */
+
+	spin_lock_init(&rc->lock);
+	rc->page_order  = page_order;
+	rc->nr_areas    = nr_areas;
+	rc->active_area = 0;
+	rc->level       = DEBUG_DEFAULT_LEVEL;
+	rc->buf_size    = buf_size;
+	rc->entry_size  = sizeof(debug_entry_t) + buf_size;
+	strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+	memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
+		sizeof(struct proc_dir_entry*));
+	atomic_set(&(rc->ref_count), 0);
+
+	return rc;
+
+fail_malloc_areas2:
+	kfree(rc->areas);
+fail_malloc_areas:
+	kfree(rc->active_entry);
+fail_malloc_active_entry:
+	kfree(rc);
+fail_malloc_rc:
+	return NULL;
+}
+
+/*
+ * debug_info_free
+ * - free memory debug-info
+ */
+
+static void debug_info_free(debug_info_t* db_info){
+	int i;
+	for (i = 0; i < db_info->nr_areas; i++) {
+		free_pages((unsigned long) db_info->areas[i],
+		db_info->page_order);
+	}
+	kfree(db_info->areas);
+	kfree(db_info->active_entry);
+	kfree(db_info);
+}
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t*  debug_info_create(char *name, int page_order, 
+                                        int nr_areas, int buf_size)
+{
+	debug_info_t* rc;
+
+        rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
+        if(!rc) 
+		goto out;
+
+
+	/* create proc rood directory */
+
+        rc->proc_root_entry =
+            debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+                                        S_IFDIR | S_IRUGO | S_IXUGO |
+                                        S_IWUSR | S_IWGRP, NULL, NULL);
+
+	/* append new element to linked list */
+
+        if(debug_area_first == NULL){
+                /* first element in list */
+                debug_area_first = rc;
+                rc->prev = NULL;
+        }
+        else{
+                /* append element to end of list */
+                debug_area_last->next = rc;
+                rc->prev = debug_area_last;
+        }
+        debug_area_last = rc;
+        rc->next = NULL;
+
+	debug_info_get(rc);
+out:
+	return rc;
+}
+
+/*
+ * debug_info_copy
+ * - copy debug-info
+ */
+
+static debug_info_t* debug_info_copy(debug_info_t* in)
+{
+        int i;
+        debug_info_t* rc;
+        rc = debug_info_alloc(in->name, in->page_order, 
+                                in->nr_areas, in->buf_size);
+        if(!rc)
+                goto out;
+
+        for(i = 0; i < in->nr_areas; i++){
+                memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
+        }
+out:
+        return rc;
+}
+
+/*
  * debug_info_get
  * - increments reference count for debug-info
  */
@@ -179,44 +344,120 @@
 		}
 		debug_delete_proc_dir_entry(debug_proc_root_entry,
 					    db_info->proc_root_entry);
-		for (i = 0; i < db_info->nr_areas; i++) {
-			free_pages((unsigned long) db_info->areas[i],
-				   db_info->page_order);
-		}
-		kfree(db_info->areas);
-		db_info->areas = NULL;
-		*((debug_info_t **) db_info) = free_area;
-		free_area = db_info;
+		if(db_info == debug_area_first)
+			debug_area_first = db_info->next;
+		if(db_info == debug_area_last)
+			debug_area_last = db_info->prev;
+		if(db_info->prev) db_info->prev->next = db_info->next;
+		if(db_info->next) db_info->next->prev = db_info->prev;
+		debug_info_free(db_info);
 	}
 }
 
+/*
+ * debug_format_entry:
+ * - format one debug entry and return size of formated data
+ */
+
+static int debug_format_entry(file_private_info_t *p_info)
+{
+	debug_info_t *id_org    = p_info->debug_info_org;
+	debug_info_t *id_snap   = p_info->debug_info_snap;
+	struct debug_view *view = p_info->view;
+	debug_entry_t *act_entry;
+	size_t len = 0;
+	if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+		/* print prolog */
+        	if (view->prolog_proc)
+                	len += view->prolog_proc(id_org, view,p_info->temp_buf);
+		goto out;
+	}
+
+	act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
+					p_info->act_entry);
+                        
+	if (act_entry->id.stck == 0LL)
+			goto out;  /* empty entry */
+	if (view->header_proc)
+		len += view->header_proc(id_org, view, p_info->act_area, 
+					act_entry, p_info->temp_buf + len);
+	if (view->format_proc)
+		len += view->format_proc(id_org, view, p_info->temp_buf + len,
+						DEBUG_DATA(act_entry));
+      out:
+        return len;
+}
+
+/*
+ * debug_next_entry:
+ * - goto next entry in p_info
+ */
+
+extern inline int debug_next_entry(file_private_info_t *p_info)
+{
+	debug_info_t *id = p_info->debug_info_snap;
+	if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+		p_info->act_entry = 0;
+		goto out;
+	}
+	if ((p_info->act_entry += id->entry_size)
+		> ((PAGE_SIZE << (id->page_order)) 
+		- id->entry_size)){
+
+		/* next area */
+		p_info->act_entry = 0;
+        	p_info->act_area++;
+        	if(p_info->act_area >= id->nr_areas)
+			return 1;
+	}
+out:
+	return 0;	
+}
 
 /*
  * debug_output:
  * - called for user read()
- * - copies formated output form private_data of the file
- *   handle to the user buffer
+ * - copies formated debug entries to the user buffer
  */
 
 static ssize_t debug_output(struct file *file,	/* file descriptor */
 			    char *user_buf,	/* user buffer */
-			    size_t user_len,	/* length of buffer */
+			    size_t  len,	/* length of buffer */
 			    loff_t *offset	/* offset in the file */ )
 {
-	loff_t len;
+	size_t count = 0;
+	size_t entry_offset, size = 0;
 	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
-	if (*offset >= p_info->len) {
-		return 0;	/* EOF */
-	} else {
-		len = MIN(user_len, (p_info->len - *offset));
-		if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
-			return rc;;
-		(*offset) += len;
-		return len;	/* number of bytes "read" */
+	if (*offset != p_info->offset) 
+		return -EPIPE;
+	if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
+		return 0;
+
+	entry_offset = p_info->act_entry_offset;
+
+	while(count < len){
+		size = debug_format_entry(p_info);
+		size = MIN((len - count), (size - entry_offset));
+
+		if(size){
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
+		}
+		count += size;
+		entry_offset = 0;
+		if(count != len)
+			if(debug_next_entry(p_info)) 
+				goto out;
 	}
+out:
+	p_info->offset           = *offset + count;
+	p_info->act_entry_offset = size;	
+	*offset = p_info->offset;
+	return count;
 }
 
 /*
@@ -235,69 +476,16 @@
 	down(&debug_lock);
 	p_info = ((file_private_info_t *) file->private_data);
 	if (p_info->view->input_proc)
-		rc = p_info->view->input_proc(p_info->debug_info,
+		rc = p_info->view->input_proc(p_info->debug_info_org,
 					      p_info->view, file, user_buf,
 					      length, offset);
+	else
+		rc = -EPERM;
 	up(&debug_lock);
 	return rc;		/* number of input characters */
 }
 
 /*
- * debug_format_output:
- * - calls prolog, header and format functions of view to format output
- */
-
-static int debug_format_output(debug_info_t * debug_area, char *buf,
-			       int size, struct debug_view *view)
-{
-	int len = 0;
-	int i, j;
-	int nr_of_entries;
-	debug_entry_t *act_entry;
-
-	/* print prolog */
-	if (view->prolog_proc)
-		len += view->prolog_proc(debug_area, view, buf);
-	/* print debug records */
-	if (!(view->format_proc) && !(view->header_proc))
-		goto out;
-	nr_of_entries = PAGE_SIZE / debug_area->entry_size
-			<< debug_area->page_order;
-	for (i = 0; i < debug_area->nr_areas; i++) {
-		act_entry = debug_area->areas[i];
-		for (j = 0; j < nr_of_entries; j++) {
-			if (act_entry->id.fields.used == 0)
-				break;	/* empty entry */
-			if (view->header_proc)
-				len += view->header_proc(debug_area, view, i,
-						         act_entry, buf + len);
-			if (view->format_proc)
-				len += view->format_proc(debug_area, view,
-						         buf + len,
-						         act_entry->data);
-			len += sprintf(buf + len, "\n");
-			if (len > size) {
-				printk(KERN_ERR
-				"debug: error -- memory exceeded for (%s/%s)\n",
-				debug_area->name, view->name);
-				printk(KERN_ERR "debug: fix view %s!!\n",
-				       view->name);
-				printk(KERN_ERR
-				"debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
-				i, debug_area->nr_areas - 1, j,
-				nr_of_entries - 1);
-				goto out;
-			}
-			act_entry = (debug_entry_t *) (((char *) act_entry) +
-					       debug_area->entry_size);
-		}
-	}
-      out:
-	return len;
-}
-
-
-/*
  * debug_open:
  * - called for user open()
  * - copies formated output to private_data area of the file
@@ -306,119 +494,68 @@
 
 static int debug_open(struct inode *inode, struct file *file)
 {
-	int i, j = 0, size = 0, rc = 0, f_entry_size = 0;
+	int i = 0, rc = 0;
 	file_private_info_t *p_info;
+	debug_info_t *debug_info, *debug_info_snapshot;
 
 #ifdef DEBUG
 	printk("debug_open\n");
 #endif
-
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	down(&debug_lock);
 
 	/* find debug log and view */
 
-	for (i = 0; i < DEBUG_MAX_AREAS; i++) {
-		if (debug_areas[i].areas == NULL)
-			continue;	/* not in use */
-		for (j = 0; j < DEBUG_MAX_VIEWS; j++) {
-			if (debug_areas[i].views[j] == NULL)
+	debug_info = debug_area_first;
+	while(debug_info != NULL){
+		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+			if (debug_info->views[i] == NULL)
 				continue;
-			else if (debug_areas[i].proc_entries[j]->low_ino ==
+			else if (debug_info->proc_entries[i]->low_ino ==
 				 file->f_dentry->d_inode->i_ino) {
 				goto found;	/* found view ! */
 			}
 		}
+		debug_info = debug_info->next;
 	}
 	/* no entry found */
 	rc = -EINVAL;
 	goto out;
+
       found:
-	if ((file->private_data =
-	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
-		printk(KERN_ERR "debug_open: kmalloc failed\n");
-		rc = -ENOMEM;
-		goto out;
-	}
-	p_info = (file_private_info_t *) file->private_data;
 
-	/*
-	 * the size for the formated output is calculated
-	 * with the following formula:
-	 *
-	 *   prolog-size
-	 *   +
-	 *   (record header size + record data field size)
-	 *   * number of entries per page
-	 *   * number of pages per area
-	 *   * number of areas
-	 */
-
-	if (debug_areas[i].views[j]->prolog_proc)
-		size +=
-		    debug_areas[i].views[j]->prolog_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], NULL);
-
-	if (debug_areas[i].views[j]->header_proc)
-		f_entry_size =
-		    debug_areas[i].views[j]->header_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], 0, NULL,
-							 NULL);
-	if (debug_areas[i].views[j]->format_proc)
-		f_entry_size +=
-		    debug_areas[i].views[j]->format_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], NULL,
-							 NULL);
-	if (f_entry_size)
-		f_entry_size += 1;	/* \n in each line */
-
-
-	size += f_entry_size 
-		* (PAGE_SIZE / debug_areas[i].entry_size
-		<< debug_areas[i].page_order)
-		* debug_areas[i].nr_areas + 1;	/* terminating \0 */
-#ifdef DEBUG
-	printk("debug_open: size: %i\n", size);
-#endif
+	/* make snapshot of current debug areas to get it consistent */
+
+	debug_info_snapshot = debug_info_copy(debug_info);
 
-	/* alloc some bytes more to be safe against bad views */
-	if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
-		printk(KERN_ERR "debug_open: vmalloc failed\n");
-		vfree(file->private_data);
+	if(!debug_info_snapshot){
+		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
 		rc = -ENOMEM;
 		goto out;
 	}
 
-	p_info->size = size;
-	p_info->debug_info = &debug_areas[i];
-	p_info->view = debug_areas[i].views[j];
-
-	spin_lock_irq(&debug_areas[i].lock);
-
-	p_info->len =
-	    debug_format_output(&debug_areas[i], p_info->data, size,
-				debug_areas[i].views[j]);
-#ifdef DEBUG
-	{
-		int ilen = p_info->len;
-		printk("debug_open: len: %i\n", ilen);
+	if ((file->private_data =
+	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+		printk(KERN_ERR "debug_open: kmalloc failed\n");
+		debug_info_free(debug_info_snapshot);	
+		rc = -ENOMEM;
+		goto out;
 	}
-#endif
+	p_info = (file_private_info_t *) file->private_data;
+	p_info->offset = 0;
+	p_info->debug_info_snap = debug_info_snapshot;
+	p_info->debug_info_org  = debug_info;
+	p_info->view = debug_info->views[i];
+	p_info->act_area = 0;
+	p_info->act_entry = DEBUG_PROLOG_ENTRY;
+	p_info->act_entry_offset = 0;
 
-	spin_unlock_irq(&debug_areas[i].lock);
-	debug_info_get(&debug_areas[i]);
+	debug_info_get(debug_info);
 
       out:
 	up(&debug_lock);
-#ifdef MODULE
 	if (rc != 0)
 		MOD_DEC_USE_COUNT;
-#endif
 	return rc;
 }
 
@@ -434,18 +571,11 @@
 #ifdef DEBUG
 	printk("debug_close\n");
 #endif
-	down(&debug_lock);
 	p_info = (file_private_info_t *) file->private_data;
-	debug_info_put(p_info->debug_info);
-	if (p_info->data) {
-		vfree(p_info->data);
-		kfree(file->private_data);
-	}
-	up(&debug_lock);
-
-#ifdef MODULE
+	debug_info_free(p_info->debug_info_snap);
+	debug_info_put(p_info->debug_info_org);
+	kfree(file->private_data);
 	MOD_DEC_USE_COUNT;
-#endif
 	return 0;		/* success */
 }
 
@@ -522,74 +652,25 @@
     (char *name, int page_order, int nr_areas, int buf_size) 
 {
 	debug_info_t *rc = NULL;
-	int i;
 
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	if (!initialized)
 		debug_init();
 	down(&debug_lock);
-	if (!free_area) {
-		printk(KERN_WARNING "debug: no free debug area for %s\n",
-		       name);
-		goto out;
-	}
-	rc = free_area;
-	free_area = *((debug_info_t **) rc);
-	rc->areas = (debug_entry_t **) kmalloc(nr_areas *
-					       sizeof(debug_entry_t *),
-					       GFP_ATOMIC);
-	if (!rc->areas) {
-		free_area = rc;
-		rc = NULL;
-		goto out;
-	}
-	for (i = 0; i < nr_areas; i++) {
-		rc->areas[i] =
-		    (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
-						       page_order);
-		if (!rc->areas[i]) {
-			for (i--; i >= 0; i--) {
-				free_pages((unsigned long) rc->areas[i],
-					   page_order);
-			}
-			free_area = rc;
-			rc = NULL;
-			goto out;
-		} else {
-			memset(rc->areas[i], 0, PAGE_SIZE << page_order);
-		}
-	}
 
-	rc->page_order  = page_order;
-	rc->nr_areas    = nr_areas;
-	rc->active_area = 0;
-	rc->level       = DEBUG_DEFAULT_LEVEL;
-	rc->buf_size    = buf_size;
-	rc->entry_size  = sizeof(debug_entry_t) 
-                          + buf_size - 4;  /* must subtract data[4] */
-	strncpy(rc->name, name,
-		MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
-	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
-	memset(rc->active_entry, 0, nr_areas * sizeof(int));
-	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
-	atomic_set(&(rc->ref_count), 0);
-	rc->proc_root_entry =
-	    debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
-					S_IFDIR | S_IRUGO | S_IXUGO |
-					S_IWUSR | S_IWGRP, NULL, NULL);
+        /* create new debug_info */
+
+	rc = debug_info_create(name, page_order, nr_areas, buf_size);
+	if(!rc) 
+		goto out;
 	debug_register_view(rc, &debug_level_view);
-	debug_info_get(rc);
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
       out:
         if (rc == NULL){
 		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
-#ifdef MODULE
 		MOD_DEC_USE_COUNT;
-#endif
         }
 	up(&debug_lock);
 	return rc;
@@ -609,20 +690,44 @@
 	debug_info_put(id);
 	up(&debug_lock);
 
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
       out:
 	return;
 }
 
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void debug_set_level(debug_info_t* id, int new_level)
+{
+	unsigned long flags;
+	if(!id)
+		return;	
+	spin_lock_irqsave(&id->lock,flags);
+        if(new_level == DEBUG_OFF_LEVEL){
+                id->level = DEBUG_OFF_LEVEL;
+                printk(KERN_INFO "debug: %s: switched off\n",id->name);
+        } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+                printk(KERN_INFO
+                        "debug: %s: level %i is out of range (%i - %i)\n",
+                        id->name, new_level, 0, DEBUG_MAX_LEVEL);
+        } else {
+                id->level = new_level;
+                printk(KERN_INFO 
+			"debug: %s: new level %i\n",id->name,id->level);
+        }
+	spin_unlock_irqrestore(&id->lock,flags);
+}
+
 
 /*
  * proceed_active_entry:
  * - set active entry to next in the ring buffer
  */
 
-static inline void proceed_active_entry(debug_info_t * id)
+extern inline void proceed_active_entry(debug_info_t * id)
 {
 	if ((id->active_entry[id->active_area] += id->entry_size)
 	    > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
@@ -634,7 +739,7 @@
  * - set active area to next in the ring buffer
  */
 
-static inline void proceed_active_area(debug_info_t * id)
+extern inline void proceed_active_area(debug_info_t * id)
 {
 	id->active_area++;
 	id->active_area = id->active_area % id->nr_areas;
@@ -644,7 +749,7 @@
  * get_active_entry:
  */
 
-static inline debug_entry_t *get_active_entry(debug_info_t * id)
+extern inline debug_entry_t *get_active_entry(debug_info_t * id)
 {
 	return (debug_entry_t *) ((char *) id->areas[id->active_area] +
 				  id->active_entry[id->active_area]);
@@ -655,162 +760,126 @@
  * - set timestamp, caller address, cpu number etc.
  */
 
-static inline debug_entry_t *debug_common(debug_info_t * id)
+extern inline debug_entry_t *debug_common(debug_info_t * id, int level, 
+                                    const void *buf, int len, int exception)
 {
+	unsigned long flags;
 	debug_entry_t *active;
 
+	spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	STCK(active->id.stck);
 	active->id.fields.cpuid = smp_processor_id();
-	active->id.fields.used = 1;
 	active->caller = __builtin_return_address(0);
-	return active;
-}
-
-/*
- * debug_event:
- */
-
-debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
-			   int len)
-{
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 0;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, buf, MIN(len, id->buf_size));
+	active->id.fields.exception = exception;
+	active->id.fields.level     = level;
+	memset(DEBUG_DATA(active), 0, id->buf_size);
+	memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
 	proceed_active_entry(id);
+	if(exception)
+		proceed_active_area(id);
 	spin_unlock_irqrestore(&id->lock, flags);
-      out:
+
 	return active;
 }
 
 /*
- * debug_int_event:
+ * debug_event_common:
+ * - write debug entry with given size
  */
 
-debug_entry_t *debug_int_event(debug_info_t * id, int level,
-			       unsigned int tag)
+debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
+			          int len)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 0;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size));
-	proceed_active_entry(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	return debug_common(id, level, buf, len, 0);
 }
 
 /*
- * debug_text_event:
+ * debug_exception_common:
+ * - write debug entry with given size and switch to next debug area
  */
 
-debug_entry_t *debug_text_event(debug_info_t * id, int level,
-				const char *txt)
+debug_entry_t *debug_exception_common(debug_info_t * id, int level, 
+                                      const void *buf, int len)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	memset(active->data, 0, id->buf_size);
-	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
-	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
-	active->id.fields.exception = 0;
-	proceed_active_entry(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
-
+	return debug_common(id, level, buf, len, 1);
 }
 
 /*
- * debug_exception:
+ * counts arguments in format string for sprintf view
  */
 
-debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
-			       int len)
+extern inline int debug_count_numargs(char *string)
 {
-	long flags;
-	debug_entry_t *active = NULL;
+	int numargs=0;
 
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 1;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, buf, MIN(len, id->buf_size));
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	while(*string) {
+		if(*string++=='%')
+			numargs++;
+	}
+	return(numargs);
 }
 
 /*
- * debug_int_exception:
+ * debug_sprintf_event:
  */
 
-debug_entry_t *debug_int_exception(debug_info_t * id, int level,
-				   unsigned int tag)
+debug_entry_t *debug_sprintf_event(debug_info_t* id,
+                                   int level,char *string,...)
 {
-	long flags;
-	debug_entry_t *active = NULL;
+	va_list   ap;
+	int numargs,alloc_size,idx;
+	debug_sprintf_entry *curr_event;
+	debug_entry_t *retval = NULL;
 
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 1;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, &tag,
-	       MIN(sizeof(unsigned int), id->buf_size));
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	if((!id) || (level > id->level))
+		return NULL;
+	else {
+		numargs=debug_count_numargs(string);
+		alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
+		curr_event=alloca(alloc_size);
+
+		if(curr_event){
+			va_start(ap,string);
+			curr_event->string=string;
+			for(idx=0;idx<numargs;idx++)
+				curr_event->args[idx]=va_arg(ap,long);
+			retval=debug_common(id,level, curr_event,alloc_size,0);
+			va_end(ap);
+		}
+		return retval;
+	}
 }
 
 /*
- * debug_text_exception:
+ * debug_sprintf_exception:
  */
 
-debug_entry_t *debug_text_exception(debug_info_t * id, int level,
-				    const char *txt)
+debug_entry_t *debug_sprintf_exception(debug_info_t* id,
+                                       int level,char *string,...)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	memset(active->data, 0, id->buf_size);
-	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
-	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
-	active->id.fields.exception = 1;
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	va_list   ap;
+	int numargs,alloc_size,idx;
+	debug_sprintf_entry *curr_event;
+	debug_entry_t *retval = NULL;
 
+	if((!id) || (level > id->level))
+		return NULL;
+	else {
+		numargs=debug_count_numargs(string);
+		alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
+		curr_event=alloca(alloc_size);
+
+		if(curr_event){
+			va_start(ap,string);
+			curr_event->string=string;
+			for(idx=0;idx<numargs;idx++)
+				curr_event->args[idx]=va_arg(ap,long);
+			retval=debug_common(id,level, curr_event,alloc_size,1);
+			va_end(ap);
+		}
+		return retval;
+	}
 }
 
 /*
@@ -821,7 +890,6 @@
 int debug_init(void)
 {
 	int rc = 0;
-	int i;
 
 	down(&debug_lock);
 	if (!initialized) {
@@ -830,15 +898,7 @@
 						S_IFDIR | S_IRUGO | S_IXUGO
 						| S_IWUSR | S_IWGRP, NULL,
 						NULL);
-		for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) {
-			*(debug_info_t **) (&debug_areas[i]) =
-			    (debug_info_t *) (&debug_areas[i + 1]);
-		}
-		*(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
-		free_area = &(debug_areas[0]);
-		printk(KERN_INFO
-		       "debug: %d areas reserved for debugging information\n",
-		       DEBUG_MAX_AREAS);
+		printk(KERN_INFO "debug: Initialization complete\n");
 		initialized = 1;
 	}
 	up(&debug_lock);
@@ -854,7 +914,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 	mode_t mode = S_IFREG;
 
 	if (!id)
@@ -897,7 +957,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	if (!id)
 		goto out;
@@ -933,12 +993,8 @@
 {
 	int rc = 0;
 
-	if (out_buf == NULL) {
-		rc = 2;
-		goto out;
-	}
-	rc = sprintf(out_buf, "%i\n", id->level);
-      out:
+	if(id->level == -1) rc = sprintf(out_buf,"-\n");
+	else rc = sprintf(out_buf, "%i\n", id->level);
 	return rc;
 }
 
@@ -955,20 +1011,15 @@
 
 	if (*offset != 0)
 		goto out;
-	if ((rc = copy_from_user(input_buf, user_buf, 1)))
+	if (copy_from_user(input_buf, user_buf, 1)){
+		rc = -EFAULT;
 		goto out;
+	}
 	if (isdigit(input_buf[0])) {
 		int new_level = ((int) input_buf[0] - (int) '0');
-		if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
-			printk(KERN_INFO
-			       "debug: level %i is out of range (%i - %i)\n",
-			       new_level, 0, DEBUG_MAX_LEVEL);
-		} else {
-			id->level = new_level;
-			printk(KERN_INFO
-			       "debug: set new level %i for %s\n",
-			       id->level, id->name);
-		}
+		debug_set_level(id, new_level);
+	} else if(input_buf[0] == '-') {
+		debug_set_level(id, DEBUG_OFF_LEVEL);
 	} else {
 		printk(KERN_INFO "debug: level `%c` is not valid\n",
 		       input_buf[0]);
@@ -979,72 +1030,55 @@
 }
 
 /*
- * prints debug data in hex format
+ * prints debug header in raw format
  */
 
-static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
-			       char *out_buf, const char *in_buf)
+int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+                         int area, debug_entry_t * entry, char *out_buf)
 {
-	int i, rc = 0;
+        int rc;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size * 3;
-		goto out;
-	}
-	for (i = 0; i < id->buf_size; i++) {
-		rc += sprintf(out_buf + rc, "%02x ",
-			      ((unsigned char *) in_buf)[i]);
-	}
-      out:
-	return rc;
+	rc = sizeof(debug_entry_t);
+	memcpy(out_buf,entry,sizeof(debug_entry_t));
+        return rc;
 }
 
 /*
- * prints debug data in ascii format
+ * prints debug data in raw format
  */
 
-static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, 
-				 char *out_buf, const char *in_buf)
+static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+			       char *out_buf, const char *in_buf)
 {
-	int i, rc = 0;
+	int rc;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size;
-		goto out;
-	}
-	for (i = 0; i < id->buf_size; i++) {
-		unsigned char c = in_buf[i];
-		if (!isprint(c))
-			rc += sprintf(out_buf + rc, ".");
-		else
-			rc += sprintf(out_buf + rc, "%c", c);
-	}
-      out:
+	rc = id->buf_size;
+	memcpy(out_buf, in_buf, id->buf_size);
 	return rc;
 }
 
 /*
- * prints debug data in ebcdic format
+ * prints debug data in hex/ascii format
  */
 
-static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, 
-				  char *out_buf, const char *in_buf)
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+		    		  char *out_buf, const char *in_buf)
 {
 	int i, rc = 0;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size;
-		goto out;
-	}
+	for (i = 0; i < id->buf_size; i++) {
+                rc += sprintf(out_buf + rc, "%02x ",
+                              ((unsigned char *) in_buf)[i]);
+        }
+	rc += sprintf(out_buf + rc, "| ");
 	for (i = 0; i < id->buf_size; i++) {
 		unsigned char c = in_buf[i];
-		EBCASC(&c, 1);
 		if (!isprint(c))
 			rc += sprintf(out_buf + rc, ".");
 		else
 			rc += sprintf(out_buf + rc, "%c", c);
 	}
-      out:
+	rc += sprintf(out_buf + rc, "\n");
 	return rc;
 }
 
@@ -1060,12 +1094,9 @@
 	char *except_str;
 	unsigned long caller;
 	int rc = 0;
+	unsigned int level;
 
-	if (out_buf == NULL) {
-		rc = DEBUG_PROC_HEADER_SIZE;
-		goto out;
-	}
-
+	level = entry->id.fields.level;
 	time = entry->id.stck;
 	/* adjust todclock to 1970 */
 	time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
@@ -1076,14 +1107,61 @@
 	else
 		except_str = "-";
 	caller = (unsigned long) entry->caller;
-#if defined(CONFIG_ARCH_S390)
+#if defined(CONFIG_ARCH_S390X)
+	rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx  ",
+		      area, time_val.tv_sec, time_val.tv_usec, level,
+		      except_str, entry->id.fields.cpuid, caller);
+#else
 	caller &= 0x7fffffff;
-	rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx  ",
-		      area, time_val.tv_sec,
-		      time_val.tv_usec, except_str,
-		      entry->id.fields.cpuid, caller);
+	rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx  ",
+		      area, time_val.tv_sec, time_val.tv_usec, level,
+		      except_str, entry->id.fields.cpuid, caller);
 #endif
-      out:
+	return rc;
+}
+
+/*
+ * prints debug data sprintf-formated:
+ * debug_sprinf_event/exception calls must be used together with this view
+ */
+
+#define DEBUG_SPRINTF_MAX_ARGS 10
+
+int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+                            char *out_buf, debug_sprintf_entry *curr_event)
+{
+	int num_longs, num_used_args = 0,i, rc = 0;
+	int index[DEBUG_SPRINTF_MAX_ARGS];
+
+	/* count of longs fit into one entry */
+	num_longs = id->buf_size /  sizeof(long); 
+
+	if(num_longs < 1)
+		goto out; /* bufsize of entry too small */
+	if(num_longs == 1) {
+		/* no args, we use only the string */
+		strcpy(out_buf, curr_event->string);
+		rc = strlen(curr_event->string);
+		goto out;
+	}
+
+	/* number of arguments used for sprintf (without the format string) */
+	num_used_args   = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
+
+	memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
+
+	for(i = 0; i < num_used_args; i++)
+		index[i] = i;
+
+	rc =  sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
+		curr_event->args[index[1]], curr_event->args[index[2]],
+		curr_event->args[index[3]], curr_event->args[index[4]],
+		curr_event->args[index[5]], curr_event->args[index[6]],
+		curr_event->args[index[7]], curr_event->args[index[8]],
+		curr_event->args[index[9]]);
+
+out:
+
 	return rc;
 }
 
@@ -1118,3 +1196,17 @@
 }
 
 #endif			/* MODULE */
+
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister); 
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event_common);
+EXPORT_SYMBOL(debug_exception_common);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
+EXPORT_SYMBOL(debug_sprintf_view);
+EXPORT_SYMBOL(debug_sprintf_exception);
+EXPORT_SYMBOL(debug_sprintf_event);
diff -urN linux-2.2.19-pre13/arch/s390/kernel/ebcdic.c linux/arch/s390/kernel/ebcdic.c
--- linux-2.2.19-pre13/arch/s390/kernel/ebcdic.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/ebcdic.c	Mon Dec  3 21:07:19 2001
@@ -9,6 +9,7 @@
  *               Martin Peschke <peschke@fh-brandenburg.de>
  */
 
+#include <linux/module.h>
 #include <asm/types.h>
 
 /*
@@ -389,3 +390,11 @@
 	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
 	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
 };
+
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
diff -urN linux-2.2.19-pre13/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- linux-2.2.19-pre13/arch/s390/kernel/entry.S	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/entry.S	Mon Dec  3 21:07:19 2001
@@ -148,11 +148,11 @@
         xc      0(4,%r15),0(%r15)     ; /* clear back chain */
 
 #define RESTORE_ALL \
-        mvc     __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
+        mvc     __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
         lam     %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
-        lm      %r0,%r15,SP_R0(%r15)      ; /* load gprs 0-15 of user */ \
-        ni      __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
-        lpsw    __LC_RETURN_PSW             /* back to caller */
+        lm      %r0,%r15,SP_R0(%r15)    ; /* load gprs 0-15 of user */ \
+        ni      __LC_RETURN_PSW+1,0xfd  ; /* clear wait state bit */ \
+        lpsw    __LC_RETURN_PSW           /* back to caller */
 
 #define GET_CURRENT /* load pointer to task_struct to R9 */ \
 	lr      %r9,%r15 ;  \
diff -urN linux-2.2.19-pre13/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- linux-2.2.19-pre13/arch/s390/kernel/head.S	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/head.S	Mon Dec  3 21:07:19 2001
@@ -5,7 +5,7 @@
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
- *               Rob van der Heij
+ *               Rob van der Heij (rvdhei@iae.nl)
  *
  * There are 5 different IPL methods
  *  1) load the image directly into ram at address 0 and do an PSW restart
@@ -13,11 +13,18 @@
  *     and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
  *  3) generate the tape ipl header, store the generated image on a tape
  *     and ipl from it
+ *     In case of SL tape you need to IPL 5 times to get past VOL1 etc
  *  4) generate the vm reader ipl header, move the generated image to the
  *     VM reader (use option NOH!) and do a ipl from reader (VM only)
  *  5) direct call of start by the SALIPL loader
  *  We use the cpuid to distinguish between VM and native ipl
  *  params for kernel are pushed to 0x10400 (see setup.h)
+
+    Changes: 
+    Okt 25 2000 <rvdheij@iae.nl>
+	added code to skip HDR and EOF to allow SL tape IPL (5 retries)
+	changed first CCW from rewind to backspace block
+
  */
 
 #include <linux/config.h>
@@ -32,7 +39,7 @@
 #define IPL_BS 1024
         .org   0
         .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
-        .long  0x07000000,0x60000001           # by ipl to addresses 0-23.
+        .long  0x27000000,0x60000001           # by ipl to addresses 0-23.
         .long  0x02000000,0x20000000+IPL_BS    # (a PSW and two CCWs).
         .long  0x00000000,0x00000000           # external old psw
         .long  0x00000000,0x00000000           # svc old psw
@@ -140,7 +147,7 @@
 .Lcrash:.long  0x000a0000,0x00000000
 .Lldret:.long  0
 .Lsnsret: .long 0
-#endif  /* CONFIG_IPL_NONE */
+#endif  /* CONFIG_IPL_TAPE */
 
 #ifdef CONFIG_IPL_VM
 #define IPL_BS 0x730
@@ -260,6 +267,7 @@
 #
 # load parameter file from ipl device
 #
+.Lagain1:
  	l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
         bas   %r14,.Lloader                    # load parameter file
         ltr   %r2,%r2                          # got anything ?
@@ -269,6 +277,10 @@
 	la    %r2,895
 .Lnotrunc:
 	l     %r4,INITRD_START-PARMAREA(%r12)
+	clc   0(3,%r4),.L_hdr		       # if it is HDRx
+	bz    .Lagain1			       # skip dataset header
+	clc   0(3,%r4),.L_eof		       # if it is EOFx
+	bz    .Lagain1			       # skip dateset trailer
         la    %r5,0(%r4,%r2)
         lr    %r3,%r2
 .Lidebc:
@@ -306,6 +318,7 @@
 #
 # load ramdisk from ipl device
 #	
+.Lagain2:
  	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
         bas   %r14,.Lloader                    # load ramdisk
  	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
@@ -313,6 +326,12 @@
         bnz   .Lrdcont
         st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
 .Lrdcont:
+	l     %r2,INITRD_START-PARMAREA(%r12)
+
+	clc   0(3,%r2),.L_hdr		       # skip HDRx and EOFx 
+	bz    .Lagain2
+	clc   0(3,%r2),.L_eof
+	bz    .Lagain2
 
 #ifdef CONFIG_IPL_VM
 #
@@ -340,7 +359,8 @@
 .Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
         .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
         .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
-
+.L_eof:	.long  0xc5d6c600	/* C'EOF' */
+.L_hdr:	.long  0xc8c4d900	/* C'HDR' */
 #endif  /* CONFIG_IPL */
 
 #
@@ -375,7 +395,7 @@
 	.long 0x83300060		# diag 3,0,x'0060' - storage size
 	b     .done
 .test:
-	mvc   0x68(8,0),.pgmnw		# set up pgm check handler
+	mvc   0x68(8),.pgmnw		# set up pgm check handler
 	l     %r2,.fourmeg
 	lr    %r3,%r2
 	bctr  %r3,%r0			# 4M-1
@@ -443,7 +463,7 @@
 #
 # find out memory size.
 #
-	mvc   104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
+	mvc   104(8),.Lpcmem-.LPG1(%r13) # setup program check handler
         slr   %r1,%r1
         lhi   %r2,1
         sll   %r2,20
@@ -507,7 +527,7 @@
 #
 # find out if we have an IEEE fpu
 #
-        mvc    104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+        mvc    104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler
         ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
         ldr    %f2,%f0
         adbr   %f0,%f2                  # test IEEE add instruction
@@ -517,7 +537,7 @@
 #
 # find out if we have the CSP instruction
 #
-       mvc    104(8,0),.Lpccsp-.LPG1(%r13) # setup program check handler
+       mvc    104(8),.Lpccsp-.LPG1(%r13) # setup program check handler
        la     %r0,0
        lr     %r1,%r0
        la     %r2,.Lflt0-.LPG1(%r13)
diff -urN linux-2.2.19-pre13/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- linux-2.2.19-pre13/arch/s390/kernel/irq.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/irq.c	Mon Dec  3 21:07:19 2001
@@ -11,6 +11,7 @@
  *  S/390 I/O interrupt processing and I/O request processing is
  *   implemented in arch/s390/kernel/s390io.c
  */
+#include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -426,3 +427,12 @@
 
 }
 
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(s390_bh_lock);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(synchronize_bh);
+#endif
diff -urN linux-2.2.19-pre13/arch/s390/kernel/reipl.S linux/arch/s390/kernel/reipl.S
--- linux-2.2.19-pre13/arch/s390/kernel/reipl.S	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/reipl.S	Mon Dec  3 21:07:19 2001
@@ -16,7 +16,7 @@
                 ni      .Lctlsave-.Lpg0(%r13),0xef
                 lctl    %c0,%c0,.Lctlsave-.Lpg0(%r13)
                 lr      %r1,%r2
-        	mvc     __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13)
+        	mvc     __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
                 stsch   .Lschib-.Lpg0(%r13)                                    
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
@@ -24,9 +24,9 @@
 		ssch	.Liplorb-.Lpg0(%r13)           
 		jz	.L001   
 		bas	%r14,.Ldisab-.Lpg0(%r13)
-.L001:		mvc	__LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13)	
+.L001:		mvc	__LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpsw	.Lwaitpsw-.Lpg0(%r13)          
-.Lcont:		c	%r1,__LC_SUBCHANNEL_ID(%r0)
+.Lcont:		c	%r1,__LC_SUBCHANNEL_ID
 		jnz	.Ltpi
 		clc	__LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
 		jnz	.Ltpi
@@ -38,7 +38,7 @@
                 jz      .L003
                 bas     %r14,.Ldisab-.Lpg0(%r13)	
 .L003:		spx	.Lnull-.Lpg0(%r13)
-		st 	%r1,__LC_SUBCHANNEL_ID(%r0)	
+		st 	%r1,__LC_SUBCHANNEL_ID
                 lpsw 	0
 		sigp    0,0,0(6)               
 .Ldisab:	st      %r14,.Ldispsw+4-.Lpg0(%r13)
diff -urN linux-2.2.19-pre13/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c
--- linux-2.2.19-pre13/arch/s390/kernel/s390_ext.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/s390_ext.c	Mon Dec  3 21:07:19 2001
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/module.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -74,4 +75,6 @@
         return 0;
 }
 
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -urN linux-2.2.19-pre13/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- linux-2.2.19-pre13/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 21:06:37 2001
+++ linux/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 21:07:19 2001
@@ -3,73 +3,15 @@
  *
  *  S390 version
  */
-#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <asm/debug.h>
 #include <linux/genhd.h>
-#include <asm/ccwcache.h>
-#include <asm/irq.h>
-#include <asm/string.h>
 #include <asm/checksum.h>
-#include <asm/s390_ext.h>
-#include <asm/s390dyn.h>
-#include <asm/ebcdic.h>
-#include <asm/timex.h>
 #include <asm/delay.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
 
 /*
- * I/O subsystem
- */
-EXPORT_SYMBOL(halt_IO);
-EXPORT_SYMBOL(clear_IO);
-EXPORT_SYMBOL(do_IO);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(ioinfo);
-EXPORT_SYMBOL(get_dev_info_by_irq);
-EXPORT_SYMBOL(get_dev_info_by_devno);
-EXPORT_SYMBOL(get_irq_by_devno);
-EXPORT_SYMBOL(get_devno_by_irq);
-EXPORT_SYMBOL(get_irq_first);
-EXPORT_SYMBOL(get_irq_next);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
-EXPORT_SYMBOL(s390_request_irq_special);
-EXPORT_SYMBOL(s390_device_register);
-EXPORT_SYMBOL(s390_device_unregister);
-
-#ifdef	__SMP__
-EXPORT_SYMBOL(s390_bh_lock);
-#endif
-
-EXPORT_SYMBOL(ccw_alloc_request);
-EXPORT_SYMBOL(ccw_free_request);
-
-EXPORT_SYMBOL(register_external_interrupt);
-EXPORT_SYMBOL(unregister_external_interrupt);
-
-/* 
- * debug feature
- */
-EXPORT_SYMBOL(debug_register);
-EXPORT_SYMBOL(debug_unregister); 
-EXPORT_SYMBOL(debug_register_view);
-EXPORT_SYMBOL(debug_unregister_view);
-EXPORT_SYMBOL(debug_event);
-EXPORT_SYMBOL(debug_int_event);
-EXPORT_SYMBOL(debug_text_event);
-EXPORT_SYMBOL(debug_exception);
-EXPORT_SYMBOL(debug_int_exception);
-EXPORT_SYMBOL(debug_text_exception);
-EXPORT_SYMBOL(debug_hex_view);
-EXPORT_SYMBOL(debug_ascii_view);
-EXPORT_SYMBOL(debug_ebcdic_view);
-EXPORT_SYMBOL(debug_dflt_header_fn);
-
-/*
  * memory management
  */
 EXPORT_SYMBOL(init_mm);
@@ -94,32 +36,12 @@
 EXPORT_SYMBOL_NOVERS(strpbrk);
 EXPORT_SYMBOL_NOVERS(strstr);
 
-EXPORT_SYMBOL_NOVERS(_ascebc_500);
-EXPORT_SYMBOL_NOVERS(_ebcasc_500);
-EXPORT_SYMBOL_NOVERS(_ascebc);
-EXPORT_SYMBOL_NOVERS(_ebcasc);
-EXPORT_SYMBOL_NOVERS(_ebc_tolower);
-EXPORT_SYMBOL_NOVERS(_ebc_toupper);
-
 /*
  * misc.
  */
 EXPORT_SYMBOL(__copy_from_user_fixup);
 EXPORT_SYMBOL(__copy_to_user_fixup);
 EXPORT_SYMBOL(__udelay);
-#ifdef CONFIG_SMP
-#include <asm/smplock.h>
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(global_bh_lock);
-EXPORT_SYMBOL(synchronize_bh);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(smp_ctl_set_bit);
-EXPORT_SYMBOL(smp_ctl_clear_bit);
-EXPORT_SYMBOL(smp_do_callback_all);
-#endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(genhd_dasd_name);
diff -urN linux-2.2.19-pre13/arch/s390/kernel/s390dyn.c linux/arch/s390/kernel/s390dyn.c
--- linux-2.2.19-pre13/arch/s390/kernel/s390dyn.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/s390dyn.c	Mon Dec  3 21:07:19 2001
@@ -7,6 +7,7 @@
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 
@@ -204,3 +205,5 @@
 	return( pdevreg);
 }
 
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
diff -urN linux-2.2.19-pre13/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c
--- linux-2.2.19-pre13/arch/s390/kernel/s390io.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/s390io.c	Mon Dec  3 21:07:19 2001
@@ -8,6 +8,7 @@
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
@@ -126,7 +127,7 @@
                               not_oper_handler_func_t  not_oper_handler,
                               unsigned long            irqflags,
                               const char              *devname,
-                              void                    *dev_id)
+                              devstat_t               *dev_id)
 {
 	int               retval;
 	struct s390_irqaction *action;
@@ -204,7 +205,7 @@
                                    NULL,
                                    irqflags,
                                    devname,
-                                   dev_id);
+                                   (devstat_t *)dev_id);
 
 	if ( ret == 0 )
 	{
@@ -2041,6 +2042,7 @@
 	int               ending_status   = 0;
 	int               allow4handler   = 1;
 	int               chnchk          = 0;
+	devstat_t        *dp;
 #if 0
 	int               cpu             = smp_processor_id();
 
@@ -2058,7 +2060,8 @@
 		action = ioinfo[irq]->irq_desc.action;
 	
   	} /* endif */
-
+	dp  = &ioinfo[irq]->devstat;
+	
 #ifdef CONFIG_DEBUG_IO
 	/*
 	 * It might be possible that a device was not-oper. at the time
@@ -2176,8 +2179,22 @@
 		chnchk = 1;
 
 	} /* endif */
+	if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
+	     &&	(dp->ii.irb.scsw.eswf  == 0                     ))
+	{
+		issense = 0;
+	}
+	else if (    (dp->ii.irb.scsw.stctl ==
+	                (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
+	          && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0))
+	{
+		issense = 0;
+	}
+	else
+	{
+		issense = dp->ii.irb.esw.esw0.erw.cons;
 
-	issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;
+	} /* endif */
 
 	if ( issense )
 	{
@@ -5524,3 +5541,17 @@
 	do_reipl( 0x10000 | sch );
 }
 
+EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
+EXPORT_SYMBOL(do_IO);
+EXPORT_SYMBOL(resume_IO);
+EXPORT_SYMBOL(ioinfo);
+EXPORT_SYMBOL(get_dev_info_by_irq);
+EXPORT_SYMBOL(get_dev_info_by_devno);
+EXPORT_SYMBOL(get_irq_by_devno);
+EXPORT_SYMBOL(get_devno_by_irq);
+EXPORT_SYMBOL(get_irq_first);
+EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
diff -urN linux-2.2.19-pre13/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- linux-2.2.19-pre13/arch/s390/kernel/signal.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/signal.c	Mon Dec  3 21:07:19 2001
@@ -327,6 +327,11 @@
 #endif
 	/* Martin wants this for pthreads */
 	regs->gprs[3] = (addr_t)&frame->sc;
+
+	/* We forgot to include these in the sigcontext. 
+	   To avoid breaking binary compatibility, they are passed as args. */
+	regs->gprs[4] = current->tss.trap_no;
+	regs->gprs[5] = current->tss.prot_addr;
 	return;
 
 give_sigsegv:
@@ -383,7 +388,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	/* Are we from a system call? */
-	if (regs->orig_gpr2 >= 0) {
+	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
 			case -ERESTARTNOHAND:
diff -urN linux-2.2.19-pre13/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- linux-2.2.19-pre13/arch/s390/kernel/smp.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/kernel/smp.c	Mon Dec  3 21:07:19 2001
@@ -24,6 +24,7 @@
 #include <asm/timex.h>
 #include <asm/init.h>
 #include <asm/spinlock.h>
+#include <linux/module.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
@@ -721,3 +722,7 @@
         }
 }
 
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_do_callback_all);
diff -urN linux-2.2.19-pre13/arch/s390/lib/strcmp.S linux/arch/s390/lib/strcmp.S
--- linux-2.2.19-pre13/arch/s390/lib/strcmp.S	Tue Jan  4 10:12:12 2000
+++ linux/arch/s390/lib/strcmp.S	Mon Dec  3 21:07:19 2001
@@ -18,8 +18,8 @@
         CLST    2,3
         JO      .-4
         JE      strcmp_equal
-        IC      0,0(0,3)
-        IC      1,0(0,2)
+        IC      0,0(3)
+        IC      1,0(2)
         SR      1,0
 strcmp_equal:
         LR      2,1
diff -urN linux-2.2.19-pre13/arch/s390/lib/strncpy.S linux/arch/s390/lib/strncpy.S
--- linux-2.2.19-pre13/arch/s390/lib/strncpy.S	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/lib/strncpy.S	Mon Dec  3 21:07:19 2001
@@ -20,9 +20,9 @@
 	SR      0,0
 strncpy_loop:
         ICM     0,1,0(3)       # ICM sets the cc, IC does not
-	LA      3,1(0,3)
-        STC     0,0(0,1)
-	LA      1,1(0,1)
+	LA      3,1(3)
+        STC     0,0(1)
+	LA      1,1(1)
         JZ      strncpy_exit   # ICM inserted a 0x00
         BRCT    4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0
 strncpy_exit:
diff -urN linux-2.2.19-pre13/arch/s390/mm/init.c linux/arch/s390/mm/init.c
--- linux-2.2.19-pre13/arch/s390/mm/init.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/mm/init.c	Mon Dec  3 21:07:19 2001
@@ -141,7 +141,7 @@
         if(pgtable_cache_size > high) {
                 do {
                         if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast()), freed++;
+                                free_pgd_slow(get_pgd_fast()), freed += 2;
                         if(pmd_quicklist)
                                 free_pmd_slow(get_pmd_fast()), freed++;
                         if(pte_quicklist)
diff -urN linux-2.2.19-pre13/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- linux-2.2.19-pre13/arch/s390/tools/dasdfmt/dasdfmt.c	Sun Dec 10 16:49:41 2000
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Mon Dec  3 21:07:19 2001
@@ -201,7 +201,7 @@
 
 	/*	fgets(line,sizeof(line),file); omit first line */ 
 	while (fgets(line,sizeof(line),file)!=NULL) {
-		rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
+		rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
 		ma=ma_i;
 		mi=mi_i;
 		if ( (rc==3) &&
@@ -219,7 +219,8 @@
 	fclose(file);
 
 	ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-		"filesystem (are you sure to have the right param line?)\n",
+		    "filesystem (are you sure to have the right parameter " \
+		    "dasd=xxx?)\n",
 		prog_name);
 }
 
diff -urN linux-2.2.19-pre13/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.2.19-pre13/drivers/block/genhd.c	Mon Dec  3 21:06:40 2001
+++ linux/drivers/block/genhd.c	Mon Dec  3 21:07:19 2001
@@ -1792,7 +1792,7 @@
 }
 
 #ifdef CONFIG_PROC_FS
-int get_partition_list(char * page)
+int get_partition_list(char *page, char **start, off_t offset, int count)
 {
 	struct gendisk *p;
 	char buf[MAX_DISKNAME_LEN];
@@ -1801,14 +1801,23 @@
 	len = sprintf(page, "major minor  #blocks  name\n\n");
 	for (p = gendisk_head; p; p = p->next) {
 		for (n=0; n < (p->nr_real << p->minor_shift); n++) {
-			if (p->part[n].nr_sects && len < PAGE_SIZE - 80) {
+			if (p->part[n].nr_sects) {
 				len += sprintf(page+len,
 					       "%4d  %4d %10d %s\n",
 					       p->major, n, p->sizes[n],
 					       disk_name(p, n, buf));
+				if (len < offset) 
+					offset -= len, len = 0;
+				else if (len >= offset + count)
+					goto leave_loops;
 			}
 		}
 	}
-	return len;
+leave_loops:
+	*start = page + offset;
+	len -= offset;
+	if (len < 0)
+		len = 0;
+	return len > count ? count : len;
 }
 #endif
diff -urN linux-2.2.19-pre13/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- linux-2.2.19-pre13/drivers/isdn/Config.in	Mon Dec  3 21:06:42 2001
+++ linux/drivers/isdn/Config.in	Mon Dec  3 21:07:20 2001
@@ -16,9 +16,7 @@
 if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
    bool '    Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
 fi
-
-#  CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y
-if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then
+if [ "$CONFIG_X25" != "n" ]; then
    bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
 fi
 
@@ -91,9 +89,18 @@
 dep_tristate       'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
 dep_tristate       'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
 
-dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+bool               'Eicon active card support' CONFIG_ISDN_DRV_EICON
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
-   bool '  Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+   if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
+      dep_tristate '  Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN
+   fi
+   if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
+      dep_tristate '  Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
+      if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
+         dep_bool  '    Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
+         bool      '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+      fi
+   fi
 fi
 
 # CAPI subsystem
diff -urN linux-2.2.19-pre13/drivers/isdn/Makefile linux/drivers/isdn/Makefile
--- linux-2.2.19-pre13/drivers/isdn/Makefile	Mon Dec  3 21:06:42 2001
+++ linux/drivers/isdn/Makefile	Mon Dec  3 21:07:20 2001
@@ -32,7 +32,7 @@
 
 # Object files in subdirectories
 
-mod-subdirs				:= avmb1
+mod-subdirs				:= avmb1 eicon
 subdir-$(CONFIG_ISDN_DIVERSION)		+= divert
 subdir-$(CONFIG_ISDN_DRV_HISAX)		+= hisax
 subdir-$(CONFIG_ISDN_DRV_ICN)		+= icn
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/Divas_mod.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/Divas_mod.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,151 @@
+
+/*
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#undef N_DATA
+
+#include <linux/kernel.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <errno.h>
+
+#include "adapter.h"
+#include "uxio.h"
+
+#include <linux/isdn_compat.h>
+
+#ifdef MODULE
+#include "idi.h"
+void DIVA_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#endif
+
+int DivasCardsDiscover(void);
+
+static int __init
+divas_init(void)
+{
+	printk(KERN_DEBUG "DIVA Server Driver - initialising\n");
+	
+	printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n");
+
+
+#if !defined(CONFIG_PCI)
+	printk(KERN_WARNING "CONFIG_PCI is not defined!\n");
+	return -ENODEV;
+#endif
+
+	if (pci_present())
+	{
+		if (DivasCardsDiscover() < 0)
+		{
+			printk(KERN_WARNING "Divas: Not loaded\n");
+			return -ENODEV;
+		}
+	}
+	else
+	{
+		printk(KERN_WARNING "Divas: No PCI bus present\n");
+		return -ENODEV;
+	}
+
+    return 0;
+}
+
+static void 
+divas_exit(void)
+{
+	card_t *pCard;
+	word wCardIndex;
+	extern int Divas_major;
+
+	printk(KERN_DEBUG "DIVA Server Driver - unloading\n");
+
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+		if ((pCard->hw) && (pCard->hw->in_use))
+		{
+
+			(*pCard->card_reset)(pCard);
+			
+			UxIsrRemove(pCard->hw, pCard);
+			UxCardHandleFree(pCard->hw);
+
+			if(pCard->e_tbl != NULL)
+			{
+				kfree(pCard->e_tbl);
+			}
+
+			
+			if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+			{	
+				release_region(pCard->hw->io_base,0x20);		
+				release_region(pCard->hw->reset_base,0x80);		
+			}
+
+			// If this is a 4BRI ...
+			if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+			{
+				// Skip over the next 3 virtual adapters
+				wCardIndex += 3;
+
+				// But free their handles 
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+			
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+				
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+				
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+				
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+				
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+			}
+		}
+		pCard++;
+	}
+
+	unregister_chrdev(Divas_major, "Divas");
+}
+
+module_init(divas_init);
+module_exit(divas_exit);
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile
--- linux-2.2.19-pre13/drivers/isdn/eicon/Makefile	Mon Dec  3 21:06:42 2001
+++ linux/drivers/isdn/eicon/Makefile	Mon Dec  3 21:07:21 2001
@@ -6,20 +6,37 @@
 
 # Objects that export symbols.
 
-export-objs	:= eicon_mod.o
+export-objs	:= Divas_mod.o eicon_mod.o
 
 # Multipart objects.
 
-list-multi	:= eicon.o
-eicon-objs	:= eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+list-multi	:= eicon.o divas.o
+eicon-objs	:= eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \
+		   eicon_io.o
+divas-objs	:= common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \
+		   fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o
+
+# Optional parts of multipart objects.
+
+eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \
+		   xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \
+		   linsys.o linio.o
+
+eicon-objs 	+= $(eicon-objs-y)
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_ISDN_DRV_EICON)    	+= eicon.o
+obj-$(CONFIG_ISDN_DRV_EICON_OLD)    	+= eicon.o
+obj-$(CONFIG_ISDN_DRV_EICON_DIVAS)	+= divas.o
 
-include $(TOPDIR)/Rules.make
+include $(TOPDIR)/drivers/isdn/Rules.make
 
 # Link rules for multi-part drivers.
 
 eicon.o: $(eicon-objs)
 	$(LD) -r -o $@ $(eicon-objs)
+
+divas.o: $(divas-objs)
+	$(LD) -r -o $@ $(divas-objs)
+
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/adapter.h linux/drivers/isdn/eicon/adapter.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/adapter.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/adapter.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,262 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.7  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Main internal include file for Diva Server driver */
+
+#if !defined(ADAPTER_H)
+#define ADAPTER_H
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+
+#define XMOREC 0x1f
+#define XMOREF 0x20
+#define XBUSY  0x40
+#define RMORE  0x80
+
+        /* structure for all information we have to keep on a per   */
+        /* adapater basis                                           */
+
+typedef struct adapter_s ADAPTER;
+
+struct adapter_s {
+  void * io;
+
+  byte IdTable[256];
+  byte ReadyInt;
+
+  byte (* ram_in)(ADAPTER * a, void * adr);
+  word (* ram_inw)(ADAPTER * a, void * adr);
+  void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length);
+  void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+
+  void (* ram_out)(ADAPTER * a, void * adr, byte data);
+  void (* ram_outw)(ADAPTER * a, void * adr, word data);
+  void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length);
+
+  void (* ram_inc)(ADAPTER * a, void * adr);
+};
+
+typedef struct card card_t;
+
+typedef int	card_load_fn_t(card_t *card, dia_load_t *load);
+typedef int	card_config_fn_t(card_t *card, dia_config_t *config);
+typedef int	card_start_fn_t(card_t *card, byte *channels);
+typedef	int	card_reset_fn_t(card_t *card);
+typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block);
+
+#define	MAX_PENTITIES	256		/* Number of entities primary adapter */
+#define MAX_ENTITIES	16		/* Number of entities standard adapter */
+
+typedef struct e_info_s E_INFO;
+
+struct e_info_s
+{
+	ENTITY		*e;				/* entity pointer */
+	byte		next;			/* chaining index */
+	word		assign_ref;		/* assign reference */
+};
+
+/* DIVA card info (details hidden from user) */
+
+typedef struct	ux_diva_card_s ux_diva_card_t;
+
+/* card info */
+
+struct card
+{
+	ADAPTER				a;				/* per-adapter information */
+	dia_card_t			cfg;			/* card configuration */
+	int 				state;			/* State of the adapter */
+	dword 				serial_no;		/* serial number */
+	int 				test_int_pend;	/* set for interrupt testing */
+	ux_diva_card_t		*hw;			/* O/S-specific handle */
+	card_reset_fn_t		*card_reset;	/* call this to reset card */
+	card_load_fn_t		*card_load;		/* call this to load card */
+	card_config_fn_t	*card_config;	/* call this to config card */
+	card_start_fn_t		*card_start;	/* call this to start card */
+	card_mem_get_fn_t	*card_mem_get;	/* call this to get card memory */
+	E_INFO				*e_tbl;			/* table of ENTITY pointers */
+	byte				e_head;			/* list of active ENTITIES */
+	byte				e_tail;			/* list of active ENTITIES */
+	int					e_count;		/* # of active ENTITIES */
+	int					e_max;			/* total # of ENTITIES */
+	byte				assign;			/* assign queue entry */
+	PBUFFER				RBuffer;		/* Copy of receive lookahead buffer */
+	int					log_types;		/* bit-mask of active logs */
+	word				xlog_offset;	/* offset to XLOG buffer on card */
+	void		(*out)(ADAPTER *a);
+	byte		(*dpc)(ADAPTER * a);
+	byte		(*test_int)(ADAPTER * a);
+	void		(*clear_int)(ADAPTER * a);
+	void		(*reset_int)(card_t *c);
+	int  		is_live;
+
+	int		(*card_isr)(card_t *card);
+
+	int 		int_pend;		/* interrupt pending */
+	long		interrupt_reentered;
+	long 		dpc_reentered;
+	int 		set_xlog_request;
+
+} ;
+
+/* card information */
+
+#define	MAX_CARDS	20		/* max number of cards on a system */
+
+extern
+card_t			DivasCards[];
+
+extern
+int				DivasCardNext;
+
+extern
+dia_config_t	DivasCardConfigs[];
+
+extern
+byte 			DivasFlavourConfig[];
+
+/*------------------------------------------------------------------*/
+/* public functions of IDI common code                              */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a);
+byte DivasDpc(ADAPTER * a);
+byte DivasTestInt(ADAPTER * a);
+void DivasClearInt(ADAPTER * a);
+
+/*------------------------------------------------------------------*/
+/* public functions of configuration platform-specific code         */
+/*------------------------------------------------------------------*/
+
+int DivasConfigGet(dia_card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of LOG related code                             */
+/*------------------------------------------------------------------*/
+
+void	DivasXlogReq(int card_num);
+int		DivasXlogRetrieve(card_t *card);
+void	DivasLog(dia_log_t *log);
+void	DivasLogIdi(card_t *card, ENTITY *e, int request);
+
+/*------------------------------------------------------------------*/
+/* public functions to initialise cards for each type supported     */
+/*------------------------------------------------------------------*/
+
+int		DivasPriInit(card_t *card, dia_card_t *cfg);
+
+int		DivasBriInit(card_t *card, dia_card_t *cfg);
+int		Divas4BriInit(card_t *card, dia_card_t *cfg);
+void 	DivasBriPatch(card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of log common code                              */
+/*------------------------------------------------------------------*/
+
+extern	char	*DivasLogFifoRead(void);
+extern	void	DivasLogFifoWrite(char *entry, int length);
+extern	int		DivasLogFifoEmpty(void);
+extern	int		DivasLogFifoFull(void);
+extern	void    DivasLogAdd(void *buffer, int length);
+
+/*------------------------------------------------------------------*/
+/* public functions of misc. platform-specific code         		*/
+/*------------------------------------------------------------------*/
+
+int		DivasDpcSchedule(void);
+void		DivasDoDpc(void *);
+void		DivasDoRequestDpc(void *pData);
+int		DivasScheduleRequestDpc(void);
+
+/* table of IDI request functions */
+
+extern
+IDI_CALL	DivasIdiRequest[];
+
+/*
+ * intialisation entry point
+ */
+
+int		DivasInit(void);
+
+/*
+ * Get information on the number and type of cards present
+ */
+
+extern
+int 	DivasCardsDiscover(void);
+
+/*
+ * initialise a new card
+ */
+
+int		DivasCardNew(dia_card_t *card);
+
+/*
+ * configure specified card
+ */
+
+int		DivasCardConfig(dia_config_t *config);
+
+/*
+ * load specified binary code onto card
+ */
+
+int		DivasCardLoad(dia_load_t *load);
+
+/*
+ * start specified card running
+ */
+
+int		DivasCardStart(int card_id);
+
+/*
+ * ISR for card
+ * Returns 0 if specified card was interrupting
+ */
+
+int		DivasIsr(void *arg);
+
+/*
+ * Get number of active cards
+ */
+
+int		DivasGetNum(void);
+
+/*
+ * Get list of active cards
+ */
+
+int		DivasGetList(dia_card_list_t *card_list);
+
+/* definitions common to several card types */
+
+#define DIVAS_SHARED_OFFSET     (0x1000)
+
+#endif /* ADAPTER_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/bri.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/bri.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,714 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.8  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+#include <sys/types.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define PCI_COMMAND	0x04
+#define PCI_STATUS	0x06
+#define PCI_LATENCY	0x0D
+#define PCI_BADDR0	0x10
+#define PCI_BADDR1	0x14
+#define PCI_BADDR2	0x18
+
+#define DIVAS_SIGNATURE 0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define	DIVAS_MAINT_OFFSET	0xff00		/* value for BRI card */
+
+#define PROTCAP_TELINDUS	0x1
+#define PROTCAP_V90D		0x8
+
+word GetProtFeatureValue(char *sw_id);
+byte io_in(ADAPTER *a, void *adr);
+word io_inw(ADAPTER *a, void *adr);
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void io_out(ADAPTER *a, void *adr, byte data);
+void io_outw(ADAPTER *a, void *adr, word data);
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_inc(ADAPTER *a, void *adr);
+
+static int diva_server_bri_test_int(card_t *card);
+static int bri_ISR (card_t* card);
+
+#define PLX_IOBASE		0
+#define	DIVAS_IOBASE	1
+
+#define	REG_DATA		0x00
+#define	REG_ADDRLO		0x04
+#define REG_ADDRHI		0x0C
+#define REG_IOCTRL		0x10
+
+#define M_PCI_RESET	0x10
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg);
+
+static
+int	diva_server_bri_reset(card_t *card)
+{
+	byte *DivasIOBase;
+	word i;
+	dword dwWait;
+
+	UxCardLog(0);
+
+	DPRINTF(("divas: resetting BRI adapter"));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0);
+
+	for (i=0; i < 50000; i++)
+		;
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA  , 0);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000);
+
+	for (i=0; i<0x8000; i++)
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
+	}
+
+	for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++)
+		;
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return 0;
+}
+
+static
+void diva_server_bri_reset_int(card_t *card)
+{
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return;
+}
+
+static
+int diva_server_bri_start(card_t *card, byte *channels)
+{
+	byte *DivasIOBase, *PLXIOBase;
+	word wSig = 0;
+	word i;
+	dword dwSerialNum;
+	byte bPLX9060 = FALSE;
+
+	DPRINTF(("divas: starting Diva Server BRI card"));
+
+	card->is_live = FALSE;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA  , 0);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA  , 0);
+	
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+	/* wait for signature to indicate card has started */
+	for (i = 0; i < 300; i++)
+	{
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+		wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+		if (wSig == DIVAS_SIGNATURE)
+		{
+			DPRINTF(("divas: card started after %d ms", i * 10));
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (wSig != DIVAS_SIGNATURE)
+	{
+		DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig));
+		UxCardMemDetach(card->hw, DivasIOBase);
+		return -1;
+	}
+
+	card->is_live = TRUE;
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6);
+	*channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+	bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+	if (bPLX9060)
+	{ 
+		dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | 
+					(UxCardPortIoInW(card->hw, PLXIOBase, 0x22));
+		DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum));
+	}
+	else
+	{
+		dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | 
+					(UxCardPortIoInW(card->hw, PLXIOBase, 0x26));
+		DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum));
+	}
+
+	UxCardMemDetach(card->hw, PLXIOBase);
+
+	card->serial_no = dwSerialNum;
+
+	diva_server_bri_test_int(card);
+	
+	return 0;
+}
+
+static
+int diva_server_bri_load(card_t *card, dia_load_t *load)
+{
+	byte *DivasIOBase;
+	dword r3000_base;
+	dword dwAddr, dwLength, i;
+	word wTest, aWord;
+
+	DPRINTF(("divas: loading Diva Server BRI card"));
+
+	switch (load->code_type)
+	{
+		case DIA_CPU_CODE:
+		DPRINTF(("divas: loading RISC %s", &load->code[0x80]));
+
+		card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+		DPRINTF(("divas: features 0x%x", card->hw->features));
+		if (card->hw->features == 0xFFFF)
+		{
+			DPRINTF(("divas: invalid feature string failed load\n"));
+			return -1;
+		}
+
+		r3000_base = 0;
+		break;
+
+		case DIA_DSP_CODE:
+		DPRINTF(("divas: DSP code \"%s\"", load->code));
+
+		if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS)))
+		{
+			DPRINTF(("divas: only Telindus style binaries supported"));
+			return -1;
+		}
+
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			DPRINTF(("divas: V.90 DSP binary"));
+			r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+		}
+		else
+		{
+			DPRINTF(("divas: non-V.90 DSP binary"));
+			r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+		}
+		DPRINTF(("divas: loading at 0x%x", r3000_base));
+		break;
+
+		case DIA_TABLE_CODE:
+		DPRINTF(("divas: TABLE code"));
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			r3000_base = 0xBF790000 + sizeof(dword);
+		}
+		else
+		{
+			r3000_base = 0xBF7A0000 + sizeof(dword);
+		}
+
+		break;
+
+		case DIA_DLOAD_CNT:
+		DPRINTF(("divas: COUNT code"));
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			r3000_base = 0xBF790000;
+		}
+		else
+		{
+			r3000_base = 0xBF7A0000;
+		}
+		break;
+
+		default:
+		DPRINTF(("divas: unknown code type %d", load->code_type));
+		return -1;
+		break;
+	}
+
+	DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	DPRINTF(("divas: Attached to 0x%04X", DivasIOBase));
+
+	dwLength = load->length;
+
+	for (i=0; i < dwLength; i++)
+	{
+		dwAddr = r3000_base + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]);
+	}
+
+	DPRINTF(("divas: Verifying"));
+
+	for (i=0; i<dwLength; i++)
+	{
+		dwAddr = r3000_base + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+		wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+
+		aWord = load->code[i];
+
+		if (wTest != aWord)
+		{
+			DPRINTF(("divas: load verify failed on byte %d", i));
+			DPRINTF(("divas: RAM 0x%x   File 0x%x",wTest,aWord));
+			
+			UxCardMemDetach(card->hw, DivasIOBase);
+
+			return -1;
+		}
+	}
+
+	DPRINTF(("divas: Loaded and verified. Detaching from adapter"));
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	UxCardLog(0);
+
+	return 0;
+}
+
+static
+int diva_server_bri_config(card_t *card, dia_config_t *config)
+{
+	byte *DivasIOBase, i;
+
+	DPRINTF(("divas: configuring Diva Server BRI card"));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+	{
+		DPRINTF(("divas: Signifying V.90"));
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4);
+	}
+	else
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+	}
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21);
+
+	for (i=0; i<32; i++)
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]);
+
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return 0;
+}
+
+void DivasBriPatch(card_t *card)
+{
+	dword	PLXIOBase = 0;
+	dword	DivasIOBase = 0;
+
+	PLXIOBase = card->cfg.reset_base;
+	DivasIOBase = card->cfg.io_base;
+
+	if(card->hw == NULL)
+	{
+		DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null"));
+		return;
+	}
+
+	if (PLXIOBase == 0)
+	{
+		DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may"));
+		DPRINTF(("Divas:   not function properly. If you do encounter problems,"));
+		DPRINTF(("Divas:   ensure that your machine is using the latest BIOS."));
+		return;
+	}
+
+	DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+	DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+	if (PLXIOBase & 0x80)
+	{
+		dword dwSize, dwSerialNum, dwCmd;
+		boolean_t bPLX9060;
+		word wSerHi, wSerLo;
+
+		DPRINTF(("Divas: Patch required"));
+		dwCmd = 0;
+		UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+		PLXIOBase &= ~0x80;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase);
+
+		dwSize = 0xFFFFFFFF;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize);
+		UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize);
+		
+		dwSize = (~ (dwSize & ~7)) + 1;
+
+		DivasIOBase = PLXIOBase + dwSize;
+
+		card->cfg.reset_base = PLXIOBase;
+		card->cfg.io_base = DivasIOBase;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base);
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base);
+
+		dwCmd = 5;
+		UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+		bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | 
+			   UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+		if (bPLX9060)
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+			UxCardLog(0);
+		}
+		else
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+			UxCardLog(0);
+		}
+	}
+	else
+	{
+		word wSerHi, wSerLo;
+		boolean_t bPLX9060;
+		dword dwSerialNum;
+
+		DPRINTF(("divas: No patch required"));
+
+		bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | 
+			   UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+		if (bPLX9060)
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+		}
+		else
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+		}
+	}
+	DPRINTF(("Divas: After patching:"));
+	DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+	DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+}
+
+#define TEST_INT_DIVAS_BRI	0x12
+static
+int	diva_server_bri_test_int(card_t *card)
+{
+	boolean_t bPLX9060 = FALSE;
+	byte *PLXIOBase = NULL, *DivasIOBase = NULL;
+
+	DPRINTF(("divas: test interrupt for Diva Server BRI card"));
+
+	PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+	bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+	if (bPLX9060)
+	{ /* PLX9060 */
+		UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09);
+	}
+	else
+	{ /* PLX9050 */
+		UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41);
+	}
+
+	card->test_int_pend = TEST_INT_DIVAS_BRI;
+
+	UxCardMemDetach(card->hw, PLXIOBase);
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+	
+	return 0;
+}
+
+static
+int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block)
+{
+	dword user_addr = mem_block->addr;
+	word	length = 0;
+	dword	addr;
+	word	i;
+	byte *DivasIOBase;
+
+	DPRINTF(("divas: Retrieving memory from 0x%x", user_addr));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	addr = user_addr;
+
+	for (i=0; i < (16 * 8); i++)
+	{
+		addr = user_addr + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr);
+
+		mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return length;
+}
+
+int DivasBriInit(card_t *card, dia_card_t *cfg)
+{
+	DPRINTF(("divas: initialise Diva Server BRI card"));
+
+	if (DivasBRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	card->card_reset 		= diva_server_bri_reset;
+	card->card_start 		= diva_server_bri_start;
+	card->card_load  		= diva_server_bri_load;
+	card->card_config		= diva_server_bri_config;
+	card->reset_int 		= diva_server_bri_reset_int;
+	card->card_mem_get 		= diva_server_bri_mem_get;
+
+	card->xlog_offset 		= DIVAS_MAINT_OFFSET;
+
+	card->out 			= DivasOut;
+	card->test_int 			= DivasTestInt;
+	card->dpc 			= DivasDpc;
+	card->clear_int 		= DivasClearInt;
+	card->card_isr 			= bri_ISR;
+
+	card->a.ram_out 		= io_out;
+	card->a.ram_outw 		= io_outw;
+	card->a.ram_out_buffer 	= io_out_buffer;
+	card->a.ram_inc 		= io_inc;
+
+	card->a.ram_in 			= io_in;
+	card->a.ram_inw 		= io_inw;
+	card->a.ram_in_buffer 	= io_in_buffer;
+	card->a.ram_look_ahead	= io_look_ahead;
+
+	return 0;
+}
+
+word GetProtFeatureValue(char *sw_id)
+{
+	word features = 0;
+
+	while ((*sw_id) && (sw_id[0] != '['))
+		sw_id++;
+
+	if (sw_id == NULL)
+	{
+		DPRINTF(("divas: no feature string present"));
+		features = -1;
+	}
+	else
+	{
+		byte i, shifter;
+
+		sw_id += 3;
+
+		for (i=0, shifter=12; i<4; i++, shifter-=4)
+		{
+			if ((sw_id[i] >= '0') && (sw_id[i] <= '9'))
+			{
+				features |= (sw_id[i] - '0') << shifter;
+			}
+			else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f'))
+			{
+				features |= (sw_id[i] - 'a' + 10) << shifter;
+			}
+			else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F'))
+			{
+				features |= (sw_id[i] - 'A' + 10) << shifter;
+			}
+			else
+			{
+				DPRINTF(("divas: invalid feature string"));
+				return -1;
+			}
+		}
+	}
+
+	return features;
+}
+
+
+int bri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) 
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); /* ISR DPC */
+		UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return (served != 0);
+}
+
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/common.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/common.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,896 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.15  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "uxio.h"
+#include <sys/types.h>
+
+#define MAX_ADDR_LEN
+
+#define DIVAS_LOAD_CMD		0x02
+#define DIVAS_START_CMD		0x03
+#define DIVAS_IRQ_RESET		0xC18
+#define DIVAS_IRQ_RESET_VAL	0xFE
+
+#define	PCI_COMMAND	0x04
+#define	PCI_STATUS	0x06
+#define	PCI_LATENCY	0x0D
+#define PCI_INTERRUPT	0x3C
+
+#define TEST_INT_DIVAS		0x11
+#define TEST_INT_DIVAS_BRI	0x12
+#define TEST_INT_DIVAS_Q	0x13
+
+#define DIVAS_RESET	0x81
+#define DIVAS_LED1	0x04
+#define DIVAS_LED2	0x08
+#define DIVAS_LED3	0x20
+#define DIVAS_LED4	0x40
+
+#define DIVAS_SIGNATURE 0x4447
+
+#define MP_PROTOCOL_ADDR 0xA0011000
+
+#define PLX_IOBASE	0
+#define	DIVAS_IOBASE	1
+
+typedef struct {
+		dword cmd;
+		dword addr;
+		dword len;
+		dword err;
+		dword live;
+		dword reserved[(0x1020>>2)-6];
+		dword signature;
+		byte  data[1];
+} diva_server_boot_t;
+
+int		DivasCardNext;
+card_t	DivasCards[MAX_CARDS];
+
+dia_config_t *DivasConfig(card_t *, dia_config_t *);
+
+static
+DESCRIPTOR DIDD_Table[32];
+
+void    DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength )
+{
+        bzero(table, tablelength);
+
+        if (tablelength > sizeof(DIDD_Table))
+          tablelength = sizeof(DIDD_Table);
+
+        if(tablelength % sizeof(DESCRIPTOR)) {
+          tablelength /= sizeof(DESCRIPTOR);
+          tablelength *= sizeof(DESCRIPTOR);
+        }
+
+        if (tablelength > 0)
+          bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength);
+
+	return;
+}
+
+void 	DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength)
+{
+        if (tablelength > sizeof(DIDD_Table))
+          tablelength = sizeof(DIDD_Table);
+
+	bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength);
+
+	return;
+}
+
+static
+void    init_idi_tab(void)
+{
+    DESCRIPTOR d[32];
+
+    bzero(d, sizeof(d));
+
+    d[0].type = IDI_DIMAINT;  /* identify the DIMAINT entry */
+    d[0].channels = 0; /* zero channels associated with dimaint*/
+    d[0].features = 0; /* no features associated with dimaint */
+    d[0].request = (IDI_CALL) DivasPrintf;
+    
+    DIVA_DIDD_Write(d, sizeof(d));
+
+    return;
+}
+
+/*
+ * I/O routines for memory mapped cards
+ */
+
+byte mem_in(ADAPTER *a, void *adr)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+	byte			value;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemIn(card->hw, m);
+
+	UxCardMemDetach(card->hw, b);
+
+	return value;
+}
+
+word mem_inw(ADAPTER *a, void *adr)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+	word			value;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemInW(card->hw, m);
+
+	UxCardMemDetach(card->hw, b);
+
+	return value;
+}
+
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemInBuffer(card->hw, m, P, length);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (dword) &RBuffer->length;
+	card->RBuffer.length = UxCardMemInW(card->hw, m);
+
+	m = b;
+	m += (dword) &RBuffer->P;
+	UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length);
+
+	e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_out(ADAPTER *a, void *adr, byte data)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOut(card->hw, m, data);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_outw(ADAPTER *a, void *adr, word data)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOutW(card->hw, m, data);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOutBuffer(card->hw, m, P, length);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_inc(ADAPTER *a, void *adr)
+{
+	word			value;
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemInW(card->hw, m);
+	value++;
+	UxCardMemOutW(card->hw, m, value);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+/*
+ * I/O routines for I/O mapped cards
+ */
+
+byte io_in(ADAPTER *a, void *adr)
+{
+	card_t		    *card = a->io;
+	byte		    value;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoIn(card->hw, DivasIOBase, adr);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return value;
+}
+
+word io_inw(ADAPTER *a, void *adr)
+{
+	card_t		*card = a->io;
+	word		value;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoInW(card->hw, DivasIOBase, adr);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return value;
+}
+
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t *card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+	card_t *card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer);
+
+	UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+    return;
+}
+
+void io_out(ADAPTER *a, void *adr, byte data)
+{
+	card_t		*card = a->io;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOut(card->hw, DivasIOBase, adr, data);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_outw(ADAPTER *a, void *adr, word data)
+{
+	card_t		*card = a->io;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOutW(card->hw, DivasIOBase, adr, data);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t		*card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_inc(ADAPTER *a, void *adr)
+{
+	word		value;
+	card_t		*card = a->io;
+	byte *DivasIOBase;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoInW(card->hw, DivasIOBase, adr);
+	
+	value++;
+
+	UxCardIoOutW(card->hw, DivasIOBase, adr, value);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+static
+void test_int(card_t *card)
+
+{
+	byte *shared, *DivasIOBase;
+
+	switch (card->test_int_pend)
+	{
+		case TEST_INT_DIVAS:
+			DPRINTF(("divas: test interrupt pending"));
+			shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+			if (UxCardMemIn(card->hw, &shared[0x3FE]))
+			{
+				UxCardMemOut(card->hw, 
+								&(((struct pr_ram *)shared)->RcOutput), 0);
+				UxCardMemDetach(card->hw, shared);
+            	(*card->reset_int)(card);
+				shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+				UxCardMemOut(card->hw, &shared[0x3FE], 0);
+				DPRINTF(("divas: test interrupt cleared"));
+			}
+
+			UxCardMemDetach(card->hw, shared);
+
+			card->test_int_pend = 0;
+			break;
+
+		case TEST_INT_DIVAS_BRI:
+			DPRINTF(("divas: BRI test interrupt pending"));
+			(*card->reset_int)(card);
+			DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+			UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0);
+			UxCardMemDetach(card->hw, DivasIOBase);
+			DPRINTF(("divas: test interrupt cleared"));
+			card->test_int_pend = 0;
+			break;
+
+		case TEST_INT_DIVAS_Q:
+			DPRINTF(("divas: 4BRI test interrupt pending"));
+			(*card->reset_int)(card);
+			card->test_int_pend = 0;
+			break;
+
+		default:
+			DPRINTF(("divas: unknown test interrupt pending"));
+			return;
+	}
+	return;
+}
+
+void card_isr (void *dev_id)
+{
+	card_t *card = (card_t *) dev_id;
+	ADAPTER *a = &card->a;
+	int ipl;
+
+	if (card->test_int_pend)
+	{
+		ipl = UxCardLock(card->hw);
+		card->int_pend=0;
+		test_int(card);
+		UxCardUnlock(card->hw,ipl);
+		return;
+	}
+	
+	if(card->card_isr)
+	{
+		(*(card->card_isr))(card);
+	}
+	else
+	{
+		ipl = UxCardLock(card->hw);
+	
+		if ((card->test_int)(a))
+		{
+			(card->reset_int)(card);
+		}
+		
+		UxCardUnlock(card->hw,ipl);
+		
+	}
+
+}
+
+int DivasCardNew(dia_card_t *card_info)
+{
+	card_t *card;
+	byte b;
+	static boolean_t first_call = TRUE;
+	boolean_t NeedISRandReset = FALSE;
+
+	DPRINTF(("divas: new card "));
+
+	if (first_call)
+	{
+		first_call = FALSE;
+		init_idi_tab();
+	}
+
+	DivasConfigGet(card_info);
+	
+	if (DivasCardNext == DIM(DivasCards))
+	{
+		KDPRINTF((KERN_WARNING "Divas: no space available for new card"));
+		return -1;
+	}
+
+	card = &DivasCards[DivasCardNext];
+
+	card->state = DIA_UNKNOWN;
+
+	card->cfg = *card_info;
+
+	card->a.io = card;
+
+	if (UxCardHandleGet(&card->hw, card_info))
+	{
+		KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card"));
+		return -1;
+	}
+
+	if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+	{
+		DivasBriPatch(card);
+		card_info->io_base = card->cfg.io_base;
+	}
+
+	switch (card_info->card_type)
+	{
+		case DIA_CARD_TYPE_DIVA_SERVER:
+			if (DivasPriInit(card, card_info))
+			{
+				return -1;
+			}
+			NeedISRandReset = TRUE;
+			break;
+
+		case DIA_CARD_TYPE_DIVA_SERVER_B:
+			if (DivasBriInit(card, card_info))
+			{
+				return -1;
+			}
+			NeedISRandReset = TRUE;
+			break;
+
+ 		case DIA_CARD_TYPE_DIVA_SERVER_Q:
+			if (Divas4BriInit(card, card_info))
+			{
+				return -1;
+			}
+
+			if (card_info->name[6] == '0')
+			{
+				NeedISRandReset = TRUE;
+			}
+			else // Need to set paramater for ISR anyway
+			{
+				card->hw->user_isr_arg = card;
+				card->hw->user_isr = card_isr;
+			}
+			break;   
+
+		default:
+			KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type));
+			return -1;
+	}
+
+	if (NeedISRandReset)
+	{
+		if (UxIsrInstall(card->hw, card_isr, card))
+		{
+			KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq));
+			UxCardHandleFree(card->hw);
+			return -1;
+		}
+
+		b = card->cfg.irq;
+
+		UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b);
+
+		if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
+		{
+			if ((*card->card_reset)(card))
+			{
+				KDPRINTF((KERN_WARNING "Divas: Adapter reset failed"));
+				return -1;
+			}
+			card->state = DIA_RESET;
+		}
+
+		NeedISRandReset = FALSE;
+	}
+
+	DivasCardNext++;
+
+	return 0;
+}
+
+void	*get_card(int card_id)
+{
+	int i;
+
+	for (i=0; i < DivasCardNext; i++)
+	{
+		if (DivasCards[i].cfg.card_id == card_id)
+		{
+			return(&DivasCards[i]);
+		}
+	}
+
+	DPRINTF(("divas: get_card() : no such card id (%d)", card_id));
+
+	return NULL;
+}
+
+int DivasCardConfig(dia_config_t *config)
+{
+	card_t *card;
+	int status;
+
+	DPRINTF(("divas: configuring card"));
+
+	card = get_card(config->card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	config = DivasConfig(card, config);
+
+	status = (*card->card_config)(card, config);
+
+	if (!status)
+	{
+		card->state = DIA_CONFIGURED;
+	}
+	return status;
+}
+
+int DivasCardLoad(dia_load_t *load)
+{
+	card_t *card;
+	int	status;
+
+	card = get_card(load->card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	if (card->state == DIA_RUNNING)
+	{
+		(*card->card_reset)(card);
+	}
+
+	status = (*card->card_load)(card, load);
+	if (!status)
+	{
+		card->state = DIA_LOADED;
+	}
+	return status;
+}
+
+static int idi_register(card_t *card, byte channels)
+{
+    DESCRIPTOR d[32];
+    int length, num_entities;
+
+	DPRINTF(("divas: registering card with IDI"));
+
+	num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES;
+	card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities);
+
+	if (!card->e_tbl)
+	{
+		KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available"));
+		return -1;
+	}
+
+	bzero(card->e_tbl, sizeof(E_INFO) * num_entities);
+	card->e_max = num_entities;
+
+    DIVA_DIDD_Read(d, sizeof(d));
+
+        for(length=0; length < DIM(d); length++)
+          if (d[length].type == 0) break;
+
+	if (length >= DIM(d))
+	{
+		KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full"));
+		return -1;
+	}
+
+	switch (card->cfg.card_type)
+	{
+		case DIA_CARD_TYPE_DIVA_SERVER:
+		d[length].type = IDI_ADAPTER_PR;
+		/* d[length].serial = card->serial_no; */
+		break;
+
+		case DIA_CARD_TYPE_DIVA_SERVER_B:
+		d[length].type = IDI_ADAPTER_MAESTRA;
+		/* d[length].serial = card->serial_no; */
+		break;
+
+		// 4BRI is treated as 4 BRI adapters
+		case DIA_CARD_TYPE_DIVA_SERVER_Q:
+		d[length].type = IDI_ADAPTER_MAESTRA;
+		/* d[length].serial = card->cfg.serial; */
+	}
+
+	d[length].features = 0;
+	d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120;
+
+	if ( card->hw->features & PROTCAP_MANIF )
+	{
+		d[length].features |= DI_MANAGE ;
+	}
+	if ( card->hw->features & PROTCAP_V_42 )
+	{
+		d[length].features |= DI_V_42 ;
+	}
+	if ( card->hw->features & PROTCAP_EXTD_FAX )
+	{
+		d[length].features |= DI_EXTD_FAX ;
+	}
+
+	d[length].channels = channels;
+	d[length].request = DivasIdiRequest[card - DivasCards];
+
+	length++;
+
+	DIVA_DIDD_Write(d, sizeof(d));
+
+    return 0;
+}
+
+int DivasCardStart(int card_id)
+{
+	card_t *card;
+	byte channels;
+	int status;
+
+	DPRINTF(("divas: starting card"));
+
+	card = get_card(card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	status = (*card->card_start)(card, &channels);
+	if (status)
+	{
+		return status;
+	}
+
+	/* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */
+	if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+	{
+		int i;
+		card_t *FourBRISlave;
+
+		for (i=3; i >= 0; i--)
+		{
+			FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */
+			if (FourBRISlave)
+			{
+				idi_register(FourBRISlave, 2);
+				FourBRISlave->state = DIA_RUNNING;
+			}
+		}
+		card->serial_no = card->cfg.serial;
+
+		DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", 
+				card_id - 3, card->serial_no, (int) channels));
+	}
+	else
+	{
+		status = idi_register(card, channels);
+		if (!status)
+		{
+			card->state = DIA_RUNNING;
+			DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", 
+						card_id, card->serial_no, (int) channels));
+		}
+	}
+
+	return status;
+}
+
+int DivasGetMem(mem_block_t *mem_block)
+{
+	card_t *card;
+	word	card_id = mem_block->card_id;
+
+	card = get_card(card_id);
+	if (!card)
+	{
+		return 0;
+	}
+
+	return (*card->card_mem_get)(card, mem_block);
+}
+
+
+/*
+ * Deleyed Procedure Call for handling interrupts from card
+ */
+
+void	DivaDoCardDpc(card_t *card)
+{
+	ADAPTER	*a;
+
+	a = &card->a;
+
+	if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1)
+	{
+		return;
+	}
+
+	do{
+		if((*(card->test_int))(a))
+		{
+			(*(card->dpc))(a);
+			(*(card->clear_int))(a);
+		}
+			(*(card->out))(a);
+	}while(UxInterlockedDecrement(card->hw, &card->dpc_reentered));
+			
+}
+
+void	DivasDoDpc(void *pData)
+{
+	card_t	*card = DivasCards;
+	int 	i = DivasCardNext;
+	
+	while(i--)
+	{
+		DivaDoCardDpc(card++);
+	}
+}
+
+void	DivasDoRequestDpc(void *pData)
+{
+	DivasDoDpc(pData);
+}
+
+/*
+ * DivasGetNum
+ * Returns the number of active adapters
+ */
+
+int DivasGetNum(void)
+{
+	return(DivasCardNext);
+}
+
+/*
+ * DivasGetList
+ * Returns a list of active adapters
+ */
+int DivasGetList(dia_card_list_t *card_list)
+{
+	int i;
+
+	bzero(card_list, sizeof(dia_card_list_t));
+
+	for(i = 0; i < DivasCardNext; i++)
+	{
+		card_list->card_type = DivasCards[i].cfg.card_type;
+		card_list->card_slot = DivasCards[i].cfg.slot;
+		card_list->state     = DivasCards[i].state;
+		card_list++;
+	}
+
+	return 0;
+
+}
+
+/*
+ * control logging for specified card
+ */
+
+void	DivasLog(dia_log_t *log)
+{
+	card_t *card;
+
+	card = get_card(log->card_id);
+	if (!card)
+	{
+		return;
+	}
+
+	card->log_types = log->log_types;
+
+	return;
+}
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/constant.h linux/drivers/isdn/eicon/constant.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/constant.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/constant.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,176 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+
+/*------------------------------------------------------------------*/
+/* Q.931 information elements maximum length                        */
+/* excluding the identifier, including the length field             */
+/*------------------------------------------------------------------*/
+
+#define MAX_LEN_BC      13
+#define MAX_LEN_LLC     19 /* ctr3 */
+#define MAX_LEN_HLC     6  /* ctr3 */
+#define MAX_LEN_UUI     200 /* Hicom USBS req */
+#define MAX_LEN_NUM     24
+#define MAX_LEN_DSP     83 /* ctr3 */
+#define MAX_LEN_NI      4
+#define MAX_LEN_PI      5
+#define MAX_LEN_SIN     3
+#define MAX_LEN_CST     4
+#define MAX_LEN_SIG     2
+#define MAX_LEN_SPID    32
+#define MAX_LEN_EID     3
+#define MAX_LEN_CHI     35  /* ctr3 */
+#define MAX_LEN_CAU     33
+#define MAX_LEN_FTY     130
+#define MAX_LEN_KEY     83  /* ctr3 */
+#define MAX_LEN_RSI     4
+#define MAX_LEN_CAI     11
+#define MAX_NUM_SPID    4
+#define MAX_LEN_USERID  9
+#define MAX_LEN_APPLID  5
+#define MAX_LEN_NTTCIF  15
+
+/*------------------------------------------------------------------*/
+/* decision return values                                           */
+/*------------------------------------------------------------------*/
+
+#define YES             1
+#define NO              0
+
+
+/*-------------------------------------------------------------------*/
+/* w element coding                                                  */
+/*-------------------------------------------------------------------*/
+
+#define NTTCIF          0x01
+#define BC              0x04
+#define CAU             0x08
+#define CAD             0x0c
+#define CAI             0x10
+#define CST             0x14
+#define CHI             0x18
+#define LLI             0x19
+#define CHA             0x1a
+#define FTY             0x1c
+#define PI              0x1e
+#define NFAC            0x20
+#define TC              0x24
+#define ATT_EID         0x26
+#define NI              0x27
+#define DSP             0x28
+#define DT              0x29
+#define KEY             0x2c
+#define KP              0x2c
+#define UID             0x2d
+#define SIG             0x34
+#define FI              0x39
+#define SPID            0x3a
+#define EID             0x3b
+#define DSPF            0x3c
+#define ECAD            0x4c
+#define OAD             0x6c
+#define OSA             0x6d
+#define DAD             0x70
+#define CPN             0x70
+#define DSA             0x71
+#define RDX             0x73
+#define RAD             0x74
+#define RDN             0x74
+#define RSI             0x79
+#define SCR             0x7A   /* internal unscreened CPN          */
+#define MIE             0x7a   /* internal management info element */
+#define LLC             0x7c
+#define HLC             0x7d
+#define UUI             0x7e
+#define ESC             0x7f
+
+#define SHIFT           0x90
+#define MORE            0xa0
+#define CL              0xb0
+
+/* information elements used on the spid interface */
+#define SPID_CMD        0xc0
+#define SPID_LINK       0x10
+#define SPID_DN         0x70
+#define SPID_BC         0x04
+#define SPID_SWITCH     0x11
+
+/*------------------------------------------------------------------*/
+/* global configuration parameters, defined in exec.c               */
+/* these parameters are configured with program loading             */
+/*------------------------------------------------------------------*/
+
+#define PROT_1TR6       0
+#define PROT_ETSI       1
+#define PROT_FRANC      2
+#define PROT_BELG       3
+#define PROT_SWED       4
+#define PROT_NI         5
+#define PROT_5ESS       6
+#define PROT_JAPAN      7
+#define PROT_ATEL       8
+#define PROT_US         9
+#define PROT_ITALY      10
+#define PROT_TWAN       11
+#define PROT_AUSTRAL    12
+
+#define INIT_PROT_1TR6    0x80|PROT_1TR6
+#define INIT_PROT_ETSI    0x80|PROT_ETSI
+#define INIT_PROT_FRANC   0x80|PROT_FRANC
+#define INIT_PROT_BELG    0x80|PROT_BELG
+#define INIT_PROT_SWED    0x80|PROT_SWED
+#define INIT_PROT_NI      0x80|PROT_NI
+#define INIT_PROT_5ESS    0x80|PROT_5ESS
+#define INIT_PROT_JAPAN   0x80|PROT_JAPAN
+#define INIT_PROT_ATEL    0x80|PROT_ATEL
+#define INIT_PROT_ITALY   0x80|PROT_ITALY
+#define INIT_PROT_TWAN    0x80|PROT_TWAN
+#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL
+
+
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING in feature.h (included         **
+** in prstart.sx and astart.sx) defines capabilities and      **
+** features of the actual protocol code. It's used as a bit   **
+** mask.                                                      **
+** The following Bits are defined:                            **
+** -----------------------------------------------------------*/
+                                           
+#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
+#define PROTCAP_MANIF     0x0002  /* Management interface implemented    */
+#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
+#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_FREE4     0x0020  /* not used                            */
+#define PROTCAP_FREE5     0x0040  /* not used                            */
+#define PROTCAP_FREE6     0x0080  /* not used                            */
+#define PROTCAP_FREE7     0x0100  /* not used                            */
+#define PROTCAP_FREE8     0x0200  /* not used                            */
+#define PROTCAP_FREE9     0x0400  /* not used                            */
+#define PROTCAP_FREE10    0x0800  /* not used                            */
+#define PROTCAP_FREE11    0x1000  /* not used                            */
+#define PROTCAP_FREE12    0x2000  /* not used                            */
+#define PROTCAP_FREE13    0x4000  /* not used                            */
+#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/divalog.h linux/drivers/isdn/eicon/divalog.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/divalog.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/divalog.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,54 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Include file for defining the kernel loggger messages
+ * These definitions are shared between the klog driver and the
+ * klogd daemon process
+ */
+
+#if !defined(_KLOGMSG_H)
+#define _KLOGMSG_H
+
+/* define a type for a log entry */
+
+#define KLOG_TEXT_MSG   	(0)
+#define KLOG_XLOG_MSG   	(1)
+#define KLOG_XTXT_MSG   	(2)
+#define KLOG_IDI_REQ   		(4)
+#define KLOG_IDI_CALLBACK   (5)
+#define KLOG_CAPI_MSG   	(6)
+
+typedef struct
+{
+    unsigned long   time_stamp; /* in ms since last system boot */
+    int    			card;       /* card number (-1 for all) */
+    unsigned int    type;       /* type of log message (0 is text) */
+    unsigned int    length;     /* message length (non-text messages only) */
+    unsigned short  code;       /* message code (non-text messages only) */
+    char            buffer[110];/* text/data to log */
+} klog_t;
+
+void    DivasLogAdd(void *buffer, int length);
+#endif /* of _KLOGMSG_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/divas.h linux/drivers/isdn/eicon/divas.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/divas.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/divas.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,229 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* External Diva Server driver include file */
+
+#if !defined(DIVAS_H)
+#define DIVAS_H
+
+#include "sys.h"
+
+
+/* IOCTL commands */
+
+#define	DIA_IOCTL_INIT				(0)
+#define	DIA_IOCTL_LOAD				(1)
+#define	DIA_IOCTL_CONFIG			(2)
+#define	DIA_IOCTL_START				(3)
+#define	DIA_IOCTL_GET_NUM			(4)
+#define	DIA_IOCTL_GET_LIST			(5)
+#define	DIA_IOCTL_LOG				(6)
+#define	DIA_IOCTL_DETECT			(7)
+#define	DIA_IOCTL_SPACE				(8)
+#define DIA_IOCTL_GET_MEM           (9)
+#define DIA_IOCTL_FLAVOUR			(10)
+#define	DIA_IOCTL_XLOG_REQ			(11)
+
+/* Error codes */
+
+#define XLOG_ERR_CARD_NUM	(13)
+#define XLOG_ERR_DONE		(14)
+#define XLOG_ERR_CMD		(15)
+#define XLOG_ERR_TIMEOUT	(16)
+#define XLOG_ERR_CARD_STATE	(17)
+#define XLOG_ERR_UNKNOWN	(18)
+#define XLOG_OK 			(0)
+
+/* Adapter states */
+
+#define DIA_UNKNOWN		(0)
+#define DIA_RESET		(1)
+#define DIA_LOADED		(2)
+#define DIA_CONFIGURED	(3)
+#define DIA_RUNNING		(4)
+
+/* Stucture for getting card specific information from active cad driver */
+
+typedef struct
+{
+	int card_type;
+	int card_slot;
+	int	state;
+} dia_card_list_t;
+
+/* use following to select which logging to have active */
+
+#define	DIVAS_LOG_DEBUG		(1 << 0)
+#define	DIVAS_LOG_XLOG		(1 << 1)
+#define	DIVAS_LOG_IDI		(1 << 2)
+#define	DIVAS_LOG_CAPI		(1 << 3)
+
+/* stucture for DIA_IOCTL_LOG to get information from adapter */
+
+typedef struct
+{
+	int		card_id;
+	int		log_types;	/* bit mask of log types: use DIVAS_LOG_XXX */
+} dia_log_t;
+
+/* list of cards supported by this driver */
+
+#define	DIA_CARD_TYPE_DIVA_SERVER	(0)	/* Diva Server PRI */
+#define	DIA_CARD_TYPE_DIVA_SERVER_B	(1)	/* Diva Server BRI */
+#define	DIA_CARD_TYPE_DIVA_SERVER_Q	(2)	/* Diva Server 4-BRI */
+
+/* bus types */
+
+#define	DIA_BUS_TYPE_ISA		(0)
+#define	DIA_BUS_TYPE_ISA_PNP	(1)
+#define	DIA_BUS_TYPE_PCI		(2)
+#define	DIA_BUS_TYPE_MCA		(3)
+
+/* types of memory used (index for memory array below) */
+
+#define DIVAS_RAM_MEMORY 	0
+#define DIVAS_REG_MEMORY 	1
+#define DIVAS_CFG_MEMORY 	2
+#define DIVAS_SHARED_MEMORY 3
+#define DIVAS_CTL_MEMORY	4
+/*
+ * card config information
+ * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card
+ */
+
+typedef struct
+{
+	int		card_id;	/* unique id assigned to this card */
+	int		card_type;	/* use DIA_CARD_TYPE_xxx above */
+	int		bus_type;	/* use DIA_BUS_TYPE_xxx above */
+	int		bus_num;	/* bus number (instance number of bus type) */
+	int		func_num;	/* adapter function number (PCI register) */
+	int		slot;		/* slot number in bus */
+	unsigned char	irq;		/* IRQ number */
+    int     reset_base; /* Reset register  for I/O mapped cards */
+	int		io_base;	/* I/O base for I/O mapped cards */
+	void	*memory[5];	/* memory base addresses for memory mapped cards */
+	char	name[9];	/* name of adapter */
+	int		serial;		/* serial number */
+	unsigned char	int_priority;	/* Interrupt priority */
+} dia_card_t;
+
+/*
+ * protocol configuration information
+ * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card
+ */
+
+typedef struct
+{
+	int				card_id;			/* to identify particular card */
+	unsigned char	tei;
+	unsigned char	nt2;
+	unsigned char	watchdog;
+	unsigned char	permanent;
+	unsigned char	x_interface;
+	unsigned char	stable_l2;
+	unsigned char	no_order_check;
+	unsigned char	handset_type;
+	unsigned char	sig_flags;
+	unsigned char	low_channel;
+	unsigned char	prot_version;
+	unsigned char	crc4;
+	struct
+	{
+		unsigned char oad[32];
+		unsigned char osa[32];
+		unsigned char spid[32];
+	}terminal[2];
+} dia_config_t;
+
+/*
+ * code configuration 
+ * passed as parameter to DIA_IOCTL_LOAD ioctl
+ * one of these ioctl per code file to load
+ */
+
+typedef struct
+{
+	int				card_id;	/* card to load */
+	enum
+	{
+		DIA_CPU_CODE,			/* CPU code */
+		DIA_DSP_CODE,			/* DSP code */
+		DIA_CONT_CODE,			/* continuation of code */
+		DIA_TABLE_CODE,			/* code table */
+	        DIA_DLOAD_CNT,           /* number of downloads*/
+		DIA_FPGA_CODE
+	}				code_type;	/* code for CPU or DSP ? */
+	int				length;		/* length of code */
+	unsigned char	*code;		/* pointer (in user-space) to code */
+} dia_load_t;
+
+/*
+ * start configuration 
+ * passed as parameter to DIA_IOCTL_START ioctl
+ */
+
+typedef struct
+{
+	int				card_id;	/* card to start */
+} dia_start_t;
+
+/* used for retrieving memory from the card */
+
+typedef struct {
+	word	card_id;
+	dword 	addr;
+	byte	data[16 * 8];
+} mem_block_t;
+
+/* DIVA Server specific addresses */
+
+#define DIVAS_CPU_START_ADDR    (0x0)
+#define	ORG_MAX_PROTOCOL_CODE_SIZE	0x000A0000
+#define	ORG_MAX_DSP_CODE_SIZE		(0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE)
+#define	ORG_DSP_CODE_BASE		(0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE)
+#define DIVAS_DSP_START_ADDR    (0xBF7A0000)
+#define DIVAS_SHARED_OFFSET     (0x1000)
+#define MP_DSP_CODE_BASE           0xa03a0000
+#define MQ_PROTCODE_OFFSET  0x100000
+#define MQ_SM_OFFSET		0X0f0000
+
+#define	V90D_MAX_PROTOCOL_CODE_SIZE	0x00090000
+#define V90D_MAX_DSP_CODE_SIZE		(0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE)
+#define	V90D_DSP_CODE_BASE		(0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE)
+
+#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE   0x000a0000  /* max 640K Protocol-Code */
+#define MQ_ORG_MAX_DSP_CODE_SIZE        0x00050000  /* max 320K DSP-Code */
+#define MQ_ORG_DSP_CODE_BASE           (MQ_MAX_DSP_DOWNLOAD_ADDR \
+                                      - MQ_ORG_MAX_DSP_CODE_SIZE)
+#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE  0x00090000  /* max 576K Protocol-Code */
+#define MQ_V90D_MAX_DSP_CODE_SIZE       0x00060000  /* max 384K DSP-Code if V.90D included */
+#define	MQ_MAX_DSP_DOWNLOAD_ADDR        0xa03f0000
+#define MQ_V90D_DSP_CODE_BASE          (MQ_MAX_DSP_DOWNLOAD_ADDR \
+                                      - MQ_V90D_MAX_DSP_CODE_SIZE)
+
+
+#define ALIGNMENT_MASK_MAESTRA        0xfffffffc
+
+#endif /* DIVAS_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/dsp_defs.h linux/drivers/isdn/eicon/dsp_defs.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/dsp_defs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/dsp_defs.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,300 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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 DSP_DEFS_H_
+#define DSP_DEFS_H_
+
+#ifndef DSPDIDS_H_
+#include "dspdids.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*---------------------------------------------------------------------------*/
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE (0 == 0)
+#endif
+#ifndef FALSE
+#define FALSE (0 != 0)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_MEMORY_TYPE_EXTERNAL_DM         0
+#define DSP_MEMORY_TYPE_EXTERNAL_PM         1
+#define DSP_MEMORY_TYPE_INTERNAL_DM         2
+#define DSP_MEMORY_TYPE_INTERNAL_PM         3
+
+#define DSP_DOWNLOAD_FLAG_BOOTABLE          0x0001
+#define DSP_DOWNLOAD_FLAG_2181              0x0002
+#define DSP_DOWNLOAD_FLAG_TIMECRITICAL      0x0004
+#define DSP_DOWNLOAD_FLAG_COMPAND           0x0008
+
+#define DSP_MEMORY_BLOCK_COUNT              16
+
+#define DSP_SEGMENT_PM_FLAG                 0x0001
+#define DSP_SEGMENT_SHARED_FLAG             0x0002
+
+#define DSP_SEGMENT_EXTERNAL_DM             DSP_MEMORY_TYPE_EXTERNAL_DM
+#define DSP_SEGMENT_EXTERNAL_PM             DSP_MEMORY_TYPE_EXTERNAL_PM
+#define DSP_SEGMENT_INTERNAL_DM             DSP_MEMORY_TYPE_INTERNAL_DM
+#define DSP_SEGMENT_INTERNAL_PM             DSP_MEMORY_TYPE_INTERNAL_PM
+#define DSP_SEGMENT_FIRST_RELOCATABLE       4
+
+#define DSP_DATA_BLOCK_PM_FLAG              0x0001
+#define DSP_DATA_BLOCK_DWORD_FLAG           0x0002
+#define DSP_DATA_BLOCK_RESOLVE_FLAG         0x0004
+
+#define DSP_RELOC_NONE                      0x00
+#define DSP_RELOC_SEGMENT_MASK              0x3f
+#define DSP_RELOC_TYPE_MASK                 0xc0
+#define DSP_RELOC_TYPE_0                    0x00  /* relocation of address in DM word / high part of PM word */
+#define DSP_RELOC_TYPE_1                    0x40  /* relocation of address in low part of PM data word */
+#define DSP_RELOC_TYPE_2                    0x80  /* relocation of address in standard command */
+#define DSP_RELOC_TYPE_3                    0xc0  /* relocation of address in call/jump on flag in */
+
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
+
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
+
+
+typedef struct tag_dsp_combifile_header
+{
+  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  header_size;
+  word                  combifile_description_size;
+  word                  directory_entries;
+  word                  directory_size;
+  word                  download_count;
+  word                  usage_mask_size;
+} t_dsp_combifile_header;
+
+typedef struct tag_dsp_combifile_directory_entry
+{
+  word                  card_type_number;
+  word                  file_set_number;
+} t_dsp_combifile_directory_entry;
+
+typedef struct tag_dsp_file_header
+{
+  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  header_size;
+  word                  download_description_size;
+  word                  memory_block_table_size;
+  word                  memory_block_count;
+  word                  segment_table_size;
+  word                  segment_count;
+  word                  symbol_table_size;
+  word                  symbol_count;
+  word                  total_data_size_dm;
+  word                  data_block_count_dm;
+  word                  total_data_size_pm;
+  word                  data_block_count_pm;
+} t_dsp_file_header;
+
+typedef struct tag_dsp_memory_block_desc
+{
+  word                  alias_memory_block;
+  word                  memory_type;
+  word                  address;
+  word                  size;             /* DSP words */
+} t_dsp_memory_block_desc;
+
+typedef struct tag_dsp_segment_desc
+{
+  word                  memory_block;
+  word                  attributes;
+  word                  base;
+  word                  size;
+  word                  alignment;        /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+
+typedef struct tag_dsp_symbol_desc
+{
+  word                  symbol_id;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_symbol_desc;
+
+typedef struct tag_dsp_data_block_header
+{
+  word                  attributes;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_data_block_header;
+
+typedef struct tag_dsp_download_desc      /* be sure to keep native alignment for MAESTRA's */
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  byte              	*p_excess_header_data;
+  char 					*p_download_description;
+  t_dsp_memory_block_desc *p_memory_block_table;
+  t_dsp_segment_desc 	*p_segment_table;
+  t_dsp_symbol_desc 	*p_symbol_table;
+  word 					*p_data_blocks_dm;
+  word 					*p_data_blocks_pm;
+} t_dsp_download_desc;
+
+#define DSP_DOWNLOAD_INDEX_KERNEL               0
+#define DSP30TX_DOWNLOAD_INDEX_KERNEL           1
+#define DSP30RX_DOWNLOAD_INDEX_KERNEL           2
+#define DSP_MAX_DOWNLOAD_COUNT                  35
+
+
+#define DSP_DOWNLOAD_MAX_SEGMENTS         16
+
+#define DSP_UDATA_REQUEST_RECONFIGURE     0
+/*
+parameters:
+  <word> reconfigure delay (in 8kHz samples)
+  <word> reconfigure code
+  <byte> reconfigure hdlc preamble flags
+*/
+
+#define DSP_RECONFIGURE_TX_FLAG           0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG  0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG         0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG         0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK     0x00ff
+#define DSP_RECONFIGURE_IDLE              0
+#define DSP_RECONFIGURE_V25               1
+#define DSP_RECONFIGURE_V21_CH2           2
+#define DSP_RECONFIGURE_V27_2400          3
+#define DSP_RECONFIGURE_V27_4800          4
+#define DSP_RECONFIGURE_V29_7200          5
+#define DSP_RECONFIGURE_V29_9600          6
+#define DSP_RECONFIGURE_V33_12000         7
+#define DSP_RECONFIGURE_V33_14400         8
+#define DSP_RECONFIGURE_V17_7200          9
+#define DSP_RECONFIGURE_V17_9600          10
+#define DSP_RECONFIGURE_V17_12000         11
+#define DSP_RECONFIGURE_V17_14400         12
+
+/*
+data indications if transparent framer
+  <byte> data 0
+  <byte> data 1
+  ...
+
+data indications if HDLC framer
+  <byte> data 0
+  <byte> data 1
+  ...
+  <byte> CRC 0
+  <byte> CRC 1
+  <byte> preamble flags
+*/
+
+#define DSP_UDATA_INDICATION_SYNC         0
+/*
+returns:
+  <word> time of sync (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_OFF      1
+/*
+returns:
+  <word> time of DCD off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_ON       2
+/*
+returns:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_OFF      3
+/*
+returns:
+  <word> time of CTS off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_ON       4
+/*
+returns:
+  <word> time of CTS on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_TFAST            12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+
+#define DSP_CONNECTED_OPTION_TRELLIS        0x0001
+
+
+/*---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/dspdids.h linux/drivers/isdn/eicon/dspdids.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/dspdids.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/dspdids.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,81 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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 DSPDIDS_H_
+#define DSPDIDS_H_
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_DID_INVALID			0
+#define DSP_DID_DIVA			1
+#define DSP_DID_DIVA_PRO		2
+#define DSP_DID_DIVA_PRO_20		3
+#define DSP_DID_DIVA_PRO_PCCARD		4
+#define DSP_DID_DIVA_SERVER_BRI_1M	5
+#define DSP_DID_DIVA_SERVER_BRI_2M	6
+#define DSP_DID_DIVA_SERVER_PRI_2M_TX	7
+#define DSP_DID_DIVA_SERVER_PRI_2M_RX	8
+#define DSP_DID_DIVA_SERVER_PRI_30M	9
+#define DSP_DID_TASK_HSCX		100
+#define DSP_DID_TASK_HSCX_PRI_2M_TX	101
+#define DSP_DID_TASK_HSCX_PRI_2M_RX	102
+#define DSP_DID_TASK_V110KRNL		200
+#define DSP_DID_OVERLAY_V1100		201
+#define DSP_DID_OVERLAY_V1101		202
+#define DSP_DID_OVERLAY_V1102		203
+#define DSP_DID_OVERLAY_V1103		204
+#define DSP_DID_OVERLAY_V1104		205
+#define DSP_DID_OVERLAY_V1105		206
+#define DSP_DID_OVERLAY_V1106		207
+#define DSP_DID_OVERLAY_V1107		208
+#define DSP_DID_OVERLAY_V1108		209
+#define DSP_DID_OVERLAY_V1109		210
+#define DSP_DID_TASK_V110_PRI_2M_TX	220
+#define DSP_DID_TASK_V110_PRI_2M_RX	221
+#define DSP_DID_TASK_MODEM		300
+#define DSP_DID_TASK_FAX05		400
+#define DSP_DID_TASK_VOICE		500
+#define DSP_DID_TASK_TIKRNL81		600
+#define DSP_DID_OVERLAY_DIAL		601
+#define DSP_DID_OVERLAY_V22		602
+#define DSP_DID_OVERLAY_V32		603
+#define DSP_DID_OVERLAY_FSK		604
+#define DSP_DID_OVERLAY_FAX		605
+#define DSP_DID_OVERLAY_VXX		606
+#define DSP_DID_OVERLAY_V8		607
+#define DSP_DID_OVERLAY_INFO		608
+#define DSP_DID_OVERLAY_V34		609
+#define DSP_DID_OVERLAY_DFX		610
+#define DSP_DID_PARTIAL_OVERLAY_DIAL	611
+#define DSP_DID_PARTIAL_OVERLAY_FSK	612
+#define DSP_DID_PARTIAL_OVERLAY_FAX	613
+#define DSP_DID_TASK_TIKRNL05		700
+
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon.h	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon.h	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -20,86 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon.h,v $
- * Revision 1.19  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.18  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.17  1999/10/26 21:15:33  armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.16  1999/10/08 22:09:33  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.15  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.14  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.13  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.12  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.11  1999/08/29 17:23:44  armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10  1999/08/22 20:26:41  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9  1999/08/18 20:16:57  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8  1999/07/25 15:12:01  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7  1999/07/11 17:16:23  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6  1999/06/09 19:31:24  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5  1999/03/29 11:19:41  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4  1999/03/02 12:37:42  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3  1999/01/24 20:14:07  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2  1999/01/10 18:46:04  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1  1999/01/01 18:09:41  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 
@@ -124,6 +44,8 @@
 #define EICON_IOCTL_TEST     98
 #define EICON_IOCTL_DEBUGVAR 99
 
+#define EICON_IOCTL_DIA_OFFSET	100
+
 /* Bus types */
 #define EICON_BUS_ISA          1
 #define EICON_BUS_MCA          2
@@ -185,39 +107,10 @@
 	unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */
 } eicon_isa_codebuf;
 
-/* Struct for downloading protocol via ioctl for PCI cards */
-typedef struct {
-        /* start-up parameters */
-        unsigned char tei;
-        unsigned char nt2;
-        unsigned char WatchDog;
-        unsigned char Permanent;
-        unsigned char XInterface;
-        unsigned char StableL2;
-        unsigned char NoOrderCheck;
-        unsigned char HandsetType;
-        unsigned char LowChannel;
-        unsigned char ProtVersion;
-        unsigned char Crc4;
-        unsigned char NoHscx30Mode;  /* switch PRI into No HSCX30 test mode */
-        unsigned char Loopback;      /* switch card into Loopback mode */
-        struct q931_link_s
-        {
-          unsigned char oad[32];
-          unsigned char osa[32];
-          unsigned char spid[32];
-        } l[2];
-        unsigned long protocol_len;
-	unsigned int  dsp_code_num;
-        unsigned long dsp_code_len[9];
-        unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */
-} eicon_pci_codebuf;
-
 /* Data for downloading protocol via ioctl */
 typedef union {
 	eicon_isa_codebuf isa;
 	eicon_isa_codebuf mca;
-	eicon_pci_codebuf pci;
 } eicon_codebuf;
 
 /* Data for Management interface */
@@ -228,6 +121,7 @@
 	unsigned char data[700]; 
 } eicon_manifbuf;
 
+#define TRACE_OK                 (1)
 
 #ifdef __KERNEL__
 
@@ -245,7 +139,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
@@ -257,7 +151,6 @@
 #include <linux/isdn.h>
 #include <linux/isdnif.h>
 
-
 typedef struct {
   __u16 length __attribute__ ((packed)); /* length of data/parameter field */
   __u8  P[1];                          /* data/parameter field */
@@ -265,206 +158,34 @@
 
 #include "eicon_isa.h"
 
+#include "idi.h"
+
+typedef struct {
+  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
+  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
+  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
+  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
+  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
+  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
+  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
+  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
+  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
+  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
+  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
+  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
+  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
+  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
+  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
+} eicon_pr_ram;
+
 /* Macro for delay via schedule() */
 #define SLEEP(j) {                     \
-  current->state = TASK_UNINTERRUPTIBLE; \
+  set_current_state(TASK_UNINTERRUPTIBLE); \
   schedule_timeout(j);                 \
 }
 
-#endif /* KERNEL */
-
-#define DIVAS_SHARED_OFFSET	(0x1000)
-
-#define MIPS_BUFFER_SZ  128
-#define MIPS_MAINT_OFFS 0xff00
-
-#define XLOG_ERR_CARD_NUM       (13)
-#define XLOG_ERR_DONE           (14)
-#define XLOG_ERR_CMD            (15)
-#define XLOG_ERR_TIMEOUT        (16)
-#define XLOG_ERR_CARD_STATE     (17)
-#define XLOG_ERR_UNKNOWN        (18)
-#define XLOG_OK                  (0)
-
-#define TRACE_OK                 (1)
-
-typedef struct {
-  __u8 Id	__attribute__ ((packed));
-  __u8 uX	__attribute__ ((packed));
-  __u8 listen	__attribute__ ((packed));
-  __u8 active	__attribute__ ((packed));
-  __u8 sin[3]	__attribute__ ((packed));
-  __u8 bc[6]	__attribute__ ((packed));
-  __u8 llc[6]	__attribute__ ((packed));
-  __u8 hlc[6]	__attribute__ ((packed));
-  __u8 oad[20]	__attribute__ ((packed));
-}DSigStruc;
-
-typedef struct {
-  __u32 cx_b1	__attribute__ ((packed));
-  __u32 cx_b2	__attribute__ ((packed));
-  __u32 cr_b1	__attribute__ ((packed));
-  __u32 cr_b2	__attribute__ ((packed));
-  __u32 px_b1	__attribute__ ((packed));
-  __u32 px_b2	__attribute__ ((packed));
-  __u32 pr_b1	__attribute__ ((packed));
-  __u32 pr_b2	__attribute__ ((packed));
-  __u16 er_b1	__attribute__ ((packed));
-  __u16 er_b2	__attribute__ ((packed));
-}BL1Struc;
-
-typedef struct {
-  __u32 XTotal	__attribute__ ((packed));
-  __u32 RTotal	__attribute__ ((packed));
-  __u16 XError	__attribute__ ((packed));
-  __u16 RError	__attribute__ ((packed));
-}L2Struc;
-
-typedef struct {
-  __u16 free_n;
-}OSStruc;
-
-typedef union
-{
-  DSigStruc DSigStats;
-  BL1Struc BL1Stats;
-  L2Struc L2Stats;
-  OSStruc OSStats;
-  __u8   b[MIPS_BUFFER_SZ];
-  __u16   w[MIPS_BUFFER_SZ>>1];
-  __u16   l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
-  __u32  d[MIPS_BUFFER_SZ>>2];
-} MIPS_BUFFER;
-
-typedef struct
-{
-  __u8 req	__attribute__ ((packed));
-  __u8 rc	__attribute__ ((packed));
-  __u8 reserved[2]	__attribute__ ((packed));     /* R3000 alignment ... */
-  __u8 *mem	__attribute__ ((packed));
-  __u16 length	__attribute__ ((packed));		/* used to be short */
-  __u16 port	__attribute__ ((packed));
-  __u8 fill[4]	__attribute__ ((packed));         /* data at offset 16   */
-  MIPS_BUFFER data	__attribute__ ((packed));
-} mi_pc_maint_t;
-
-typedef struct
-{
-        __u16 command;
-        mi_pc_maint_t pcm;
-}xlogreq_t;
-
-typedef struct{
-        __u16 code	__attribute__ ((packed));	/* used to be short */
-        __u16 timeh	__attribute__ ((packed));
-        __u16 timel	__attribute__ ((packed));
-        char buffer[MIPS_BUFFER_SZ - 6];
-}xlog_entry_t;
-
-
-#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
-
-#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
-
-typedef struct tag_dsp_combifile_header
-{
-  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
-  __u16                  format_version_bcd             __attribute__ ((packed));
-  __u16                  header_size                    __attribute__ ((packed));
-  __u16                  combifile_description_size     __attribute__ ((packed));
-  __u16                  directory_entries              __attribute__ ((packed));
-  __u16                  directory_size                 __attribute__ ((packed));
-  __u16                  download_count                 __attribute__ ((packed));
-  __u16                  usage_mask_size                __attribute__ ((packed));
-} t_dsp_combifile_header;
-
-typedef struct tag_dsp_combifile_directory_entry
-{
-  __u16                  card_type_number               __attribute__ ((packed));
-  __u16                  file_set_number                __attribute__ ((packed));
-} t_dsp_combifile_directory_entry;
-
-typedef struct tag_dsp_file_header
-{
-  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
-  __u16                 format_version_bcd              __attribute__ ((packed));
-  __u16                 download_id                     __attribute__ ((packed));
-  __u16                 download_flags                  __attribute__ ((packed));
-  __u16                 required_processing_power       __attribute__ ((packed));
-  __u16                 interface_channel_count         __attribute__ ((packed));
-  __u16                 header_size                     __attribute__ ((packed));
-  __u16                 download_description_size       __attribute__ ((packed));
-  __u16                 memory_block_table_size         __attribute__ ((packed));
-  __u16                 memory_block_count              __attribute__ ((packed));
-  __u16                 segment_table_size              __attribute__ ((packed));
-  __u16                 segment_count                   __attribute__ ((packed));
-  __u16                 symbol_table_size               __attribute__ ((packed));
-  __u16                 symbol_count                    __attribute__ ((packed));
-  __u16                 total_data_size_dm              __attribute__ ((packed));
-  __u16                 data_block_count_dm             __attribute__ ((packed));
-  __u16                 total_data_size_pm              __attribute__ ((packed));
-  __u16                 data_block_count_pm             __attribute__ ((packed));
-} t_dsp_file_header;
-
-typedef struct tag_dsp_memory_block_desc
-{
-  __u16                 alias_memory_block;
-  __u16                 memory_type;
-  __u16                 address;
-  __u16                 size;             /* DSP words */
-} t_dsp_memory_block_desc;
-
-typedef struct tag_dsp_segment_desc
-{
-  __u16                 memory_block;
-  __u16                 attributes;
-  __u16                 base;
-  __u16                 size;
-  __u16                 alignment;        /* ==0 -> no other legal start address than base */
-} t_dsp_segment_desc;
-
-typedef struct tag_dsp_symbol_desc
-{
-  __u16                 symbol_id;
-  __u16                 segment;
-  __u16                 offset;
-  __u16                 size;             /* DSP words */
-} t_dsp_symbol_desc;
-
-typedef struct tag_dsp_data_block_header
-{
-  __u16                 attributes;
-  __u16                 segment;
-  __u16                 offset;
-  __u16                 size;             /* DSP words */
-} t_dsp_data_block_header;
-
-typedef struct tag_dsp_download_desc      /* be sure to keep native alignment for MAESTRA's */
-{
-  __u16                 download_id;
-  __u16                 download_flags;
-  __u16                 required_processing_power;
-  __u16                 interface_channel_count;
-  __u16                 excess_header_size;
-  __u16                 memory_block_count;
-  __u16                 segment_count;
-  __u16                 symbol_count;
-  __u16                 data_block_count_dm;
-  __u16                 data_block_count_pm;
-  __u8  *            p_excess_header_data               __attribute__ ((packed));
-  char  *            p_download_description             __attribute__ ((packed));
-  t_dsp_memory_block_desc  *p_memory_block_table        __attribute__ ((packed));
-  t_dsp_segment_desc  *p_segment_table                  __attribute__ ((packed));
-  t_dsp_symbol_desc  *p_symbol_table                    __attribute__ ((packed));
-  __u16 *            p_data_blocks_dm                   __attribute__ ((packed));
-  __u16 *            p_data_blocks_pm                   __attribute__ ((packed));
-} t_dsp_download_desc;
-
-
-#ifdef __KERNEL__
-
 typedef struct {
   __u8                  Req;            /* pending request          */
   __u8                  Rc;             /* return code received     */
@@ -508,6 +229,7 @@
 	unsigned short statectrl;	 /* State controling bits	*/
 	unsigned short eazmask;          /* EAZ-Mask for this Channel   */
 	int		queued;          /* User-Data Bytes in TX queue */
+	int		pqueued;         /* User-Data Packets in TX queue */
 	int		waitq;           /* User-Data Bytes in wait queue */
 	int		waitpq;          /* User-Data Bytes in packet queue */
 	struct sk_buff *tskb1;           /* temp skb 1			*/
@@ -518,7 +240,9 @@
 	T30_s		*fax;		 /* pointer to fax data in LL	*/
 	eicon_ch_fax_buf fax2;		 /* fax related struct		*/
 #endif
-	entity		e;		 /* Entity  			*/
+	entity		e;		 /* Native Entity		*/
+	ENTITY		de;		 /* Divas D Entity 		*/
+	ENTITY		be;		 /* Divas B Entity 		*/
 	char		cpn[32];	 /* remember cpn		*/
 	char		oad[32];	 /* remember oad		*/
 	char		dsa[32];	 /* remember dsa		*/
@@ -542,8 +266,6 @@
 #define EICON_FLAGS_MVALID   8 /* Cards membase is valid */
 #define EICON_FLAGS_LOADED   8 /* Firmware loaded        */
 
-#define EICON_BCH            2 /* # of channels per card */
-
 /* D-Channel states */
 #define EICON_STATE_NULL     0
 #define EICON_STATE_ICALL    1
@@ -565,9 +287,6 @@
 
 #define EICON_MAX_QUEUE  2138
 
-#define EICON_LOCK_TX 0
-#define EICON_LOCK_RX 1
-
 typedef union {
 	eicon_isa_card isa;
 	eicon_pci_card pci;
@@ -593,17 +312,12 @@
 	__u8 more;
 } eicon_indhdr;
 
-typedef struct msn_entry {
-	char eaz;
-        char msn[16];
-        struct msn_entry * next;
-} msn_entry;
-
 /*
  * Per card driver data
  */
 typedef struct eicon_card {
 	eicon_hwif hwif;                 /* Hardware dependant interface     */
+	DESCRIPTOR *d;			 /* IDI Descriptor		     */
         u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
         u_char bus;                      /* Bustype (ISA, MCA, PCI)          */
         u_char type;                     /* Cardtype (EICON_CTYPE_...)       */
@@ -621,49 +335,23 @@
 	struct tq_struct snd_tq;         /* Task struct for xmit bh          */
 	struct tq_struct rcv_tq;         /* Task struct for rcv bh           */
 	struct tq_struct ack_tq;         /* Task struct for ack bh           */
-	msn_entry *msn_list;
 	eicon_chan*	IdTable[256];	 /* Table to find entity   */
 	__u16  ref_in;
 	__u16  ref_out;
 	int    nchannels;                /* Number of B-Channels             */
 	int    ReadyInt;		 /* Ready Interrupt		     */
 	eicon_chan *bch;                 /* B-Channel status/control         */
-	char   status_buf[256];          /* Buffer for status messages       */
-	char   *status_buf_read;
-	char   *status_buf_write;
-	char   *status_buf_end;
+	DBUFFER *dbuf;			 /* Dbuffer for Diva Server	     */
+	BUFFERS *sbuf;			 /* Buffer for Diva Server	     */
+	char *sbufp;			 /* Data Buffer for Diva Server	     */
         isdn_if interface;               /* Interface to upper layer         */
-        char regname[35];                /* Name used for request_region     */
+        char regname[35];                /* Drivers card name 		     */
 #ifdef CONFIG_MCA
         int	mca_slot;	 	 /* # of cards MCA slot              */
 	int	mca_io;			 /* MCA cards IO port		     */
 #endif /* CONFIG_MCA */
 } eicon_card;
 
-/* -----------------------------------------------------------**
-** The PROTOCOL_FEATURE_STRING                                **
-** defines capabilities and                                   **
-** features of the actual protocol code. It's used as a bit   **
-** mask.                                                      **
-** The following Bits are defined:                            **
-** -----------------------------------------------------------*/
-#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
-#define PROTCAP_MANIF     0x0002  /* Management interface implemented    */
-#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
-#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
-#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
-#define PROTCAP_FREE4     0x0020  /* not used                            */
-#define PROTCAP_FREE5     0x0040  /* not used                            */
-#define PROTCAP_FREE6     0x0080  /* not used                            */
-#define PROTCAP_FREE7     0x0100  /* not used                            */
-#define PROTCAP_FREE8     0x0200  /* not used                            */
-#define PROTCAP_FREE9     0x0400  /* not used                            */
-#define PROTCAP_FREE10    0x0800  /* not used                            */
-#define PROTCAP_FREE11    0x1000  /* not used                            */
-#define PROTCAP_FREE12    0x2000  /* not used                            */
-#define PROTCAP_FREE13    0x4000  /* not used                            */
-#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
-
 #include "eicon_idi.h"
 
 extern eicon_card *cards;
@@ -688,13 +376,11 @@
         mark_bh(IMMEDIATE_BH);
 }
 
-extern char *eicon_find_eaz(eicon_card *, char);
-extern int eicon_addcard(int, int, int, char *);
+extern int eicon_addcard(int, int, int, char *, int);
 extern void eicon_io_transmit(eicon_card *card);
 extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
 extern void eicon_io_rcv_dispatch(eicon_card *ccard);
 extern void eicon_io_ack_dispatch(eicon_card *ccard);
-extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
 #ifdef CONFIG_MCA
 extern int eicon_mca_find_card(int, int, int, char *);
 extern int eicon_mca_probe(int, int, int, int, char *);
@@ -704,6 +390,8 @@
 extern ulong DebugVar;
 extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
 extern void eicon_putstatus(eicon_card * card, char * buf);
+
+extern spinlock_t eicon_lock;
 
 #endif  /* __KERNEL__ */
 
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_dsp.h linux/drivers/isdn/eicon/eicon_dsp.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_dsp.h	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_dsp.h	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        DSP definitions
@@ -20,75 +20,14 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: eicon_dsp.h,v $
- * Revision 1.5  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.4  1999/07/25 15:12:02  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.3  1999/07/11 17:16:24  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.2  1999/03/29 11:19:42  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.1  1999/03/02 12:18:54  armin
- * First checkin of DSP defines for audio features.
- *
  *
  */
 
 #ifndef DSP_H 
 #define DSP_H
 
-#define DSP_UDATA_REQUEST_RECONFIGURE           0
-/*
-parameters:
-  <word> reconfigure delay (in 8kHz samples)
-  <word> reconfigure code
-  <byte> reconfigure hdlc preamble flags
-*/
-
-#define DSP_RECONFIGURE_TX_FLAG             0x8000
-#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG    0x4000
-#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG   0x2000
-#define DSP_RECONFIGURE_HDLC_FLAG           0x1000
-#define DSP_RECONFIGURE_SYNC_FLAG           0x0800
-#define DSP_RECONFIGURE_PROTOCOL_MASK       0x00ff
-#define DSP_RECONFIGURE_IDLE                0
-#define DSP_RECONFIGURE_V25                 1
-#define DSP_RECONFIGURE_V21_CH2             2
-#define DSP_RECONFIGURE_V27_2400            3
-#define DSP_RECONFIGURE_V27_4800            4
-#define DSP_RECONFIGURE_V29_7200            5
-#define DSP_RECONFIGURE_V29_9600            6
-#define DSP_RECONFIGURE_V33_12000           7
-#define DSP_RECONFIGURE_V33_14400           8
-#define DSP_RECONFIGURE_V17_7200            9
-#define DSP_RECONFIGURE_V17_9600            10
-#define DSP_RECONFIGURE_V17_12000           11
-#define DSP_RECONFIGURE_V17_14400           12
+#include "dsp_defs.h"
 
-/*
-data indications if transparent framer
-  <byte> data 0
-  <byte> data 1
-  ...
-
-data indications if HDLC framer
-  <byte> data 0
-  <byte> data 1
-  ...
-  <byte> CRC 0
-  <byte> CRC 1
-  <byte> preamble flags
-*/
 
 #define DSP_UDATA_REQUEST_SWITCH_FRAMER         1
 /*
@@ -122,49 +61,6 @@
   - none -
 */
 
-
-#define DSP_UDATA_INDICATION_SYNC               0
-/*
-returns:
-  <word> time of sync (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_OFF            1
-/*
-returns:
-  <word> time of DCD off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_ON             2
-/*
-returns:
-  <word> time of DCD on (sampled from counter at 8kHz)
-  <byte> connected norm
-  <word> connected options
-  <dword> connected speed (bit/s, max of tx and rx speed)
-  <word> roundtrip delay (ms)
-  <dword> connected speed tx (bit/s)
-  <dword> connected speed rx (bit/s)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_OFF            3
-/*
-returns:
-  <word> time of CTS off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_ON             4
-/*
-returns:
-  <word> time of CTS on (sampled from counter at 8kHz)
-  <byte> connected norm
-  <word> connected options
-  <dword> connected speed (bit/s, max of tx and rx speed)
-  <word> roundtrip delay (ms)
-  <dword> connected speed tx (bit/s)
-  <dword> connected speed rx (bit/s)
-*/
-
 typedef struct eicon_dsp_ind {
 	__u16	time		__attribute__ ((packed));
 	__u8	norm		__attribute__ ((packed));
@@ -175,32 +71,11 @@
 	__u32	rxspeed		__attribute__ ((packed));
 } eicon_dsp_ind;
 
-#define DSP_CONNECTED_NORM_UNSPECIFIED      0
-#define DSP_CONNECTED_NORM_V21              1
-#define DSP_CONNECTED_NORM_V23              2
-#define DSP_CONNECTED_NORM_V22              3
-#define DSP_CONNECTED_NORM_V22_BIS          4
-#define DSP_CONNECTED_NORM_V32_BIS          5
-#define DSP_CONNECTED_NORM_V34              6
-#define DSP_CONNECTED_NORM_V8               7
-#define DSP_CONNECTED_NORM_BELL_212A        8
-#define DSP_CONNECTED_NORM_BELL_103         9
-#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
-#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
-#define DSP_CONNECTED_NORM_V90              12
-#define DSP_CONNECTED_NORM_V21_CH2          13
-#define DSP_CONNECTED_NORM_V27_TER          14
-#define DSP_CONNECTED_NORM_V29              15
-#define DSP_CONNECTED_NORM_V33              16
-#define DSP_CONNECTED_NORM_V17              17
-
-#define DSP_CONNECTED_OPTION_TRELLIS             0x0001
 #define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
 #define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
 #define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
 
-
 #define DSP_UDATA_INDICATION_DISCONNECT         5
 /*
 returns:
@@ -213,7 +88,6 @@
 #define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY    0x03
 #define DSP_DISCONNECT_CAUSE_CLEARDOWN          0x04
 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT   0x05
-
 
 #define DSP_UDATA_INDICATION_TX_CONFIRMATION    6
 /*
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_idi.c	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_idi.c	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
+/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        IDI interface 
@@ -25,135 +25,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_idi.c,v $
- * Revision 1.33  2000/03/06 15:45:17  armin
- * Fixed incomplete number handling with BRI PtP connection.
- *
- * Revision 1.32  2000/03/04 17:04:21  armin
- * Fix of statemachine, B-connect before D-connect,
- * thanks to Helmut Adams <adams@ipcon.de>
- * Minor change in send-data packet handling.
- *
- * Revision 1.31  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.30  2000/02/16 16:08:46  armin
- * Fixed virtual channel handling of IDI.
- *
- * Revision 1.29  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.28  2000/01/20 19:55:34  keil
- * Add FAX Class 1 support
- *
- * Revision 1.27  1999/11/29 13:12:03  armin
- * Autoconnect on L2_TRANS doesn't work with link_level correctly,
- * changed back to former mode.
- *
- * Revision 1.26  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.25  1999/11/18 20:30:55  armin
- * removed old workaround for ISA cards.
- *
- * Revision 1.24  1999/10/26 21:15:33  armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.23  1999/10/11 18:13:25  armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.22  1999/10/08 22:09:33  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.21  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.20  1999/09/21 20:35:43  armin
- * added more error checking.
- *
- * Revision 1.19  1999/09/21 20:06:40  armin
- * Added pointer checks.
- *
- * Revision 1.18  1999/09/07 12:48:05  armin
- * Prepared for sub-address usage.
- *
- * Revision 1.17  1999/09/07 12:35:39  armin
- * Better checking and channel Id handling.
- *
- * Revision 1.16  1999/09/04 13:44:19  armin
- * Fix of V.42 analog Modem negotiation handling.
- *
- * Revision 1.15  1999/08/28 21:32:50  armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.14  1999/08/28 20:24:40  armin
- * Corrected octet 3/3a in CPN/OAD information element.
- * Thanks to John Simpson <xfl23@dial.pipex.com>
- *
- * Revision 1.13  1999/08/22 20:26:44  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.12  1999/08/18 20:16:59  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.11  1999/07/25 15:12:03  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.10  1999/07/11 17:16:24  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.9  1999/03/29 11:19:42  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.8  1999/03/02 12:37:43  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.7  1999/02/03 18:34:35  armin
- * Channel selection for outgoing calls w/o CHI.
- * Added channel # in debug messages.
- * L2 Transparent should work with 800 byte/packet now.
- *
- * Revision 1.6  1999/01/26 07:18:59  armin
- * Bug with wrong added CPN fixed.
- *
- * Revision 1.5  1999/01/24 20:14:11  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.4  1999/01/10 18:46:05  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.3  1999/01/05 14:49:34  armin
- * Added experimental usage of full BC and HLC for
- * speech, 3.1kHz audio, fax gr.2/3
- *
- * Revision 1.2  1999/01/04 13:19:29  armin
- * Channel status with listen-request wrong - fixed.
- *
- * Revision 1.1  1999/01/01 18:09:41  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -161,25 +32,14 @@
 #include "eicon.h"
 #include "eicon_idi.h"
 #include "eicon_dsp.h"
+#include "uxio.h"
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.33 $";
+char *eicon_idi_revision = "$Revision: 1.41.6.1 $";
 
 eicon_manifbuf *manbuf;
 
-static char BC_Speech[3] = 	{ 0x80, 0x90, 0xa3 };
-static char BC_31khz[3] =  	{ 0x90, 0x90, 0xa3 };
-static char BC_64k[2] =    	{ 0x88, 0x90 };
-static char BC_video[3] =  	{ 0x91, 0x90, 0xa5 };
-
-#ifdef EICON_FULL_SERVICE_OKTETT
-/* 
-static char HLC_telephony[2] =	{ 0x91, 0x81 }; 
-*/
-static char HLC_faxg3[2] =  	{ 0x91, 0x84 };
-#endif
-
 int eicon_idi_manage_assign(eicon_card *card);
 int eicon_idi_manage_remove(eicon_card *card);
 int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
@@ -209,7 +69,7 @@
 	reqbuf->XBuffer.P[l++] = 0; /* end */
 	reqbuf->Req = ASSIGN;
 	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 0;
+	reqbuf->ReqId = DSIG_ID;
 	reqbuf->XBuffer.length = l;
 	reqbuf->Reference = 0; /* Sig Entity */
   }
@@ -221,6 +81,9 @@
 	reqbuf->XBuffer.P[l++] = LLC;
 	reqbuf->XBuffer.P[l++] = 2;
 	switch(chan->l2prot) {
+		case ISDN_PROTO_L2_V11096:
+		case ISDN_PROTO_L2_V11019:
+		case ISDN_PROTO_L2_V11038:
 		case ISDN_PROTO_L2_TRANS:
 			reqbuf->XBuffer.P[l++] = 2; /* transparent */
 			break;
@@ -262,7 +125,7 @@
 	reqbuf->XBuffer.P[l++] = 0; /* end */
 	reqbuf->Req = ASSIGN;
 	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 0x20;
+	reqbuf->ReqId = NL_ID;
 	reqbuf->XBuffer.length = l;
 	reqbuf->Reference = 1; /* Net Entity */
   }
@@ -282,6 +145,21 @@
 }
 
 int
+idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+	reqbuf->Req = SUSPEND;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+	reqbuf->XBuffer.P[0] = CAI;
+	reqbuf->XBuffer.P[1] = 1;
+	reqbuf->XBuffer.P[2] = chan->No;
+	reqbuf->XBuffer.P[3] = 0;
+	reqbuf->XBuffer.length = 4;
+	reqbuf->Reference = 0; /* Sig Entity */
+   return(0);
+}
+
+int
 idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
 {
 	int l = 9;
@@ -295,7 +173,7 @@
 	reqbuf->XBuffer.P[4] = 0;
 	reqbuf->XBuffer.P[5] = 0;
 	reqbuf->XBuffer.P[6] = 32;
-	reqbuf->XBuffer.P[7] = 3;
+	reqbuf->XBuffer.P[7] = 0;
 	switch(chan->l2prot) {
 		case ISDN_PROTO_L2_X75I:
 		case ISDN_PROTO_L2_X75UI:
@@ -391,6 +269,12 @@
 		case HANGUP:
 			idi_put_req(reqbuf, HANGUP, 0, 0);
 			break;
+		case SUSPEND:
+			idi_put_suspend_req(reqbuf, chan);
+			break;
+		case RESUME:
+			idi_put_req(reqbuf, RESUME, 0 ,0);
+			break;
 		case REJECT:
 			idi_put_req(reqbuf, REJECT, 0 ,0);
 			break;
@@ -400,17 +284,20 @@
 		case CALL_RES:
 			idi_call_res_req(reqbuf, chan);
 			break;
-		case IDI_N_CONNECT|0x700:
-			idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0);
+		case CALL_HOLD:
+			idi_put_req(reqbuf, CALL_HOLD, 0, 0);
+			break;
+		case N_CONNECT|0x700:
+			idi_put_req(reqbuf, N_CONNECT, 1, 0);
 			break;
-		case IDI_N_CONNECT_ACK|0x700:
-			idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0);
+		case N_CONNECT_ACK|0x700:
+			idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
 			break;
-		case IDI_N_DISC|0x700:
-			idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh);
+		case N_DISC|0x700:
+			idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
 			break;
-		case IDI_N_DISC_ACK|0x700:
-			idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh);
+		case N_DISC_ACK|0x700:
+			idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh);
 			break;
 		default:
 			eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
@@ -492,7 +379,7 @@
 
 	if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
 	    (chan->fsm_state == EICON_STATE_WMCONN)) {
-  		if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
+  		if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1);
 	}
 	if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
 	if (chan->fsm_state != EICON_STATE_NULL) {
@@ -508,6 +395,32 @@
 }
 
 int
+capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm)
+{
+	if ((cm->para[0] != 3) || (cm->para[1] != 0))
+		return -1;
+	if (cm->para[2] < 3)
+		return -1;
+	if (cm->para[4] != 0)
+		return -1;
+	switch(cm->para[3]) {
+		case 4: /* Suspend */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No);
+			if (cm->para[5]) {
+				idi_do_req(card, chan, SUSPEND, 0);
+			} else {
+				idi_do_req(card, chan, CALL_HOLD, 0);
+			}
+			break;
+		case 5: /* Resume */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No);
+			idi_do_req(card, chan, RESUME, 0);
+			break;
+        }
+	return 0;
+}
+
+int
 idi_connect_res(eicon_card *card, eicon_chan *chan)
 {
 	if ((!card) || (!chan))
@@ -612,7 +525,14 @@
 			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
 	}
 
-	if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
+	if (si2 > 2) {
+		reqbuf->XBuffer.P[l++] = SHIFT|6;
+		reqbuf->XBuffer.P[l++] = SIN;
+		reqbuf->XBuffer.P[l++] = 2;
+		reqbuf->XBuffer.P[l++] = si1;
+		reqbuf->XBuffer.P[l++] = si2;
+	}
+	else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
 		reqbuf->XBuffer.P[l++] = BC;
 		reqbuf->XBuffer.P[l++] = tmp;
 		for(i=0; i<tmp;i++) 
@@ -632,7 +552,7 @@
 	reqbuf->XBuffer.P[l++] = 0;
 	reqbuf->XBuffer.P[l++] = 0;
 	reqbuf->XBuffer.P[l++] = 32;
-	reqbuf->XBuffer.P[l++] = 3;
+	reqbuf->XBuffer.P[l++] = 0;
         switch(chan->l2prot) {
 		case ISDN_PROTO_L2_X75I:
 		case ISDN_PROTO_L2_X75UI:
@@ -859,7 +779,7 @@
 				}
 				for(i=0; i < wlen; i++) 
 					message->llc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0],
 					message->llc[1],message->llc[2],message->llc[3]);
 				break;
 			case HLC:
@@ -869,7 +789,7 @@
 				}
 				for(i=0; i < wlen; i++) 
 					message->hlc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No,
 					message->hlc[0], message->hlc[1],
 					message->hlc[2], message->hlc[3], message->hlc[4]);
 				break;
@@ -1061,31 +981,55 @@
 }
 
 void
-idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2)
+idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2)
 {
-  si1[0] = 0;
-  si2[0] = 0;
-  if (memcmp(bc, BC_Speech, 3) == 0) {		/* Speech */
-	si1[0] = 1;
+	si1[0] = 0;
+	si2[0] = 0;
+
+	switch (bc[0] & 0x7f) {
+		case 0x00: /* Speech */
+			si1[0] = 1;
 #ifdef EICON_FULL_SERVICE_OKTETT
-	si2[0] = 1;
+			si1[0] = sin[0];
+			si2[0] = sin[1];
 #endif
-  }
-  if (memcmp(bc, BC_31khz, 3) == 0) {		/* 3.1kHz audio */
-	si1[0] = 1;
+			break;
+		case 0x10: /* 3.1 Khz audio */
+			si1[0] = 1;
 #ifdef EICON_FULL_SERVICE_OKTETT
-	si2[0] = 2;
-  	if (memcmp(hlc, HLC_faxg3, 2) == 0) {	/* Fax Gr.2/3 */
-		si1[0] = 2;
-	}
+			si1[0] = sin[0];
+			si2[0] = sin[1];
 #endif
-  }
-  if (memcmp(bc, BC_64k, 2) == 0) {		/* unrestricted 64 kbits */
-	si1[0] = 7;
-  }
-  if (memcmp(bc, BC_video, 3) == 0) {		/* video */
-	si1[0] = 4;
-  }
+			break;
+		case 0x08: /* Unrestricted digital information */
+			si1[0] = 7;
+			si2[0] = sin[1];
+			break;
+		case 0x09: /* Restricted digital information */
+			si1[0] = 2;
+			break;
+		case 0x11:
+			/* Unrestr. digital information  with
+			 * tones/announcements ( or 7 kHz audio
+			 */
+			si1[0] = 3;
+			break;
+		case 0x18: /* Video */
+			si1[0] = 4;
+			break;
+	}
+	switch (bc[1] & 0x7f) {
+		case 0x40: /* packed mode */
+			si1[0] = 8;
+			break;
+		case 0x10: /* 64 kbit */
+		case 0x11: /* 2*64 kbit */
+		case 0x13: /* 384 kbit */
+		case 0x15: /* 1536 kbit */
+		case 0x17: /* 1920 kbit */
+			/* moderate = bc[1] & 0x7f; */
+			break;
+	}
 }
 
 /********************* FAX stuff ***************************/
@@ -1225,7 +1169,7 @@
 
 	reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
 
-	reqbuf->Req = IDI_N_EDATA;
+	reqbuf->Req = N_EDATA;
 	reqbuf->ReqCh = chan->e.IndCh;
 	reqbuf->ReqId = 1;
 
@@ -1359,7 +1303,7 @@
 			eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
 			break;
 	}
-	idi_send_data(card, chan, 0, skb, 0);
+	idi_send_data(card, chan, 0, skb, 0, 0);
 }
 
 void
@@ -1913,7 +1857,7 @@
 	OutBuf->Len = 0;
 	OutBuf->Next = OutBuf->Data;
 
-	return(idi_send_data(ccard, chan, 0, skb, 1));
+	return(idi_send_data(ccard, chan, 0, skb, 1, 0));
 }
 
 int
@@ -1958,6 +1902,8 @@
 
         if (chan->queued + skb->len > 1200)
                 return 0;
+	if (chan->pqueued > 1)
+		return 0;
 
 	InBuf.Data = skb->data;
 	InBuf.Size = skb->len;
@@ -2183,6 +2129,7 @@
 	}
 	if ((chan->fax->code > 1) && (chan->fax->code < 120))
 		chan->fax->code += 120;
+	eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code);
 	chan->fax->r_code = ISDN_TTY_FAX_HNG;
 	cmd.driver = ccard->myid;
 	cmd.command = ISDN_STAT_FAXIND;
@@ -2224,7 +2171,7 @@
 
 	reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
 
-	reqbuf->Req = IDI_N_UDATA;
+	reqbuf->Req = N_UDATA;
 	reqbuf->ReqCh = chan->e.IndCh;
 	reqbuf->ReqId = 1;
 
@@ -2418,12 +2365,12 @@
 		                while((skb2 = skb_dequeue(&chan->e.X))) {
 					dev_kfree_skb(skb2);
 				}
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued = 0;
+				chan->pqueued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				if (message.e_cau[0] & 0x7f) {
 					cmd.driver = ccard->myid;
 					cmd.arg = chan->No;
@@ -2433,10 +2380,6 @@
 					ccard->interface.statcallb(&cmd);
 				}
 				chan->cause[0] = 0; 
-#ifdef CONFIG_ISDN_TTY_FAX
-				if (!chan->e.B2Id)
-					chan->fax = 0;
-#endif
 				if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
 				    (chan->fsm_state == EICON_STATE_WMCONN)) ||
 				    ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
@@ -2446,6 +2389,7 @@
 					if (chan->e.B2Id)
 						idi_do_req(ccard, chan, REMOVE, 1);
 					chan->statectrl &= ~WAITING_FOR_HANGUP;
+					chan->statectrl &= ~IN_HOLD;
 					if (chan->statectrl & HAVE_CONN_REQ) {
 						eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
 						chan->statectrl &= ~HAVE_CONN_REQ;
@@ -2463,6 +2407,9 @@
 						cmd.command = ISDN_STAT_DHUP;
 						ccard->interface.statcallb(&cmd);
 						eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+						chan->fax = 0;
+#endif
 					}
 				}
 				break;
@@ -2475,7 +2422,7 @@
 					break;
 				}
 				chan->fsm_state = EICON_STATE_ICALL;
-				idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
+				idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2);
 				strcpy(chan->cpn, message.cpn + 1);
 				strcpy(chan->oad, message.oad);
 				strcpy(chan->dsa, message.dsa);
@@ -2553,12 +2500,15 @@
 						case ISDN_PROTO_L2_MODEM:
 							/* do nothing, wait for connect */
 							break;
+						case ISDN_PROTO_L2_V11096:
+						case ISDN_PROTO_L2_V11019:
+						case ISDN_PROTO_L2_V11038:
 						case ISDN_PROTO_L2_TRANS:
-							idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+							idi_do_req(ccard, chan, N_CONNECT, 1);
 							break;
-						default:
+						default:;
 							/* On most incoming calls we use automatic connect */
-							/* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
+							/* idi_do_req(ccard, chan, N_CONNECT, 1); */
 					}
 				} else {
 					if (chan->fsm_state != EICON_STATE_ACTIVE)
@@ -2568,33 +2518,50 @@
 			case CALL_CON:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
 				if (chan->fsm_state == EICON_STATE_OCALL) {
-					chan->fsm_state = EICON_STATE_OBWAIT;
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_DCONN;
-					cmd.arg = chan->No;
-					ccard->interface.statcallb(&cmd);
-
 					/* check if old NetID has been removed */
 					if (chan->e.B2Id) {
 						eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
 							chan->No, chan->e.B2Id);
 						idi_do_req(ccard, chan, REMOVE, 1);
 					}
-
-					idi_do_req(ccard, chan, ASSIGN, 1); 
-					idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
 #ifdef CONFIG_ISDN_TTY_FAX
 					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-						if (chan->fax)
+						if (chan->fax) {
 							chan->fax->phase = ISDN_FAX_PHASE_A;
+						} else {
+							eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n");
+							idi_hangup(ccard, chan);
+							break;
+						}
 					}
 #endif
+					chan->fsm_state = EICON_STATE_OBWAIT;
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_DCONN;
+					cmd.arg = chan->No;
+					ccard->interface.statcallb(&cmd);
+
+					idi_do_req(ccard, chan, ASSIGN, 1); 
+					idi_do_req(ccard, chan, N_CONNECT, 1);
 				} else
-				idi_hangup(ccard, chan);
+					idi_hangup(ccard, chan);
 				break;
 			case AOC_IND:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
 				break;
+			case CALL_HOLD_ACK:
+				chan->statectrl |= IN_HOLD;
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No);
+				break;
+			case SUSPEND_REJ:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No);
+				break;
+			case SUSPEND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No);
+				break;
+			case RESUME:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No);
+				break;
 			default:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
 		}
@@ -2613,7 +2580,7 @@
 		} 
 		else
 		switch(ind->Ind) {
-			case IDI_N_CONNECT_ACK:
+			case N_CONNECT_ACK:
 				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
 				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
 					chan->fsm_state = EICON_STATE_WMCONN;
@@ -2634,7 +2601,7 @@
 						}
 					}
 					else {
-						eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+						eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n");
 					}
 #endif
 					break;
@@ -2646,10 +2613,10 @@
 				strcpy(cmd.parm.num, "64000");
 				ccard->interface.statcallb(&cmd);
 				break; 
-			case IDI_N_CONNECT:
+			case N_CONNECT:
 				eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
 				chan->e.IndCh = ind->IndCh;
-				if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+				if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					break;
 				}
@@ -2664,43 +2631,47 @@
 				strcpy(cmd.parm.num, "64000");
 				ccard->interface.statcallb(&cmd);
 				break; 
-			case IDI_N_DISC:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
+			case N_DISC:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No);
 				if (chan->e.B2Id) {
 		                	while((skb2 = skb_dequeue(&chan->e.X))) {
 						dev_kfree_skb(skb2);
 					}
-					idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
+					idi_do_req(ccard, chan, N_DISC_ACK, 1);
 					idi_do_req(ccard, chan, REMOVE, 1);
 				}
 #ifdef CONFIG_ISDN_TTY_FAX
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+				if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){
 					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 					idi_fax_hangup(ccard, chan);
 				}
 #endif
 				chan->e.IndCh = 0;
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued = 0;
+				chan->pqueued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
-				restore_flags(flags);
-				idi_do_req(ccard, chan, HANGUP, 0);
+				spin_unlock_irqrestore(&eicon_lock, flags);
+				if (!(chan->statectrl & IN_HOLD)) {
+					idi_do_req(ccard, chan, HANGUP, 0);
+				}
 				if (chan->fsm_state == EICON_STATE_ACTIVE) {
 					cmd.driver = ccard->myid;
 					cmd.command = ISDN_STAT_BHUP;
 					cmd.arg = chan->No;
 					ccard->interface.statcallb(&cmd);
 					chan->fsm_state = EICON_STATE_NULL;
-					chan->statectrl |= WAITING_FOR_HANGUP;
+					if (!(chan->statectrl & IN_HOLD)) {
+						chan->statectrl |= WAITING_FOR_HANGUP;
+					}
 				}
 #ifdef CONFIG_ISDN_TTY_FAX
 				chan->fax = 0;
 #endif
 				break; 
-			case IDI_N_DISC_ACK:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+			case N_DISC_ACK:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -2708,10 +2679,10 @@
 				}
 #endif
 				break; 
-			case IDI_N_DATA_ACK:
-				eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+			case N_DATA_ACK:
+				eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No);
 				break;
-			case IDI_N_DATA:
+			case N_DATA:
 				skb_pull(skb, sizeof(eicon_IND) - 1);
 				eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
@@ -2723,11 +2694,11 @@
 					free_buff = 0; 
 				}
 				break; 
-			case IDI_N_UDATA:
+			case N_UDATA:
 				idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 				break; 
 #ifdef CONFIG_ISDN_TTY_FAX
-			case IDI_N_EDATA:
+			case N_EDATA:
 				idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 				break; 
 #endif
@@ -2747,6 +2718,8 @@
 {
 	ulong flags;
 	isdn_ctrl cmd;
+	int tqueued = 0;
+	int twaitpq = 0;
 
 	if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
 		/* I dont know why this happens, should not ! */
@@ -2770,16 +2743,15 @@
 			eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
 				ack->Reference, chan->e.ref);
 		}
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
 		ccard->IdTable[ack->RcId] = NULL;
-		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
-			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
 		if (!chan->e.ReqCh) 
 			chan->e.D3Id = 0;
 		else
 			chan->e.B2Id = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
+		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
 		return 1;
 	}
 
@@ -2790,25 +2762,21 @@
 	} else {
 	/* Network layer */
 		switch(chan->e.Req & 0x0f) {
-			case IDI_N_CONNECT:
+			case N_CONNECT:
 				chan->e.IndCh = ack->RcCh;
 				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
 					ack->RcId, ack->RcCh, ack->Reference);
 				break;
-			case IDI_N_MDATA:
-			case IDI_N_DATA:
-				if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
-					if (chan->queued) {
-						cmd.driver = ccard->myid;
-						cmd.command = ISDN_STAT_BSENT;
-						cmd.arg = chan->No;
-						cmd.parm.length = chan->waitpq;
-						ccard->interface.statcallb(&cmd);
-					}
-					save_flags(flags);
-					cli();
+			case N_MDATA:
+			case N_DATA:
+				tqueued = chan->queued;
+				twaitpq = chan->waitpq;
+				if ((chan->e.Req & 0x0f) == N_DATA) {
+					spin_lock_irqsave(&eicon_lock, flags);
 					chan->waitpq = 0;
-					restore_flags(flags);
+					if(chan->pqueued)
+						chan->pqueued--;
+					spin_unlock_irqrestore(&eicon_lock, flags);
 #ifdef CONFIG_ISDN_TTY_FAX
 					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 						if (((chan->queued - chan->waitq) < 1) &&
@@ -2828,11 +2796,17 @@
 					}
 #endif
 				}
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued -= chan->waitq;
 				if (chan->queued < 0) chan->queued = 0;
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
+				if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) {
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_BSENT;
+					cmd.arg = chan->No;
+					cmd.parm.length = twaitpq;
+					ccard->interface.statcallb(&cmd);
+				}
 				break;
 			default:
 				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
@@ -2858,11 +2832,10 @@
 		return;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	if ((chan = ccard->IdTable[ack->RcId]) != NULL)
 		dCh = chan->No;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
 
 	switch (ack->Rc) {
 		case OK_FC:
@@ -2890,8 +2863,7 @@
 				eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
 					chan->No, chan->e.D3Id, chan->e.B2Id);
 			}
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&eicon_lock, flags);
 			for(j = 0; j < ccard->nchannels + 1; j++) {
 				if ((ccard->bch[j].e.ref == ack->Reference) &&
 					(ccard->bch[j].e.Req == ASSIGN)) {
@@ -2901,12 +2873,12 @@
 						ccard->bch[j].e.B2Id  = ack->RcId;
 					ccard->IdTable[ack->RcId] = &ccard->bch[j];
 					chan = &ccard->bch[j];
-					eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
-						ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
 					break;
 				}
-			}		
-			restore_flags(flags);
+			}
+			spin_unlock_irqrestore(&eicon_lock, flags);
+			eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
+				ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
 			if (j > ccard->nchannels) {
 				eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
 					ack->Reference, ack->RcId);
@@ -2917,6 +2889,7 @@
 		case UNKNOWN_COMMAND:
 		case WRONG_COMMAND:
 		case WRONG_ID:
+		case ADAPTER_DEAD:
 		case WRONG_CH:
 		case UNKNOWN_IE:
 		case WRONG_IE:
@@ -2949,19 +2922,18 @@
 				ccard->interface.statcallb(&cmd);
 			}
 	}
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	if (chan) {
 		chan->e.ref = 0;
 		chan->e.busy = 0;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
 	dev_kfree_skb(skb);
 	eicon_schedule_tx(ccard);
 }
 
 int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que)
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk)
 {
         struct sk_buff *xmit_skb;
         struct sk_buff *skb2;
@@ -2985,13 +2957,14 @@
 		return -1;
         if (!len)
                 return 0;
-	if (chan->queued + len > EICON_MAX_QUEUE)
+
+	if ((chk) && (chan->pqueued > 1))
 		return 0;
 
-	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
+	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n",
+		chan->No, len, chan->pqueued);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	while(offset < len) {
 
 		plen = ((len - offset) > 270) ? 270 : len - offset;
@@ -3000,7 +2973,7 @@
         	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
 	        if ((!xmit_skb) || (!skb2)) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&eicon_lock, flags);
         	        eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
 			if (xmit_skb) 
 				dev_kfree_skb(skb);
@@ -3013,13 +2986,10 @@
         	chan2->ptr = chan;
 
 	        reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
-		if (((len - offset) > 270) &&
-			(chan->l2prot != ISDN_PROTO_L2_MODEM) &&
-			(chan->l2prot != ISDN_PROTO_L2_FAX) &&
-			(chan->l2prot != ISDN_PROTO_L2_TRANS)) {
-		        reqbuf->Req = IDI_N_MDATA;
+		if ((len - offset) > 270) { 
+		        reqbuf->Req = N_MDATA;
 		} else {
-		        reqbuf->Req = IDI_N_DATA;
+		        reqbuf->Req = N_DATA;
 			/* if (ack) reqbuf->Req |= N_D_BIT; */
 		}	
         	reqbuf->ReqCh = chan->e.IndCh;
@@ -3033,9 +3003,11 @@
 
 		offset += plen;
 	}
-	if (que)
+	if (que) {
 		chan->queued += len;
-	restore_flags(flags);
+		chan->pqueued++;
+	}
+	spin_unlock_irqrestore(&eicon_lock, flags);
 	eicon_schedule_tx(card);
         dev_kfree_skb(skb);
         return len;
@@ -3073,7 +3045,7 @@
         reqbuf->XBuffer.P[0] = 0;
         reqbuf->Req = ASSIGN;
         reqbuf->ReqCh = 0;
-        reqbuf->ReqId = 0xe0;
+        reqbuf->ReqId = MAN_ID;
         reqbuf->XBuffer.length = 1;
         reqbuf->Reference = 2; /* Man Entity */
 
@@ -3199,7 +3171,7 @@
         reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
 
         reqbuf->XBuffer.P[l++] = 0;
-        reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */
+        reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ;
         reqbuf->ReqCh = 0;
         reqbuf->ReqId = 1;
         reqbuf->XBuffer.length = l;
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_idi.h	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_idi.h	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN lowlevel-module for the Eicon active cards.
  * IDI-Interface
@@ -20,168 +20,30 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_idi.h,v $
- * Revision 1.9  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.8  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.7  1999/08/22 20:26:46  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/07/25 15:12:04  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5  1999/07/11 17:16:26  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.4  1999/03/29 11:19:44  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:45  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:18  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:42  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
  *
  */
 
-#ifndef IDI_H
-#define IDI_H
+#ifndef E_IDI_H
+#define E_IDI_H
 
 #include <linux/config.h>
 
-#define ASSIGN  0x01
-#define REMOVE  0xff
-	
-#define CALL_REQ 1      /* call request                             */
-#define CALL_CON 1      /* call confirmation                        */
-#define CALL_IND 2      /* incoming call connected                  */
-#define LISTEN_REQ 2    /* listen request                           */
-#define HANGUP 3        /* hangup request/indication                */
-#define SUSPEND 4       /* call suspend request/confirm             */
-#define RESUME 5        /* call resume request/confirm              */
-#define SUSPEND_REJ 6   /* suspend rejected indication              */
-#define USER_DATA 8     /* user data for user to user signaling     */
-#define CONGESTION 9    /* network congestion indication            */
-#define INDICATE_REQ 10 /* request to indicate an incoming call     */
-#define INDICATE_IND 10 /* indicates that there is an incoming call */
-#define CALL_RES 11     /* accept an incoming call                  */
-#define CALL_ALERT 12   /* send ALERT for incoming call             */
-#define INFO_REQ 13     /* INFO request                             */
-#define INFO_IND 13     /* INFO indication                          */
-#define REJECT 14       /* reject an incoming call                  */
-#define RESOURCES 15    /* reserve B-Channel hardware resources     */
-#define TEL_CTRL 16     /* Telephone control request/indication     */
-#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
-#define FAC_REG_REQ 18  /* connection idependent fac registration   */
-#define FAC_REG_ACK 19  /* fac registration acknowledge             */
-#define FAC_REG_REJ 20  /* fac registration reject                  */
-#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
-#define AOC_IND       26/* Advice of Charge                         */
-
-#define IDI_N_MDATA         (0x01)
-#define IDI_N_CONNECT       (0x02)
-#define IDI_N_CONNECT_ACK   (0x03)
-#define IDI_N_DISC          (0x04)
-#define IDI_N_DISC_ACK      (0x05)
-#define IDI_N_RESET         (0x06)
-#define IDI_N_RESET_ACK     (0x07)
-#define IDI_N_DATA          (0x08)
-#define IDI_N_EDATA         (0x09)
-#define IDI_N_UDATA         (0x0a)
-#define IDI_N_BDATA         (0x0b)
-#define IDI_N_DATA_ACK      (0x0c)
-#define IDI_N_EDATA_ACK     (0x0d)
-
-#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
-#define N_M_BIT         0x20    /* M-bit for req/ind                */
-#define N_D_BIT         0x40    /* D-bit for req/ind                */
-
-
-#define SHIFT 0x90              /* codeset shift                    */
-#define MORE 0xa0               /* more data                        */
-#define CL 0xb0                 /* congestion level                 */
-
-        /* codeset 0                                                */
-
-#define BC  0x04                /* Bearer Capability                */
-#define CAU 0x08                /* cause                            */
-#define CAD 0x0c                /* Connected address                */
-#define CAI 0x10                /* call identity                    */
-#define CHI 0x18                /* channel identification           */
-#define LLI 0x19                /* logical link id                  */
-#define CHA 0x1a                /* charge advice                    */
-#define FTY 0x1c
-#define PI  0x1e		/* Progress Indicator		    */
-#define NI  0x27		/* Notification Indicator	    */
-#define DT  0x29                /* ETSI date/time                   */
-#define KEY 0x2c                /* keypad information element       */
-#define DSP 0x28                /* display                          */
-#define OAD 0x6c                /* origination address              */
-#define OSA 0x6d                /* origination sub-address          */
-#define CPN 0x70                /* called party number              */
-#define DSA 0x71                /* destination sub-address          */
-#define RDN 0x74		/* redirecting number		    */
-#define LLC 0x7c                /* low layer compatibility          */
-#define HLC 0x7d                /* high layer compatibility         */
-#define UUI 0x7e                /* user user information            */
-#define ESC 0x7f                /* escape extension                 */
-
-#define DLC 0x20                /* data link layer configuration    */
-#define NLC 0x21                /* network layer configuration      */
-
-        /* codeset 6                                                */
-
-#define SIN 0x01                /* service indicator                */
-#define CIF 0x02                /* charging information             */
-#define DATE 0x03               /* date                             */
-#define CPS 0x07                /* called party status              */
-
-/*------------------------------------------------------------------*/
-/* return code coding                                               */
-/*------------------------------------------------------------------*/
-
-#define UNKNOWN_COMMAND         0x01    /* unknown command          */
-#define WRONG_COMMAND           0x02    /* wrong command            */
-#define WRONG_ID                0x03    /* unknown task/entity id   */
-#define WRONG_CH                0x04    /* wrong task/entity id     */
-#define UNKNOWN_IE              0x05    /* unknown information el.  */
-#define WRONG_IE                0x06    /* wrong information el.    */
-#define OUT_OF_RESOURCES        0x07    /* card out of res.         */
-#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
-#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
-#define ASSIGN_OK               0xef    /* ASSIGN OK                */
-#define OK_FC                   0xfc    /* Flow-Control RC          */
-#define READY_INT               0xfd    /* Ready interrupt          */
-#define TIMER_INT               0xfe    /* timer interrupt          */
-#define OK                      0xff    /* command accepted         */
+#undef N_DATA
+#undef ID_MASK
+
+#include "pc.h"
 
-/*------------------------------------------------------------------*/
+#define AOC_IND  26		/* Advice of Charge                         */
+#define PI  0x1e                /* Progress Indicator               */
+#define NI  0x27                /* Notification Indicator           */
+
+#define CALL_HOLD	0x22
+#define CALL_HOLD_ACK	0x24
 
 /* defines for statectrl */
 #define WAITING_FOR_HANGUP	0x01
 #define HAVE_CONN_REQ		0x02
+#define IN_HOLD			0x04
 
 typedef struct {
 	char cpn[32];
@@ -242,26 +104,6 @@
 } eicon_IND;
 
 typedef struct {
-  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
-  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
-  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
-  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
-  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
-  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
-  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
-  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
-  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
-  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
-  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
-  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
-  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
-  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
-  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
-} eicon_pr_ram;
-
-typedef struct {
 	__u8		*Data;
 	unsigned int	Size;
 	unsigned int	Len;
@@ -278,8 +120,9 @@
 extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
 extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
 extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk);
 extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm);
 #ifdef CONFIG_ISDN_TTY_FAX
 extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
 extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_io.c	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_io.c	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Code for communicating with hardware.
@@ -6,7 +6,7 @@
  * Copyright 1999,2000  by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000  Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,52 +23,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_io.c,v $
- * Revision 1.10  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.9  1999/11/18 20:55:25  armin
- * Ready_Int fix of ISA cards.
- *
- * Revision 1.8  1999/10/08 22:09:34  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.7  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.6  1999/09/21 20:35:43  armin
- * added more error checking.
- *
- * Revision 1.5  1999/08/31 11:20:11  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.4  1999/08/22 20:26:47  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3  1999/08/18 20:17:01  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.2  1999/07/25 15:12:05  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.1  1999/03/29 11:19:45  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- *
  */
 
 
 #include <linux/config.h>
 #include "eicon.h"
+#include "uxio.h"
 
 void
 eicon_io_rcv_dispatch(eicon_card *ccard) {
@@ -85,12 +45,12 @@
 	while((skb = skb_dequeue(&ccard->rcvq))) {
         	ind = (eicon_IND *)skb->data;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
         	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+			spin_unlock_irqrestore(&eicon_lock, flags);
 			if (DebugVar & 1) {
 				switch(ind->Ind) {
-					case IDI_N_DISC_ACK: 
+					case N_DISC_ACK: 
 						/* doesn't matter if this happens */ 
 						break;
 					default: 
@@ -99,11 +59,10 @@
 							ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
 				}
 			}
-			restore_flags(flags);
 	                dev_kfree_skb(skb);
 	                continue;
 	        }
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 
 		if (chan->e.complete) { /* check for rec-buffer chaining */
 			if (ind->MLength == ind->RBuffer.length) {
@@ -119,12 +78,9 @@
 			}
 		}
 		else {
-			save_flags(flags);
-			cli();
 			if (!(skb2 = skb_dequeue(&chan->e.R))) {
 				chan->e.complete = 1;
                 		eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
-				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 				continue;	
 			}
@@ -133,7 +89,6 @@
 					GFP_ATOMIC);
 			if (!skb_new) {
                 		eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
-				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 	                	dev_kfree_skb(skb2);
 				continue;	
@@ -152,14 +107,12 @@
                 	dev_kfree_skb(skb2);
 			if (ind->MLength == ind->RBuffer.length) {
 				chan->e.complete = 2;
-				restore_flags(flags);
 				idi_handle_ind(ccard, skb_new);
 				continue;
 			}
 			else {
 				chan->e.complete = 0;
 				skb_queue_tail(&chan->e.R, skb_new);
-				restore_flags(flags);
 				continue;
 			}
 		}
@@ -181,242 +134,120 @@
 
 
 /*
- *  IO-Functions for different card-types
+ *  IO-Functions for ISA cards
  */
 
 u8 ram_inb(eicon_card *card, void *adr) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 	
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        return(inb((u16)pcard->PCIreg + M_DATA));
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        return(readb(addr));
-        }
- return(0);
+	return(readb(addr));
 }
 
 u16 ram_inw(eicon_card *card, void *adr) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
-	
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
 
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        return(inw((u16)pcard->PCIreg + M_DATA));
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        return(readw(addr));
-        }
- return(0);
+	return(readw(addr));
 }
 
 void ram_outb(eicon_card *card, void *adr, u8 data) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        outb((u8)data, (u16)pcard->PCIreg + M_DATA);
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        writeb(data, addr);
-                        break;
-        }
+	writeb(data, addr);
 }
 
 void ram_outw(eicon_card *card, void *adr , u16 data) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        outw((u16)data, (u16)pcard->PCIreg + M_DATA);
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        writew(data, addr);
-                        break;
-        }
+	writew(data, addr);
 }
 
 void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) {
-        int i;
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        for(i = 0; i < len; i++) {
-                                writeb(ram_inb(card, adr + i), adrto + i);
-                        }
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                        memcpy(adrto, adr, len);
-                        break;
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        memcpy_fromio(adrto, adr, len);
-                        break;
-        }
+	memcpy_fromio(adrto, adr, len);
 }
 
 void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
-        int i;
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        for(i = 0; i < len; i++) {
-                                ram_outb(card, adrto + i, readb(adr + i));
-                        }
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                        memcpy(adrto, adr, len);
-                        break;
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        memcpy_toio(adrto, adr, len);
-                        break;
-        }
+	memcpy_toio(adrto, adr, len);
 }
 
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 /*
- * XLOG
+ *  IDI-Callback function
  */
-int
-eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
+void
+eicon_idi_callback(ENTITY *de)
 {
-	int timeout, i;
-	int divas_shared_offset = 0;
+	eicon_card *ccard = (eicon_card *)de->R;
+	struct sk_buff *skb;
+	eicon_RC *ack;
+	eicon_IND *ind;
 	int len = 0;
-	int stype = 0;
-	__u32 time = 0;
-	mi_pc_maint_t	*pcm = &xlogreq->pcm;
-        eicon_pci_card *pci_card = &card->hwif.pci;
-        eicon_isa_card *isa_card = &card->hwif.isa;
-	eicon_pr_ram  *prram = 0;
-        char *ram;
 
-	switch(card->type) {
-		case EICON_CTYPE_MAESTRAP:
-			ram = (char *)pci_card->PCIram;
-			prram = (eicon_pr_ram *)ram;
-			divas_shared_offset = DIVAS_SHARED_OFFSET;
-			len = sizeof(mi_pc_maint_t);
-			break;
-		case EICON_CTYPE_MAESTRA:
-			prram = 0;
-			divas_shared_offset = 0;
-			len = sizeof(mi_pc_maint_t);
-			break;
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-		case EICON_CTYPE_S2M:
-			prram = (eicon_pr_ram *)isa_card->shmem;
-			divas_shared_offset = 0xfb80;
-			len = sizeof(mi_pc_maint_t) - 78;
-			stype = 1;
-			break;
-		default:
-			return -ENODEV;
-	}
-
-        memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
-
-        xlogreq->pcm.rc = 0;
-        xlogreq->pcm.req = 1; /* DO_LOG */
-
-        ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
-
-	ram_outb(card, ram+1, pcm->rc); 
-	ram_outb(card, ram+0, pcm->req); 
-
-        timeout = jiffies + 50;
-        while (timeout > jiffies) {
-		pcm->rc = ram_inb(card, ram+1);
-		pcm->req = ram_inb(card, ram+0);
-                if (!pcm->req) break;
-                SLEEP(10);
-        }
-
-	if (pcm->req) {
-		return XLOG_ERR_TIMEOUT;
-	}
-
-	if (pcm->rc != OK) {
-		return XLOG_ERR_DONE;
-	}
-	
-	ram_copyfromcard(card, pcm, ram, len);
-
-	if (stype) {
-		for (i=0; i<8; i++)
-			((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
-		time =	(__u32)pcm->data.w[2] * 3600 	* 1000 +
-			(__u32)pcm->data.w[1] 		* 1000 +
-			(__u32)pcm->data.b[1] 		* 20 +
-			(__u32)pcm->data.b[0]		;
-		pcm->data.w[1] = (__u16) (time >> 16);
-		pcm->data.w[2] = (__u16) (time & 0x0000ffff);
-		pcm->data.w[0] = 2;
+	if (de->complete == 255) {
+		/* Return Code */
+		skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+		} else {
+			ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+			ack->Rc = de->Rc;
+			if (de->Rc == ASSIGN_OK) {
+				ack->RcId = de->Id;
+				de->user[1] = de->Id;
+			} else {
+				ack->RcId = de->user[1];
+			}
+			ack->RcCh = de->RcCh;
+			ack->Reference = de->user[0];
+			skb_queue_tail(&ccard->rackq, skb);
+			eicon_schedule_ack(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete);
+		}
+	} else {
+		/* Indication */
+		if (de->complete) {
+			len = de->RLength;
+		} else {
+			len = 270;
+			if (de->RLength <= 270)
+				eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n");
+		}
+		skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+		} else {
+			ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+			ind->Ind = de->Ind;
+			ind->IndId = de->user[1];
+			ind->IndCh = de->IndCh;
+			ind->MInd  = de->Ind;
+			ind->RBuffer.length = len;
+			ind->MLength = de->RLength;
+			memcpy(&ind->RBuffer.P, &de->RBuffer->P, len);
+			skb_queue_tail(&ccard->rcvq, skb);
+			eicon_schedule_rx(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete);
+		}
 	}
 
-	return XLOG_OK;
+	de->RNum = 0;
+	de->RNR = 0;
+	de->Rc = 0;
+	de->Ind = 0;
 }
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
 
 /*
  *  Transmit-Function
  */
 void
 eicon_io_transmit(eicon_card *ccard) {
-        eicon_pci_card *pci_card;
         eicon_isa_card *isa_card;
         struct sk_buff *skb;
         struct sk_buff *skb2;
         unsigned long flags;
-        char *ram, *reg, *cfg;
 	eicon_pr_ram  *prram = 0;
 	eicon_isa_com	*com = 0;
 	eicon_REQ *ReqOut = 0;
@@ -426,10 +257,11 @@
 	int ReqCount;
 	int scom = 0;
 	int tmp = 0;
+	int tmpid = 0;
 	int quloop = 1;
 	int dlev = 0;
+	ENTITY *ep = 0;
 
-	pci_card = &ccard->hwif.pci;
 	isa_card = &ccard->hwif.isa;
 
         if (!ccard) {
@@ -451,20 +283,17 @@
 			prram = (eicon_pr_ram *)isa_card->shmem;
 			break;
 #endif
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 		case EICON_CTYPE_MAESTRAP:
-			scom = 0;
-        		ram = (char *)pci_card->PCIram;
-		        reg = (char *)pci_card->PCIreg;
-        		cfg = (char *)pci_card->PCIcfg;
-			prram = (eicon_pr_ram *)ram;
+			scom = 2;
+			break;
+		case EICON_CTYPE_MAESTRAQ:
+			scom = 2;
 			break;
 		case EICON_CTYPE_MAESTRA:
-			scom = 0;
-        		ram = (char *)pci_card->PCIram;
-		        reg = (char *)pci_card->PCIreg;
-        		cfg = (char *)pci_card->PCIcfg;
-			prram = 0;
+			scom = 2;
 			break;
+#endif
 		default:
                 	eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
 			return;
@@ -474,69 +303,91 @@
 	if (!(skb2 = skb_dequeue(&ccard->sndq)))
 		quloop = 0; 
 	while(quloop) { 
-                save_flags(flags);
-                cli();
-		if (scom) {
+		spin_lock_irqsave(&eicon_lock, flags);
+		switch (scom) {
+		  case 1:
 			if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
 				if (!ccard->ReadyInt) {
 					tmp = ram_inb(ccard, &com->ReadyInt) + 1;
 					ram_outb(ccard, &com->ReadyInt, tmp);
 					ccard->ReadyInt++;
 				}
-        	                restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
        	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
 			}
-		} else {
+			break;
+		  case 0:
 	                if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
-        	                restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
        	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
         	        }
+			break;
 		}
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
+
 		chan2 = (eicon_chan_ptr *)skb2->data;
 		chan = chan2->ptr;
 		if (!chan->e.busy) {
 		 if((skb = skb_dequeue(&chan->e.X))) { 
-		  save_flags(flags);
-		  cli();
+
 		  reqbuf = (eicon_REQ *)skb->data;
 		  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
 			eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
 		  } else {
-			if (scom) {
+			spin_lock_irqsave(&eicon_lock, flags);
+
+			switch (scom) {
+			  case 1:
 				ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
 				ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
 				ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh);
-				
-			} else {
+				break;	
+			  case 0:
 				/* get address of next available request buffer */
 				ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)];
 				ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length);
 				ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
 				ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
 				ram_outb(ccard, &ReqOut->Req, reqbuf->Req); 
+				break;
 			}
+
 			dlev = 160;
+
 			if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
 
 				if (!reqbuf->Reference) { /* Signal Layer */
-					if (scom)
+					switch (scom) {
+					  case 1:
 						ram_outb(ccard, &com->ReqId, chan->e.D3Id); 
-					else
+						break;
+					  case 0:
 						ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); 
-
+						break;
+					  case 2:
+						ep = &chan->de;
+						break;
+					}
+					tmpid = chan->e.D3Id;
 					chan->e.ReqCh = 0; 
 				}
 				else {			/* Net Layer */
-					if (scom)
+					switch(scom) {
+					  case 1:
 						ram_outb(ccard, &com->ReqId, chan->e.B2Id); 
-					else
+						break;
+					  case 0:
 						ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); 
-
+						break;
+					  case 2:
+						ep = &chan->be;
+						break;
+					}
+					tmpid = chan->e.B2Id;
 					chan->e.ReqCh = 1;
 					if (((reqbuf->Req & 0x0f) == 0x08) ||
 					   ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
@@ -548,51 +399,106 @@
 
 			} else {	/* It is an ASSIGN */
 
-				if (scom)
+				switch(scom) {
+				  case 1:
 					ram_outb(ccard, &com->ReqId, reqbuf->ReqId); 
-				else
+					break;
+				  case 0:
 					ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); 
+					break;
+				  case 2:
+					if (!reqbuf->Reference) 
+						ep = &chan->de;
+					else
+						ep = &chan->be;
+					ep->Id = reqbuf->ReqId;
+					break;
+				}
+				tmpid = reqbuf->ReqId;
 
 				if (!reqbuf->Reference) 
 					chan->e.ReqCh = 0; 
 				 else
 					chan->e.ReqCh = 1; 
 			} 
-			if (scom)
+
+			switch(scom) {
+			  case 1:
 			 	chan->e.ref = ccard->ref_out++;
-			else
+				break;
+			  case 0:
 			 	chan->e.ref = ram_inw(ccard, &ReqOut->Reference);
+				break;
+			  case 2:
+				chan->e.ref = chan->No;
+				break;
+			}
 
 			chan->e.Req = reqbuf->Req;
 			ReqCount++; 
-			if (scom)
+
+			switch (scom) {
+			  case 1:
 				ram_outb(ccard, &com->Req, reqbuf->Req); 
-			else
+				break;
+			  case 0:
 				ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); 
+				break;
+			  case 2:
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+				if (!ep) break;
+				ep->callback = eicon_idi_callback;
+				ep->R = (BUFFERS *)ccard;
+				ep->user[0] = (word)chan->No;
+				ep->user[1] = (word)tmpid;
+				ep->XNum = 1;
+				ep->RNum = 0;
+				ep->RNR = 0;
+				ep->Rc = 0;
+				ep->Ind = 0;
+				ep->X->PLength = reqbuf->XBuffer.length;
+				memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+				ep->ReqCh = reqbuf->ReqCh;
+				ep->Req = reqbuf->Req;
+#endif
+				break;
+			}
 
 			chan->e.busy = 1;
+			spin_unlock_irqrestore(&eicon_lock, flags);
 	               	eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
-					reqbuf->Req, 
-					(scom) ? ram_inb(ccard, &com->ReqId) :
-						ram_inb(ccard, &ReqOut->ReqId),
+					reqbuf->Req, tmpid, 
 					reqbuf->ReqCh, reqbuf->XBuffer.length,
 					chan->e.ref); 
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+			if (scom == 2) {
+				if (ep) {
+					ccard->d->request(ep);
+					if (ep->Rc)
+						eicon_idi_callback(ep);
+				}
+			}
+#endif
 		  }
-		  restore_flags(flags);
 		  dev_kfree_skb(skb);
 		 }
 		 dev_kfree_skb(skb2);
 		} 
 		else {
-		skb_queue_tail(&ccard->sackq, skb2);
-               	eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
+			skb_queue_tail(&ccard->sackq, skb2);
+        	       	eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
 		}
 
-		if (scom)
-			quloop = 0;
-		else
-			if (!(skb2 = skb_dequeue(&ccard->sndq)))
+		switch(scom) {
+			case 1:
 				quloop = 0;
+				break;
+			case 0:
+			case 2:
+				if (!(skb2 = skb_dequeue(&ccard->sndq)))
+					quloop = 0;
+				break;
+		}
 
 	}
 	if (!scom)
@@ -603,18 +509,14 @@
 	}
 }
 
-
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
 /*
  * IRQ handler 
  */
 void
 eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
 	eicon_card *ccard = (eicon_card *)dev_id;
-        eicon_pci_card *pci_card;
         eicon_isa_card *isa_card;
-    	char *ram = 0;
-	char *reg = 0;
-	char *cfg = 0;	
 	eicon_pr_ram  *prram = 0;
 	eicon_isa_com	*com = 0;
         eicon_RC *RcIn;
@@ -646,11 +548,9 @@
 		}
 	}
 
-	pci_card = &ccard->hwif.pci;
 	isa_card = &ccard->hwif.isa;
 
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_S:
 		case EICON_CTYPE_SX:
 		case EICON_CTYPE_SCOM:
@@ -664,23 +564,6 @@
 			prram = (eicon_pr_ram *)isa_card->shmem;
 			irqprobe = &isa_card->irqprobe;
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			scom = 0;
-			ram = (char *)pci_card->PCIram;
-			reg = (char *)pci_card->PCIreg;
-			cfg = (char *)pci_card->PCIcfg;
-			irqprobe = &pci_card->irqprobe;
-			prram = (eicon_pr_ram *)ram;
-			break;
-		case EICON_CTYPE_MAESTRA:
-			scom = 0;
-			ram = (char *)pci_card->PCIram;
-			reg = (char *)pci_card->PCIreg;
-			cfg = (char *)pci_card->PCIcfg;
-			irqprobe = &pci_card->irqprobe;
-			prram = 0;
-			break;
 		default:
                 	eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
 			return;
@@ -688,7 +571,6 @@
 
 	if (*irqprobe) {
 		switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 			case EICON_CTYPE_S:
 			case EICON_CTYPE_SX:
 			case EICON_CTYPE_SCOM:
@@ -706,26 +588,11 @@
 				}
 				(*irqprobe)++;
 				break;
-#endif
-			case EICON_CTYPE_MAESTRAP:
-	        		if (readb(&ram[0x3fe])) { 
-        		               	writeb(0, &prram->RcOutput);
-				        writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-				        writew(0, &cfg[MP_IRQ_RESET + 2]);
-					writeb(0, &ram[0x3fe]);
-       			        } 
-				*irqprobe = 0;
-				break;
-			case EICON_CTYPE_MAESTRA:
-				outb(0x08, pci_card->PCIreg + M_RESET);
-				*irqprobe = 0;
-				break;
 		}
 		return;
 	}
 
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_S:
 		case EICON_CTYPE_SX:
 		case EICON_CTYPE_SCOM:
@@ -736,20 +603,6 @@
 				return;
 			} 
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
-				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
-				return;
-			} 
-			break;
-		case EICON_CTYPE_MAESTRA:
-			outw(0x3fe, pci_card->PCIreg + M_ADDR);
-			if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
-				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
-				return;
-			} 
-			break;
 	}
 
     if (scom) {
@@ -891,7 +744,6 @@
 
 	/* clear interrupt */
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_QUADRO:
 			writeb(0, isa_card->intack);
 			writeb(0, &com[0x401]);
@@ -902,19 +754,8 @@
 		case EICON_CTYPE_S2M:
 			writeb(0, isa_card->intack);
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-			writew(0, &cfg[MP_IRQ_RESET + 2]); 
-			writeb(0, &ram[0x3fe]); 
-			break;
-		case EICON_CTYPE_MAESTRA:
-			outb(0x08, pci_card->PCIreg + M_RESET);
-			outw(0x3fe, pci_card->PCIreg + M_ADDR);
-			outb(0, pci_card->PCIreg + M_DATA);
-			break;
 	}
 
   return;
 }
-
+#endif
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_isa.c	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_isa.c	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for old ISA cards.
@@ -21,62 +21,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_isa.c,v $
- * Revision 1.14  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.13  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.12  1999/11/27 12:56:19  armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.11  1999/11/25 11:33:09  armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.10  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.9  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.8  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.7  1999/08/22 20:26:48  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/07/25 15:12:06  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5  1999/04/01 12:48:33  armin
- * Changed some log outputs.
- *
- * Revision 1.4  1999/03/29 11:19:46  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:45  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:19  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:43  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -87,7 +31,7 @@
 #define release_shmem release_region
 #define request_shmem request_region
 
-char *eicon_isa_revision = "$Revision: 1.14 $";
+char *eicon_isa_revision = "$Revision: 1.16 $";
 
 #undef EICON_MCA_DEBUG
 
@@ -354,7 +298,7 @@
 	printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); 
 	if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
 		tmp = eicon_addcard(card->type, card->physmem, card->irq, 
-					((eicon_card *)card->card)->regname);
+				((eicon_card *)card->card)->regname, 0);
 		printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
 	}
 	return 0;
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_isa.h	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_isa.h	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -20,38 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_isa.h,v $
- * Revision 1.8  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.7  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.6  1999/11/15 19:37:04  keil
- * need config.h
- *
- * Revision 1.5  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.4  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.3  1999/03/29 11:19:47  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2  1999/03/02 12:37:46  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1  1999/01/01 18:09:44  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #ifndef eicon_isa_h
@@ -138,7 +106,6 @@
 	unsigned char     mvalid;   /* Flag: Memory is valid      */
 	unsigned char     ivalid;   /* Flag: IRQ is valid         */
 	unsigned char     master;   /* Flag: Card ist Quadro 1/4  */
-	void*             generic;  /* Ptr to generic card struct */
 } eicon_isa_card;
 
 /* Offsets for special locations on standard cards */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_mod.c	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_mod.c	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * 
@@ -6,11 +6,9 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de) 
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  * 
- * Thanks to    Eicon Technology GmbH & Co. oHG for
+ * Thanks to    Eicon Networks for
  *              documents, informations and hardware.
  *
- *              Deutsche Telekom AG for S2M support.
- *
  *		Deutsche Mailbox Saar-Lor-Lux GmbH
  *		for sponsoring and testing fax
  *		capabilities with Diva Server cards.
@@ -30,105 +28,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_mod.c,v $
- * Revision 1.25  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.24  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.23  2000/01/20 19:55:34  keil
- * Add FAX Class 1 support
- *
- * Revision 1.22  1999/11/27 12:56:19  armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.21  1999/11/25 11:35:10  armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- * Minor cleanup.
- *
- * Revision 1.20  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.19  1999/11/12 13:21:44  armin
- * Bugfix of undefined reference with CONFIG_MCA
- *
- * Revision 1.18  1999/10/11 18:13:25  armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.17  1999/10/08 22:09:34  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.16  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.15  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.14  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.13  1999/09/04 17:37:59  armin
- * Removed not used define, did not work and caused error
- * in 2.3.16
- *
- * Revision 1.12  1999/08/31 11:20:14  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.11  1999/08/29 17:23:45  armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10  1999/08/28 21:32:53  armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.9  1999/08/18 20:17:02  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8  1999/07/25 15:12:08  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7  1999/07/11 17:16:27  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6  1999/06/09 19:31:26  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5  1999/04/01 12:48:35  armin
- * Changed some log outputs.
- *
- * Revision 1.4  1999/03/29 11:19:47  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:47  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:21  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:44  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
-#define DRIVERPATCH ""
+#define DRIVERNAME "Eicon active ISDN driver"
+#define DRIVERRELEASE "2.0"
+#define DRIVERPATCH ".16"
+
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -139,17 +44,27 @@
 
 #include "eicon.h"
 
+#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
+
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
+
 #define INCLUDE_INLINE_FUNCS
 
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.25 $";
+static char *eicon_revision = "$Revision: 1.37.6.4 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
 extern char *eicon_idi_revision;
 
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
+			unsigned int command, unsigned long arg);
+extern void eicon_pci_init_conf(eicon_card *card);
+
 #ifdef MODULE
 #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
 #endif
@@ -158,6 +73,10 @@
 
 ulong DebugVar;
 
+spinlock_t eicon_lock;
+
+DESCRIPTOR idi_d[32];
+
 /* Parameters to be set by insmod */
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 static int   membase      = -1;
@@ -189,23 +108,6 @@
         "DIVA Server PRI/PCI"
 };
 
-static int
-getrel(char *p)
-{
-        int v = 0;
-	char *tmp = 0;
-
-	if ((tmp = strchr(p, '.')))
-		p = tmp + 1;
-        while (p[0] >= '0' && p[0] <= '9') {
-                v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0');
-		p++;
-	}
-        return v;
-
-
-}
-
 static char *
 eicon_getrev(const char *revision)
 {
@@ -229,68 +131,26 @@
 	return NULL;
 }
 
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 /*
- * Free MSN list
+ * Find pcicard with given card number 
  */
-static void
-eicon_clear_msn(eicon_card *card)
+static inline eicon_card *
+eicon_findnpcicard(int driverid)
 {
-        struct msn_entry *p = card->msn_list;
-        struct msn_entry *q;
-	unsigned long flags;
+        eicon_card *p = cards;
 
-	save_flags(flags);
-	cli();
-        card->msn_list = NULL;
-	restore_flags(flags);
         while (p) {
-                q  = p->next;
-                kfree(p);
-                p = q;
+                if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) &&
+			(p->bus == EICON_BUS_PCI))
+                        return p;
+                p = p->next;
         }
+        return (eicon_card *) 0;
 }
-
-/*
- * Find an MSN entry in the list.
- * If ia5 != 0, return IA5-encoded EAZ, else
- * return a bitmask with corresponding bit set.
- */
-static __u16
-eicon_find_msn(eicon_card *card, char *msn, int ia5)
-{
-        struct msn_entry *p = card->msn_list;
-	__u8 eaz = '0';
-
-	while (p) {
-		if (!strcmp(p->msn, msn)) {
-			eaz = p->eaz;
-			break;
-		}
-		p = p->next;
-	}
-	if (!ia5)
-		return (1 << (eaz - '0'));
-	else
-		return eaz;
-}
-
-/*
- * Find an EAZ entry in the list.
- * return a string with corresponding msn.
- */
-char *
-eicon_find_eaz(eicon_card *card, char eaz)
-{
-        struct msn_entry *p = card->msn_list;
-
-	while (p) {
-		if (p->eaz == eaz)
-			return(p->msn);
-		p = p->next;
-	}
-	return("\0");
-}
-
+#endif
+#endif /* CONFIG_PCI */
 
 static void
 eicon_rcv_dispatch(struct eicon_card *card)
@@ -337,39 +197,19 @@
 	}
 }
 
-static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
-{
-	xlogreq_t *xlr;
-	int ret_val;
-
-	if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
-		eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n");
-		return -ENOMEM;
-	}
-	if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
-		kfree(xlr);
-		return -EFAULT;
-	}
-
-	ret_val = eicon_get_xlog(card, xlr);
-
-	if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) {
-		kfree(xlr);
-		return -EFAULT;
-	}
-	kfree(xlr);
-
-	return ret_val;
-}
-
 static int
 eicon_command(eicon_card * card, isdn_ctrl * c)
 {
         ulong a;
         eicon_chan *chan;
 	eicon_cdef cdef;
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	dia_start_t dstart;
+        int idi_length = 0;
+#endif
+#endif
 	isdn_ctrl cmd;
-	char tmp[17];
 	int ret = 0;
 	unsigned long flags;
  
@@ -383,16 +223,15 @@
 				case EICON_IOCTL_GETVER:
 					return(EICON_CTRL_VERSION);
 				case EICON_IOCTL_GETTYPE:
+					if (card->bus == EICON_BUS_PCI) {
+						copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int));
+					}
 					return(card->type);
 				case EICON_IOCTL_GETMMIO:
 					switch (card->bus) {
 						case EICON_BUS_ISA:
 						case EICON_BUS_MCA:
 							return (int)card->hwif.isa.shmem;
-#if CONFIG_PCI
-						case EICON_BUS_PCI:
-							return card->hwif.pci.PCIram;
-#endif
 						default:
 							eicon_log(card, 1,
 							       "eicon: Illegal BUS type %d\n",
@@ -433,10 +272,6 @@
 						case EICON_BUS_ISA:
 						case EICON_BUS_MCA:
 							return card->hwif.isa.irq;
-#if CONFIG_PCI
-						case EICON_BUS_PCI:
-							return card->hwif.pci.irq;
-#endif
 						default:
 							eicon_log(card, 1,
 							       "eicon: Illegal BUS type %d\n",
@@ -514,7 +349,9 @@
 				case EICON_IOCTL_MANIF:
 					if (!card->flags & EICON_FLAGS_RUNNING)
 						return -ENODEV;
-					if (!card->Feature & PROTCAP_MANIF)
+					if (!card->d)
+						return -ENODEV;
+					if (!card->d->features & DI_MANAGE)
 						return -ENODEV;
 					ret = eicon_idi_manage(
 						card, 
@@ -522,49 +359,12 @@
 					return ret;
 
 				case EICON_IOCTL_GETXLOG:
-					if (!card->flags & EICON_FLAGS_RUNNING)
-						return XLOG_ERR_CARD_STATE;
-					ret = eicon_xlog(card, (xlogreq_t *)a);
-					return ret;
-#if CONFIG_PCI 
-				case EICON_IOCTL_LOADPCI:
-						if (card->flags & EICON_FLAGS_RUNNING)
-							return -EBUSY;  
-                                                if (card->bus == EICON_BUS_PCI) {
-							switch(card->type) {
-								case EICON_CTYPE_MAESTRA:
-                                                		        ret = eicon_pci_load_bri(
-		                                                                &(card->hwif.pci),
-                		                                                &(((eicon_codebuf *)a)->pci)); 
-									break;
-
-								case EICON_CTYPE_MAESTRAP:
-		                                                        ret = eicon_pci_load_pri(
-                		                                                &(card->hwif.pci),
-                                		                                &(((eicon_codebuf *)a)->pci)); 
-									break;
-							}
-                                                        if (!ret) {
-                                                                card->flags |= EICON_FLAGS_LOADED;
-                                                                card->flags |= EICON_FLAGS_RUNNING;
-								if (card->hwif.pci.channels > 1) {
-									cmd.command = ISDN_STAT_ADDCH;
-									cmd.driver = card->myid;
-									cmd.arg = card->hwif.pci.channels - 1;
-									card->interface.statcallb(&cmd);
-								}
-								cmd.command = ISDN_STAT_RUN;    
-								cmd.driver = card->myid;        
-								cmd.arg = 0;                    
-								card->interface.statcallb(&cmd);
-							} 
-                                                        return ret;
-						} else return -ENODEV;
-#endif
+					return -ENODEV;
+
 				case EICON_IOCTL_ADDCARD:
 					if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
 						return -EFAULT;
-					if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id)))
+					if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0)))
 						return -EIO;
 					return 0;
 				case EICON_IOCTL_DEBUGVAR:
@@ -577,8 +377,87 @@
 					MOD_INC_USE_COUNT;
 					return 0;
 #endif
-				default:
+				case EICON_IOCTL_LOADPCI:
+					eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n");
+					eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n");
+					eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n");
 					return -EINVAL;
+				default:	
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+					if (c->arg < EICON_IOCTL_DIA_OFFSET)
+						return -EINVAL;
+					if (copy_from_user(&dstart, (char *)a, sizeof(dstart)))
+						return -1;
+					if (!(card = eicon_findnpcicard(dstart.card_id)))
+						return -EINVAL;
+					ret = do_ioctl(NULL, NULL,
+						c->arg - EICON_IOCTL_DIA_OFFSET,
+						(unsigned long) a);
+					if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) {
+						if (card->type != EICON_CTYPE_MAESTRAQ) {
+							DIVA_DIDD_Read(idi_d, sizeof(idi_d));
+                                                        for(idi_length = 0; idi_length < 32; idi_length++) {
+                                                          if (idi_d[idi_length].type == 0) break;
+                                                        }
+                                                        if ((idi_length < 1) || (idi_length >= 32)) {
+					                  eicon_log(card, 1, "eicon: invalid idi table length.\n");
+                                                          break;
+                                                        }
+							card->d = &idi_d[idi_length - 1];
+							card->flags |= EICON_FLAGS_LOADED;
+							card->flags |= EICON_FLAGS_RUNNING;
+							eicon_pci_init_conf(card);
+							if (card->d->channels > 1) {
+								cmd.command = ISDN_STAT_ADDCH;
+								cmd.driver = card->myid;
+								cmd.arg = card->d->channels - 1;
+								card->interface.statcallb(&cmd);
+							}
+							cmd.command = ISDN_STAT_RUN;    
+							cmd.driver = card->myid;        
+							cmd.arg = 0;                    
+							card->interface.statcallb(&cmd);
+							eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n",
+								(card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI",
+								card->d->channels, card->d->features);
+						} else {
+							int i;
+							DIVA_DIDD_Read(idi_d, sizeof(idi_d));
+                                                        for(idi_length = 0; idi_length < 32; idi_length++)
+                                                          if (idi_d[idi_length].type == 0) break;
+                                                        if ((idi_length < 1) || (idi_length >= 32)) {
+					                  eicon_log(card, 1, "eicon: invalid idi table length.\n");
+                                                          break;
+                                                        }
+        						for(i = 3; i >= 0; i--) {
+								if (!(card = eicon_findnpcicard(dstart.card_id - i)))
+									return -EINVAL;
+	
+								card->flags |= EICON_FLAGS_LOADED;
+								card->flags |= EICON_FLAGS_RUNNING;
+								card->d = &idi_d[idi_length - (i+1)];
+								eicon_pci_init_conf(card);
+								if (card->d->channels > 1) {
+									cmd.command = ISDN_STAT_ADDCH;
+									cmd.driver = card->myid;
+									cmd.arg = card->d->channels - 1;
+									card->interface.statcallb(&cmd);
+								}
+								cmd.command = ISDN_STAT_RUN;    
+								cmd.driver = card->myid;        
+								cmd.arg = 0;                    
+								card->interface.statcallb(&cmd);
+								eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n",
+									4-i, card->d->channels, card->d->features);
+							}
+						}
+					}
+					return ret;
+#else
+					return -EINVAL;
+#endif
+#endif /* CONFIG_PCI */
 			}
 			break;
 		case ISDN_CMD_DIAL:
@@ -586,20 +465,15 @@
 				return -ENODEV;
 			if (!(chan = find_channel(card, c->arg & 0x1f)))
 				break;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&eicon_lock, flags);
 			if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				eicon_log(card, 1, "Dial on channel %d with state %d\n",
 					chan->No, chan->fsm_state);
 				return -EBUSY;
 			}
-			if (card->ptype == ISDN_PTYPE_EURO)
-				tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1);
-			else
-				tmp[0] = c->parm.setup.eazmsn[0];
 			chan->fsm_state = EICON_STATE_OCALL;
-			restore_flags(flags);
+			spin_unlock_irqrestore(&eicon_lock, flags);
 			
 			ret = idi_connect_req(card, chan, c->parm.setup.phone,
 						     c->parm.setup.eazmsn,
@@ -637,19 +511,7 @@
 				return -ENODEV;
 			if (!(chan = find_channel(card, c->arg & 0x1f)))
 				break;
-			if (strlen(c->parm.num)) {
-				if (card->ptype == ISDN_PTYPE_EURO) {
-					chan->eazmask = eicon_find_msn(card, c->parm.num, 0);
-				}
-				if (card->ptype == ISDN_PTYPE_1TR6) {
-					int i;
-					chan->eazmask = 0;
-					for (i = 0; i < strlen(c->parm.num); i++)
-						if (isdigit(c->parm.num[i]))
-							chan->eazmask |= (1 << (c->parm.num[i] - '0'));
-				}
-			} else
-				chan->eazmask = 0x3ff;
+			chan->eazmask = 0x3ff;
 			eicon_idi_listen_req(card, chan);
 			return 0;
 		case ISDN_CMD_CLREAZ:
@@ -680,8 +542,10 @@
 				break;
 			chan->l3prot = (c->arg >> 8);
 #ifdef CONFIG_ISDN_TTY_FAX
-			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
+			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) {
 				chan->fax = c->parm.fax;
+				eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax);
+			}
 #endif
 			return 0;
 		case ISDN_CMD_GETL3:
@@ -729,6 +593,23 @@
 				break;
 			idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
 			return 0;
+		case CAPI_PUT_MESSAGE:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if (c->parm.cmsg.Length < 8)
+				break;
+			switch(c->parm.cmsg.Command) {
+				case CAPI_FACILITY:
+					if (c->parm.cmsg.Subcommand == CAPI_REQ)
+						return(capipmsg(card, chan, &c->parm.cmsg));
+					break;
+				case CAPI_MANUFACTURER:
+				default:
+					break;
+			}
+			return 0;
         }
 	
         return -EINVAL;
@@ -787,8 +668,7 @@
                 if (!card->flags & EICON_FLAGS_RUNNING)
                         return -ENODEV;
 	
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
 		while((skb = skb_dequeue(&card->statq))) {
 
 			if ((skb->len + count) > len)
@@ -811,12 +691,12 @@
 			} else {
 				skb_pull(skb, cnt);
 				skb_queue_head(&card->statq, skb);
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				return count;
 			}
 		}
 		card->statq_entries = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 		return count;
         }
         printk(KERN_ERR
@@ -848,7 +728,7 @@
 			}
 			else
 #endif
-				ret = idi_send_data(card, chan, ack, skb, 1);
+				ret = idi_send_data(card, chan, ack, skb, 1, 1);
 			return (ret);
 		} else {
 			return -ENODEV;
@@ -895,12 +775,11 @@
 			return;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	count = strlen(buf);
 	skb = alloc_skb(count, GFP_ATOMIC);
 	if (!skb) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 		printk(KERN_ERR "eicon: could not alloc skb in putstatus\n");
 		return;
 	}
@@ -918,7 +797,7 @@
 	} else
 		card->statq_entries++;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
         if (count) {
                 cmd.command = ISDN_STAT_STAVAIL;
                 cmd.driver = card->myid;
@@ -967,7 +846,7 @@
  * link it into cards-list.
  */
 static void
-eicon_alloccard(int Type, int membase, int irq, char *id)
+eicon_alloccard(int Type, int membase, int irq, char *id, int card_id)
 {
 	int i;
 	int j;
@@ -976,9 +855,6 @@
 	char qid[5];
 #endif
         eicon_card *card;
-#if CONFIG_PCI
-	eicon_pci_card *pcic;
-#endif
 
 	qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
 	for (i = 0; i <= qloop; i++) {
@@ -1088,9 +964,9 @@
 				card->interface.channels = 1;
 				break;
 #endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 			case EICON_CTYPE_MAESTRA:
-				(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
                                 card->bus = EICON_BUS_PCI;
 				card->interface.features |=
 					ISDN_FEATURE_L2_V11096 |
@@ -1101,11 +977,26 @@
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
-				card->hwif.pci.PCIreg = pcic->PCIreg;
-				card->hwif.pci.PCIcfg = pcic->PCIcfg;
-                                card->hwif.pci.master = 1;
-                                card->hwif.pci.mvalid = pcic->mvalid;
-                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.master = card_id;
+                                card->hwif.pci.irq = irq;
+                                card->hwif.pci.type = Type;
+				card->flags = 0;
+                                card->nchannels = 2;
+				card->interface.channels = 1;
+				break;
+
+			case EICON_CTYPE_MAESTRAQ:
+                                card->bus = EICON_BUS_PCI;
+				card->interface.features |=
+					ISDN_FEATURE_L2_V11096 |
+					ISDN_FEATURE_L2_V11019 |
+					ISDN_FEATURE_L2_V11038 |
+					ISDN_FEATURE_L2_MODEM |
+					ISDN_FEATURE_L2_FAX | 
+					ISDN_FEATURE_L3_TRANSDSP |
+					ISDN_FEATURE_L3_FCLASS2;
+                                card->hwif.pci.card = (void *)card;
+                                card->hwif.pci.master = card_id;
                                 card->hwif.pci.irq = irq;
                                 card->hwif.pci.type = Type;
 				card->flags = 0;
@@ -1114,7 +1005,6 @@
 				break;
 
 			case EICON_CTYPE_MAESTRAP:
-				(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
                                 card->bus = EICON_BUS_PCI;
 				card->interface.features |=
 					ISDN_FEATURE_L2_V11096 |
@@ -1125,13 +1015,7 @@
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
-                                card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
-				card->hwif.pci.PCIreg = pcic->PCIreg;
-				card->hwif.pci.PCIram = pcic->PCIram;
-				card->hwif.pci.PCIcfg = pcic->PCIcfg;
-                                card->hwif.pci.master = 1;
-                                card->hwif.pci.mvalid = pcic->mvalid;
-                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.master = card_id;
                                 card->hwif.pci.irq = irq;
                                 card->hwif.pci.type = Type;
 				card->flags = 0;
@@ -1139,6 +1023,7 @@
 				card->interface.channels = 1;
 				break;
 #endif
+#endif
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 			case EICON_CTYPE_ISABRI:
 				if (membase == -1)
@@ -1197,6 +1082,53 @@
 			skb_queue_head_init(&card->bch[j].e.X);
 			skb_queue_head_init(&card->bch[j].e.R);
 		}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+		/* *** Diva Server *** */
+		if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2
+							 , GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate DBUFFER-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			return;
+		}
+		if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate BUFFERS-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			kfree(card->dbuf);
+			return;
+		}
+		if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			kfree(card->dbuf);
+			kfree(card->sbuf);
+			return;
+		}
+		for (j=0; j< (card->nchannels + 1); j++) {
+			memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER));
+			card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j];
+			memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+			card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)];
+
+			memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS));
+			card->bch[j].de.X = (BUFFERS *)&card->sbuf[j];
+			memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+			card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)];
+
+			memset((char *)&card->sbufp[j], 0, 270);
+			card->bch[j].de.X->P = (char *)&card->sbufp[j * 270];
+			memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270);
+			card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270];
+		}
+		/* *** */
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
+
 		card->next = cards;
 		cards = card;
 	}
@@ -1220,10 +1152,7 @@
 #endif /* CONFIG_MCA */
 #endif
 		case EICON_BUS_PCI:
-#if CONFIG_PCI
-			eicon_pci_printpar(&card->hwif.pci); 
 			break;
-#endif
 		default:
 			eicon_log(card, 1,
 			       "eicon_registercard: Illegal BUS type %d\n",
@@ -1241,8 +1170,7 @@
         return 0;
 }
 
-#ifdef MODULE
-static void
+static void 
 unregister_card(eicon_card * card)
 {
         isdn_ctrl cmd;
@@ -1260,10 +1188,7 @@
 			break;
 #endif
 		case EICON_BUS_PCI:
-#if CONFIG_PCI
-			eicon_pci_release(&card->hwif.pci);
 			break;
-#endif
 		default:
 			eicon_log(card, 1,
 			       "eicon: Invalid BUS type %d\n",
@@ -1271,7 +1196,6 @@
 			break;
         }
 }
-#endif /* MODULE */
 
 static void
 eicon_freecard(eicon_card *card) {
@@ -1295,13 +1219,17 @@
 	while((skb = skb_dequeue(&card->statq)))
 		dev_kfree_skb(skb);
 
-	eicon_clear_msn(card);
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	kfree(card->sbufp);
+	kfree(card->sbuf);
+	kfree(card->dbuf);
+#endif
 	kfree(card->bch);
 	kfree(card);
 }
 
 int
-eicon_addcard(int Type, int membase, int irq, char *id)
+eicon_addcard(int Type, int membase, int irq, char *id, int card_id)
 {
 	eicon_card *p;
 	eicon_card *q = NULL;
@@ -1314,7 +1242,7 @@
 		if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
 			return 0;
 #endif
-	eicon_alloccard(Type, membase, irq, id);
+	eicon_alloccard(Type, membase, irq, id, card_id);
         p = cards;
         while (p) {
 		registered = 0;
@@ -1333,12 +1261,14 @@
 					break;
 #endif
 				case EICON_BUS_PCI:
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 					if (eicon_registercard(p))
 						break;
 					registered = 1;
 					break;
 #endif
+#endif
 				default:
 					printk(KERN_ERR
 					       "eicon: addcard: Invalid BUS type %d\n",
@@ -1371,46 +1301,35 @@
         return (added - failed);
 }
 
-#define DRIVERNAME "Eicon active ISDN driver"
-#define DRIVERRELEASE "1"
 
-#ifdef MODULE
-#define eicon_init init_module
-#endif
-
-int
+static int __init
 eicon_init(void)
 {
 	int card_count = 0;
-	int release = 0;
 	char tmprev[50];
 
 	DebugVar = 1;
+	eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
         printk(KERN_INFO "%s Rev: ", DRIVERNAME);
 	strcpy(tmprev, eicon_revision);
 	printk("%s/", eicon_getrev(tmprev));
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_pci_revision);
-#if CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 	printk("%s/", eicon_getrev(tmprev));
 #else
 	printk("---/");
 #endif
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_isa_revision);
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 	printk("%s/", eicon_getrev(tmprev));
 #else
 	printk("---/");
 #endif
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_idi_revision);
 	printk("%s\n", eicon_getrev(tmprev));
-	release += getrel(tmprev);
-	sprintf(tmprev,"%d", release);
-        printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME,
-		DRIVERRELEASE, tmprev, DRIVERPATCH);
+        printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME,
+		DRIVERRELEASE, DRIVERPATCH);
 
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 #ifdef CONFIG_MCA
@@ -1427,18 +1346,23 @@
                        card_count++;
         };
 #else
-	card_count = eicon_addcard(0, membase, irq, id);
+	card_count = eicon_addcard(0, membase, irq, id, 0);
 #endif /* CONFIG_MCA */
 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
  
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	DivasCardsDiscover();
 	card_count += eicon_pci_find_card(id);
 #endif
+#endif
+
         if (!cards) {
 #ifdef MODULE
-#ifndef CONFIG_PCI
+#ifndef CONFIG_ISDN_DRV_EICON_PCI
 #ifndef CONFIG_ISDN_DRV_EICON_ISA
                 printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n");
+                printk(KERN_INFO "Eicon: Driver not loaded !\n");
 #else
                 printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
 #endif
@@ -1451,17 +1375,34 @@
 	} else
 		printk(KERN_INFO "Eicon: %d card%s added\n", card_count, 
                        (card_count>1)?"s":"");
-        /* No symbols to export, hide all symbols */
-        EXPORT_NO_SYMBOLS;
         return 0;
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+void DIVA_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#else
+int DivasCardNext;
+card_t DivasCards[1];
+#endif
+
+static void 
+eicon_exit(void)
 {
+#if CONFIG_PCI	
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	card_t *pCard;
+	word wCardIndex;
+	extern int Divas_major;
+	int iTmp = 0;
+#endif
+#endif
+	
         eicon_card *card = cards;
         eicon_card *last;
+
         while (card) {
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 #ifdef CONFIG_MCA
@@ -1481,10 +1422,58 @@
                 card = card->next;
 		eicon_freecard(last);
         }
+
+#if CONFIG_PCI	
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+		if ((pCard->hw) && (pCard->hw->in_use))
+		{
+			(*pCard->card_reset)(pCard);
+			
+			UxIsrRemove(pCard->hw, pCard);
+			UxCardHandleFree(pCard->hw);
+
+			if(pCard->e_tbl != NULL)
+			{
+				kfree(pCard->e_tbl);
+			}
+
+			if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+			{
+				release_region(pCard->hw->io_base,0x20);
+				release_region(pCard->hw->reset_base,0x80);
+			}
+
+                        // If this is a 4BRI ...
+                        if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+                        {
+                                // Skip over the next 3 virtual adapters
+                                wCardIndex += 3;
+
+                                // But free their handles
+				for (iTmp = 0; iTmp < 3; iTmp++)
+				{
+					pCard++;
+					UxCardHandleFree(pCard->hw);
+
+					if(pCard->e_tbl != NULL)
+					{
+						kfree(pCard->e_tbl);
+					}
+				}
+                        }
+		}
+		pCard++;
+	}
+	unregister_chrdev(Divas_major, "Divas");
+#endif
+#endif /* CONFIG_PCI */
         printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
 }
 
-#else /* no module */
+#ifndef MODULE
 
 void
 eicon_setup(char *str, int *ints)
@@ -1669,7 +1658,7 @@
 			return  ENODEV;
 	};
 	/* matching membase & irq */
-	if ( 1 == eicon_addcard(type, membase, irq, id)) { 
+	if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { 
 		mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
   		mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
 
@@ -1691,3 +1680,5 @@
 #endif /* CONFIG_MCA */
 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
 
+module_init(eicon_init);
+module_exit(eicon_exit);
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_pci.c	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_pci.c	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for PCI cards.
@@ -6,11 +6,9 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
- *		Deutsche Telekom AG for S2M support.
- *
  * 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, or (at your option)
@@ -25,53 +23,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_pci.c,v $
- * Revision 1.11  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.10  1999/08/22 20:26:49  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9  1999/08/11 21:01:11  keil
- * new PCI codefix
- *
- * Revision 1.8  1999/08/10 16:02:20  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.7  1999/06/09 19:31:29  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.6  1999/04/01 12:48:37  armin
- * Changed some log outputs.
- *
- * Revision 1.5  1999/03/29 11:19:49  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4  1999/03/02 12:37:48  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3  1999/01/24 20:14:24  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2  1999/01/10 18:46:06  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1  1999/01/01 18:09:45  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -80,894 +31,90 @@
 #include "eicon.h"
 #include "eicon_pci.h"
 
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
 
-char *eicon_pci_revision = "$Revision: 1.11 $";
+char *eicon_pci_revision = "$Revision: 1.15.6.2 $";
 
 #if CONFIG_PCI	         /* intire stuff is only for PCI */
-
-#undef EICON_PCI_DEBUG 
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 
 int eicon_pci_find_card(char *ID)
 {
-  if (pci_present()) { 
-    struct pci_dev *pdev = NULL;  
-    int pci_nextindex=0, pci_cards=0, pci_akt=0; 
-    int pci_type = PCI_MAESTRA;
-    int NoMorePCICards = FALSE;
-    char *ram, *reg, *cfg;	
-    unsigned int pram=0, preg=0, pcfg=0;
-    char did[12];
-    eicon_pci_card *aparms;
-
-   if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) {
-                  printk(KERN_WARNING
-                      "eicon_pci: Could not allocate card-struct.\n");
-                  return 0;
-   }
-
-  for (pci_cards = 0; pci_cards < 0x0f; pci_cards++)
-  {
-  do {
-      if ((pdev = pci_find_device(PCI_VENDOR_EICON,          
-                                  pci_type,                  
-                                  pdev)))                    
-	{
-              pci_nextindex++;
-              break;
-	}
-	else {
-              pci_nextindex = 0;
-              switch (pci_type) /* switch to next card type */
-               {
-               case PCI_MAESTRA:
-                 pci_type = PCI_MAESTRAQ; break;
-               case PCI_MAESTRAQ:
-                 pci_type = PCI_MAESTRAQ_U; break;
-               case PCI_MAESTRAQ_U:
-                 pci_type = PCI_MAESTRAP; break;
-               default:
-               case PCI_MAESTRAP:
-                 NoMorePCICards = TRUE;
-               }
-	}
-     }
-     while (!NoMorePCICards);
-     if (NoMorePCICards)
-        {
-           if (pci_cards < 1) {
-           printk(KERN_INFO "Eicon: No supported PCI cards found.\n");
-	   kfree(aparms);	
-           return 0;
-           }
-           else
-           {
-           printk(KERN_INFO "Eicon: %d PCI card%s registered.\n",
-			pci_cards, (pci_cards > 1) ? "s":"");
-	   kfree(aparms);	
-           return (pci_cards);
-           }
-        }
-
-   pci_akt = 0;
-   switch(pci_type)
-   {
-    case PCI_MAESTRA:
-         printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n");
-          aparms->type = EICON_CTYPE_MAESTRA;
-
-          aparms->irq = pdev->irq;
-          preg = pdev->base_address[ 2] & 0xfffffffc;
-          pcfg = pdev->base_address[ 1] & 0xffffff80;
-
-#ifdef EICON_PCI_DEBUG
-          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
-          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg);
-          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg);
-#endif
-	 pci_akt = 1;
-         break;
+	int pci_cards = 0;
+	int card_id = 0;
+	int had_q = 0;
+	int ctype = 0;
+	char did[20];
+	card_t *pCard;
+	word wCardIndex;
 
-    case PCI_MAESTRAQ:
-    case PCI_MAESTRAQ_U:
-         printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n");
-         pci_cards--;
-	 pci_akt = 0;
-         break;
-
-    case PCI_MAESTRAP:
-         printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
-          aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
-          aparms->irq = pdev->irq;
-          pram = pdev->base_address[ 0] & 0xfffff000;
-          preg = pdev->base_address[ 2] & 0xfffff000;
-          pcfg = pdev->base_address[ 4] & 0xfffff000;
-
-#ifdef EICON_PCI_DEBUG
-          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
-          printk(KERN_DEBUG "eicon_pci: ram=0x%x\n",
-               (pram));
-          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n",
-               (preg));
-          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n",
-               (pcfg));
-#endif
-	  pci_akt = 1;
-	  break;	
-    default:
-         printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n");
-         pci_cards--;
-	 pci_akt = 0;
-	 break;
-   }
-
-	if (pci_akt) {
-		/* remapping memory */
-		switch(pci_type)
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+	if ((pCard->hw) && (pCard->hw->in_use))
 		{
-    		case PCI_MAESTRA:
-			aparms->PCIreg = (unsigned int) preg;
-			aparms->PCIcfg = (unsigned int) pcfg;
-			if (check_region((aparms->PCIreg), 0x20)) {
-				printk(KERN_WARNING "eicon_pci: reg port already in use !\n");
-				aparms->PCIreg = 0;
-				break;	
-			} else {
-				request_region(aparms->PCIreg, 0x20, "eicon reg");
-			}
-			if (check_region((aparms->PCIcfg), 0x80)) {
-				printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
-				aparms->PCIcfg = 0;
-				release_region(aparms->PCIreg, 0x20);
-				break;	
-			} else {
-				request_region(aparms->PCIcfg, 0x80, "eicon cfg");
+			switch(pCard->hw->card_type) {
+				case DIA_CARD_TYPE_DIVA_SERVER:
+					ctype = EICON_CTYPE_MAESTRAP;
+					card_id++;
+					had_q = 0;
+					break;
+				case DIA_CARD_TYPE_DIVA_SERVER_B:
+					ctype = EICON_CTYPE_MAESTRA;
+					card_id++;
+					had_q = 0;
+					break;
+				case DIA_CARD_TYPE_DIVA_SERVER_Q:
+					ctype = EICON_CTYPE_MAESTRAQ;
+					if (!had_q)
+						card_id++;
+					if (++had_q >=4)
+						had_q = 0;
+					break;
+				default:
+					printk(KERN_ERR "eicon_pci: unknown card type %d !\n",
+						pCard->hw->card_type);
+					goto err;
 			}
-			break;
-    		case PCI_MAESTRAQ:
-		case PCI_MAESTRAQ_U:
-		case PCI_MAESTRAP:
-			aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000);
-			ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET);
-			reg =  ioremap(preg, 0x4000);
-			cfg =  ioremap(pcfg, 0x1000);	
-			aparms->PCIram = (unsigned int) ram;
-			aparms->PCIreg = (unsigned int) reg;
-			aparms->PCIcfg = (unsigned int) cfg;
-			break;
-		 }
-		if ((!aparms->PCIreg) || (!aparms->PCIcfg)) {
-			printk(KERN_ERR "eicon_pci: Card could not be added !\n");
-			pci_cards--;
-		} else {
-			aparms->mvalid = 1;
-	
 			sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards);
-
-			printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did);
-
-			if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) {
+			if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) {
 				printk(KERN_ERR "eicon_pci: Card could not be added !\n");
-				pci_cards--;
+			} else {
+				pci_cards++;
+				printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n",
+					eicon_ctype_name[ctype], did, card_id);
 			}
+err:;
 		}
+		pCard++;
 	}
-
-  }
- } else
-	printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n");
- return 0;
-}
-
-/*
- * Checks protocol file id for "F#xxxx" string fragment to
- * extract the features, supported by this protocol version.
- * binary representation of the feature string value is returned
- * in *value. The function returns 0 if feature string was not
- * found or has a wrong format, else 1.
- */
-static int GetProtFeatureValue(char *sw_id, int *value)
-{
-  __u8 i, offset;
-
-  while (*sw_id)
-  {
-    if ((sw_id[0] == 'F') && (sw_id[1] == '#'))
-    {
-      sw_id = &sw_id[2];
-      for (i=0, *value=0; i<4; i++, sw_id++)
-      {
-        if ((*sw_id >= '0') && (*sw_id <= '9'))
-        {
-          offset = '0';
-        }
-        else if ((*sw_id >= 'A') && (*sw_id <= 'F'))
-        {
-          offset = 'A' + 10;
-        }
-        else if ((*sw_id >= 'a') && (*sw_id <= 'f'))
-        {
-          offset = 'a' + 10;
-        }
-        else
-        {
-          return 0;
-        }
-        *value |= (*sw_id - offset) << (4*(3-i));
-      }
-      return 1;
-    }
-    else
-    {
-      sw_id++;
-    }
-  }
-  return 0;
-}
-
-
-void
-eicon_pci_printpar(eicon_pci_card *card) {
-        switch (card->type) {
-                case EICON_CTYPE_MAESTRA:
-			printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n",
-				eicon_ctype_name[card->type],
-				(unsigned int)card->PCIreg,
-				(unsigned int)card->PCIcfg,
-				card->irq); 
-			break;
-                case EICON_CTYPE_MAESTRAQ:
-                case EICON_CTYPE_MAESTRAQ_U:
-                case EICON_CTYPE_MAESTRAP:
-			printk(KERN_INFO "%s at 0x%x, irq %d\n",
-				eicon_ctype_name[card->type],
-				(unsigned int)card->shmem,
-				card->irq); 
-#ifdef EICON_PCI_DEBUG
-		        printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram);
-		        printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg);
-		        printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); 
-#endif
-			break;
-	}
-}
-
-
-static void
-eicon_pci_release_shmem(eicon_pci_card *card) {
-	if (!card->master)
-		return;
-	if (card->mvalid) {
-        	switch (card->type) {
-                	case EICON_CTYPE_MAESTRA:
-			        /* reset board */
-				outb(0, card->PCIcfg + 0x4c);	/* disable interrupts from PLX */
-				outb(0, card->PCIreg + M_RESET);
-				SLEEP(20);
-				outb(0, card->PCIreg + M_ADDRH);
-				outw(0, card->PCIreg + M_ADDR);
-				outw(0, card->PCIreg + M_DATA);
-
-				release_region(card->PCIreg, 0x20);
-				release_region(card->PCIcfg, 0x80);
-				break;
-                	case EICON_CTYPE_MAESTRAQ:
-	                case EICON_CTYPE_MAESTRAQ_U:
-	                case EICON_CTYPE_MAESTRAP:
-			        /* reset board */
-		        	writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
-			        SLEEP(20);
-			        writeb(0, card->PCIreg + MP_RESET);
-			        SLEEP(20);
-
-				iounmap((void *)card->shmem);
-				iounmap((void *)card->PCIreg);
-				iounmap((void *)card->PCIcfg);
-				break;
-		}
-	}
-	card->mvalid = 0;
-}
-
-static void
-eicon_pci_release_irq(eicon_pci_card *card) {
-	if (!card->master)
-		return;
-	if (card->ivalid)
-		free_irq(card->irq, card);
-	card->ivalid = 0;
+	return pci_cards;
 }
 
 void
-eicon_pci_release(eicon_pci_card *card) {
-        eicon_pci_release_irq(card);
-        eicon_pci_release_shmem(card);
-}
-
-/*
- * Upload buffer content to adapters shared memory
- * on verify error, 1 is returned and a message is printed on screen
- * else 0 is returned
- * Can serve IO-Type and Memory type adapters
- */
-int eicon_upload(t_dsp_download_space   *p_para,
-            __u16                 length,   /* byte count */
-            __u8                  *buffer,
-            int                   verify)
-{
-  __u32               i, dwdata = 0, val = 0, timeout;
-  __u16               data;
-  eicon_pci_boot *boot = 0;
-
-  switch (p_para->type) /* actions depend on type of union */
-  {
-    case DL_PARA_IO_TYPE:
-      for (i=0; i<length; i+=2)
-      {
-	outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
-	outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
-	/* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */
-	outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); 
-      }
-      if (verify) /* check written block */
-      {
-        for (i=0; i<length; i+=2)
-        {
-	  outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
-          outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
-          data = inw(p_para->dat.io.ioDATA);
-          if (data != *(u16 *)&buffer[i])
-          {
-            p_para->dat.io.r3addr  += i;
-            p_para->dat.io.BadData  = data;
-            p_para->dat.io.GoodData = *(u16 *)&buffer[i];
-            return 1;
-          }
-        }
-      }
-      break;
-
-    case DL_PARA_MEM_TYPE:
-      boot = p_para->dat.mem.boot;
-      writel(p_para->dat.mem.r3addr, &boot->addr);
-      for (i=0; i<length; i+=4)
-      {
-        writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
-      }
-      if (verify) /* check written block */
-      {
-        for (i=0; i<length; i+=4)
-        {
-          dwdata = readl(&boot->data[i]);
-          if (((u32 *)buffer)[i >> 2] != dwdata)
-          {
-            p_para->dat.mem.r3addr  += i;
-            p_para->dat.mem.BadData  = dwdata;
-            p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2];
-            return 1;
-          }
-        }
-      }
-      writel(((length + 3) / 4), &boot->len);  /* len in dwords */
-      writel(2, &boot->cmd);
-
-	timeout = jiffies + 20;
-	while (timeout > jiffies) {
-		val = readl(&boot->cmd);
-		if (!val) break;
-		SLEEP(2);
-	}
-	if (val)
-         {
-		p_para->dat.mem.timeout = 1;
-		return 1;
-	 }
-      break;
-  }
-  return 0;
-}
-
-
-/* show header information of code file */
-static
-int eicon_pci_print_hdr(unsigned char *code, int offset)
+eicon_pci_init_conf(eicon_card *card)
 {
-  unsigned char hdr[80];
-  int i, fvalue = 0;
-
-  i = 0;
-  while ((i < (sizeof(hdr) -1))
-          && (code[offset + i] != '\0')
-          && (code[offset + i] != '\r')
-          && (code[offset + i] != '\n'))
-   {
-     hdr[i] = code[offset + i];
-     i++;
-   }
-   hdr[i] = '\0';
-   printk(KERN_DEBUG "Eicon: loading %s\n", hdr);
-   if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue);
-    else return(0);
-}
-
+	int j;
 
-/*
- * Configure a card, download code into BRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
-        int               i,j;
-        int               timeout;
-	unsigned int	  offset, offp=0, size, length;
-	int		  signature = 0;
-	int		  FeatureValue = 0;
-        eicon_pci_codebuf cbuf;
-	t_dsp_download_space dl_para;
-	t_dsp_download_desc  dsp_download_table;
-        unsigned char     *code;
-	unsigned int	  reg;
-	unsigned int	  cfg;
-
-        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
-                return -EFAULT;
-
-	reg = card->PCIreg;
-	cfg = card->PCIcfg;
-
-	/* reset board */
-	outb(0, reg + M_RESET);
-	SLEEP(10);
-	outb(0, reg + M_ADDRH);
-	outw(0, reg + M_ADDR);
-	outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: reset card\n");
-#endif
+	/* initializing some variables */
+	card->ReadyInt = 0;
 
-	/* clear shared memory */
-	outb(0xff, reg + M_ADDRH);
-	outw(0, reg + M_ADDR);
-	for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA);
-	SLEEP(10);
+	for(j = 0; j < 256; j++)
+		card->IdTable[j] = NULL;
 
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: clear shared memory\n");
-#endif
-
-	/* download protocol and dsp file */
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
-#endif
-
-       	/* Allocate code-buffer */
-       	if (!(code = kmalloc(400, GFP_KERNEL))) {
-                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
-       	        return -ENOMEM;
-        }
-
-	/* prepare protocol upload */
-	dl_para.type		= DL_PARA_IO_TYPE;
-	dl_para.dat.io.ioADDR	= reg + M_ADDR;
-	dl_para.dat.io.ioADDRH	= reg + M_ADDRH;
-	dl_para.dat.io.ioDATA	= reg + M_DATA;
-
-	for (j = 0; j <= cbuf.dsp_code_num; j++) 
-	 {	
-	   if (j == 0)  size = cbuf.protocol_len;
-	           else size = cbuf.dsp_code_len[j];
-
-        	offset = 0;
-
-		if (j == 0) dl_para.dat.io.r3addr = 0;
-		if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE +
-					((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
-		if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE;
-		if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32);
-
-           do  /* download block of up to 400 bytes */
-            {
-              length = ((size - offset) >= 400) ? 400 : (size - offset);
-
-        	if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
-                	kfree(code);
-	                return -EFAULT;
-        	}
-
-		if ((offset == 0) && (j < 2)) {
-		       	FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
-#ifdef EICON_PCI_DEBUG
-	if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue);
-#endif
-			if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
-                  		printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
-				kfree(code);
-		                return -EFAULT;
-			}
-                	((eicon_card *)card->card)->Feature = FeatureValue;
-		}
-
-		if (eicon_upload(&dl_para, length, code, 1))
-		{
-                  printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
-		  kfree(code);
-                  return -EIO;
-		}
-              /* move onto next block */
-              offset += length;
-	      dl_para.dat.io.r3addr += length;
-            } while (offset < size);
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset);
-#endif
-	offp += size;
+	for(j = 0; j < (card->d->channels + 1); j++) {
+		card->bch[j].e.busy = 0;
+		card->bch[j].e.D3Id = 0;
+		card->bch[j].e.B2Id = 0;
+		card->bch[j].e.ref = 0;
+		card->bch[j].e.Req = 0;
+		card->bch[j].e.complete = 1;
+		card->bch[j].fsm_state = EICON_STATE_NULL;
 	}
-	kfree(code);	
-
-	/* clear signature */
-	outb(0xff, reg + M_ADDRH);
-	outw(0x1e, reg + M_ADDR);
-	outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
-	/* copy configuration data into shared memory */
-	outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA);
-	outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA);
-	outw(10,reg + M_ADDR); outb(0, reg + M_DATA);
-	outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA);
-	outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA);
-	outw(13,reg + M_ADDR); outb(0, reg + M_DATA);                 /* XInterface */
-	outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA);
-	outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA);
-	outw(16,reg + M_ADDR); outb(0, reg + M_DATA);                 /* HandsetType */
-	outw(17,reg + M_ADDR); outb(0, reg + M_DATA);                 /* SigFlags */
-	outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA);
-	outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA);
-	outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA);
-	outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA);
-
-	for (i=0;i<32;i++)
-	{
-		outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA);
-		outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA);
-		outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA);
-		outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA);
-		outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA);
-		outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA);
-	}
-
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: starting CPU...\n");
-#endif
-	/* let the CPU run */
-	outw(0x08, reg + M_RESET);
-
-        timeout = jiffies + (5*HZ);
-        while (timeout > jiffies) {
-	   outw(0x1e, reg + M_ADDR);	
-           signature = inw(reg + M_DATA);
-           if (signature == DIVAS_SIGNATURE) break;
-           SLEEP(2);
-         }
-        if (signature != DIVAS_SIGNATURE)
-         {
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE);
-#endif
-           printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n");
-           return -EIO; 
-         }
-#ifdef EICON_PCI_DEBUG
-        printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
-        /* get serial number and number of channels supported by card */
-	outb(0xff, reg + M_ADDRH);
-	outw(0x3f6, reg + M_ADDR);
-        card->channels = inw(reg + M_DATA);
-        card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26);
-        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
-        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
-        /* test interrupt */
-        card->irqprobe = 1;
-
-        if (!card->ivalid) {
-                if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
-                 {
-                  printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
-                  return -EIO;
-                 }
-        }
-        card->ivalid = 1;
-
-#ifdef EICON_PCI_DEBUG
-        printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
-        /* Trigger an interrupt and check if it is delivered */
-        outb(0x41, cfg + 0x4c);		/* enable PLX for interrupts */
-	outb(0x89, reg + M_RESET);	/* place int request */
-
-        timeout = jiffies + 20;
-        while (timeout > jiffies) {
-          if (card->irqprobe != 1) break;
-          SLEEP(5);
-         }
-        if (card->irqprobe == 1) {
-           free_irq(card->irq, card); 
-           card->ivalid = 0; 
-           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
-           return -EIO;
-         }
-
-   /* initializing some variables */
-   ((eicon_card *)card->card)->ReadyInt = 0;
-   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
-   for(j=0; j< (card->channels + 1); j++) {
-                ((eicon_card *)card->card)->bch[j].e.busy = 0;
-                ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
-                ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
-                ((eicon_card *)card->card)->bch[j].e.ref = 0;
-                ((eicon_card *)card->card)->bch[j].e.Req = 0;
-                ((eicon_card *)card->card)->bch[j].e.complete = 1;
-                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
-   }
-
-   printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
 }
 
-
-/*
- * Configure a card, download code into PRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
-        eicon_pci_boot    *boot;
-	eicon_pr_ram  *prram;
-        int               i,j;
-        int               timeout;
-	int		  FeatureValue = 0;
-	unsigned int	  offset, offp=0, size, length;
-	unsigned long int signature = 0;
-	t_dsp_download_space dl_para;
-	t_dsp_download_desc  dsp_download_table;
-        eicon_pci_codebuf cbuf;
-        unsigned char     *code;
-	unsigned char	  req_int;
-    	char *ram, *reg, *cfg;	
-
-        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
-                return -EFAULT;
-
-        boot = &card->shmem->boot;
-	ram = (char *)card->PCIram;
-	reg = (char *)card->PCIreg;
-	cfg = (char *)card->PCIcfg;
-	prram = (eicon_pr_ram *)ram;
-
-	/* reset board */
-	writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
-	SLEEP(20);
-	writeb(0, card->PCIreg + MP_RESET);
-	SLEEP(20);
-
-	/* set command count to 0 */
-	writel(0, &boot->reserved); 
-
-	/* check if CPU increments the life word */
-        i = readw(&boot->live);
-        SLEEP(20);
-        if (i == readw(&boot->live)) {
-           printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n");
-           return -EIO;
-         }
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n");
-#endif
-
-	/* download firmware : DSP and Protocol */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
 #endif
-
-       	/* Allocate code-buffer */
-       	if (!(code = kmalloc(400, GFP_KERNEL))) {
-                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
-       	        return -ENOMEM;
-        }
-
-	/* prepare protocol upload */
-	dl_para.type		= DL_PARA_MEM_TYPE;
-	dl_para.dat.mem.boot	= boot;
-
-        for (j = 0; j <= cbuf.dsp_code_num; j++)
-         {
-	   if (j==0) size = cbuf.protocol_len;
-		else size = cbuf.dsp_code_len[j];	
-
-           if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */
-
-		if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR;
-		if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE +
-					((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
-		if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE;
-		if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32);
-
-           offset = 0;
-           do  /* download block of up to 400 bytes */
-            {
-              length = ((size - offset) >= 400) ? 400 : (size - offset);
-
-        	if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
-                	kfree(code);
-	                return -EFAULT;
-        	}
-
-		if ((offset == 0) && (j < 2)) {
-	           	FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
-#ifdef EICON_PCI_DEBUG
-	if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue);
-#endif
-			if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
-                  		printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
-				kfree(code);
-		                return -EFAULT;
-			}
-                	((eicon_card *)card->card)->Feature = FeatureValue;
-		}
-
-		if (eicon_upload(&dl_para, length, code, 1))
-		{
-		  if (dl_para.dat.mem.timeout == 0)
-	                  printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
-			else
-			  printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n");
-		  kfree(code);
-                  return -EIO;
-		}
-
-              /* move onto next block */
-              offset += length;
-	      dl_para.dat.mem.r3addr += length;
-            } while (offset < size);
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset);
-#endif
-	 offp += size;
-         }
-	 kfree(code);	
-
-	/* initialize the adapter data structure */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
-        /* clear out config space */
-        for (i = 0; i < 256; i++) writeb(0, &ram[i]);
-
-        /* copy configuration down to the card */
-        writeb(cbuf.tei, &ram[8]);
-        writeb(cbuf.nt2, &ram[9]);
-        writeb(0, &ram[10]);
-        writeb(cbuf.WatchDog, &ram[11]);
-        writeb(cbuf.Permanent, &ram[12]);
-        writeb(cbuf.XInterface, &ram[13]);
-        writeb(cbuf.StableL2, &ram[14]);
-        writeb(cbuf.NoOrderCheck, &ram[15]);
-        writeb(cbuf.HandsetType, &ram[16]);
-        writeb(0, &ram[17]);
-        writeb(cbuf.LowChannel, &ram[18]);
-        writeb(cbuf.ProtVersion, &ram[19]);
-        writeb(cbuf.Crc4, &ram[20]);
-        for (i = 0; i < 32; i++)
-         {
-           writeb(cbuf.l[0].oad[i], &ram[32 + i]);
-           writeb(cbuf.l[0].osa[i], &ram[64 + i]);
-           writeb(cbuf.l[0].spid[i], &ram[96 + i]);
-           writeb(cbuf.l[1].oad[i], &ram[128 + i]);
-           writeb(cbuf.l[1].osa[i], &ram[160 + i]);
-           writeb(cbuf.l[1].spid[i], &ram[192 + i]);
-         }
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: configured card OK\n");
-#endif
-
-	/* start adapter */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: tell card to start...\n");
-#endif
-        writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */
-        writel(3, &boot->cmd); /* DIVAS_START_CMD */
-
-        /* wait till card ACKs */
-        timeout = jiffies + (5*HZ);
-        while (timeout > jiffies) {
-           signature = readl(&boot->signature);
-           if ((signature >> 16) == DIVAS_SIGNATURE) break;
-           SLEEP(2);
-         }
-        if ((signature >> 16) != DIVAS_SIGNATURE)
-         {
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE);
-#endif
-           printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n");
-           return -EIO;
-         }
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
-	/* get serial number and number of channels supported by card */
-        card->channels = readb(&ram[0x3f6]);
-        card->serial = readl(&ram[0x3f0]);
-        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
-        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
-	/* test interrupt */
-	readb(&ram[0x3fe]);
-        writeb(0, &ram[0x3fe]); /* reset any pending interrupt */
-	readb(&ram[0x3fe]);
-
-        writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-        writew(0, &cfg[MP_IRQ_RESET + 2]);
-
-        card->irqprobe = 1;
-
-	if (!card->ivalid) {
-	        if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) 
-        	 {
-	          printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
-        	  return -EIO;
-	         }
-	}
-	card->ivalid = 1;
-
-        req_int = readb(&prram->ReadyInt);
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
-        req_int++;
-        /* Trigger an interrupt and check if it is delivered */
-        writeb(req_int, &prram->ReadyInt);
-
-        timeout = jiffies + 20;
-        while (timeout > jiffies) {
-          if (card->irqprobe != 1) break;
-          SLEEP(2);
-         }
-        if (card->irqprobe == 1) {
-           free_irq(card->irq, card);
-	   card->ivalid = 0;
-           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
-           return -EIO;
-         }
-
-   /* initializing some variables */
-   ((eicon_card *)card->card)->ReadyInt = 0;
-   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
-   for(j=0; j< (card->channels + 1); j++) {
-		((eicon_card *)card->card)->bch[j].e.busy = 0;
-		((eicon_card *)card->card)->bch[j].e.D3Id = 0;
-		((eicon_card *)card->card)->bch[j].e.B2Id = 0;
-		((eicon_card *)card->card)->bch[j].e.ref = 0;
-		((eicon_card *)card->card)->bch[j].e.Req = 0;
-                ((eicon_card *)card->card)->bch[j].e.complete = 1;
-                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
-   }
-
-   printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
-}
-
 #endif	/* CONFIG_PCI */
 
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/eicon_pci.h linux/drivers/isdn/eicon/eicon_pci.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/eicon_pci.h	Wed May  3 17:16:39 2000
+++ linux/drivers/isdn/eicon/eicon_pci.h	Mon Dec  3 21:07:21 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
  *
@@ -19,26 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_pci.h,v $
- * Revision 1.4  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.3  1999/03/29 11:19:51  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2  1999/03/02 12:37:50  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1  1999/01/01 18:09:46  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #ifndef eicon_pci_h
@@ -46,147 +26,20 @@
 
 #ifdef __KERNEL__
 
-
-#define PCI_VENDOR_EICON        0x1133
-#define PCI_DIVA_PRO20          0xe001	/* Not supported */
-#define PCI_DIVA20              0xe002	/* Not supported */
-#define PCI_DIVA_PRO20_U        0xe003	/* Not supported */
-#define PCI_DIVA20_U            0xe004	/* Not supported */
-#define PCI_MAESTRA             0xe010
-#define PCI_MAESTRAQ            0xe012
-#define PCI_MAESTRAQ_U          0xe013
-#define PCI_MAESTRAP            0xe014
-
-#define DIVA_PRO20          1
-#define DIVA20              2
-#define DIVA_PRO20_U        3
-#define DIVA20_U            4
-#define MAESTRA             5
-#define MAESTRAQ            6
-#define MAESTRAQ_U          7
-#define MAESTRAP            8
-
-#define TRUE  1
-#define FALSE 0
-
-#define DIVAS_SIGNATURE 0x4447
-
-
-/* MAESTRA BRI PCI */
-
-#define M_RESET		0x10		/* offset of reset register */
-#define M_DATA		0x00		/* offset of data register */
-#define M_ADDR		0x04		/* offset of address register */
-#define M_ADDRH		0x0c		/* offset of high address register */
-
-#define M_DSP_CODE_LEN            0xbf7d0000
-#define M_DSP_CODE                0xbf7d0004  /* max 128K DSP-Code */ 
-#define M_DSP_CODE_BASE           0xbf7a0000  
-#define M_MAX_DSP_CODE_SIZE       0x00050000  /* max 320K DSP-Code (Telindus) */
-
-
-
-/* MAESTRA PRI PCI */
-
-#define MP_SHARED_RAM_OFFSET 0x1000  /* offset of shared RAM base in the DRAM memory bar */
-
-#define MP_IRQ_RESET     0xc18       /* offset of interrupt status register in the CONFIG memory bar */
-#define MP_IRQ_RESET_VAL 0xfe        /* value to clear an interrupt */
-
-#define MP_PROTOCOL_ADDR 0xa0011000  /* load address of protocol code */
-#define MP_DSP_ADDR      0xa03c0000  /* load address of DSP code */
-#define MP_MAX_PROTOCOL_CODE_SIZE  0x000a0000   /* max 640K Protocol-Code */
-#define MP_DSP_CODE_BASE           0xa03a0000
-#define MP_MAX_DSP_CODE_SIZE       0x00060000   /* max 384K DSP-Code */
-
-#define MP_RESET         0x20        /* offset of RESET register in the DEVICES memory bar */
-
-/* RESET register bits */
-#define _MP_S2M_RESET    0x10        /* active lo   */
-#define _MP_LED2         0x08        /* 1 = on      */
-#define _MP_LED1         0x04        /* 1 = on      */
-#define _MP_DSP_RESET    0x02        /* active lo   */
-#define _MP_RISC_RESET   0x81        /* active hi, bit 7 for compatibility with old boards */
-
-/* boot interface structure */
-typedef struct {
-	__u32 cmd	__attribute__ ((packed));
-	__u32 addr	__attribute__ ((packed));
-	__u32 len	__attribute__ ((packed));
-	__u32 err	__attribute__ ((packed));
-	__u32 live	__attribute__ ((packed));
-	__u32 reserved[(0x1020>>2)-6] __attribute__ ((packed));
-	__u32 signature	__attribute__ ((packed));
-	__u8 data[1];    /* real interface description */
-} eicon_pci_boot;
-
-
-#define DL_PARA_IO_TYPE   0
-#define DL_PARA_MEM_TYPE  1
-
-typedef struct tag_dsp_download_space
-{
-  __u16 type;  /* see definitions above to differ union elements */
-  union
-  {
-    struct
-    {
-      __u32               r3addr;
-      __u16               ioADDR;
-      __u16               ioADDRH;
-      __u16               ioDATA;
-      __u16               BadData;  /* in case of verify error */
-      __u16               GoodData;
-    } io;     /* for io based adapters */
-    struct
-    {
-      __u32               r3addr;
-      eicon_pci_boot	  *boot;
-      __u32               BadData;  /* in case of verify error */
-      __u32               GoodData;
-      __u16               timeout;
-    } mem;    /* for memory based adapters */
-  } dat;
-} t_dsp_download_space;
-
-
-/* Shared memory */
-typedef union {
-	eicon_pci_boot boot;
-} eicon_pci_shmem;
-
 /*
  * card's description
  */
 typedef struct {
-	int		  ramsize;
 	int   		  irq;	    /* IRQ		          */
-	unsigned int      PCIram;
-	unsigned int	  PCIreg;
-	unsigned int	  PCIcfg;
-	long int   	  serial;   /* Serial No.		  */
 	int		  channels; /* No. of supported channels  */
         void*             card;
-        eicon_pci_shmem*  shmem;    /* Shared-memory area         */
-        unsigned char*    intack;   /* Int-Acknowledge            */
-        unsigned char*    stopcpu;  /* Writing here stops CPU     */
-        unsigned char*    startcpu; /* Writing here starts CPU    */
         unsigned char     type;     /* card type                  */
-        unsigned char     irqprobe; /* Flag: IRQ-probing          */
-        unsigned char     mvalid;   /* Flag: Memory is valid      */
-        unsigned char     ivalid;   /* Flag: IRQ is valid         */
         unsigned char     master;   /* Flag: Card is Quadro 1/4   */
-        void*             generic;  /* Ptr to generic card struct */
 } eicon_pci_card;
 
-
-
-extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern void eicon_pci_release(eicon_pci_card *card);
-extern void eicon_pci_printpar(eicon_pci_card *card);
 extern int eicon_pci_find_card(char *ID);
 
 #endif  /* __KERNEL__ */
 
 #endif	/* eicon_pci_h */
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/fourbri.c linux/drivers/isdn/eicon/fourbri.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/fourbri.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/fourbri.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,573 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.7  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Diva Server 4BRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+#include "constant.h"
+#include "adapter.h"
+#include "uxio.h"
+
+#define TEST_INT_DIVAS_Q	0x13
+
+#define	DIVAS_MAINT_OFFSET	0xff00	/* value for 4BRI card */
+#define MQ_BOARD_DSP_OFFSET 0x00a00000
+#define MQ_DSP1_ADDR_OFFSET 0x00000008
+#define MQ_DSP_JUNK_OFFSET  0x00000400
+#define MQ_DSP1_DATA_OFFSET 0x00000000
+#define MQ_BOARD_ISAC_DSP_RESET  0x00800028
+#define MQ_BREG_RISC  0x1200      /* RISC Reset */
+#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */
+#define MQ_RISC_COLD_RESET_MASK         0x0001      /* RISC Cold reset                        */
+#define MQ_RISC_WARM_RESET_MASK         0x0002      /* RISC Warm reset                        */
+#define MQ_IRQ_REQ_ON                   0x1
+#define MQ_IRQ_REQ_OFF                  0x0
+#define MQ_BREG_IRQ_TEST                0x0608
+#define PLX9054_INTCSR      0x69 
+#define PLX9054_INT_ENA     0x09
+
+#define DIVAS_IOBASE	0x01
+#define M_PCI_RESET	0x10
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg);
+static int fourbri_ISR (card_t* card);
+
+int FPGA_Download(word, dword, byte *, byte *, int);
+extern byte FPGA_Bytes[];
+extern void *get_card(int);
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+word GetProtFeatureValue(char *sw_id);
+
+void memcp(byte *dst, byte *src, dword dwLen);
+int memcm(byte *dst, byte *src, dword dwLen);
+
+static int diva_server_4bri_reset(card_t *card)
+{
+	byte *ctl;
+
+	DPRINTF(("divas: reset Diva Server 4BRI"));
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	/* stop RISC, DSP's and ISAC  */
+   UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0);
+   UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	return 0;
+}
+
+static int diva_server_4bri_config(card_t *card, dia_config_t *config)
+{
+	byte *shared;
+	int i, j;
+
+	DPRINTF(("divas: configure Diva Server 4BRI"));
+
+	shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+	
+	for (i=0; i<256; i++)
+	{
+		UxCardMemOut(card->hw, &shared[i], 0);
+	}
+
+	UxCardMemOut(card->hw, &shared[ 8], config->tei);
+	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
+	UxCardMemOut(card->hw, &shared[11], config->watchdog);
+	UxCardMemOut(card->hw, &shared[12], config->permanent);
+	UxCardMemOut(card->hw, &shared[13], config->x_interface);
+	UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+	UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+	UxCardMemOut(card->hw, &shared[16], config->handset_type);
+	UxCardMemOut(card->hw, &shared[17], 0);
+	UxCardMemOut(card->hw, &shared[18], config->low_channel);
+	UxCardMemOut(card->hw, &shared[19], config->prot_version);
+	UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+	if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+	{
+		DPRINTF(("divas: Signifying V.90"));
+		UxCardMemOut(card->hw, &shared[22], 4);
+	}
+	else
+	{
+		UxCardMemOut(card->hw, &shared[22], 0);
+	}
+
+	for (i=0; i<2; i++)
+	{
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+		}
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	return 0;
+}
+
+static
+void diva_server_4bri_reset_int(card_t *card)
+{
+	byte *ctl;
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	return;
+}
+
+ 
+static int diva_server_4bri_test_int(card_t *card)
+{
+	byte *ctl, i;
+	byte *reg;
+
+	DPRINTF(("divas: test interrupt for Diva Server 4BRI"));
+
+	/* We get the last (dummy) adapter in so we need to go back to the first */
+
+	card = get_card(card->cfg.card_id - 3);
+
+	/* Enable interrupts on PLX chip */
+
+	reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+	UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA);
+
+	UxCardMemDetach(card->hw, reg);
+
+	/* Set the test interrupt flag */
+	card->test_int_pend = TEST_INT_DIVAS_Q;
+
+	/* Now to trigger the interrupt */
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	for (i = 0; i < 50; i++)
+	{
+		if (!card->test_int_pend)
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (card->test_int_pend)
+	{
+		DPRINTF(("active: timeout waiting for card to interrupt"));
+		return (-1);
+	}
+	
+	return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+	unsigned char hdr[80];
+	int i;
+
+	i = 0;
+
+	while ((i < (DIM(hdr) -1)) && 
+		(code[offset + i] != '\0') &&
+		(code[offset + i] != '\r') &&
+		(code[offset + i] != '\n'))
+	{
+		hdr[i] = code[offset + i];
+		i++;
+	}
+
+	hdr[i] = '\0';
+
+	DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_4bri_load(card_t *card, dia_load_t *load)
+{
+	byte *pRAM=NULL;
+	int download_offset=0;
+	card_t *FirstCard;
+	byte sw_id[80];
+
+	DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id));
+
+	switch(load->code_type)
+	{
+		case DIA_CPU_CODE:
+			DPRINTF(("divas: RISC code"));
+			print_hdr(load->code, 0x80);
+			card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+			download_offset = 0; // Protocol code written to offset 0
+			pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_DSP_CODE:
+			DPRINTF(("divas: DSP code"));
+			print_hdr(load->code, 0x0); 
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE;
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE;
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC);
+
+			break;
+
+		case DIA_TABLE_CODE:
+			DPRINTF(("divas: TABLE code"));
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword);
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword);
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_CONT_CODE:
+			DPRINTF(("divas: continuation code"));
+			break;
+
+        case DIA_DLOAD_CNT:
+			DPRINTF(("divas: COUNT code"));
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE;
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE;
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_FPGA_CODE:
+			DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length));
+			if (FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ 			card->hw->io_base,
+			 sw_id,
+			 load->code,
+			 load->length
+			) == -1)
+			{
+				DPRINTF(("divas: FPGA download failed"));
+				return -1;
+			}
+
+			/* NOW reset the 4BRI */
+			diva_server_4bri_reset(card);
+			return 0; // No need for anything further loading
+
+		default:
+			DPRINTF(("divas: unknown code type"));
+			return -1;
+	}
+
+   memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length);
+
+	{
+		int mism_off;
+	if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length)))
+	{
+		DPRINTF(("divas: memory mismatch at offset %d", mism_off));
+		UxCardMemDetach(card->hw, pRAM);
+		return -1;
+	}
+	}
+
+	UxCardMemDetach(card->hw, pRAM);
+
+	return 0;
+}
+
+static int diva_server_4bri_start(card_t *card, byte *channels)
+{
+	byte *ctl;
+	byte *shared, i;
+	int adapter_num;
+
+	DPRINTF(("divas: start Diva Server 4BRI"));
+	*channels = 0;
+	card->is_live = FALSE;
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK);
+
+	UxPause(2);
+
+	UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK);
+
+	UxPause(10);
+	
+	UxCardMemDetach(card->hw, ctl);
+
+	shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	for ( i = 0 ; i < 300 ; ++i )
+	{
+		UxPause (10) ;
+
+		if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 )
+		{
+			DPRINTF(("divas: Protocol startup time %d.%02d seconds",
+			         (i / 100), (i % 100) ));
+
+			break;
+		}
+	}
+
+	if (i==300)
+	{
+		DPRINTF(("divas: Timeout starting card"));
+		DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E])));
+
+		UxCardMemDetach(card->hw, shared);
+		return -1;
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	for (adapter_num=3; adapter_num >= 0; adapter_num--)
+	{
+		card_t *qbri_card;
+
+		qbri_card = get_card(card->cfg.card_id - adapter_num);
+
+		if (qbri_card)
+		{
+			qbri_card->is_live = TRUE;
+			shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY);
+			*channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]);
+			UxCardMemDetach(qbri_card->hw, shared);
+		}
+		else
+		{
+			DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id));
+		}
+	}
+
+	diva_server_4bri_test_int(card);
+
+	return 0;
+}
+
+static
+int 	diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+	byte	*a;
+	byte	*card_addr;
+	word	length = 0;
+	int		i;
+
+	a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	card_addr = a;
+	card_addr += mem_block->addr;
+
+	for (i=0; i < sizeof(mem_block->data); i++)
+	{
+		mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+		card_addr++;
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, a);
+
+	return length;
+}
+
+/*
+ * Initialise 4BRI specific entry points
+ */
+
+int Divas4BriInit(card_t *card, dia_card_t *cfg)
+{
+//	byte sw_id[80];
+//	extern int FPGA_Done;
+
+	DPRINTF(("divas: initialise Diva Server 4BRI"));
+
+	if (Divas4BRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	/* Need to download the FPGA */
+/*	if (!FPGA_Done)
+	{
+		int retVal;
+
+		retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ 			cfg->io_base,
+			 sw_id,
+			 FPGA_Bytes
+			);
+		if(retVal==-1)
+		{
+		
+			DPRINTF(("divas: FPGA Download Failed"));
+			return -1;
+
+		}
+		FPGA_Done = 1;
+	} */
+
+	card->card_reset = diva_server_4bri_reset;
+	card->card_load = diva_server_4bri_load;
+	card->card_config = diva_server_4bri_config;
+	card->card_start = diva_server_4bri_start;
+	card->reset_int = diva_server_4bri_reset_int;
+	card->card_mem_get = diva_server_4bri_mem_get;
+
+	card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+	card->out = DivasOut;
+	card->test_int = DivasTestInt;
+	card->dpc = DivasDpc;
+	card->clear_int = DivasClearInt;
+	card->card_isr = fourbri_ISR;
+
+	card->a.ram_out = mem_out;
+	card->a.ram_outw = mem_outw;
+	card->a.ram_out_buffer = mem_out_buffer;
+	card->a.ram_inc = mem_inc;
+
+	card->a.ram_in = mem_in;
+	card->a.ram_inw = mem_inw;
+	card->a.ram_in_buffer = mem_in_buffer;
+	card->a.ram_look_ahead = mem_look_ahead;
+
+	return 0;
+}
+
+void memcp(byte *dst, byte *src, dword dwLen)
+{
+	while (dwLen)
+	{
+		*dst = *src;
+		dst++; src++;
+		dwLen--;
+	}
+}
+
+int memcm(byte *dst, byte *src, dword dwLen)
+{
+	int offset = 0;
+
+	while (offset < dwLen)
+	{
+		if(*dst != *src)
+			return (offset+1);
+
+		offset++;
+		src++;
+		dst++;
+	}
+
+	return 0;
+}
+
+
+
+/*int fourbri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+	
+
+	if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) 
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); 
+		UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return (served != 0);
+}*/
+
+
+static int fourbri_ISR (card_t* card) 
+{
+	byte *ctl;
+
+	card->int_pend  += 1;
+	DivasDpcSchedule(); /* ISR DPC */
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+	UxCardMemDetach(card->hw, ctl);
+
+	return (1);
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/fpga.c linux/drivers/isdn/eicon/fpga.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/fpga.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/fpga.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,155 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "uxio.h"
+
+#define FPGA_PORT		0x6E
+#define FPGA_DLOAD_BUFLEN   	256
+#define NAME_OFFSET         	0x10
+#define NAME_MAXLEN         	12
+#define DATE_OFFSET         	0x2c
+#define DATE_MAXLEN         	10
+
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+void UxPause(long int);
+
+/*-------------------------------------------------------------------------*/
+/* Loads the FPGA configuration file onto the hardware.                    */
+/* Function returns 0 on success, else an error number.                    */
+/* On success, an identifier string is returned in the buffer              */
+/*                                                                         */
+/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream      */
+/* file and a file read function has to be provided by the operating       */
+/* system part.                                                            */
+/* ----------------------------------------------------------------------- */
+int FPGA_Download( word      cardtype,
+                        dword     RegBase,
+                        byte *strbuf,
+                        byte FPGA_SRC[],
+			int FPGA_LEN
+                      )
+{
+  word        i, j, k;
+  word        baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN;
+  dword       addr;
+  byte        *pFPGA;
+
+  //--- check for legal cardtype
+  switch (cardtype)
+  {
+    case IDI_ADAPTER_MAESTRAQ:
+      addr          = RegBase ; // address where to access FPGA
+      Mask_PROGRAM  = 0x0001;         // FPGA pins at address
+      Mask_DONE     = 0x0002;
+      Mask_CCLK     = 0x0100;
+      Mask_DIN      = 0x0400;
+      baseval       = 0x000d;         // PROGRAM hi, CCLK lo, DIN lo by default
+    break;
+      
+    default:
+	
+  	DPRINTF(("divas: FPGA Download ,Illegal Card"));
+      	return -1; // illegal card 
+  }
+
+  //--- generate id string from file content
+  for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name
+  {
+    if (!FPGA_SRC[j]) break;
+    strbuf[k] = FPGA_SRC[j];
+  } 
+  strbuf[k++] = ' ';
+  for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date
+  {
+    if (!FPGA_SRC[j]) break;
+    strbuf[k] = FPGA_SRC[j];
+  } 
+  strbuf[k] = 0;
+
+  DPRINTF(("divas: FPGA Download - %s", strbuf));
+
+  //--- prepare download, Pulse PROGRAM pin down.
+  UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM);  // PROGRAM low pulse
+  UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // release
+  UxPause(50);  // wait until FPGA finised internal memory clear
+  
+  //--- check done pin, must be low
+  if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) 
+  {
+    DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL"));
+    return -1;
+  }
+
+  pFPGA = FPGA_SRC;
+
+  i = 0; 
+  /* Move past the header */
+  while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) 
+  {
+    i++;
+  }
+
+  // We've hit the 0xFF so move on to the next byte
+  // i++;
+  DPRINTF(("divas: FPGA Code starts at offset %d", i));
+
+  //--- put data onto the FPGA
+  for (;i<FPGA_LEN; i++)
+  {
+    //--- put byte onto FPGA
+    for (j=0; j<8; j++)
+    {
+      if (FPGA_SRC[i] &(0x80>>j)) baseval |= Mask_DIN; // write a hi
+      else                      baseval &=~Mask_DIN; // write a lo
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK);     // set CCLK hi
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // set CCLK lo
+    }
+  }
+
+  //--- add some additional startup clock cycles and check done pin
+  for (i=0; i<5; i++) 
+  {
+    UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK);     // set CCLK hi
+    UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // set CCLK lo
+  }
+
+  UxPause(100);
+
+  if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) 
+  {
+    DPRINTF(("divas: FPGA download successful"));
+  }
+  else
+  {
+    DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT)));
+	return -1;
+  }
+
+return 0;
+}
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/idi.c linux/drivers/isdn/eicon/idi.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/idi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/idi.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,867 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.8  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Core driver for Diva Server cards
+ * Implements the IDI interface
+ */
+
+#include "idi.h"
+#include "adapter.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "sys.h"
+#include "uxio.h"
+
+/* IDI request functions */
+
+static void	request(card_t *card, ENTITY *e);
+
+static void req_0(ENTITY *e)	{ request(&DivasCards[ 0], e); }
+static void req_1(ENTITY *e)	{ request(&DivasCards[ 1], e); }
+static void req_2(ENTITY *e)	{ request(&DivasCards[ 2], e); }
+static void req_3(ENTITY *e)	{ request(&DivasCards[ 3], e); }
+static void req_4(ENTITY *e)	{ request(&DivasCards[ 4], e); }
+static void req_5(ENTITY *e)	{ request(&DivasCards[ 5], e); }
+static void req_6(ENTITY *e)	{ request(&DivasCards[ 6], e); }
+static void req_7(ENTITY *e)	{ request(&DivasCards[ 7], e); }
+static void req_8(ENTITY *e)	{ request(&DivasCards[ 8], e); }
+static void req_9(ENTITY *e)	{ request(&DivasCards[ 9], e); }
+static void req_10(ENTITY *e)	{ request(&DivasCards[10], e); }
+static void req_11(ENTITY *e)	{ request(&DivasCards[11], e); }
+static void req_12(ENTITY *e)	{ request(&DivasCards[12], e); }
+static void req_13(ENTITY *e)	{ request(&DivasCards[13], e); }
+static void req_14(ENTITY *e)	{ request(&DivasCards[14], e); }
+static void req_15(ENTITY *e)	{ request(&DivasCards[15], e); }
+
+IDI_CALL DivasIdiRequest[16] =
+{
+    &req_0,		&req_1,		&req_2,		&req_3,
+    &req_4,		&req_5,		&req_6,		&req_7,
+    &req_8,		&req_9,		&req_10,	&req_11,
+	&req_12,	&req_13,	&req_14,	&req_15
+};
+
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+
+static byte isdn_rc(ADAPTER *, byte, byte, byte, word);
+static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
+
+/*
+ * IDI related functions
+ */
+
+static
+ENTITY	*entity_ptr(ADAPTER *a, byte e_no)
+{
+	card_t	*card;
+
+	card = a->io;
+
+	return card->e_tbl[e_no].e;
+}
+
+static
+void	CALLBACK(ADAPTER *a, ENTITY *e)
+{
+	card_t	*card = a->io;
+
+	if (card->log_types & DIVAS_LOG_IDI)
+	{
+		DivasLogIdi(card, e, FALSE);
+	}
+
+	(*e->callback)(e);
+}
+
+static
+void	*PTR_P(ADAPTER *a, ENTITY *e, void *P)
+{
+	return(P);
+}
+
+static
+void	*PTR_R(ADAPTER *a, ENTITY *e)
+{
+	return((void*)e->R);
+}
+
+static
+void	*PTR_X(ADAPTER *a, ENTITY *e)
+{
+	return((void*)e->X);
+}
+
+static
+void	free_entity(ADAPTER *a, byte e_no) 
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].e = NULL;
+	card->e_count--;
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+void	assign_queue(ADAPTER * a, byte e_no, word ref)
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].assign_ref = ref;
+	card->e_tbl[e_no].next = card->assign;
+	card->assign = e_no;
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+byte	get_assign(ADAPTER *a, word ref)
+{
+	card_t	*card;
+	byte	e_no;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	e_no = (byte)card->assign;
+	while (e_no)
+	{
+		if (card->e_tbl[e_no].assign_ref == ref)
+		{
+			break;
+		}
+		e_no = card->e_tbl[e_no].next;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return e_no;
+}
+
+static
+void	req_queue(ADAPTER * a, byte e_no)
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].next = 0;
+
+	if (card->e_head)
+	{
+		card->e_tbl[card->e_tail].next = e_no;
+		card->e_tail = e_no;
+	}
+	else
+	{
+		card->e_head = e_no;
+		card->e_tail = e_no;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+byte	look_req(ADAPTER * a)
+{
+	card_t	*card;
+
+	card = a->io;
+
+	return(card->e_head);
+}
+
+static
+void	next_req(ADAPTER * a)
+{
+	card_t	*card;
+	int		ipl;
+
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_head = card->e_tbl[card->e_head].next;
+	if (!card->e_head)
+	{
+		card->e_tail = 0;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+
+/*
+ * IDI request function for active cards
+ */
+static
+void	request(card_t *card, ENTITY *e)
+{
+	word	*special_req;
+	int		i;
+	int		ipl;
+
+
+	if (card->log_types & DIVAS_LOG_IDI)
+	{
+		DivasLogIdi(card, e, TRUE);
+	}
+
+	if (!e->Req)
+	{
+		special_req = (word *) e;
+
+		switch (*special_req)
+		{
+		case REQ_REMOVE:
+			return;
+
+		case REQ_NAME:
+			for (i=0; i < DIM(card->cfg.name); i++)
+			{
+				((struct get_name_s *) e)->name[i] = card->cfg.name[i];
+			}
+			return;
+
+		case REQ_SERIAL:
+		case REQ_XLOG:
+			DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG"));
+			return;
+
+		default:
+			return;
+		}
+	}
+
+	ipl = UxCardLock(card->hw);
+
+   	if (!(e->Id & 0x1f))
+	{
+		DPRINTF(("IDI: ASSIGN req"));
+
+		for (i = 1; i < card->e_max; i++)
+		{
+			if (!card->e_tbl[i].e)
+			{
+				break;
+			}
+		}
+
+		if (i == card->e_max)
+		{
+			DPRINTF(("IDI: request all ids in use (IDI req ignored)"));
+			UxCardUnlock(card->hw, ipl);
+			e->Rc = OUT_OF_RESOURCES;
+			return;
+		}
+
+		card->e_tbl[i].e = e;
+		card->e_count++;
+
+		e->No = (byte) i;
+		e->More = 0;
+		e->RCurrent = 0xff;
+	}
+	else
+	{
+		i = e->No;
+	}
+    
+    if (e->More & XBUSY)
+	{
+		DPRINTF(("IDI: request - entity is busy"));
+		UxCardUnlock(card->hw, ipl);
+		return;
+	}
+
+	e->More |= XBUSY;
+	e->More &= ~ XMOREF;
+	e->XCurrent = 0;
+	e->XOffset = 0;
+
+	card->e_tbl[i].next = 0;
+
+	if(card->e_head)
+	{
+		card->e_tbl[card->e_tail].next = i;
+		card->e_tail = i;
+	}
+	else
+	{
+		card->e_head = i;
+		card->e_tail = i;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	DivasScheduleRequestDpc();
+
+	return;
+}
+
+static byte pr_ready(ADAPTER * a)
+{
+  byte ReadyCount;
+
+  ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
+                      a->ram_in(a, &PR_RAM->ReqInput));
+
+  if(!ReadyCount) {
+    if(!a->ReadyInt) {
+      a->ram_inc(a, &PR_RAM->ReadyInt);
+      a->ReadyInt++;
+    }
+  }
+  return ReadyCount;
+}
+
+/*------------------------------------------------------------------*/
+/* output function                                                  */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a)
+{
+  byte e_no;
+  ENTITY  * this = NULL;
+  BUFFERS  *X;
+  word length;
+  word i;
+  word clength;
+  REQ * ReqOut;
+  byte more;
+  byte ReadyCount;
+  byte ReqCount;
+  byte Id;
+
+        /* while a request is pending ...                           */
+  e_no = look_req(a);
+  if(!e_no)
+  {
+    return;
+  }
+
+  ReadyCount = pr_ready(a);
+  if(!ReadyCount)
+  {
+    DPRINTF(("IDI: card not ready for next request"));
+    return;
+  }
+
+  ReqCount = 0;
+  while(e_no && ReadyCount) {
+
+    next_req(a);
+
+    this = entity_ptr(a, e_no);
+
+#ifdef	USE_EXTENDED_DEBUGS
+	if ( !this )
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
+		e_no = look_req(a) ;
+		ReadyCount-- ;
+		continue ;
+	}
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
+	}
+#else
+    DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+#endif
+
+        /* get address of next available request buffer             */
+    ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
+
+        /* now copy the data from the current data buffer into the  */
+        /* adapters request buffer                                  */
+    length = 0;
+    i = this->XCurrent;
+    X = PTR_X(a,this);
+    while(i<this->XNum && length<270) {
+      clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+      a->ram_out_buffer(a,
+                        &ReqOut->XBuffer.P[length],
+                        PTR_P(a,this,&X[i].P[this->XOffset]),
+                        clength);
+
+      length +=clength;
+      this->XOffset +=clength;
+      if(this->XOffset==X[i].PLength) {
+        this->XCurrent = (byte)++i;
+        this->XOffset = 0;
+      }
+    }
+
+    a->ram_outw(a, &ReqOut->XBuffer.length, length);
+    a->ram_out(a, &ReqOut->ReqId, this->Id);
+    a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
+
+        /* if its a specific request (no ASSIGN) ...                */
+
+    if(this->Id &0x1f) {
+
+        /* if buffers are left in the list of data buffers do       */
+        /* do chaining (LL_MDATA, N_MDATA)                          */
+
+      this->More++;
+      if(i<this->XNum && this->MInd) {
+        a->ram_out(a, &ReqOut->Req, this->MInd);
+        more = TRUE;
+      }
+      else {
+        this->More |=XMOREF;
+        a->ram_out(a, &ReqOut->Req, this->Req);
+        more = FALSE;
+      }
+
+        /* if we did chaining, this entity is put back into the     */
+        /* request queue                                            */
+
+      if(more) {
+        req_queue(a,this->No);
+      }
+    }
+
+        /* else it's a ASSIGN                                       */
+
+    else {
+
+        /* save the request code used for buffer chaining           */
+
+      this->MInd = 0;
+      if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+      if (this->Id==NL_ID   ||
+          this->Id==TASK_ID ||
+          this->Id==MAN_ID
+        ) this->MInd = N_MDATA;
+
+        /* send the ASSIGN                                          */
+
+      this->More |=XMOREF;
+      a->ram_out(a, &ReqOut->Req, this->Req);
+
+        /* save the reference of the ASSIGN                         */
+
+      assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
+    }
+    a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
+    ReadyCount--;
+    ReqCount++;
+
+    e_no = look_req(a);
+  }
+
+        /* send the filled request buffers to the ISDN adapter      */
+
+  a->ram_out(a, &PR_RAM->ReqInput,
+             (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
+
+        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
+        /* Id from our table after sending the request             */
+  if(this->Req==UREMOVE && this->Id) {
+    Id = this->Id;
+    e_no = a->IdTable[Id];
+    free_entity(a, e_no);
+    a->IdTable[Id] = 0;
+    this->Id = 0;
+  }
+
+}
+
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler                                           */
+/*------------------------------------------------------------------*/
+
+byte DivasDpc(ADAPTER * a)
+{
+  byte Count;
+  RC * RcIn;
+  IND * IndIn;
+  byte c;
+  byte RNRId;
+  byte Rc;
+  byte Ind;
+
+        /* if return codes are available ...                        */
+  if((Count = a->ram_in(a, &PR_RAM->RcOutput))) {
+
+    DPRINTF(("IDI: #Rc=%x",Count));
+
+        /* get the buffer address of the first return code          */
+    RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
+
+        /* for all return codes do ...                              */
+    while(Count--) {
+
+      if((Rc=a->ram_in(a, &RcIn->Rc))) {
+
+        /* call return code handler, if it is not our return code   */
+        /* the handler returns 2                                    */
+        /* for all return codes we process, we clear the Rc field   */
+        isdn_rc(a,
+                Rc,
+                a->ram_in(a, &RcIn->RcId),
+                a->ram_in(a, &RcIn->RcCh),
+                a->ram_inw(a, &RcIn->Reference));
+
+        a->ram_out(a, &RcIn->Rc, 0);
+      }
+
+        /* get buffer address of next return code                   */
+      RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
+    }
+
+        /* clear all return codes (no chaining!)                    */
+    a->ram_out(a, &PR_RAM->RcOutput ,0);
+
+        /* call output function                                     */
+    DivasOut(a);
+  }
+
+        /* clear RNR flag                                           */
+  RNRId = 0;
+
+        /* if indications are available ...                         */
+  if((Count = a->ram_in(a, &PR_RAM->IndOutput))) {
+
+    DPRINTF(("IDI: #Ind=%x",Count));
+
+        /* get the buffer address of the first indication           */
+    IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
+
+        /* for all indications do ...                               */
+    while(Count--) {
+
+        /* if the application marks an indication as RNR, all       */
+        /* indications from the same Id delivered in this interrupt */
+        /* are marked RNR                                           */
+      if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
+        a->ram_out(a, &IndIn->Ind, 0);
+        a->ram_out(a, &IndIn->RNR, TRUE);
+      }
+      else {
+        Ind = a->ram_in(a, &IndIn->Ind);
+        if(Ind) {
+          RNRId = 0;
+
+        /* call indication handler, a return value of 2 means chain */
+        /* a return value of 1 means RNR                            */
+        /* for all indications we process, we clear the Ind field   */
+          c = isdn_ind(a,
+                       Ind,
+                       a->ram_in(a, &IndIn->IndId),
+                       a->ram_in(a, &IndIn->IndCh),
+                       &IndIn->RBuffer,
+                       a->ram_in(a, &IndIn->MInd),
+                       a->ram_inw(a, &IndIn->MLength));
+
+          if(c==1) {
+            DPRINTF(("IDI: RNR"));
+            a->ram_out(a, &IndIn->Ind, 0);
+            RNRId = a->ram_in(a, &IndIn->IndId);
+            a->ram_out(a, &IndIn->RNR, TRUE);
+          }
+        }
+      }
+
+        /* get buffer address of next indication                    */
+      IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
+    }
+
+    a->ram_out(a, &PR_RAM->IndOutput, 0);
+  }
+  return FALSE;
+}
+
+byte DivasTestInt(ADAPTER * a)
+{
+  return a->ram_in(a,(void *)0x3fe);
+}
+
+void DivasClearInt(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3fe,0); 
+}
+
+/*------------------------------------------------------------------*/
+/* return code handler                                              */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_rc(ADAPTER * a,
+             byte Rc,
+             byte Id,
+             byte Ch,
+             word Ref)
+{
+  ENTITY  * this;
+  byte e_no;
+
+#ifdef	USE_EXTENDED_DEBUGS
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
+	}
+#else
+  DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+
+        /* check for ready interrupt                                */
+  if(Rc==READY_INT) {
+    if(a->ReadyInt) {
+      a->ReadyInt--;
+      return 0;
+    }
+    return 2;
+  }
+
+        /* if we know this Id ...                                   */
+  e_no = a->IdTable[Id];
+  if(e_no) {
+
+    this = entity_ptr(a,e_no);
+
+    this->RcCh = Ch;
+
+        /* if it is a return code to a REMOVE request, remove the   */
+        /* Id from our table                                        */
+    if(this->Req==REMOVE && Rc==OK) {
+      free_entity(a, e_no);
+      a->IdTable[Id] = 0;
+      this->Id = 0;
+/**************************************************************/
+      if ((this->More & XMOREC) > 1) {
+        this->More &= ~XMOREC;
+	this->More |= 1;
+	DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
+      }
+    }
+
+    if (Rc==OK_FC) {
+      this->Rc = Rc;
+      this->More = (this->More & (~XBUSY | XMOREC)) | 1;
+      this->complete = 0xFF;
+      CALLBACK(a, this);
+      return 0;
+    }
+    if(this->More &XMOREC)
+      this->More--;
+
+        /* call the application callback function                   */
+    if(this->More &XMOREF && !(this->More &XMOREC)) {
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+
+        /* if it's an ASSIGN return code check if it's a return     */
+        /* code to an ASSIGN request from us                        */
+  if((Rc &0xf0)==ASSIGN_RC) {
+
+    e_no = get_assign(a, Ref);
+
+    if(e_no) {
+
+      this = entity_ptr(a,e_no);
+
+      this->Id = Id;
+
+        /* call the application callback function                   */
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      CALLBACK(a, this);
+
+      if(Rc==ASSIGN_OK) {
+        a->IdTable[Id] = e_no;
+      }
+      else
+      {
+        free_entity(a, e_no);
+        a->IdTable[Id] = 0;
+        this->Id = 0;
+      }
+      return 1;
+    }
+  }
+  return 2;
+}
+
+/*------------------------------------------------------------------*/
+/* indication handler                                               */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_ind(ADAPTER * a,
+              byte Ind,
+              byte Id,
+              byte Ch,
+              PBUFFER * RBuffer,
+              byte MInd,
+              word MLength)
+{
+  ENTITY  * this;
+  word clength;
+  word offset;
+  BUFFERS  *R;
+
+#ifdef	USE_EXTENDED_DEBUGS
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
+	}
+#else
+  DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+
+  if(a->IdTable[Id]) {
+
+    this = entity_ptr(a,a->IdTable[Id]);
+
+    this->IndCh = Ch;
+
+        /* if the Receive More flag is not yet set, this is the     */
+        /* first buffer of the packet                               */
+    if(this->RCurrent==0xff) {
+
+        /* check for receive buffer chaining                        */
+      if(Ind==this->MInd) {
+        this->complete = 0;
+        this->Ind = MInd;
+      }
+      else {
+        this->complete = 1;
+        this->Ind = Ind;
+      }
+
+        /* call the application callback function for the receive   */
+        /* look ahead                                               */
+      this->RLength = MLength;
+
+      a->ram_look_ahead(a, RBuffer, this);
+
+      this->RNum = 0;
+      CALLBACK(a, this);
+
+        /* map entity ptr, selector could be re-mapped by call to   */
+        /* IDI from within callback                                 */
+      this = entity_ptr(a,a->IdTable[Id]);
+
+        /* check for RNR                                            */
+      if(this->RNR==1) {
+        this->RNR = 0;
+        return 1;
+      }
+
+        /* if no buffers are provided by the application, the       */
+        /* application want to copy the data itself including       */
+        /* N_MDATA/LL_MDATA chaining                                */
+      if(!this->RNR && !this->RNum) {
+        return 0;
+      }
+
+        /* if there is no RNR, set the More flag                    */
+      this->RCurrent = 0;
+      this->ROffset = 0;
+    }
+
+    if(this->RNR==2) {
+      if(Ind!=this->MInd) {
+        this->RCurrent = 0xff;
+        this->RNR = 0;
+      }
+      return 0;
+    }
+        /* if we have received buffers from the application, copy   */
+        /* the data into these buffers                              */
+    offset = 0;
+    R = PTR_R(a,this);
+    do {
+      if(this->ROffset==R[this->RCurrent].PLength) {
+        this->ROffset = 0;
+        this->RCurrent++;
+      }
+      clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+                    R[this->RCurrent].PLength-this->ROffset);
+      if(R[this->RCurrent].P) {
+        a->ram_in_buffer(a,
+                         &RBuffer->P[offset],
+                         PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                         clength);
+      }
+      offset +=clength;
+      this->ROffset +=clength;
+    } while(offset<(a->ram_inw(a, &RBuffer->length)));
+
+        /* if it's the last buffer of the packet, call the          */
+        /* application callback function for the receive complete   */
+        /* call                                                     */
+    if(Ind!=this->MInd) {
+      R[this->RCurrent].PLength = this->ROffset;
+      if(this->ROffset) this->RCurrent++;
+      this->RNum = this->RCurrent;
+      this->RCurrent = 0xff;
+      this->Ind = Ind;
+      this->complete = 2;
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+  return 2;
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/idi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/idi.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,143 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* External IDI interface */
+
+#if !defined(IDI_H)
+#define IDI_H
+
+#include "sys.h"
+
+/* typedefs for our data structures */
+
+typedef struct get_name_s GET_NAME;
+typedef struct entity_s ENTITY;
+typedef struct buffers_s BUFFERS;
+
+/* IDI request/callback function pointer */
+
+typedef void (* IDI_CALL)(ENTITY *);
+
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} DBUFFER;
+
+#define REQ_NAME	0x0100
+#define BOARD_NAME_LENGTH 9
+struct get_name_s {
+  word command;         /* command = 0x0100 */
+  byte name[BOARD_NAME_LENGTH];
+};
+
+#define REQ_REMOVE    0x0000    /* pointer to word which is 0 */
+#define REQ_SERIAL    0x0200  
+struct get_serial_s {
+  word      command;            /* command = 0x0200 */
+  dword     serial;             /* serial number */
+};
+
+#define REQ_POSTCALL  0x0300  
+struct postcall_s {
+  word        command;         /* command = 0x0300 */
+  word        dummy;           /* not used */
+  IDI_CALL    callback;        /* routine adress to call back */
+  ENTITY      *contxt;         /* ptr to entity to use */
+};
+
+#define REQ_XLOG      0x0400   /* structure is card dependent/defined locally */
+
+struct buffers_s {
+  word PLength;
+  byte *P;
+};
+
+struct entity_s {
+  byte                  Req;            /* pending request          */
+  byte                  Rc;             /* return code received     */
+  byte                  Ind;            /* indication received      */
+  byte                  ReqCh;          /* channel of current Req   */
+  byte                  RcCh;           /* channel of current Rc    */
+  byte                  IndCh;          /* channel of current Ind   */
+  byte                  Id;             /* ID used by this entity   */
+  byte                  GlobalId;       /* reserved field           */
+  byte                  XNum;           /* number of X-buffers      */
+  byte                  RNum;           /* number of R-buffers      */
+  BUFFERS               *X;        		/* pointer to X-buffer list */
+  BUFFERS               *R;        		/* pointer to R-buffer list */
+  word                  RLength;        /* length of current R-data */
+  DBUFFER               *RBuffer;       /* buffer of current R-data */
+  byte                  RNR;            /* receive not ready flag   */
+  byte                  complete;       /* receive complete status  */
+  IDI_CALL              callback;
+
+  word                  user[2];
+
+        /* fields used by the driver internally                     */
+  byte                  No;             /* entity number            */
+  byte                  reserved2;      /* reserved field           */
+  byte                  More;           /* R/X More flags           */
+  byte                  MInd;           /* MDATA coding for this ID */
+  byte                  XCurrent;       /* current transmit buffer  */
+  byte                  RCurrent;       /* current receive buffer   */
+  word                  XOffset;        /* offset in x-buffer       */
+  word                  ROffset;        /* offset in r-buffer       */
+};
+
+typedef struct {
+  byte                  type;
+  byte                  channels;
+  word                  features;
+  /* dword		serial; */
+  IDI_CALL              request;
+} DESCRIPTOR;
+
+extern void    DIVA_DIDD_Read(DESCRIPTOR *, int);
+
+        /* descriptor type field coding */
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#define IDI_ADAPTER_MAESTRAQ    5
+#define IDI_ADAPTER_MAESTRAP    6
+#define IDI_VADAPTER            0x40
+#define IDI_DRIVER              0x80
+#define IDI_DIMAINT             0xff
+
+/* feature bit mask values */
+
+#define DI_VOICE        0x0 /* obsolete define */
+#define DI_FAX3         0x1
+#define DI_MODEM        0x2
+#define DI_POST         0x4
+#define DI_V110         0x8
+#define DI_V120         0x10
+#define DI_POTS         0x20
+#define DI_CODEC        0x40
+#define DI_MANAGE       0x80
+#define DI_V_42         0x0100
+#define DI_EXTD_FAX     0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+
+#endif /* IDI_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/kprintf.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/kprintf.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,535 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.3  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Source file for kernel interface to kernel log facility
+ */
+
+
+#include "sys.h"
+#include <stdarg.h>
+#undef MAX
+#undef MIN
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include "divas.h"
+#include "divalog.h"
+#include "uxio.h"
+
+/*
+ * Implementation of printf and sprintf for kernel
+ */
+
+#define MAX_BUFF    (80)        /* limit size of temporary buffers */
+
+#define WRITE_CHAR(BUFFER, SIZE, C) \
+  if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C)
+
+
+/*
+ * convert a number to decimal ASCII
+ */
+
+static
+void    do_decimal( char            *temp,
+                    int             temp_len,
+                    unsigned int    value,
+                    char            *s)
+
+{
+    int     i;
+
+    temp[0] = '\0';
+
+    for (i = 1; i < temp_len; i++)
+    {
+        temp[i] = (char) ((value % 10) + (int) '0');
+        value /= 10;
+    }
+
+    for (i = (temp_len - 1); temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a number to octal ASCII
+ */
+
+static
+void    do_octal(   char            *temp,
+                    unsigned int    value,
+                    char            *s)
+
+{
+    int     i;
+
+    temp[0] = '\0';
+
+    for (i = 1; i <= 11; i++)
+    {
+        temp[i] = (char) ((value & 07) + (int) '0');
+        value >>= 3;
+    }
+    temp[11] &= '3';
+
+    for (i = 11; temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a number to hex ASCII
+ */
+
+static
+void    do_hex( char            *temp,
+                unsigned int    value,
+                char            *s)
+
+{
+    int     i;
+    static
+    char    *dec_to_hex = "0123456789abcdef";
+
+    temp[0] = '\0';
+
+    for (i = 1; i <= 8; i++)
+    {
+        temp[i] = dec_to_hex[value & 0x0f];
+        value >>= 4;
+    }
+
+    for (i = 8; temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a buffer to ASCII HEX
+ */
+
+static
+void    do_buffer(  char    *buffer,
+                    int     length,
+                    char    *s)
+
+{
+    static
+    char    hex_char [] = "0123456789abcdef";
+    char    *b = buffer;
+    int     hex_byte;
+    int     nybble;
+
+    length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length;
+
+    while (length)
+    {
+        hex_byte = (int) *b++;
+        nybble = (hex_byte >> 4) & 0xf;
+        *s++ = hex_char[nybble];
+        nybble = hex_byte & 0xf;
+        *s++ = hex_char[nybble];
+        *s++ = ' ';
+        length--;
+    }
+    *s = '\0';
+
+    return;
+}
+
+/*
+ * Body of sprintf function: behaves just like standard sprintf, except we
+ * have an extra argument (buffer size) which we use to ensure we don't
+ * overflow
+ */
+
+void    Divas_vsprintf(   char    *buffer,
+                    int     size,
+                    char    *fmt,
+                    va_list argptr)
+
+{
+    char        c;          /* single character buffer */
+    int         i;          /* handy scratch counter */
+    int         f;          /* format character (after %) */
+    char        *str;       /* pointer into string */
+    char        temp[20];   /* temp buffer used in printing numbers */
+    char        string[MAX_BUFF]; /* output from number conversion */
+    int         length;     /* length of string "str" */
+    char        fill;       /* fill character ' ' or '0' */
+    boolean_t   leftjust;   /* TRUE if left justified, else right justified */
+    int         fmax, fmin; /* field specifiers % MIN . MAX s */
+    int         leading;    /* number of leading/trailing fill characters */
+    char        sign;       /* set to '-' for negative decimals */
+    int         number;     /* numeric argument */
+
+    char        *buff_ptr;  /* pointer to user's buffer of hex data */
+    int         buff_len;   /* length of hex data */
+
+    /* make sure we have somthing to write into */
+
+    if ((!buffer) || (size <= 0))
+    {
+        return;
+    }
+
+    while (TRUE)
+    {
+        /* echo characters until end or '%' encountered */
+
+        while ((c = *fmt++) != '%')
+        {
+            if (!c)
+            {
+                *buffer = '\0';
+                return;
+            }
+            WRITE_CHAR(buffer, size, c);
+        }
+
+        /* echo %% as % */
+
+        if (*fmt == '%')
+        {
+            WRITE_CHAR(buffer, size, *fmt);
+            continue;
+        }
+
+        /* %- turns on left-justify */
+
+        if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE)))
+        {
+            fmt++;
+        }
+
+        /* %0 turns on zero filling */
+
+        if (*fmt == '0')
+        {
+            fill = '0';
+        }
+        else
+        {
+            fill = ' ';
+        }
+
+        /* minium field width specifier for %d, u, x, c, s */
+
+        fmin = 0;
+
+        if (*fmt == '*')
+        {
+            fmin = va_arg(argptr, int);
+            fmt++;
+        }
+        else
+        {
+            while ('0' <= *fmt && *fmt <= '9')
+            {
+                fmin = (fmin * 10) + (*fmt++ - '0');
+            }
+        }
+
+        /* maximum string width specifier for %s */
+
+        fmax = 0;
+
+        if (*fmt == '.')
+        {
+            if (*(++fmt) == '*')
+            {
+                fmax = va_arg(argptr, int);
+                fmt++;
+            }
+            else
+            {
+                while ('0' <= *fmt && *fmt <= '9')
+                {
+                    fmax = (fmax * 10) + (*fmt++ - '0');
+                }
+            }
+        }
+
+        /* skip over 'l' option (ints are assumed same size as longs) */
+
+        if (*fmt == 'l')
+        {
+            fmt++;
+        }
+
+        /* get the format chacater */
+
+        if (!(f = *fmt++))
+        {
+            WRITE_CHAR(buffer, size, '%');
+            *buffer = '\0';
+            return;
+        }
+
+        sign = '\0';        /* sign == '-' for negative decimal */
+
+        str = string;
+
+        switch (f)
+        {
+        case 'c' :
+            string[0] = (char) va_arg(argptr, int);
+            string[1] = '\0';
+            fmax = 0;
+            fill = ' ';
+            break;
+
+        case 's' :
+            str = va_arg(argptr, char *);
+            fill = ' ';
+            break;
+
+        case 'D' :
+        case 'd' :
+            number = va_arg(argptr, int);
+            if (number < 0)
+            {
+                sign = '-';
+                number = -number;
+            }
+            do_decimal(temp, DIM(temp), (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'U' :
+        case 'u' :
+            number = va_arg(argptr, int);
+            do_decimal(temp, DIM(temp), (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'O' :
+        case 'o' :
+            number = va_arg(argptr, int);
+            do_octal(temp, (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'X' :
+        case 'x' :
+            number = va_arg(argptr, int);
+            do_hex(temp, (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'H' :
+        case 'h' :
+            buff_ptr = va_arg(argptr, char *);
+            buff_len = va_arg(argptr, int);
+            do_buffer(buff_ptr, buff_len, str);
+            fmax = 0;
+            break;
+
+        default :
+            WRITE_CHAR(buffer, size, ((char) f));
+            break;
+        }
+
+        /* get the length of the string */
+
+        length = 0;
+        while (str[length])
+        {
+            length++;
+        }
+
+        /* make sure we have fmax and fmin values that are O.K. */
+
+        if (fmin > DIM(string) || fmin < 0)
+        {
+            fmin = 0;
+        }
+
+        if (fmax > DIM(string) || fmax < 0)
+        {
+            fmax = 0;
+        }
+
+        /* figure out how many leading characters thare are */
+
+        leading = 0;
+
+        if (fmax || fmin)
+        {
+            if (fmax)
+            {
+                if (length > fmax)
+                {
+                    length = fmax;
+                }
+            }
+
+            if (fmin)
+            {
+                leading = fmin - length;
+            }
+
+            if (sign == '-')
+            {
+                leading--;
+            }
+        }
+
+        /* output sign now, if fill is numeric */
+
+        if (sign == '-' && fill == '0')
+        {
+            WRITE_CHAR(buffer, size, '-');
+        }
+
+        /* if right justified, output fill characters */
+
+        if (!leftjust)
+        {
+            for (i = 0; i < leading; i++)
+            {
+                WRITE_CHAR(buffer, size, fill);
+            }
+        }
+
+        /* output sign now, if fill is spaces */
+
+        if (sign == '-' && fill == ' ')
+        {
+            WRITE_CHAR(buffer, size, '-');
+        }
+
+        /* now the actual value */
+
+        for (i = 0; i < length; i++)
+        {
+            WRITE_CHAR(buffer, size, str[i]);
+        }
+
+        /* if left justified, fill out with the fill character */
+
+        if (leftjust)
+        {
+            for (i = 0; i < leading; i++)
+            {
+                WRITE_CHAR(buffer, size, fill);
+            }
+        }
+    }
+}
+
+/*
+ * sprintf for kernel
+ *
+ * call our vsprintf assuming user has a big buffer....
+ */
+
+void    DivasSprintf(char *buffer, char *fmt, ...)
+
+{
+    va_list     argptr;         /* pointer to additional args */
+
+    va_start(argptr, fmt);
+
+    Divas_vsprintf(buffer, 1024, fmt, argptr);
+
+    va_end(argptr);
+
+    return;
+}
+
+void    DivasPrintf(char  *fmt, ...)
+
+{
+    klog_t      log;            /* log entry buffer */
+
+    va_list     argptr;         /* pointer to additional args */
+
+    va_start(argptr, fmt);
+
+    /* clear log entry */
+
+    bzero((caddr_t) &log, sizeof(klog_t));
+
+    log.card = -1;
+    log.type = KLOG_TEXT_MSG;
+
+    /* time stamp the entry */
+
+    log.time_stamp = UxTimeGet();
+
+    /* call vsprintf to format the user's information */
+
+    Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr);
+
+    va_end(argptr);
+
+    /* send to the log streams driver and return */
+
+    DivasLogAdd(&log, sizeof(klog_t));
+
+    return;
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/lincfg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/lincfg.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,407 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.9  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/fs.h>
+#undef N_DATA   /* Because we have our own definition */
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+
+#define HW_ID_EICON_PCI			0x1133
+#define HW_ID_DIVA_SERVER_P		0xE014
+#define HW_ID_DIVA_SERVER_B_ST	0xE010
+#define HW_ID_DIVA_SERVER_B_U	0xE013
+#define HW_ID_DIVA_SERVER_Q   	0xE012
+
+struct file_operations Divas_fops;
+int Divas_major;
+
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
+			 unsigned int command, unsigned long arg);
+extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable);
+extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset);
+extern int do_open(struct inode *, struct file *);
+extern int do_release(struct inode *, struct file *);
+
+int FPGA_Done=0;
+
+int DivasCardsDiscover(void)
+{
+	word wNumCards = 0, wDeviceIndex = 0;
+	byte byBus, byFunc;
+	word wPCIConsultation, PCItmp;
+	dword j, i;
+	unsigned int PCIserial;
+	dia_card_t Card;
+	byte *b;
+	
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_Q, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+
+			dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; 			
+			byte byIRQ;
+			
+			printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n");
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM);
+			dwRAM &= 0xFFC00000;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFF00;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG);
+			dwCFG &= 0xFFFFFF00;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL);
+			dwCTL &= 0xFFFFE000;
+			
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+			/* Retrieve the serial number */
+
+			pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC);
+
+			for (j=0, PCItmp=0; j<10000 && !PCItmp; j++)
+			{
+				pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp);
+				PCItmp &= 0x8000;  // extract done flag
+			}
+
+			pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial);
+
+		
+			Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000);
+			Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000);
+			Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100);
+			Card.io_base=dwDivasIOBase;
+
+			Card.irq = byIRQ;
+			
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+	
+			FPGA_Done = 0;
+
+			/* Create four virtual card structures as we want to treat 
+			   the 4Bri card as 4 Bri cards*/
+			for(i=0;i<4;i++)
+			{
+
+				b=Card.memory[DIVAS_RAM_MEMORY];
+				b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); 
+				DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET));
+				Card.memory[DIVAS_RAM_MEMORY]=b;
+ 
+				b = Card.memory[DIVAS_RAM_MEMORY];
+				b += MQ_SM_OFFSET;
+				Card.memory[DIVAS_SHARED_MEMORY] = b;
+
+				Card.bus_num = byBus;
+				Card.func_num = byFunc;
+				Card.slot = -1;
+
+			
+				/* Fill in Name */
+				Card.name[0] = 'D';
+				Card.name[1] = 'I';
+				Card.name[2] = 'V';
+				Card.name[3] = 'A';
+				Card.name[4] = 'S';
+				Card.name[5] = 'Q';
+				Card.name[6] = '0' + i;
+				Card.name[7] = '\0';
+
+				Card.serial = PCIserial;
+
+			 	Card.card_id = wNumCards;
+
+ 				if (DivasCardNew(&Card) != 0)
+				{
+					// Force for loop to terminate
+					i = 4;
+					continue;
+				}
+				wNumCards++;
+
+			}//for
+		}
+		wDeviceIndex++;
+	}
+
+	wDeviceIndex = 0;
+
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_B_ST, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwPLXIOBase, dwDivasIOBase;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n");
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFFFC;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'B';
+			Card.name[6] = '\0';
+
+			if (check_region(Card.io_base, 0x20))
+			{
+				printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (check_region(Card.reset_base, 0x80))
+			{
+				printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_B_U, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwPLXIOBase, dwDivasIOBase;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n");
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFFFC;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'B';
+			Card.name[6] = '\0';
+
+			if (check_region(Card.io_base, 0x20))
+			{
+				printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);	
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (check_region(Card.reset_base, 0x80))
+			{
+				printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wDeviceIndex++;
+	}
+
+	wDeviceIndex = 0;
+
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_P, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwRAM, dwREG, dwCFG;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n");
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM);
+			dwRAM &= 0xFFFFF000;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG);
+			dwREG &= 0xFFFFF000;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG);
+			dwCFG &= 0xFFFFF000;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000);
+			Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000);
+			Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000);
+			Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET;
+
+/*			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFFFc;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+*/
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+/*			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;*/
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'P';
+			Card.name[6] = '\0';
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wDeviceIndex++;
+	}
+
+
+	printk(KERN_INFO "Divas: %d cards detected\n", wNumCards);
+
+	if(wNumCards == 0)
+	{
+		return -1;
+	}
+
+	Divas_fops.ioctl = do_ioctl;
+	Divas_fops.poll = do_poll;
+	Divas_fops.read = do_read;
+	Divas_fops.open = do_open;
+	Divas_fops.release = do_release;
+
+	Divas_major = register_chrdev(0, "Divas", &Divas_fops);
+
+	if (Divas_major < 0)
+	{
+		printk(KERN_WARNING "Divas: Unable to register character driver\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Error return -1 */
+int DivasConfigGet(dia_card_t *card)
+{
+	/* Retrieve Config from O/S? Not in Linux */
+	return 0;
+}
+
+dia_config_t *DivasConfig(card_t *card, dia_config_t *config)
+{
+	/*	If config retrieved from OS then copy the data into a dia_config_t structure here
+		and return the pointer here. If the config 'came from above' then just 
+
+			return config;
+	*/
+
+	return config;
+}
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/linchr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/linchr.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,269 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.12  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#undef N_DATA
+
+#include "adapter.h"
+#include "divas.h"
+#include "divalog.h"
+
+extern int DivasCardNext;
+void UxPause(long ms);
+void bcopy(void *pSource, void *pDest, dword dwLength);
+int DivasGetMem(mem_block_t *);
+
+#define DIA_IOCTL_UNLOCK 12
+void UnlockDivas(void);
+
+int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
+			 unsigned int command, unsigned long arg)
+{
+	dia_load_t *pDivaLoad;
+	dia_start_t *pDivaStart;
+	dia_config_t *pDivaConfig;
+	dia_log_t *pDivaLog;
+	byte *pUserCards, card_i;
+	word wCardNum;
+	mem_block_t *mem_block;
+
+	switch (command)
+	{
+		case DIA_IOCTL_CONFIG:
+			pDivaConfig = (dia_config_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
+			{
+				DivasCardConfig(pDivaConfig);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
+				return -1;
+			}
+				return 0;
+
+		case DIA_IOCTL_DETECT:
+			pUserCards = (byte *) arg;
+
+			if (!verify_area(VERIFY_WRITE, pUserCards, 20))
+			{
+				put_user(DivasCardNext, pUserCards++);
+
+				for (card_i=1; card_i < 20; card_i++)
+				{
+					put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+				}
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_START:
+			pDivaStart = (dia_start_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
+			{
+				return DivasCardStart(pDivaStart->card_id);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
+				return -1;
+			}
+
+
+		case DIA_IOCTL_FLAVOUR:
+			return 0;
+
+		case DIA_IOCTL_LOAD:
+			pDivaLoad = (dia_load_t *) arg;
+			if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+			{
+				if (DivasCardLoad(pDivaLoad))
+				{
+					printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
+					return -EINVAL;
+				}
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
+				return -EINVAL;
+			}
+			return 0;
+
+		case DIA_IOCTL_LOG:
+			pDivaLog = (dia_log_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
+			{
+				DivasLog(pDivaLog);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_XLOG_REQ:
+			
+			if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
+			{
+				wCardNum = * (word *) arg;
+				DivasXlogReq(wCardNum);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_NUM:
+			
+			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
+			{
+				* (int *) arg = DivasCardNext;
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_LIST:
+			DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
+			
+			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
+			{
+				DivasGetList((dia_card_list_t *)arg);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_MEM:
+			mem_block = (mem_block_t *) arg;
+			
+			if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
+			{
+				DivasGetMem(mem_block);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_UNLOCK:
+			UnlockDivas();
+			return 0;
+
+		default:
+			printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
+			return -EINVAL;
+	}
+	
+	return -EINVAL;
+}
+
+unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable)
+{
+	word wMask = 0;
+
+    if (!DivasLogFifoEmpty())
+    {
+		wMask |= POLLIN | POLLRDNORM;
+	}
+
+	return wMask;
+}
+
+ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset)
+{
+	klog_t *pClientLogBuffer = (klog_t *) pUserBuffer;
+	klog_t *pHeadItem;
+
+	if (BufferSize < sizeof(klog_t))
+	{
+		printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
+			BufferSize, sizeof(klog_t));
+		return 0;
+	}
+
+	pHeadItem = (klog_t *) DivasLogFifoRead();
+
+	if (pHeadItem)
+	{
+		bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t));
+		kfree(pHeadItem);
+		return sizeof(klog_t);
+	}
+
+	return 0;
+}
+static int private_usage_count;
+
+int do_open(struct inode *pInode, struct file *pFile)
+{
+	MOD_INC_USE_COUNT;
+#ifdef MODULE
+	private_usage_count++;
+#endif
+	return 0;
+}
+
+int do_release(struct inode *pInode, struct file *pFile)
+{
+	MOD_DEC_USE_COUNT;
+#ifdef MODULE
+	private_usage_count--;
+#endif
+	return 0;
+}
+
+void UnlockDivas(void)
+{
+	while (private_usage_count > 0)
+	{
+		private_usage_count--;
+		MOD_DEC_USE_COUNT;
+	}
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/linio.c linux/drivers/isdn/eicon/linio.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/linio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/linio.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,747 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.16  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#define N_DATA
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#undef N_DATA
+
+#include "uxio.h"
+
+static
+int log_on=0;
+
+int		Divasdevflag = 0;
+
+//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
+
+static
+ux_diva_card_t card_pool[MAX_CARDS];
+
+void UxPause(long int ms)
+{
+	int timeout = jiffies + ((ms * HZ) / 1000);
+
+	while (time_before(jiffies, timeout));
+}
+
+int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg)
+{
+	int 		i;
+	ux_diva_card_t	*c;
+
+	if (cfg->bus_type != DIA_BUS_TYPE_PCI)
+	{
+		DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type));
+		return -1;
+	}
+
+	for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++)
+	{
+		;
+	}
+
+	if (i == DIM(card_pool))
+	{
+		DPRINTF(("divas hw: card_pool exhausted"));
+		return -1;
+	}
+
+	c = *card = &card_pool[i];
+
+	switch (cfg->bus_type)
+	{
+	case DIA_BUS_TYPE_PCI:
+		c->bus_num = cfg->bus_num;
+		c->func_num = cfg->func_num;
+		c->io_base = cfg->io_base;
+		c->reset_base = cfg->reset_base;
+		c->card_type    = cfg->card_type;
+		c->mapped = NULL;
+		c->slot 	= cfg->slot;
+		c->irq 		= (int) cfg->irq;
+		c->pDRAM    	= cfg->memory[DIVAS_RAM_MEMORY];
+		c->pDEVICES 	= cfg->memory[DIVAS_REG_MEMORY];
+		c->pCONFIG  	= cfg->memory[DIVAS_CFG_MEMORY];
+		c->pSHARED  	= cfg->memory[DIVAS_SHARED_MEMORY];
+		c->pCONTROL  	= cfg->memory[DIVAS_CTL_MEMORY];
+
+	/*		c->bus_type 	= DIA_BUS_TYPE_PCI;
+		c->bus_num 	= cfg->bus_num & 0x3f;
+		c->slot 	= cfg->slot;
+		c->irq 		= (int) cfg->irq;
+		c->int_priority = (int) cfg->int_priority;
+		c->card_type    = cfg->card_type;
+		c->io_base      = cfg->io_base;
+		c->reset_base   = cfg->reset_base;
+		c->pDRAM    	= cfg->memory[DIVAS_RAM_MEMORY];
+		c->pDEVICES 	= cfg->memory[DIVAS_REG_MEMORY];
+		c->pCONFIG  	= cfg->memory[DIVAS_CFG_MEMORY];
+		c->pSHARED  	= cfg->memory[DIVAS_SHARED_MEMORY];
+		DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM));
+		DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED));
+		DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG));
+		c->cm_key		= cm_getbrdkey("Divas", cfg->card_id);*/
+		break;
+	default:
+		break;
+	}
+
+	c->in_use = TRUE;
+
+	return 0;
+}
+
+void UxCardHandleFree(ux_diva_card_t *card)
+{
+	card->in_use = FALSE;
+}
+
+
+#define PLX_IOBASE 0
+#define DIVAS_IOBASE 1
+void *UxCardMemAttach(ux_diva_card_t *card, int id)
+{
+	if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER)
+	{
+		switch (id)
+		{
+		case DIVAS_SHARED_MEMORY:
+			card->mapped = card->pSHARED;
+			return card->pSHARED;
+			break;
+		case DIVAS_RAM_MEMORY:
+			card->mapped = card->pDRAM;
+			return card->pDRAM;
+			break;
+		case DIVAS_REG_MEMORY:
+			card->mapped = card->pDEVICES;
+			return card->pDEVICES;
+			break;
+		case DIVAS_CFG_MEMORY:
+			card->mapped = card->pCONFIG;
+			return card->pCONFIG;
+			break;
+		default:
+			ASSERT(FALSE);
+			card->mapped = NULL;
+			return (void *) 0;
+		}
+	}
+	else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+	{
+		switch (id)
+		{
+		case PLX_IOBASE:
+			return (void *) card->reset_base;
+			break;
+		case DIVAS_IOBASE:
+			return (void *) card->io_base;
+			break;
+		default:
+			ASSERT(FALSE);
+			return 0;
+		}
+	}
+	
+	else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+	{
+		switch (id)
+		{
+		case DIVAS_SHARED_MEMORY:
+			card->mapped = card->pSHARED;
+			return card->pSHARED;
+			break;
+		case DIVAS_RAM_MEMORY:
+			card->mapped = card->pDRAM;
+			return card->pDRAM;
+			break;
+		case DIVAS_REG_MEMORY:
+			card->mapped = (void *) card->io_base;
+			return (void *) card->io_base;
+			break;
+		case DIVAS_CTL_MEMORY:
+			card->mapped = card->pCONTROL;
+			return card->pCONTROL;
+			break;
+		default:
+			// ASSERT(FALSE);
+			DPRINTF(("divas: Trying to attach to mem %d", id));
+			card->mapped = NULL;
+			return (void *) 0;
+		}
+	} else
+		DPRINTF(("divas: Tried to attach to unknown card"));
+
+	/* Unknown card type */
+	return NULL;
+}
+
+void UxCardMemDetach(ux_diva_card_t *card, void *address)
+{
+	return; // Just a place holder. No un-mapping done.
+}
+
+void UxCardLog(int turn_on)
+{
+	log_on = turn_on;
+}
+
+/*
+ * Control Register I/O Routines to be performed on Attached I/O ports
+ */
+
+void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outb(the_byte, base);
+}
+
+void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outw(the_word, base);
+}
+
+void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outl(the_dword, base);
+}
+
+byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	return inb(base);
+}
+
+word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	return inw(base);
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardMemIn(ux_diva_card_t *card, void *address)
+{
+	byte	b;
+	volatile byte* t = (byte*)address;
+
+	b = *t;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a));
+    	}
+
+    return(b); 
+}
+
+word UxCardMemInW(ux_diva_card_t *card, void *address)
+{
+	word	w;
+	volatile word* t = (word*)address;
+
+    w = *t;
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a));
+    }
+
+    return (w);
+}
+
+dword UxCardMemInD(ux_diva_card_t *card, void *address)
+{
+	dword	dw;
+	volatile dword* t = (dword*)address;
+
+    dw = *t;
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a));
+    }
+
+    return (dw);
+}
+
+void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+	volatile byte *pSource = address;
+	byte *pDest = buffer;
+
+	while (length--)
+	{
+		*pDest++ = *pSource++;
+	}
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		pDest = buffer;
+		DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		a));
+    }
+
+    return;
+}
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data)
+{
+	volatile byte* t = (byte*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a));
+	}
+
+	*t = data;
+
+    	return;
+}
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data)
+{
+	volatile word* t = (word*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a));
+	}
+
+	*t = data;
+    return;
+}
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data)
+{
+	volatile dword* t = (dword*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a));
+	}
+
+	*t = data;
+    return;
+}
+
+void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+	byte 	*pSource = buffer;
+	byte	*pDest = address;
+
+	while (length--)
+	{
+		*pDest++ = *pSource++;
+	}
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		pDest = buffer;
+		DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		a));
+    }
+
+    return;
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	byte the_byte;
+
+    outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+
+	the_byte = inb(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", 
+					the_byte & 0xff, address));
+    }
+    
+	return the_byte;
+}
+
+word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	word the_word;
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	the_word = inw(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", 
+					the_word & 0xffff, address));
+    }
+
+	return the_word;
+}
+
+dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	dword the_dword;
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	the_dword = inl(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", 
+					the_dword, address));
+    }
+
+    return the_dword;
+}
+
+void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+	byte *pSource = address;
+	byte *pDest = buffer;
+
+	if ((word) (dword) address & 0x1)
+	{
+		outb(0xFF, card->io_base + 0xC);
+		outw((word) (dword) pSource, card->io_base + 4);
+		*pDest = (byte) inb(card->io_base);
+		pDest++;
+		pSource++;
+		length--;
+		if (!length)
+        {
+            return;
+        }
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) pSource, card->io_base + 4);
+	insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1);
+
+	if (log_on)
+    {
+		pDest = buffer;
+		DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		address));
+    }
+
+    return;
+}
+
+/* Output */
+
+void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", 
+					data & 0xff, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outb((byte) data & 0xFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", 
+					data & 0xffff, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outw((word) data & 0xFFFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outl((dword) data & 0xFFFFFFFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+	byte 	*pSource = buffer;
+	byte	*pDest = address;
+
+	if ((word) (dword) address & 1)
+	{
+		outb(0xFF, card->io_base + 0xC);
+		outw((word) (dword) pDest, card->io_base + 4);
+		outb(*pSource, card->io_base);
+		pSource++;
+		pDest++;
+		length--;
+		if (!length)
+        {
+			return;
+        }
+	}
+
+    outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) pDest, card->io_base + 4);
+	outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1);
+
+	if (log_on)
+    {
+		pDest = buffer;
+		DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		address));
+    }
+
+    return;
+}
+
+void 	Divasintr(int arg, void *unused, struct pt_regs *unused_regs)
+{
+	int i;
+	card_t *card = NULL;
+	ux_diva_card_t *ux_ref = NULL;
+
+	for (i = 0; i < DivasCardNext; i++)
+	{
+
+		if (arg == DivasCards[i].cfg.irq)
+		{
+			card = &DivasCards[i];
+			ux_ref = card->hw;
+	
+			if ((ux_ref) && (card->is_live))
+			{
+				(*ux_ref->user_isr)(ux_ref->user_isr_arg);	
+			}
+			else 
+			{
+				DPRINTF(("divas: ISR couldn't locate card"));
+			}
+		}
+	}
+
+	return;
+}
+
+
+int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg)
+{
+	int result;
+
+        card->user_isr = isr_fn;
+        card->user_isr_arg = isr_arg;
+
+	result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg);
+
+	return result;
+}
+
+void UxIsrRemove(ux_diva_card_t *card, void *dev_id)
+{
+	free_irq(card->irq, card->user_isr_arg);
+}
+
+void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value)
+{
+	switch (size)
+	{
+	case sizeof(byte):
+		pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value);
+		break;
+	case sizeof(word):
+		pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value);
+		break;
+	case sizeof(dword):
+		pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value);
+		break;
+	default:
+		printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n");
+	}
+}
+
+void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value)
+{
+	switch (size)
+	{
+	case sizeof(byte):
+		pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value);
+		break;
+	case sizeof(word):
+		pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value);
+		break;
+	case sizeof(dword):
+		pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value);
+		break;
+	default:
+		printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n");
+	}
+}
+
+void *UxAlloc(unsigned int size)
+{
+	void *m;
+
+	m = kmalloc(size, GFP_ATOMIC);
+
+	return m;
+}
+
+void UxFree(void *ptr)
+{
+	kfree(ptr);
+}
+
+int UxCardLock(ux_diva_card_t *card)
+{
+	unsigned long flags;
+
+ 	//spin_lock_irqsave(&diva_lock, flags);
+	
+	save_flags(flags);
+	cli();
+	return flags;
+	
+}
+
+void UxCardUnlock(ux_diva_card_t *card, int ipl)
+{
+	//spin_unlock_irqrestore(&diva_lock, ipl);
+
+	restore_flags(ipl);
+
+}
+
+dword UxTimeGet(void)
+{
+	return jiffies;
+}
+
+long UxInterlockedIncrement(ux_diva_card_t *card, long *dst)
+{
+	register volatile long *p;
+	register long ret;
+	int ipl;
+
+	p =dst;
+	
+	ipl = UxCardLock(card);
+
+	*p += 1;
+	ret = *p;
+
+	UxCardUnlock(card,ipl);
+
+	return(ret);
+
+}
+
+long UxInterlockedDecrement(ux_diva_card_t *card, long *dst)
+{
+	register volatile long *p;
+	register long ret;
+	int ipl;
+
+	p =dst;
+	
+	ipl = UxCardLock(card);
+
+	*p -= 1;
+	ret = *p;
+
+	UxCardUnlock(card,ipl);
+
+	return(ret);
+
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/linsys.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/linsys.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,167 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.10  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/sched.h>
+#undef N_DATA
+#include <linux/tqueue.h>
+
+#include <linux/smp.h>
+struct pt_regs;
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include "sys.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+#ifdef MODULE
+void bcopy(void *pSource, void *pDest, dword dwLength)
+{
+	memcpy(pDest, pSource, dwLength);
+}
+#endif
+
+void bzero(void *pDataArea, dword dwLength)
+{
+	memset(pDataArea, 0, dwLength);
+}
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Use UxPciConfigWrite	routines to initialise PCI config space */
+
+/*	wPCIcommand = 0x03;
+	cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+
+	wPCIcommand = 0x280;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+
+	bPCIcommand = 0x30;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+*/
+	return 0; 
+}
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Use UxPciConfigWrite	routines to initialise PCI config space */
+
+/*		wPCIcommand = 0x03;
+	cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+	
+	wPCIcommand = 0x280;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+	
+	bPCIcommand = 0x30;
+	cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/
+
+	return 0;  
+}
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Need to set these platform dependent values after patching */
+
+	card->hw->reset_base = card->cfg.reset_base;
+	card->hw->io_base = card->cfg.io_base;
+
+	request_region(card->hw->reset_base,0x80,"Divas");
+	request_region(card->hw->io_base,0x20,"Divas");
+
+
+	/* Same as for PRI */
+	return DivasPRIInitPCI(card, cfg);
+}
+
+/* ######################### Stubs of routines that are not done yet ################## */
+/*void DivasLogIdi(card_t *card, ENTITY *e, int request)
+{
+}
+*/
+
+int	DivasDpcSchedule(void)
+{
+	static	struct tq_struct DivasTask;
+
+	DivasTask.routine = DivasDoDpc;
+	DivasTask.data = (void *) 0;
+
+	queue_task(&DivasTask, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return 0;
+}
+
+int	DivasScheduleRequestDpc(void)
+{
+	static	struct tq_struct DivasTask;
+
+	DivasTask.routine = DivasDoRequestDpc;
+	DivasTask.data = (void *) 0;
+
+	queue_task(&DivasTask, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return 0;
+}
+
+void    DivasLogAdd(void *buffer, int length)
+{
+    static
+    boolean_t   overflow = FALSE;
+    static
+    boolean_t   busy = FALSE;
+
+    /* make sure we're not interrupting ourselves */
+
+    if (busy)
+    {
+        printk(KERN_DEBUG "Divas: Logging interrupting self !\n");
+        return;
+    }
+    busy = TRUE;
+
+    /* ignore call if daemon isn't running and we've reached limit */
+
+    if (DivasLogFifoFull())
+    {
+        if (!overflow)
+        {
+            printk(KERN_DEBUG "Divas: Trace buffer full\n");
+            overflow = TRUE;
+        }
+        busy = FALSE;
+        return;
+    }
+
+	DivasLogFifoWrite(buffer, length);
+
+    busy = FALSE;
+    return;
+}
+
+/* #################################################################################### */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/log.c linux/drivers/isdn/eicon/log.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/log.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/log.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,176 @@
+   
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Source file for diva log facility
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+/*Counter to monitor number of messages */ 
+static int m_count;
+ 
+#define     MAX_BUFFERED_MSGS   (1000)
+
+/* Our Linked List Structure to hold message */
+typedef struct klog_link{
+  klog_t klog;
+  struct klog_link *next;
+}KNODE;
+
+/* First & Last structures in list*/
+KNODE *head;
+KNODE *tail;
+
+/* 
+ * retrieve message from FIFO buffer
+ * returns NULL if buffer empty
+ * otherwise returns pointer to entry 
+ */
+
+char	*DivasLogFifoRead(void)
+
+{
+	KNODE *old_head;
+
+	if(head==NULL) 
+	{
+		/* Buffer Empty - No Messages */
+		return NULL;	
+	}
+
+	m_count--;
+	/* Keep track of message to be read & increment to next message*/
+	old_head = head;
+	head = head->next;
+    /*Return ptr to Msg */	
+    return((char *)old_head);
+}
+
+/* 
+ * write message into FIFO buffer
+ */
+
+void	DivasLogFifoWrite(char *entry, int length)
+
+{
+    KNODE *new_klog;
+
+    if(head == NULL) 
+    {
+	/* No Entries in Log */
+	tail=NULL;
+	m_count=0;
+	new_klog=UxAlloc(sizeof(KNODE));
+
+	if(new_klog==NULL)
+	{
+		return;
+	}
+
+	m_count++;
+	bzero(new_klog,sizeof(KNODE));
+
+	/* Set head & tail to point to the new Msg Struct */
+	head=tail=new_klog;
+	tail->next=NULL;
+    }
+    else
+    {
+	new_klog=UxAlloc(sizeof(KNODE));
+	
+	if(new_klog==NULL)
+	{
+		return;
+	}
+
+	m_count++;
+	bzero(new_klog,sizeof(KNODE));
+
+	/* Let last Msg Struct point to new Msg Struct & inc tail */
+	tail->next=new_klog;
+	tail=new_klog;
+	tail->next=NULL;
+    }
+
+    if (length > sizeof(klog_t))
+    {
+        length = sizeof(klog_t);
+    }
+
+    bcopy(entry,&tail->klog,length);
+
+    return;
+}
+
+/*
+ * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE
+ */
+int DivasLogFifoEmpty(void)
+{
+	return (m_count == 0);
+}
+
+/*
+ *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE
+ */
+int DivasLogFifoFull(void)
+{
+	return (m_count == MAX_BUFFERED_MSGS);
+}
+
+/*
+ * generate an IDI log entry
+ */
+
+void	DivasLogIdi(card_t *card, ENTITY *e, int request)
+
+{
+	klog_t		klog;
+
+	bzero(&klog, sizeof(klog));
+
+	klog.time_stamp = UxTimeGet();
+
+	klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ?
+						sizeof(klog.buffer) : sizeof(ENTITY);
+
+	klog.card = (int) (card - DivasCards);
+
+	klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK;
+	klog.code = 0;
+	bcopy(e, klog.buffer, klog.length);
+
+    /* send to the log driver and return */
+
+    DivasLogAdd(&klog, sizeof(klog));
+
+	return;
+}
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/pc.h linux/drivers/isdn/eicon/pc.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/pc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/pc.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,317 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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 PC_H_INCLUDED
+#define PC_H_INCLUDED
+
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/*------------------------------------------------------------------*/
+/* buffer definition                                                */
+/*------------------------------------------------------------------*/
+
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} PBUFFER;
+
+/*------------------------------------------------------------------*/
+/* dual port ram structure                                          */
+/*------------------------------------------------------------------*/
+
+struct dual
+{
+  byte Req;             /* request register                         */
+  byte ReqId;           /* request task/entity identification       */
+  byte Rc;              /* return code register                     */
+  byte RcId;            /* return code task/entity identification   */
+  byte Ind;             /* Indication register                      */
+  byte IndId;           /* Indication task/entity identification    */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte RNR;             /* Receiver Not Ready (set by PC)           */
+  byte XLock;           /* XBuffer locked Flag                      */
+  byte Int;             /* ISDN-S interrupt                         */
+  byte ReqCh;           /* Channel field for layer-3 Requests       */
+  byte RcCh;            /* Channel field for layer-3 Returncodes    */
+  byte IndCh;           /* Channel field for layer-3 Indications    */
+  byte MInd;            /* more data indication field               */
+  word MLength;         /* more data total packet length            */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte SWReg;           /* Software register for special purposes   */  
+  byte Reserved[11];    /* reserved space                           */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-S adapter Signature (GD)            */
+  PBUFFER XBuffer;      /* Transmit Buffer                          */
+  PBUFFER RBuffer;      /* Receive Buffer                           */
+};
+
+/*------------------------------------------------------------------*/
+/* SWReg Values (0 means no command)                                */
+/*------------------------------------------------------------------*/
+#define SWREG_DIE_WITH_LEDON  0x01
+#define SWREG_HALT_CPU        0x02 /* Push CPU into a while(1) loop */         
+
+/*------------------------------------------------------------------*/
+/* Id Fields Coding                                                 */
+/*------------------------------------------------------------------*/
+
+#define ID_MASK 0xe0    /* Mask for the ID field                    */
+#define GL_ERR_ID 0x1f  /* ID for error reporting on global requests*/
+
+#define DSIG_ID  0x00   /* ID for D-channel signaling               */
+#define NL_ID    0x20   /* ID for network-layer access (B or D)     */
+#define BLLC_ID  0x60   /* ID for B-channel link level access       */
+#define TASK_ID  0x80   /* ID for dynamic user tasks                */
+#define TIMER_ID 0xa0   /* ID for timer task                        */
+#define TEL_ID   0xc0   /* ID for telephone support                 */
+#define MAN_ID   0xe0   /* ID for management                        */
+
+/*------------------------------------------------------------------*/
+/* ASSIGN and REMOVE requests are the same for all entities         */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN  0x01
+#define UREMOVE  0xfe   /* without returncode */  
+#define REMOVE  0xff
+
+/*------------------------------------------------------------------*/
+/* Timer Interrupt Task Interface                                   */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TIM 0x01
+#define REMOVE_TIM 0xff
+
+/*------------------------------------------------------------------*/
+/* dynamic user task interface                                      */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TSK 0x01
+#define REMOVE_TSK 0xff
+
+#define LOAD 0xf0
+#define RELOCATE 0xf1
+#define START 0xf2
+#define LOAD2 0xf3
+#define RELOCATE2 0xf4
+
+/*------------------------------------------------------------------*/
+/* dynamic user task messages                                       */
+/*------------------------------------------------------------------*/
+
+#define TSK_B2          0x0000
+#define TSK_WAKEUP      0x2000
+#define TSK_TIMER       0x4000
+#define TSK_TSK         0x6000
+#define TSK_PC          0xe000
+
+/*------------------------------------------------------------------*/
+/* LL management primitives                                         */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_LL 1     /* assign logical link                      */
+#define REMOVE_LL 0xff  /* remove logical link                      */
+
+/*------------------------------------------------------------------*/
+/* LL service primitives                                            */
+/*------------------------------------------------------------------*/
+
+#define LL_UDATA 1      /* link unit data request/indication        */
+#define LL_ESTABLISH 2  /* link establish request/indication        */
+#define LL_RELEASE 3    /* link release request/indication          */
+#define LL_DATA 4       /* data request/indication                  */
+#define LL_LOCAL 5      /* switch to local operation (COM only)     */
+#define LL_DATA_PEND 5  /* data pending indication (SDLC SHM only)  */
+#define LL_REMOTE 6     /* switch to remote operation (COM only)    */
+#define LL_TEST 8       /* link test request                        */
+#define LL_MDATA 9      /* more data request/indication             */
+#define LL_BUDATA 10    /* broadcast unit data request/indication   */
+#define LL_XID 12       /* XID command request/indication           */
+#define LL_XID_R 13     /* XID response request/indication          */
+
+/*------------------------------------------------------------------*/
+/* NL service primitives                                            */
+/*------------------------------------------------------------------*/
+
+#define N_MDATA         1       /* more data to come REQ/IND        */
+#define N_CONNECT       2       /* OSI N-CONNECT REQ/IND            */
+#define N_CONNECT_ACK   3       /* OSI N-CONNECT CON/RES            */
+#define N_DISC          4       /* OSI N-DISC REQ/IND               */
+#define N_DISC_ACK      5       /* OSI N-DISC CON/RES               */
+#define N_RESET         6       /* OSI N-RESET REQ/IND              */
+#define N_RESET_ACK     7       /* OSI N-RESET CON/RES              */
+#define N_DATA          8       /* OSI N-DATA REQ/IND               */
+#define N_EDATA         9       /* OSI N-EXPEDITED DATA REQ/IND     */
+#define N_UDATA         10      /* OSI D-UNIT-DATA REQ/IND          */
+#define N_BDATA         11      /* BROADCAST-DATA REQ/IND           */
+#define N_DATA_ACK      12      /* data ack ind for D-bit procedure */
+#define N_EDATA_ACK     13      /* data ack ind for INTERRUPT       */
+
+#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
+#define N_M_BIT         0x20    /* M-bit for req/ind                */
+#define N_D_BIT         0x40    /* D-bit for req/ind                */
+
+/*------------------------------------------------------------------*/
+/* Signaling management primitives                                  */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_SIG 1    /* assign signaling task                    */
+#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */
+#define REMOVE_SIG 0xff /* remove signaling task                    */
+
+/*------------------------------------------------------------------*/
+/* Signaling service primitives                                     */
+/*------------------------------------------------------------------*/
+
+#define CALL_REQ 1      /* call request                             */
+#define CALL_CON 1      /* call confirmation                        */
+#define CALL_IND 2      /* incoming call connected                  */
+#define LISTEN_REQ 2    /* listen request                           */
+#define HANGUP 3        /* hangup request/indication                */
+#define SUSPEND 4       /* call suspend request/confirm             */
+#define RESUME 5        /* call resume request/confirm              */
+#define SUSPEND_REJ 6   /* suspend rejected indication              */
+#define USER_DATA 8     /* user data for user to user signaling     */
+#define CONGESTION 9    /* network congestion indication            */
+#define INDICATE_REQ 10 /* request to indicate an incoming call     */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11     /* accept an incoming call                  */
+#define CALL_ALERT 12   /* send ALERT for incoming call             */
+#define INFO_REQ 13     /* INFO request                             */
+#define INFO_IND 13     /* INFO indication                          */
+#define REJECT 14       /* reject an incoming call                  */
+#define RESOURCES 15    /* reserve B-Channel hardware resources     */
+#define TEL_CTRL 16     /* Telephone control request/indication     */
+#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
+#define FAC_REG_REQ 18  /* connection idependent fac registration   */
+#define FAC_REG_ACK 19  /* fac registration acknowledge             */
+#define FAC_REG_REJ 20  /* fac registration reject                  */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
+#define FACILITY_REQ 22 /* send a Facility Message type             */
+#define FACILITY_IND 22 /* Facility Message type indication         */
+#define SIG_CTRL     29 /* Control for signalling hardware          */
+#define DSP_CTRL     30 /* Control for DSPs                         */
+#define LAW_REQ      31 /* Law config request for (returns info_i)  */ 
+
+ 
+/*------------------------------------------------------------------*/
+/* management service primitives                                    */
+/*------------------------------------------------------------------*/
+
+#define MAN_READ        2
+#define MAN_WRITE       3
+#define MAN_EXECUTE     4
+#define MAN_EVENT_ON    5
+#define MAN_EVENT_OFF   6
+#define MAN_LOCK        7
+#define MAN_UNLOCK      8   
+
+#define MAN_INFO_IND    2
+#define MAN_EVENT_IND   3
+#define MAN_TRACE_IND   4  
+
+#define MAN_ESC         0x80
+
+/*------------------------------------------------------------------*/
+/* return code coding                                               */
+/*------------------------------------------------------------------*/
+
+#define UNKNOWN_COMMAND         0x01    /* unknown command          */
+#define WRONG_COMMAND           0x02    /* wrong command            */
+#define WRONG_ID                0x03    /* unknown task/entity id   */
+#define WRONG_CH                0x04    /* wrong task/entity id     */
+#define UNKNOWN_IE              0x05    /* unknown information el.  */
+#define WRONG_IE                0x06    /* wrong information el.    */
+#define OUT_OF_RESOURCES        0x07    /* ISDN-S card out of res.  */
+#define ADAPTER_DEAD            0x08    /* ISDN card CPU halted     */ 
+#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
+#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
+#define ASSIGN_OK               0xef    /* ASSIGN OK                */
+#define OK_FC                   0xfc    /* Flow-Control RC          */
+#define READY_INT               0xfd    /* Ready interrupt          */
+#define TIMER_INT               0xfe    /* timer interrupt          */
+#define OK                      0xff    /* command accepted         */
+
+/*------------------------------------------------------------------*/
+/* information elements                                             */
+/*------------------------------------------------------------------*/
+
+#define SHIFT 0x90              /* codeset shift                    */
+#define MORE 0xa0               /* more data                        */
+#define CL 0xb0                 /* congestion level                 */
+
+        /* codeset 0                                                */
+
+#define BC  0x04                /* Bearer Capability                */
+#define CAU 0x08                /* cause                            */
+#define CAD 0x0c                /* Connected address                */
+#define CAI 0x10                /* call identity                    */
+#define CHI 0x18                /* channel identification           */
+#define LLI 0x19                /* logical link id                  */
+#define CHA 0x1a                /* charge advice                    */
+#define DT  0x29                /* ETSI date/time                   */
+#define KEY 0x2c                /* keypad information element       */
+#define FTY 0x1c                /* facility information element     */ 
+#define DSP 0x28                /* display                          */
+#define OAD 0x6c                /* origination address              */
+#define OSA 0x6d                /* origination sub-address          */
+#define CPN 0x70                /* called party number              */
+#define DSA 0x71                /* destination sub-address          */
+#define RDX 0x73                /* redirected number extended       */
+#define RDN 0x74                /* redirected number                */  
+#define LLC 0x7c                /* low layer compatibility          */
+#define HLC 0x7d                /* high layer compatibility         */
+#define UUI 0x7e                /* user user information            */
+#define ESC 0x7f                /* escape extension                 */
+
+#define DLC 0x20                /* data link layer configuration    */
+#define NLC 0x21                /* network layer configuration      */
+
+        /* codeset 6                                                */
+
+#define SIN 0x01                /* service indicator                */
+#define CIF 0x02                /* charging information             */
+#define DATE 0x03               /* date                             */
+#define CPS 0x07                /* called party status              */
+
+/*------------------------------------------------------------------*/
+/* TEL_CTRL contents                                                */
+/*------------------------------------------------------------------*/
+
+#define RING_ON         0x01
+#define RING_OFF        0x02
+#define HANDS_FREE_ON   0x03
+#define HANDS_FREE_OFF  0x04
+#define ON_HOOK         0x80
+#define OFF_HOOK        0x90
+
+#endif
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/pc_maint.h linux/drivers/isdn/eicon/pc_maint.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/pc_maint.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/pc_maint.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,162 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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 PC_MAINT_H
+#define PC_MAINT_H
+
+#if !defined(MIPS_SCOM)
+#define BUFFER_SZ  48
+#define MAINT_OFFS 0x380
+#else
+#define BUFFER_SZ  128
+#define MAINT_OFFS 0xff00
+#endif
+
+#define MIPS_BUFFER_SZ  128
+#define MIPS_MAINT_OFFS 0xff00
+
+#define DO_LOG                     1
+#define MEMR                    2
+#define MEMW                    3
+#define IOR                     4
+#define IOW                     5
+#define B1TEST                  6
+#define B2TEST                  7
+#define BTESTOFF                8
+#define DSIG_STATS              9
+#define B_CH_STATS              10
+#define D_CH_STATS              11
+#define BL1_STATS               12
+#define BL1_STATS_C             13
+#define GET_VERSION             14
+#define OS_STATS                15
+#define XLOG_SET_MASK           16
+#define XLOG_GET_MASK           17
+#define DSP_READ                20
+#define DSP_WRITE               21
+
+#define OK 0xff
+#define MORE_EVENTS 0xfe
+#define NO_EVENT 1
+
+struct DSigStruc
+{
+  byte Id;
+  byte uX;
+  byte listen;
+  byte active;
+  byte sin[3];
+  byte bc[6];
+  byte llc[6];
+  byte hlc[6];
+  byte oad[20];
+};
+
+struct BL1Struc {
+  dword cx_b1;
+  dword cx_b2;
+  dword cr_b1;
+  dword cr_b2;
+  dword px_b1;
+  dword px_b2;
+  dword pr_b1;
+  dword pr_b2;
+  word er_b1;
+  word er_b2;
+};
+
+struct L2Struc {
+  dword XTotal;
+  dword RTotal;
+  word XError;
+  word RError;
+};
+
+struct OSStruc {
+  word free_n;
+};
+
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[BUFFER_SZ];
+  word   w[BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[BUFFER_SZ>>2];
+} BUFFER;
+
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[MIPS_BUFFER_SZ];
+  word   w[MIPS_BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+
+
+#if !defined(MIPS_SCOM)
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte *mem;  /*far*/
+  short length;
+  word port;
+  byte fill[6];
+  BUFFER data;
+};
+#else
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  byte far *mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  BUFFER data;
+};
+#endif
+
+struct mi_pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  byte *mem; /*far*/
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  MIPS_BUFFER data;
+};
+
+#endif /* PC_MAINT_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/pr_pc.h linux/drivers/isdn/eicon/pr_pc.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/pr_pc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/pr_pc.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,83 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#if !defined(PR_PC_H)
+#define PR_PC_H
+
+struct pr_ram {
+  word NextReq;         /* pointer to next Req Buffer               */
+  word NextRc;          /* pointer to next Rc Buffer                */
+  word NextInd;         /* pointer to next Ind Buffer               */
+  byte ReqInput;        /* number of Req Buffers sent               */
+  byte ReqOutput;       /* number of Req Buffers returned           */
+  byte ReqReserved;     /* number of Req Buffers reserved           */
+  byte Int;             /* ISDN-P interrupt                         */
+  byte XLock;           /* Lock field for arbitration               */
+  byte RcOutput;        /* number of Rc buffers received            */
+  byte IndOutput;       /* number of Ind buffers received           */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte Reserved1[2];    /* reserved field, do not use               */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte Reserved2[12];   /* reserved field, do not use               */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-P initialized indication            */
+  byte B[1];            /* buffer space for Req,Ind and Rc          */
+};
+
+typedef struct {
+  word next;
+  byte Req;
+  byte ReqId;
+  byte ReqCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved[8];
+  PBUFFER XBuffer;
+} REQ;
+
+typedef struct {
+  word next;
+  byte Rc;
+  byte RcId;
+  byte RcCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved2[8];
+} RC;
+
+typedef struct {
+  word next;
+  byte Ind;
+  byte IndId;
+  byte IndCh;
+  byte MInd;
+  word MLength;
+  word Reference;
+  byte RNR;
+  byte Reserved;
+  dword Ack;
+  PBUFFER RBuffer;
+} IND;
+
+#endif
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/pri.c linux/drivers/isdn/eicon/pri.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/pri.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/pri.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,530 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Diva Server PRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define	DIVAS_LOAD_CMD		0x02
+#define	DIVAS_START_CMD		0x03
+#define	DIVAS_IRQ_RESET		0xC18
+#define DIVAS_IRQ_RESET_VAL	0xFE
+
+#define	TEST_INT_DIVAS		0x11
+#define TEST_INT_DIVAS_BRI	0x12
+
+#define DIVAS_RESET	0x81
+#define DIVAS_LED1	0x04
+#define DIVAS_LED2	0x08
+#define DIVAS_LED3	0x20
+#define DIVAS_LED4	0x40
+
+#define	DIVAS_RESET_REG		0x20
+
+#define	DIVAS_SIGNATURE	0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define	DIVAS_MAINT_OFFSET	0xef00	/* value for PRI card */
+
+#define MP_PROTOCOL_ADDR		0xA0011000
+#define MP_DSP_CODE_BASE		0xa03a0000  
+
+typedef struct {
+		dword cmd;
+		dword addr;
+		dword len;
+		dword err;
+		dword live;
+		dword reserved[(0x1020>>2)-6];
+		dword signature;
+		byte  data[1];
+} diva_server_boot_t;
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg);
+static int pri_ISR (card_t* card);
+
+static int diva_server_reset(card_t *card)
+{
+	byte *reg;
+	diva_server_boot_t *boot = NULL;
+	dword live = 0;
+	int	i = 0;
+	dword	dwWait;
+
+	DPRINTF(("divas: reset Diva Server PRI"));
+
+	reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+	UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], DIVAS_RESET | 
+						DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4);
+
+	for (dwWait = 0x000fffff; dwWait; dwWait--)
+		;
+
+	UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], 0x00);
+
+	for (dwWait = 0x000fffff; dwWait; dwWait--)
+		;
+
+	UxCardMemDetach(card->hw, reg);
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	UxCardMemOutD(card->hw, boot->reserved, 0);
+
+	live = UxCardMemInD(card->hw, &boot->live);
+
+	for (i=0; i<5; i++)
+	{
+		if (live != UxCardMemInD(card->hw, &boot->live))
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (i == 5)
+	{
+		UxCardMemDetach(card->hw, boot);
+
+		DPRINTF(("divas: card is reset but CPU not running"));
+		return -1;
+	}
+
+	UxCardMemDetach(card->hw, boot);
+
+	DPRINTF(("divas: card reset after %d ms", i * 10));
+
+	return 0;
+}
+
+static int diva_server_config(card_t *card, dia_config_t *config)
+{
+	byte *shared;
+	int i, j;
+
+	DPRINTF(("divas: configure Diva Server PRI"));
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	UxCardLog(0);
+	for (i=0; i<256; i++)
+	{
+		UxCardMemOut(card->hw, &shared[i], 0);
+	}
+
+	UxCardMemOut(card->hw, &shared[ 8], config->tei);
+	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
+	UxCardMemOut(card->hw, &shared[11], config->watchdog);
+	UxCardMemOut(card->hw, &shared[12], config->permanent);
+	UxCardMemOut(card->hw, &shared[13], config->x_interface);
+	UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+	UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+	UxCardMemOut(card->hw, &shared[16], config->handset_type);
+	UxCardMemOut(card->hw, &shared[17], 0);
+	UxCardMemOut(card->hw, &shared[18], config->low_channel);
+	UxCardMemOut(card->hw, &shared[19], config->prot_version);
+	UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+	for (i=0; i<2; i++)
+	{
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+		}
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	return 0;
+}
+
+static
+void diva_server_reset_int(card_t *card)
+{
+	byte *cfg;
+
+	cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+
+	UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL);
+	UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0);
+	UxCardMemDetach(card->hw, cfg);
+
+	return;
+}
+
+ 
+static int diva_server_test_int(card_t *card)
+{
+	int i;
+	byte *shared;
+	byte req_int;
+
+	DPRINTF(("divas: test interrupt for Diva Server PRI"));
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	UxCardMemIn(card->hw, &shared[0x3FE]);
+	UxCardMemOut(card->hw, &shared[0x3FE], 0);
+	UxCardMemIn(card->hw, &shared[0x3FE]);
+
+	UxCardMemDetach(card->hw, shared);
+
+	diva_server_reset_int(card);
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	card->test_int_pend = TEST_INT_DIVAS;
+
+	req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt));
+
+	req_int++;
+
+	UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int);
+
+	UxCardMemDetach(card->hw, shared);
+
+	UxCardLog(0);
+	for (i = 0; i < 50; i++)
+	{
+		if (!card->test_int_pend)
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+
+	if (card->test_int_pend)
+	{
+
+		DPRINTF(("active: timeout waiting for card to interrupt"));
+		return (-1);
+	
+	}
+	
+	return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+	unsigned char hdr[80];
+		int i;
+
+	i = 0;
+
+	while ((i < (DIM(hdr) -1)) && 
+		(code[offset + i] != '\0') &&
+		(code[offset + i] != '\r') &&
+		(code[offset + i] != '\n'))
+	{
+		hdr[i] = code[offset + i];
+		i++;
+	}
+
+	hdr[i] = '\0';
+
+	DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_load(card_t *card, dia_load_t *load)
+{
+	diva_server_boot_t *boot;
+	int i, offset, length;
+	dword cmd = 0;
+
+	DPRINTF(("divas: loading Diva Server PRI"));
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	switch(load->code_type)
+	{
+		case DIA_CPU_CODE:
+			DPRINTF(("divas: RISC code"));
+			print_hdr(load->code, 0x80);
+
+			UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+			break;
+
+		case DIA_DSP_CODE:
+			DPRINTF(("divas: DSP code"));
+			print_hdr(load->code, 0x0);
+
+			UxCardMemOutD(card->hw, &boot->addr,  
+				(MP_DSP_CODE_BASE + (((sizeof(dword) +
+				(sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT))
+				+ ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA)));
+			break;
+
+		case DIA_TABLE_CODE:
+			DPRINTF(("divas: TABLE code"));
+			UxCardMemOutD(card->hw, &boot->addr,
+				(MP_DSP_CODE_BASE + sizeof(dword)));
+			break;
+
+		case DIA_CONT_CODE:
+			DPRINTF(("divas: continuation code"));
+			break;
+
+        case DIA_DLOAD_CNT:
+			DPRINTF(("divas: COUNT code"));
+			UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE);
+			break;
+
+		default:
+			DPRINTF(("divas: unknown code type"));
+			UxCardMemDetach(card->hw, boot);
+			return -1;
+	}
+
+	UxCardLog(0);
+	offset = 0;
+
+	do
+	{
+		length = (load->length - offset >= 400) ? 400 : load->length - offset;
+
+		for (i=0; i<length; i++)
+		{
+			UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]);
+		}
+
+        for (i=0; i<length; i++)
+		{
+			if (load->code[offset + i] != UxCardMemIn(card->hw, &boot->data[i]))
+			{
+				UxCardMemDetach(card->hw, boot);
+
+				DPRINTF(("divas: card code block verify failed"));
+				return -1;
+			}
+		}
+	
+		UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4);
+		UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD);
+
+		for (i=0; i<50000; i++)
+		{
+			cmd = UxCardMemInD(card->hw, &boot->cmd);
+			if (!cmd)
+			{
+				break;
+			}
+			/*UxPause(1);*/
+		}
+
+		if (cmd)
+		{
+			DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset));
+			UxCardMemDetach(card->hw, boot);
+			return -1;
+		}
+
+		offset += length;
+
+	} while (offset < load->length);
+
+	UxCardMemDetach(card->hw, boot);
+
+	DPRINTF(("divas: DIVA Server card loaded"));
+
+	return 0;
+}
+
+static int diva_server_start(card_t *card, byte *channels)
+{
+	diva_server_boot_t *boot;
+	byte *ram;
+	int	i;
+	dword signature = 0;
+
+	DPRINTF(("divas: start Diva Server PRI"));
+
+	card->is_live = FALSE;
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+	UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD);
+
+	UxCardLog(0);
+
+	for (i = 0; i < 300; i++)
+	{
+		signature = UxCardMemInD(card->hw, &boot->signature);
+		if ((signature >> 16) == DIVAS_SIGNATURE)
+		{
+			DPRINTF(("divas: started card after %d ms", i * 10));
+			break;
+		}
+		UxPause(10);
+	}
+
+	if ((signature >> 16) != DIVAS_SIGNATURE)
+	{
+		UxCardMemDetach(card->hw, boot);
+		DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature));
+		return -1;
+	}
+
+	card->is_live = TRUE;
+
+	ram = (byte *) boot;
+	ram += DIVAS_SHARED_OFFSET;
+
+	*channels = UxCardMemIn(card->hw, &ram[0x3F6]);
+	card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]);
+
+	UxCardMemDetach(card->hw, boot);
+
+	if (diva_server_test_int(card))
+	{
+		DPRINTF(("divas: interrupt test failed"));
+		return -1;	
+	}
+
+	DPRINTF(("divas: DIVA Server card started"));
+
+	return 0;
+}
+
+static
+int 	diva_server_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+	byte	*a;
+	byte	*card_addr;
+	word	length = 0;
+	int		i;
+
+	a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	card_addr = a;
+	card_addr += mem_block->addr;
+
+	for (i=0; i < sizeof(mem_block->data); i++)
+	{
+		mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+		card_addr++;
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, a);
+
+	return length;
+}
+
+/*
+ * Initialise PRI specific entry points
+ */
+
+int DivasPriInit(card_t *card, dia_card_t *cfg)
+{
+	DPRINTF(("divas: initialise Diva Server PRI"));
+
+	if (DivasPRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	card->card_reset = diva_server_reset;
+	card->card_load = diva_server_load;
+	card->card_config = diva_server_config;
+	card->card_start = diva_server_start;
+	card->reset_int = diva_server_reset_int;
+	card->card_mem_get = diva_server_mem_get;
+
+	card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+	card->out = DivasOut;
+	card->test_int = DivasTestInt;
+	card->dpc = DivasDpc;
+	card->clear_int = DivasClearInt;
+	card->card_isr  = pri_ISR;
+
+	card->a.ram_out = mem_out;
+	card->a.ram_outw = mem_outw;
+	card->a.ram_out_buffer = mem_out_buffer;
+	card->a.ram_inc = mem_inc;
+
+	card->a.ram_in = mem_in;
+	card->a.ram_inw = mem_inw;
+	card->a.ram_in_buffer = mem_in_buffer;
+	card->a.ram_look_ahead = mem_look_ahead;
+
+	return 0;
+}
+
+
+static int pri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+	volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET];
+	register unsigned long val = *isr;
+	
+	if (val & 0x80000000)  /* our card had caused interrupt ??? */
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); /* ISR DPC */
+
+		*isr = (unsigned long)~0x03E00000; /* Clear interrupt line */
+	}
+
+	UxCardMemDetach(card->hw, cfg);
+
+	return (served != 0);
+}
+
+
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/sys.h linux/drivers/isdn/eicon/sys.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/sys.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/sys.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,116 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Environment provided by system and miscellaneous definitions */
+
+#if !defined(SYS_H)
+#define SYS_H
+
+/* abreviations for unsigned types */
+typedef int boolean_t;
+
+typedef unsigned char byte;
+
+typedef unsigned long dword;
+typedef unsigned short word;
+
+/* abreviations for volatile types */
+
+typedef volatile byte	vbyte;
+typedef volatile word	vword;
+typedef volatile dword	vdword;
+
+/* Booleans */
+
+#if !defined(TRUE)
+#define TRUE    (1)
+#define FALSE   (0)
+#endif
+
+/* NULL pointer */
+
+#if !defined(NULL)
+#define NULL    ((void *) 0)
+#endif
+
+/* MIN and MAX */
+
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/* Return the dimension of an array */
+
+#if !defined(DIM)
+#define DIM(array)  (sizeof (array)/sizeof ((array)[0]))
+#endif
+
+/*
+ * Return the number of milliseconds since last boot
+ */
+
+extern	dword	UxTimeGet(void);
+
+extern	void 	DivasSprintf(char *buffer, char *format, ...);
+extern	void 	DivasPrintf(char *format, ...);
+
+/* fatal errors, asserts and tracing */
+
+void HwFatalErrorFrom(char *file, int line);
+void HwFatalError(void);
+/* void HwAssert(char *file, int line, char *condition); */
+
+#include <linux/kernel.h>
+#define _PRINTK printk
+
+#define _PRINTF	DivasPrintf
+void _PRINTF(char *format, ...);
+#define PRINTF(arg_list)	_PRINTF arg_list
+#if defined DTRACE
+# define DPRINTF(arg_list)	_PRINTF arg_list
+# define KDPRINTF(arg_list)	_PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n");
+#else
+# define DPRINTF(arg_list)	(void)0
+# define KDPRINTF(arg_list)	_PRINTK arg_list ; _PRINTK("\n");
+#endif
+
+#if !defined(ASSERT)
+#if defined DEBUG || defined DBG
+# define HwFatalError()	HwFatalErrorFrom(__FILE__, __LINE__)
+# define ASSERT(cond)								\
+		if (!(cond)) 								\
+		{											\
+/*			HwAssert(__FILE__, __LINE__, #cond);*/	\
+		}
+#else
+# define ASSERT(cond)	((void)0)
+#endif
+#endif /* !defined(ASSERT) */
+
+#define TRACE	(_PRINTF(__FILE__"@%d\n", __LINE__))
+
+#endif /* SYS_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h
--- linux-2.2.19-pre13/drivers/isdn/eicon/uxio.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/uxio.h	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,217 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.6  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Interface to Unix specific code for performing card I/O
+ */
+
+#if !defined(UXIO_H)
+#define UXIO_H
+
+#include "sys.h"
+#include "adapter.h"
+
+
+struct pt_regs;
+
+/* user callback, returns zero if interrupt was from this card */
+typedef	void		isr_fn_t(void *);
+struct ux_diva_card_s
+{
+	word	in_use;
+	int		io_base;
+	int		reset_base;
+	int		card_type;
+	byte		*mapped;
+	int		bus_num;
+	int		func_num;
+	int		slot;
+	int		irq;
+	byte		*pDRAM;
+	byte		*pDEVICES;
+	byte		*pCONFIG;
+	byte		*pSHARED;
+	byte		*pCONTROL;
+	word		features;
+	void		*user_isr_arg;
+	isr_fn_t	*user_isr;
+};
+
+void bcopy(void *pSource, void *pDest, dword dwLength);
+void bzero(void *pDataArea, dword dwLength);
+
+
+/*
+ * Get a card handle to enable card to be accessed
+ */
+
+int		UxCardHandleGet(	ux_diva_card_t	**card,
+							dia_card_t		*cfg);
+
+/*
+ * Free a card handle as no longer needed
+ */
+
+void	UxCardHandleFree(ux_diva_card_t *card);
+
+/*
+ * Lock and unlock access to a card
+ */
+
+int		UxCardLock(ux_diva_card_t *card);
+void	UxCardUnlock(ux_diva_card_t *card, int ipl);
+
+/*
+ * Set the mapping address for PCI cards
+ */
+
+int		UxCardAddrMappingSet(ux_diva_card_t	*card,
+							int				id,
+							void			*address,
+							int				size);
+
+/*
+ * Attach card to memory to enable it to be accessed
+ * Returns the mapped address
+ */
+
+void	*UxCardMemAttach(ux_diva_card_t *card, int id);
+
+/*
+ * map card out of memory after completion of access
+ */
+
+void	UxCardMemDetach(ux_diva_card_t *card, void *address);
+
+/*
+ * input functions for memory-mapped cards
+ */
+
+byte	UxCardMemIn(ux_diva_card_t *card, void *address);
+
+word	UxCardMemInW(ux_diva_card_t *card, void *address);
+
+dword	UxCardMemInD(ux_diva_card_t *card, void *address);
+
+void	UxCardMemInBuffer(	ux_diva_card_t *card,
+							void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * output functions for memory-mapped cards
+ */
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data);
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data);
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data);
+
+void UxCardMemOutBuffer(	ux_diva_card_t	*card,
+							void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * input functions for I/O-mapped cards
+ */
+
+byte	UxCardIoIn(ux_diva_card_t *card, void *, void *address);
+
+word	UxCardIoInW(ux_diva_card_t *card, void *, void *address);
+
+dword	UxCardIoInD(ux_diva_card_t *card, void *, void *address);
+
+void	UxCardIoInBuffer(	ux_diva_card_t *card,
+							void *, void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * output functions for I/O-mapped cards
+ */
+
+void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data);
+
+void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data);
+
+void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data);
+
+void UxCardIoOutBuffer(	ux_diva_card_t	*card,
+							void *, void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * Get specified PCI config
+ */
+
+void	UxPciConfigRead(ux_diva_card_t	*card, 
+						int				size,
+						int				offset,
+						void			*value);
+
+/*
+ * Set specified PCI config
+ */
+
+void	UxPciConfigWrite(ux_diva_card_t	*card, 
+						int				size,
+						int				offset,
+						void			*value);
+
+/* allocate memory, returning NULL if none available */
+
+void	*UxAlloc(unsigned int size);
+
+void	UxFree(void *);
+
+/*
+ * Pause for specified number of milli-seconds 
+ */
+
+void	UxPause(long ms);
+
+/*
+ * Install an ISR for the specified card
+ */
+
+int		UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg);
+
+/*
+ * Remove an ISR for the specified card
+ */
+void	UxIsrRemove(ux_diva_card_t *card, void *);
+
+/*
+ * DEBUG function to turn logging ON or OFF
+ */
+
+void	UxCardLog(int turn_on);
+
+long	UxInterlockedIncrement(ux_diva_card_t *card, long *dst);
+long	UxInterlockedDecrement(ux_diva_card_t *card, long *dst);
+
+#endif /* of UXIO_H */
diff -urN linux-2.2.19-pre13/drivers/isdn/eicon/xlog.c linux/drivers/isdn/eicon/xlog.c
--- linux-2.2.19-pre13/drivers/isdn/eicon/xlog.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/eicon/xlog.c	Mon Dec  3 21:07:21 2001
@@ -0,0 +1,180 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Unix Eicon active card driver
+ * XLOG related functions
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "pc.h"
+#include "pc_maint.h"
+#include "divalog.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+/*
+ * convert/copy XLOG info into a KLOG entry
+ */
+
+static
+void	xlog_to_klog(byte *b, int size, int card_num)
+
+{
+	typedef struct
+	{
+		word	code;
+		word	time_hi;
+		word	time_lo;
+		word	xcode;
+		byte	data[2];
+	} card_xlog_t;
+
+	card_xlog_t	*x;
+
+	klog_t		klog;
+
+	x = (card_xlog_t *) b;
+
+	bzero(&klog, sizeof(klog));
+
+	klog.time_stamp = (dword) x->time_hi;
+	klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo;
+
+	klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size;
+
+	klog.card = card_num;
+	if (x->code == 1)
+	{
+		klog.type = KLOG_XTXT_MSG;
+		klog.code = 0;
+		bcopy(&x->xcode, klog.buffer, klog.length);
+	}
+	else if (x->code == 2)
+	{
+		klog.type = KLOG_XLOG_MSG;
+		klog.code = x->xcode;
+		bcopy(&x->data, klog.buffer, klog.length);
+	}
+	else
+	{
+		char	*c; int i;
+		klog.type = KLOG_TEXT_MSG;
+		klog.code = 0;
+		c = "divas: invalid xlog message code from card";
+		i = 0;
+		while (*c)
+		{
+			klog.buffer[i] = *c;
+			c++;
+			i++;
+		}
+		klog.buffer[i] = *c;
+	}
+
+    /* send to the log driver and return */
+
+    DivasLogAdd(&klog, sizeof(klog));
+
+	return;
+}
+
+/*
+ * send an XLOG request down to specified card
+ * if response available from previous request then read it
+ * if not then just send down new request, ready for next time
+ */
+
+void	DivasXlogReq(int card_num)
+
+{
+	card_t				*card;
+	ADAPTER 			*a;
+
+	if ((card_num < 0) || (card_num > DivasCardNext))
+	{
+		DPRINTF(("xlog: invalid card number"));
+		return;
+	}
+
+	card = &DivasCards[card_num];
+
+	if (DivasXlogRetrieve(card))
+	{
+		return;
+	}
+
+	/* send down request for next time */
+
+	a = &card->a;
+
+	a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+	a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+	return;
+}
+
+/*
+ * retrieve XLOG request from specified card
+ * returns non-zero if new request sent to card
+ */
+
+int		DivasXlogRetrieve(card_t *card)
+
+{
+	ADAPTER 			*a;
+	struct mi_pc_maint	pcm;
+
+	a = &card->a;
+
+	/* get status of last request */
+
+	pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1));
+
+	/* if nothing there from previous request, send down a new one */
+
+	if (pcm.rc == OK)
+	{
+		/* read in response */
+
+		a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); 
+
+		xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), 
+						(int) (card - DivasCards));
+	}
+
+	/* if any response received from card, re-send request */
+
+	if (pcm.rc)
+	{
+		a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+		a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+		return 1;
+	} 
+
+	return 0;
+}
diff -urN linux-2.2.19-pre13/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- linux-2.2.19-pre13/drivers/net/3c59x.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/net/3c59x.c	Mon Dec  3 21:07:25 2001
@@ -60,14 +60,42 @@
     - In vortex_open(), set vp->tx_full to zero (else we get errors if the device was
       closed with a full Tx ring).
 
-	15Sep00 <2.2.18-pre3> andrewm
+	17Oct00 <2.2.18-pre16> andrewm
 	- Added support for the 3c556B Laptop Hurricane (Louis Gerbarg)
+    - Backported transceiver options handling from 2.4.  This changes the semantics
+      of forcing full duplex in the `options' parm!  (It's better to use
+      `full_duplex' anyway).  See Documentation/vortex.txt (Maciej Rozycki).
+    - Set PCI latency timer to maximum for the 3c590 (From Donald's driver)
+    - Removed all the CARDBUS code (it's never used).
+    - Added INVERT_MII_PWR, EEPROM_8BIT, EEPROM_OFFSET.  Use them.
+    - Use EEPROM_8BIT for the 3c555
+    - Merged ACPI WOL support from Donald's drivers.
+    - Sort-of backported Donald's new medialock code. Called it duplexlock
+      and we now prefer to use `full_duplex=[-1,0,1]' to force duplex mode.
+    - Merged the rx_oom_timer from 2.4.  This gives better handling of OOM
+      conditions.  Backed out the previous way of handling this.
+    - Replace suser() with capable(CAP_NET_ADMIN) in ioctl().
+
+    07Jan01 <2.2.19-pre6> andrewm
+    - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
+    - Added and used wait_for_completion().  3c905CX problems.
+    - Removed the code for older kernel versions.
+    - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger)
+    - Search for phy 24 first for 3c905CX. (D Becker)
+    - Don't free skbs we don't own on oom path in vortex_open().
+    - Added explicit `medialock' flag so we can truly
+      lock the media type down with `options'.
+    - In vortex_error(), only reset the up/down load engine, not all the
+      interface stuff.
+    - Added and used EEPROM_NORESET for 3c556B PM resumes.
+    - Enable WOL with the `enable_wol' module parm
+    - Give the 3c980 HAS_NWAY
 
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details.
 */
 
 static char version[] =
-"3c59x.c 15Sep00 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
+"3c59x.c 18Feb01 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -101,16 +129,6 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -124,9 +142,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-#include <linux/bios32.h>
-#endif
+#include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -136,48 +153,18 @@
 
 #define RUN_AT(x) (jiffies + (x))
 
-#include <linux/delay.h>
-
-#if (LINUX_VERSION_CODE <= 0x20100)
-#ifndef __alpha__
-#define ioremap(a,b) \
-	(((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
-#define iounmap(v) \
-	do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
-#endif
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#define le32_to_cpu(val) (val)
-#define cpu_to_le32(val) (val)
-#endif
-#if LINUX_VERSION_CODE < 0x20155
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
-#else  /* Grrr, unneeded incompatible change. */
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#endif
 
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(compaq_ioaddr, "i");
 MODULE_PARM(compaq_irq, "i");
 MODULE_PARM(compaq_device_id, "i");
-#endif
 
 /* Operational parameter that usually are not changed. */
 
@@ -286,7 +273,9 @@
 };
 
 enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
-	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80,
+	   INVERT_MII_PWR=0x100, EEPROM_8BIT=0x200, EEPROM_OFFSET=0x400,
+	   EEPROM_NORESET=0x800};
 static struct device *vortex_probe1(int pci_bus, int pci_devfn,
 									struct device *dev, long ioaddr,
 									int irq, int dev_id, int card_idx);
@@ -316,7 +305,7 @@
 	{"3c900B-FL Cyclone 10base-FL",	0x10B7, 0x900A, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c900 Cyclone 10Mbps TPO",	0x10B7, 0x9004, 0xffff,			/* AKPM: from Don's 0.99M */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3c900 Cyclone 10Mbps TPC",	0x10B7, 0x9006, 0xffff,			/* AKPM: from Don's 0.99M */
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c905 Boomerang 100baseTx",	0x10B7, 0x9050, 0xffff,
@@ -332,15 +321,15 @@
 	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, vortex_probe1},
 	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, vortex_probe1},
 	{"3c556 10/100 Mini PCI Adapter",	0x10B7, 0x6055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_CB_FNS, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, vortex_probe1},
 	{"3c556B Laptop Hurricane",	0x10B7, 0x6056, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_CB_FNS, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|EEPROM_NORESET, 128, vortex_probe1},
 	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
 	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
@@ -501,7 +490,7 @@
 };
 
 /* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20 };
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_private {
 	/* The Rx and Tx rings should be quad-word-aligned. */
@@ -515,23 +504,27 @@
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct net_device_stats stats;
-	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
+	struct sk_buff *tx_skb;				/* Packet being eaten by bus master ctrl.  */
 
 	/* PCI configuration space information. */
-	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
-	char *cb_fn_base;			/* CardBus function status addr space. */
+	u8 pci_bus, pci_devfn;				/* PCI bus location, for power management. */
+	char *cb_fn_base;					/* CardBus function status addr space. */
 	int chip_id;
 
 	/* The remainder are related to chip state, mostly media selection. */
-	struct timer_list timer;	/* Media selection timer. */
-	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:3, 			/* Passed-in media type. */
+	struct timer_list timer;			/* Media selection timer. */
+	struct timer_list rx_oom_timer;		/* Rx skb allocation retry timer */
+	int options;						/* User-settable misc. driver options. */
+	unsigned int media_override:4, 		/* Passed-in media type. */
 		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
+		full_duplex:1,					/* User wants FD (or we're running at FD) */
+		duplexlock:1,					/* User has forced duplex */
+		autoselect:1,					/* Can use NWAY negotiation */
+		bus_master:1,					/* Vortex can only do a fragment bus-m. */
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1;
+		tx_full:1,
+		enable_wol:1,
+		medialock:1;
 	u16 status_enable;
 	u16 intr_enable;
 	u16 available_media;				/* From Wn3_Options. */
@@ -571,14 +564,13 @@
   { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
-#ifndef CARDBUS
 static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]);
-#endif
 static int vortex_open(struct device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
 static void vortex_timer(unsigned long arg);
+static void rx_oom_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
 static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
 static int vortex_rx(struct device *dev);
@@ -590,116 +582,33 @@
 static struct net_device_stats *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
 static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static void acpi_wake(int pci_bus, int pci_devfn);
+static void acpi_set_WOL(struct device *dev);
 
 
-/* #define dev_alloc_skb dev_alloc_skb_debug */
+#if 0
+#warning dev_alloc_skb_debug is defined!
+#define dev_alloc_skb dev_alloc_skb_debug
+#endif
 
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
 #define MAX_UNITS 8
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 /* A list of all installed Vortex devices, for removing the driver module. */
 static struct device *root_vortex_dev = NULL;
 
 #ifdef MODULE
-#ifndef CARDBUS
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
-
-#ifdef CARDBUS
-
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *vortex_attach(dev_locator_t *loc)
-{
-	u16 dev_id, vendor_id;
-	u32 io;
-	u8 bus, devfn, irq;
-	struct device *dev;
-	int chip_idx;
-
-	if (loc->bus != LOC_PCI) return NULL;
-	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-		   bus, devfn, dev_id);
-	io &= ~3;
-	if (io == 0 || irq == 0) {
-		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
-			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
-			   io == 0 ? "I/O address" : "IRQ");
-		return NULL;
-	}
-	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor_id == pci_tbl[chip_idx].vendor_id
-			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==
-			pci_tbl[chip_idx].device_id)
-			break;
-	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */
-		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
-			   "vortex_attach().\n", vendor_id, dev_id);
-		return NULL;
-	}
-	dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
-	if (dev) {
-		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-		if (!node)
-			return NULL;
-		strcpy(node->dev_name, dev->name);
-		node->major = node->minor = 0;
-		node->next = NULL;
-		MOD_INC_USE_COUNT;
-		return node;
-	}
-	return NULL;
-}
-
-static void vortex_detach(dev_node_t *node)
-{
-	struct device **devp, **next;
-	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
-	for (devp = &root_vortex_dev; *devp; devp = next) {
-		next = &((struct vortex_private *)(*devp)->priv)->next_module;
-		if (strcmp((*devp)->name, node->dev_name) == 0) break;
-	}
-	if (*devp) {
-		struct device *dev = *devp;
-		struct vortex_private *vp = dev->priv;
-		if (dev->flags & IFF_UP)
-			vortex_close(dev);
-		dev->flags &= ~(IFF_UP|IFF_RUNNING);
-		unregister_netdev(dev);
-		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
-		kfree(dev);
-		*devp = *next;
-		kfree(vp);
-		kfree(node);
-		MOD_DEC_USE_COUNT;
-	}
-}
-
-struct driver_operations vortex_ops = {
-	"3c575_cb", vortex_attach, NULL, NULL, vortex_detach
-};
-
-#endif  /* Cardbus support */
-
 
 int init_module(void)
 {
 	if (vortex_debug)
 		printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
-	register_driver(&vortex_ops);
-	return 0;
-#else
 	return vortex_scan(0, pci_tbl);
-#endif
 }
 
 #else
@@ -713,7 +622,30 @@
 }
 #endif  /* not MODULE */
 
-#ifndef CARDBUS
+static void wait_for_completion(struct device *dev, int cmd)
+{
+	int i;
+
+	outw(cmd, dev->base_addr + EL3_CMD);
+	for (i = 0; i < 2000; i++) {
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+			return;
+	}
+
+	/* OK, that didn't work.  Do it the slow way.  One second */
+	for (i = 0; i < 100000; i++) {
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) {
+			if (vortex_debug > 1)
+				printk(KERN_INFO "%s: command 0x%04x took %d usecs!\n",
+					   dev->name, cmd, i * 10);
+			return;
+		}
+		udelay(10);
+	}
+	printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+			   dev->name, cmd, inw(dev->base_addr + EL3_STATUS));
+}
+
 static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
 {
 	int cards_found = 0;
@@ -734,8 +666,7 @@
 			long ioaddr;
 
 			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-									&pci_bus, &pci_device_fn)
-				!= PCIBIOS_SUCCESSFUL)
+									&pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
 				break;
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_VENDOR_ID, &vendor);
@@ -749,21 +680,13 @@
 			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
 				continue;
 
+			/* The Cyclone requires config space re-write if powered down. */
+			acpi_wake(pci_bus, pci_device_fn);
+
 			{
-#if LINUX_VERSION_CODE >= 0x20155
 				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
 				ioaddr = pdev->base_address[0] & ~3;
 				irq = pdev->irq;
-#else
-				u32 pci_ioaddr;
-				u8 pci_irq_line;
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq_line);
-				pcibios_read_config_dword(pci_bus, pci_device_fn,
-										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-				ioaddr = pci_ioaddr & ~3;;
-				irq = pci_irq_line;
-#endif
 			}
 
 			/* Power-up the card. */
@@ -811,21 +734,21 @@
 								chip_idx, cards_found);
 
 			if (dev) {
-				/* Get and check the latency values.  On the 3c590 series
-				   the latency timer must be set to the maximum value to avoid
-				   data corruption that occurs when the timer expires during
-				   a transfer -- a bug in the Vortex chip only. */
-				u8 pci_latency;
-				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-				
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency < new_latency) {
-					printk(KERN_INFO "%s: Overriding PCI latency"
-						   " timer (CFLT) setting of %d, new value is %d.\n",
-						   dev->name, pci_latency, new_latency);
-					pcibios_write_config_byte(pci_bus, pci_device_fn,
-											  PCI_LATENCY_TIMER, new_latency);
+				if ((device & 0xff00) == 0x5900) {
+					/* Get and check the latency values.  On the 3c590 series
+					   the latency timer must be set to the maximum value to avoid
+					   data corruption that occurs when the timer expires during
+					   a transfer -- a bug in the Vortex chip only. */
+					u8 pci_latency;
+					u8 new_latency = 248;
+					
+					pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency);
+					if (pci_latency < new_latency) {
+						printk(KERN_INFO "%s: Overriding PCI latency"
+							   " timer (CFLT) setting of %d, new value is %d.\n",
+							   dev->name, pci_latency, new_latency);
+						pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, new_latency);
+					}
 				}
 				dev = 0;
 				cards_found++;
@@ -866,7 +789,6 @@
 
 	return cards_found ? 0 : -ENODEV;
 }
-#endif  /* ! Cardbus */
 
 static struct device *vortex_probe1(int pci_bus, int pci_devfn,
 									struct device *dev, long ioaddr,
@@ -878,6 +800,10 @@
 	int i;
 
 	dev = init_etherdev(dev, 0);
+	if (dev == NULL) {
+		printk(KERN_EMERG "3c59x: init_etherdev failed\n");
+		return NULL;
+	}
 
 	printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
 		   dev->name, pci_tbl[chip_idx].name, ioaddr);
@@ -889,12 +815,16 @@
 	/* Make certain the descriptor lists are aligned. */
 	{
 		void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
-		if (!mem)
+		if (!mem) {
+			printk(KERN_EMERG "3c59x: out of memory for dev->priv\n");
+			unregister_netdev(dev);
+			kfree(dev);
 			return NULL;
+		}
 		vp =  (void *)(((long)mem + 15) & ~15);
+		memset(vp, 0, sizeof(*vp));
 		vp->priv_addr = mem;
 	}
-	memset(vp, 0, sizeof(*vp));
 	dev->priv = vp;
 
 	vp->next_module = root_vortex_dev;
@@ -906,51 +836,68 @@
 	vp->pci_devfn = pci_devfn;
 
 	/* The lower four bits are the media type. */
+	option = -1;
 	if (dev->mem_start)
 		option = dev->mem_start;
 	else if (card_idx < MAX_UNITS)
 		option = options[card_idx];
-	else
-		option = -1;
 
 	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 7;
-		vp->full_duplex = (option & 8) ? 1 : 0;
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		if (vp->media_override != 7)
+			vp->medialock = 1;
+		if (option & 0x200) {
+			vp->full_duplex = 1;
+			vp->duplexlock = 1;
+			printk(	"\n" KERN_WARNING
+					"%s: forcing duplex via options is deprecated - use `full_duplex'.\n",
+					dev->name);
+		}
 		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
 		vp->full_duplex = 0;
 		vp->bus_master = 0;
 	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		vp->full_duplex = 1;
-
-	vp->force_fd = vp->full_duplex;
+	if (card_idx < MAX_UNITS) {
+		if (enable_wol[card_idx] > 0)
+			vp->enable_wol = 1;
+		if (full_duplex[card_idx] == 0) {	/* full_duplex=0 : force half duplex */
+			vp->duplexlock = 1;
+		}
+		if (full_duplex[card_idx] > 0) {	/* full_duplex=1: force full duplex */
+			vp->duplexlock = 1;
+			vp->full_duplex = 1;
+		}
+		/* full_duplex=-1: duplex is not forced */
+	}
 	vp->options = option;
 
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 0x40; i++) {
-		int timer;
-#ifdef CARDBUS
-		outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
-		if (pci_tbl[chip_idx].device_id == 0x6055) {
-			outw(0x230 + i, ioaddr + Wn0EepromCmd);
-		} else if (pci_tbl[chip_idx].device_id == 0x6056) {
-			outw(EEPROM_Read + 0x30 + i, ioaddr + Wn0EepromCmd);
-		} else {
-			outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-		}
-#endif
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 10; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-				break;
+	{
+		int base;
+
+		if (pci_tbl[chip_idx].drv_flags & EEPROM_8BIT)
+			base = 0x230;
+		else if (pci_tbl[chip_idx].drv_flags & EEPROM_OFFSET)
+			base = EEPROM_Read + 0x30;
+		else
+			base = EEPROM_Read;
+
+		for (i = 0; i < 0x40; i++) {
+			int timer;
+			outw(base + i, ioaddr + Wn0EepromCmd);
+			/* Pause for at least 162 us. for the read to take place. */
+			for (timer = 10; timer >= 0; timer--) {
+				udelay(162);
+				if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+					break;
+			}
+			eeprom[i] = inw(ioaddr + Wn0EepromData);
 		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
 	}
+
 	for (i = 0; i < 0x18; i++)
 		checksum ^= eeprom[i];
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
@@ -978,6 +925,7 @@
 
 	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
 		u32 fn_st_addr;			/* Cardbus function status space */
+		u16 n;
 		pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
 								  &fn_st_addr);
 		if (fn_st_addr)
@@ -985,11 +933,12 @@
 		printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
 			   " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
-		if (pci_tbl[chip_idx].device_id == 0x6055) {
-			outw(0x4010 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
-		} else {
-			outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
-		}
+
+		n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
+		n |= 0x10;
+		if (pci_tbl[chip_idx].drv_flags & INVERT_MII_PWR)
+			n |= 0x4000;
+		outw(n, ioaddr + Wn2_ResetOptions);
 	}
 
 	/* Extract our information from the EEPROM data. */
@@ -997,7 +946,7 @@
 	vp->info2 = eeprom[15];
 	vp->capabilities = eeprom[16];
 
-	if (vp->info1 & 0x8000)
+	if (!vp->duplexlock && (vp->info1 & 0x8000))
 		vp->full_duplex = 1;
 
 	{
@@ -1035,8 +984,19 @@
 		mii_preamble_required++;
 		mii_preamble_required++;
 		mdio_read(ioaddr, 24, 1);
-		for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
-			int mii_status, phyx = phy & 0x1f;
+		for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
+			int mii_status, phyx;
+
+			/*
+			 * For the 3c905CX we look at index 24 first, because it bogusly
+			 * reports an external PHY at all indices
+			 */
+			if (phy == 0)
+				phyx = 24;
+			else if (phy <= 24)
+				phyx = phy - 1;
+			else
+				phyx = phy;
 			mii_status = mdio_read(ioaddr, phyx, 1);
 			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phyx;
@@ -1060,6 +1020,9 @@
 		}
 	}
 
+	if (vp->enable_wol && (vp->capabilities & CapPwrMgmt))
+		acpi_set_WOL(dev);
+
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
 		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
@@ -1093,6 +1056,9 @@
 
 	MOD_INC_USE_COUNT;
 
+	if (vp->enable_wol)
+		acpi_wake(vp->pci_bus, vp->pci_devfn);
+
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
 	config = inl(ioaddr + Wn3_Config);
@@ -1104,7 +1070,9 @@
 				   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
 	} else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
-			dev->if_port = XCVR_NWAY;
+		if (vortex_debug > 1)
+			printk(KERN_INFO "%s: using NWAY from config\n", dev->name);
+		dev->if_port = XCVR_NWAY;
 	} else if (vp->autoselect) {
 		/* Find first available media type, starting with 100baseTx. */
 		dev->if_port = XCVR_100baseTx;
@@ -1113,11 +1081,11 @@
 	} else
 		dev->if_port = vp->default_media;
 
-	if (vortex_debug > 1)
-		printk(KERN_DEBUG "%s: Initial media type %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
+	printk(KERN_INFO "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name);
+
+	if (!vp->duplexlock && (vp->info1 & 0x8000))
+		vp->full_duplex = 1;
 
-	vp->full_duplex = vp->force_fd;
 	config = BFINS(config, dev->if_port, 20, 4);
 	outl(config, ioaddr + Wn3_Config);
 
@@ -1129,35 +1097,25 @@
 		mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
 		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
 			;					/* No MII device or no link partner report */
-		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
-				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+		else if (!vp->duplexlock &&
+				((mii_reg5 & 0x0100) != 0			/* 100baseTx-FD */
+				|| (mii_reg5 & 0x00C0) == 0x0040))		/* 10T-FD, but not 100-HD */
 			vp->full_duplex = 1;
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-				   " setting %s-duplex.\n", dev->name, vp->phys[0],
-				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+		printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
+			   " setting %s-duplex.\n", dev->name, vp->phys[0],
+			   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
 		EL3WINDOW(3);
 	}
 
 	/* Set the full-duplex bit. */
-	outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+	outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
 
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
-			dev->name, config);
+		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", dev->name, config);
 	}
 
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(RxReset, ioaddr + EL3_CMD);
-	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
 
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
@@ -1224,18 +1182,15 @@
 			if (skb == NULL)
 				break;			/* Bad news!  */
 			skb->dev = dev;			/* Mark as being used by this device. */
-#if LINUX_VERSION_CODE >= 0x10300
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
-#else
-			vp->rx_ring[i].addr = virt_to_bus(skb->data);
-#endif
 		}
 		if (i != RX_RING_SIZE) {
 			int j;
-			for (j = 0; j < RX_RING_SIZE; j++) {
+			printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name);
+			for (j = 0; j < i; j++) {
 				if (vp->rx_skbuff[j])
-					DEV_FREE_SKB(vp->rx_skbuff[j]);
+					dev_kfree_skb(vp->rx_skbuff[j]);
 			}
 			retval = -ENOMEM;
 			goto out_free_irq;
@@ -1285,6 +1240,10 @@
 	vp->timer.function = &vortex_timer;		/* timer handler */
 	add_timer(&vp->timer);
 
+	init_timer(&vp->rx_oom_timer);
+	vp->rx_oom_timer.data = (unsigned long)dev;
+	vp->rx_oom_timer.function = rx_oom_timer;
+
 	return 0;
 
 out_free_irq:
@@ -1306,6 +1265,8 @@
 		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
+	if (vp->medialock)
+		goto leave_media_alone;
 	disable_irq(dev->irq);
 	old_window = inw(ioaddr + EL3_CMD) >> 13;
 	EL3WINDOW(4);
@@ -1332,7 +1293,7 @@
 					 dev->name, mii_status);
 		  if (mii_status & 0x0004) {
 			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
+			  if (!vp->duplexlock && mii_reg5 != 0xffff) {
 				  int duplex = (mii_reg5&0x0100) ||
 					  (mii_reg5 & 0x01C0) == 0x0040;
 				  if (vp->full_duplex != duplex) {
@@ -1342,7 +1303,7 @@
 							 dev->name, vp->full_duplex ? "full" : "half",
 							 vp->phys[0], mii_reg5);
 					  /* Set the full-duplex bit. */
-					  EL3WINDOW(3);   /* AKPM */
+					  EL3WINDOW(3);
 					  outb((vp->full_duplex ? 0x20 : 0) |
 						   (dev->mtu > 1500 ? 0x40 : 0),
 						   ioaddr + Wn3_MAC_Ctrl);
@@ -1392,6 +1353,7 @@
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
 
+leave_media_alone:
 	if (vortex_debug > 2)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
@@ -1407,7 +1369,6 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int j;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, inb(ioaddr + TxStatus),
@@ -1435,12 +1396,7 @@
 			__restore_flags(flags);
 		}
 	}
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (j = 200; j >= 0 ; j--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
 
-#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300
 	if (vp->full_bus_master_tx) {
 		int i;
 		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
@@ -1456,7 +1412,7 @@
 				   le32_to_cpu(vp->tx_ring[i].status));
 		}
 	}
-#endif
+	wait_for_completion(dev, TxReset);
 	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
 		if (vortex_debug > 0)
@@ -1494,7 +1450,6 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
-	int i;
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
 		unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1545,20 +1500,14 @@
 				   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
 		if (vp->full_bus_master_tx) {
-			outw(TotalReset | 0xff, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, TotalReset|0xff);
 			/* Re-enable the receiver. */
 			outw(RxEnable, ioaddr + EL3_CMD);
 			outw(TxEnable, ioaddr + EL3_CMD);
 		} else if (fifo_diag & 0x0400)
 			do_tx_reset = 1;
 		if (fifo_diag & 0x3000) {
-			outw(RxReset, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, RxReset);
 			/* Set the Rx filter to the current state. */
 			set_rx_mode(dev);
 			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1566,11 +1515,7 @@
 		}
 	}
 	if (do_tx_reset) {
-		int j;
-		outw(TxReset, ioaddr + EL3_CMD);
-		for (j = 4000; j >= 0 ; j--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, TxReset);
 		outw(TxEnable, ioaddr + EL3_CMD);
 		if (!vp->full_bus_master_tx) {
 			clear_bit(0, (void*)&dev->tbusy);
@@ -1580,7 +1525,6 @@
 
 }
 
-
 static int
 vortex_start_xmit(struct sk_buff *skb, struct device *dev)
 {
@@ -1609,7 +1553,7 @@
 #else
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
-		DEV_FREE_SKB(skb);
+		dev_kfree_skb(skb);
 		if (inw(ioaddr + TxFree) > 1536) {
 			clear_bit(0, (void*)&dev->tbusy);
 		} else
@@ -1631,13 +1575,8 @@
 						 dev->name, tx_status);
 				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
-				if (tx_status & 0x30) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 200; j >= 0 ; j--)
-						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
-				}
+				if (tx_status & 0x30)
+					wait_for_completion(dev, TxReset);
 				outw(TxEnable, ioaddr + EL3_CMD);
 			}
 			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
@@ -1663,7 +1602,6 @@
 		struct boom_tx_desc *prev_entry =
 			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
 		unsigned long flags;
-		int i;
 
 		if (vortex_debug > 3)
 			printk(KERN_DEBUG "%s: Trying to send a boomerang packet, Tx index %d.\n",
@@ -1681,11 +1619,7 @@
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
 		spin_lock_irqsave(&vp->lock, flags);
-		outw(DownStall, ioaddr + EL3_CMD);
-		/* Wait for the stall to complete. */
-		for (i = 4000; i >= 0; i--)
-			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
-				break;
+		wait_for_completion(dev, DownStall);
 		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
 		if (inl(ioaddr + DownListPtr) == 0) {
 			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
@@ -1761,7 +1695,7 @@
 		if (status & DMADone) {
 			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
 				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
+				dev_kfree_skb(vp->tx_skb); /* Release the transfered buffer */
 				if (inw(ioaddr + TxFree) > 1536) {
 					clear_bit(0, (void*)&dev->tbusy);
 					mark_bh(NET_BH);
@@ -1854,7 +1788,7 @@
 					virt_to_bus(&vp->tx_ring[entry]))
 					break;			/* It still hasn't been processed. */
 				if (vp->tx_skbuff[entry]) {
-					DEV_FREE_SKB(vp->tx_skbuff[entry]);
+					dev_kfree_skb(vp->tx_skbuff[entry]);
 					vp->tx_skbuff[entry] = 0;
 				}
 				/* vp->stats.tx_packets++;  Counted below. */
@@ -1898,14 +1832,6 @@
 
 	} while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch);
 
-	/*
-	 * If we have totally run out to rx skb's due to persistent OOM,
-	 * we can use the Tx interrupt to retry the allocation.  Dirty
-	 * but expedient
-	 */
-	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
-		boomerang_rx(dev);
-
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
@@ -1980,12 +1906,8 @@
 				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
 					   "size %d.\n", dev->name, pkt_len);
 		}
-		outw(RxDiscard, ioaddr + EL3_CMD);
 		vp->stats.rx_dropped++;
-		/* Wait a limited time to skip this packet. */
-		for (i = 200; i >= 0; i--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, RxDiscard);
 	}
 
 	return 0;
@@ -2074,8 +1996,16 @@
 		entry = vp->dirty_rx % RX_RING_SIZE;
 		if (vp->rx_skbuff[entry] == NULL) {
 			skb = dev_alloc_skb(PKT_BUF_SZ);
-			if (skb == NULL)
+			if (skb == NULL) {
+				static unsigned long last_jif;
+				if ((jiffies - last_jif) > 10 * HZ) {
+					printk(KERN_WARNING "%s: memory shortage\n", dev->name);
+					last_jif = jiffies;
+				}
+				if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
+					mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1));
 				break;			/* Bad news!  */
+			}
 			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
@@ -2087,6 +2017,26 @@
 	return 0;
 }
 
+/*
+ * If we've hit a total OOM refilling the Rx ring we poll once a second
+ * for some memory.  Otherwise there is no way to restart the rx process.
+ */
+static void
+rx_oom_timer(unsigned long arg)
+{
+	struct device *dev = (struct device *)arg;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+
+	spin_lock_irq(&vp->lock);
+	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)	/* This test is redundant, but makes me feel good */
+		boomerang_rx(dev);
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name,
+			((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying");
+	}
+	spin_unlock_irq(&vp->lock);
+}
+
 static int
 vortex_close(struct device *dev)
 {
@@ -2106,6 +2056,7 @@
 	}
 
 	del_timer(&vp->timer);
+	del_timer(&vp->rx_oom_timer);
 
 	/* Turn off statistics ASAP.  We update vp->stats below. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
@@ -2127,10 +2078,7 @@
 		outl(0, ioaddr + UpListPtr);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-#if LINUX_VERSION_CODE < 0x20100
-				vp->rx_skbuff[i]->free = 1;
-#endif
-				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				dev_kfree_skb(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
@@ -2138,11 +2086,13 @@
 		outl(0, ioaddr + DownListPtr);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
-				DEV_FREE_SKB(vp->tx_skbuff[i]);
+				dev_kfree_skb(vp->tx_skbuff[i]);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
 
+	if (vp->enable_wol && (vp->capabilities & CapPwrMgmt))
+		acpi_set_WOL(dev);
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -2219,7 +2169,7 @@
 		retval = 0;
 		break;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser()) {
+		if (!capable(CAP_NET_ADMIN)) {
 			retval = -EPERM;
 		} else {
 			EL3WINDOW(4);
@@ -2349,22 +2299,66 @@
 	return;
 }
 
+/* ACPI: Advanced Configuration and Power Interface. */
+/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
+static void acpi_set_WOL(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+	EL3WINDOW(7);
+	outw(2, ioaddr + 0x0c);
+	/* The RxFilter must accept the WOL frames. */
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	outw(RxEnable, ioaddr + EL3_CMD);
+	/* Change the power state to D3; RxEnable doesn't take effect. */
+	pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
+}
+
+/* Change from D3 (sleep) to D0 (active).
+   Problem: The Cyclone forgets all PCI config info during the transition! */
+static void acpi_wake(int bus, int devfn)
+{
+	u32 base0, base1, romaddr;
+	u16 pci_command, pwr_command;
+	u8  pci_latency, pci_cacheline, irq;
+
+	pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
+	if ((pwr_command & 3) == 0)
+		return;
+	pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
+	pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
+	pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
+	pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
+
+	pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
+	pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
+	pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
+	pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
+	pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
+	pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
+}
+
 
 #ifdef MODULE
 void cleanup_module(void)
 {
 	struct device *next_dev;
 
-#ifdef CARDBUS
-	unregister_driver(&vortex_ops);
-#endif
-
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_vortex_dev) {
 		struct vortex_private *vp=(void *)(root_vortex_dev->priv);
+		int drv_flags = pci_tbl[vp->chip_id].drv_flags;
 		next_dev = vp->next_module;
 		unregister_netdev(root_vortex_dev);
-		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
+		outw((drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset,
+				root_vortex_dev->base_addr + EL3_CMD);
 		release_region(root_vortex_dev->base_addr,
 					   pci_tbl[vp->chip_id].io_size);
 		kfree(root_vortex_dev);
@@ -2377,9 +2371,6 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -urN linux-2.2.19-pre13/drivers/net/8139too.c linux/drivers/net/8139too.c
--- linux-2.2.19-pre13/drivers/net/8139too.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/net/8139too.c	Mon Dec  3 21:07:26 2001
@@ -5,12 +5,12 @@
  	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
  
  	Much code comes from Donald Becker's rtl8139.c driver,
- 	versions 1.11 and older.  This driver was originally based
- 	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.11:
+ 	versions 1.13 and older.  This driver was originally based
+ 	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.13:
  
  	-----<snip>-----
  
-         	Written 1997-2000 by Donald Becker.
+         	Written 1997-2001 by Donald Becker.
  		This software may be used and distributed according to the
  		terms of the GNU General Public License (GPL), incorporated
  		herein by reference.  Drivers based on or derived from this
@@ -74,6 +74,9 @@
 		
 		Tobias Ringström - Rx interrupt status checking suggestion
 
+		Andrew Morton - Clear blocked signals, avoid
+		buffer overrun setting current->comm.
+
 	Submitting bug reports:
 
 		"rtl8139-diag -mmmaaavvveefN" output
@@ -147,7 +150,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.12-2.2"
+#define RTL8139_VERSION "0.9.14-2.2"
 #define MODNAME "8139too"
 #define RTL8139_DRIVER_NAME   MODNAME " FastEthernet driver " RTL8139_VERSION
 #define RTL8139_AUTHOR "Jeff Garzik <jgarzik@mandrakesoft.com>"
@@ -283,7 +286,9 @@
 
 /* A few user-configurable values. */
 /* media options */
-static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -325,6 +330,7 @@
 
 
 enum {
+	HAS_MII_XCVR = 0x010000,
 	HAS_CHIP_XCVR = 0x020000,
 	HAS_LNK_CHNG = 0x040000,
 };
@@ -332,26 +338,34 @@
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8139B_IO_SIZE 256
 
+#define RTL8129_CAPS	HAS_MII_XCVR
 #define RTL8139_CAPS	HAS_CHIP_XCVR|HAS_LNK_CHNG
 
 typedef enum {
 	RTL8139 = 0,
 	RTL8139_CB,
 	SMC1211TX,
+	/*MPX5030,*/
 	DELTA8139,
 	ADDTRON8139,
+	DFE538TX,
+	RTL8129,
 } board_t;
 
 
 /* indexed by board_t, above */
 static struct {
 	const char *name;
+	u32 hw_flags;
 } board_info[] = {
-	{ "RealTek RTL8139 Fast Ethernet" },
-	{ "RealTek RTL8139B PCI/CardBus" },
-	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
-	{ "Delta Electronics 8139 10/100BaseTX" },
-	{ "Addtron Technolgy 8139 10/100BaseTX" },
+	{ "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS },
+	{ "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS },
+	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS },
+/*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/
+	{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "RealTek RTL8129", RTL8129_CAPS },
 };
 
 struct pci_device_id {
@@ -363,8 +377,11 @@
 	{0x10ec, 0x8139, RTL8139 },
 	{0x10ec, 0x8138, RTL8139_CB },
 	{0x1113, 0x1211, SMC1211TX },
+/*	{0x1113, 0x1211, MPX5030 },*/
 	{0x1500, 0x1360, DELTA8139 },
 	{0x4033, 0x1360, ADDTRON8139 },
+	{0x1186, 0x1300, DFE538TX },
+	{0x10ec, 0x8129, RTL8129 },
 	{0,}
 };
 
@@ -601,7 +618,6 @@
 
 
 struct rtl8139_private {
-	board_t board;
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
@@ -610,8 +626,8 @@
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
 	unsigned int tx_flag;
-	unsigned int cur_tx;
-	unsigned int dirty_tx;
+	unsigned long cur_tx;
+	unsigned long dirty_tx;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct ring_info tx_info[NUM_TX_DESC];
 	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
@@ -619,6 +635,7 @@
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_bufs_dma;
 	char phys[4];		/* MII device addresses. */
+	u16 advertising;					/* NWay media advertisement */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
@@ -841,14 +858,6 @@
 		RTL_W8 (Config1, 0);
 	}
 
-#ifndef USE_IO_OPS
-	/* sanity checks -- ensure PIO and MMIO registers agree */
-	assert (inb (pio_start+Config0) == readb (ioaddr+Config0));
-	assert (inb (pio_start+Config1) == readb (ioaddr+Config1));
-	assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));
-	assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
-#endif /* !USE_IO_OPS */
-
 	/* make sure chip thinks PIO and MMIO are enabled */
 	tmp8 = RTL_R8 (Config1);
 	if ((tmp8 & Cfg1_PIO) == 0) {
@@ -949,17 +958,13 @@
 	tp = dev->priv;
 
 	/* note: tp->chipset set in rtl8139_init_board */
-	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER | RTL8139_CAPS;
+	tp->drv_flags = board_info[ent->board].hw_flags;
 	tp->pci_dev = pdev;
-	tp->board = ent->board;
 	tp->mmio_addr = ioaddr;
 	spin_lock_init (&tp->lock);
 	init_waitqueue_head (&tp->thr_wait);
 	init_MUTEX_LOCKED (&tp->thr_exited);
 
-	tp->phys[0] = 32;
-
 	if (rtl8139_device_count == 0) {
 		printk (KERN_INFO "%s: " RTL8139_DRIVER_NAME " " RTL8139_AUTHOR "\n", dev->name);
 		printk (KERN_INFO "%s: Linux-2.2 bug reports to Jens David <dg1kjd@afthd.tu-darmstadt.de>\n", dev->name);
@@ -976,6 +981,30 @@
 		dev->dev_addr[2], dev->dev_addr[3],
 		dev->dev_addr[4], dev->dev_addr[5]);
 
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	if (tp->drv_flags & HAS_MII_XCVR) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				tp->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+					   "advertising %4.4x.\n",
+					   dev->name, phy, mii_status, tp->advertising);
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = 32;
+		}
+	} else
+		tp->phys[0] = 32;
+
 	/* Put the chip into low-power mode. */
 	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 
@@ -986,21 +1015,29 @@
 	RTL_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
 
 	/* The lower four bits are the media type. */
-	option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx];
+	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
 	if (option > 0) {
-		tp->full_duplex = (option & 0x200) ? 1 : 0;
-		tp->default_port = option & 15;
+		tp->full_duplex = (option & 0x210) ? 1 : 0;
+		tp->default_port = option & 0xFF;
 		if (tp->default_port)
 			tp->medialock = 1;
 	}
-
+	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
+		tp->full_duplex = full_duplex[board_idx];
 	if (tp->full_duplex) {
-		printk (KERN_INFO
-			"%s: Media type forced to Full Duplex.\n",
-			dev->name);
-		mdio_write (dev, tp->phys[0], 4, 0x141);
+		printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		/* Changing the MII-advertised media because might prevent
+		   re-connection. */
 		tp->duplex_lock = 1;
 	}
+	if (tp->default_port) {
+		printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
+			   (option & 0x20 ? 100 : 10),
+			   (option & 0x10 ? "full" : "half"));
+		mdio_write(dev, tp->phys[0], 0,
+				   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+	}
 
 	rtl8139_device_tab[rtl8139_device_count++] = dev;
 	
@@ -1120,7 +1157,7 @@
 #define MDIO_WRITE0 (MDIO_DIR)
 #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
 
-#define mdio_delay()	readb(mdio_addr)
+#define mdio_delay(mdio_addr)	readb(mdio_addr)
 
 
 static char mii_2_8139_map[8] = {
@@ -1144,9 +1181,9 @@
 
 	for (i = 32; i >= 0; i--) {
 		writeb (MDIO_WRITE1, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -1174,20 +1211,18 @@
 		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
 
 		writeb (MDIO_DIR | dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	/* Read the two transition, 16 data, and wire-idle bits. */
 	for (i = 19; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
-		retval =
-		    (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
-				     : 0);
+		mdio_delay (mdio_addr);
+		retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
@@ -1200,19 +1235,19 @@
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
-	int mii_cmd =
-	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
 	int i;
 
 	DPRINTK ("ENTER\n");
 
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		if (location < 8 && mii_2_8139_map[location]) {
-			writew (value,
-				tp->mmio_addr + mii_2_8139_map[location]);
-			readw (tp->mmio_addr + mii_2_8139_map[location]);
-		}
-		DPRINTK ("EXIT after directly using 8139 internal regs\n");
+		void *ioaddr = tp->mmio_addr;
+		if (location == 0) {
+			RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+			RTL_W16_F (BasicModeCtrl, value);
+			RTL_W8_F (Cfg9346, Cfg9346_Lock);
+		} else if (location < 8 && mii_2_8139_map[location])
+			RTL_W16_F (mii_2_8139_map[location], value);
 		return;
 	}
 	mdio_sync (mdio_addr);
@@ -1222,20 +1257,19 @@
 		int dataval =
 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
 		writeb (dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	/* Clear out extra bits. */
 	for (i = 2; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
-
-	DPRINTK ("EXIT\n");
+	return;
 }
 
 
@@ -1249,9 +1283,12 @@
 
 	DPRINTK ("ENTER\n");
 
+	MOD_INC_USE_COUNT;
+
 	retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
 	if (retval) {
 		DPRINTK ("EXIT, returning %d\n", retval);
+		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -1267,6 +1304,7 @@
 		if (tp->rx_ring) kfree(tp->rx_ring);
 
 		DPRINTK ("EXIT, returning -ENOMEM\n");
+		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 
 	}
@@ -1313,6 +1351,8 @@
 		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
 			break;
 
+	/* unlock Config[01234] and BMCR register writes */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 	/* Restore our idea of the MAC address. */
 	RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
 	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
@@ -1328,12 +1368,23 @@
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
-	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
-	udelay (10);
-
 	tp->cur_rx = 0;
 
+	/* This is check_duplex() */
+	if (tp->phys[0] >= 0  ||  (tp->drv_flags & HAS_MII_XCVR)) {
+		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			tp->full_duplex = 1;
+		printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+			   " auto-negotiated partner ability %4.4x.\n", dev->name,
+			   mii_reg5 == 0 ? "" :
+			   (mii_reg5 & 0x0180) ? "100Mbps " : "10Mbps ",
+			   tp->full_duplex ? "full" : "half", mii_reg5);
+	}
+
 	if (tp->chipset >= CH_8139A) {
 		tmp = RTL_R8 (Config1) & Config1Clear;
 		tmp |= Cfg1_Driver_Load;
@@ -1536,7 +1587,7 @@
 	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
 		 dev->name, RTL_R16 (NWayLPAR));
 	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
-		 " RxStatus %4.4x.\n", dev->name,
+		 " RxStatus %4.4lx.\n", dev->name,
 		 RTL_R16 (IntrMask),
 		 RTL_R16 (IntrStatus),
 		 RTL_R32 (RxEarlyStatus));
@@ -1553,7 +1604,13 @@
 	unsigned long timeout;
 
 	daemonize ();
-	sprintf (current->comm, "k8139d-%s", dev->name);
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+	current->comm[sizeof(current->comm) - 1] = '\0';
 
 	while (1) {
 		timeout = next_tick;
@@ -1615,7 +1672,7 @@
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Emit info to figure out what went wrong. */
-        printk (KERN_DEBUG "%s: Tx queue start entry %d  dirty entry %d.\n",
+        printk (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\n",
 		dev->name, tp->cur_tx, tp->dirty_tx);
 	for (i = 0; i < NUM_TX_DESC; i++)
 		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8lx.%s\n",
@@ -1665,11 +1722,15 @@
 		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	dev->trans_start = jiffies;
+
+	spin_lock_irq (&tp->lock);
+
 	tp->cur_tx++;
-	mb();
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
 
+	spin_unlock_irq (&tp->lock);
+
 	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
 		 dev->name, skb->data, skb->len, entry);
 
@@ -1681,7 +1742,7 @@
 					 struct rtl8139_private *tp,
 					 void *ioaddr)
 {
-	unsigned int dirty_tx, tx_left;
+	unsigned long dirty_tx, tx_left;
 
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -1736,8 +1797,7 @@
 
 #ifndef RTL8139_NDEBUG
 	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR
-		  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
+		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
 		     dev->name, dirty_tx, tp->cur_tx);
 		dirty_tx += NUM_TX_DESC;
 	}
@@ -1746,7 +1806,6 @@
 	/* only wake the queue if we did work, and the queue is stopped */
 	if (tp->dirty_tx != dirty_tx) {
 		tp->dirty_tx = dirty_tx;
-		mb();
 		if (netif_queue_stopped (dev))
 			netif_wake_queue (dev);
 	}
@@ -1979,8 +2038,6 @@
 	void *ioaddr = tp->mmio_addr;
 	int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
 
-	spin_lock (&tp->lock);
-
 	do {
 		status = RTL_R16 (IntrStatus);
 
@@ -2031,8 +2088,11 @@
 		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
 			rtl8139_rx_interrupt (dev, tp, ioaddr);
 
-		if (status & (TxOK | TxErr))
+		if (status & (TxOK | TxErr)) {
+			spin_lock (&tp->lock);
 			rtl8139_tx_interrupt (dev, tp, ioaddr);
+			spin_unlock (&tp->lock);
+		}
 
 		boguscnt--;
 	} while (boguscnt > 0);
@@ -2047,8 +2107,6 @@
 		RTL_W16 (IntrStatus, 0xffff);
 	}
 
-	spin_unlock (&tp->lock);
-
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
 }
@@ -2121,6 +2179,8 @@
 	RTL_W8 (Config1, 0x03);
 	RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
 
+	MOD_DEC_USE_COUNT;
+
 	DPRINTK ("EXIT\n");
 	return 0;
 }
@@ -2149,8 +2209,20 @@
 			break;
 		}
 
-		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
-		break;
+		if (data[0] == tp->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				/* Check for autonegotiation on or reset. */
+				tp->medialock = (value & 0x9000) ? 0 : 1;
+				if (tp->medialock)
+					tp->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4: tp->advertising = value; break;
+			}
+		}
+		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
+  		break;
 
 	default:
 		rc = -EOPNOTSUPP;
@@ -2170,8 +2242,10 @@
 	DPRINTK ("ENTER\n");
 
 	if (netif_running(dev)) {
+		spin_lock_irq(&tp->lock);
 		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 		RTL_W32 (RxMissed, 0);
+		spin_unlock_irq(&tp->lock);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -2194,8 +2268,7 @@
 		unsigned char current_octet = *data++;
 		int bit;
 		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ?
+			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
 			     ethernet_polynomial : 0);
 	}
 
@@ -2208,13 +2281,14 @@
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
 
 	DPRINTK ("ENTER\n");
 
-	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
 			dev->name, dev->flags, RTL_R32 (RxConfig));
 
 	/* Note: do not reorder, GCC is clever about common statements. */
@@ -2241,7 +2315,7 @@
 				 mc_filter);
 	}
 
-	spin_lock_irq (&tp->lock);
+	spin_lock_irqsave (&tp->lock, flags);
 
 	/* We can safely update without stopping the chip. */
 	tmp = rtl8139_rx_config | rx_mode |
@@ -2250,7 +2324,7 @@
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
-	spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	DPRINTK ("EXIT\n");
 }
@@ -2291,7 +2365,8 @@
 MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
-MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 int init_module(void)
 {
diff -urN linux-2.2.19-pre13/drivers/net/slhc.c linux/drivers/net/slhc.c
--- linux-2.2.19-pre13/drivers/net/slhc.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/slhc.c	Mon Dec  3 21:07:26 2001
@@ -82,8 +82,6 @@
 #include <net/checksum.h>
 #include <asm/unaligned.h>
 
-int last_retran;
-
 static unsigned char *encode(unsigned char *cp, unsigned short n);
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
@@ -257,8 +255,7 @@
 	ip = (struct iphdr *) icp;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
-	if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
-				       (ip->frag_off & 32)){
+	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
 		/* Send as regular IP */
 		if(ip->protocol != IPPROTO_TCP)
 			comp->sls_o_nontcp++;
@@ -352,10 +349,9 @@
 	 */
 	oth = &cs->cs_tcp;
 
-	if(last_retran
-	 || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
+	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
 	 || ip->tos != cs->cs_ip.tos
-	 || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
+	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
 	 || ip->ttl != cs->cs_ip.ttl
 	 || th->doff != cs->cs_tcp.doff
 	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
diff -urN linux-2.2.19-pre13/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- linux-2.2.19-pre13/drivers/net/sunhme.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/sunhme.c	Mon Dec  3 21:07:26 2001
@@ -3523,6 +3523,7 @@
 	struct linux_sbus_device *sdev = 0;
 	static int called = 0;
 	int cards = 0, v;
+	char model[128];
 
 	if(called)
 		return ENODEV;
@@ -3534,7 +3535,13 @@
 				dev = NULL;
 			if(!strcmp(sdev->prom_name, "SUNW,hme")) {
 				cards++;
-				if((v = happy_meal_ether_init(dev, sdev, 0)))
+				prom_getstring(sdev->prom_node, "model",
+					       model, sizeof(model));
+				if (!strcmp(model, "SUNW,sbus-qfe"))
+					v = happy_meal_ether_init(dev, sdev, 1);
+				else
+					v = happy_meal_ether_init(dev, sdev, 0);
+				if(v)
 					return v;
 			} else if(!strcmp(sdev->prom_name, "qfe") ||
 				  !strcmp(sdev->prom_name, "SUNW,qfe")) {
@@ -3582,11 +3589,20 @@
 cleanup_module(void)
 {
 	struct happy_meal *sunshine;
+	struct quattro *last_seen_qfe = NULL;
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
 		sunshine = root_happy_dev->next_module;
+
+		if (!(hp->happy_flags & HFLAG_PCI) &&
+		    (hp->happy_flags & HFLAG_QUATTRO)) {
+			if (hp->qfe_parent != last_seen_qfe) {
+				free_irq(hp->dev->irq, hp->qfe_parent);
+				last_seen_qfe = hp->qfe_parent;
+			}
+		}
 
 		sparc_free_io(hp->gregs, sizeof(struct hmeal_gregs));
 		sparc_free_io(hp->etxregs, sizeof(struct hmeal_etxregs));
diff -urN linux-2.2.19-pre13/drivers/s390/Config.in linux/drivers/s390/Config.in
--- linux-2.2.19-pre13/drivers/s390/Config.in	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/Config.in	Mon Dec  3 21:07:26 2001
@@ -53,7 +53,7 @@
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     comment 'S390 Network devices'
     tristate 'CTC device support' CONFIG_CTC
-    bool 'IUCV device support (VM only)' CONFIG_IUCV
+    tristate 'IUCV device support (VM only)' CONFIG_IUCV
     tristate 'Dummy net driver support' CONFIG_DUMMY
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
     bool 'Token Ring driver support' CONFIG_TR
diff -urN linux-2.2.19-pre13/drivers/s390/Makefile linux/drivers/s390/Makefile
--- linux-2.2.19-pre13/drivers/s390/Makefile	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/Makefile	Mon Dec  3 21:07:26 2001
@@ -11,12 +11,13 @@
 
 CFLAGS += 
 O_TARGET := io.o
-O_OBJS   := ccwcache.o idals.o
+O_OBJS   := idals.o
+OX_OBJS  := ccwcache.o
 M_OBJS   :=
 
 SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
 	arch/s390/drivers/misc  arch/s390/drivers/net
-MOD_SUB_DIRS += ./net ./block
+MOD_SUB_DIRS += ./net ./block ./char
 
 O_OBJS += block/s390-block.o \
   char/s390-char.o \
diff -urN linux-2.2.19-pre13/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- linux-2.2.19-pre13/drivers/s390/block/Makefile	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/block/Makefile	Mon Dec  3 21:07:26 2001
@@ -4,10 +4,11 @@
 O_TARGET := s390-block.o
 O_OBJS   := 
 M_OBJS   :=
-D_OBJS   :=
+MI_OBJS  :=
+MIX_OBJS :=
 
 ifeq ($(CONFIG_DASD),y)
-  O_OBJS += dasd.o
+  OX_OBJS += dasd.o
   ifeq ($(CONFIG_DASD_ECKD),y)
    O_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
@@ -17,26 +18,20 @@
   ifeq ($(CONFIG_DASD_MDSK),y)
    O_OBJS += dasd_diag.o
   endif 
-#  ifeq ($(CONFIG_DASD_CKD),y)
-#   O_OBJS += dasd_ckd.o
-#  endif 
 endif
 
 ifeq ($(CONFIG_DASD),m)
   M_OBJS += dasd_mod.o
-  D_OBJS += dasd.o 
+  MIX_OBJS += dasd.o 
   ifeq ($(CONFIG_DASD_ECKD),y)
-   D_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
+   MI_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+   MI_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   D_OBJS += dasd_diag.o
+   MI_OBJS += dasd_diag.o
   endif 
-#  ifeq ($(CONFIG_DASD_CKD),y)
-#   O_OBJS += dasd_ckd.o
-#  endif 
 endif
 
 ifeq ($(CONFIG_MDISK),y)
@@ -51,7 +46,7 @@
  endif
 endif
 
-dasd_mod.o: $(D_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS)
+dasd_mod.o: $(MI_OBJS) $(MIX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.2.19-pre13/drivers/s390/block/dasd.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd.c	Mon Dec  3 21:07:26 2001
@@ -1,9 +1,10 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                  Horst Hummel <Horst.Hummel@de.ibm.com>  
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
+ *
  * History of changes (starts July 2000)
  * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels
  * 07/05/00 Added some missing cases when shutting down a device
@@ -36,8 +37,12 @@
  * 10/26/00 fixed ITPM PL010261EPA race condition when formatting  
             are the fixes in dasd_do_chanq
  * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers
+ * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,...
+ * 01/23/01 fixed sleep_on_request to terminate when signal_pending
+ * 01/25/01 added code for error recovery with PAC'0x1D' = long busy
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/init.h>
@@ -96,12 +101,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct block_device_operations dasd_device_operations;
 #endif /* VERSION_CODE */
-  
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#include <linux/module.h>
 
-EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE("dasd");
@@ -113,13 +113,8 @@
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
 
-#else
-#endif				/* MODULE */
-
 /* SECTION: Constant definitions to be used within this file */
-#ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
-#endif
 #define PRINTK_HEADER DASD_NAME":"
 
 #define DASD_QUEUE_LIMIT 10
@@ -252,7 +247,7 @@
 
 static char dasd_parm_string[1024] = {0,};
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 static int
 dasd_setup (char *str) 
 {
@@ -280,7 +275,7 @@
 #endif /* LINUX_IS_24 */
 
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 __setup("dasd=", dasd_setup);
 #endif /* LINUX_IS_24 */
 
@@ -476,7 +471,7 @@
  * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static void
+void
 dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	if (q->head != NULL) {
@@ -493,7 +488,7 @@
  * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static void
+void
 dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	cqr->next = q->head;
@@ -501,14 +496,17 @@
 	if (q->tail == NULL)
 		q->tail = cqr;
 	q->queued_requests++;
-	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+
+        atomic_compare_and_swap_debug (&cqr->status, 
+                                       CQR_STATUS_FILLED, 
+                                       CQR_STATUS_QUEUED);
 }
 
 /* 
  * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static int
+int
 dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	ccw_req_t *prev;
@@ -776,9 +774,8 @@
 	int retries = DASD_SSCH_RETRIES;
 	dasd_device_t *device = cqr->device;
 	int irq, devno;
-	int devindex, partn;
+	int devindex;
 	major_info_t *major_info;
-	struct request *req;
 
 	if (!cqr) {
 		printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
@@ -786,10 +783,9 @@
 	}
 	irq = device->devinfo.irq;
 	devno = device->devinfo.devno;
-	req = (struct request *) cqr->req;
-	devindex = devindex_from_kdev_t (req->rq_dev);
+	devindex = devindex_from_devno (devno);
 	major_info = major_info_from_devindex (devindex);
-	partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+
 	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"0x%04X on sch %d = /dev/%s (%d:%d)"
@@ -801,10 +797,12 @@
 			cqr->magic, *(long *) device->discipline->name);
 		return -EINVAL;
 	}
-	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+	atomic_compare_and_swap_debug (&cqr->status, 
+                                       CQR_STATUS_QUEUED, 
+                                       CQR_STATUS_IN_IO);
 	do {
 		asm volatile ("STCK %0":"=m" (cqr->startclk));
-		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+		rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
 		switch (rc) {
 		case 0:
                         if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
@@ -848,7 +846,7 @@
 	if (rc) {
                 atomic_compare_and_swap_debug (&cqr->status, 
                                                CQR_STATUS_IN_IO, 
-                                               CQR_STATUS_ERROR);
+                                               CQR_STATUS_FAILED);
 	}
 	return rc;
 }
@@ -879,6 +877,10 @@
                 schedule ();
                 s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
                 cs = atomic_read (&req->status);
+		if ( signal_pending(current) ) {
+			rc = -ERESTARTSYS;
+			break;
+		}
         } while ( ! (cs & CQR_STATUS_FINISHED) );
         /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ 
         remove_wait_queue (&device->wait_q, &wait);
@@ -1178,189 +1180,216 @@
 					printk (KERN_WARNING PRINTK_HEADER
 						" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 						" Failing to start I/O operation with rc %d\n",
-						devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+						devno, irq, device->name, major_from_devindex (devindex), 
+                                                devindex << DASD_PARTN_BITS, rc);
 					switch (rc) {
 					case EBUSY:
 						if (cqr->retries--) {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:"
 								" retrying ... %d retries left\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+								devno, irq, device->name, major_from_devindex (devindex), 
+                                                                devindex << DASD_PARTN_BITS, cqr->retries);
 							break;
 						}
 					default:{	/* Fallthrough ?? */
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 								" Giving up this request!\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-
-							atomic_compare_and_swap_debug (&cqr->status,
-                                                                                       CQR_STATUS_QUEUED,
-                                                                                       CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
+								devno, irq, device->name, major_from_devindex (devindex),
+                                                                devindex << DASD_PARTN_BITS);
 							break;
 						}
 					}
 				}
 				break;
 			case CQR_STATUS_IN_IO:{
-                                        unsigned long long now;
-                                        unsigned long long delta;
-                                        
-					asm volatile ("STCK %0":"=m" (now));
-					if (cqr->expires && cqr->startclk &&
-					    cqr->expires < now) {
-                                                delta = cqr->expires - cqr->startclk;
-						printk (KERN_ERR PRINTK_HEADER
-							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-							" I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
-							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
-							cqr->expires += delta;
+                                unsigned long long now;
+                                unsigned long long delta;
+                                
+                                asm volatile ("STCK %0":"=m" (now));
+                                if (cqr->expires && cqr->startclk &&
+                                    cqr->expires < now) {
+                                        delta = cqr->expires - cqr->startclk;
+                                        printk (KERN_ERR PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
+                                                devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
+                                        cqr->expires += delta;
 #if 0
-						if ( cqr->retries-- ) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" waiting %d more times\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
-							cqr->expires += delta;
-							break;
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" You should disable that device by issueing '@#?!'\n",		/* FIXME */
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-							halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
-							break;
-						}
+                                        if ( cqr->retries-- ) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " waiting %d more times\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+                                                cqr->expires += delta;
+                                                break;
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " You should disable that device by issueing '@#?!'\n",		/* FIXME */
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+                                                halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
+                                                break;
+                                        }
 #endif
-					}
-					break;
+                                }
+                                break;
                         }
 			case CQR_STATUS_ERROR:{
-                                        dasd_erp_action_fn_t erp_action;
-                                        ccw_req_t *erp_cqr = NULL;
-                                        
- 					if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
- 						atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED);
-                                                next = cqr;
-                                        } else if ( cqr -> retries--  &&
-                                             cqr -> refers == NULL &&
-                                             discipline -> erp_action != NULL &&
-                                             (erp_action = discipline->erp_action (cqr)) != NULL &&
-                                             (erp_cqr = erp_action (cqr)) != NULL ) {
+                                dasd_erp_action_fn_t erp_action;
+                                ccw_req_t *erp_cqr = NULL;
+                                
+                                if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+                                        atomic_compare_and_swap_debug(&cqr->status,
+                                                                      CQR_STATUS_ERROR,
+                                                                      CQR_STATUS_FAILED);
+                                        next = cqr;
+                                } else if (discipline -> erp_action != NULL                    &&
+                                           (erp_action = discipline->erp_action (cqr)) != NULL &&
+                                           (erp_cqr = erp_action (cqr)) != NULL                  ) {
+
+                                        if (erp_cqr != cqr){
+                                                
                                                 dasd_chanq_enq_head (qp, erp_cqr);
-                                                next = erp_cqr;		/* prefer execution of erp ccw */
-                                        } else {
-                                                atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-                                                next = cqr;
                                         }
-					break;
-				}
+                                        cqr->retries--;
+                                        next = erp_cqr;	/* prefer execution of erp ccw */
+
+                                } else {
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_ERROR, 
+                                                                       CQR_STATUS_FAILED);
+                                        next = cqr;
+                                }
+                                break;
+                        }
 			case CQR_STATUS_DONE:{
-                                        dasd_erp_postaction_fn_t erp_postaction;
-                                        next = cqr->next;
-                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
-					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if ( discipline->erp_postaction &&
-						     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing successful error recovery action using %p\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
-							erp_postaction (cqr, 1);
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" No procedure to postprocess error recovery action"
-                                                                " giving up request",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-						}
+                                dasd_erp_postaction_fn_t erp_postaction;
+                                next = cqr->next;
+                                asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+                                        if ( discipline->erp_postaction &&
+                                             ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " postprocessing successful ERA using %p\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), 
+                                                        devindex << DASD_PARTN_BITS, erp_postaction);
+                                                cqr = erp_postaction (cqr);  
+                                                next = cqr; 
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No procedure to postprocess ERA - "
+                                                        " giving up request",
+                                                        devno, irq, device->name, major_from_devindex (devindex), 
+                                                        devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->refers->status,
+                                                                               CQR_STATUS_ERROR, 
+                                                                               CQR_STATUS_FAILED);
+
                                                 atomic_dec (&device->queue.dirty_requests);
                                                 dasd_chanq_deq (&device->queue, cqr);
                                                 dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else if ( cqr->req ) {
-						dasd_end_request (cqr->req, 1);
+                                        }
+                                } else if ( cqr->req ) {
+                                        dasd_end_request (cqr->req, 1);
 #ifdef DASD_PROFILE
-						dasd_profile_add (cqr);
+                                        dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
-                                                dasd_chanq_deq (&device->queue, cqr);
-                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else {
-                                                /* during format we don't have the request structure */
-                                                /* notify sleeping task about finished postprocessing */
-                                                atomic_compare_and_swap_debug (&cqr->status, 
-                                                                               CQR_STATUS_DONE, 
-                                                                               CQR_STATUS_DONE | CQR_STATUS_FINISHED); 
-                                                dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+                                } else {
+                                        /* during format we don't have the request structure */
+                                        /* notify sleeping task about finished postprocessing */
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_DONE, 
+                                                                       CQR_STATUS_DONE | CQR_STATUS_FINISHED); 
+                                        dasd_chanq_deq (&device->queue, cqr);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-                                                wake_up (&device->wait_q);
+                                        wake_up (&device->wait_q);
 #else
-                                                if (device->wait_q) {
-                                                  wake_up (&device->wait_q);
-                                                }
-#endif /* LINUX_IS_24 */
+                                        if (device->wait_q) {
+                                                wake_up (&device->wait_q);
                                         }
-					break;
-				}
+#endif /* LINUX_IS_24 */
+                                }
+                                break;
+                        }
 			case CQR_STATUS_FAILED:{
-					dasd_erp_postaction_fn_t erp_postaction;
-					next = cqr->next;
-                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
-					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if ( discipline->erp_postaction &&
-                                                     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing unsuccessful error recovery action using %p\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
-							erp_postaction (cqr, 0);
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" No procedure to postprocess unsuccessful error recovery action"
-                                                                " giving up request",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-						}
+                                dasd_erp_postaction_fn_t erp_postaction;
+                                next = cqr->next;
+                                asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+                                        if ( discipline->erp_postaction &&
+                                             ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " postprocessing unsuccessful ERA using %p\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+                                                cqr = erp_postaction (cqr); 
+                                                next = cqr; 
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No procedure to postprocess unsuccessful ERA - "
+                                                        " giving up request",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->refers->status, 
+                                                                               CQR_STATUS_ERROR, 
+                                                                               CQR_STATUS_FAILED);
+                                                
                                                 atomic_dec (&device->queue.dirty_requests);
                                                 dasd_chanq_deq (&device->queue, cqr);
                                                 dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else if (cqr->req) {
-						dasd_end_request (cqr->req, 0);
+                                        }
+                                } else if (cqr->req) {
+                                        dasd_end_request (cqr->req, 0);
 #ifdef DASD_PROFILE
-						dasd_profile_add (cqr);
+                                        dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
-                                                dasd_chanq_deq (&device->queue, cqr);
-                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else {
-                                                /* during format we don't have the request structure */
-                                                /* notify sleeping task about finished postprocessing */
-                                                atomic_compare_and_swap_debug (&cqr->status, 
-                                                                               CQR_STATUS_FAILED, 
-                                                                               CQR_STATUS_FAILED | CQR_STATUS_FINISHED); 
-
-                                                dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+                                } else {
+                                        /* during format we don't have the request structure */
+                                        /* notify sleeping task about finished postprocessing */
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_FAILED, 
+                                                                       CQR_STATUS_FAILED | CQR_STATUS_FINISHED); 
+                                        
+                                        dasd_chanq_deq (&device->queue, cqr);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-                                                wake_up (&device->wait_q);
+                                        wake_up (&device->wait_q);
 #else
-                                                if (device->wait_q) {
-                                                  wake_up (&device->wait_q);
-                                                }
+                                        if (device->wait_q) {
+                                                wake_up (&device->wait_q);
+                                        }
 #endif /* LINUX_IS_24 */
-                                        } 
-					break;
-				}
+                                } 
+                                break;
+                        }
 
-			default:{
-					printk (KERN_WARNING PRINTK_HEADER
-						"Internal error in " __FILE__ " on line %d."
-                                                " inconsistent content of ccw_req_t"
-						" cqrstatus = %d"
-						" Pls send this message and your System.map to"
-						" linux390@de.ibm.com\n",
-						__LINE__, cqrstatus);
-				}
+			case CQR_STATUS_PENDING:
+                                /* just wait */
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                        " CQR_STATUS_PENDING - just wait...\n",
+                                        devno, irq, device->name, 
+                                        major_from_devindex (devindex), 
+                                        devindex << DASD_PARTN_BITS);
+                                break;
+                        
+			default:
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        "Internal error in " __FILE__ " on line %d."
+                                        " inconsistent content of ccw_req_t"
+                                        " cqrstatus = %d"
+                                        " Pls send this message and your System.map to"
+                                        " linux390@de.ibm.com\n",
+                                        __LINE__, cqrstatus);
+                                
 			}
 			s390irq_spin_unlock_irqrestore (irq, flags);
 		} while ((cqr = next) != NULL);
@@ -1369,6 +1398,56 @@
         return;
 }
 
+/*
+ * DASD_HANDLE_STATE_CHANGE_PENDING 
+ *
+ * DESCRIPTION
+ *   Handles the state change pending interrupt.
+ *   Search for the device related request queue and check if the first 
+ *   cqr in queue in in status 'CQR_STATUE_PENDING'.
+ *   If so the status is set to 'CQR_STATUS_QUEUED' and the bh is
+ *   scheduled.
+ *
+ *  PARAMETER
+ *   stat               device status of state change pending interrupt.
+ */
+void 
+dasd_handle_state_change_pending (devstat_t *stat)
+{
+        dasd_device_t *device;
+        ccw_req_t     *cqr;
+        int           devindex;
+
+	devindex = devindex_from_devno (stat->devno);
+	if (devindex < 0) {
+                return;
+	}
+
+	device = find_dasd_device (devindex);
+	if (device == NULL) {
+                return; 
+        }
+
+        /* re-activate first request in queue */
+        cqr = device->queue.head;    
+        
+        if (cqr != NULL                                     &&
+            atomic_read(&cqr->status) == CQR_STATUS_PENDING   ) {
+                dasd_device_t *device = cqr->device;
+
+                DASD_MESSAGE (KERN_INFO, device,
+                              "%s",
+                              "device request queue restarted by "
+                              "SCP interrupt\n");
+                
+                del_timer(&device->timer);
+                atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_PENDING, 
+                                               CQR_STATUS_QUEUED);
+                dasd_schedule_bh();
+        }
+} /* end dasd_handle_state_change_pending */
+
 void
 dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
@@ -1380,8 +1459,7 @@
 	dasd_device_t *device;
 	int devno = -1, devindex = -1;
         
-#undef  ERP_DEBUG
-#ifdef ERP_DEBUG 
+#ifdef ERP_DEBUG                /* #define ERP_DEBUG is done in dasd.h */
         static int counter = 0;
 #endif
 
@@ -1389,12 +1467,23 @@
 		PRINT_ERR ("handler called without devstat");
 		return;
 	}
+
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		PRINT_INFO ("%04X caught unsolicited interrupt\n",
 			    stat->devno);
+
+                /* check for state change pending interrupt */
+                if (stat->dstat & (DEV_STAT_ATTENTION | 
+                                   DEV_STAT_DEV_END   |
+                                   DEV_STAT_UNIT_EXCEP )) {
+                        
+                        dasd_handle_state_change_pending (stat);
+                }
+
 		return;
 	}
+
 	if (ip & 0x80000001) {
 		PRINT_INFO ("%04X  caught spurious interrupt with parm %08x\n",
 			    stat->devno, ip);
@@ -1436,20 +1525,63 @@
 		return;
 	}
 	asm volatile ("STCK %0":"=m" (cqr->stopclk));
-	if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
-	     stat->cstat == 0x00 &&
-	     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
- 	    (device->discipline->examine_error &&
-	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
 #ifdef ERP_DEBUG
-                if ( ++counter % 137 == 0 ) {
-                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n");
+                if ((++counter % 937 >= 100) &&
+                    (  counter % 937 <= 110) &&
+                    (  counter < 5000    ) &&
+                    (  counter > 2000    )   ){
+                        static int fake_count = 0;
+                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
+                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count);
+                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
                         era = dasd_era_recover;
                         stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
                         stat->dstat |= 0x02;
-                        goto error_fake_done;
+// reset notification
+                        {
+                                char *sense = stat->ii.sense.data;
+                                char buffer[100];
+				memset(sense,0,32);
+                                sprintf(buffer,"CPU ALL TR IO %X INST INT CCW", devno);
+                                cpcmd(buffer,NULL,NULL);
+                                sense[0]=0x10;
+                                sense[4]=0x21;
+                                sense[7]=0x9;
+                                sense[15]=0x4;
+                                sense[16]=0xe5;
+                                sense[18]=0x43;
+                                sense[19]=0xfb;
+                                sense[20]=0x54;
+                                sense[22]=0x0f;
+                                sense[23]=0x09;
+                                sense[26]=0x40;
+                                sense[27]=0xe0;
+                        }
+// sense 32
+//                        {
+//                                char *sense = stat->ii.sense.data;
+//                                sense [25] = 0x1D;
+//                                sense [27] = 0x00;
+//                                //sense [25] = (fake_count % 256); //0x1B;
+//                               //sense [27] = 0x00;
+//                        }
+// sense 24
+//                        {
+//                                char *sense = stat->ii.sense.data;
+//                                sense [0] = (counter % 0xFF); //0x1B;
+//                                sense [1] = ((counter * 7) % 0xFF); //0x1B;
+//                                sense [2] = (fake_count % 0xFF); //0x1B;
+//                                sense [27] = 0x80;
+//                        }
                 }
 #endif
+
+	if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
+	     stat->cstat == 0x00 &&
+	     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
+ 	    (device->discipline->examine_error &&
+	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
+
 		atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
                 atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
 					 DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -1462,9 +1594,6 @@
 			}
 		}
 	} else {		/* only visited in case of error ! */
-#ifdef ERP_DEBUG
-        error_fake_done:
-#endif
 		if (cqr->dstat == NULL)
 			cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
 		if (cqr->dstat) {
@@ -1512,7 +1641,12 @@
 ccw_req_t *
 default_erp_action (ccw_req_t * cqr)
 {
-	ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
+	if ( !erp ) {
+		printk(KERN_WARNING PRINTK_HEADER 
+                       "unable to allocate ERP request\n");
+		return NULL;
+	}
         
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
         erp->cpaddr->cda = (__u32)cqr -> cpaddr;
@@ -1528,30 +1662,97 @@
         return erp;
 }
 
-int
-default_erp_postaction (ccw_req_t * cqr, int success)
+/*
+ * DEFAULT_ERP_POSTACTION
+ *
+ * DESCRIPTION
+ *   Frees all ERPs of the current ERP Chain and set the status
+ *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
+ *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *
+ * RETURN VALUES
+ *   cqr                pointer to the original CQR
+ */
+ccw_req_t *
+default_erp_postaction (ccw_req_t * erp)
 {
-	if (cqr->refers == NULL || cqr->function == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"ERP postaction called for non ERP cqr\n");
-		return -EINVAL;
+	ccw_req_t *cqr = NULL, *free_erp = NULL;
+	dasd_device_t *device = NULL;
+	int success;
+
+	device = (dasd_device_t *) (erp->device);
+
+	if (atomic_read(&erp->status) == CQR_STATUS_DONE)
+		success = 1;
+	else
+		success = 0;
+
+#ifdef ERP_DEBUG
+
+	/* print current erp_chain */
+        printk (KERN_WARNING PRINTK_HEADER
+                "default ERP postaction called for erp chain:\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "       erp %p refers to %p with erp function %p\n",
+                               temp_erp,
+                               temp_erp->refers,
+                               temp_erp->function );
+                }
+        }
+
+#endif /* ERP_DEBUG*/
+
+	if (erp->refers == NULL || erp->function == NULL) {
+		panic (PRINTK_HEADER "Programming error in ERP! Postaction called "
+                       "for invalid ERPt\n");
+	}
+
+	/* free all ERPs - but NOT the original cqr */
+	while (erp->refers != NULL) {
+		free_erp = erp;
+		erp = erp->refers;
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,	free_erp);
+		/* free the finished erp request */
+		dasd_free_request (free_erp);
+	}
+
+	/* save ptr to original cqr */
+	cqr = erp;
+
+	/* set corresponding status to original cqr */
+	if (success) {
+		atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_ERROR, 
+                                               CQR_STATUS_DONE);
+	} else {
+		atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
 	}
-	if (cqr->function != default_erp_action) {
-		printk (KERN_WARNING PRINTK_HEADER
-                        "default ERP postaction called for non default ERP cqr\n");
-		return -EINVAL;
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+	printk (KERN_WARNING PRINTK_HEADER
+		"default ERP postaction finished with remaining chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+		for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) {
+			printk (KERN_WARNING PRINTK_HEADER
+				" erp %p refers to %p \n",
+				temp_erp, temp_erp->refers);
+		}
 	}
-        if ( success ) {
-		atomic_compare_and_swap_debug (&cqr->refers->status,
-					       CQR_STATUS_ERROR,
-					       CQR_STATUS_DONE);
-        } else {
-		atomic_compare_and_swap_debug (&cqr->refers->status,
-					       CQR_STATUS_ERROR,
-					       CQR_STATUS_FAILED);
-        } 
-	return 0;
-}
+#endif /* ERP_DEBUG */
+
+	return cqr;
+} /* end default_erp_postaction */
 
 /* SECTION: The helpers of the struct file_operations */
 
@@ -1985,10 +2186,6 @@
 	major_info_t *major_info = NULL;
 	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
 	if (major_info) {
-                major_info_t *temp = dasd_major_info;
-                while (temp->next)
-                        temp = temp->next;
-		temp->next = major_info;
                 
 		memset (major_info, 0, sizeof (major_info_t));
 		major_info->read_ahead = 8;
@@ -1998,7 +2195,8 @@
 		major_info->gendisk.minor_shift = DASD_PARTN_BITS;
 		major_info->gendisk.max_p = 1 << DASD_PARTN_BITS;
 #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-		major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS;
+		/* HSM changed for PL020234MVE */
+		major_info->gendisk.max_nr= DASD_PER_MAJOR;
 #endif /* LINUX_IS_24 */
 		major_info->gendisk.nr_real=DASD_PER_MAJOR;
 	}
@@ -2013,6 +2211,7 @@
 #endif /* LINUX_IS_24 */
 	int rc = 0;
 	int major;
+        int need_insert=0;
 
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
@@ -2024,6 +2223,7 @@
 			printk (KERN_INFO PRINTK_HEADER
 				"Created another major number\n");
 		}
+                need_insert=1; //insert new major info into dasd_major_info later
 	}
 	major = major_info->gendisk.major;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
@@ -2052,6 +2252,13 @@
 
 		}
 	}
+        /* Insert the new major info into dasd_major_info if needed */
+        if (need_insert) {
+            major_info_t *temp = dasd_major_info;
+            while (temp->next)
+                temp = temp->next;
+            temp->next = major_info;
+        }
         major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), 
                                                               GFP_ATOMIC);
         memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*));
@@ -2153,15 +2360,15 @@
                 index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
         }
         third = index % 26;
-        second = (index / 26) % 27;
-	first = ((index / 26) / 27) % 27;
+        second = ((index-26) / 26) % 26;
+	first = (((index-702) / 26) / 26) % 26;
         
 	len = sprintf (str, "dasd");
-	if (first) {
-                len += sprintf (str + len, "%c", first + 'a' - 1 );
+	if (index>701) {
+                len += sprintf (str + len, "%c", first + 'a' );
 	}
-	if (second) {
-                len += sprintf (str + len, "%c", second + 'a' - 1 );
+	if (index>25) {
+                len += sprintf (str + len, "%c", second + 'a' );
 	}
         len += sprintf (str + len, "%c", third + 'a' );
 	if (partition) {
@@ -2307,6 +2514,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
         init_waitqueue_head(&device->wait_q);
 #endif /* KERNEL_VERSION */
+        init_timer(&device->timer);
         minor = MINOR(device->kdev);
 	current_level = atomic_read (&device->level);
 	if (desired_level > current_level) {
@@ -2509,6 +2717,14 @@
         int len;
 } tempinfo_t;
 
+void dasd_fill_inode (struct inode* inode, int fill) {
+    if (fill)
+        MOD_INC_USE_COUNT;
+    else
+        MOD_DEC_USE_COUNT;
+}
+
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct proc_dir_entry *dasd_proc_root_entry = NULL;
 #else
@@ -2521,7 +2737,8 @@
 	nlink:1,
 	uid:0,
 	gid:0,
-	size:0
+	size:0,
+        fill_inode:dasd_fill_inode
 };
 #endif /* KERNEL_VERSION */
 static struct proc_dir_entry* dasd_devices_entry;
@@ -2604,6 +2821,9 @@
 		temp = temp->next;
 	}
         info->len=len;
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
         return rc;
 }
 
@@ -2661,6 +2881,9 @@
                 if ( p_info->data ) vfree(p_info->data);
                 vfree(p_info);
         }
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
         return rc;
 }
 
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd.h linux/drivers/s390/block/dasd.h
--- linux-2.2.19-pre13/drivers/s390/block/dasd.h	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd.h	Mon Dec  3 21:07:26 2001
@@ -1,5 +1,4 @@
 ccw_req_t *default_erp_action (ccw_req_t *);
-int default_erp_postaction ( ccw_req_t *, int);
 int dasd_start_IO (ccw_req_t * cqr);
 void dasd_int_handler (int , void *, struct pt_regs *);
 ccw_req_t * dasd_alloc_request (char *, int , int ) ;
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- linux-2.2.19-pre13/drivers/s390/block/dasd_3990_erp.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd_3990_erp.c	Mon Dec  3 21:07:26 2001
@@ -1,47 +1,31 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ *                  Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
 #include <linux/blkdev.h>
 #include <asm/ccwcache.h>
+#include <asm/idals.h>
 #include <asm/dasd.h>
+#include <asm/s390io.h>
+#include <linux/timer.h>
+#include "dasd_eckd.h"
+#include "dasd_3990_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
-#define PRINTK_HEADER "dasd_erp(3990)"
-#endif /* PRINTK_HEADER */
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd_erp(3990): "
+
 
 /*
- * DASD_3990_ERP_EXAMINE_32 
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recoverable error. 
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for recoverable others.
+ ***************************************************************************** 
+ * SECTION ERP EXAMINATION
+ ***************************************************************************** 
  */
-dasd_era_t
-dasd_3990_erp_examine_32 (char *sense)
-{
-
-	switch (sense[25]) {
-	case 0x00:
-		return dasd_era_none;
-	case 0x01:
-		return dasd_era_fatal;
-	default:
-		return dasd_era_recover;
-	}
-
-}				/* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE_24 
@@ -53,7 +37,7 @@
  *
  *   Each bit configuration leading to an action code 2 (Exit with
  *   programming error or unusual condition indication)
- *   and 10 (disabled interface) are handled as fatal error´s.
+ *   are handled as fatal error´s.
  * 
  *   All other configurations are handled as recoverable errors.
  *
@@ -65,31 +49,58 @@
 dasd_3990_erp_examine_24 (char *sense)
 {
 
-	/* check for 'Command Recejct' whithout environmental data present  */
-	if (sense[0] & 0x80) {
-                if (sense[2] &0x10){
-                        return dasd_era_recover;
-                } else {
-                        return dasd_era_fatal;
-                }
-        }
-	
-        /* check for 'Invalid Track Format' whithout environmental data present  */
-	if (sense[1] & 0x40) {
-                if (sense[2] &0x10){
-                        return dasd_era_recover;
-                } else {
-                        return dasd_era_fatal;
-                }
+	/* check for 'Command Recejct' which is always a fatal error  */
+	if (sense[0] & SNS0_CMD_REJECT) {
+		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+			return dasd_era_recover;
+		} else {
+			return dasd_era_fatal;
+		}
+	}
+	/* check for 'Invalid Track Format'                           */
+	if (sense[1] & SNS1_INV_TRACK_FORMAT) {
+		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+			return dasd_era_recover;
+		} else {
+			return dasd_era_fatal;
+		}
 	}
 	/* check for 'No Record Found'                                */
-	if (sense[1] & 0x08) {
+	if (sense[1] & SNS1_NO_REC_FOUND) {
 		return dasd_era_fatal;
 	}
 	/* return recoverable for all others                          */
 	return dasd_era_recover;
 
-}				/* END dasd_3990_erp_examine_24 */
+} /* END dasd_3990_erp_examine_24 */
+
+/*
+ * DASD_3990_ERP_EXAMINE_32 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recoverable error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ * RETURN VALUES
+ *   dasd_era_none      no error 
+ *   dasd_era_fatal     for all fatal (unrecoverable errors)
+ *   dasd_era_recover   for recoverable others.
+ */
+dasd_era_t
+dasd_3990_erp_examine_32 (char *sense)
+{
+
+	switch (sense[25]) {
+	case 0x00:
+		return dasd_era_none;
+	case 0x01:
+		return dasd_era_fatal;
+	default:
+		return dasd_era_recover;
+	}
+
+}				/* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE 
@@ -119,19 +130,1134 @@
 		return dasd_era_none;
 
 	/* distinguish between 24 and 32 byte sense data */
-	if (sense[27] & 0x80) {
+	if (sense[27] & DASD_SENSE_BIT_0) {
+
+		/* examine the 24 byte sense data */
+		return dasd_3990_erp_examine_24 (sense);
+
+	} else {
 
 		/* examine the 32 byte sense data */
 		return dasd_3990_erp_examine_32 (sense);
 
+	} /* end distinguish between 24 and 32 byte sense data */
+
+} /* END dasd_3990_erp_examine */
+
+/*
+ ***************************************************************************** 
+ * SECTION ERP HANDLING
+ ***************************************************************************** 
+ */
+/*
+ ***************************************************************************** 
+ * 24 and 32 byte sense ERP functions
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_BLOCK_QUEUE 
+ *
+ * DESCRIPTION
+ *   Block the given device request queue to prevent from further
+ *   processing until the started timer has expired or an related
+ *   interrupt was received.
+ *
+ *  PARAMETER
+ *   erp                request to be blocked
+ *   expires            time to wait until restart (in seconds) 
+ *
+ * RETURN VALUES
+ *   void               
+ */
+void
+dasd_3990_erp_block_queue (ccw_req_t     *erp,
+                           unsigned long expires)
+{
+
+	dasd_device_t *device = erp->device;
+
+        DASD_MESSAGE (KERN_INFO, device,
+                      "blocking request queue for %is",
+                      (int) expires);
+
+        atomic_compare_and_swap_debug (&erp->status,
+                                       CQR_STATUS_ERROR,
+                                       CQR_STATUS_PENDING);
+
+        /* restart queue after some time */
+        device->timer.function = dasd_3990_erp_restart_queue; 
+        device->timer.data = (unsigned long) erp;
+        device->timer.expires = jiffies + (expires * HZ);
+        add_timer(&device->timer); 
+
+        /* restart queue using int handler routing - just for testing - TDB */
+        /* insert "void dasd_handle_state_change_pending (devstat_t *stat);" to dasd.h */
+//        device->timer.function = dasd_handle_state_change_pending;
+//        device->timer.data = (unsigned long) &device->dev_status;
+//        device->timer.expires = jiffies + (expires * HZ);
+//        add_timer(&device->timer); 
+
+} /* end dasd_3990_erp_block_queue */ 
+
+/*
+ * DASD_3990_ERP_RESTART_QUEUE 
+ *
+ * DESCRIPTION
+ *   Restarts request currently in status PENDING.
+ *   This has to be done if either an related interrupt has received, or 
+ *   a timer has expired.
+ *   
+ *
+ *  PARAMETER
+ *   erp                pointer to the PENDING ERP
+ *
+ * RETURN VALUES
+ *   void               
+ *
+ */
+void
+dasd_3990_erp_restart_queue (unsigned long erp)
+{
+        ccw_req_t     *cqr    = (void *) erp;
+	dasd_device_t *device = cqr->device;
+	unsigned long flags;
+        
+        /* TBD delete */
+        DASD_MESSAGE (KERN_INFO, device,
+                      "%s irq %d erp %p",
+                      "dasd_3990_erp_restart_queue entered",device->devinfo.irq, erp);
+        /* get the needed locks to modify the request queue */
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+
+        /* 'restart' the device queue */
+        if (atomic_read(&cqr->status) == CQR_STATUS_PENDING){
+                
+                DASD_MESSAGE (KERN_INFO, device,
+                              "%s",
+                              "request queue restarted by MIH");
+
+                atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_PENDING,
+                                               CQR_STATUS_QUEUED);
+}
+
+        /* release the lock */
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+        dasd_schedule_bh();
+
+} /* end dasd_3990_erp_restart_queue */
+
+/*
+ * DASD_3990_ERP_ALTERNATE_PATH 
+ *
+ * DESCRIPTION
+ *   Repeat the operation on a different channel path.
+ *   If all alternate paths have been tried, the request is posted with a
+ *   permanent error.
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                modified pointer to the ERP
+ *
+ */
+void
+dasd_3990_erp_alternate_path (ccw_req_t *erp)
+{
+
+	dasd_device_t *device = erp->device;
+        int irq = device->devinfo.irq;
+
+	/* dissable current channel path - this causes the use of an other 
+	   channel path if there is one.. */
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "disable lpu %x",
+                      erp->dstat->lpum);
+
+        /* try alternate valid path */
+        erp->lpm     &= ~(erp->dstat->lpum);
+        erp->options |= DOIO_VALID_LPM;		/* use LPM for DO_IO */
+
+	if ((erp->lpm & ioinfo[irq]->opm) != 0x00) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+			"try alternate lpm %x",
+			erp->lpm);
+
+		/* reset status to queued to handle the request again... */
+		atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_QUEUED);
+
+                erp->retries = 1;
+                
 	} else {
+         
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",      
+                              "No alternate channel path left -> "
+                              "permanent error");
+                
+                /* post request with permanent error */
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
 
-		/* examine the 24 byte sense data */
-		return dasd_3990_erp_examine_24 (sense);
+        }
+        
+} /* end dasd_3990_erp_alternate_path */
+
+/*
+ * DASD_3990_ERP_ACTION_1 
+ *
+ * DESCRIPTION
+ *   Setup ERP to do the ERP action 1 (see Reference manual).
+ *   Repeat the operation on a different channel path.
+ *   If all alternate paths have been tried, the request is posted with a
+ *   permanent error.
+ *   Note: duplex handling is not implemented (yet).
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_action_1 (ccw_req_t * erp)
+{
+        
+        erp->function = dasd_3990_erp_action_1;
+        
+ //       cpcmd ("TRACE IO 153 INST INT CCW", NULL, 0);  
+
+        dasd_3990_erp_alternate_path (erp);
+
+	return erp;
+
+} /* end dasd_3990_erp_action_1 */
+
+/*
+ * DASD_3990_ERP_ACTION_4 
+ *
+ * DESCRIPTION
+ *   Setup ERP to do the ERP action 4 (see Reference manual).
+ *   Set the current request to PENDING to block the CQR queue for that device
+ *   until the state change interrupt appears.
+ *   Use a timer (20 seconds) to retry the cqr if the interrupt is still missing.
+ *
+ *  PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_action_4 (ccw_req_t *erp,
+			char      *sense)
+{
+	dasd_device_t *device = erp->device;
+
+        /* first time set initial retry counter and erp_function    */
+        /* and retry once without waiting for state change pending  */
+        /* interrupt (this enables easier enqueing of the cqr)      */
+        if (erp->function != dasd_3990_erp_action_4) {
+                erp->retries  = 255; /* TBD 255 */
+                erp->function = dasd_3990_erp_action_4;
+
+        } else {
+
+                if (sense[25] & 0x1D) {	/* state change pending */
+                        
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "waiting for state change pending "
+                                      "int");
+                        
+                        dasd_3990_erp_block_queue (erp,
+                                                   60);    /* TBD change to 30 */
+                        
+                } else {
+                        /* no state change pending - retry */
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "no state change pending - retry\n");
+                        
+                        atomic_compare_and_swap_debug (&erp->status,
+                                                       CQR_STATUS_ERROR,
+                                                       CQR_STATUS_QUEUED);
+                }
+        }
+
+	return erp;
+
+} /* end dasd_3990_erp_action_4 */
+
+/*
+ ***************************************************************************** 
+ * 24 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_EQUIP_CHECK
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Equipment Check' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_equip_check (ccw_req_t * erp,
+			   char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_equip_check;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Equipment Check - environmental data present");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_equip_check */
+
+/*
+ * DASD_3990_ERP_DATA_CHECK
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Data Check' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_data_check (ccw_req_t * erp,
+			  char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_data_check;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+                
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Uncorrectable data check recovered secondary "
+                              "addr of duplex pair");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_data_check */
+
+
+/*
+ * DASD_3990_ERP_INV_FORMAT
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Invalid Track Format' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_inv_format (ccw_req_t * erp,
+			  char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_inv_format;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Track format error when destaging or "
+                              "staging data");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_inv_format */
+
+/*
+ * DASD_3990_ERP_ENV_DATA
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Environmental-Data Present' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_env_data (ccw_req_t * erp,
+			char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_env_data;
+
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Environmental data present");
+
+	erp = dasd_3990_erp_action_4 (erp,
+				      sense);
+
+	return erp;
+
+}				/* end dasd_3990_erp_env_data */
+
+/*
+ * DASD_3990_ERP_INSPECT_24 
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection of the 24 byte sense data
+ *   and sets up a related error recovery action.  
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the (addtitional) ERP
+ */
+ccw_req_t *
+dasd_3990_erp_inspect_24 ( ccw_req_t * erp,
+                           char *sense)
+{
+	ccw_req_t *erp_filled = NULL;
+
+	/* Check sense for ....    */
+	/* 'Equipment Check'       */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_EQUIPMENT_CHECK)) {
+		erp_filled = dasd_3990_erp_equip_check (erp,
+							sense);
+	}
+	/* 'Data Check'            */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_DATA_CHECK)) {
+		erp_filled = dasd_3990_erp_data_check (erp,
+						       sense);
+	}
+	/* 'Invalid Track Format'  */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
+		erp_filled = dasd_3990_erp_inv_format (erp,
+						       sense);
+	}
+	/* 'Environmental Data'    */
+	if ((erp_filled == NULL) &&
+	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
+		erp_filled = dasd_3990_erp_env_data (erp,
+						     sense);
+	}
+
+	/* other (unknown/not jet implemented) error - do default ERP */
+	if (erp_filled == NULL) {
+
+                printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP taken\n");
+
+		erp_filled = erp;	
+	}
+
+	return erp_filled;
+
+} /* END dasd_3990_erp_inspect_24 */
+
+/*
+ ***************************************************************************** 
+ * 32 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_ACTION_1B_32
+ *
+ * DESCRIPTION
+ *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
+ *   A write operation could not be finished because of an unexpected 
+ *   condition.
+ *   The already created 'default erp' is used to get the link to 
+ *   the erp chain, but it can not be used for this recovery 
+ *   action because it contains no DE/LO data space.
+ *
+ * PARAMETER
+ *   default_erp        already created default erp.
+ *   sense              current sense data 
+ * RETURN VALUES
+ *   erp                new erp or default_erp in case of error
+ */
+ccw_req_t *
+dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
+                            char      *sense)
+{
+	dasd_device_t  *device     = default_erp->device;
+        ccw_req_t      *cqr;
+	ccw_req_t      *erp;
+        __u32          cpa;
+	DE_eckd_data_t *DE_data;
+	char           *LO_data;   /* LO_eckd_data_t */
+        ccw1_t         *ccw;
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Write not finsihed because of unexpected condition");
+        
+        /* determine the original cqr */
+        cqr = default_erp; 
+        while (cqr->refers != NULL){
+                cqr = cqr->refers;
+        }
+         
+        /* determine the address of the CCW to be restarted */
+        cpa = default_erp->refers->dstat->cpa;
+                
+        if (cpa == 0) {
+                cpa = (__u32) cqr->cpaddr;
+        }
+        
+        if (cpa == 0) {
+                
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to determine address of the CCW "
+                              "to be restarted");
+                
+                atomic_compare_and_swap_debug (&default_erp->status,
+                                               CQR_STATUS_FILLED,
+                                               CQR_STATUS_FAILED);
+                
+                return default_erp;
+        }
+        
+	/* Build new ERP request including DE/LO */
+	erp = dasd_alloc_request ((char *) &cqr->magic,
+                                  2 + 1,                    /* DE/LO + TIC */
+                                  sizeof (DE_eckd_data_t) +
+                                  sizeof (LO_eckd_data_t));
+	if ( !erp ) {
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to allocate ERP");
+                
+                atomic_compare_and_swap_debug (&default_erp->status,
+                                               CQR_STATUS_FILLED,
+                                               CQR_STATUS_FAILED);
+                
+                return default_erp;
+	}
+        
+        /* use original DE */
+	DE_data = erp->data;
+        memcpy (DE_data, 
+                cqr->data, 
+                sizeof (DE_eckd_data_t));
+        
+        /* create LO */
+	LO_data = erp->data + sizeof (DE_eckd_data_t);
+        
+        if ((sense[3]  == 0x01) &&
+            (LO_data[1] & 0x01)   ){
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "BUG - this should not happen");
+                //BUG();    /* check for read count suffixing n.a. */
+        }
+
+        LO_data[0] = sense[7];  /* operation */
+        LO_data[1] = sense[8];  /* auxiliary */
+        LO_data[2] = sense[9];  
+        LO_data[3] = sense[3];  /* count */ 
+        LO_data[4] = sense[29]; /* seek_addr.cyl */
+        LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */
+        LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */  
+
+        memcpy (&(LO_data[8]), &(sense[11]), 8);   
+
+        /* create DE ccw */    
+        ccw = erp->cpaddr;
+	memset (ccw, 0, sizeof (ccw1_t));
+	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa (DE_data);
+
+        /* create LO ccw */    
+        ccw++;
+	memset (ccw, 0, sizeof (ccw1_t));
+	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa (LO_data);
+        
+        /* TIC to the failed ccw */
+        ccw++;
+	ccw->cmd_code = CCW_CMD_TIC;
+	ccw->cda = cpa;
+
+        /* fill erp related fields */
+        erp->function = dasd_3990_erp_action_1B_32;
+	erp->refers   = default_erp->refers;
+	erp->device   = device;
+	erp->magic    = default_erp->magic;
+	erp->lpm      = 0xFF;
+	erp->expires  = 0;
+	erp->retries  = 2;
+
+	atomic_set(&erp->status, 
+                   CQR_STATUS_FILLED);
+        
+        /* remove the default erp */
+        dasd_free_request (default_erp);
+        
+	return erp;
+        
+} /* end dasd_3990_erp_action_1B_32 */
+
+
+/*
+ * DASD_3990_ERP_INSPECT_32 
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection of the 32 byte sense data
+ *   and sets up a related error recovery action.  
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp_filled         pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
+                           char      *sense )
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_inspect_32;
+
+	if (sense[25] & DASD_SENSE_BIT_0) {
+
+		/* compound program action codes (byte25 bit 0 == '1') */
+                printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP taken\n");
+
+	} else {
+
+		/* single program action codes (byte25 bit 0 == '0') */
+		switch (sense[25]) {
+
+		case 0x1B:	/* unexpected condition during write */
+
+                        erp = dasd_3990_erp_action_1B_32 (erp,
+                                                          sense);
+#ifdef ERP_DEBUG
+                        /* TBD */
+//                        cpcmd ("STOP", NULL, 0);
+#endif
+                        break;
+
+		case 0x1D:	/* state-change pending */
+                        DASD_MESSAGE (KERN_WARNING, device, 
+                                      "%s",
+                                      "A State change pending condition exists "
+                                      "for the subsystem or device");
+
+                        erp = dasd_3990_erp_action_4 (erp,
+                                                      sense);
+//                        cpcmd ("STOP", NULL, 0);
+			break;
+
+		default:	/* all others errors */
+			printk (KERN_WARNING PRINTK_HEADER
+			 "default ERP taken\n");
+		}
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_inspect_32 */
+
+/*
+ ***************************************************************************** 
+ * main ERP control fuctions (24 and 32 byte sense)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_INSPECT
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection for sense data by calling either
+ *   the 24-byte or the 32-byte inspection routine.
+ *
+ * PARAMETER
+ *   erp                pointer to the currently created default ERP
+ * RETURN VALUES
+ *   erp_new            contens was possibly modified 
+ */
+ccw_req_t *
+dasd_3990_erp_inspect (ccw_req_t * erp)
+{
+	ccw_req_t *erp_new = NULL;
+	/* sense data are located in the refers record of the */
+	/* already set up new ERP !                           */
+	char *sense = erp->refers->dstat->ii.sense.data;
+
+	/* distinguish between 24 and 32 byte sense data */
+	if (sense[27] & DASD_SENSE_BIT_0) {
+
+		/* inspect the 24 byte sense data */
+		erp_new = dasd_3990_erp_inspect_24 (erp,
+                                                    sense);
+
+	} else {
+
+		/* inspect the 32 byte sense data */
+		erp_new = dasd_3990_erp_inspect_32 (erp,
+                                                    sense);
+
+	} /* end distinguish between 24 and 32 byte sense data */
+
+	return erp_new;
+
+} /* END dasd_3990_erp_inspect */
+
+/*
+ * DASD_3990_ERP_ADD_ERP
+ * 
+ * DESCRIPTION
+ *   This funtion adds an additional request block (ERP) to the head of
+ *   the given cqr (or erp).
+ *   This erp is initialized as an default erp (retry TIC)
+ *
+ * PARAMETER
+ *   cqr                head of the current ERP-chain (or single cqr if 
+ *                      first error)
+ * RETURN VALUES
+ *   erp                pointer to new ERP-chain head
+ */
+ccw_req_t *
+dasd_3990_erp_add_erp (ccw_req_t * cqr)
+{
+	/* allocate additional request block */
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
+	if ( !erp ) {
+		printk( KERN_WARNING PRINTK_HEADER
+			"unable to allocate ERP request\n" );
+                return NULL;
+	}
+
+	/* initialize request with default TIC to current ERP/CQR */
+	erp->cpaddr->cmd_code = CCW_CMD_TIC;
+	erp->cpaddr->cda      = ((__u32) cqr->cpaddr);
+	erp->function = dasd_3990_erp_add_erp;
+	erp->refers   = cqr;
+	erp->device   = cqr->device;
+	erp->magic    = cqr->magic;
+	erp->lpm      = 0xFF;
+	erp->expires  = 0;
+	erp->retries  = 255;
+
+	atomic_set(&erp->status, 
+                   CQR_STATUS_FILLED);
+
+	return erp;
+}
+
+/*
+ * DASD_3990_ERP_ADDITIONAL_ERP 
+ * 
+ * DESCRIPTION
+ *   An additional ERP is needed to handle the current error.
+ *   Add ERP to the head of the ERP-chain containing the ERP processing
+ *   determined based on the sense data.
+ *
+ * PARAMETER
+ *   cqr                head of the current ERP-chain (or single cqr if 
+ *                      first error)
+ *
+ * RETURN VALUES
+ *   erp                pointer to new ERP-chain head
+ */
+ccw_req_t *
+dasd_3990_erp_additional_erp (ccw_req_t * cqr)
+{
+
+	ccw_req_t *erp = NULL;
+
+	/* add erp and initialize with default TIC */
+	erp = dasd_3990_erp_add_erp (cqr);
+
+	/* inspect sense, determine specific ERP if possible */
+	erp = dasd_3990_erp_inspect (erp);
+
+	return erp;
+
+}				/* end dasd_3990_erp_additional_erp */
+
+/*
+ * DASD_3990_ERP_ERROR_MATCH
+ *
+ * DESCRIPTION
+ *   check if the the device status of the given cqr is the same.
+ *   This means that the failed CCW and the relevant sense data
+ *   must match.
+ *   I don't distinguish between 24 and 32 byte sense becaus in case of
+ *   24 byte sense byte 25 and 27 is set as well.
+ *
+ * PARAMETER
+ *   cqr1               first cqr, which will be compared with the 
+ *   cqr2               second cqr.
+ *
+ * RETURN VALUES
+ *   match              'boolean' for match found
+ *                      returns 1 if match found, otherwise 0.
+ */
+int
+dasd_3990_erp_error_match (ccw_req_t * cqr1,
+			   ccw_req_t * cqr2)
+{
+	/* check failed CCW */
+	if (cqr1->dstat->cpa !=
+	    cqr2->dstat->cpa) {
+		return 0;	/* CCW doesn't match */
+
+	}
+	/* check sense data; byte 0-2,25,27 */
+	if (!((strncmp (cqr1->dstat->ii.sense.data,
+			cqr2->dstat->ii.sense.data,
+			3) == 0) &&
+	      (cqr1->dstat->ii.sense.data[27] ==
+	       cqr2->dstat->ii.sense.data[27]   ) &&
+	      (cqr1->dstat->ii.sense.data[25] ==
+	       cqr2->dstat->ii.sense.data[25]   )   )) {
+
+		return 0;	/* sense doesn't match */
+	}
+	return 1;		/* match */
+
+}				/* end dasd_3990_erp_error_match */
+
+/*
+ * DASD_3990_ERP_IN_ERP
+ *
+ * DESCRIPTION
+ *   check if the current error already happened before.
+ *   quick exit if current cqr is not an ERP (cqr->refers=NULL)
+ *
+ * PARAMETER
+ *   cqr                failed cqr (either original cqr or already an erp)
+ *
+ * RETURN VALUES
+ *   erp                erp-pointer to the already defined error recovery procedure OR
+ *                      NULL if a 'new' error occured.
+ */
+ccw_req_t *
+dasd_3990_erp_in_erp (ccw_req_t * cqr)
+{
+	ccw_req_t *erp_head = cqr,	/* save erp chain head */
+	         *erp_match = NULL;	/* save erp chain head */
+	int match = 0;		/* 'boolean' for matching error found */
+
+	if (cqr->refers == NULL) {	/* return if not in erp */
+		return NULL;
+	}
+	/* check the erp/cqr chain for current error */
+	do {
+		match = dasd_3990_erp_error_match (erp_head,
+						   cqr->refers);
+		erp_match = cqr;	/* save possible matching erp  */
+		cqr = cqr->refers;	/* check next erp/cqr in queue */
+	} while ((cqr->refers != NULL) &&
+		 (match == 0));
+
+	if (match) {
+                /* TBD */
+                printk(KERN_WARNING PRINTK_HEADER 
+                       "dasd_3990_erp_in_erp: return matching erp\n");
+		return erp_match;	/* retrun address of matching erp */
+	} else {
+                printk(KERN_WARNING PRINTK_HEADER 
+                       "dasd_3990_erp_in_erp: return no match\n");
+		return NULL;	/* return NULL to indicate that no match
+				   was found */
+	}
+
+}				/* END dasd_3990_erp_in_erp */
+
+/*
+ * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
+ *
+ * DESCRIPTION
+ *   No retry is left for the current ERP. Check what has to be done 
+ *   with the ERP.
+ *     - do further defined ERP action or
+ *     - wait for interrupt or  
+ *     - exit with permanent error
+ *
+ * PARAMETER
+ *   erp                ERP which is in progress wiht no retry left
+ *
+ * RETURN VALUES
+ *   erp                modified/additional ERP
+ */
+ccw_req_t *
+dasd_3990_erp_further_erp (ccw_req_t * erp)
+{
+        dasd_device_t     *device = erp->device;
+        
+        /* check for 24 byte sense ERP */
+	if ((erp->function == dasd_3990_erp_action_1) ||
+            (erp->function == dasd_3990_erp_action_4)   ){
+                
+                erp = dasd_3990_erp_action_1 (erp);
+                
+	} else {
+                /* no retry left and no additional special handling necessary */
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "no retries left for erp %p - "
+                              "set status to FAILED",
+                              erp);
+
+		atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
+	}
+
+	return erp; 
+
+} /* end dasd_3990_erp_further_erp */
+
+/*
+ * DASD_3990_ERP_HANDLE_MATCH_ERP 
+ *
+ * DESCRIPTION
+ *   An error occured again and an ERP has been detected which is already
+ *   used to handle this error (e.g. retries). 
+ *   All prior ERP's are set to status DONE and the retry counter is
+ *   decremented.
+ *   If retry counter is already 0, it has to checked if further action
+ *   is needed (besides retry) or if the ERP has failed.
+ *
+ * PARAMETER
+ *   erp_head           first ERP in ERP-chain
+ *   erp_match          ERP that handles the actual error.
+ *
+ * RETURN VALUES
+ *   none                
+ */
+void
+dasd_3990_erp_handle_match_erp (ccw_req_t * erp_head,
+				ccw_req_t * erp_match)
+{
+
+	dasd_device_t *device   = erp_head->device;
+	ccw_req_t     *erp_done = erp_head;
+
+	/* loop over successful ERPs and remove them from chanq */
+	while ((erp_done != erp_match) &&
+	       (erp_done != NULL)) {
+
+#ifdef ERP_DEBUG
+		printk (KERN_WARNING PRINTK_HEADER
+			"successful ERP - dequeue and free request %p\n",
+			(void *) erp_done);
+#endif
+		atomic_compare_and_swap_debug (&erp_done->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_DONE);
+
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,
+				erp_done);
+
+		/* free the finished erp request */
+		dasd_free_request (erp_done);
+
+		erp_done = erp_done->refers;
+	}
+
+	if (erp_done == NULL) 	/* erp_done should never be NULL! */
+		panic (PRINTK_HEADER "Programming error in ERP! The original "
+                       "request was lost\n");
+
+#ifdef ERP_DEBUG
+	/* handle matching ERP */
+        printk (KERN_WARNING PRINTK_HEADER
+                "handle matching erp %p\n",
+                (void *) erp_done);
+#endif
+        
+        if (erp_done->retries > 0) {
+                
+                /* check for special retries */
+                if (erp_done->function == dasd_3990_erp_action_4) {
+                        char *sense = erp_done->dstat->ii.sense.data;
+                        erp_done = dasd_3990_erp_action_4 (erp_done,
+                                                           sense);
+                        
+                } else {
+                        /* simple retry   */
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "%i retries left for erp %p\n",
+                                erp_done->retries,
+                                (void *) erp_done);
+                        
+                        /* handle the request again... */
+                        atomic_compare_and_swap_debug (&erp_done->status,
+                                                       CQR_STATUS_ERROR,
+                                                       CQR_STATUS_QUEUED);
+                }
+        } else {
+                /* no retry left - check for further necessary action    */
+                /* if no further actions, handle rest as permanent error */
+                erp_done = dasd_3990_erp_further_erp (erp_done);
+	}
+
+        erp_head = erp_done;
+
+} /* end dasd_3990_erp_handle_match_erp */
+
+/*
+ * DASD_3990_ERP_ACTION
+ *
+ * DESCRIPTION
+ *   controll routine for 3990 erp actions.
+ *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
+ *
+ * PARAMETER
+ *   cqr                failed cqr (either original cqr or already an erp)
+ *
+ * RETURN VALUES
+ *   erp                erp-pointer to the head of the ERP action chain.
+ *                      This means:
+ *                       - either a ptr to an additional ERP cqr or
+ *                       - the original given cqr (which's status might be modified)
+ */
+ccw_req_t *
+dasd_3990_erp_action (ccw_req_t *cqr)
+{
+	ccw_req_t *erp = NULL;
+	dasd_device_t *device = cqr->device;
+
+#ifdef ERP_DEBUG 
+
+	printk (KERN_WARNING PRINTK_HEADER
+		"entering 3990 ERP for "
+		"0x%04X on sch %d = /dev/%s \n",
+		device->devinfo.devno,
+		device->devinfo.irq,
+		device->name);
+
+	/* print current erp_chain */
+        printk(KERN_WARNING PRINTK_HEADER 
+               "ERP chain at BEGINNING of ERP-ACTION\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "      erp %p refers to %p \n",
+                               temp_erp,
+                               temp_erp->refers);
+                }
+        } 
+#endif
+
+	/* double-check if current erp/cqr was successfull */
+	if ((cqr->dstat->cstat == 0x00) &&
+	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "ERP called for successful request %p"
+                              " - NO ERP necessary",
+                              cqr);
+                
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_DONE);
+
+		return cqr;
+	}
+	/* check if sense data are available */
+	if (!cqr->dstat->ii.sense.data) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			"ERP called witout sense data avail ..."
+			"request %p - NO ERP possible",
+			cqr);
+
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
+
+		return cqr; 
+
+	}
+
+	/* check if error happened before */
+	erp = dasd_3990_erp_in_erp (cqr);
+
+	if (erp == NULL) {
+		/* no matching erp found - set up erp */
+		erp = dasd_3990_erp_additional_erp (cqr);
+	} else {
+		/* matching erp found - set all leading erp's to DONE */
+		dasd_3990_erp_handle_match_erp (cqr, erp);
+		erp = cqr;
+	}
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+        printk(KERN_WARNING PRINTK_HEADER 
+               "ERP chain at END of ERP-ACTION\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "      erp %p refers to %p \n",
+                               temp_erp,
+                               temp_erp->refers);
+                }
+        }
+#endif
 
-	}			/* end distinguish between 24 and 32 byte sense data */
+	return erp;
 
-}				/* END dasd_3990_erp_examine */
+} /* end dasd_3990_erp_action */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h
--- linux-2.2.19-pre13/drivers/s390/block/dasd_3990_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_3990_erp.h	Mon Dec  3 21:07:26 2001
@@ -0,0 +1,21 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3990_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts Jul 2000)
+ */
+
+#ifndef DASD_3990_ERP_H
+#define DASD_3990_ERP_H
+
+
+dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *);
+
+ccw_req_t *dasd_3990_erp_action (ccw_req_t *);
+ccw_req_t *dasd_2105_erp_action (ccw_req_t *);
+
+void dasd_3990_erp_restart_queue (unsigned long);
+
+#endif /* DASD_3990_ERP_H */
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h
--- linux-2.2.19-pre13/drivers/s390/block/dasd_9343_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_9343_erp.h	Mon Dec  3 21:07:26 2001
@@ -0,0 +1,18 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9343_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_9343_ERP_H
+#define DASD_9343_ERP_H
+
+
+dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *);
+
+ccw_req_t *dasd_9343_erp_action (ccw_req_t *);
+
+#endif /* DASD_9343_ERP_H */
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- linux-2.2.19-pre13/drivers/s390/block/dasd_diag.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/block/dasd_diag.c	Mon Dec  3 21:07:26 2001
@@ -268,13 +268,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-		device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
-		if ( device->private == NULL ) {
-			printk ( KERN_WARNING PRINTK_HEADER
-				 "memory allocation failed for private data\n");
-			return -ENOMEM;
-		}
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_diag_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -318,7 +319,7 @@
                 if (rc > 4) {
                         continue;
 		}
-                cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0);
+                cqr = dasd_alloc_request (dasd_diag_discipline.name, 2,0);
                 if ( cqr == NULL ) {
                         printk ( KERN_WARNING PRINTK_HEADER
                                  "No memory to allocate initialization request\n");
@@ -501,7 +502,7 @@
 			}
 		} else {
 			PRINT_WARN ("Cannot fulfill request smaller than block\n");
-			ccw_free_request (rw_cp);
+			dasd_free_request (rw_cp);
 			return NULL;
 		}
 	}
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- linux-2.2.19-pre13/drivers/s390/block/dasd_eckd.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd_eckd.c	Mon Dec  3 21:07:26 2001
@@ -12,6 +12,7 @@
  * 08/07/00 added some bits to define_extent for ESS support
  * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF)
  * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages)
+ * 01/23/00 fixed kmalloc in dump_sense to be GFP_ATOMIC
  */
 
 #include <linux/stddef.h>
@@ -49,22 +50,6 @@
 #define ECKD_F7(i) (i->factor7)
 #define ECKD_F8(i) (i->factor8)
 
-#define DASD_ECKD_CCW_WRITE 0x05
-#define DASD_ECKD_CCW_READ 0x06
-#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
-#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
-#define DASD_ECKD_CCW_READ_COUNT 0x12
-#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
-#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
-#define DASD_ECKD_CCW_WRITE_CKD 0x1d
-#define DASD_ECKD_CCW_READ_CKD 0x1e
-#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
-#define DASD_ECKD_CCW_WRITE_MT 0x85
-#define DASD_ECKD_CCW_READ_MT 0x86
-#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
-
 dasd_discipline_t dasd_eckd_discipline;
 
 typedef struct
@@ -374,9 +359,9 @@
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
 {
         int rc = -ENODEV;
-        void *conf_data;
+        void *conf_data=NULL;
         void *rdc_data;
-        int conf_len;
+        int conf_len=0;
         dasd_eckd_private_t *private;
 
         if ( device == NULL ) {
@@ -384,13 +369,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-          device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
-          if ( device->private == NULL ) {
-            printk ( KERN_WARNING PRINTK_HEADER
-                     "memory allocation failed for private data\n");
-            return -ENOMEM;
-          }
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_eckd_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -450,7 +436,7 @@
 	LO_eckd_data_t *LO_data;
 	eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area);
 
-        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
         if ( cqr == NULL ) {
                 printk ( KERN_WARNING PRINTK_HEADER
                          "No memory to allocate initialization request\n");
@@ -624,9 +610,9 @@
                         datasize += sizeof(eckd_home_t);
                 }
         }
-	fcp = ccw_alloc_request (dasd_eckd_discipline.name, 
-                                 wrccws + 2,
-                                 datasize+rpt*sizeof(eckd_count_t));
+	fcp = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  wrccws + 2,
+                                  datasize+rpt*sizeof(eckd_count_t));
         if ( fcp != NULL ) {
                 fcp->device = device;
                 fcp->retries = 2;       /* set retry counter to enable ERP */
@@ -751,21 +737,26 @@
 	}
 }
 
-static dasd_erp_action_fn_t 
-dasd_eckd_erp_action ( ccw_req_t * cqr ) 
+static dasd_erp_action_fn_t
+dasd_eckd_erp_action (ccw_req_t * cqr)
 {
-        return default_erp_action;
+	dasd_device_t *device = (dasd_device_t *) cqr->device;
+
+	switch (device->devinfo.sid_data.cu_type) {
+	case 0x3990:
+	case 0x2105:
+		return dasd_3990_erp_action;
+	case 0x9343:
+		/* return dasd_9343_erp_action; */
+	default:
+		return default_erp_action;
+	}
 }
 
 static dasd_erp_postaction_fn_t
 dasd_eckd_erp_postaction (ccw_req_t * cqr)
 {
-        if ( cqr -> function == default_erp_action)
-                return default_erp_postaction;
-        printk ( KERN_WARNING PRINTK_HEADER
-                 "unknown ERP action %p\n",
-                 cqr -> function);
-	return NULL;
+	return default_erp_postaction;
 }
 
 static ccw_req_t *
@@ -844,7 +835,7 @@
 			}
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors);
-				ccw_free_request (rw_cp);
+				dasd_free_request (rw_cp);
 				return NULL;
 			}
 			ccw->flags = CCW_FLAG_CC;
@@ -862,7 +853,7 @@
 static char *
 dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-        char *page = (char *)get_free_page(GFP_KERNEL);
+        char *page = (char *)get_free_page(GFP_ATOMIC);
         devstat_t *stat = &device->dev_status;
 	char *sense = stat->ii.sense.data;
         int len,sl,sct;
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h
--- linux-2.2.19-pre13/drivers/s390/block/dasd_eckd.h	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd_eckd.h	Mon Dec  3 21:07:26 2001
@@ -1,6 +1,25 @@
 #ifndef DASD_ECKD_H
 #define DASD_ECKD_H
 
+#include "dasd_3990_erp.h"
+#include "dasd_9343_erp.h"
+
+#define DASD_ECKD_CCW_WRITE 0x05
+#define DASD_ECKD_CCW_READ 0x06
+#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
+#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
+#define DASD_ECKD_CCW_READ_COUNT 0x12
+#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
+#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
+#define DASD_ECKD_CCW_WRITE_CKD 0x1d
+#define DASD_ECKD_CCW_READ_CKD 0x1e
+#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
+#define DASD_ECKD_CCW_WRITE_MT 0x85
+#define DASD_ECKD_CCW_READ_MT 0x86
+#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
+#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
+
 typedef 
 struct eckd_count_t {
 	__u16 cyl;
diff -urN linux-2.2.19-pre13/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- linux-2.2.19-pre13/drivers/s390/block/dasd_fba.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/block/dasd_fba.c	Mon Dec  3 21:07:26 2001
@@ -117,13 +117,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-		device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
-		if ( device->private == NULL ) {
-			printk ( KERN_WARNING PRINTK_HEADER
-				 "memory allocation failed for private data\n");
-			return -ENOMEM;
-		}
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_fba_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -306,7 +307,7 @@
 					ccw->flags = CCW_FLAG_DC;
 				} else {
 					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					ccw_free_request (rw_cp);
+					dasd_free_request (rw_cp);
 					return NULL;
 				}
 				ccw->cmd_code = rw_cmd;
@@ -318,7 +319,7 @@
 			ccw->flags = CCW_FLAG_CC;
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				ccw_free_request (rw_cp);
+				dasd_free_request (rw_cp);
 				return NULL;
 			}
 		}
diff -urN linux-2.2.19-pre13/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- linux-2.2.19-pre13/drivers/s390/block/xpram.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/block/xpram.c	Mon Dec  3 21:07:26 2001
@@ -413,7 +413,7 @@
 		"   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
 		/* copy page from expanded memory */
 		"0: ipm  %0          \n"   /* save status (cc & program mask */
-		"   srl  %0,28(0)    \n"   /* cc into least significant bits */
+		"   srl  %0,28       \n"   /* cc into least significant bits */
                 "1:                  \n"   /* we are done                    */
                 ".section .fixup,\"ax\"\n" /* start of fix up section        */
                 "2: lhi    %0,2      \n"   /* return unused condition code 2 */
@@ -456,7 +456,7 @@
 		" .long 0xb22f0012 \n"   /* pgout r1,r2                    */
                                 /* copy page from expanded memory */
 		"0: ipm  %0        \n"   /* save status (cc & program mask */
-                " srl  %0,28(0)    \n"   /* cc into least significant bits */
+                " srl  %0,28       \n"   /* cc into least significant bits */
                 "1:                  \n"   /* we are done                    */
                 ".section .fixup,\"ax\"\n" /* start of fix up section        */
                 "2: lhi   %0,2       \n"   /* return unused condition code 2 */
diff -urN linux-2.2.19-pre13/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c
--- linux-2.2.19-pre13/drivers/s390/ccwcache.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/ccwcache.c	Mon Dec  3 21:07:26 2001
@@ -8,6 +8,7 @@
    * 07/10/00 moved ccwcache.h from linux/ to asm/
  */
 
+#include <linux/module.h>
 #include <linux/malloc.h>
 #include <asm/debug.h>
 #include <asm/ccwcache.h>
@@ -15,19 +16,14 @@
 #include <asm/ebcdic.h>
 #include <asm/spinlock.h>
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif
+#undef  PRINTK_HEADER
 #define PRINTK_HEADER "ccwcache"
 
-#ifdef MODULE
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 CCW cache,"
 		    "Copyright 2000 IBM Corporation");
-EXPORT_NO_SYMBOLS; 
 EXPORT_SYMBOL(ccw_alloc_request);
 EXPORT_SYMBOL(ccw_free_request);
-#endif /* MODULE */
 
 
 /* pointer to list of allocated requests */
@@ -314,8 +310,7 @@
 	} else {
 		printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
 	}
-        debug_register_view(debug_area,&debug_hex_view);
-        debug_register_view(debug_area,&debug_ebcdic_view);
+        debug_register_view(debug_area,&debug_hex_ascii_view);
 	debug_text_event ( debug_area, 0, "INIT");
 	
 	/* First allocate the kmem caches */
@@ -389,3 +384,4 @@
 	ccwcache_cleanup();
 }
 #endif /* MODULE */
+
diff -urN linux-2.2.19-pre13/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h
--- linux-2.2.19-pre13/drivers/s390/char/hwc.h	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/char/hwc.h	Mon Dec  3 21:07:27 2001
@@ -39,6 +39,8 @@
 #define HWC_BUSY		2
 #define HWC_NOT_OPERATIONAL	3
 
+#define hwc_cmdw_t u32;
+
 #define HWC_CMDW_READDATA 0x00770005
 
 #define HWC_CMDW_WRITEDATA 0x00760005
@@ -207,9 +209,25 @@
 	0x0000,
 	0x0000,
 	sizeof (_hwcb_mask_t),
-	ET_OpCmd_Mask | ET_PMsgCmd_Mask,
-	ET_Msg_Mask
+	ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
+	ET_Msg_Mask | ET_PMsgCmd_Mask
 };
+
+typedef struct {
+	_EBUF_HEADER
+	u8 validity_hwc_active_facility_mask:1;
+	u8 validity_hwc_receive_mask:1;
+	u8 validity_hwc_send_mask:1;
+	u8 validity_read_data_function_mask:1;
+	u16 _zeros:12;
+	u16 mask_length;
+	u64 hwc_active_facility_mask;
+	_hwcb_mask_t hwc_receive_mask;
+	_hwcb_mask_t hwc_send_mask;
+	u32 read_data_function_mask;
+} __attribute__ ((packed)) 
+
+statechangebuf_t;
 
 #define _GDS_VECTOR_HEADER	u16	length; \
 				u16	gds_id;
diff -urN linux-2.2.19-pre13/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
--- linux-2.2.19-pre13/drivers/s390/char/hwc_rw.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/char/hwc_rw.c	Mon Dec  3 21:07:27 2001
@@ -29,9 +29,13 @@
 #include <asm/s390_ext.h>
 
 #ifndef MIN
-#define MIN(a,b) ((a<b) ? a : b)
+#define MIN(a,b) (((a<b) ? a : b))
 #endif
 
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
@@ -50,7 +54,7 @@
 
 #undef BUFFER_STRESS_TEST
 
-#define MEASURE_HWC_OUTPUT
+#undef MEASURE_HWC_OUTPUT
 
 typedef struct {
 	unsigned char *next;
@@ -119,15 +123,16 @@
 static unsigned char
  _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
 
-typedef u32 kmem_pages_t;
+typedef unsigned long kmem_pages_t;
 
 #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
 
-#define HWC_TIMER_RUNS	1
-#define HWC_FLUSH	2
-#define HWC_INIT	4
-#define HWC_BROKEN	8
-#define HWC_INTERRUPT	16
+#define HWC_WTIMER_RUNS	1
+#define HWC_FLUSH		2
+#define HWC_INIT		4
+#define HWC_BROKEN		8
+#define HWC_INTERRUPT		16
+#define HWC_PTIMER_RUNS	32
 
 static struct {
 
@@ -169,6 +174,7 @@
 	unsigned char write_prio:1;
 	unsigned char read_nonprio:1;
 	unsigned char read_prio:1;
+	unsigned char read_statechange:1;
 
 	unsigned char flags;
 
@@ -177,6 +183,8 @@
 	spinlock_t lock;
 
 	struct timer_list write_timer;
+
+	struct timer_list poll_timer;
 } hwc_data =
 {
 	{
@@ -185,7 +193,6 @@
 		8,
 		    0,
 		    80,
-		    CODE_ASCII,
 		    1,
 		    50,
 		    MAX_KMEM_PAGES,
@@ -218,6 +225,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL
 
 };
@@ -231,7 +239,6 @@
 
 static signed int do_hwc_write (int from_user, unsigned char *,
 				unsigned int,
-				unsigned char,
 				unsigned char);
 
 static asmlinkage int 
@@ -244,7 +251,7 @@
 	va_start (args, fmt);
 	i = vsprintf (buf, fmt, args);
 	va_end (args);
-	return do_hwc_write (0, buf, i, CODE_ASCII, write_time);
+	return do_hwc_write (0, buf, i, write_time);
 }
 
 int 
@@ -260,7 +267,7 @@
 
 	i = vsprintf (buf, fmt, args);
 	va_end (args);
-	retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
+	retval = do_hwc_write (0, buf, i, IMMEDIATE_WRITE);
 
 	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
@@ -310,8 +317,8 @@
 {
 	unsigned int condition_code = 1;
 
-	__asm__ __volatile__ ("L 1, 0(0,%0) \n\t"
-			      "LRA 2, 0(0,%1) \n\t"
+	__asm__ __volatile__ ("L 1, 0(%0) \n\t"
+			      "LRA 2, 0(%1) \n\t"
 			      ".long 0xB2200012 \n\t"
 			      :
 			      :"a" (&hwc_command_word), "a" (hwcb)
@@ -329,7 +336,7 @@
 {
 	u32 param;
 
-	__asm__ __volatile__ ("L %0,128(0,0)\n\t"
+	__asm__ __volatile__ ("L %0,128\n\t"
 			      :"=r" (param));
 
 	return ((unsigned char *) param);
@@ -350,9 +357,6 @@
 
 	memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
 
-	if (!hwc_data.write_nonprio && hwc_data.write_prio)
-		hwcb->msgbuf.type = ET_PMsgCmd;
-
 	return 0;
 }
 
@@ -375,7 +379,7 @@
 
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		__asm__ ("LHI 1,0xe30\n\t"
-			 "LRA 2,0(0,%0) \n\t"
+			 "LRA 2,0(%0) \n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (bad_addr)
@@ -437,8 +441,8 @@
 	if (hwc_data.hwcb_count < 2)
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		__asm__ ("LHI 1,0xe31\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (BUF_HWCB), "a" (OUT_HWCB)
@@ -658,32 +662,65 @@
 	return count;
 }
 
+static int write_event_data_1 (void);
+
+static void 
+do_poll_hwc (unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
+	write_event_data_1 ();
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+}
+
+void 
+start_poll_hwc (void)
+{
+	init_timer (&hwc_data.poll_timer);
+	hwc_data.poll_timer.function = do_poll_hwc;
+	hwc_data.poll_timer.data = (unsigned long) NULL;
+	hwc_data.poll_timer.expires = jiffies + 2 * HZ;
+	add_timer (&hwc_data.poll_timer);
+	hwc_data.flags |= HWC_PTIMER_RUNS;
+}
+
 static int 
 write_event_data_1 (void)
 {
 	unsigned short int condition_code;
 	int retval;
+	write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
 
-	if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))
-		return -EPERM;
+	if ((!hwc_data.write_prio) &&
+	    (!hwc_data.write_nonprio) &&
+	    hwc_data.read_statechange)
+		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
 
 	retval = sane_write_hwcb ();
 	if (retval < 0)
-		return retval;
+		return -EIO;
 
 	if (!OUT_HWCB_MTO)
 		return -ENODATA;
 
+	if (!hwc_data.write_nonprio && hwc_data.write_prio)
+		hwcb->msgbuf.type = ET_PMsgCmd;
+	else
+		hwcb->msgbuf.type = ET_Msg;
+
 	condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	if (condition_code != HWC_COMMAND_INITIATED)
 		__asm__ ("LHI 1,0xe20\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (OUT_HWCB)
@@ -702,6 +739,8 @@
 	case HWC_BUSY:
 		retval = -EBUSY;
 		break;
+	case HWC_NOT_OPERATIONAL:
+		start_poll_hwc ();
 	default:
 		retval = -EIO;
 	}
@@ -724,7 +763,7 @@
 write_event_data_2 (void)
 {
 	write_hwcb_t *hwcb;
-	int retval;
+	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	unsigned char *param;
@@ -734,7 +773,7 @@
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-				       "write_event_mask_2 : "
+				       "write_event_data_2 : "
 				       "HWCB address does not fit "
 				       "(expected: 0x%x, got: 0x%x).\n",
 				       hwc_data.current_hwcb,
@@ -748,10 +787,10 @@
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 	if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
 		__asm__ ("LHI 1,0xe22\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
-			 "LRA 4,0(0,%2)\n\t"
-			 "LRA 5,0(0,%3)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
+			 "LRA 4,0(%2)\n\t"
+			 "LRA 5,0(%3)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (OUT_HWCB),
@@ -765,11 +804,11 @@
 #ifdef DUMP_HWC_WRITE_ERROR
 	if (hwcb->response_code != 0x0020) {
 		__asm__ ("LHI 1,0xe21\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
-			 "LRA 4,0(0,%2)\n\t"
-			 "LH 5,0(0,%3)\n\t"
-			 "SRL 5,8(0)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
+			 "LRA 4,0(%2)\n\t"
+			 "LH 5,0(%3)\n\t"
+			 "SRL 5,8\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
@@ -779,11 +818,22 @@
 	}
 #endif
 
-	if (hwcb->response_code == 0x0020) {
+	switch (hwcb->response_code) {
+	case 0x0020:
 
 		retval = OUT_HWCB_CHAR;
 		release_write_hwcb ();
-	} else {
+		break;
+	case 0x0040:
+	case 0x0340:
+	case 0x40F0:
+		if (!hwc_data.read_statechange) {
+			hwcb->response_code = 0;
+			start_poll_hwc ();
+		}
+		retval = -EIO;
+		break;
+	default:
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
@@ -796,6 +846,13 @@
 		retval = -EIO;
 	}
 
+	if (retval == -EIO) {
+
+		hwcb->control_mask[0] = 0;
+		hwcb->control_mask[1] = 0;
+		hwcb->control_mask[2] = 0;
+		hwcb->response_code = 0;
+	}
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
 
@@ -819,10 +876,10 @@
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		if (add_mto (message, count) != count)
 			__asm__ ("LHI 1,0xe32\n\t"
-				 "LRA 2,0(0,%0)\n\t"
-				 "L 3,0(0,%1)\n\t"
-				 "LRA 4,0(0,%2)\n\t"
-				 "LRA 5,0(0,%3)\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "L 3,0(%1)\n\t"
+				 "LRA 4,0(%2)\n\t"
+				 "LRA 5,0(%3)\n\t"
 				 "J .+0 \n\t"
 		      :
 		      :	 "a" (message), "a" (&hwc_data.kmem_pages),
@@ -840,9 +897,9 @@
 		 unsigned short count)
 {
 
-	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
+	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
 		del_timer (&hwc_data.write_timer);
-		hwc_data.flags &= ~HWC_TIMER_RUNS;
+		hwc_data.flags &= ~HWC_WTIMER_RUNS;
 	}
 	hwc_data.obuf_start += count;
 
@@ -888,13 +945,12 @@
 		     int from_user,
 		     unsigned char *msg,
 		     unsigned int count,
-		     unsigned char code,
 		     unsigned char write_time)
 {
 	unsigned int i_msg = 0;
 	unsigned short int spaces = 0;
 	unsigned int processed_characters = 0;
-	unsigned char ch, orig_ch;
+	unsigned char ch;
 	unsigned short int obuf_count;
 	unsigned short int obuf_cursor;
 	unsigned short int obuf_columns;
@@ -911,15 +967,10 @@
 	}
 
 	for (i_msg = 0; i_msg < count; i_msg++) {
-
 		if (from_user)
-			get_user (orig_ch, msg + i_msg);
+			get_user (ch, msg + i_msg);
 		else
-			orig_ch = msg[i_msg];
-		if (code == CODE_EBCDIC)
-			ch = (MACHINE_IS_VM ? _ebcasc[orig_ch] : _ebcasc_500[orig_ch]);
-		else
-			ch = orig_ch;
+			ch = msg[i_msg];
 
 		processed_characters++;
 
@@ -957,7 +1008,7 @@
 				if (obuf_cursor < obuf_columns) {
 					hwc_data.obuf[hwc_data.obuf_start +
 						      obuf_cursor]
-					    = 0x20;
+					    = HWC_ASCEBC (' ');
 					obuf_cursor++;
 				} else
 					break;
@@ -975,7 +1026,7 @@
 			while (spaces) {
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor - spaces]
-				    = 0x20;
+				    = HWC_ASCEBC (' ');
 				spaces--;
 			}
 
@@ -1005,11 +1056,7 @@
 			if (isprint (ch))
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor++]
-				    = (code == CODE_ASCII) ?
-				    (MACHINE_IS_VM ?
-				     _ascebc[orig_ch] :
-				     _ascebc_500[orig_ch]) :
-				    orig_ch;
+				    = HWC_ASCEBC (ch);
 		}
 		if (obuf_cursor > obuf_count)
 			obuf_count = obuf_cursor;
@@ -1028,11 +1075,10 @@
 
 			if (hwc_data.ioctls.final_nl > 0) {
 
-				if (hwc_data.flags & HWC_TIMER_RUNS) {
+				if (hwc_data.flags & HWC_WTIMER_RUNS) {
 
-					hwc_data.write_timer.expires =
-					    jiffies +
-					    hwc_data.ioctls.final_nl * HZ / 10;
+					mod_timer (&hwc_data.write_timer,
+						   jiffies + hwc_data.ioctls.final_nl * HZ / 10);
 				} else {
 
 					init_timer (&hwc_data.write_timer);
@@ -1044,7 +1090,7 @@
 					    jiffies +
 					    hwc_data.ioctls.final_nl * HZ / 10;
 					add_timer (&hwc_data.write_timer);
-					hwc_data.flags |= HWC_TIMER_RUNS;
+					hwc_data.flags |= HWC_WTIMER_RUNS;
 				}
 			} else;
 
@@ -1072,8 +1118,7 @@
 	spin_lock_irqsave (&hwc_data.lock, flags);
 
 	retval = do_hwc_write (from_user, (unsigned char *) msg,
-			       count, hwc_data.ioctls.code,
-			       IMMEDIATE_WRITE);
+			       count, IMMEDIATE_WRITE);
 
 	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
@@ -1329,15 +1374,11 @@
 	if (hwc_data.ioctls.delim)
 		count = seperate_cases (start, count);
 
+	HWC_EBCASC_STR (start, count);
+
 	if (hwc_data.ioctls.echo)
-		do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
+		do_hwc_write (0, start, count, IMMEDIATE_WRITE);
 
-	if (hwc_data.ioctls.code == CODE_ASCII) {
-		if (MACHINE_IS_VM)
-			EBCASC (start, count);
-		else
-			EBCASC_500 (start, count);
-	}
 	if (hwc_data.calls != NULL)
 		if (hwc_data.calls->move_input != NULL)
 			(hwc_data.calls->move_input) (start, count);
@@ -1440,7 +1481,7 @@
 	return retval;
 }
 
-inline static int 
+static int 
 eval_evbuf (gds_vector_t * start, void *end)
 {
 	gds_vector_t *vec;
@@ -1458,6 +1499,128 @@
 	return retval;
 }
 
+static inline int 
+eval_hwc_receive_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.write_nonprio
+	    = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
+
+	hwc_data.write_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+
+	if (hwc_data.write_prio || hwc_data.write_nonprio) {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can write messages\n");
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can not write messages\n");
+		return -1;
+	}
+}
+
+static inline int 
+eval_hwc_send_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.read_statechange
+	    = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
+	if (hwc_data.read_statechange)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can read state change notifications\n");
+	else
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				 "can not read state change notifications\n");
+
+	hwc_data.read_nonprio
+	    = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
+	if (hwc_data.read_nonprio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read commands\n");
+
+	hwc_data.read_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+	if (hwc_data.read_prio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read priority commands\n");
+
+	if (hwc_data.read_prio || hwc_data.read_nonprio) {
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can not read commands from operator\n");
+		return -1;
+	}
+}
+
+static int 
+eval_statechangebuf (statechangebuf_t * scbuf)
+{
+	int retval = 0;
+
+	internal_print (
+			       DELAYED_WRITE,
+			       HWC_RW_PRINT_HEADER
+			       "HWC state change detected\n");
+
+	if (scbuf->validity_hwc_active_facility_mask) {
+
+	}
+	if (scbuf->validity_hwc_receive_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe50\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_receive_mask
+			    (scbuf->hwc_receive_mask);
+		}
+	}
+	if (scbuf->validity_hwc_send_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe51\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_send_mask
+			    (scbuf->hwc_send_mask);
+		}
+	}
+	if (scbuf->validity_read_data_function_mask) {
+
+	}
+	return retval;
+}
+
 static int 
 process_evbufs (void *start, void *end)
 {
@@ -1490,17 +1653,17 @@
 			retval += eval_evbuf (evbuf_data, evbuf_end);
 			break;
 		case ET_StateChange:
-
-			retval = -ENOSYS;
+			retval += eval_statechangebuf
+			    ((statechangebuf_t *) evbuf);
 			break;
 		default:
-			printk (
-				       KERN_WARNING
-				       HWC_RW_PRINT_HEADER
-				       "unconditional read: "
-				       "unknown event buffer found, "
-				       "type 0x%x",
-				       evbuf->type);
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "unconditional read: "
+					       "unknown event buffer found, "
+					       "type 0x%x",
+					       evbuf->type);
 			retval = -ENOSYS;
 		}
 		evbuf = (evbuf_t *) evbuf_end;
@@ -1515,11 +1678,14 @@
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 	int retval;
 
+#if 0
+
 	if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
 		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
+#endif
 
 	memset (hwcb, 0x00, PAGE_SIZE);
 	memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
@@ -1529,8 +1695,8 @@
 #ifdef DUMP_HWC_READ_ERROR
 	if (condition_code == HWC_NOT_OPERATIONAL)
 		__asm__ ("LHI 1,0xe40\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (hwc_data.page)
@@ -1564,8 +1730,8 @@
 	    (hwcb->response_code != 0x60F0) &&
 	    (hwcb->response_code != 0x62F0))
 		__asm__ ("LHI 1,0xe41\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "L 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "L 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (hwc_data.page), "a" (&(hwcb->response_code))
@@ -1625,26 +1791,21 @@
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			   "unconditional read: invalid function code - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			       "unconditional read: invalid function code\n");
 		return -EIO;
 
 	case 0x70F0:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			  "unconditional read: invalid selection mask - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			      "unconditional read: invalid selection mask\n");
 		return -EIO;
 
 	case 0x0040:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			    "unconditional read: HWC equipment check - don't "
-				       "know how to handle this case\n");
+				 "unconditional read: HWC equipment check\n");
 		return -EIO;
 
 	default:
@@ -1671,8 +1832,8 @@
 
 	if (condition_code == HWC_NOT_OPERATIONAL)
 		__asm__ ("LHI 1,0xe10\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (hwc_data.page)
@@ -1701,38 +1862,34 @@
 	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
 	int retval = 0;
 
-	if (hwcb->hwc_receive_mask & ET_Msg_Mask)
-		hwc_data.write_nonprio = 1;
-
-	if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
-		hwc_data.write_prio = 1;
-
-	if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of priority commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if ((hwcb->response_code != 0x0020) ||
-	    (!hwc_data.write_nonprio) ||
-	    ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
+	if (hwcb->response_code != 0x0020) {
 #ifdef DUMP_HWC_INIT_ERROR
 		__asm__ ("LHI 1,0xe11\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "L 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "L 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (hwcb), "a" (&(hwcb->response_code))
 	      :	 "1", "2", "3");
 #else
-		retval = -EIO;
+		retval = -1;
 #endif
+	} else {
+		if (hwcb->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe52\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (hwcb)
+		      :	 "1", "2");
+#endif
+		} else {
+			retval += eval_hwc_receive_mask
+			    (hwcb->hwc_receive_mask);
+			retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
+		}
+	}
 
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
@@ -1764,18 +1921,6 @@
 	} else
 		tmp.columns = ioctls->columns;
 
-	switch (ioctls->code) {
-	case CODE_EBCDIC:
-	case CODE_ASCII:
-		tmp.code = ioctls->code;
-		break;
-	default:
-		if (correct)
-			tmp.code = CODE_ASCII;
-		else
-			retval = -EINVAL;
-	}
-
 	tmp.final_nl = ioctls->final_nl;
 
 	if (ioctls->max_hwcb < 2) {
@@ -1915,7 +2060,7 @@
 			       HWC_RW_PRINT_HEADER
 			       "use %i bytes for buffering.\n",
 			       hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
-	for (i = 0; i < 500; i++) {
+	for (i = 0; i < 2000; i++) {
 		hwcb = (init_hwcb_t *) BUF_HWCB;
 		internal_print (
 				       DELAYED_WRITE,
@@ -1975,6 +2120,10 @@
 	} else {
 		spin_lock (&hwc_data.lock);
 
+		if (hwc_data.flags & HWC_PTIMER_RUNS) {
+			del_timer (&hwc_data.poll_timer);
+			hwc_data.flags &= ~HWC_PTIMER_RUNS;
+		}
 		if (!hwc_data.current_servc) {
 
 			unconditional_read_1 ();
@@ -2064,12 +2213,6 @@
 			goto fault;
 		break;
 
-	case TIOCHWCSCODE:
-		if (get_user (tmp.code, (ioctl_code_t *) arg))
-			goto fault;
-
-		break;
-
 	case TIOCHWCSNL:
 		if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
 			goto fault;
@@ -2126,12 +2269,6 @@
 	case TIOCHWCGCOLS:
 		if (put_user (tmp.columns, (ioctl_cols_t *) arg))
 			goto fault;
-		break;
-
-	case TIOCHWCGCODE:
-		if (put_user (tmp.code, (ioctl_code_t *) arg))
-			goto fault;
-
 		break;
 
 	case TIOCHWCGNL:
diff -urN linux-2.2.19-pre13/drivers/s390/char/hwc_rw.h linux/drivers/s390/char/hwc_rw.h
--- linux-2.2.19-pre13/drivers/s390/char/hwc_rw.h	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/char/hwc_rw.h	Mon Dec  3 21:07:27 2001
@@ -26,7 +26,6 @@
 typedef unsigned short int ioctl_htab_t;
 typedef unsigned char ioctl_echo_t;
 typedef unsigned short int ioctl_cols_t;
-typedef unsigned char ioctl_code_t;
 typedef signed char ioctl_nl_t;
 typedef unsigned short int ioctl_obuf_t;
 typedef unsigned char ioctl_case_t;
@@ -37,7 +36,6 @@
 	ioctl_htab_t width_htab;
 	ioctl_echo_t echo;
 	ioctl_cols_t columns;
-	ioctl_code_t code;
 	ioctl_nl_t final_nl;
 	ioctl_obuf_t max_hwcb;
 	ioctl_obuf_t kmem_hwcb;
@@ -58,8 +56,6 @@
 
 #define TIOCHWCSCOLS	_IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns)
 
-#define TIOCHWCSCODE	_IOW(HWC_IOCTL_LETTER, 3, _hwc_ioctls.code)
-
 #define TIOCHWCSNL	_IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl)
 
 #define TIOCHWCSOBUF	_IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb)
@@ -78,8 +74,6 @@
 
 #define TIOCHWCGCOLS	_IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns)
 
-#define TIOCHWCGCODE	_IOR(HWC_IOCTL_LETTER, 13, _hwc_ioctls.code)
-
 #define TIOCHWCGNL	_IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl)
 
 #define TIOCHWCGOBUF	_IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb)
@@ -99,9 +93,6 @@
 #define TIOCHWCGMEASC  _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars)
 
 #define TIOCHWCGMEASS	_IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls)
-
-#define CODE_ASCII              0x0
-#define CODE_EBCDIC             0x1
 
 #ifndef __HWC_RW_C__
 
diff -urN linux-2.2.19-pre13/drivers/s390/idals.c linux/drivers/s390/idals.c
--- linux-2.2.19-pre13/drivers/s390/idals.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/idals.c	Mon Dec  3 21:07:27 2001
@@ -9,71 +9,36 @@
  */
 
 #include <linux/malloc.h>
+
 #include <asm/irq.h>
 #include <asm/idals.h>
-#include <asm/spinlock.h>
-
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif
-#define PRINTK_HEADER "idals:"
-
-/* a name template for the cache-names */
-static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */
-/* the cache's names */
-static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; 
-/* the caches itself*/
-static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; 
 
-void
-free_idal ( ccw1_t *cp )
+#ifdef CONFIG_ARCH_S390X
+void 
+set_normalized_cda ( ccw1_t * cp, unsigned long address )
 {
+	int nridaws;
 	idaw_t *idal;
-	unsigned long upper2k,lower2k;
-	int nridaws,cacheind;
-	if ( cp -> flags & CCW_FLAG_IDA ) {
-		idal = cp -> cda;
-		lower2k = *idal & 0xfffffffffffff800;
-		upper2k = (*idal  + cp -> count - 1) & 0xfffffffffffff800;
-		nridaws = ((upper2k - lower2k) >> 11) + 1;
-		for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ );
-		kmem_cache_free ( idal_cache[cacheind], idal );
-	}
-}
-
-int 
-idal_support_init ( void ) 
-{
-	int rc=0;
-	int cachind;
-	
-	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
-		int slabsize = 8 << cachind;
-		sprintf ( idal_cache_name[cachind], 
-			  "%s%d%c", idal_name_template, slabsize, 0);
-		idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], 
-							 slabsize, 0,
-							 SLAB_HWCACHE_ALIGN | SLAB_DMA, 
-							 NULL, NULL );
-		if ( ! idal_cache [cachind] ) {
-			printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n");
-		}
-	}
-	
-	return rc;
-}
+        int count = cp->count;
 
-void idal_support_cleanup ( void )
-{
-	int cachind;
-
-	/* Shrink the caches, if available */
-	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
-		if ( idal_cache[cachind] ) {
-			if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) {
-				idal_cache[cachind] = NULL;
-			}
-		}
+	if (cp->flags & CCW_FLAG_IDA)
+		BUG();
+	if (((address + count) >> 31) == 0)
+		cp -> cda = address;
+		return;
+        nridaws = ((address & 2047L) + count + 2047L) >> 11;
+	idal = idal_alloc(nridaws);
+	if ( idal == NULL ) {
+		/* probably we should have a fallback here */
+		panic ("Cannot allocate memory for IDAL\n");
 	}
-
+	cp->flags |= CCW_FLAG_IDA;
+	cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
+        do {
+		*idal++ = address;
+		address = (address & -2048L) + 2048;
+		nridaws --;
+        } while ( nridaws > 0 );
+	return;
 }
+#endif
diff -urN linux-2.2.19-pre13/drivers/s390/misc/Makefile linux/drivers/s390/misc/Makefile
--- linux-2.2.19-pre13/drivers/s390/misc/Makefile	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/misc/Makefile	Mon Dec  3 21:07:27 2001
@@ -2,7 +2,8 @@
 
 CFLAFS += 
 O_TARGET := s390-misc.o
-O_OBJS    :=         
+O_OBJS   :=         
+OX_OBJS  :=         
 M_OBJS   := 
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.19-pre13/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile
--- linux-2.2.19-pre13/drivers/s390/net/Makefile	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/net/Makefile	Mon Dec  3 21:07:27 2001
@@ -2,7 +2,8 @@
 
 CFLAFS += 
 O_TARGET := s390-net.o
-O_OBJS   := iucv.o
+O_OBJS   :=
+OX_OBJS  := iucv.o
 M_OBJS   :=
 
 ifeq ($(CONFIG_CTC),y)
diff -urN linux-2.2.19-pre13/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- linux-2.2.19-pre13/drivers/s390/net/ctc.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/s390/net/ctc.c	Mon Dec  3 21:07:27 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $
+ * $Id: ctc.c,v 1.29 2001/01/25 22:28:21 uweigand Exp $
  *
  *  drivers/s390/net/ctc.c 
  *    CTC / ESCON network driver
@@ -22,12 +22,13 @@
  *    order or doesn't want to have automatic channel selection on, you can do 
  *    this with the "ctc= kernel keyword". 
  *
- *	 ctc=0,0xrrrr,0xwwww,ddddd
+ *	 ctc=prid,0xrrrr,0xwwww,ddddd
  *
  *     Where:
  *
- *	 "rrrr" is the read channel address
- *	 "wwww" is the write channel address
+ *       "prid" is the protocol id (must always be 0)
+ *	 "rrrr" is the read channel address (hexadecimal)
+ *	 "wwww" is the write channel address (hexadecimal)
  *	 "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
  *		to escon7 for ESCON channels).
  *
@@ -38,24 +39,39 @@
  *	 ctc=noauto
  * 
  * $Log: ctc.c,v $
- * Revision 1.25.2.5  2000/10/11 15:08:59  bird
- * ctc_tx(): Quick fix of possible underflow when calculating free block space
+ * Revision 1.29  2001/01/25 22:28:21  uweigand
+ * Minor 2.2.18 fix.
  *
- * Revision 1.25.2.4  2000/09/25 16:40:56  bird
- * Some more debug information
+ * Revision 1.28  2001/01/18 13:04:47  tonn
+ * upgrade to 2.2.18
  *
- * Revision 1.25.2.3  2000/09/20 13:28:19  bird
- * - ctc_open(): fixed bug
- * - ctc_release(): added timer for terminating in case of halt_io()-hang
- *
- * Revision 1.25.2.2  2000/09/20 09:48:27  bird
- * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
- *   instead of direct waiting on a wait queue
- * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
- *   print more debug information
+ * Revision 1.27  2000/10/26 16:16:07  bird
+ * Merged in changes from Revision 1.25.2.1 to Revision 1.25.2.6:
  *
- * Revision 1.25.2.1  2000/09/19 09:09:56  bird
- * Merged in changes from 1.25 to 1.26
+ *   Revision 1.25.2.6  2000/10/25 16:11:55  bird
+ *   Set size of empty block to BLOCK_HEADER_LENGTH (used to be 0)
+ *
+ *   Revision 1.25.2.5  2000/10/11 15:08:59  bird
+ *   ctc_tx(): Quick fix of possible underflow when calculating free block space
+ *
+ *   Revision 1.25.2.4  2000/09/25 16:40:56  bird
+ *   Some more debug information
+ *
+ *   Revision 1.25.2.3  2000/09/20 13:28:19  bird
+ *   - ctc_open(): fixed bug
+ *   - ctc_release(): added timer for terminating in case of halt_io()-hang
+ *
+ *   Revision 1.25.2.2  2000/09/20 09:48:27  bird
+ *   - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
+ *     instead of direct waiting on a wait queue
+ *   - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
+ *     print more debug information
+ *
+ *   Revision 1.25.2.1  2000/09/19 09:09:56  bird
+ *   Merged in changes from 1.25 to 1.26
+ *
+ * Revision 1.26  2000/09/15 12:29:32  weigand
+ * Some 2.3 diffs merged and other fixes.
  *
  * Revision 1.25  2000/09/08 09:22:11  bird
  * Proper cleanup and bugfixes in ctc_probe()
@@ -317,9 +333,9 @@
 #define CTC_BH_ACTIVE	    0	
 	__u8		    last_dstat;
 	__u8		    flag;
-#define CTC_WRITE      0x01      /* - Set if this is a write channel */
+#define CTC_WRITE	     0x01      /* - Set if this is a write channel */
 #define CTC_WAKEUP     0x02      /* - Set if this channel should wake up from waiting for an event */
-#define CTC_TIMER      0x80      /* - Set if timer made the wake_up  */ 
+#define CTC_TIMER	     0x80      /* - Set if timer made the wake_up  */ 
 };
 
 
@@ -350,6 +366,8 @@
 	__u16	      length;
 	struct packet data;
 };
+#define BLOCK_PAGES_POW 4    /* 2^4 = 16 pages per block (64k) */
+#define BLOCK_MAX_DATA 65535 /* maximal amount of data a block can hold */
 
 #if LINUX_VERSION_CODE>=0x02032D
 #define ctc_protect_busy(dev) \
@@ -483,7 +501,7 @@
  */
 static void print_banner(void) {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.25.2.5 $";
+	char vbuf[] = "$Revision: 1.29 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -761,12 +779,12 @@
 	else {	
 		p->next = NULL;	 
 		p->packets = 0;
-		p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+		p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, BLOCK_PAGES_POW);
 		if (p->block == NULL) {
 			kfree(p);
 			return -ENOMEM;
 		}
-		p->block->length = 0; 
+		p->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 	}
    
 	if (ctc->free_anchor == NULL) 
@@ -1107,7 +1125,7 @@
 
 } 
 
- 
+
 static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
 {
 	int		  rc = 0;
@@ -1194,7 +1212,6 @@
 			wake_up(&ctc->wait);   /* wake up ctc_release */
 			return;
  
-
 		case CTC_START_HALT_IO:	 /* HALT_IO issued by ctc_open (start sequence) */
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_HALT_IO");
@@ -1226,7 +1243,6 @@
 				return;
 			ctc->state =  CTC_START_SELECT;
  
-
 		case CTC_START_SELECT:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_SELECT");
@@ -1239,7 +1255,7 @@
 			}
 			if (!(ctc->flag & CTC_WRITE)) {
 				ctc->state = CTC_START_READ_TEST;
-				ctc->free_anchor->block->length = 0;	
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc;
 				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1251,7 +1267,7 @@
 			} else {
 				ctc->state = CTC_START_WRITE_TEST;
 				/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-				ctc->free_anchor->block->length = 0;	
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc; 
@@ -1261,7 +1277,6 @@
 			}
 			return;
 
-
 		case CTC_START_READ_TEST:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ_TEST");
@@ -1298,8 +1313,7 @@
 			/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
 			/* wake_up(&privptr->channel[WRITE].wait);*/  /* wake up ctc_open (WRITE) */
 
-
-		case CTC_START_READ:
+		case CTC_START_READ: 
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ");
 #endif 
@@ -1331,7 +1345,7 @@
 			ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
 
 			if (ctc->free_anchor != NULL) {
-				ctc->free_anchor->block->length = 0;
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc;
 				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1350,7 +1364,6 @@
 			}
 			return;
 
-
 		case CTC_START_WRITE_TEST:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE_TEST");
@@ -1376,7 +1389,6 @@
 			wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
 			return;
  
-
 		case CTC_START_WRITE:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE");
@@ -1392,7 +1404,7 @@
 				privptr->stats.tx_packets += ctc->proc_anchor->packets;
 			} 
 
-			ctc->proc_anchor->block->length = 0;
+			ctc->proc_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 			ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
 			ctc_clearbit_busy(TB_NOBUFFER, dev);	 
 			if (ctc->proc_anchor != NULL) {	 
@@ -1414,7 +1426,7 @@
 							 "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
 				return;
 			}
-			if (ctc->free_anchor->block->length != 0) {
+			if (ctc->free_anchor->block->length != BLOCK_HEADER_LENGTH) { /* non-empty block */
 				if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {	    
 				       /* set transmission to busy */
 					ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
@@ -1468,15 +1480,17 @@
 
 	while (ctc->proc_anchor != NULL) {
 		block = ctc->proc_anchor->block;
-		if (block->length < BLOCK_HEADER_LENGTH) {
-			if(block->length == 0 && !ctc->initial_block_received)
-				ctc->initial_block_received = 1;
-			else
+
+		if ((block->length < BLOCK_HEADER_LENGTH)
+		    || (block->length == BLOCK_HEADER_LENGTH && ctc->initial_block_received)) {
 				printk(KERN_INFO "%s: %s(): discarding block at 0x%p: "
-				       "block length=%d<%d=block header length\n",
+					 "block length=%d<=%d=block header length\n",
 				       dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH);
 		}
-		else {
+		else if(block->length == BLOCK_HEADER_LENGTH && !ctc->initial_block_received) {
+			ctc->initial_block_received = 1;
+		}
+		else { /* there is valid data in the buffer */
 			lp = &block->data;
 			while ((__u8 *) lp < (__u8 *) block + block->length) {
 				if(lp->length < PACKET_HEADER_LENGTH) {
@@ -1557,6 +1571,7 @@
 	       dev->name, ctc->state);
 #endif	
 	s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+
 	if (ctc->state != CTC_STOP) {
 		if (!ctc->free_anchor) {
 			s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
@@ -1566,7 +1581,7 @@
 			return;
 		}
 
-		ctc->free_anchor->block->length = 0;
+		ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 		ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 		parm = (__u32)(long) ctc; 
 		rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
@@ -1634,7 +1649,6 @@
 	struct ctc_priv	   *privptr;
 	struct timer_list  timer;
 
-
 	ctc_set_busy(dev);
 
 	privptr = (struct ctc_priv *) (dev->priv);
@@ -1696,13 +1710,13 @@
 		rc = halt_IO(privptr->channel[i].irq, parm, flags);
 		s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
 
-		wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
-
-		del_timer(&timer);
-
 		if(rc != 0)
 			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
 
+		wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+			del_timer(&timer);
+	
 		if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */
 			for (ii=0; ii<=i; ii++) {
 
@@ -1718,7 +1732,7 @@
 			return -ERESTARTSYS;
 		}
 	}
-	
+
 	if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & 
 	       ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
 	    (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
@@ -1781,7 +1795,7 @@
 	ctc_setbit_busy(TB_STOP,dev);	 
 	ctc_unprotect_busy_irqrestore(dev, saveflags);
 
-	for (i = 0; i < 2;  i++) {
+	for (i = 0; i < 2;  i++) {		  
 		privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER);
 		init_timer(&timer);
 		timer.function = ctc_timer; 
@@ -1803,7 +1817,7 @@
 		if (rc != 0) {
 			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
 		}
-
+		 
 		if(privptr->channel[i].flag & CTC_TIMER)
 		{
 			printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n",
@@ -1872,7 +1886,7 @@
 		goto Done;
 	} 
 
-	if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) {
+	if (privptr->channel[WRITE].free_anchor->block->length + PACKET_HEADER_LENGTH + skb->len > BLOCK_MAX_DATA) {
 #ifdef DEBUG
 		printk(KERN_DEBUG "%s: early swap\n", dev->name);
 #endif
@@ -1885,15 +1899,14 @@
 		}
 	}
 	
-	if (privptr->channel[WRITE].free_anchor->block->length == 0) {
-		privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
+	if (privptr->channel[WRITE].free_anchor->block->length == BLOCK_HEADER_LENGTH) { /* empty block */
 		privptr->channel[WRITE].free_anchor->packets = 0;
 	} 
 
 
 	(__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length;
-	privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
-	lp->length = skb->len + PACKET_HEADER_LENGTH; 
+	privptr->channel[WRITE].free_anchor->block->length += PACKET_HEADER_LENGTH + skb->len;
+	lp->length = PACKET_HEADER_LENGTH + skb->len; 
 	lp->type = 0x0800; 
 	lp->unused = 0;
 	memcpy(&lp->data, skb->data, skb->len); 
diff -urN linux-2.2.19-pre13/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- linux-2.2.19-pre13/drivers/s390/net/iucv.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/net/iucv.c	Mon Dec  3 21:07:27 2001
@@ -9,6 +9,8 @@
  *               Alan Altmark (Alan_Altmark@us.ibm.com)
  */
 
+#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
@@ -28,8 +30,6 @@
 //#define DEBUG         /* Turns Printk's on                         */
 //#define DEBUG2        /* This prints the parameter list before and */
 		      /* after the b2f0 call to cp                 */
-#define EXPORT_SYMTAB
-#include <linux/module.h>
 #undef NULL
 #define NULL 0
 #define ADDED_STOR 64		/* ADDITIONAL STORAGE FOR PATHID @'S */
@@ -1533,7 +1533,7 @@
 {
 	iucv_packet *pkt;
 	pkt = (iucv_packet *) kmalloc
-	    (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC);
+	    (sizeof (iucv_packet), GFP_ATOMIC);
 	if (pkt == NULL) {
 		printk (KERN_DEBUG "out of memory\n");
 		return;
@@ -1869,15 +1869,16 @@
 	new_handler->size = ADDED_STOR;
 	/* Allocate storage for pathid table */
 	new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
-	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
 	if (new_handler->start == NULL) {
 #ifdef DEBUG
 		printk (KERN_DEBUG
 			"IUCV: returned NULL address for pathid table,"
 			" exiting\n");
 #endif
+		kfree(new_handler);
 		return NULL;
 	}
+	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
 	new_handler->end = (*new_handler).start + ADDED_STOR;
 	new_handler->next = 0;
 	new_handler->prev = 0;
diff -urN linux-2.2.19-pre13/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- linux-2.2.19-pre13/drivers/s390/net/netiucv.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/s390/net/netiucv.c	Mon Dec  3 21:07:27 2001
@@ -493,7 +493,7 @@
 	pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
 		  buffer_length);
 
-	buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA);
+	buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA);
 	if (buffer == NULL) {
 		p->stats.rx_dropped++;
 		return;
diff -urN linux-2.2.19-pre13/drivers/usb/hid.c linux/drivers/usb/hid.c
--- linux-2.2.19-pre13/drivers/usb/hid.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/usb/hid.c	Mon Dec  3 21:07:30 2001
@@ -698,7 +698,7 @@
 static __inline__ __u32 s32ton(__s32 value, unsigned n)
 {
 	__s32 a = value >> (n - 1);
-	if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1;
+	if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
 	return value & ((1 << n) - 1);
 }
 
@@ -1016,9 +1016,15 @@
 	__s32 max = field->logical_maximum;
 	__s32 value[count]; /* WARNING: gcc specific */
    
-	for (n = 0; n < count; n++)
+	for (n = 0; n < count; n++) {
 			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : 
 						    extract(data, offset + n * size, size);
+			/* Handle the ErrorRollOver code (1) by simply ignoring this report */
+			if (!(field->flags & HID_MAIN_ITEM_VARIABLE)
+			    && value[n] >= min && value[n] <= max
+			    && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+				return;
+	}
 
 	for (n = 0; n < count; n++) {
 
@@ -1231,7 +1237,7 @@
 
 static int hid_submit_out(struct hid_device *hid)
 {
-	hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length;
+	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
 	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
 	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
 	hid->urbout.dev = hid->dev;
@@ -1271,8 +1277,8 @@
 	hid_set_field(field, offset, value);
 	hid_output_report(field->report, hid->out[hid->outhead].buffer);
 
-	hid->out[hid->outhead].dr.value = 0x200 | field->report->id;
-	hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1;
+	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id);
+	hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3);
 
 	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
@@ -1448,7 +1454,7 @@
 	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
 		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
 		hid->out[n].dr.request = USB_REQ_SET_REPORT;
-		hid->out[n].dr.index = hid->ifnum;
+		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
 	}
 
 	hid->input.name = hid->name;
diff -urN linux-2.2.19-pre13/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- linux-2.2.19-pre13/drivers/usb/serial/Config.in	Mon Dec  3 21:06:43 2001
+++ linux/drivers/usb/serial/Config.in	Mon Dec  3 21:07:30 2001
@@ -22,6 +22,7 @@
      bool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
      bool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
      bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
+     bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
   fi
   dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
diff -urN linux-2.2.19-pre13/drivers/usb/usb.c linux/drivers/usb/usb.c
--- linux-2.2.19-pre13/drivers/usb/usb.c	Mon Dec  3 21:06:43 2001
+++ linux/drivers/usb/usb.c	Mon Dec  3 21:07:30 2001
@@ -501,12 +501,17 @@
 			
 		tmp = tmp->next;
 		down(&driver->serialize);
+		if (usb_interface_claimed(interface)) {
+			up(&driver->serialize);
+			return -1;
+		}
 		private = driver->probe(dev, ifnum);
-		up(&driver->serialize);
-		if (!private)
+		if (!private) {
+			up(&driver->serialize);
 			continue;
+		}
 		usb_driver_claim_interface(driver, interface, private);
-
+		up(&driver->serialize);
 		return 0;
 	}
 	
@@ -754,7 +759,7 @@
 		dbg("unhandled interfaces on device");
 
 	if (!claimed) {
-		warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.",
+		warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.",
 			dev->devnum,
 			dev->descriptor.idVendor,
 			dev->descriptor.idProduct);
diff -urN linux-2.2.19-pre13/drivers/video/promcon.c linux/drivers/video/promcon.c
--- linux-2.2.19-pre13/drivers/video/promcon.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/promcon.c	Mon Dec  3 21:07:30 2001
@@ -1,4 +1,4 @@
-/* $Id: promcon.c,v 1.15 1999/04/22 06:35:32 davem Exp $
+/* $Id: promcon.c,v 1.14 1999/03/09 14:02:42 davem Exp $
  * Console driver utilizing PROM sun terminal emulation
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.2.19-pre13/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.19-pre13/fs/proc/array.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/proc/array.c	Mon Dec  3 21:07:30 2001
@@ -1329,7 +1329,7 @@
 extern int get_ksyms_list(char *, char **, off_t, int);
 #endif
 extern int get_device_list(char *);
-extern int get_partition_list(char *);
+extern int get_partition_list(char *, char **, off_t, int);
 extern int get_filesystem_list(char *);
 extern int get_filesystem_info( char * );
 #ifndef CONFIG_ARCH_S390
@@ -1397,7 +1397,7 @@
 			return get_device_list(page);
 
 		case PROC_PARTITIONS:
-			return get_partition_list(page);
+			return get_partition_list(page, start, offset, length);
 #ifndef CONFIG_ARCH_S390
 		case PROC_INTERRUPTS:
 			return get_irq_list(page);
diff -urN linux-2.2.19-pre13/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- linux-2.2.19-pre13/include/asm-s390/bitops.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/bitops.h	Mon Dec  3 21:07:30 2001
@@ -495,9 +495,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -521,9 +521,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -547,9 +547,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -632,7 +632,7 @@
                 "   lr   2,%1\n"
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
-                "   sll  2,3(0)\n"
+                "   sll  2,3\n"
                 "   tml  1,0xFFFF\n"
                 "   jno  2f\n"
                 "   ahi  2,16\n"
@@ -804,7 +804,7 @@
                 "   lr   2,%1\n"
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
-                "   sll  2,3(0)\n"
+                "   sll  2,3\n"
                 "   lhi  0,0xff\n"
                 "   ahi  2,24\n"
                 "   tmh  1,0xFFFF\n"
diff -urN linux-2.2.19-pre13/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h
--- linux-2.2.19-pre13/include/asm-s390/ccwcache.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/ccwcache.h	Mon Dec  3 21:07:30 2001
@@ -1,5 +1,5 @@
 /* 
-   * File...........: linux/drivers/s390/block/ccwcache.c
+   * File...........: linux/include/asm-s390/ccwcache.h
    * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
    * Bugreports.to..: <Linux390@de.ibm.com>
    * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
@@ -34,7 +34,8 @@
 	devstat_t *dstat;	/* The device status in case of an error */
 
 	/* these are important for recovering erroneous requests */
-	int retries;		/* A retry counter to be set when filling */
+	short retries;		/* A retry counter to be set when filling */
+	char lpm;               /* logical path mask                      */
 	devstat_t *devstat;	/* Keeping the device status */
 	struct ccw_req_t *refers;	/* Does this request refer to another one? */
 	void *function; /* refers to the originating ERP action */ ;
@@ -64,6 +65,7 @@
 #define CQR_STATUS_DONE     0x08	/* request is completed sucessfully */
 #define CQR_STATUS_ERROR    0x10	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x20	/* request is finally failed */
+#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
 #define CQR_STATUS_FINISHED 0x40	/* request is ready for cleanup */
 
 #ifdef __KERNEL__
diff -urN linux-2.2.19-pre13/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- linux-2.2.19-pre13/include/asm-s390/dasd.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/dasd.h	Mon Dec  3 21:07:30 2001
@@ -2,12 +2,15 @@
 #ifndef DASD_H
 #define DASD_H
 
+#undef ERP_DEBUG               /* enable debug messages */
+
 /* First of all the external stuff */
 #include <linux/version.h>
 #include <linux/ioctl.h>
 #include <linux/major.h>
 #include <linux/wait.h>
 #include <asm/ccwcache.h>
+#include <asm/todclk.h>
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #include <linux/blkdev.h> 
 #endif
@@ -65,6 +68,12 @@
 	dasd_era_recover = 2	/* recovery action recommended       */
 } dasd_era_t;
 
+/* BIT DEFINITIONS FOR SENSE DATA */
+#define DASD_SENSE_BIT_0 0x80
+#define DASD_SENSE_BIT_1 0x40
+#define DASD_SENSE_BIT_2 0x20
+#define DASD_SENSE_BIT_3 0x10
+
 /* 
  * struct dasd_sizes_t
  * represents all data needed to access dasd with properly set up sectors
@@ -97,7 +106,7 @@
 struct dasd_device_t;
 
 typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
-typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int);
+typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
 
 typedef int (*dasd_ck_id_fn_t) (dev_info_t *);
 typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
@@ -165,6 +174,7 @@
         struct wait_queue wait;
         struct wait_queue *wait_q;
 #endif /* LINUX_IS_24 */
+        struct timer_list timer;      /* HUM new */
         dasd_sizes_t sizes;
 	devstat_t dev_status;
 	char *characteristics;
@@ -231,6 +241,24 @@
 int dasd_discipline_deq(dasd_discipline_t *);
 int dasd_start_IO (ccw_req_t *);
 void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t *default_erp_action (ccw_req_t *);
+ccw_req_t *default_erp_postaction (ccw_req_t *);
+int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
+ccw_req_t *dasd_alloc_request (char *, int, int);
+void dasd_free_request (ccw_req_t *);
+
+
+#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+do { \
+        int d_devno = d_device->devinfo.devno; \
+        int d_irq = d_device->devinfo.irq; \
+        char *d_name = d_device->name; \
+        int d_major = MAJOR(d_device->kdev); \
+        int d_minor = MINOR(d_device->kdev); \
+        printk(d_loglevel PRINTK_HEADER \
+               "/dev/%s(%d:%d), 0x%04X on SCH 0x%x: " \
+               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
+} while(0)
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.2.19-pre13/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- linux-2.2.19-pre13/include/asm-s390/debug.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/debug.h	Mon Dec  3 21:07:30 2001
@@ -9,42 +9,59 @@
 #ifndef DEBUG_H
 #define DEBUG_H
 
-#ifdef __KERNEL__
+/* Note:
+ * struct __debug_entry must be defined outside of #ifdef __KERNEL__ 
+ * in order to allow a user program to analyze the 'raw'-view.
+ */
+
+struct __debug_entry{
+        union {
+                struct {
+                        unsigned long long clock:52;
+                        unsigned long long exception:1;
+                        unsigned long long level:3;
+                        unsigned long long cpuid:8;
+                } fields;
+
+                unsigned long long stck;
+        } id;
+        void* caller;
+} __attribute__((packed));
+
 
-#include <asm/spinlock.h>
+#define __DEBUG_FEATURE_VERSION      1  /* version of debug feature */
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ #include <asm/spinlock.h>
+#else
+ #include <linux/spinlock.h>
+#endif /* LINUX_VERSION_CODE */
 #include <linux/kernel.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
 
-#define DEBUG_MAX_AREAS            16 /* max number of allowed registers */
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
+#define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
 #define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
 
+#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
+                                             /* the entry information */
+
 #define STCK(x)	asm volatile ("STCK %0":"=m" (x))
 
-typedef struct {
-	union {
-		struct {
-			unsigned long long clock:52;
-			unsigned long long unused:2;
-			unsigned long long cpuid:8;
-			unsigned long long exception:1;
-			unsigned long long used:1;
-		} fields;
-
-		unsigned long long stck;
-	} id;
-	void* caller;
-	char data[4];
-} debug_entry_t;
+typedef struct __debug_entry debug_entry_t;
 
 struct debug_view;
 
-typedef struct {	
+typedef struct debug_info {	
+	struct debug_info* next;
+	struct debug_info* prev;
 	atomic_t ref_count;
 	spinlock_t lock;			
 	int level;
@@ -54,7 +71,7 @@
 	int entry_size;	
 	debug_entry_t** areas;
 	int active_area;
-	int active_entry[DEBUG_MAX_AREAS];
+	int *active_entry;
 	struct proc_dir_entry* proc_root_entry;
 	struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
 	struct debug_view* views[DEBUG_MAX_VIEWS];	
@@ -87,29 +104,97 @@
 	debug_header_proc_t* header_proc;
 	debug_format_proc_t* format_proc;
 	debug_input_proc_t*  input_proc;
+	void*                private_data;
 };
 
-extern struct debug_view debug_ascii_view;
-extern struct debug_view debug_ebcdic_view;
-extern struct debug_view debug_hex_view;
+extern struct debug_view debug_hex_ascii_view;
+extern struct debug_view debug_raw_view;
+extern struct debug_view debug_sprintf_view;
+
+/* do NOT use the _common functions */
+
+debug_entry_t* debug_event_common(debug_info_t* id, int level, 
+                                  const void* data, int length);
+
+debug_entry_t* debug_exception_common(debug_info_t* id, int level, 
+                                      const void* data, int length);
+
+/* Debug Feature API: */
 
 debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
-			     int buf_size);
+                             int buf_size);
+
 void debug_unregister(debug_info_t* id);
 
-debug_entry_t* debug_event(debug_info_t* id, int level, void* data,
-			   int length);
-debug_entry_t* debug_int_event(debug_info_t* id, int level,
-			       unsigned int tag);
-debug_entry_t* debug_text_event(debug_info_t* id, int level,
-				const char* txt);
-
-debug_entry_t* debug_exception(debug_info_t* id, int level, void* data,
-			       int length);
-debug_entry_t* debug_int_exception(debug_info_t* id, int level,
-				   unsigned int tag);
-debug_entry_t* debug_text_exception(debug_info_t* id, int level,
-				    const char* txt);
+void debug_set_level(debug_info_t* id, int new_level);
+
+extern inline debug_entry_t* 
+debug_event(debug_info_t* id, int level, void* data, int length)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,data,length);
+}
+
+extern inline debug_entry_t* 
+debug_int_event(debug_info_t* id, int level, unsigned int tag)
+{
+        unsigned int t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,&t,sizeof(unsigned int));
+}
+
+extern inline debug_entry_t *
+debug_long_event (debug_info_t* id, int level, unsigned long tag)
+{
+        unsigned long t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,&t,sizeof(unsigned long));
+}
+
+extern inline debug_entry_t* 
+debug_text_event(debug_info_t* id, int level, const char* txt)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,txt,strlen(txt));
+}
+
+extern debug_entry_t *
+debug_sprintf_event(debug_info_t* id,int level,char *string,...);
+
+
+extern inline debug_entry_t* 
+debug_exception(debug_info_t* id, int level, void* data, int length)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,data,length);
+}
+
+extern inline debug_entry_t* 
+debug_int_exception(debug_info_t* id, int level, unsigned int tag)
+{
+        unsigned int t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,&t,sizeof(unsigned int));
+}
+
+extern inline debug_entry_t * 
+debug_long_exception (debug_info_t* id, int level, unsigned long tag)
+{
+        unsigned long t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,&t,sizeof(unsigned long));
+}
+
+extern inline debug_entry_t* 
+debug_text_exception(debug_info_t* id, int level, const char* txt)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,txt,strlen(txt));
+}
+
+
+extern debug_entry_t *
+debug_sprintf_exception(debug_info_t* id,int level,char *string,...);
 
 int debug_register_view(debug_info_t* id, struct debug_view* view);
 int debug_unregister_view(debug_info_t* id, struct debug_view* view);
diff -urN linux-2.2.19-pre13/include/asm-s390/elf.h linux/include/asm-s390/elf.h
--- linux-2.2.19-pre13/include/asm-s390/elf.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/elf.h	Mon Dec  3 21:07:30 2001
@@ -22,7 +22,8 @@
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
-#define elf_check_arch(x) ((x) == EM_S390) 
+#define elf_check_arch(x) \
+        ((x) == EM_S390 || (x) == EM_S390_OLD)
 
 /*
  * These are used to set parameters in the core dumps.
diff -urN linux-2.2.19-pre13/include/asm-s390/idals.h linux/include/asm-s390/idals.h
--- linux-2.2.19-pre13/include/asm-s390/idals.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/idals.h	Mon Dec  3 21:07:30 2001
@@ -7,19 +7,50 @@
    * History of changes
    * 07/24/00 new file
  */
-
-#define IDAL_NUMBER_CACHES 7
+#include <asm/irq.h>
 
 typedef unsigned long idaw_t;
 
-#ifdef CONFIG_ARCH_S390
-extern inline int 
-normalize_cpa(ccw1_t * ccw, unsigned long address)
+static inline idaw_t *
+idal_alloc ( int nridaws )
 {
-	return address;
+	if ( nridaws > 33 )
+		BUG();
+	return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
 }
+
+static inline void 
+idal_free ( idaw_t *idal )
+{
+	kfree (idal);
+}
+
+/*
+ * Function: set_normalized_cda
+ * sets the address of the data in CCW
+ * if necessary it allocates an IDAL and sets sthe appropriate flags
+ */
+#if defined (CONFIG_ARCH_S390)
+static inline void
+set_normalized_cda(ccw1_t * ccw, unsigned long address)
+{
+	ccw->cda = address;
+}
+#elif defined (CONFIG_ARCH_S390X)
+extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
 #endif
 
-int idal_alloc ( int nridaws );
-void idal_release ( idaw_t *idal );
+/*
+ * Function: clear_normalized_cda
+ * releases any allocated IDAL related to the CCW
+ */
+static inline void
+clear_normalized_cda ( ccw1_t * ccw ) 
+{
+	if ( ccw -> flags & CCW_FLAG_IDA ) {
+		idal_free ( (idaw_t *) (ccw -> cda ));
+		ccw -> flags &= ~CCW_FLAG_IDA;
+	}
+	ccw -> cda = 0;
+}
 
diff -urN linux-2.2.19-pre13/include/asm-s390/io.h linux/include/asm-s390/io.h
--- linux-2.2.19-pre13/include/asm-s390/io.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/io.h	Mon Dec  3 21:07:30 2001
@@ -25,7 +25,7 @@
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
 	unsigned long real_address;
-	__asm__ ("   lra    %0,0(0,%1)\n"
+	__asm__ ("   lra    %0,0(%1)\n"
                  "   jz     0f\n"
                  "   sr     %0,%0\n"
                  "0:"
diff -urN linux-2.2.19-pre13/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- linux-2.2.19-pre13/include/asm-s390/irq.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/irq.h	Mon Dec  3 21:07:30 2001
@@ -183,6 +183,33 @@
 #define SNS0_EQUIPMENT_CHECK    0x10
 #define SNS0_DATA_CHECK         0x08
 #define SNS0_OVERRUN            0x04
+/*                              0x02 reserved */
+#define SNS0_INCOMPL_DOMAIN     0x01
+
+/*
+ * architectured values for second sense byte
+ */
+#define SNS1_PERM_ERR           0x80
+#define SNS1_INV_TRACK_FORMAT   0x40
+#define SNS1_EOC                0x20
+#define SNS1_MESSAGE_TO_OPER    0x10
+#define SNS1_NO_REC_FOUND       0x08
+#define SNS1_FILE_PROTECTED     0x04
+#define SNS1_WRITE_INHIBITED    0x02
+#define SNS1_INPRECISE_END      0x01
+
+/*
+ * architectured values for third sense byte
+ */
+#define SNS2_REQ_INH_WRITE      0x80
+#define SNS2_CORRECTABLE        0x40
+#define SNS2_FIRST_LOG_ERR      0x20
+#define SNS2_ENV_DATA_PRESENT   0x10
+/*                              0x08 reserved */
+#define SNS2_INPRECISE_END      0x04
+/*                              0x02 reserved */
+/*                              0x01 reserved */
+
 
 /*
  * operation request block
@@ -319,6 +346,7 @@
 #define CIW_TYPE_SII    0x1    // set interface identifier
 #define CIW_TYPE_RNI    0x2    // read node identifier
 
+#define MAX_CIWS 8
 //
 // sense-id response buffer layout
 //
@@ -331,7 +359,7 @@
       __u8           dev_model;    /* device model */
       __u8           unused;       /* padding byte */
   /* extended part */
-      ciw_t    ciw[16];            /* variable # of CIWs */
+      ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
 #endif /* __KERNEL__ */
@@ -383,6 +411,7 @@
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
+
 #ifdef __KERNEL__
 
 typedef  void (* io_handler_func1_t) ( int             irq,
@@ -543,7 +572,7 @@
                               not_oper_handler_func_t  not_oper_handler,
                               unsigned long            irqflags,
                               const char              *devname,
-                              void                    *dev_id);
+                              devstat_t               *dev_id);
 
 extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *);
 
@@ -809,7 +838,7 @@
 {
         if (prof_buffer && current->pid) {
                 addr &= 0x7fffffff;
-                addr -= (unsigned long)&_stext;
+                addr -= (unsigned long) &_stext;
                 addr >>= prof_shift;
                 /*
                  * Don't ignore out-of-bounds EIP values silently,
@@ -832,8 +861,10 @@
 
 #define s390irq_spin_lock_irqsave(irq,flags) \
         spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
+
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
 #endif /* __KERNEL__ */
+
 #endif
 
diff -urN linux-2.2.19-pre13/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- linux-2.2.19-pre13/include/asm-s390/pgtable.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/pgtable.h	Mon Dec  3 21:07:30 2001
@@ -546,7 +546,7 @@
 extern __inline__ pgd_t* get_pgd_slow(void)
 {
         int i;
-        pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
+        pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1);
 	if (ret)
 		for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++)
 			pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE));
@@ -560,17 +560,7 @@
         if((ret = pgd_quicklist) != NULL) {
                 pgd_quicklist = (unsigned long *)(*ret);
                 ret[0] = ret[1];
-                pgtable_cache_size--;
-		/*
-		 * Need to flush tlb, since private page tables
-		 * are unique thru address of pgd and virtual address.
-		 * If we reuse pgd we need to be sure no tlb entry
-		 * with that pdg is left -> global flush
-		 *
-		 * Fixme: To avoid this global flush we should
-		 * use pdg_quicklist as fix lenght fifo list
-		 * and not as stack
-		 */
+                pgtable_cache_size -= 2;
         } else
                 ret = (unsigned long *)get_pgd_slow();
         return (pgd_t *)ret;
@@ -580,12 +570,12 @@
 {
         *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
         pgd_quicklist = (unsigned long *) pgd;
-        pgtable_cache_size++;
+        pgtable_cache_size += 2;
 }
 
 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-        free_pages((unsigned long)pgd,2);
+        free_pages((unsigned long)pgd, 1);
 }
 
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
diff -urN linux-2.2.19-pre13/include/asm-s390/system.h linux/include/asm-s390/system.h
--- linux-2.2.19-pre13/include/asm-s390/system.h	Sun Dec 10 16:49:44 2000
+++ linux/include/asm-s390/system.h	Mon Dec  3 21:07:30 2001
@@ -33,14 +33,14 @@
                                 "   nr    1,%0\n"     /* isolate last 2 bits */
                                 "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
-                                "   icm   1,8,%1\n"   /* for ptr&3 == 0 */
-                                "   stcm  0,8,%1\n"
-                                "   icm   1,4,%1\n"   /* for ptr&3 == 1 */
-                                "   stcm  0,4,%1\n"
-                                "   icm   1,2,%1\n"   /* for ptr&3 == 2 */
-                                "   stcm  0,2,%1\n"
-                                "   icm   1,1,%1\n"   /* for ptr&3 == 3 */
-                                "   stcm  0,1,%1\n"
+                                "   icm   1,8,3(%1)\n"   /* for ptr&3 == 0 */
+                                "   stcm  0,8,3(%1)\n"
+                                "   icm   1,4,3(%1)\n"   /* for ptr&3 == 1 */
+                                "   stcm  0,4,3(%1)\n"
+                                "   icm   1,2,3(%1)\n"   /* for ptr&3 == 2 */
+                                "   stcm  0,2,3(%1)\n"
+                                "   icm   1,1,3(%1)\n"   /* for ptr&3 == 3 */
+                                "   stcm  0,1,3(%1)\n"
                                 "0: sll   1,3\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
                                 "   l     0,0(%0)\n"  /* get fullword */
@@ -49,8 +49,9 @@
                                 "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr), "+m" (x) :
+                                : "+a&" (ptr) : "a" (&x)
                                 : "memory", "0", "1", "2");
+			break;
                 case 2:
                         if(((__u32)ptr)&1)
                                 panic("misaligned (__u16 *) in __xchg\n");
@@ -59,10 +60,10 @@
                                 "   nr    1,%0\n"     /* isolate bit 2^1 */
                                 "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
-                                "   icm   1,12,%1\n"   /* for ptr&2 == 0 */
-                                "   stcm  0,12,%1\n"
-                                "   icm   1,3,%1\n"    /* for ptr&2 == 1 */
-                                "   stcm  0,3,%1\n"
+                                "   icm   1,12,2(%1)\n"   /* for ptr&2 == 0 */
+                                "   stcm  0,12,2(%1)\n"
+                                "   icm   1,3,2(%1)\n"    /* for ptr&2 == 1 */
+                                "   stcm  0,3,2(%1)\n"
                                 "0: sll   1,2\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
                                 "   l     0,0(%0)\n"  /* get fullword */
@@ -71,7 +72,7 @@
                                 "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr), "+m" (x) :
+                                : "+a&" (ptr) : "a" (&x)
                                 : "memory", "0", "1", "2");
                         break;
                 case 4:
diff -urN linux-2.2.19-pre13/include/asm-s390/todclk.h linux/include/asm-s390/todclk.h
--- linux-2.2.19-pre13/include/asm-s390/todclk.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/todclk.h	Mon Dec  3 21:07:30 2001
@@ -0,0 +1,19 @@
+/*
+ * File...........: linux/include/asm/todclk.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef __ASM_TODCLK_H
+#define __ASM_TODCLK_H
+
+#define TOD_uSEC (0x1000ULL)
+#define TOD_mSEC (1000 * TOD_uSEC)
+#define TOD_SEC (1000 * TOD_mSEC)
+#define TOD_MIN (60 * TOD_SEC)
+#define TOD_HOUR (60 * TOD_MIN)
+
+#endif
diff -urN linux-2.2.19-pre13/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- linux-2.2.19-pre13/include/asm-sparc/page.h	Wed Mar 10 16:53:37 1999
+++ linux/include/asm-sparc/page.h	Mon Dec  3 21:07:30 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.43 1998/05/11 08:40:11 davem Exp $
+/* $Id: page.h,v 1.43.2.1 2001/02/20 04:21:45 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -27,6 +27,10 @@
 #define TASK_UNION_SIZE		8192
 
 #ifndef __ASSEMBLY__
+
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \
+} while (0)
 
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
diff -urN linux-2.2.19-pre13/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- linux-2.2.19-pre13/include/asm-sparc64/page.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc64/page.h	Mon Dec  3 21:07:30 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
+/* $Id: page.h,v 1.24.2.1 2001/02/20 04:21:45 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -17,6 +17,8 @@
 #ifdef __KERNEL__
 
 #ifndef __ASSEMBLY__
+
+#define BUG()		__builtin_trap()
 
 extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
diff -urN linux-2.2.19-pre13/include/linux/blk.h linux/include/linux/blk.h
--- linux-2.2.19-pre13/include/linux/blk.h	Mon Dec  3 21:06:44 2001
+++ linux/include/linux/blk.h	Mon Dec  3 21:07:30 2001
@@ -397,7 +397,7 @@
 #define LOCAL_END_REQUEST
 #define DEVICE_NAME "dasd"
 #define DEVICE_REQUEST do_dasd_request
-#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device) (MINOR(device) >> DASD_PARTN_BITS)
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
diff -urN linux-2.2.19-pre13/include/linux/elf.h linux/include/linux/elf.h
--- linux-2.2.19-pre13/include/linux/elf.h	Tue Jan  4 10:12:24 2000
+++ linux/include/linux/elf.h	Mon Dec  3 21:07:30 2001
@@ -68,6 +68,8 @@
 
 #define EM_SPARCV9     43	/* SPARC v9 64-bit */
 
+#define EM_S390        22	/* IBM S/390 */
+
 /*
  * This is an interim value that we will use until the committee comes
  * up with a final number.
@@ -75,9 +77,9 @@
 #define EM_ALPHA	0x9026
 
 /*
- * This is an interim value for S390 architecture
+ * This is the old interim value for S/390 architecture
  */
-#define EM_S390         0xA390
+#define EM_S390_OLD     0xA390
 
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
diff -urN linux-2.2.19-pre13/init/main.c linux/init/main.c
--- linux-2.2.19-pre13/init/main.c	Mon Dec  3 21:06:44 2001
+++ linux/init/main.c	Mon Dec  3 21:07:31 2001
@@ -203,9 +203,6 @@
 #ifdef CONFIG_MDISK
 extern void mdisk_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_DASD
-extern void dasd_setup(char *str, int *ints);
-#endif
 #ifdef CONFIG_BLK_DEV_XPRAM
 extern void xpram_setup(char *str, int *ints);
 #endif
@@ -1110,9 +1107,6 @@
 #endif
 #ifdef CONFIG_MDISK
         { "mdisk=", mdisk_setup },
-#endif
-#ifdef CONFIG_DASD
-        { "dasd=", dasd_setup },
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
         { "xpram_parts=", xpram_setup },
diff -urN linux-2.2.19-pre13/net/core/filter.c linux/net/core/filter.c
--- linux-2.2.19-pre13/net/core/filter.c	Wed May  3 17:16:53 2000
+++ linux/net/core/filter.c	Mon Dec  3 21:07:31 2001
@@ -196,7 +196,7 @@
 			case BPF_LD|BPF_W|BPF_ABS:
 				k = fentry->k;
 load_w:
-				if(k+sizeof(u32) <= len) {
+				if((unsigned int)(k+sizeof(u32)) <= len) {
 					A = ntohl(*(u32*)&data[k]);
 					continue;
 				}
@@ -215,7 +215,7 @@
 			case BPF_LD|BPF_H|BPF_ABS:
 				k = fentry->k;
 load_h:
-				if(k + sizeof(u16) <= len) {
+				if((unsigned int) (k + sizeof(u16)) <= len) {
 					A = ntohs(*(u16*)&data[k]);
 					continue;
 				}
@@ -234,7 +234,7 @@
 			case BPF_LD|BPF_B|BPF_ABS:
 				k = fentry->k;
 load_b:
-				if(k < len) {
+				if((unsigned int)k < len) {
 					A = data[k];
 					continue;
 				}
@@ -271,7 +271,7 @@
 
 			case BPF_LDX|BPF_B|BPF_MSH:
 				k = fentry->k;
-				if(k >= len)
+				if((unsigned int)k >= len)
 					return (0);
 				X = (data[k] & 0xf) << 2;
 				continue;
diff -urN linux-2.2.19-pre13/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- linux-2.2.19-pre13/net/ipv6/ipv6_sockglue.c	Mon Dec  3 21:06:44 2001
+++ linux/net/ipv6/ipv6_sockglue.c	Mon Dec  3 21:07:31 2001
@@ -230,6 +230,10 @@
 
 		if (optlen == 0)
 			goto update;
+		
+		retv = -EINVAL;
+		if(optlen > 1024)
+			break;
 
 		opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
 		retv = -ENOBUFS;
diff -urN linux-2.2.19-pre13/scripts/makelst linux/scripts/makelst
--- linux-2.2.19-pre13/scripts/makelst	Mon Sep  4 10:39:29 2000
+++ linux/scripts/makelst	Mon Dec  3 21:07:31 2001
@@ -2,7 +2,8 @@
 # A script to dump mixed source code & assembly
 # with correct relocations from System.map
 # Requires the following lines in Rules.make.
-#
+# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+#            William Stearns <wstearns@pobox.com>
 #%.lst: %.c
 #	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
 #	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
@@ -16,6 +17,6 @@
 t3=`grep $t2 $2/System.map`
 t4=`echo $t3 | gawk '{ print $1 }'`
 t5=`echo $t1 | gawk '{ print $1 }'`
-t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g`
+t6=`echo $t4 - $t5 | sed -e s/a/A/g -e s/b/B/g -e s/c/C/g -e s/d/D/g -e s/e/E/g -e s/f/F/g`
 t7=`( echo  ibase=16 ; echo $t6 ) | bc`
 $3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
