diff -u --recursive --new-file linux-2.0.26.org/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax
--- linux-2.0.26.org/Documentation/isdn/README.HiSax	Thu Jan  1 01:00:00 1970
+++ linux/Documentation/isdn/README.HiSax	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,162 @@
+
+HiSax is a Linux hardware level driver for passive ISDN cards with Siemens
+chipset (ISAC_S 2085/2086/2186 HSCX SAB 82525). It is based on the Teles
+driver from Jan den Ouden.
+It is meant to be used with isdn4isdn4linux, an ISDN Link-level module 
+for Linux written by Fritz Elfert.
+
+Supported Cards
+---------------
+
+Teles 8.0/16.0/16.3 (not PNP) and compatible
+Creatix PNP S0
+AVM A1 (Fritz)
+ELSA Microlink PCC-16 PCF PCF-Pro PCC-8
+
+Note: PCF PCF-Pro only the ISDN part is supported yet
+      PCC-8 not tested yet
+
+If you know other passive cards with Siemens chipset, please let me know.
+To use the PNP cards you need the isapnptools.
+
+
+Configuring the Driver
+----------------------
+
+The driver can be build direct into the kernel or as module.
+The HiSax driver can be configured using the commandline-feature
+while loading the kernel with LILO or LOADLIN or if build as module
+using insmod/modprobe with parameters.
+
+LILO/LOADLIN:
+
+hisax=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... ,pa_n,pb_n,pc_n][,idstring]
+
+insmod/modprobe
+
+insmod hisax.o \
+  io=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... ,pa_n,pb_n,pc_n] \
+     [HiSax_id=idstring]
+
+where
+     typ1 = Cardtype of 1st card. (default: 1 = Teles 16.0)
+     dp1  = D-channel protocol of 1st card. 1=1TR6, 2=EDSS1 (default: 2)
+     pa_1 = 1. parameter (depend on the cardtype) (default: 15 (irq))
+     pb_1 = 2. parameter (depend on the cardtype) (default: 0xD0000)					
+     pc_1 = 3. parameter (depend on the cardtype) (default: 0xD80)					
+
+     typ2,dp2,pa_2,pb_2,pc_2 = Parameters of second card   (defaults: none)
+     typn,dpn,pa_n,pb_n,pc_n = Parameters of n'th card (up to 16 cards are supported)
+
+     idstring = Driver-Id for accessing with utilities and identification
+                when using a Line-monitor. (default: none)
+                idstring must start with a character!
+
+     Cardtypes:
+
+   typ  
+    1 	Teles 16.0      pa=irq	pb=membase	pc=iobase
+    2 	Teles  8.0      pa=irq	pb=membase
+    3 	Teles 16.3      pa=irq	pb=iobase
+    4 	Creatix PNP     pa=irq	pb=IO0 (ISAC)	pc=IO1 (HSCX)
+    5 	AVM A1 (Fritz)  pa=irq	pb=iobase
+    6 	ELSA Cards      pa=iobase or nothing for autodetect (the iobase is
+                           only required, if you have more as one ELSA card
+			   in your PC)
+	
+If you use more as one card set unused parameter to zero.
+In the moment is no IRQ sharing possible.
+Please be sure that you IRQ is free and enabled for ISA use.
+
+Examples for module loading
+1. Teles 16.3 Euro ISDN Jumper 280 hex IRQ 10
+modprobe hisax io=3,2,10,0x280
+
+2. Teles 16.0 1TR6 ISDN Jumper d80 hex IRQ 5 Memory d0000 hex
+modprobe hisax io=1,1,5,0xd0000,0xd80
+
+3. Fritzcard Jumper EURO 340 hex IRQ 10 und ELSA PCF EURO
+modprobe hisax io=5,2,10,0x340,0,6,2
+
+Running
+-------
+
+When you insmod isdn.o and hisax.o (or with the kernel-version, during 
+boottime) a few lines should appear in your syslog. Look for something like:
+
+Oct 13 20:46:39 kke01 kernel: ISDN subsystem Rev: 1.23/1.21/1.18/1.13/none loaded
+Oct 13 20:46:41 kke01 kernel: HiSax: Driver for Siemens Chipset ISDN cards
+Oct 13 20:46:41 kke01 kernel: HiSax: Revision (1.3)
+Oct 13 20:46:41 kke01 kernel: HiSax: Total 1 card defined
+Oct 13 20:46:41 kke01 kernel: HiSax: Card 1 Protocol EDSS1
+...
+Oct 13 20:46:41 kke01 kernel: Elsa: PCC16 found at 0x360 Rev.:B IRQ 9
+...
+Oct 13 20:46:41 kke01 kernel: HiSax: 2 channels available
+Oct 13 20:46:41 kke01 kernel: HiSax: module installed
+
+This means that the card is ready for use.
+Cabling problems or line downs are not detected, ELSA can detect the
+S0 power.
+
+Remember, that according to the new strategy for accessing Low-level-drivers
+from within isdn4linux you should also define a driver-id while doing
+insmod: Simply append hisax_id=<SomeString> to the insmod-commandline. This
+string MUST NOT start with a digit or a small 'x'!
+
+At this point you can run a 'cat /dev/isdnctrl0' and view debugging 
+messages. 
+In the moment debugging messages are enabled with the telesctrl tool : 
+
+    telesctrl <DriverId> 1 <debugging_flags>  
+
+<DriverId> default is line0, if you didn't specified one.
+
+where <debugging_flags> is the integer sum of the following debugging
+options you wish enabled:
+
+	1   Link-level <--> Hardware-level communication
+	2   Top state machine 
+	4   D channel Q.931 (call control messages)
+	8   D channel Q.921 
+	16  B channel X.75
+	32  unused
+	64  LOCK debug in callc.c
+
+For example 'telesctrl line0 1 31' enables full debugging.
+
+
+
+Warning
+-------
+HiSax is a work in progress and may crash your machine. It has not been
+certified and therefore operation on your PTT's ISDN network is probably
+illegal.
+
+Limitations
+-----------
+HiSax only works on Euro ISDN lines and german 1TR6-lines.(in this time)
+
+Bugs 
+----
+If you find any please let me know. 
+
+Thanks
+------
+Special thanks to:
+
+	Emil Stephan for the name HiSax which is a mix of HSCX and ISAC.
+
+	Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein, 
+	Andreas Kool 
+	and more people, who are hunting bugs
+
+	Firma ELSA GmbH
+	
+	My girl friend and partner in life Ute for her patience with me
+
+
+Enjoy,
+
+Karsten Keil   
+keil@temic-ech.spacenet.de
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- linux-2.0.26.org/drivers/isdn/Config.in	Fri Nov 22 19:21:20 1996
+++ linux/drivers/isdn/Config.in	Fri Nov 22 19:06:39 1996
@@ -12,3 +12,12 @@
 dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
 dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
 dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+    bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
+    bool 'HiSax Support for Teles 16.3 or PNP' CONFIG_HISAX_16_3
+    bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+    bool 'HiSax Support for Elsa ML PCC16/PCC8' CONFIG_HISAX_ELSA_PCC
+    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+    bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+fi
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/Makefile linux/drivers/isdn/Makefile
--- linux-2.0.26.org/drivers/isdn/Makefile	Fri Nov 22 19:21:20 1996
+++ linux/drivers/isdn/Makefile	Fri Nov 22 19:06:39 1996
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit
+ALL_SUB_DIRS := icn teles pcbit hisax
 
 L_OBJS :=
 LX_OBJS :=
@@ -43,6 +43,16 @@
 else
   ifeq ($(CONFIG_ISDN_DRV_TELES),m)
     MOD_SUB_DIRS += teles
+  endif
+endif
+
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+  L_OBJS += hisax/hisax.o
+  SUB_DIRS += hisax
+  MOD_SUB_DIRS += hisax
+else
+  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+    MOD_SUB_DIRS += hisax
   endif
 endif
 
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- linux-2.0.26.org/drivers/isdn/hisax/Makefile	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/Makefile	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,42 @@
+L_OBJS :=
+M_OBJS :=
+O_OBJS := isdnl1.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
+          llglue.o q931.o callc.o fsm.o
+
+# EXTRA_CFLAGS += -S
+
+ifeq ($(CONFIG_HISAX_EURO),y)
+	 O_OBJS += l3dss1.o
+endif
+
+ifeq ($(CONFIG_HISAX_1TR6),y)
+	 O_OBJS += l3_1tr6.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_0),y)
+	 O_OBJS += teles0.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_3),y)
+	 O_OBJS += teles3.o
+endif
+
+ifeq ($(CONFIG_HISAX_AVM_A1),y)
+	 O_OBJS += avm_a1.o
+endif
+
+ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
+	 O_OBJS += elsa.o
+endif
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+  O_TARGET += hisax.o
+else
+  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+    O_TARGET += hisax.o
+    M_OBJS += hisax.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- linux-2.0.26.org/drivers/isdn/hisax/avm_a1.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/avm_a1.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,977 @@
+/* $Id: avm_a1.c,v 1.2 1996/10/27 22:07:31 keil Exp $
+ *
+ * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * 
+ * $Log: avm_a1.c,v $
+ * Revision 1.2  1996/10/27 22:07:31  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:49  keil
+ * Initial revision
+ *
+ *
+*/
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "avm_a1.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const   char    *CardType[];
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline byte
+readreg(unsigned int adr, byte off)
+{
+        return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, byte off, byte data)
+{
+	byteout(adr +off , data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, byte * data, int size)
+{
+	insb(adr - 0x400 , data, size);
+}
+        
+static void
+write_fifo(unsigned int adr, byte * data, int size)
+{
+	outsb(adr -0x400 , data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+	int            to = 50;
+
+	while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "AVM A1: waitforCEC timeout\n");
+}
+
+    
+static inline void
+waitforXFW(int adr)
+{
+	int            to = 50;
+
+	while ((!(readreg(adr, HSCX_STAR) & 0x44)==0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "AVM A1: waitforXFW timeout\n");
+}
+static inline void
+writehscxCMDR(int adr, byte data)
+{
+	long            flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr);
+	writereg(adr, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+        printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+avm_a1_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	byte			*ptr;
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh = hsp->rcvibh;
+	long 			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
+					      HSCX_RBUF_BPPS)) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->rcvptr;
+
+	hsp->rcvptr += count;
+	save_flags(flags);
+	cli();
+        read_fifo(sp->hscx[hsp->hscx], ptr, count);
+        writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_empty_fifo %c cnt %d",
+			hsp->hscx?'B':'A',count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh;
+	int			more, count;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	ibh = hsp->xmtibh;
+	if (!ibh)
+                return;
+
+	count = ibh->datasize - hsp->sendptr;
+	if (count <= 0)
+                return;
+
+	more = (hsp->mode == 1)?1:0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->sendptr;
+	hsp->sendptr += count;
+
+        waitforXFW(sp->hscx[hsp->hscx]);
+	save_flags(flags);
+	cli();
+        write_fifo(sp->hscx[hsp->hscx], ptr, count);
+        writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_fill_fifo %c cnt %d",
+			hsp->hscx?'B':'A', count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
+{
+	byte             r;
+	struct HscxState *hsp = sp->hs + hscx;
+	int              count, err;
+	char		 tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode) 
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			if (hsp->rcvibh)
+				BufPoolRelease(hsp->rcvibh);
+			hsp->rcvibh = NULL;
+			writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+			goto afterRME;
+		}
+		if (!hsp->rcvibh)
+			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+                                       GFP_ATOMIC, (void *) 1, 1)) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RME out of buffers");
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+				goto afterRME;
+			} else
+				hsp->rcvptr = 0;
+
+		count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		hscx_empty_fifo(hsp, count);
+		hsp->rcvibh->datasize = hsp->rcvptr - 1;
+		BufQueueLink(&hsp->rq, hsp->rcvibh);
+		hsp->rcvibh = NULL;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+      afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!hsp->rcvibh) {
+			if (hsp->mode == 1)
+				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
+					GFP_ATOMIC, (void *)1, 2);
+			else
+				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+					GFP_ATOMIC, (void *)1, 2);
+			
+			if (err) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RPF out of buffers");
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+				goto afterRPF;
+			} else
+				hsp->rcvptr = 0;
+		}
+		
+		hscx_empty_fifo(hsp, 32);
+                if (hsp->mode == 1) {
+                        /* receive audio data */
+                        hsp->rcvibh->datasize = hsp->rcvptr;
+                        BufQueueLink(&hsp->rq, hsp->rcvibh);
+                        hsp->rcvibh = NULL;
+                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+                }
+                
+	}
+      afterRPF:
+	if (val & 0x10) {	/* XPR */
+		if (hsp->xmtibh)
+			if (hsp->xmtibh->datasize > hsp->sendptr) {
+				hscx_fill_fifo(hsp);
+				goto afterXPR;
+			} else {
+				if (hsp->releasebuf)
+					BufPoolRelease(hsp->xmtibh);
+				hsp->sendptr = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->xmtibh = NULL;
+			}
+		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
+			hsp->releasebuf = !0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+      afterXPR:
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	byte			*ptr;
+	struct BufHeader	*ibh = sp->rcvibh;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+	if (sp->debug & L1_DEB_ISAC)
+        	debugl1(sp, "isac_empty_fifo"); 
+
+	if (sp->rcvptr >= 3072) {
+		if (sp->debug & L1_DEB_WARN) {
+			char		 tmp[40];
+			sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
+        		debugl1(sp, tmp); 
+		}
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->rcvptr;
+	sp->rcvptr += count;
+
+	save_flags(flags);
+	cli();
+        read_fifo(sp->isac, ptr, count);
+        writereg(sp->isac, ISAC_CMDR, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_empty_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	struct BufHeader	*ibh;
+	int			count, more;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_fill_fifo"); 
+
+	ibh = sp->xmtibh;
+	if (!ibh)
+		return;
+
+	count = ibh->datasize - sp->sendptr;
+	if (count <= 0)
+		return;
+	if (count >= 3072)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->sendptr;
+	sp->sendptr += count;
+
+	save_flags(flags);
+	cli();
+	write_fifo(sp->isac, ptr, count);
+        writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_fill_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char	tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+        	debugl1(sp, tmp);
+        } 
+	writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, byte val) {
+	byte		exval;
+	unsigned int    count;
+	char		tmp[32];    
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+        	debugl1(sp, tmp); 
+        }
+	if (val & 0x80) {	/* RME */
+		exval = readreg(sp->isac, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC CRC error");
+			if (sp->rcvibh)
+				BufPoolRelease(sp->rcvibh);
+			sp->rcvibh = NULL;
+			writereg(sp->isac, ISAC_CMDR, 0x80);
+			goto afterRME;
+		}
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC,(void *) 1, 3)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writereg(sp->isac, ISAC_CMDR, 0x80);
+				goto afterRME;
+			} else
+				sp->rcvptr = 0;
+		count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(sp, count);
+		sp->rcvibh->datasize = sp->rcvptr;
+		BufQueueLink(&(sp->rq), sp->rcvibh);
+		sp->rcvibh = NULL;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC, (void *) 1, 4)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writereg(sp->isac, ISAC_CMDR, 0x80);
+				goto afterRPF;
+			} else
+				sp->rcvptr = 0;
+		isac_empty_fifo(sp, 32);
+	}
+	afterRPF:
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->xmtibh)
+			if (sp->xmtibh->datasize > sp->sendptr) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				if (sp->releasebuf)
+					BufPoolRelease(sp->xmtibh);
+				sp->xmtibh = NULL;
+				sp->sendptr = 0;
+			}
+		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
+			sp->releasebuf = !0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+	afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2) 
+				& 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+        		sprintf(tmp, "l1state %d", sp->ph_state);
+        		debugl1(sp, tmp);
+        	}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readreg(sp->isac, ISAC_EXIR); 
+		if (sp->debug & L1_DEB_WARN) {
+        		sprintf(tmp, "ISAC EXIR %02x", exval);
+        		debugl1(sp, tmp);
+        	}
+
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, byte val) {
+
+	byte    		exval;
+	struct HscxState	*hsp;
+	char			tmp[32];
+	
+		
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+        	exval = readreg(sp->hscx[1], HSCX_EXIR);
+	        if (exval == 0x40) {
+                	if (hsp->mode == 1)
+        	        	hscx_fill_fifo(hsp);
+	                else {
+                        	/* Here we lost an TX interrupt, so
+                        	* restart transmitting the whole frame.
+                	        */
+        	                hsp->sendptr = 0;
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+                        }
+                } else
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX B EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+        		debugl1(sp, tmp); 
+        	}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+                exval = readreg(sp->hscx[0], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+	                	/* Here we lost an TX interrupt, so
+        	        	* restart transmitting the whole frame.
+                		*/
+                		hsp->sendptr = 0;
+				writehscxCMDR(sp->hscx[hsp->hscx],0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+        		}
+		} else 
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX A EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+        if (val & 0x04) {
+                exval = readreg(sp->hscx[0], HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+        		debugl1(sp, tmp); 
+        	}
+        	hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState 	*sp;
+	byte                 	val, sval, stat=0;
+	char			tmp[32];
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	
+	if (!sp) {
+		printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
+		return;
+	}
+	
+	while (((sval=bytein(sp->cfg_reg))& 0xf) !=0x7) {
+		if (!(sval & AVM_A1_STAT_TIMER)) {
+			byteout(sp->cfg_reg,0x14);
+			byteout(sp->cfg_reg,0x18);
+			sval=bytein(sp->cfg_reg);
+		} else 
+			if (sp->debug & L1_DEB_INTSTAT) {
+				sprintf(tmp, "avm IntStatus %x", sval);
+        			debugl1(sp, tmp);
+			}
+		if (!(sval & AVM_A1_STAT_HSCX)) {
+			val = readreg(sp->hscx[1], HSCX_ISTA);
+			if (val) {
+				hscx_int_main(sp,val);
+				stat |= 1;
+			}
+		}
+		if (!(sval & AVM_A1_STAT_ISAC)) {
+			val = readreg(sp->isac, ISAC_ISTA);
+			if (val) { 
+				isac_interrupt(sp,val);
+				stat |= 2;
+			}
+		}
+	}
+	if (stat & 1) {
+		writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[0], HSCX_MASK, 0x0);
+		writereg(sp->hscx[1], HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writereg(sp->isac, ISAC_MASK, 0xFF);
+		writereg(sp->isac, ISAC_MASK, 0x0);
+	}
+
+}
+
+
+static void
+initisac(struct IsdnCardState    *sp)
+{
+	unsigned int	adr=sp->isac;
+	
+	/* 16.3 IOM 2 Mode */
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_ADF2, 0x80);
+	writereg(adr, ISAC_SQXR, 0x2f);
+	writereg(adr, ISAC_SPCR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x2);
+	writereg(adr, ISAC_STCR, 0x70);
+	writereg(adr, ISAC_MODE, 0xc9);
+	writereg(adr, ISAC_TIMR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x0);
+	writereg(adr, ISAC_CMDR, 0x41);
+	writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int             hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char  tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+	        	'A'+hscx, mode, ichan);
+        	debugl1(sp, tmp);
+        } 
+        hs->mode = mode;
+        writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+        writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+        writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+        switch (mode) {
+	case (0):
+        	writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+		writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+		writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+		writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+		writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+		writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+        	break;
+	case (1):
+                if (ichan == 0) {
+                	writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                } else {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                }
+		writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+		writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+        	break;
+	case (2):
+                if (ichan == 0) {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                } else {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                }
+		writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+		writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+        	break;
+        }
+	writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask) {
+	release_region(card->sp->cfg_reg, 8);
+        if (mask & 1) release_region(card->sp->isac, 32);
+        if (mask & 2) release_region(card->sp->isac - 0x400, 1);
+        if (mask & 4) release_region(card->sp->hscx[0], 32);
+        if (mask & 8) release_region(card->sp->hscx[0] -0x400, 1);
+        if (mask & 0x10) release_region(card->sp->hscx[1], 32);
+        if (mask & 0x20) release_region(card->sp->hscx[1] -0x400, 1);
+}
+
+void release_io_avm_a1(struct IsdnCard *card) {
+	release_ioregs(card, 0x3f);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int	val;
+	char	tmp[64];
+	
+        val = readreg(sp->hscx[1], HSCX_ISTA);
+        sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readreg(sp->hscx[1], HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x02) {
+        	val = readreg(sp->hscx[0], HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+        }
+        val = readreg(sp->hscx[0], HSCX_ISTA);
+        sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->hscx[1], HSCX_STAR);
+        sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->hscx[0], HSCX_STAR);
+        sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_STAR);
+        sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_MODE);
+        sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_ADF2);
+        sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_ISTA);
+        sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readreg(sp->isac, ISAC_EXIR);
+                sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x04) {
+        	val = readreg(sp->isac, ISAC_CIR0);
+                sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+        }
+        writereg(sp->isac, ISAC_MASK, 0);
+        writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initavm_a1(struct IsdnCardState *sp)
+{
+	int	ret;
+	char  tmp[40];
+	
+	sp->counter = kstat.interrupts[sp->irq]; 
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr,&avm_a1_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+        	debugl1(sp, tmp);
+        	if (kstat.interrupts[sp->irq]==sp->counter) {
+        		printk(KERN_WARNING 
+        		"AVM A1: IRQ(%d) getting no interrupts during init\n",
+        		sp->irq);
+        		irq2dev_map[sp->irq] = NULL;
+        		free_irq(sp->irq, NULL);
+        		return(0); 
+        	}
+	}
+	return(ret);
+}
+
+int
+setup_avm_a1(struct IsdnCard *card)
+{
+	int			timout;
+	byte			val, verA, verB;
+	struct IsdnCardState 	*sp = card->sp;
+
+	if (sp->typ != ISDN_CTYPE_A1)
+		return(0);
+		
+        sp->cfg_reg = card->para[1] + 0x1800;
+        sp->isac    = card->para[1] + 0x1400; 
+        sp->hscx[0] = card->para[1] + 0x400;
+        sp->hscx[1] = card->para[1] + 0xc00;
+        sp->irq     = card->para[0];
+        if (check_region((sp->cfg_reg) ,8)) {
+                printk(KERN_WARNING
+                  	"HiSax: %s config port %x-%x already in use\n",
+                  	CardType[card->typ],
+                        sp->cfg_reg,
+                        sp->cfg_reg + 8);
+                return (0);
+        } else {
+                request_region(sp->cfg_reg, 8, "avm cfg");
+	}
+        if (check_region((sp->isac) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s isac ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->isac,
+                        sp->isac + 32);
+		release_ioregs(card, 0);
+                return(0);
+        } else {
+        	request_region(sp->isac, 32, "HiSax isac");
+	}
+        if (check_region((sp->isac -0x400) , 1)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s isac fifo port %x already in use\n",
+                  	CardType[sp->typ],
+                        sp->isac -0x400);
+		release_ioregs(card, 1);
+                return(0);
+        } else {
+        	request_region(sp->isac -0x400, 1, "HiSax isac fifo");
+	}
+        if (check_region((sp->hscx[0]) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx A ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[0],
+                        sp->hscx[0] + 32);
+		release_ioregs(card, 3);
+                return(0);
+        } else {
+        	request_region(sp->hscx[0], 32, "HiSax hscx A");
+	}
+        if (check_region((sp->hscx[0] -0x400) , 1)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx A fifo port %x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[0] -0x400);
+		release_ioregs(card, 7);
+                return(0);
+        } else {
+        	request_region(sp->hscx[0] -0x400, 1, "HiSax hscx A fifo");
+	}
+        if (check_region((sp->hscx[1]) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx B ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[1],
+                        sp->hscx[1] + 32);
+		release_ioregs(card, 0xf);
+                return(0);
+        } else {
+        	request_region(sp->hscx[1], 32, "HiSax hscx B");
+	}
+        if (check_region((sp->hscx[1] -0x400) , 1)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx B fifo port %x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[1] -0x400);
+		release_ioregs(card, 0x1f);
+                return(0);
+        } else {
+        	request_region(sp->hscx[1] -0x400, 1, "HiSax hscx B fifo");
+	}
+       	byteout(sp->cfg_reg,0x0);
+        cli();
+        timout = jiffies + (HZ / 5) + 1;
+       	sti();
+        while (jiffies <= timout);
+        byteout(sp->cfg_reg,0x1);
+       	cli();
+        timout = jiffies + (HZ / 5) + 1;
+        sti();
+        while (jiffies <= timout);
+        byteout(sp->cfg_reg,0x0);
+        cli();
+        timout = jiffies + (HZ / 5) + 1;
+        sti();
+        while (jiffies <= timout);
+        val = sp->irq;
+        if (val==9) val=2;
+       	byteout(sp->cfg_reg+1,val);
+        cli();
+        timout = jiffies + (HZ / 5) + 1;
+        sti();
+       	while (jiffies <= timout);
+	byteout(sp->cfg_reg,0x0);
+        cli();
+        timout = jiffies + (HZ / 5) + 1;
+        sti();
+        while (jiffies <= timout);
+
+        val=bytein(sp->cfg_reg);
+        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+               	sp->cfg_reg,val);
+        val=bytein(sp->cfg_reg+3);
+        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+               	sp->cfg_reg+3,val);
+        val=bytein(sp->cfg_reg+2);
+        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+               	sp->cfg_reg+2,val);
+       	byteout(sp->cfg_reg,0x14);
+       	byteout(sp->cfg_reg,0x18);
+        val=bytein(sp->cfg_reg);
+        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+               	sp->cfg_reg,val);
+
+        printk(KERN_NOTICE
+        	"HiSax: %s found,irq:%d isac:%x/%x cfg:%x\n",
+                CardType[sp->typ], sp->irq,              
+                sp->isac, sp->isac -0x400, sp->cfg_reg);
+        printk(KERN_NOTICE
+        	"HiSax: hscx A:%x/%x  hscx B:%x/%x\n",
+                 sp->hscx[0], sp->hscx[0] -0x400,
+                 sp->hscx[1], sp->hscx[1] -0x400);
+        verA = readreg(sp->hscx[0],HSCX_VSTR) & 0xf;
+        verB = readreg(sp->hscx[1],HSCX_VSTR) & 0xf;
+        printk(KERN_INFO "AVM A1: HSCX version A: %s  B: %s\n",
+        	HscxVersion(verA), HscxVersion(verB));
+        val = readreg(sp->isac, ISAC_RBCH);
+        printk(KERN_INFO "AVM A1: ISAC %s\n",
+        	ISACVersion(val));
+	if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
+        	printk(KERN_WARNING 
+        		"AVM A1: wrong HSCX versions check IO address\n");
+		release_io_avm_a1(card);
+                return (0);
+	}
+        sp->modehscx       = &modehscx;
+        sp->ph_command     = &ph_command;
+        sp->hscx_fill_fifo = &hscx_fill_fifo;
+        sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/avm_a1.h linux/drivers/isdn/hisax/avm_a1.h
--- linux-2.0.26.org/drivers/isdn/hisax/avm_a1.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/avm_a1.h	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,22 @@
+/* $Id: avm_a1.h,v 1.1 1996/10/12 21:42:40 keil Exp $
+ *
+ * avm_a1.h   Header for AVM A1 (Fritz) ISDN card
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * 
+ * $Log: avm_a1.h,v $
+ * Revision 1.1  1996/10/12 21:42:40  keil
+ * Initial revision
+ *
+ *
+*/
+
+#define	 AVM_A1_STAT_ISAC	0x01
+#define	 AVM_A1_STAT_HSCX	0x02
+#define	 AVM_A1_STAT_TIMER	0x04
+
+extern	void avm_a1_report(struct IsdnCardState *sp);
+extern  void release_io_avm_a1(struct IsdnCard *card);
+extern	int  setup_avm_a1(struct IsdnCard *card);
+extern  int  initavm_a1(struct IsdnCardState *sp);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/buffers.c linux/drivers/isdn/hisax/buffers.c
--- linux-2.0.26.org/drivers/isdn/hisax/buffers.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/buffers.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,326 @@
+/* $Id: buffers.c,v 1.1 1996/10/13 20:04:49 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: buffers.c,v $
+ * Revision 1.1  1996/10/13 20:04:49  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+#undef SMALLOC_DEBUG
+
+void
+BufPoolInit(struct BufPool *bp, int order, int bpps,
+	    int maxpages)
+{
+#ifdef DEBUG_MAGIC
+	generateerror
+	    bp->magic = 010167;
+#endif
+
+#if 0
+	printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
+#endif
+
+	bp->freelist = NULL;
+	bp->pageslist = NULL;
+	bp->pageorder = order;
+	bp->pagescount = 0;
+	bp->bpps = bpps;
+	bp->bufsize = BUFFER_SIZE(order, bpps);
+	bp->maxpages = maxpages;
+}
+
+int
+BufPoolAdd(struct BufPool *bp, int priority)
+{
+	struct Pages   *ptr;
+	byte           *bptr;
+	int             i;
+	struct BufHeader *bh = NULL, *prev, *first;
+
+#if 0
+	printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
+#endif
+
+	ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
+	if (!ptr) {
+		printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
+		return (-1);
+	}
+#if 0
+	printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
+#endif
+
+	ptr->next = bp->pageslist;
+	bp->pageslist = ptr;
+	bp->pagescount++;
+
+	bptr = (byte *) ptr + sizeof(struct Pages *);
+
+	i = bp->bpps;
+	first = (struct BufHeader *) bptr;
+	prev = NULL;
+	while (i--) {
+		bh = (struct BufHeader *) bptr;
+#ifdef DEBUG_MAGIC
+		bh->magic = 020167;
+#endif
+		bh->next = prev;
+		prev = bh;
+		bh->bp = bp;
+		bptr += PART_SIZE(bp->pageorder, bp->bpps);
+	}
+
+	first->next = bp->freelist;
+	bp->freelist = bh;
+	return (0);
+}
+
+void
+BufPoolFree(struct BufPool *bp)
+{
+	struct Pages   *p;
+
+#if 0
+	printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
+#endif
+
+	while (bp->pagescount--) {
+		p = bp->pageslist->next;
+		free_pages((unsigned long) bp->pageslist, bp->pageorder);
+#if 0
+		printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
+#endif
+		bp->pageslist = p;
+	}
+}
+
+int
+BufPoolGet(struct BufHeader **bh,
+	   struct BufPool *bp, int priority, void *heldby, int where)
+{
+	long            flags;
+	int             i;
+
+#ifdef DEBUG_MAGIC
+	if (bp->magic != 010167) {
+		printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
+		return (-1);
+	}
+#endif
+
+	save_flags(flags);
+	cli();
+	i = 0;
+	while (!0) {
+		if (bp->freelist) {
+			*bh = bp->freelist;
+			bp->freelist = bp->freelist->next;
+			(*bh)->heldby = heldby;
+			(*bh)->where = where;
+			restore_flags(flags);
+			return (0);
+		}
+		if ((i == 0) && (bp->pagescount < bp->maxpages)) {
+                        if (BufPoolAdd(bp, priority)) {
+                                restore_flags(flags);
+                                return -1;
+                        }
+			i++;
+		} else {
+			*bh = NULL;
+			restore_flags(flags);
+			return (-1);
+		}
+	}
+
+}
+
+void
+BufPoolRelease(struct BufHeader *bh)
+{
+	struct BufPool *bp;
+	long            flags;
+
+#ifdef DEBUG_MAGIC
+	if (bh->magic != 020167) {
+		printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
+		printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
+		return;
+	}
+#endif
+
+	bp = bh->bp;
+
+#ifdef DEBUG_MAGIC
+	if (bp->magic != 010167) {
+		printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
+		return;
+	}
+#endif
+
+	save_flags(flags);
+	cli();
+	bh->next = bp->freelist;
+	bp->freelist = bh;
+	restore_flags(flags);
+}
+
+void
+BufQueueLink(struct BufQueue *bq,
+	     struct BufHeader *bh)
+{
+	unsigned long   flags;
+
+	save_flags(flags);
+	cli();
+	if (!bq->head)
+		bq->head = bh;
+	if (bq->tail)
+		bq->tail->next = bh;
+	bq->tail = bh;
+	bh->next = NULL;
+	restore_flags(flags);
+}
+
+void
+BufQueueLinkFront(struct BufQueue *bq,
+		  struct BufHeader *bh)
+{
+	unsigned long   flags;
+
+	save_flags(flags);
+	cli();
+	bh->next = bq->head;
+	bq->head = bh;
+	if (!bq->tail)
+		bq->tail = bh;
+	restore_flags(flags);
+}
+
+int
+BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
+{
+	long            flags;
+
+	save_flags(flags);
+	cli();
+
+	if (bq->head) {
+		if (bq->tail == bq->head)
+			bq->tail = NULL;
+		*bh = bq->head;
+		bq->head = (*bh)->next;
+		restore_flags(flags);
+		return (0);
+	} else {
+		restore_flags(flags);
+		return (-1);
+	}
+}
+
+void
+BufQueueInit(struct BufQueue *bq)
+{
+#ifdef DEBUG_MAGIC
+	bq->magic = 030167;
+#endif
+	bq->head = NULL;
+	bq->tail = NULL;
+}
+
+void
+BufQueueRelease(struct BufQueue *bq)
+{
+	struct BufHeader *bh;
+
+	while (bq->head) {
+		BufQueueUnlink(&bh, bq);
+		BufPoolRelease(bh);
+	}
+}
+
+int
+BufQueueLength(struct BufQueue *bq)
+{
+	int             i = 0;
+	struct BufHeader *bh;
+
+	bh = bq->head;
+	while (bh) {
+		i++;
+		bh = bh->next;
+	}
+	return (i);
+}
+
+void
+BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
+		int releasetoo)
+{
+	long            flags;
+	struct BufHeader *sp;
+
+	save_flags(flags);
+	cli();
+
+	while (!0) {
+		sp = q->head;
+		if (!sp)
+			break;
+		if ((sp->primitive == pr) && (sp->heldby == heldby)) {
+			q->head = sp->next;
+			if (q->tail == sp)
+				q->tail = NULL;
+			if (releasetoo)
+				BufPoolRelease(sp);
+		} else
+			break;
+	}
+
+	sp = q->head;
+	if (sp)
+		while (sp->next) {
+			if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
+				if (q->tail == sp->next)
+					q->tail = sp;
+				if (releasetoo)
+					BufPoolRelease(sp->next);
+				sp->next = sp->next->next;
+			} else
+				sp = sp->next;
+		}
+	restore_flags(flags);
+}
+
+void
+Sfree(byte * ptr)
+{
+#ifdef SMALLOC_DEBUG
+	printk(KERN_DEBUG "Sfree %x\n", (unsigned int)ptr);
+#endif
+	kfree(ptr);
+}
+
+byte           *
+Smalloc(int size, int pr, char *why)
+{
+	byte           *p;
+
+	p = (byte *) kmalloc(size, pr);
+#ifdef SMALLOC_DEBUG
+	printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, (unsigned int)p);
+#endif
+	return (p);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- linux-2.0.26.org/drivers/isdn/hisax/callc.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/callc.c	Mon Dec  9 00:11:20 1996
@@ -0,0 +1,1636 @@
+/* $Id: callc.c,v 1.13 1996/12/08 19:51:17 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: callc.c,v $
+ * Revision 1.13  1996/12/08 19:51:17  keil
+ * bugfixes from Pekka Sarnila
+ *
+ * Revision 1.12  1996/11/26 20:20:03  keil
+ * fixed warning while compile
+ *
+ * Revision 1.11  1996/11/26 18:43:17  keil
+ * change ioctl 555 --> 55 (555 didn't work)
+ *
+ * Revision 1.10  1996/11/26 18:06:07  keil
+ * fixed missing break statement,ioctl 555 reset modcount
+ *
+ * Revision 1.9  1996/11/18 20:23:19  keil
+ * log writebuf channel not open changed
+ *
+ * Revision 1.8  1996/11/06 17:43:17  keil
+ * more changes for 2.1.X;block fixed ST_PRO_W
+ *
+ * Revision 1.7  1996/11/06 15:13:51  keil
+ * typo 0x64 --->64 in debug code
+ *
+ * Revision 1.6  1996/11/05 19:40:33  keil
+ * X.75 windowsize
+ *
+ * Revision 1.5  1996/10/30 10:11:06  keil
+ * debugging LOCK changed;ST_REL_W EV_HANGUP added
+ *
+ * Revision 1.4  1996/10/27 22:20:16  keil
+ * alerting bugfixes
+ * no static b-channel<->channel mapping
+ *
+ * Revision 1.2  1996/10/16 21:29:45  keil
+ * compile bug as "not module"
+ * Callback with euro
+ *
+ * Revision 1.1  1996/10/13 20:04:50  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+#ifdef MODULE
+extern long mod_use_count_;
+#endif MODULE
+
+extern struct IsdnCard cards[];
+extern int      nrcards;
+extern int      drid;
+extern isdn_if  iif;
+extern void     HiSax_mod_dec_use_count(void);
+extern void     HiSax_mod_inc_use_count(void);
+
+static int      init_ds(int chan, int incoming);
+static void     release_ds(int chan);
+static char    *strcpyupto(char *dest, char *src, char upto);
+
+static struct Fsm callcfsm =
+{NULL, 0, 0},   lcfsm =
+{NULL, 0, 0};
+
+struct Channel *chanlist;
+static int      chancount = 0;
+unsigned int    debugflags = 0;
+
+#define TMR_DCHAN_EST 2000
+
+static void
+stat_debug(struct Channel *chanp, char *s)
+{
+	char            tmp[100], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
+	HiSax_putstatus(tmp);
+}
+
+
+enum {
+        ST_NULL,           /*  0 inactive                                               */
+        ST_OUT,            /*  1 outgoing, awaiting SETUP confirm                       */
+        ST_CLEAR,          /*  2 call release, awaiting RELEASE confirm                 */
+        ST_OUT_W,          /*  3 outgoing, awaiting d-channel establishment             */
+        ST_REL_W,          /*  4 awaiting d-channel release                             */
+        ST_IN_W,           /*  5 incoming, awaiting d-channel establishment             */
+        ST_IN,             /*  6 incoming call received                                 */
+        ST_IN_SETUP,       /*  7 incoming, SETUP response sent                          */
+        ST_IN_DACT,        /*  8 incoming connected, no b-channel prot.                 */
+        ST_OUT_ESTB,       /* 10 outgoing connected, awaiting b-channel prot. estbl.    */
+        ST_ACTIVE,         /* 11 active, b channel prot. established                    */
+        ST_BC_HANGUP,      /* 12 call clear. (initiator), awaiting b channel prot. rel. */
+        ST_PRO_W,          /* 13 call clear. (initiator), DISCONNECT req. sent          */
+        ST_ANT_W,          /* 14 call clear. (receiver), awaiting DISCONNECT ind.       */
+        ST_DISC_BC_HANGUP, /* 15 d channel gone, wait for b channel deactivation        */
+	ST_OUT_W_HANGUP,   /* 16 Outgoing waiting for D-Channel hangup received         */
+        ST_D_ERR,          /* 17 d channel released while active                        */
+};
+
+#define STATE_COUNT (ST_D_ERR+1)
+
+static char    *strState[] =
+{
+        "ST_NULL",
+        "ST_OUT",
+        "ST_CLEAR",
+        "ST_OUT_W",
+        "ST_REL_W",
+        "ST_IN_W",
+        "ST_IN",
+        "ST_IN_SETUP",
+        "ST_IN_DACT",
+        "ST_OUT_ESTB",
+        "ST_ACTIVE",
+        "ST_BC_HANGUP",
+        "ST_PRO_W",
+        "ST_ANT_W",
+        "ST_DISC_BC_HANGUP",
+        "ST_OUT_W_HANGUP",
+        "ST_D_ERR",
+};
+
+enum {
+        EV_DIAL,           /*  0 */
+        EV_SETUP_CNF,      /*  1 */
+        EV_ACCEPTB,        /*  2 */
+        EV_DISCONNECT_CNF, /*  5 */
+        EV_DISCONNECT_IND, /*  6 */
+        EV_RELEASE_CNF,    /*  7 */
+        EV_DLEST,          /*  8 */
+        EV_DLRL,           /*  9 */
+        EV_SETUP_IND,      /* 10 */
+        EV_RELEASE_IND,    /* 11 */
+        EV_ACCEPTD,        /* 12 */
+        EV_SETUP_CMPL_IND, /* 13 */
+        EV_BC_EST,         /* 14 */
+        EV_WRITEBUF,       /* 15 */
+        EV_DATAIN,         /* 16 */
+        EV_HANGUP,         /* 17 */
+        EV_BC_REL,         /* 18 */
+        EV_CINF,           /* 19 */
+        EV_SUSPEND,        /* 20 */
+        EV_RESUME,         /* 21 */
+        EV_ICALL_TIMER,    /* 22 */
+};
+
+#define EVENT_COUNT (EV_ICALL_TIMER+1)
+
+static char    *strEvent[] =
+{
+        "EV_DIAL",
+        "EV_SETUP_CNF",
+        "EV_ACCEPTB",
+        "EV_DISCONNECT_CNF",
+        "EV_DISCONNECT_IND",
+        "EV_RELEASE_CNF",
+        "EV_DLEST",
+        "EV_DLRL",
+        "EV_SETUP_IND",
+        "EV_RELEASE_IND",
+        "EV_ACCEPTD",
+        "EV_SETUP_CMPL_IND",
+        "EV_BC_EST",
+        "EV_WRITEBUF",
+        "EV_DATAIN",
+        "EV_HANGUP",
+        "EV_BC_REL",
+        "EV_CINF",
+        "EV_SUSPEND",
+        "EV_RESUME",
+        "EV_ICALL_TIMER",
+};
+
+enum {
+        ST_LC_NULL,
+        ST_LC_ACTIVATE_WAIT,
+        ST_LC_DELAY,
+        ST_LC_ESTABLISH_WAIT,
+        ST_LC_CONNECTED,
+        ST_LC_FLUSH_WAIT,
+        ST_LC_FLUSH_DELAY,
+        ST_LC_RELEASE_WAIT,
+};
+
+#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
+
+static char    *strLcState[] =
+{
+        "ST_LC_NULL",
+        "ST_LC_ACTIVATE_WAIT",
+        "ST_LC_DELAY",
+        "ST_LC_ESTABLISH_WAIT",
+        "ST_LC_CONNECTED",
+        "ST_LC_FLUSH_WAIT",
+        "ST_LC_FLUSH_DELAY",
+        "ST_LC_RELEASE_WAIT",
+};
+
+enum {
+        EV_LC_ESTABLISH,
+        EV_LC_PH_ACTIVATE,
+        EV_LC_PH_DEACTIVATE,
+        EV_LC_DL_ESTABLISH,
+        EV_LC_TIMER,
+        EV_LC_DL_FLUSH,
+        EV_LC_DL_RELEASE,
+        EV_LC_FLUSH,
+        EV_LC_RELEASE,
+};
+
+#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
+
+static char    *strLcEvent[] =
+{
+        "EV_LC_ESTABLISH",
+        "EV_LC_PH_ACTIVATE",
+        "EV_LC_PH_DEACTIVATE",
+        "EV_LC_DL_ESTABLISH",
+        "EV_LC_TIMER",
+        "EV_LC_DL_FLUSH",
+        "EV_LC_DL_RELEASE",
+        "EV_LC_FLUSH",
+        "EV_LC_RELEASE",
+};
+
+#define LC_D  0
+#define LC_B  1
+
+static int
+my_atoi(char *s)
+{
+        int             i, n;
+
+        n = 0;
+        if (!s)
+                return -1;
+        for (i = 0; *s >= '0' && *s <= '9'; i++, s++)
+                n = 10 * n + (*s - '0');
+        return n;
+}
+
+/*
+ * Dial out
+ */
+static void
+r1(struct FsmInst *fi, int event, void *arg)
+{
+        isdn_ctrl      *ic = arg;
+        struct Channel *chanp = fi->userdata;
+        char           *ptr;
+        char            sis[3];
+
+        /* Destination Phone-Number */
+        ptr = strcpyupto(chanp->para.called, ic->num, ',');
+        /* Source Phone-Number */
+        ptr = strcpyupto(chanp->para.calling, ptr + 1, ',');
+        if (!strcmp(chanp->para.calling, "0"))
+                chanp->para.calling[0] = '\0';
+
+        /* Service-Indicator 1 */
+        ptr = strcpyupto(sis, ptr + 1, ',');
+        chanp->para.info = my_atoi(sis);
+
+        /* Service-Indicator 2 */
+        ptr = strcpyupto(sis, ptr + 1, '\0');
+        chanp->para.info2 = my_atoi(sis);
+
+        chanp->l2_active_protocol = chanp->l2_protocol;
+        chanp->incoming = 0;
+        chanp->lc_b.l2_start = !0;
+
+        switch (chanp->l2_active_protocol) {
+          case (ISDN_PROTO_L2_X75I):
+                  chanp->lc_b.l2_establish = !0;
+                  break;
+          case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
+                  chanp->lc_b.l2_establish = 0;
+                  break;
+          default:
+                  printk(KERN_WARNING "r1 unknown protocol\n");
+                  break;
+        }
+
+        FsmChangeState(fi, ST_OUT_W);
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+ll_hangup(struct Channel *chanp, int bchantoo)
+{
+        isdn_ctrl       ic;
+
+        if (bchantoo) {
+                if (chanp->debug & 1)
+                        stat_debug(chanp, "STAT_BHUP");
+                ic.driver = drid;
+                ic.command = ISDN_STAT_BHUP;
+                ic.arg = chanp->chan;
+                iif.statcallb(&ic);
+        }
+        if (chanp->debug & 1)
+                stat_debug(chanp, "STAT_DHUP");
+        ic.driver = drid;
+        ic.command = ISDN_STAT_DHUP;
+        ic.arg = chanp->chan;
+        iif.statcallb(&ic);
+}
+
+static void
+r2(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+
+        FsmChangeState(fi, ST_CLEAR);
+        ll_hangup(chanp, 0);
+}
+
+
+static void
+r2_1(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_OUT_W_HANGUP);
+        chanp->is.l4.l4l3(&chanp->is, CC_REJECT_REQ, NULL);
+}
+
+
+static void
+r2_2(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_REL_W);
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+        ll_hangup(chanp, 0);
+}
+
+
+static void
+r2_3(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_REL_W);
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL);
+        ll_hangup(chanp, 0);
+}
+
+
+static void
+r2_4(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_OUT_W_HANGUP);
+        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+}
+
+
+static void
+r3(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+        FsmChangeState(fi, ST_REL_W);
+}
+
+
+static void
+r3_1(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
+	
+        FsmChangeState(fi, ST_NULL);
+        ll_hangup(chanp, 0);
+}
+
+static void
+r4(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp=fi->userdata;  
+  
+        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);                                  
+        FsmChangeState(fi, ST_NULL);
+}
+
+static void
+r5(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->para.callref = chanp->outcallref;
+
+        chanp->outcallref++;
+        if (chanp->outcallref == 128)
+                chanp->outcallref = 64;
+
+        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
+
+        FsmChangeState(fi, ST_OUT);
+}
+
+static void
+r6(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_IN_W);
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+r7(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+        isdn_ctrl       ic;
+        int		ret;
+        char		txt[32];	       
+
+        /*
+         * Report incoming calls only once to linklevel, use CallFlags
+         * which is set to 3 with each broadcast message in isdnl1.c
+         * and resetted if a interface  answered the STAT_ICALL.
+         */
+        if ((chanp->sp) &&(chanp->sp->CallFlags==3)) {
+                FsmChangeState(fi, ST_IN);
+                if (chanp->debug & 1)
+                        stat_debug(chanp, "STAT_ICALL");
+                ic.driver = drid;
+                ic.command = ISDN_STAT_ICALL;
+                ic.arg = chanp->chan;
+                /*
+                 * No need to return "unknown" for calls without OAD,
+                 * cause that's handled in linklevel now (replaced by '0')
+                 */
+                sprintf(ic.num, "%s,%d,0,%s", chanp->para.calling, chanp->para.info,
+                        chanp->para.called);
+                ret=iif.statcallb(&ic);
+                if (chanp->debug & 1) {
+                	sprintf(txt,"statcallb ret=%d",ret);
+                	stat_debug(chanp, txt);
+                }
+                if (ret) /* if a interface knows this call, reset the CallFlag
+			  * to avoid a second Call report to the linklevel */
+                	chanp->sp->CallFlags &= ~(chanp->chan+1); 
+                switch(ret) {
+                  case 1: /* OK, anybody likes this call */
+                  	chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
+                	break;
+                  case 2: /* Rejecting Call ,nothing to do here */
+                  	break;
+                  case 0: /* OK, nobody likes this call */
+                  default: /* statcallb problems */
+                	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
+                	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+                	FsmChangeState(fi, ST_REL_W);
+                	break;
+                }
+        } else {
+                	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
+                	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+                	FsmChangeState(fi, ST_REL_W);
+        }
+}
+
+static void
+r8(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_IN_SETUP);
+        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
+
+}
+
+static void
+r9(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_IN_DACT);
+
+        chanp->l2_active_protocol = chanp->l2_protocol;
+        chanp->incoming = !0;
+        chanp->lc_b.l2_start = 0;
+
+        switch (chanp->l2_active_protocol) {
+          case (ISDN_PROTO_L2_X75I):
+                  chanp->lc_b.l2_establish = !0;
+                  break;
+          case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
+                  chanp->lc_b.l2_establish = 0;
+                  break;
+          default:
+                  printk(KERN_WARNING "r9 unknown protocol\n");
+                  break;
+        }
+
+        init_ds(chanp->chan, !0);
+
+        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+r10(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_OUT_ESTB);
+
+        init_ds(chanp->chan, 0);
+        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+
+}
+
+static void
+r12(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+        isdn_ctrl       ic;
+
+        FsmChangeState(fi, ST_ACTIVE);
+        chanp->data_open = !0;
+
+        if (chanp->debug & 1)
+                stat_debug(chanp, "STAT_DCONN");
+        ic.driver = drid;
+        ic.command = ISDN_STAT_DCONN;
+        ic.arg = chanp->chan;
+        iif.statcallb(&ic);
+
+        if (chanp->debug & 1)
+                stat_debug(chanp, "STAT_BCONN");
+        ic.driver = drid;
+        ic.command = ISDN_STAT_BCONN;
+        ic.arg = chanp->chan;
+        iif.statcallb(&ic);
+        
+}
+
+static void
+r15(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->data_open = 0;
+        FsmChangeState(fi, ST_BC_HANGUP);
+        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+r16(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        release_ds(chanp->chan);
+
+        FsmChangeState(fi, ST_PRO_W);
+        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+}
+
+static void
+r17(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->data_open = 0;
+        release_ds(chanp->chan);
+
+        FsmChangeState(fi, ST_ANT_W);
+}
+
+
+static void
+r17_1(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->data_open = 0;
+        release_ds(chanp->chan);
+
+	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
+	
+	FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
+	
+        FsmChangeState(fi, ST_NULL);
+        
+        ll_hangup(chanp,!0); 
+}
+
+static void
+r18(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_REL_W);
+        FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL);
+
+        ll_hangup(chanp, !0);
+}
+
+static void
+r19(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        FsmChangeState(fi, ST_CLEAR);
+
+        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+
+        ll_hangup(chanp, !0);
+}
+
+static void
+r20(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+        
+        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
+        
+        FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
+
+        FsmChangeState(fi, ST_NULL);
+
+        ll_hangup(chanp, 0);
+}
+
+
+static void
+r21(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->data_open = 0;
+        FsmChangeState(fi, ST_DISC_BC_HANGUP);
+        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+r22(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        release_ds(chanp->chan);
+
+        FsmChangeState(fi, ST_CLEAR);
+
+        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+
+        ll_hangup(chanp, !0);
+}
+
+static void
+r23(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        release_ds(chanp->chan);
+
+        FsmChangeState(fi, ST_PRO_W);
+        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+}
+
+static void
+r23_1(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        release_ds(chanp->chan);
+
+	chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL); 
+	
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL); 
+	
+        FsmChangeState(fi, ST_NULL);
+        
+        ll_hangup(chanp,!0); 
+}
+
+static void
+r24(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        chanp->data_open = 0;
+        FsmChangeState(fi, ST_D_ERR);
+        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+r25(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+        release_ds(chanp->chan);
+        FsmChangeState(fi, ST_NULL);
+        ll_hangup(chanp, !0);
+}
+
+static void
+r26(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+        isdn_ctrl       ic;
+
+        ic.driver = drid;
+        ic.command = ISDN_STAT_CINF;
+        ic.arg = chanp->chan;
+        sprintf(ic.num, "%d", chanp->para.chargeinfo);
+        iif.statcallb(&ic);
+}
+
+static void
+r27(struct FsmInst *fi, int event, void *arg)
+{
+        struct Channel *chanp = fi->userdata;
+
+         FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+         FsmChangeState(fi, ST_REL_W);
+}
+
+static struct FsmNode fnlist[] =
+{
+        {ST_NULL,             EV_DIAL,                r1},
+        {ST_OUT_W,            EV_DLEST,               r5},
+        {ST_OUT_W,            EV_DLRL,                r20},
+        {ST_OUT_W,            EV_RELEASE_CNF,         r2_2 },   
+        {ST_OUT,              EV_DISCONNECT_IND,      r2},
+        {ST_OUT,              EV_SETUP_CNF,           r10},
+        {ST_OUT,              EV_HANGUP,              r2_1},
+        {ST_OUT,              EV_RELEASE_IND,         r20},
+        {ST_OUT,              EV_RELEASE_CNF,         r20},
+        {ST_OUT,              EV_DLRL,                r2_2},
+        {ST_OUT_W_HANGUP,     EV_RELEASE_CNF,         r2_2},
+        {ST_OUT_W_HANGUP,     EV_RELEASE_IND,         r2_3},
+        {ST_OUT_W_HANGUP,     EV_DLRL,                r20},
+        {ST_CLEAR,            EV_RELEASE_CNF,         r3},
+        {ST_CLEAR,            EV_DLRL,                r20},
+        {ST_REL_W,            EV_HANGUP,              r4},
+        {ST_REL_W,            EV_DLRL,                r4},
+        {ST_NULL,             EV_SETUP_IND,           r6},
+        {ST_IN_W,             EV_DLEST,               r7},
+        {ST_IN_W,             EV_DLRL,                r3_1},
+        {ST_IN,               EV_DLRL,                r3_1},
+        {ST_IN,               EV_HANGUP,              r2_1},
+        {ST_IN,               EV_RELEASE_IND,         r2_3},
+        {ST_IN,               EV_RELEASE_CNF,         r2_2},
+        {ST_IN,               EV_ACCEPTD,             r8},
+        {ST_IN,               EV_ICALL_TIMER,         r27},
+        {ST_IN_SETUP,         EV_HANGUP,              r2_4},
+        {ST_IN_SETUP,         EV_SETUP_CMPL_IND,      r9},
+        {ST_IN_SETUP,         EV_RELEASE_IND,         r2_3},
+        {ST_IN_SETUP,         EV_DISCONNECT_IND,      r2},
+        {ST_IN_SETUP,         EV_DLRL,                r20},
+        {ST_OUT_ESTB,         EV_BC_EST,              r12},
+        {ST_OUT_ESTB,         EV_BC_REL,              r23},
+        {ST_OUT_ESTB,         EV_DLRL,                r23_1},
+        {ST_IN_DACT,          EV_BC_EST,              r12},
+        {ST_IN_DACT,          EV_HANGUP,              r15},
+        {ST_IN_DACT,          EV_DISCONNECT_IND,      r21}, 
+        {ST_IN_DACT,          EV_BC_REL,              r17},
+        {ST_IN_DACT,          EV_DLRL,                r17_1},
+        {ST_ACTIVE,           EV_HANGUP,              r15},
+        {ST_ACTIVE,           EV_BC_REL,              r17},
+        {ST_ACTIVE,           EV_DISCONNECT_IND,      r21},
+        {ST_ACTIVE,           EV_DLRL,                r24},
+        {ST_ACTIVE,           EV_CINF,                r26},
+        {ST_ACTIVE,           EV_RELEASE_IND,         r17},
+        {ST_BC_HANGUP,        EV_BC_REL,              r16},
+        {ST_BC_HANGUP,        EV_DISCONNECT_IND,      r21},
+        {ST_PRO_W,            EV_RELEASE_IND,         r18},
+        {ST_PRO_W,            EV_HANGUP,              r18},
+        {ST_ANT_W,            EV_DISCONNECT_IND,      r19},
+        {ST_DISC_BC_HANGUP,   EV_BC_REL,              r22},
+        {ST_D_ERR,            EV_BC_REL,              r25},
+};
+
+#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
+
+static void
+lc_r1(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
+        FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
+        lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
+
+}
+
+static void
+lc_r6(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmDelTimer(&lf->act_timer, 50);
+        FsmChangeState(fi, ST_LC_DELAY);
+        FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
+}
+
+static void
+lc_r2(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        if (lf->l2_establish) {
+                FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
+                if (lf->l2_start)
+                        lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
+        } else {
+                FsmChangeState(fi, ST_LC_CONNECTED);
+                lf->lccall(lf, LC_ESTABLISH, NULL);
+        }
+}
+
+static void
+lc_r3(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmChangeState(fi, ST_LC_CONNECTED);
+        lf->lccall(lf, LC_ESTABLISH, NULL);
+}
+
+static void
+lc_r7(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmChangeState(fi, ST_LC_FLUSH_WAIT);
+	lf->st->ma.manl2(lf->st, DL_FLUSH, NULL);
+}
+
+static void
+lc_r4(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        if (lf->l2_establish) {
+                FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+                lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
+        } else {
+                FsmChangeState(fi, ST_LC_NULL);
+                lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+                lf->lccall(lf, LC_RELEASE, NULL);
+        }
+}
+
+static void
+lc_r4_1(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmChangeState(fi, ST_LC_FLUSH_DELAY);
+        FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52);
+}
+
+static void
+lc_r5(struct FsmInst *fi, int event, void *arg)
+{
+        struct LcFsm   *lf = fi->userdata;
+
+        FsmChangeState(fi, ST_LC_NULL);
+        lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+        lf->lccall(lf, LC_RELEASE, NULL);
+}
+
+static struct FsmNode LcFnList[] =
+{
+        {ST_LC_NULL,                  EV_LC_ESTABLISH,        lc_r1},
+        {ST_LC_ACTIVATE_WAIT,         EV_LC_PH_ACTIVATE,      lc_r6},
+        {ST_LC_DELAY,                 EV_LC_TIMER,            lc_r2},
+        {ST_LC_DELAY,                 EV_LC_DL_ESTABLISH,     lc_r3},
+        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_ESTABLISH,     lc_r3},
+        {ST_LC_ESTABLISH_WAIT,        EV_LC_RELEASE,          lc_r5},
+        {ST_LC_CONNECTED,             EV_LC_FLUSH,            lc_r7},
+        {ST_LC_CONNECTED,             EV_LC_RELEASE,          lc_r4},
+        {ST_LC_CONNECTED,             EV_LC_DL_RELEASE,       lc_r5},
+        {ST_LC_FLUSH_WAIT,            EV_LC_DL_FLUSH,         lc_r4_1},
+        {ST_LC_FLUSH_DELAY,           EV_LC_TIMER,            lc_r4},
+        {ST_LC_RELEASE_WAIT,          EV_LC_DL_RELEASE,       lc_r5},
+        {ST_LC_ACTIVATE_WAIT,         EV_LC_TIMER,            lc_r5},
+        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_RELEASE,       lc_r5},
+};
+
+#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
+
+void
+CallcNew(void)
+{
+        callcfsm.state_count = STATE_COUNT;
+        callcfsm.event_count = EVENT_COUNT;
+        callcfsm.strEvent = strEvent;
+        callcfsm.strState = strState;
+        FsmNew(&callcfsm, fnlist, FNCOUNT);
+
+        lcfsm.state_count = LC_STATE_COUNT;
+        lcfsm.event_count = LC_EVENT_COUNT;
+        lcfsm.strEvent = strLcEvent;
+        lcfsm.strState = strLcState;
+        FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
+}
+
+void
+CallcFree(void)
+{
+        FsmFree(&lcfsm);
+        FsmFree(&callcfsm);
+}
+
+static void
+release_ds(int chan)
+{
+        struct PStack  *st = &chanlist[chan].ds;
+        struct IsdnCardState *sp;
+        struct HscxState *hsp;
+
+        sp = st->l1.hardware;
+        hsp = sp->hs + chanlist[chan].hscx;
+
+        close_hscxstate(hsp);
+
+        switch (chanlist[chan].l2_active_protocol) {
+          case (ISDN_PROTO_L2_X75I):
+                  releasestack_isdnl2(st);
+                  break;
+          case (ISDN_PROTO_L2_HDLC):
+          case (ISDN_PROTO_L2_TRANS):
+                  releasestack_transl2(st);
+                  break;
+        }
+}
+
+static void
+cc_l1man(struct PStack *st, int pr, void *arg)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+        switch (pr) {
+          case (PH_ACTIVATE):
+                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
+                  break;
+          case (PH_DEACTIVATE):
+                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+                  break;
+        }
+}
+
+static void
+cc_l2man(struct PStack *st, int pr, void *arg)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+        switch (pr) {
+          case (DL_ESTABLISH):
+                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
+                  break;
+          case (DL_RELEASE):
+                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
+                  break;
+          case (DL_FLUSH):
+                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL);
+                  break;
+        }
+}
+
+static void
+dcc_l1man(struct PStack *st, int pr, void *arg)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+        switch (pr) {
+          case (PH_ACTIVATE):
+                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
+                  break;
+          case (PH_DEACTIVATE):
+                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+                  break;
+        }
+}
+
+static void
+dcc_l2man(struct PStack *st, int pr, void *arg)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+        switch (pr) {
+          case (DL_ESTABLISH):
+                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+                  break;
+          case (DL_RELEASE):
+                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+                  break;
+        }
+}
+
+static void
+ll_handler(struct PStack *st, int pr,
+           struct BufHeader *ibh)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+        switch (pr) {
+          case (CC_DISCONNECT_IND):
+                  FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
+                  break;
+          case (CC_RELEASE_CNF):
+                  FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+                  break;
+          case (CC_SETUP_IND):
+                  FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+                  break;
+          case (CC_RELEASE_IND):
+                  FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
+                  break;
+          case (CC_SETUP_COMPLETE_IND):
+                  FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
+                  break;
+          case (CC_SETUP_CNF):
+                  FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+                  break;
+          case (CC_INFO_CHARGE):
+                  FsmEvent(&chanp->fi, EV_CINF, NULL);
+                  break;
+        }
+}
+
+static void
+init_is(int chan, unsigned int ces)
+{
+        struct PStack  *st = &(chanlist[chan].is);
+        struct IsdnCardState *sp = chanlist[chan].sp;
+        char            tmp[128];
+
+        setstack_HiSax(st, sp);
+
+        st->l2.sap = 0;
+
+        st->l2.tei = 255;
+
+        st->l2.ces = ces;
+        st->l2.extended = !0;
+        st->l2.laptype = LAPD;
+        st->l2.window = 1;
+        st->l2.orig = !0;
+        st->l2.t200 = 1000;               /* 1000 milliseconds  */
+        if (st->protocol == ISDN_PTYPE_1TR6) {
+                st->l2.n200 = 3;          /* try 3 times        */
+                st->l2.t203 = 10000;      /* 10000 milliseconds */
+        } else {
+                st->l2.n200 = 4;          /* try 4 times        */
+                st->l2.t203 = 5000;       /* 5000 milliseconds  */
+        }
+
+        sprintf(tmp, "Channel %d q.921", chan);
+        setstack_isdnl2(st, tmp);
+        setstack_isdnl3(st, chan);
+        st->l2.debug = 0xff;
+        st->l4.userdata = chanlist + chan;
+        st->l4.l2writewakeup = NULL;
+
+        st->l3.l3l4 = ll_handler;
+        st->l1.l1man = cc_l1man;
+        st->l2.l2man = cc_l2man;
+
+        st->pa = &chanlist[chan].para;
+        HiSax_addlist(sp, st);
+}
+
+static void
+callc_debug(struct FsmInst *fi, char *s)
+{
+        char            str[80], tm[32];
+        struct Channel *chanp = fi->userdata;
+
+        jiftime(tm, jiffies);
+        sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
+        HiSax_putstatus(str);
+}
+
+static void
+lc_debug(struct FsmInst *fi, char *s)
+{
+        char            str[256], tm[32];
+        struct LcFsm   *lf = fi->userdata;
+
+        jiftime(tm, jiffies);
+        sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
+        HiSax_putstatus(str);
+}
+
+static void
+dlc_debug(struct FsmInst *fi, char *s)
+{
+        char            str[256], tm[32];
+        struct LcFsm   *lf = fi->userdata;
+
+        jiftime(tm, jiffies);
+        sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
+        HiSax_putstatus(str);
+}
+
+static void
+lccall_d(struct LcFsm *lf, int pr, void *arg)
+{
+        struct Channel *chanp = lf->ch;
+
+        switch (pr) {
+          case (LC_ESTABLISH):
+                  FsmEvent(&chanp->fi, EV_DLEST, NULL);
+                  break;
+          case (LC_RELEASE):
+                  FsmEvent(&chanp->fi, EV_DLRL, NULL);
+                  break;
+        }
+}
+
+static void
+lccall_b(struct LcFsm *lf, int pr, void *arg)
+{
+        struct Channel *chanp = lf->ch;
+
+        switch (pr) {
+          case (LC_ESTABLISH):
+                  FsmEvent(&chanp->fi, EV_BC_EST, NULL);
+                  break;
+          case (LC_RELEASE):
+                  FsmEvent(&chanp->fi, EV_BC_REL, NULL);
+                  break;
+        }
+}
+
+static void
+init_chan(int chan, int cardnr, int hscx,
+          unsigned int ces)
+{
+        struct IsdnCard *card = cards + cardnr;
+        struct Channel *chanp = chanlist + chan;
+
+        chanp->sp = card->sp;
+        chanp->hscx = hscx;
+        chanp->chan = chan;
+        chanp->incoming = 0;
+        chanp->debug = 0;
+	
+        init_is(chan, ces);
+
+        chanp->fi.fsm = &callcfsm;
+        chanp->fi.state = ST_NULL;
+        chanp->fi.debug = 0;
+        chanp->fi.userdata = chanp;
+        chanp->fi.printdebug = callc_debug;
+
+        chanp->lc_d.lcfi.fsm = &lcfsm;
+        chanp->lc_d.lcfi.state = ST_LC_NULL;
+        chanp->lc_d.lcfi.debug = 0;
+        chanp->lc_d.lcfi.userdata = &chanp->lc_d;
+        chanp->lc_d.lcfi.printdebug = lc_debug;
+        chanp->lc_d.type = LC_D;
+        chanp->lc_d.ch = chanp;
+        chanp->lc_d.st = &chanp->is;
+        chanp->lc_d.l2_establish = !0;
+        chanp->lc_d.l2_start = !0;
+        chanp->lc_d.lccall = lccall_d;
+        FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
+
+        chanp->lc_b.lcfi.fsm = &lcfsm;
+        chanp->lc_b.lcfi.state = ST_LC_NULL;
+        chanp->lc_b.lcfi.debug = 0;
+        chanp->lc_b.lcfi.userdata = &chanp->lc_b;
+        chanp->lc_b.lcfi.printdebug = dlc_debug;
+        chanp->lc_b.type = LC_B;
+        chanp->lc_b.ch = chanp;
+        chanp->lc_b.st = &chanp->ds;
+        chanp->lc_b.l2_establish = !0;
+        chanp->lc_b.l2_start = !0;
+        chanp->lc_b.lccall = lccall_b;
+        FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
+
+        chanp->outcallref = 64;
+        chanp->data_open = 0;
+}
+
+int
+CallcNewChan(void)
+{
+        int             i, ces, c;
+
+        chancount = 0;
+        for (i = 0; i < nrcards; i++)
+                if (cards[i].sp)
+                        chancount += 2;
+
+        chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
+                                      chancount, GFP_KERNEL, "chanlist");
+
+        c = 0;
+        ces = randomces();
+        for (i = 0; i < nrcards; i++)
+                if (cards[i].sp) {
+                        init_chan(c++, i, 1, ces++);
+                        ces %= 0xffff;
+                        init_chan(c++, i, 0, ces++);
+                        ces %= 0xffff;
+                }
+        printk(KERN_INFO "HiSax: %d channels available\n", chancount);
+        return (chancount);
+
+}
+
+static void
+release_is(int chan)
+{
+        struct PStack  *st = &chanlist[chan].is;
+
+        releasestack_isdnl2(st);
+        HiSax_rmlist(st->l1.hardware, st);
+        BufQueueRelease(&st->l2.i_queue);
+}
+
+void
+CallcFreeChan(void)
+{
+        int             i;
+
+        for (i = 0; i < chancount; i++)
+                release_is(i);
+        Sfree((void *) chanlist);
+}
+
+static void
+lldata_handler(struct PStack *st, int pr,
+               void *arg)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+        byte           *ptr;
+        int             size;
+        struct BufHeader *ibh = arg;
+
+        switch (pr) {
+          case (DL_DATA):
+                  if (chanp->data_open) {
+                          ptr = DATAPTR(ibh);
+                          ptr += chanp->ds.l2.ihsize;
+                          size = ibh->datasize - chanp->ds.l2.ihsize;
+                          iif.rcvcallb(drid, chanp->chan, ptr, size);
+                  }
+                  BufPoolRelease(ibh);
+                  break;
+          default:
+                  printk(KERN_WARNING "lldata_handler unknown primitive %d\n",
+                  	pr);
+                  break;
+        }
+}
+
+static void
+lltrans_handler(struct PStack *st, int pr,
+                struct BufHeader *ibh)
+{
+        struct Channel *chanp = (struct Channel *) st->l4.userdata;
+        byte           *ptr;
+
+        switch (pr) {
+          case (PH_DATA):
+                  if (chanp->data_open) {
+                          ptr = DATAPTR(ibh);
+                          iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
+                  }
+                  BufPoolRelease(ibh);
+                  break;
+          default:
+                  printk(KERN_WARNING "lltrans_handler unknown primitive %d\n",
+                  	pr);
+                  break;
+        }
+}
+
+static void
+ll_writewakeup(struct PStack *st)
+{
+        struct Channel *chanp = st->l4.userdata;
+        isdn_ctrl       ic;
+
+        ic.driver = drid;
+        ic.command = ISDN_STAT_BSENT;
+        ic.arg = chanp->chan;
+        iif.statcallb(&ic);
+}
+
+static int
+init_ds(int chan, int incoming)
+{
+        struct PStack  *st = &(chanlist[chan].ds);
+        struct IsdnCardState *sp = (struct IsdnCardState *)
+        				chanlist[chan].is.l1.hardware;
+        struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
+        char            tmp[128];
+
+        st->l1.hardware = sp;
+
+        hsp->mode = 2;
+        hsp->transbufsize = 4000;
+
+        if (setstack_hscx(st, hsp))
+                return (-1);
+
+        st->l2.extended = 0;
+        st->l2.laptype = LAPB;
+        st->l2.orig = !incoming;
+        st->l2.t200 = 1000;        /* 1000 milliseconds */
+        st->l2.window = 7;
+        st->l2.n200 = 4;           /* try 4 times       */
+        st->l2.t203 = 5000;        /* 5000 milliseconds */
+
+        st->l2.debug = 0xff;
+        st->l3.debug = 0xff;
+        switch (chanlist[chan].l2_active_protocol) {
+          case (ISDN_PROTO_L2_X75I):
+                  sprintf(tmp, "Channel %d x.75", chan);
+                  setstack_isdnl2(st, tmp);
+                  st->l2.l2l3 = lldata_handler;
+                  st->l1.l1man = dcc_l1man;
+                  st->l2.l2man = dcc_l2man;
+                  st->l4.userdata = chanlist + chan;
+                  st->l4.l1writewakeup = NULL;
+                  st->l4.l2writewakeup = ll_writewakeup;
+                  st->l2.l2m.debug = debugflags & 16;
+                  st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+                  st->l1.hscxmode = 2;        /* Packet-Mode ? */
+                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
+                  break;
+          case (ISDN_PROTO_L2_HDLC):
+                  st->l1.l1l2 = lltrans_handler;
+                  st->l1.l1man = dcc_l1man;
+                  st->l4.userdata = chanlist + chan;
+                  st->l4.l1writewakeup = ll_writewakeup;
+                  st->l1.hscxmode = 2;
+                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
+                  break;
+          case (ISDN_PROTO_L2_TRANS):
+                  st->l1.l1l2 = lltrans_handler;
+                  st->l1.l1man = dcc_l1man;
+                  st->l4.userdata = chanlist + chan;
+                  st->l4.l1writewakeup = ll_writewakeup;
+                  st->l1.hscxmode = 1;
+                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
+                  break;
+        }
+
+        return (0);
+
+}
+
+static void
+channel_report(int i)
+{
+}
+
+static void
+command_debug(struct Channel *chanp, char *s)
+{
+        char            tmp[64], tm[32];
+
+        jiftime(tm, jiffies);
+        sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
+        HiSax_putstatus(tmp);
+}
+
+static void
+distr_debug(void)
+{
+        int             i;
+
+        for (i = 0; i < chancount; i++) {  
+                chanlist[i].debug = debugflags & 1;
+                chanlist[i].fi.debug = debugflags & 2;
+                chanlist[i].is.l2.l2m.debug = debugflags & 8;
+                chanlist[i].ds.l2.l2m.debug = debugflags & 16;
+                chanlist[i].lc_d.lcfi.debug = debugflags & 128;
+                chanlist[i].lc_b.lcfi.debug = debugflags & 256;
+        }
+        for (i = 0; i < nrcards; i++)
+                if (cards[i].sp) {
+                        cards[i].sp->dlogflag = debugflags & 4;
+                        cards[i].sp->teistack->l2.l2m.debug = debugflags & 512;
+                }
+}
+
+int
+HiSax_command(isdn_ctrl * ic)
+{
+        struct Channel *chanp;
+        char            tmp[64];
+        int             i;
+        unsigned int    num;
+
+        switch (ic->command) {
+          case (ISDN_CMD_SETEAZ):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1)
+                          command_debug(chanp, "SETEAZ");
+                  return (0);
+          case (ISDN_CMD_DIAL):
+                  chanp = chanlist + (ic->arg & 0xff);
+                  if (chanp->debug & 1) {
+                          sprintf(tmp, "DIAL %s", ic->num);
+                          command_debug(chanp, tmp);
+                  }
+                  FsmEvent(&chanp->fi, EV_DIAL, ic);
+                  return (0);
+          case (ISDN_CMD_ACCEPTB):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1)
+                          command_debug(chanp, "ACCEPTB");
+                  FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
+                  break;
+          case (ISDN_CMD_ACCEPTD):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1)
+                          command_debug(chanp, "ACCEPTD");
+                  FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
+                  break;
+          case (ISDN_CMD_HANGUP):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1)
+                          command_debug(chanp, "HANGUP");
+                  FsmEvent(&chanp->fi, EV_HANGUP, NULL);
+                  break;
+          case (ISDN_CMD_SUSPEND):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1) {
+                          sprintf(tmp, "SUSPEND %s", ic->num);
+                          command_debug(chanp, tmp);
+                  }
+                  FsmEvent(&chanp->fi, EV_SUSPEND, ic);
+                  break;
+          case (ISDN_CMD_RESUME):
+                  chanp = chanlist + ic->arg;
+                  if (chanp->debug & 1) {
+                          sprintf(tmp, "RESUME %s", ic->num);
+                          command_debug(chanp, tmp);
+                  }
+                  FsmEvent(&chanp->fi, EV_RESUME, ic);
+                  break;
+          case (ISDN_CMD_LOCK):
+                  HiSax_mod_inc_use_count();
+#ifdef MODULE
+		  if (debugflags & 64) {
+		  	jiftime(tmp, jiffies);
+		  	i=strlen(tmp);
+                  	sprintf(tmp+i, "   LOCK modcnt %lx\n",mod_use_count_);
+		  	HiSax_putstatus(tmp);
+		  }
+#endif MODULE
+                  break;
+          case (ISDN_CMD_UNLOCK):
+                  HiSax_mod_dec_use_count();
+#ifdef MODULE
+		  if (debugflags & 64) {
+		  	jiftime(tmp, jiffies);
+		  	i=strlen(tmp);
+                  	sprintf(tmp+i, " UNLOCK modcnt %lx\n",mod_use_count_);
+		  	HiSax_putstatus(tmp);
+		  }
+#endif MODULE
+                  break;
+          case (ISDN_CMD_IOCTL):
+                  switch (ic->arg) {
+                    case (0):
+                            for (i = 0; i < nrcards; i++)
+                                    if (cards[i].sp)
+                                            HiSax_reportcard(i);
+                            for (i = 0; i < chancount; i++)
+                                    channel_report(i);
+                            break;
+                    case (1):
+                            debugflags = *(unsigned int *) ic->num;
+                            distr_debug();
+                            sprintf(tmp, "debugging flags set to %x\n", debugflags);
+                            HiSax_putstatus(tmp);
+			    printk(KERN_DEBUG "HiSax: %s", tmp);
+                            break;
+                    case (2):
+                            num = *(unsigned int *) ic->num;
+                            i = num >> 8;
+                            if (i >= chancount)
+                                    break;
+                            chanp = chanlist + i;
+                            chanp->impair = num & 0xff;
+                            if (chanp->debug & 1) {
+                                    sprintf(tmp, "IMPAIR %x", chanp->impair);
+                                    command_debug(chanp, tmp);
+                            }
+                            break;
+                    case (3):
+                    	    for (i = 0; i < *(unsigned int *)ic->num; i++)
+                 	    	HiSax_mod_dec_use_count();
+                 	    break;
+                    case (4):
+                    	    for (i = 0; i < *(unsigned int *)ic->num; i++)
+                 	    	HiSax_mod_inc_use_count();
+                 	    break;
+#ifdef MODULE
+                    case (55):
+                  	    mod_use_count_ &= 0xF0000000;
+                  	    HiSax_mod_inc_use_count();
+                  	    break;
+#endif MODULE
+                    case (11):
+                    	    num=0;
+        		    for (i = 0; i < nrcards; i++)
+                	    	if (cards[i].sp) {
+                        		cards[i].sp->debug = *(unsigned int *) ic->num;
+                        		num++;
+                       	    	}
+                       	    if (num) {
+                            	sprintf(tmp, "l1 debugging flags set to %x\n", 
+                            		*(unsigned int *) ic->num);
+                                HiSax_putstatus(tmp);
+			        printk(KERN_DEBUG "HiSax: %s", tmp);
+                       	    }
+                            break;
+                    case (12):
+                    	    num=0;
+        		    for (i = 0; i < chancount; i++) {  
+                		chanlist[i].is.l3.debug = *(unsigned int *)ic->num;
+                		chanlist[i].ds.l3.debug = *(unsigned int *)ic->num;
+                		num++;
+        		    }
+                       	    if (num) {
+                            	sprintf(tmp, "l3 debugging flags set to %x\n", 
+                            		*(unsigned int *) ic->num);
+                                HiSax_putstatus(tmp);
+			        printk(KERN_DEBUG "HiSax: %s", tmp);
+                       	    }
+                       	    break;
+                    default:  
+                    	    printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
+                    	    	(int)ic->arg);
+                    	    return (-EINVAL);
+                  }
+                  break;
+          case (ISDN_CMD_SETL2):
+                  chanp = chanlist + (ic->arg & 0xff);
+                  if (chanp->debug & 1) {
+                          sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
+                          command_debug(chanp, tmp);
+                  }
+                  chanp->l2_protocol = ic->arg >> 8;
+                  break;
+          default:
+                  break;
+        }
+
+        return (0);
+}
+
+int
+HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user)
+{
+        struct Channel *chanp = chanlist + chan;
+        struct PStack  *st = &chanp->ds;
+        struct BufHeader *ibh;
+        int             err, i;
+        byte           *ptr;
+
+	if (!chanp->data_open) {
+		command_debug(chanp, "writebuf: channel not open");
+		return -EIO;
+	}
+	
+        err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
+        if (err)
+                /* Must return 0 here, since this is not an error
+                 * but a temporary lack of resources.
+                 */
+                return 0;
+
+        ptr = DATAPTR(ibh);
+        if (chanp->lc_b.l2_establish)
+                i = st->l2.ihsize;
+        else
+                i = 0;
+
+        if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
+                printk(KERN_WARNING "HiSax_writebuf: packet too large!\n");
+                return (-EINVAL);
+        }
+
+        ptr += i;
+
+        if (user)
+                copy_from_user(ptr, buf, count);
+        else
+                memcpy(ptr, buf, count);
+        ibh->datasize = count + i;
+
+        if (chanp->data_open) {
+                if (chanp->lc_b.l2_establish)
+                        chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
+                else
+                        chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
+                return (count);
+        } else {
+                BufPoolRelease(ibh);
+                return (0);
+        }
+
+}
+
+static char    *
+strcpyupto(char *dest, char *src, char upto)
+{
+        while (*src && (*src != upto) && (*src != '\0'))
+                *dest++ = *src++;
+        *dest = '\0';
+        return (src);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- linux-2.0.26.org/drivers/isdn/hisax/config.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/config.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,280 @@
+/* $Id: config.c,v 1.4 1996/11/05 19:35:17 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ *
+ * $Log: config.c,v $
+ * Revision 1.4  1996/11/05 19:35:17  keil
+ * using config.h; some spelling fixes
+ *
+ * Revision 1.3  1996/10/23 17:23:28  keil
+ * default config changes
+ *
+ * Revision 1.2  1996/10/23 11:58:48  fritz
+ * Changed default setup to reflect user's selection of supported
+ * cards/protocols.
+ *
+ * Revision 1.1  1996/10/13 20:04:51  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include "hisax.h"
+
+/*
+ * This structure array contains one entry per card. An entry looks
+ * like this:
+ * 
+ * { type, protocol, p0, p1, p2, NULL }
+ *
+ * type
+ *    1 Teles 16.0   	p0=irq p1=membase p2=iobase
+ *    2 Teles  8.0   	p0=irq p1=membase
+ *    3 Teles 16.3   	p0=irq p1=iobase
+ *    4 Creatix PNP   	p0=irq p1=IO0 (ISAC)  p2=IO1 (HSCX)
+ *    5 AVM A1 (Fritz)  p0=irq p1=iobase
+ *    6 ELSA PCC16 	[p0=iobase] or nothing (autodetect)
+ *                    
+ *
+ * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
+ *
+ *
+ */
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+#define DEFAULT_CARD ISDN_CTYPE_ELSA
+#define DEFAULT_CFG {0,0,0}
+#endif
+#ifdef CONFIG_HISAX_AVM_A1
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_A1
+#define DEFAULT_CFG {10,0x340,0}
+#endif
+#ifdef CONFIG_HISAX_16_3
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_3
+#define DEFAULT_CFG {15,0x180,0}
+#endif
+#ifdef CONFIG_HISAX_16_0
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_0
+#define DEFAULT_CFG {15,0xd0000,0xd80}
+#endif
+
+#ifdef CONFIG_HISAX_1TR6
+#define DEFAULT_PROTO ISDN_PTYPE_1TR6
+#endif
+#ifdef CONFIG_HISAX_EURO
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_EURO
+#endif
+#ifndef DEFAULT_PROTO
+#error "HiSax: No D channel protocol configured"
+#endif
+#ifndef DEFAULT_CARD
+#error "HiSax: No cards configured"
+#endif
+ 
+#define FIRST_CARD { \
+  DEFAULT_CARD, \
+  DEFAULT_PROTO, \
+  DEFAULT_CFG, \
+  NULL, \
+}
+
+#define EMPTY_CARD	{0, 0, {0, 0, 0}, NULL}
+
+struct IsdnCard cards[] =
+{
+#if 0
+	{ISDN_CTYPE_16_0, ISDN_PTYPE_EURO,{15,0xd0000,0xd80}, NULL},	/* example */
+#endif
+	FIRST_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+};
+
+extern char	*HiSax_id;
+extern char	*l1_revision;
+extern int	HiSax_Installed;
+static char *HiSax_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
+}
+
+int             nrcards;
+
+typedef struct {
+	int             typ;
+	unsigned int    protocol;
+	unsigned int    para[3];
+} io_type;
+
+#define EMPTY_IO_TYPE	{0, 0, {0, 0, 0}}
+
+io_type         io[] =
+{
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+	EMPTY_IO_TYPE,
+};
+
+void
+HiSax_mod_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+void
+HiSax_mod_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+#ifdef MODULE
+#define HiSax_init init_module
+#else
+void HiSax_setup(char *str, int *ints)
+{
+        int  i, j, argc;
+	static char sid[20];
+
+        argc = ints[0];
+        i = 0;
+        j = 1;
+        while (argc && (i<16)) {
+                if (argc) {
+                        io[i].typ    = ints[j];
+                        j++; argc--;
+                }
+                if (argc) {
+                        io[i].protocol = ints[j];
+                        j++; argc--;
+                }
+                if (argc) {
+                        io[i].para[0]  = ints[j];
+                        j++; argc--;
+                }
+                if (argc) {
+                        io[i].para[1]  = ints[j];
+                        j++; argc--;
+                }
+                if (argc) {
+                        io[i].para[2]  = ints[j];
+                        j++; argc--;
+                }
+                i++;
+        }
+	if (strlen(str)) {
+		strcpy(sid,str);
+		HiSax_id = sid;
+	}
+}
+#endif
+
+int
+HiSax_init(void)
+{
+	int             i,j;
+	char		tmp[256];
+
+	nrcards = 0;
+
+	printk(KERN_NOTICE "HiSax: Driver for Siemens chip set ISDN cards\n");
+	printk(KERN_NOTICE "HiSax: Revision (");
+	strcpy(tmp,l1_revision);
+	printk("%s)\n",HiSax_getrev(tmp));
+	
+
+	for (i = 0; i < 16; i++) {
+		if ((io[i].typ>0) && (io[i].typ<=ISDN_CTYPE_COUNT)) {
+			cards[i].typ       = io[i].typ;
+			cards[i].protocol  = io[i].protocol;
+			for (j=0;j<3;j++)
+				cards[i].para[j] = io[i].para[j];
+		}
+	}
+	for (i = 0; i < 16; i++)
+                if (cards[i].typ>0)
+                        nrcards++;
+	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+               nrcards, (nrcards > 1) ? "s" : "");
+	if (HiSax_inithardware()) {
+                /* Install only, if at least one card found */
+                Isdnl2New();
+                TeiNew();
+                CallcNew();
+                ll_init();
+
+		/* No symbols to export, hide all symbols */
+		register_symtab(NULL);
+
+#ifdef MODULE
+                printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+		HiSax_Installed = 1;
+                return (0);
+        } else
+                return -EIO;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+
+	ll_stop();
+	TeiFree();
+	Isdnl2Free();
+	CallcFree();
+	HiSax_closehardware();
+	HiSax_Installed = 0;
+	ll_unload();
+	printk(KERN_NOTICE "HiSax module removed\n");
+
+}
+#endif
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- linux-2.0.26.org/drivers/isdn/hisax/elsa.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/elsa.c	Mon Dec  9 00:09:29 1996
@@ -0,0 +1,1304 @@
+/* $Id: elsa.c,v 1.5 1996/12/08 19:46:14 keil Exp $
+ *
+ * elsa.c     low level stuff for Elsa isdn cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Elsa GmbH for documents and informations
+ *
+ * 
+ * $Log: elsa.c,v $
+ * Revision 1.5  1996/12/08 19:46:14  keil
+ * PCC-8 correct IRQs; starting ARCOFI support
+ *
+ * Revision 1.4  1996/11/18 20:50:54  keil
+ * with PCF Pro release 16 Byte IO
+ *
+ * Revision 1.3  1996/11/18 15:33:04  keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.2  1996/10/27 22:08:03  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:52  keil
+ * Initial revision
+ *
+ *
+*/
+
+#define ARCOFI_USE	0
+
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "elsa.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const   char    *CardType[];
+
+const  char    *Elsa_Types[] = {"None","PCC-8","PCF-Pro","PCC-16","PCF"};
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline byte
+readhscx(unsigned int adr, int hscx, byte off)
+{
+	register byte		ret;
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	byteout(adr+CARD_ALE,off +(hscx?0x60:0x20));
+        ret = bytein(adr +CARD_HSCX);
+	restore_flags(flags);
+        return (ret);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
+{
+	/* fifo read without cli because it's allready done  */
+	
+	byteout(adr +CARD_ALE, (hscx?0x40:0));
+	insb(adr +CARD_HSCX, data, size);
+}
+
+        
+static inline void
+writehscx(unsigned int adr, int hscx, byte off, byte data)
+{
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	byteout(adr +CARD_ALE, off +(hscx?0x60:0x20));
+	byteout(adr +CARD_HSCX, data);
+	restore_flags(flags);
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
+{
+	/* fifo write without cli because it's allready done  */
+	byteout(adr +CARD_ALE, (hscx?0x40:0));
+	outsb(adr +CARD_HSCX, data, size);
+
+}
+
+static inline byte
+readisac(unsigned int adr, byte off)
+{
+	register byte		ret;
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	byteout(adr +CARD_ALE, off +0x20);
+	ret = bytein(adr);
+	restore_flags(flags);
+        return (ret);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, byte * data, int size)
+{
+	/* fifo read without cli because it's allready done  */
+
+	byteout(adr +CARD_ALE, 0);
+	insb(adr , data, size);
+}
+
+        
+static inline void
+writeisac(unsigned int adr, byte off, byte data)
+{
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	byteout(adr +CARD_ALE, off +0x20);
+	byteout(adr, data);
+	restore_flags(flags);
+}
+
+static inline void
+write_fifo_isac(unsigned int adr, byte * data, int size)
+{
+	/* fifo write without cli because it's allready done  */
+
+	byteout(adr +CARD_ALE, 0);
+	outsb(adr, data, size);
+}
+
+static inline void 
+elsa_led_handler(struct IsdnCardState *sp) {
+
+	byte	outval=0xf0;
+	int	stat=0,cval;
+	
+	
+	if ((sp->ph_state==0) ||(sp->ph_state==15)) {
+		stat=1;
+	} else {
+	 	if (sp->hs[0].mode!=0) 
+			stat|=2;
+	 	if (sp->hs[1].mode!=0) 
+			stat|=4;
+	}
+	cval = (sp->counter>>6)&3;
+	switch (cval) {
+	  case 0:
+	  	if (!stat) 
+	  		outval |= STAT_LED;
+	  	else if (stat==1)
+	  		outval |= LINE_LED |STAT_LED;
+	  	else {
+	  		if (stat & 2)
+	  			outval |= STAT_LED;
+	  		if (stat & 4)
+	  			outval |= LINE_LED;
+	  	}
+	  	break;
+	  case 1:
+	  	if (!stat) 
+	  		outval |= LINE_LED;
+	  	else if (stat==1)
+	  		outval |= LINE_LED |STAT_LED;
+	  	else {  
+	  		if (stat & 2)
+	  			outval |= STAT_LED;
+	  		if (stat & 4)
+	  			outval |= LINE_LED;
+	  	}
+	  	break; 
+	  case 2:
+	  	if (!stat) 
+	  		outval |= STAT_LED;
+	  	else if (stat==1)
+	  		outval |= 0;
+	  	else {  
+	  		if (stat & 2)
+	  			outval |= STAT_LED;
+	  		if (stat & 4)
+	  			outval |= LINE_LED;
+	  	}
+	  	break;
+	  case 3:
+	  	if (!stat) 
+	  		outval |= LINE_LED;
+	  	break;
+	}
+	byteout(sp->cfg_reg +CARD_CONTROL, outval);
+}
+
+static inline void
+waitforCEC(int adr, int hscx)
+{
+	int            to = 50;
+
+	while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+}
+
+    
+static inline void
+waitforXFW(int adr, int hscx)
+{
+	int            to = 50;
+
+	while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, byte data)
+{
+	long            flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr, hscx);
+	writehscx(adr, hscx, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+        printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR));
+}
+
+void
+elsa_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	byte			*ptr;
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh = hsp->rcvibh;
+	long 			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
+					      HSCX_RBUF_BPPS)) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->rcvptr;
+
+	hsp->rcvptr += count;
+	save_flags(flags);
+	cli();
+        read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+        writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_empty_fifo %c cnt %d",
+			hsp->hscx?'B':'A',count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh;
+	int			more, count;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	ibh = hsp->xmtibh;
+	if (!ibh)
+                return;
+
+	count = ibh->datasize - hsp->sendptr;
+	if (count <= 0)
+                return;
+
+	more = (hsp->mode == 1)?1:0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->sendptr;
+	hsp->sendptr += count;
+
+        waitforXFW(sp->cfg_reg, hsp->hscx);
+	save_flags(flags);
+	cli();
+        write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+        writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_fill_fifo %c cnt %d",
+			hsp->hscx?'B':'A', count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
+{
+	byte             r;
+	struct HscxState *hsp = sp->hs + hscx;
+	int              count, err;
+	char		 tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode) 
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			if (hsp->rcvibh)
+				BufPoolRelease(hsp->rcvibh);
+			hsp->rcvibh = NULL;
+			writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+			goto afterRME;
+		}
+		if (!hsp->rcvibh)
+			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+                                       GFP_ATOMIC, (void *) 1, 1)) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RME out of buffers");
+				writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+				goto afterRME;
+			} else
+				hsp->rcvptr = 0;
+
+		count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		hscx_empty_fifo(hsp, count);
+		hsp->rcvibh->datasize = hsp->rcvptr - 1;
+		BufQueueLink(&hsp->rq, hsp->rcvibh);
+		hsp->rcvibh = NULL;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+      afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!hsp->rcvibh) {
+			if (hsp->mode == 1)
+				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
+					GFP_ATOMIC, (void *)1, 2);
+			else
+				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+					GFP_ATOMIC, (void *)1, 2);
+			
+			if (err) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RPF out of buffers");
+				writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+				goto afterRPF;
+			} else
+				hsp->rcvptr = 0;
+		}
+		
+		hscx_empty_fifo(hsp, 32);
+                if (hsp->mode == 1) {
+                        /* receive audio data */
+                        hsp->rcvibh->datasize = hsp->rcvptr;
+                        BufQueueLink(&hsp->rq, hsp->rcvibh);
+                        hsp->rcvibh = NULL;
+                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+                }
+                
+	}
+      afterRPF:
+	if (val & 0x10) {	/* XPR */
+		if (hsp->xmtibh)
+			if (hsp->xmtibh->datasize > hsp->sendptr) {
+				hscx_fill_fifo(hsp);
+				goto afterXPR;
+			} else {
+				if (hsp->releasebuf)
+					BufPoolRelease(hsp->xmtibh);
+				hsp->sendptr = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->xmtibh = NULL;
+			}
+		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
+			hsp->releasebuf = !0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+      afterXPR:
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	byte			*ptr;
+	struct BufHeader	*ibh = sp->rcvibh;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_empty_fifo"); 
+
+	if (sp->rcvptr >= 3072) {
+		if (sp->debug & L1_DEB_WARN) {
+			char		 tmp[40];
+			sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
+        		debugl1(sp, tmp); 
+		}
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->rcvptr;
+	sp->rcvptr += count;
+
+	save_flags(flags);
+	cli();
+        read_fifo_isac(sp->cfg_reg, ptr, count);
+        writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_empty_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	struct BufHeader	*ibh;
+	int			count, more;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_fill_fifo"); 
+
+	ibh = sp->xmtibh;
+	if (!ibh)
+		return;
+
+	count = ibh->datasize - sp->sendptr;
+	if (count <= 0)
+		return;
+	if (count >= 3072)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->sendptr;
+	sp->sendptr += count;
+
+	save_flags(flags);
+	cli();
+	write_fifo_isac(sp->cfg_reg, ptr, count);
+        writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_fill_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char	tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+        	debugl1(sp, tmp);
+        } 
+	writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, byte val) {
+	byte			exval,v1;
+	unsigned int    	count;
+	char			tmp[32];    
+#if ARCOFI_USE 
+	struct BufHeader	*ibh;
+	byte			*ptr;
+#endif
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+        	debugl1(sp, tmp); 
+        }
+	if (val & 0x80) {	/* RME */
+		exval = readisac(sp->cfg_reg, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC CRC error");
+			if (sp->rcvibh)
+				BufPoolRelease(sp->rcvibh);
+			sp->rcvibh = NULL;
+			writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+			goto afterRME;
+		}
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC,(void *) 1, 3)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+				goto afterRME;
+			} else
+				sp->rcvptr = 0;
+		count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(sp, count);
+		sp->rcvibh->datasize = sp->rcvptr;
+		BufQueueLink(&(sp->rq), sp->rcvibh);
+		sp->rcvibh = NULL;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC, (void *) 1, 4)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+				goto afterRPF;
+			} else
+				sp->rcvptr = 0;
+		isac_empty_fifo(sp, 32);
+	}
+	afterRPF:
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->xmtibh)
+			if (sp->xmtibh->datasize > sp->sendptr) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				if (sp->releasebuf)
+					BufPoolRelease(sp->xmtibh);
+				sp->xmtibh = NULL;
+				sp->sendptr = 0;
+			}
+		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
+			sp->releasebuf = !0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+	afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2) 
+				& 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+        		sprintf(tmp, "l1state %d", sp->ph_state);
+        		debugl1(sp, tmp);
+        	}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readisac(sp->cfg_reg, ISAC_EXIR); 
+		if (sp->debug & L1_DEB_WARN) {
+        		sprintf(tmp, "ISAC EXIR %02x", exval);
+        		debugl1(sp, tmp);
+        	}
+        	if (exval & 0x08) {
+			v1 = readisac(sp->cfg_reg, ISAC_MOSR); 
+			if (sp->debug & L1_DEB_WARN) {
+        			sprintf(tmp, "ISAC MOSR %02x", v1);
+        			debugl1(sp, tmp);
+        		}
+#if ARCOFI_USE
+        		if (v1 & 0x08) {
+				if (!sp->mon_rx)
+					if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+                        			GFP_ATOMIC,(void *) 1, 3)) {
+						if (sp->debug & L1_DEB_WARN)
+        						debugl1(sp, "ISAC MON RX out of buffers!");
+						writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+						goto afterMONR0;
+					} else
+						sp->mon_rxp = 0;
+				ibh = sp->mon_rx;
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_rxp;
+				sp->mon_rxp++;
+				if (sp->mon_rxp>= 3072) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+					sp->mon_rxp = 0;
+					if (sp->debug & L1_DEB_WARN)
+        					debugl1(sp, "ISAC MON RX overflow!");
+					goto afterMONR0;
+				}
+				*ptr = readisac(sp->cfg_reg, ISAC_MOR0); 
+				if (sp->debug & L1_DEB_WARN) {
+        				sprintf(tmp, "ISAC MOR0 %02x", *ptr);
+        				debugl1(sp, tmp);
+        			}
+        		} 
+afterMONR0:
+        		if (v1 & 0x80) {
+				if (!sp->mon_rx)
+					if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+                        			GFP_ATOMIC,(void *) 1, 3)) {
+						if (sp->debug & L1_DEB_WARN)
+        						debugl1(sp, "ISAC MON RX out of buffers!");
+						writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+						goto afterMONR1;
+					} else
+						sp->mon_rxp = 0;
+				ibh = sp->mon_rx;
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_rxp;
+				sp->mon_rxp++;
+				if (sp->mon_rxp>= 3072) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+					sp->mon_rxp = 0;
+					if (sp->debug & L1_DEB_WARN)
+        					debugl1(sp, "ISAC MON RX overflow!");
+					goto afterMONR1;
+				}
+				*ptr = readisac(sp->cfg_reg, ISAC_MOR1); 
+				if (sp->debug & L1_DEB_WARN) {
+        				sprintf(tmp, "ISAC MOR1 %02x", *ptr);
+        				debugl1(sp, tmp);
+        			}
+        		} 
+afterMONR1:
+        		if (v1 & 0x04) {
+        			writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+				sp->mon_rx->datasize = sp->mon_rxp;
+				sp->mon_flg |= MON0_RX;
+        		} 
+        		if (v1 & 0x40) {
+        			writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+				sp->mon_rx->datasize = sp->mon_rxp;
+				sp->mon_flg |= MON1_RX;
+        		} 
+        		if (v1 == 0x02) {
+				ibh = sp->mon_tx;
+				if (!ibh) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+					goto AfterMOX0;
+				}
+				count = ibh->datasize - sp->mon_txp;
+				if (count <= 0) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
+					BufPoolRelease(sp->mon_tx);
+					sp->mon_tx  = NULL;
+					sp->mon_txp = 0;
+					sp->mon_flg |= MON0_TX;
+					goto AfterMOX0;
+				}
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_txp;
+				sp->mon_txp++;
+        			writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
+        		} 
+AfterMOX0:
+        		if (v1 == 0x20) {
+				ibh = sp->mon_tx;
+				if (!ibh) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+					goto AfterMOX1;
+				}
+				count = ibh->datasize - sp->mon_txp;
+				if (count <= 0) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
+					BufPoolRelease(sp->mon_tx);
+					sp->mon_tx  = NULL;
+					sp->mon_txp = 0;
+					sp->mon_flg |= MON1_TX;
+					goto AfterMOX1; 
+				}
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_txp;
+				sp->mon_txp++;
+        			writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
+        		} 
+AfterMOX1:
+#endif
+        	}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, byte val) {
+
+	byte    		exval;
+	struct HscxState	*hsp;
+	char			tmp[32];
+	
+		
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+        	exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
+	        if (exval == 0x40) {
+                	if (hsp->mode == 1)
+        	        	hscx_fill_fifo(hsp);
+	                else {
+                        	/* Here we lost an TX interrupt, so
+                        	* restart transmitting the whole frame.
+                	        */
+        	                hsp->sendptr = 0;
+				writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+                        }
+                } else
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX B EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+        		debugl1(sp, tmp); 
+        	}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+                exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+	                	/* Here we lost an TX interrupt, so
+        	        	* restart transmitting the whole frame.
+                		*/
+                		hsp->sendptr = 0;
+				writehscxCMDR(sp->cfg_reg, hsp->hscx,0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+        		}
+		} else 
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX A EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+        if (val & 0x04) {
+                exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+        		debugl1(sp, tmp); 
+        	}
+        	hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	byte                 val, sval, stat=0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	
+	if (!sp) {
+		printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+		return;
+	}
+	
+	sval = bytein(sp->cfg_reg + 5);
+	INT_RESTART:
+	if (!(sval & sp->mask1)) {
+		/* Timer Restart */
+		bytein(sp->cfg_reg + 6);
+		if (!(sp->counter++ & 0x3f)) {
+			/* Call LEDs all 64 tics */
+				elsa_led_handler(sp);
+		}
+	}
+
+	val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+	Start_HSCX:
+	if (val) {
+		hscx_int_main(sp,val);
+		stat |= 1;
+	}
+	val = readisac(sp->cfg_reg, ISAC_ISTA);
+	Start_ISAC:
+	if (val) { 
+		isac_interrupt(sp,val);
+		stat |= 2;
+	}
+
+	sval = bytein(sp->cfg_reg + 5);
+	if (!(sval & sp->mask1)) 
+		goto INT_RESTART;
+
+	val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX) 
+        		debugl1(sp, "HSCX IntStat after IntRoutine"); 
+		goto Start_HSCX;
+	}
+	val = readisac(sp->cfg_reg, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC) 
+        		debugl1(sp, "ISAC IntStat after IntRoutine"); 
+		goto Start_ISAC;
+	}
+	if (stat & 1) {
+		writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
+		writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
+		writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
+		writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
+		writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+	}
+
+}
+
+
+static void
+initisac(struct IsdnCardState    *sp)
+{
+	unsigned int	adr=sp->cfg_reg;
+	
+	/* Elsa IOM 2 Mode */
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_ADF2, 0x80);
+	writeisac(adr, ISAC_SQXR, 0x2f);
+	writeisac(adr, ISAC_SPCR, 0x00);
+	writeisac(adr, ISAC_STCR, 0x70);
+	writeisac(adr, ISAC_MODE, 0xc9);
+	writeisac(adr, ISAC_TIMR, 0x00);
+	writeisac(adr, ISAC_ADF1, 0x00);
+	writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int             hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char  tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+	        	'A'+hscx, mode, ichan);
+        	debugl1(sp, tmp);
+        } 
+        hs->mode = mode;
+        writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85);
+        writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF);
+        writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF);
+        writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF);
+        writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0);
+        writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0);
+        writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30);
+
+        switch (mode) {
+	case (0):
+		writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff);
+		writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff);
+		writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84);
+        	break;
+	case (1):
+                if (ichan == 0) {
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+                } else {
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+                }
+		writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4);
+		writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+        	break;
+	case (2):
+                if (ichan == 0) {
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+                } else {
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+                }
+		writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+		writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c);
+		writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+        	break;
+        }
+	writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+}
+
+void release_io_elsa(struct IsdnCard *card) {
+	int bytecnt=8;
+	
+	if (card->sp->subtyp == ELSA_PCFPRO)
+		bytecnt=16;
+	if (card->sp->cfg_reg) 
+		release_region(card->sp->cfg_reg, bytecnt);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+        writeisac(sp->cfg_reg, ISAC_MASK, 0);
+        writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
+}
+
+static void
+check_arcofi(struct IsdnCardState *sp)
+{
+#if 0
+	byte 	val;
+	char  	tmp[40];
+	char	*t;
+	ulong	timeout;
+	long	flags;
+	byte    *p;
+	
+	if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool),
+        	GFP_ATOMIC,(void *) 1, 3)) {
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC MON TX out of buffers!");
+		return;
+	} else
+		sp->mon_txp = 0;
+	p = DATAPTR(sp->mon_tx);
+	*p++ = 0xa0;
+	*p++ = 0x0;
+	sp->mon_tx->datasize = 2;
+	sp->mon_txp = 1;
+	sp->mon_flg = 0;
+        writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+        val=readisac(sp->cfg_reg,ISAC_MOSR);
+        writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0);
+        writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0);
+	save_flags(flags);
+	timeout = jiffies +3;
+	sti();
+	while (timeout != jiffies);  /* Warte auf Startflanke */
+	restore_flags(flags);
+	if (sp->mon_flg & MON1_TX) {
+		if (sp->mon_flg & MON1_RX) {
+			sprintf(tmp,"Arcofi response received %d bytes", sp->mon_rx->datasize);
+			debugl1(sp, tmp);
+			p = DATAPTR(sp->mon_rx);
+			t=tmp;
+			t += sprintf(tmp,"Arcofi data");
+                        QuickHex(t,p,sp->mon_rx->datasize);
+			debugl1(sp, tmp);
+			BufPoolRelease(sp->mon_rx);
+			sp->mon_rx  = NULL;
+			sp->mon_rxp = 0;
+			sp->mon_flg = 0;
+		}
+	} else if (sp->mon_tx) {
+		BufPoolRelease(sp->mon_tx);
+		sp->mon_tx  = NULL;
+		sp->mon_txp = 0;
+		sprintf(tmp,"Arcofi not detected");
+		debugl1(sp, tmp);
+	}
+	sp->mon_flg = 0;
+#endif
+}
+
+int
+initelsa(struct IsdnCardState *sp)
+{
+	int	ret, irq_cnt;
+	char  	tmp[40];
+	ulong	timeout;
+	long	flags;
+	
+	sp->counter = 0;
+	irq_cnt = kstat.interrupts[sp->irq]; 
+	sprintf(tmp, "IRQ %d count %d", sp->irq, irq_cnt);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr,&elsa_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		save_flags(flags);
+		sp->counter = 0;
+		timeout = jiffies +1;
+		sti();
+		while (timeout != jiffies);  /* Warte auf Startflanke */
+		bytein(sp->cfg_reg +CARD_START_TIMER);
+		byteout(sp->cfg_reg +CARD_CONTROL,ISDN_RESET |ENABLE_TIM_INT);
+		timeout += 111;
+		while (timeout != jiffies);  /* Warte 1,11 s */
+		restore_flags(flags);
+		printk(KERN_INFO "Elsa: %d timer tics in 1.11 sek\n",
+			sp->counter);
+		if (abs(sp->counter-125)<2) {
+			printk(KERN_INFO "Elsa: timer and irq OK\n");
+		} else {
+        		printk(KERN_WARNING 
+        		"Elsa: timer problem maybe an IRQ(%d) conflict\n",
+        		sp->irq);
+        	}
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+        	debugl1(sp, tmp);
+        	if (kstat.interrupts[sp->irq]==irq_cnt) {
+        		printk(KERN_WARNING 
+        		"Elsa: IRQ(%d) getting no interrupts during init\n",
+        		sp->irq);
+        		irq2dev_map[sp->irq] = NULL;
+        		free_irq(sp->irq, NULL);
+        		return(0); 
+        	}
+		check_arcofi(sp); 
+	}
+	sp->counter=0;
+	return(ret);
+}
+
+static unsigned char
+probe_elsa_adr(unsigned int adr)
+{
+	int	i, in1, in2, p16_1=0, p16_2=0,
+		pcc_1=0, pcc_2=0, pfp_1=0, pfp_2=0;
+	long flags;
+	
+        if (check_region(adr,8)) {
+		printk(KERN_WARNING
+			"Probing ELSA Port 0x%x: already in use\n",
+                               	adr);
+                return(0);
+        }
+	save_flags(flags);
+	cli();
+	for (i=0;i<16;i++) {
+		in1 = inb(adr + CARD_CONFIG);  /* 'toggelt' bei */
+		in2 = inb(adr + CARD_CONFIG);  /* jedem Zugriff */
+		p16_1 += 0x04 & in1;
+		p16_2 += 0x04 & in2;
+		pcc_1 += 0x02 & in1;
+		pcc_2 += 0x02 & in2;
+		pfp_1 += 0x40 & in1;
+		pfp_2 += 0x40 & in2;
+	}
+	restore_flags(flags);
+        printk(KERN_INFO "Probing IO 0x%x",adr);
+	if (65 == ++p16_1 * ++p16_2) {
+                printk(" PCC-16/PCF found\n");
+                return(3);
+        } else if (1025 == ++pfp_1 * ++pfp_2) {
+                printk(" PCF-Pro found\n");
+                return(2);
+        } else if (33 == ++pcc_1 * ++pcc_2) {
+                printk(" PCC8 found\n");
+                return(1);
+        } else {
+                printk(" failed\n");
+                return(0);
+        }
+}
+
+static unsigned int
+probe_elsa(struct IsdnCardState    *sp)
+{
+	int i;
+	unsigned int	CARD_portlist[] = {0x160, 0x170, 0x260, 0x360, 0};
+
+	for (i = 0; CARD_portlist[i]; i++) {
+		if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i]))) 
+			break;
+        }
+	return(CARD_portlist[i]);
+}
+
+int
+setup_elsa(struct IsdnCard *card)
+{
+	ulong			timout;
+	long			flags;
+	int			bytecnt;
+	byte			val, verA, verB;
+	struct IsdnCardState 	*sp = card->sp;
+        
+	if (sp->typ != ISDN_CTYPE_ELSA)
+		return(0);
+		
+        sp->cfg_reg = card->para[0];
+
+ 	printk(KERN_INFO "Elsa: Mircolink IO probing\n");
+        if (sp->cfg_reg) {
+        	if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+                	printk(KERN_WARNING 
+                		"Elsa: no Elsa Mircolink at 0x%x\n",
+                		sp->cfg_reg);
+                		return(0);
+          	}
+        } else 
+        	sp->cfg_reg = probe_elsa(sp);
+        if (sp->cfg_reg) {
+                val=bytein(sp->cfg_reg + CARD_CONFIG);
+        	if (sp->subtyp == ELSA_PCC) {
+        		const byte CARD_IrqTab[8] = { 7, 3, 5, 9, 0, 0, 0, 0 };
+        		sp->irq = CARD_IrqTab[(val & 0x0c) >>2];
+        	} else {
+        		const byte CARD_IrqTab[8] = { 15, 10, 15, 3, 11, 5, 11, 9};
+        		sp->irq = CARD_IrqTab[(val & 0x38) >>3];
+        	}
+                val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+                if (val < 3) val |= 8;
+                val += 'A' - 3;
+                if (val=='B' || val=='C') val ^= 1; 
+                if ((sp->subtyp == ELSA_PCFPRO) && (val='G')) val = 'C';
+		printk(KERN_INFO 
+			"Elsa: %s found at 0x%x Rev.:%c IRQ %d\n",
+			Elsa_Types[sp->subtyp],
+			sp->cfg_reg,
+			val, sp->irq);
+                val = bytein(sp->cfg_reg + CARD_ALE) & 0x08;
+                if (val) 
+			printk(KERN_WARNING
+				"Elsa: Mircolink PCC S0 bus power bad\n");
+	} else {
+		printk(KERN_WARNING 
+			"No Elsa Mircolink found\n");
+                	return(0);
+	}
+
+	switch (sp->subtyp) {
+		case ELSA_PCC:  bytecnt = 8;
+				sp->mask1 = TIMER_RUN_PCC;
+				break;
+		case ELSA_PCFPRO:bytecnt = 16;
+				sp->mask1 = TIMER_RUN;
+				break;
+		case ELSA_PCC16:bytecnt = 8;
+				sp->mask1 = TIMER_RUN;
+				break;
+		case ELSA_PCF:  bytecnt = 16;
+				sp->mask1 = TIMER_RUN;
+				break;
+		default:
+				printk(KERN_WARNING 
+					"Unknown ELSA subtype %d\n", sp->subtyp);
+                		return(0);
+	}
+	
+ 	if (check_region((sp->cfg_reg), bytecnt)) {
+        	printk(KERN_WARNING
+                "HiSax: %s config port %x-%x already in use\n",
+                CardType[card->typ],
+                sp->cfg_reg,
+                sp->cfg_reg + bytecnt);
+                return (0);
+        } else {
+                request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+	}
+
+	/* Teste Timer */
+	bytein(sp->cfg_reg +CARD_START_TIMER);
+	if (!(bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1)) {
+		bytein(sp->cfg_reg +CARD_START_TIMER); /* 2. Versuch */
+		if (!(bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1)) { 
+        		printk(KERN_WARNING "Elsa: timer do not start\n");
+        		release_io_elsa(card);
+        		return(0);
+        	}
+        }
+        timout = jiffies +1;
+	save_flags(flags);
+	sti();
+	while (timout != jiffies);  /* Warte auf Startflanke */
+	bytein(sp->cfg_reg +CARD_START_TIMER);
+	while (timout == jiffies);  /* Warte 10 ms */
+	restore_flags(flags);
+	if (bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1) { 
+        	printk(KERN_WARNING "Elsa: timer do not run down\n");
+        	release_io_elsa(card);
+        	return(0);
+        }
+        printk(KERN_INFO "Elsa: timer OK; resetting card\n");
+	/* Wait 1 Timer */        
+	bytein(sp->cfg_reg +CARD_START_TIMER);
+	while(!(bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1));
+        byteout(sp->cfg_reg+4,0x00);  /* Reset On */
+	/* Wait 1 Timer */        
+	bytein(sp->cfg_reg +CARD_START_TIMER);
+	while(!(bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1));
+        byteout(sp->cfg_reg+4,ISDN_RESET);  /* Reset Off */
+	/* Wait 1 Timer */        
+	bytein(sp->cfg_reg +CARD_START_TIMER);
+	while(!(bytein(sp->cfg_reg +CARD_CONFIG) & sp->mask1));
+
+        verA=readhscx(sp->cfg_reg, 0,HSCX_VSTR) & 0xf;
+        verB=readhscx(sp->cfg_reg, 1,HSCX_VSTR) & 0xf;
+        printk(KERN_INFO "Elsa: HSCX version A: %s  B: %s\n",
+        	HscxVersion(verA), HscxVersion(verB));
+        val = readisac(sp->cfg_reg, ISAC_RBCH);
+        printk(KERN_INFO "Elsa: ISAC %s\n",
+        	ISACVersion(val));
+
+        sp->modehscx       = &modehscx;
+        sp->ph_command     = &ph_command;
+        sp->hscx_fill_fifo = &hscx_fill_fifo;
+        sp->isac_fill_fifo = &isac_fill_fifo;
+        
+	return (1);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/elsa.h linux/drivers/isdn/hisax/elsa.h
--- linux-2.0.26.org/drivers/isdn/hisax/elsa.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/elsa.h	Mon Dec  9 00:09:29 1996
@@ -0,0 +1,59 @@
+/* $Id: elsa.h,v 1.3 1996/12/08 19:47:38 keil Exp $
+ *
+ * elsa.h   Header for Elsa ISDN cards
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ * 
+ * Thanks to    Elsa GmbH for documents and informations
+ *
+ *
+ * $Log: elsa.h,v $
+ * Revision 1.3  1996/12/08 19:47:38  keil
+ * ARCOFI support
+ *
+ * Revision 1.2  1996/11/18 15:33:35  keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.1  1996/10/13 20:03:45  keil
+ * Initial revision
+ *
+ *
+*/
+
+#define CARD_ISAC	0
+#define CARD_HSCX	2
+#define CARD_ALE	3
+#define CARD_CONTROL	4
+#define CARD_CONFIG	5
+#define CARD_START_TIMER 6
+#define CARD_TRIG_IRQ	7
+
+#define ELSA_PCC     1
+#define ELSA_PCFPRO  2
+#define ELSA_PCC16   3
+#define ELSA_PCF     4
+
+/***                                                                    ***
+ ***   Makros als Befehle fuer die Kartenregister                       ***
+ ***   (mehrere Befehle werden durch Bit-Oderung kombiniert)            ***
+ ***                                                                    ***/
+
+/* Config-Register (Read) */
+#define TIMER_RUN       0x02    /* Bit 1 des Config-Reg     */
+#define TIMER_RUN_PCC   0x01    /* Bit 0 des Config-Reg  bei PCC */
+#define IRQ_INDEX       0x38    /* Bit 3,4,5 des Config-Reg */
+
+/* Control-Register (Write) */
+#define LINE_LED        0x02    /* Bit 1 Gelbe LED */
+#define STAT_LED        0x08    /* Bit 3 Gruene LED */
+#define ISDN_RESET      0x20    /* Bit 5 Reset-Leitung */
+#define ENABLE_TIM_INT  0x80    /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define HW_RELEASE      0x07    /* Bit 0-2 Hardwarerkennung */
+#define S0_POWER_BAD    0x08    /* Bit 3 S0-Bus Spannung fehlt */ 
+
+extern	void elsa_report(struct IsdnCardState *sp);
+extern  void release_io_elsa(struct IsdnCard *card);
+extern	int  setup_elsa(struct IsdnCard *card);
+extern  int  initelsa(struct IsdnCardState *sp);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- linux-2.0.26.org/drivers/isdn/hisax/fsm.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/fsm.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,162 @@
+/* $Id: fsm.c,v 1.1 1996/10/13 20:04:52 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: fsm.c,v $
+ * Revision 1.1  1996/10/13 20:04:52  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+void
+FsmNew(struct Fsm *fsm,
+       struct FsmNode *fnlist, int fncount)
+{
+	int             i;
+
+	fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
+					  GFP_KERNEL, "Fsm jumpmatrix");
+	memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
+
+	for (i = 0; i < fncount; i++)
+		fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+			      fnlist[i].state] = (int) fnlist[i].routine;
+}
+
+void
+FsmFree(struct Fsm *fsm)
+{
+	Sfree((void *) fsm->jumpmatrix);
+}
+
+int
+FsmEvent(struct FsmInst *fi, int event, void *arg)
+{
+	void            (*r) (struct FsmInst *, int, void *);
+	char            str[80];
+
+	r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+	if (r) {
+		if (fi->debug) {
+			sprintf(str, "State %s Event %s",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+			fi->printdebug(fi, str);
+		}
+		r(fi, event, arg);
+		return (0);
+	} else {
+		if (fi->debug) {
+			sprintf(str, "State %s Event %s no routine",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+			fi->printdebug(fi, str);
+		}
+		return (!0);
+	}
+}
+
+void
+FsmChangeState(struct FsmInst *fi, int newstate)
+{
+	char            str[80];
+
+	fi->state = newstate;
+	if (fi->debug) {
+		sprintf(str, "ChangeState %s",
+			fi->fsm->strState[newstate]);
+		fi->printdebug(fi, str);
+	}
+}
+
+static void
+FsmExpireTimer(struct FsmTimer *ft)
+{
+	FsmEvent(ft->fi, ft->event, ft->arg);
+}
+
+void
+FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+	ft->fi = fi;
+	ft->tl.function = (void *) FsmExpireTimer;
+	ft->tl.data = (long) ft;
+	init_timer(&ft->tl);
+}
+
+void
+FsmDelTimer(struct FsmTimer *ft, int where)
+{
+	long            flags;
+
+#if 0
+	if (ft->fi->debug) {
+		sprintf(str, "FsmDelTimer %lx %d", ft, where);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+
+	save_flags(flags);
+	cli();
+	if (ft->tl.next)
+		del_timer(&ft->tl);
+	restore_flags(flags);
+}
+
+int
+FsmAddTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if 0
+	if (ft->fi->debug) {
+		sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+
+	if (ft->tl.next) {
+		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
+		return -1;
+	}
+	init_timer(&ft->tl);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&ft->tl);
+	return 0;
+}
+
+int
+FsmTimerRunning(struct FsmTimer *ft)
+{
+	return (ft->tl.next != NULL);
+}
+
+void
+jiftime(char *s, long mark)
+{
+	s += 8;
+
+	*s-- = '\0';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = '.';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 6 + '0';
+	mark /= 6;
+	*s-- = ':';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- linux-2.0.26.org/drivers/isdn/hisax/hisax.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/hisax.h	Mon Dec  9 00:11:20 1996
@@ -0,0 +1,542 @@
+/* $Id: hisax.h,v 1.5 1996/12/08 19:49:19 keil Exp $
+ *
+ *   Basic declarations, defines and prototypes
+ *
+ * $Log: hisax.h,v $
+ * Revision 1.5  1996/12/08 19:49:19  keil
+ * Monitor channel support
+ *
+ * Revision 1.4  1996/11/18 15:35:39  keil
+ * some changes for ELSA cards
+ *
+ * Revision 1.3  1996/11/05 19:37:23  keil
+ * using config.h
+ *
+ * Revision 1.2  1996/10/27 22:21:52  keil
+ * CallFlags for broadcast messages
+ *
+ * Revision 1.1  1996/10/13 20:03:46  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/isdnif.h>
+#include <linux/tty.h>
+
+#define PH_ACTIVATE   1
+#define PH_DATA       2
+#define PH_DEACTIVATE 3
+
+#define MDL_ASSIGN       4
+#define DL_UNIT_DATA     5
+#define SC_STARTUP       6
+#define CC_ESTABLISH     7
+#define DL_ESTABLISH     8
+#define DL_DATA          9
+#define CC_S_STATUS_ENQ  10
+
+#define CC_CONNECT       15
+#define CC_CONNECT_ACKNOWLEDGE 16
+#define CO_EOF                 17
+#define SC_DISCONNECT          18
+#define CO_DTMF                19
+#define DL_RELEASE             20
+#define DL_FLUSH               21
+
+#define CO_ALARM               22
+#define CC_REJECT              23
+
+#define CC_SETUP_REQ           24
+#define CC_SETUP_CNF           25
+#define CC_SETUP_IND           26
+#define CC_SETUP_RSP           27
+#define CC_SETUP_COMPLETE_IND  28
+
+#define CC_DISCONNECT_REQ      29
+#define CC_DISCONNECT_IND      30
+
+#define CC_RELEASE_CNF         31
+#define CC_RELEASE_IND         32
+#define CC_RELEASE_REQ         33
+
+#define CC_REJECT_REQ          34
+
+#define CC_PROCEEDING_IND      35
+
+#define CC_DLRL                36
+#define CC_DLEST               37
+
+#define CC_ALERTING_REQ        38
+#define CC_ALERTING_IND        39
+
+#define DL_STOP                40
+#define DL_START               41
+
+#define MDL_NOTEIPROC          46
+
+#define LC_ESTABLISH           47
+#define LC_RELEASE             48
+
+#define PH_REQUEST_PULL        49
+#define PH_PULL_ACK            50
+#define	PH_DATA_PULLED	       51
+#define CC_INFO_CHARGE         52
+
+/*
+ * Message-Types 
+ */
+
+#define MT_ALERTING            0x01
+#define MT_CALL_PROCEEDING     0x02
+#define MT_CONNECT             0x07
+#define MT_CONNECT_ACKNOWLEDGE 0x0f
+#define MT_PROGRESS            0x03
+#define MT_SETUP               0x05
+#define MT_SETUP_ACKNOWLEDGE   0x0d
+#define MT_RESUME              0x26
+#define MT_RESUME_ACKNOWLEDGE  0x2e
+#define MT_RESUME_REJECT       0x22
+#define MT_SUSPEND             0x25
+#define MT_SUSPEND_ACKNOWLEDGE 0x2d
+#define MT_SUSPEND_REJECT      0x21
+#define MT_USER_INFORMATION    0x20
+#define MT_DISCONNECT          0x45
+#define MT_RELEASE             0x4d
+#define MT_RELEASE_COMPLETE    0x5a
+#define MT_RESTART             0x46
+#define MT_RESTART_ACKNOWLEDGE 0x4e
+#define MT_SEGMENT             0x60
+#define MT_CONGESTION_CONTROL  0x79
+#define MT_INFORMATION         0x7b
+#define MT_FACILITY            0x62
+#define MT_NOTIFY              0x6e
+#define MT_STATUS              0x7d
+#define MT_STATUS_ENQUIRY      0x75
+
+#define IE_CAUSE               0x08
+
+struct HscxIoctlArg {
+	int             channel;
+	int             mode;
+	int             transbufsize;
+};
+
+#ifdef __KERNEL__
+
+#undef DEBUG_MAGIC
+
+#define HSCX_SBUF_ORDER     1
+#define HSCX_SBUF_BPPS      2
+#define HSCX_SBUF_MAXPAGES  3
+
+#define HSCX_RBUF_ORDER     1
+#define HSCX_RBUF_BPPS      2
+#define HSCX_RBUF_MAXPAGES  3
+
+#define HSCX_SMALLBUF_ORDER     0
+#define HSCX_SMALLBUF_BPPS      40
+#define HSCX_SMALLBUF_MAXPAGES  1
+
+#define ISAC_SBUF_ORDER     0
+#define ISAC_SBUF_BPPS      16
+#define ISAC_SBUF_MAXPAGES  1
+
+#define ISAC_RBUF_ORDER     0
+#define ISAC_RBUF_BPPS      16
+#define ISAC_RBUF_MAXPAGES  1
+
+#define ISAC_SMALLBUF_ORDER     0
+#define ISAC_SMALLBUF_BPPS      40
+#define ISAC_SMALLBUF_MAXPAGES  1
+
+#define byte unsigned char
+
+#define MAX_WINDOW 8
+
+byte           *Smalloc(int size, int pr, char *why);
+void            Sfree(byte * ptr);
+
+/*
+ * Statemachine 
+ */
+struct Fsm {
+	int            *jumpmatrix;
+	int             state_count, event_count;
+	char          **strEvent, **strState;
+};
+
+struct FsmInst {
+	struct Fsm     *fsm;
+	int             state;
+	int             debug;
+	void           *userdata;
+	int             userint;
+	void            (*printdebug) (struct FsmInst *, char *);
+};
+
+struct FsmNode {
+	int             state, event;
+	void            (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+	struct FsmInst *fi;
+	struct timer_list tl;
+	int             event;
+	void           *arg;
+};
+
+struct BufHeader {
+#ifdef DEBUG_MAGIC
+	int             magic;
+#endif
+	struct BufHeader *next;
+	struct BufPool *bp;
+	int             datasize;
+	byte            primitive, where;
+	void           *heldby;
+};
+
+struct Pages {
+	struct Pages   *next;
+};
+
+struct BufPool {
+#ifdef DEBUG_MAGIC
+	int             magic;
+#endif
+	struct BufHeader *freelist;
+	struct Pages   *pageslist;
+	int             pageorder;
+	int             pagescount;
+	int             bpps;
+	int             bufsize;
+	int             maxpages;
+};
+
+struct BufQueue {
+#ifdef DEBUG_MAGIC
+	int             magic;
+#endif
+	struct BufHeader *head, *tail;
+};
+
+struct Layer1 {
+	void           *hardware;
+	int             hscx;
+	struct BufPool *sbufpool, *rbufpool, *smallpool;
+	struct PStack **stlistp;
+	int             act_state;
+	void            (*l1l2) (struct PStack *, int, struct BufHeader *);
+        void            (*l1man) (struct PStack *, int, void *);
+	int             hscxmode, hscxchannel, requestpull;
+};
+
+struct Layer2 {
+	int             sap, tei, ces;
+	int             extended, laptype;
+	int             uihsize, ihsize;
+	int             vs, va, vr;
+	struct BufQueue i_queue;
+	int             window, orig;
+	int             rejexp;
+	int             debug;
+	struct BufHeader *windowar[MAX_WINDOW];
+	int             sow;
+	struct FsmInst  l2m;
+	void            (*l2l1) (struct PStack *, int, struct BufHeader *);
+        void            (*l2l1discardq) (struct PStack *, int, void *, int);
+        void            (*l2man) (struct PStack *, int, void *);
+	void            (*l2l3) (struct PStack *, int, void *);
+	void            (*l2tei) (struct PStack *, int, void *);
+	struct FsmTimer t200_timer, t203_timer;
+	int             t200, n200, t203;
+	int             rc, t200_running;
+	char            debug_id[32];
+};
+
+struct Layer3 {
+	void            (*l3l4) (struct PStack *, int, struct BufHeader *);
+        void            (*l3l2) (struct PStack *, int, void *);
+	int             state, callref;
+	int             debug;
+	int		channr;
+};
+
+struct Layer4 {
+	void            (*l4l3) (struct PStack *, int, void *);
+	void           *userdata;
+	void            (*l1writewakeup) (struct PStack *);
+	void		(*l2writewakeup) (struct PStack *);
+};
+
+struct Management {
+	void            (*manl1) (struct PStack *, int, void *);
+        void            (*manl2) (struct PStack *, int, void *);
+	void            (*teil2) (struct PStack *, int, void *);
+};
+
+struct Param {
+	int             cause;
+	int             bchannel;
+	int             callref;     /* TEI-Number                      */
+	int             itc;
+	int             info;	     /* Service-Indicator               */
+	int             info2;	     /* Service-Indicator, second octet */
+	char            calling[40]; /* Called Id                       */
+	char            called[40];  /* Caller Id                       */
+	int             chargeinfo;  /* Charge Info - only for 1tr6 in
+				      * the moment 
+				      */
+	int		spv;	     /* SPV Flag */
+};
+
+struct PStack {
+	struct PStack  *next;
+	struct Layer1   l1;
+	struct Layer2   l2;
+	struct Layer3   l3;
+	struct Layer4   l4;
+	struct Management ma;
+	struct Param   *pa;
+	int             protocol;     /* EDSS1 or 1TR6 */
+};
+
+struct HscxState {
+	int             inuse, init, active;
+	struct BufPool  sbufpool, rbufpool, smallpool;
+	struct IsdnCardState *sp;
+	int             hscx, mode;
+	int             transbufsize, receive;
+	struct BufHeader *rcvibh, *xmtibh;
+	int             rcvptr, sendptr;
+	struct PStack  *st;
+	struct tq_struct tqueue;
+	int             event;
+	struct BufQueue rq, sq;
+	int             releasebuf;
+#ifdef DEBUG_MAGIC
+	int             magic;	/* 301270 */
+#endif
+};
+
+struct IsdnCardState {
+#ifdef DEBUG_MAGIC
+	int             magic;
+#endif
+	unsigned char	typ;
+	unsigned char	subtyp;
+	unsigned char	mask1;
+	unsigned char	mask2;
+	int		protocol;
+	unsigned int	irq;
+	unsigned int    cfg_reg;
+	unsigned int	membase;
+	unsigned int    isac;
+	unsigned int	hscx[2];
+	unsigned int	counter;
+	struct BufHeader *mon_rx, *mon_tx;
+	int		mon_rxp, mon_txp, mon_flg;
+	void            (*ph_command) (struct IsdnCardState *, unsigned int);
+	void		(*modehscx) (struct HscxState *, int, int);
+	void		(*hscx_fill_fifo) (struct HscxState *);
+	void		(*isac_fill_fifo) (struct IsdnCardState *);
+	struct BufPool  sbufpool, rbufpool, smallpool;
+	struct PStack   *stlist;
+	struct BufHeader *xmtibh, *rcvibh;
+	int             rcvptr, sendptr;
+	int             event;
+	struct tq_struct tqueue;
+	int             ph_active;
+	struct BufQueue rq, sq;
+
+	int             cardnr, ph_state;
+	struct PStack  *teistack;
+	struct HscxState hs[2];
+
+	int             dlogflag;
+	char           *dlogspace;
+	int             debug;
+	int             releasebuf;
+	unsigned int	CallFlags;
+};
+
+#define  MON0_RX	1
+#define  MON1_RX	2
+#define  MON0_TX	4
+#define  MON1_TX	8
+
+#define  ISDN_CTYPE_16_0	1
+#define  ISDN_CTYPE_8_0		2
+#define  ISDN_CTYPE_16_3	3
+#define  ISDN_CTYPE_PNP		4
+#define  ISDN_CTYPE_A1		5 
+#define  ISDN_CTYPE_ELSA	6
+
+#define  ISDN_CTYPE_COUNT	6
+
+#ifdef	CONFIG_HISAX_16_0
+#define  CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
+#else
+#define  CARD_TELES0  0
+#endif
+
+#ifdef	CONFIG_HISAX_16_3
+#define  CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP)
+#else
+#define  CARD_TELES3  0
+#endif
+
+#ifdef	CONFIG_HISAX_AVM_A1
+#define  CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#else
+#define  CARD_AVM_A1  0
+#endif
+
+#ifdef	CONFIG_HISAX_ELSA_PCC
+#define  CARD_ELSA (1<< ISDN_CTYPE_ELSA)
+#else
+#define  CARD_ELSA  0
+#endif
+
+#define  SUPORTED_CARDS  (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA)
+
+struct IsdnCard {
+	int    		typ;
+        int             protocol;	/* EDSS1 or 1TR6 */
+	unsigned int	para[3];
+	struct IsdnCardState *sp;
+};
+
+#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
+
+#define LAPD 0
+#define LAPB 1
+
+void            BufPoolInit(struct BufPool *bp, int order, int bpps,
+			    int maxpages);
+int             BufPoolAdd(struct BufPool *bp, int priority);
+void            BufPoolFree(struct BufPool *bp);
+int             BufPoolGet(struct BufHeader **bh, struct BufPool *bp,
+			int priority, void *heldby, int where);
+void            BufPoolRelease(struct BufHeader *bh);
+void            BufQueueLink(struct BufQueue *bq, struct BufHeader *bh);
+int             BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
+void            BufQueueInit(struct BufQueue *bq);
+void            BufQueueRelease(struct BufQueue *bq);
+void            BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
+				int releasetoo);
+int             BufQueueLength(struct BufQueue *bq);
+void            BufQueueLinkFront(struct BufQueue *bq, struct BufHeader *bh);
+
+void            l2down(struct PStack *st, byte pr, struct BufHeader *ibh);
+void            l2up(struct PStack *st, byte pr, struct BufHeader *ibh);
+void            acceptph(struct PStack *st, struct BufHeader *ibh);
+void            setstack_isdnl2(struct PStack *st, char *debug_id);
+int             HiSax_inithardware(void);
+void            HiSax_closehardware(void);
+
+void            setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
+unsigned int    randomces(void);
+void            setstack_isdnl3(struct PStack *st, int chan);
+void            HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void            releasestack_isdnl2(struct PStack *st);
+void            HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
+void            newcallref(struct PStack *st);
+
+int             ll_init(void);
+void            ll_stop(void), ll_unload(void);
+int             setstack_hscx(struct PStack *st, struct HscxState *hs);
+byte           *findie(byte * p, int size, byte ie, int wanted_set);
+int             getcallref(byte * p);
+
+void            FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
+void            FsmFree(struct Fsm *fsm);
+int             FsmEvent(struct FsmInst *fi, int event, void *arg);
+void            FsmChangeState(struct FsmInst *fi,int newstate);
+void            FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
+int             FsmAddTimer(struct FsmTimer *ft, int millisec,
+			int event, void *arg, int where);
+void            FsmDelTimer(struct FsmTimer *ft, int where);
+int             FsmTimerRunning(struct FsmTimer *ft);
+void            jiftime(char *s, long mark);
+
+void            CallcNew(void);
+void            CallcFree(void);
+int             CallcNewChan(void);
+void            CallcFreeChan(void);
+int             HiSax_command(isdn_ctrl * ic);
+int             HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user);
+void            HiSax_putstatus(char *buf);
+void            HiSax_reportcard(int cardnr);
+int             ListLength(struct BufHeader *ibh);
+int		QuickHex(char *txt, byte *p, int cnt);
+void            LogFrame(struct IsdnCardState *sp, byte * p, int size);
+void            dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
+void            iecpy(byte * dest, byte * iestart, int ieoffset);
+void            setstack_transl2(struct PStack *st);
+void            releasestack_transl2(struct PStack *st);
+void            close_hscxstate(struct HscxState *);
+void            setstack_tei(struct PStack *st);
+
+struct LcFsm {
+	struct FsmInst  lcfi;
+	int             type;
+	struct Channel *ch;
+	void            (*lccall) (struct LcFsm *, int, void *);
+	struct PStack  *st;
+	int             l2_establish;
+	int             l2_start;
+	struct FsmTimer act_timer;
+	char            debug_id[32];
+};
+
+struct Channel {
+	struct PStack   ds, is;
+	struct IsdnCardState *sp;
+	int             hscx;
+	int             chan;
+	int             incoming;
+	struct FsmInst  fi;
+	struct LcFsm    lc_d, lc_b;
+	struct Param    para;
+	int             debug;
+#ifdef DEBUG_MAGIC
+	int             magic;	/* 301272 */
+#endif
+	int             l2_protocol, l2_active_protocol;
+	int             l2_primitive, l2_headersize;
+	int             data_open;
+	int             outcallref;
+	int             impair;
+};
+
+#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
+  sizeof(void *))/bpps)
+#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
+  sizeof(struct BufHeader))
+
+#endif
+
+void            Isdnl2New(void);
+void            Isdnl2Free(void);
+void            TeiNew(void);
+void            TeiFree(void);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl1.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon Dec  9 00:11:20 1996
@@ -0,0 +1,1056 @@
+/* $Id: isdnl1.c,v 1.4 1996/12/08 19:44:53 keil Exp $
+ *
+ * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
+ *              based on the teles driver from Jan den Ouden
+ * 
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to	Jan den Ouden
+ *	        Fritz Elfert	
+ * 	        Beat Doebeli
+ *            
+ * 
+ * $Log: isdnl1.c,v $
+ * Revision 1.4  1996/12/08 19:44:53  keil
+ * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ *
+ * Revision 1.3  1996/11/18 15:34:47  keil
+ * fix HSCX version code
+ *
+ * Revision 1.2  1996/10/27 22:16:54  keil
+ * ISAC/HSCX version lookup
+ *
+ * Revision 1.1  1996/10/13 20:04:53  keil
+ * Initial revision
+ *
+ *
+ *
+*/
+
+const	char	*l1_revision        = "$Revision: 1.4 $";
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+
+#if CARD_TELES0
+#include "teles0.h"
+#endif
+
+#if CARD_TELES3
+#include "teles3.h"
+#endif
+
+#if CARD_AVM_A1
+#include "avm_a1.h"
+#endif
+
+#if CARD_ELSA
+#include "elsa.h"
+#endif
+
+#define INCLUDE_INLINE_FUNCS
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+const   char    *CardType[] =  {"No Card","Teles 16.0","Teles 8.0","Teles 16.3",
+				"Creatix PnP","AVM A1","Elsa ML PCC16"};
+
+static	char	*HSCXVer[] = {"A1","?1","A2","?3","A3","V2.1","?6","?7",
+			      "?8","?9","?10","?11","?12","?13","?14","???"};
+
+static  char    *ISACVer[] = {"2086/2186 V1.1","2085 B1","2085 B2",
+			      "2085 V2.3"};
+ 
+extern void     tei_handler(struct PStack *st, byte pr,
+			    struct BufHeader *ibh);
+extern struct   IsdnCard cards[];
+extern int      nrcards;
+
+
+
+void debugl1(struct IsdnCardState *sp, char *msg)
+{
+	char            tmp[256], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr+1, msg);
+	HiSax_putstatus(tmp); 
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+
+char *HscxVersion(byte v)
+{
+	return(HSCXVer[v&0xf]);
+}
+
+void
+hscx_sched_event(struct HscxState *hsp, int event)
+{
+	hsp->event |= 1 << event;
+	queue_task_irq_off(&hsp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+char *ISACVersion(byte v)
+{
+	return(ISACVer[(v>>5)&3]);
+}
+
+void
+isac_sched_event(struct IsdnCardState *sp, int event)
+{
+	sp->event |= 1 << event;
+	queue_task_irq_off(&sp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+int
+act_wanted(struct IsdnCardState *sp)
+{
+	struct PStack  *st;
+
+	st = sp->stlist;
+	while (st)
+		if (st->l1.act_state)
+			return (!0);
+		else
+			st = st->next;
+	return (0);
+}
+
+void
+isac_new_ph(struct IsdnCardState *sp)
+{
+	int             enq;
+
+	enq = act_wanted(sp);
+
+	switch (sp->ph_state) {
+	  case (0):
+	  case (6):
+		  if (enq)
+			  sp->ph_command(sp, 0);
+		  else
+			  sp->ph_command(sp, 15);
+		  break;
+	  case (7):
+		  if (enq)
+			  sp->ph_command(sp, 9);
+		  break;
+	  case (12):
+	          sp->ph_command(sp, 8);
+		  sp->ph_active = 5;
+		  isac_sched_event(sp, ISAC_PHCHANGE);
+		  if (!sp->xmtibh)
+			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
+				  sp->sendptr = 0;
+		  if (sp->xmtibh)
+			  sp->isac_fill_fifo(sp);
+		  break;
+	  case (13):
+	          sp->ph_command(sp, 9);
+		  sp->ph_active = 5;
+		  isac_sched_event(sp, ISAC_PHCHANGE);
+		  if (!sp->xmtibh)
+			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
+				  sp->sendptr = 0;
+		  if (sp->xmtibh)
+			  sp->isac_fill_fifo(sp);
+		  break;
+	  case (4):
+	  case (8):
+		  break;
+	  default:
+		  sp->ph_active = 0;
+		  break;
+	}
+}
+
+static void
+restart_ph(struct IsdnCardState *sp)
+{
+	switch (sp->ph_active) {
+	  case (0):
+		  if (sp->ph_state == 6)
+			  sp->ph_command(sp, 0);
+		  else
+			  sp->ph_command(sp, 1);
+		  sp->ph_active = 1;
+		  break;
+	}
+}
+
+
+static void
+act_ivated(struct IsdnCardState *sp)
+{
+	struct PStack  *st;
+
+	st = sp->stlist;
+	while (st) {
+		if (st->l1.act_state == 1) {
+			st->l1.act_state = 2;
+			st->l1.l1man(st, PH_ACTIVATE, NULL);
+		}
+		st = st->next;
+	}
+}
+
+static void
+process_new_ph(struct IsdnCardState *sp)
+{
+	if (sp->ph_active == 5)
+		act_ivated(sp);
+}
+
+static void
+process_xmt(struct IsdnCardState *sp)
+{
+	struct PStack  *stptr;
+
+	if (sp->xmtibh)
+		return;
+
+	stptr = sp->stlist;
+	while (stptr != NULL)
+		if (stptr->l1.requestpull) {
+			stptr->l1.requestpull = 0;
+			stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
+			break;
+		} else
+			stptr = stptr->next;
+}
+
+static void
+process_rcv(struct IsdnCardState *sp)
+{
+	struct BufHeader *ibh, *cibh;
+	struct PStack    *stptr;
+	byte             *ptr;
+	int              found, broadc;
+	char             tmp[64];
+
+	while (!BufQueueUnlink(&ibh, &sp->rq)) {
+#ifdef L2FRAME_DEBUG /* psa */
+	        if(sp->debug & L1_DEB_LAPD)
+		        Logl2Frame(sp,ibh,"PH_DATA",1);
+#endif
+		stptr = sp->stlist;
+		ptr = DATAPTR(ibh);
+		broadc = (ptr[1] >> 1) == 127;
+
+		if (broadc) {
+			if (sp->dlogflag && (!(ptr[0] >> 2))) {
+				LogFrame(sp, ptr, ibh->datasize);
+				dlogframe(sp, ptr + 3, ibh->datasize - 3,
+					"Q.931 frame network->user broadcast");
+			}
+			sp->CallFlags = 3;
+			while (stptr != NULL) {
+				if ((ptr[0] >> 2) == stptr->l2.sap)
+					if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
+							(void *) 1, 5)) {
+						memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
+						cibh->datasize = ibh->datasize;
+						stptr->l1.l1l2(stptr, PH_DATA, cibh);
+					} else
+						printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
+				stptr = stptr->next;
+			}
+			BufPoolRelease(ibh);
+		} else {
+			found = 0;
+			while (stptr != NULL)
+				if (((ptr[0] >> 2) == stptr->l2.sap) &&
+				    ((ptr[1] >> 1) == stptr->l2.tei)) {
+					stptr->l1.l1l2(stptr, PH_DATA, ibh);
+					found = !0;
+					break;
+				} else
+					stptr = stptr->next;
+			if (!found) {
+				/* BD 10.10.95
+				 * Print out D-Channel msg not processed
+				 * by isdn4linux
+                                 */
+
+				if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
+					sprintf(tmp,
+					"Q.931 frame network->user with tei %d (not for us)",
+					ptr[1] >> 1);
+					LogFrame(sp, ptr, ibh->datasize);
+					dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
+				}
+				BufPoolRelease(ibh);
+			}
+		}
+
+	}
+
+}
+
+static void
+isac_bh(struct IsdnCardState *sp)
+{
+	if (!sp)
+		return;
+
+	if (clear_bit(ISAC_PHCHANGE, &sp->event))
+		process_new_ph(sp);
+	if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
+		process_rcv(sp);
+	if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
+		process_xmt(sp);
+}
+
+static void
+l2l1(struct PStack *st, int pr,
+	   struct BufHeader *ibh)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+
+
+	switch (pr) {
+	  case (PH_DATA):
+	          if (sp->xmtibh) {
+			  BufQueueLink(&sp->sq, ibh);
+#ifdef L2FRAME_DEBUG /* psa */
+			  if(sp->debug & L1_DEB_LAPD)
+			        Logl2Frame(sp,ibh,"PH_DATA Queued",0);
+#endif
+		  }
+		  else {
+			  sp->xmtibh = ibh;
+			  sp->sendptr = 0;
+			  sp->releasebuf = !0;
+			  sp->isac_fill_fifo(sp);
+#ifdef L2FRAME_DEBUG /* psa */
+			  if(sp->debug & L1_DEB_LAPD)
+			        Logl2Frame(sp,ibh,"PH_DATA",0);
+#endif
+		  }
+		  break;
+	  case (PH_DATA_PULLED):
+		  if (sp->xmtibh) {
+			  if (sp->debug & L1_DEB_WARN) 
+        			debugl1(sp, " l2l1 xmtibh exist this shouldn't happen");
+			  break;
+		  }
+		  sp->xmtibh = ibh;
+		  sp->sendptr = 0;
+		  sp->releasebuf = 0;
+		  sp->isac_fill_fifo(sp);
+#ifdef L2FRAME_DEBUG /* psa */
+		  if(sp->debug & L1_DEB_LAPD)
+		          Logl2Frame(sp,ibh,"PH_DATA_PULLED",0);
+#endif
+		  break;
+	  case (PH_REQUEST_PULL):
+#ifdef L2FRAME_DEBUG /* psa */
+		  if(sp->debug & L1_DEB_LAPD)
+		          debugl1(sp,"-> PH_REQUEST_PULL");
+#endif
+		  if (!sp->xmtibh) {
+			  st->l1.requestpull = 0;
+			  st->l1.l1l2(st, PH_PULL_ACK, NULL);
+		  } else
+			  st->l1.requestpull = !0;
+		  break;
+	}
+}
+
+
+static void
+hscx_process_xmt(struct HscxState *hsp)
+{
+	struct PStack  *st = hsp->st;
+
+	if (hsp->xmtibh)
+		return;
+
+	if (st->l1.requestpull) {
+		st->l1.requestpull = 0;
+		st->l1.l1l2(st, PH_PULL_ACK, NULL);
+	}
+	if (!hsp->active)
+		if ((!hsp->xmtibh) && (!hsp->sq.head))
+			hsp->sp->modehscx(hsp, 0, 0);
+}
+
+static void
+hscx_process_rcv(struct HscxState *hsp)
+{
+	struct BufHeader *ibh;
+
+#ifdef DEBUG_MAGIC
+	if (hsp->magic != 301270) {
+		printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
+		return;
+	}
+#endif
+	while (!BufQueueUnlink(&ibh, &hsp->rq)) {
+		hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
+	}
+}
+
+static void
+hscx_bh(struct HscxState *hsp)
+{
+
+	if (!hsp)
+		return;
+
+	if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+		hscx_process_rcv(hsp);
+	if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+		hscx_process_xmt(hsp);
+
+}
+
+/*
+ * interrupt stuff ends here
+ */
+
+void
+HiSax_addlist(struct IsdnCardState *sp,
+	      struct PStack *st)
+{
+	st->next = sp->stlist;
+	sp->stlist = st;
+}
+
+void
+HiSax_rmlist(struct IsdnCardState *sp,
+	     struct PStack *st)
+{
+	struct PStack  *p;
+
+	if (sp->stlist == st)
+		sp->stlist = st->next;
+	else {
+		p = sp->stlist;
+		while (p)
+			if (p->next == st) {
+				p->next = st->next;
+				return;
+			} else
+				p = p->next;
+	}
+}
+
+static void
+check_ph_act(struct IsdnCardState *sp)
+{
+	struct PStack  *st = sp->stlist;
+
+	while (st) {
+		if (st->l1.act_state)
+			return;
+		st = st->next;
+	}
+	sp->ph_active = 0;
+}
+
+static void
+HiSax_manl1(struct PStack *st, int pr,
+	    void *arg)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)
+	st->l1.hardware;
+	long            flags;
+
+	switch (pr) {
+	  case (PH_ACTIVATE):
+		  save_flags(flags);
+		  cli();
+		  if (sp->ph_active == 5) {
+			  st->l1.act_state = 2;
+			  restore_flags(flags);
+			  st->l1.l1man(st, PH_ACTIVATE, NULL);
+		  } else {
+			  st->l1.act_state = 1;
+			  if (sp->ph_active == 0)
+				  restart_ph(sp);
+			  restore_flags(flags);
+		  }
+		  break;
+	  case (PH_DEACTIVATE):
+		  st->l1.act_state = 0;
+		  check_ph_act(sp);
+		  break;
+	}
+}
+
+static void
+HiSax_l2l1discardq(struct PStack *st, int pr,
+		   void *heldby, int releasetoo)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+
+#ifdef DEBUG_MAGIC
+	if (sp->magic != 301271) {
+		printk(KERN_DEBUG "isac_discardq magic not 301271\n");
+		return;
+	}
+#endif
+
+	BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
+{
+	st->l1.hardware = sp;
+	st->l1.sbufpool = &(sp->sbufpool);
+	st->l1.rbufpool = &(sp->rbufpool);
+	st->l1.smallpool = &(sp->smallpool);
+	st->protocol = sp->protocol;
+
+	setstack_tei(st);
+
+	st->l1.stlistp = &(sp->stlist);
+	st->l1.act_state = 0;
+	st->l2.l2l1 = l2l1;
+	st->l2.l2l1discardq = HiSax_l2l1discardq;
+	st->ma.manl1 = HiSax_manl1;
+	st->l1.requestpull = 0;
+}
+
+void
+init_hscxstate(struct IsdnCardState *sp,
+	       int hscx)
+{
+	struct HscxState *hsp = sp->hs + hscx;
+
+	hsp->sp = sp;
+	hsp->hscx = hscx;
+
+	hsp->tqueue.next = 0;
+	hsp->tqueue.sync = 0;
+	hsp->tqueue.routine = (void *) (void *) hscx_bh;
+	hsp->tqueue.data = hsp;
+
+	hsp->inuse = 0;
+	hsp->init = 0;
+	hsp->active = 0;
+
+#ifdef DEBUG_MAGIC
+	hsp->magic = 301270;
+#endif
+}
+
+int
+get_irq(int cardnr, void *routine)
+{
+	struct IsdnCard *card = cards + cardnr;
+	long            flags;
+
+	save_flags(flags);
+	cli();
+	if (request_irq(card->sp->irq, routine,
+			SA_INTERRUPT, "HiSax", NULL)) {
+		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+                       card->sp->irq);
+		restore_flags(flags);
+		return (0);
+	}
+	irq2dev_map[card->sp->irq] = (void *) card->sp;
+	restore_flags(flags);
+	return (1);
+}
+
+static void
+release_irq(int cardnr)
+{
+	struct	IsdnCard *card = cards + cardnr;
+
+	irq2dev_map[card->sp->irq] = NULL;
+	free_irq(card->sp->irq, NULL);
+}
+
+void
+close_hscxstate(struct HscxState *hs)
+{
+	hs->sp->modehscx(hs, 0, 0);
+	hs->inuse = 0;
+
+	if (hs->init) {
+		BufPoolFree(&hs->smallpool);
+		BufPoolFree(&hs->rbufpool);
+		BufPoolFree(&hs->sbufpool);
+	}
+	hs->init = 0;
+}
+
+static void
+closecard(int cardnr)
+{
+	struct IsdnCardState *sp = cards[cardnr].sp;
+
+	Sfree(sp->dlogspace);
+
+	BufPoolFree(&sp->smallpool);
+	BufPoolFree(&sp->rbufpool);
+	BufPoolFree(&sp->sbufpool);
+
+	close_hscxstate(sp->hs + 1);
+	close_hscxstate(sp->hs);
+
+        switch (sp->typ) {
+#if CARD_TELES0
+          case ISDN_CTYPE_16_0:
+          case ISDN_CTYPE_8_0:
+		release_io_teles0(&cards[cardnr]);
+                break;
+#endif
+#if CARD_TELES3
+          case ISDN_CTYPE_PNP:
+          case ISDN_CTYPE_16_3:
+		release_io_teles3(&cards[cardnr]);
+                break;
+#endif
+#if CARD_AVM_A1
+          case ISDN_CTYPE_A1:
+		release_io_avm_a1(&cards[cardnr]);
+                break;
+#endif
+#if CARD_ELSA
+          case ISDN_CTYPE_ELSA:
+		release_io_elsa(&cards[cardnr]);
+                break;
+#endif
+          default:
+          	break;
+	}
+}
+
+static int
+checkcard(int cardnr)
+{
+	int			ret=0;
+	struct IsdnCard		*card = cards + cardnr;
+	struct IsdnCardState	*sp;
+
+
+	sp = (struct IsdnCardState *)
+	    	    Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
+		    "struct IsdnCardState");
+
+	card->sp   = sp;
+	sp->cardnr = cardnr;
+	sp->cfg_reg  = 0;
+	sp->protocol = card->protocol;
+	
+	if ((card->typ>0) && (card->typ<31)) {
+		if (!((1<<card->typ) & SUPORTED_CARDS)) {
+                        printk(KERN_WARNING
+                               "HiSax: Support for %s Card not selected\n",
+                               CardType[card->typ]);
+                        return(0);
+                }
+        } else {
+        	printk(KERN_WARNING
+                        "HiSax: Card Type %d out of range\n",
+                        card->typ);
+		return (0);
+	}
+	sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
+	sp->typ      = card->typ;
+	sp->CallFlags = 0;
+	
+	printk(KERN_NOTICE
+		"HiSax: Card %d Protocol %s\n", cardnr+1,
+                (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1");
+
+        switch (card->typ) {
+#if CARD_TELES0
+          case ISDN_CTYPE_16_0:
+          case ISDN_CTYPE_8_0:
+                ret=setup_teles0(card);
+                break;
+#endif
+#if CARD_TELES3
+          case ISDN_CTYPE_PNP:
+          case ISDN_CTYPE_16_3:
+                ret=setup_teles3(card);
+                break;
+#endif
+#if CARD_AVM_A1
+          case ISDN_CTYPE_A1:
+                ret=setup_avm_a1(card);
+                break;
+#endif
+#if CARD_ELSA
+          case ISDN_CTYPE_ELSA:
+                ret=setup_elsa(card);
+                break;
+#endif
+          default: 
+                printk(KERN_WARNING  "HiSax: Unknown Card Typ %d\n",
+                  			card->typ);
+				Sfree(sp->dlogspace);
+                        	return(0);
+        }
+	if (!ret) {
+		Sfree(sp->dlogspace);
+		return (0);
+	}
+	BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
+		    ISAC_SBUF_MAXPAGES);
+	BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
+		    ISAC_RBUF_MAXPAGES);
+	BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
+		    ISAC_SMALLBUF_MAXPAGES);
+
+	
+	sp->rcvibh  = NULL;
+	sp->rcvptr  = 0;
+	sp->xmtibh  = NULL;
+	sp->sendptr = 0;
+	sp->mon_rx  = NULL;
+	sp->mon_rxp = 0;
+	sp->mon_tx  = NULL;
+	sp->mon_txp = 0;
+	sp->mon_flg = 0;
+	sp->event   = 0;
+	sp->tqueue.next = 0;
+	sp->tqueue.sync = 0;
+	sp->tqueue.routine = (void *) (void *) isac_bh;
+	sp->tqueue.data = sp;
+
+	BufQueueInit(&sp->rq);
+	BufQueueInit(&sp->sq);
+
+	sp->stlist = NULL;
+	sp->ph_active = 0;
+	sp->dlogflag = 0;
+	sp->debug = L1_DEB_WARN;
+	sp->releasebuf = 0;
+#ifdef DEBUG_MAGIC
+	sp->magic = 301271;
+#endif
+
+	init_hscxstate(sp, 0);
+	init_hscxstate(sp, 1);
+
+        switch (card->typ) {
+#if CARD_TELES0
+          case ISDN_CTYPE_16_0:
+          case ISDN_CTYPE_8_0:
+                ret=initteles0(sp);
+                break;
+#endif
+#if CARD_TELES3
+          case ISDN_CTYPE_PNP:
+          case ISDN_CTYPE_16_3:
+                ret=initteles3(sp);
+                break;
+#endif
+#if CARD_AVM_A1
+          case ISDN_CTYPE_A1:
+                ret=initavm_a1(sp);
+                break;
+#endif
+#if CARD_ELSA
+          case ISDN_CTYPE_ELSA:
+                ret=initelsa(sp);
+                break;
+#endif
+          default:
+          	ret=0;
+          	break;
+	}
+	if (!ret) {
+                closecard(cardnr);
+                return(0);
+        }
+	return(1);
+}
+
+void
+HiSax_shiftcards(int idx)
+{
+        int i;
+
+        for (i = idx; i < 15; i++)
+                memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
+}
+
+int
+HiSax_inithardware(void)
+{
+        int             foundcards = 0;
+	int             i = 0;
+
+	while (i < nrcards) {
+                if (cards[i].typ<1)
+                        break;
+		if (checkcard(i)) {
+                        foundcards++;
+                        i++;
+                } else {
+			printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+			  	CardType[cards[i].typ]);
+			Sfree((void *) cards[i].sp);
+			cards[i].sp = NULL;
+                        HiSax_shiftcards(i);
+		}
+        }
+        return foundcards;
+}
+
+void
+HiSax_closehardware(void)
+{
+	int             i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp) {
+			release_irq(i);
+			closecard(i);
+			Sfree((void *) cards[i].sp);
+			cards[i].sp = NULL;
+		}
+}
+
+static void
+hscx_l2l1(struct PStack *st, int pr,
+	  struct BufHeader *ibh)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)
+	st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+	long flags;
+
+	switch (pr) {
+                case (PH_DATA):
+			save_flags(flags);
+			cli();
+                        if (hsp->xmtibh) {
+                                BufQueueLink(&hsp->sq, ibh);
+				restore_flags(flags);
+			}
+                        else {
+				restore_flags(flags);
+                                hsp->xmtibh = ibh;
+                                hsp->sendptr = 0;
+                                hsp->releasebuf = !0;
+                                sp->hscx_fill_fifo(hsp);
+                        }
+                        break;
+                case (PH_DATA_PULLED):
+                        if (hsp->xmtibh) {
+                                printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+                                break;
+                        }
+                        hsp->xmtibh = ibh;
+                        hsp->sendptr = 0;
+                        hsp->releasebuf = 0;
+                        sp->hscx_fill_fifo(hsp);
+                        break;
+                case (PH_REQUEST_PULL):
+                        if (!hsp->xmtibh) {
+                                st->l1.requestpull = 0;
+                                st->l1.l1l2(st, PH_PULL_ACK, NULL);
+                        } else
+                                st->l1.requestpull = !0;
+                        break;
+	}
+        
+}
+extern struct IsdnBuffers *tracebuf;
+
+static void
+hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
+		  int releasetoo)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)
+	st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+
+#ifdef DEBUG_MAGIC
+	if (hsp->magic != 301270) {
+		printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
+		return;
+	}
+#endif
+
+	BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
+}
+
+static int
+open_hscxstate(struct IsdnCardState *sp,
+	       int hscx)
+{
+	struct HscxState *hsp = sp->hs + hscx;
+
+	if (!hsp->init) {
+		BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
+			    HSCX_SBUF_MAXPAGES);
+		BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
+			    HSCX_RBUF_MAXPAGES);
+		BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
+			    HSCX_SMALLBUF_MAXPAGES);
+	}
+	hsp->init = !0;
+
+	BufQueueInit(&hsp->rq);
+	BufQueueInit(&hsp->sq);
+
+	hsp->releasebuf = 0;
+	hsp->rcvibh = NULL;
+	hsp->xmtibh = NULL;
+	hsp->rcvptr = 0;
+	hsp->sendptr = 0;
+	hsp->event = 0;
+	return (0);
+}
+
+static void
+hscx_manl1(struct PStack *st, int pr,
+	   void *arg)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+
+	switch (pr) {
+	  case (PH_ACTIVATE):
+		  hsp->active = !0;
+		  sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
+		  st->l1.l1man(st, PH_ACTIVATE, NULL);
+		  break;
+	  case (PH_DEACTIVATE):
+		  if (!hsp->xmtibh)
+			  sp->modehscx(hsp, 0, 0);
+
+		  hsp->active = 0;
+		  break;
+	}
+}
+
+int
+setstack_hscx(struct PStack *st, struct HscxState *hs)
+{
+	if (open_hscxstate(st->l1.hardware, hs->hscx))
+		return (-1);
+
+	st->l1.hscx = hs->hscx;
+	st->l2.l2l1 = hscx_l2l1;
+	st->ma.manl1 = hscx_manl1;
+	st->l2.l2l1discardq = hscx_l2l1discardq;
+
+	st->l1.sbufpool = &hs->sbufpool;
+	st->l1.rbufpool = &hs->rbufpool;
+	st->l1.smallpool = &hs->smallpool;
+	st->l1.act_state = 0;
+	st->l1.requestpull = 0;
+
+	hs->st = st;
+	return (0);
+}
+
+void
+HiSax_reportcard(int cardnr)
+{
+	struct IsdnCardState *sp = cards[cardnr].sp;
+	
+	printk(KERN_DEBUG "HiSax: reportcard No %d\n",cardnr+1);
+	printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]);
+	printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug);
+	if (sp->debug) sp->debug =0;
+	else sp->debug =0xff;
+}
+
+#ifdef L2FRAME_DEBUG /* psa */
+
+char *l2cmd(byte cmd)
+{
+  switch(cmd & ~0x10) {
+  case 1:
+    return "RR";
+  case 5:
+    return "RNR";
+  case 9:
+    return "REJ";
+  case 0x6f:
+    return "SABME";
+  case 0x0f:
+    return "DM";
+  case 3:
+    return "UI";
+  case 0x43:
+    return "DISC";
+  case 0x63:
+    return "UA";
+  case 0x87:
+    return "FRMR";
+  case 0xaf:
+    return "XID";
+  default:
+    if(!(cmd & 1))
+      return "I";
+    else
+      return "invalid command";
+  }
+}
+
+static char tmp[20];
+
+char *l2frames(byte *ptr)
+{
+  switch(ptr[2] & ~0x10) {
+  case 1:
+  case 5:
+  case 9:
+    sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
+    break;
+  case 0x6f:
+  case 0x0f:
+  case 3:
+  case 0x43:
+  case 0x63:
+  case 0x87:
+  case 0xaf:
+    sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
+    break;
+  default:
+    if(!(ptr[2] & 1)) {
+      sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1,ptr[3] >> 1);
+      break;
+    }
+    else
+      return "invalid command";
+  }
+
+
+  return tmp;
+}
+
+void
+Logl2Frame(struct IsdnCardState *sp, struct BufHeader *ibh, char *buf, int dir)
+{
+  char tmp[132];
+  byte *ptr;
+
+  ptr = DATAPTR(ibh);
+
+  if(ptr[0] & 1 || !(ptr[1] & 1))
+    debugl1(sp,"Addres not LAPD");
+  else {
+    sprintf(tmp,"%s %s: %s%c (sapi %d, tei %d)",
+	    (dir?"<-":"->"), buf, l2frames(ptr),
+	    ((ptr[0] & 2) >> 1) == dir?'C':'R', ptr[0] >> 2, ptr[1] >> 1);
+    debugl1(sp, tmp);
+  }
+}
+
+#endif
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl1.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl1.h	Mon Dec  9 00:11:20 1996
@@ -0,0 +1,45 @@
+/* $Id: isdnl1.h,v 1.3 1996/12/08 19:41:55 keil Exp $
+ *
+ * $Log: isdnl1.h,v $
+ * Revision 1.3  1996/12/08 19:41:55  keil
+ * L2FRAME_DEBUG
+ *
+ * Revision 1.2  1996/10/27 22:26:27  keil
+ * ISAC/HSCX version functions
+ *
+ * Revision 1.1  1996/10/13 20:03:47  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+
+#define L2FRAME_DEBUG
+
+/* DEBUG Level */
+
+#define	L1_DEB_WARN		0x01
+#define	L1_DEB_INTSTAT		0x02
+#define	L1_DEB_ISAC		0x04
+#define	L1_DEB_ISAC_FIFO	0x08
+#define	L1_DEB_HSCX		0x10
+#define	L1_DEB_HSCX_FIFO	0x20
+#define	L1_DEB_LAPD	        0x40
+
+
+#define ISAC_RCVBUFREADY 0
+#define ISAC_XMTBUFREADY 1
+#define ISAC_PHCHANGE    2
+
+#define HSCX_RCVBUFREADY 0
+#define HSCX_XMTBUFREADY 1
+
+extern void debugl1(struct IsdnCardState *sp, char *msg);
+extern char *HscxVersion(byte v);
+extern char *ISACVersion(byte v);
+extern void hscx_sched_event(struct HscxState *hsp, int event);
+extern void isac_sched_event(struct IsdnCardState *sp, int event);
+extern void isac_new_ph(struct IsdnCardState *sp);
+extern get_irq(int cardnr, void *routine);
+extern void Logl2Frame(struct IsdnCardState *sp, struct BufHeader *ibh, char *buf, int dir);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl2.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl2.c	Mon Dec  9 00:11:20 1996
@@ -0,0 +1,1430 @@
+/* $Id: isdnl2.c,v 1.4 1996/12/08 19:51:51 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: isdnl2.c,v $
+ * Revision 1.4  1996/12/08 19:51:51  keil
+ * many fixes from Pekka Sarnila
+ *
+ * Revision 1.3  1996/11/05 19:39:12  keil
+ * X.75 bugfixes Thank to Martin Maurer
+ *
+ * Revision 1.2  1996/10/30 10:20:58  keil
+ * X.75 answer of SABMX fixed to response address (AVM X.75 problem)
+ *
+ * Revision 1.1  1996/10/13 20:04:54  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl2.h"
+
+#define TIMER_1 2000
+
+static void     l2m_debug(struct FsmInst *fi, char *s);
+
+struct Fsm      l2fsm =
+{NULL, 0, 0};
+
+enum {
+	ST_L2_1,
+	ST_L2_3,
+	ST_L2_4,
+	ST_L2_5,
+	ST_L2_6,
+	ST_L2_7,
+	ST_L2_8,
+};
+
+#define L2_STATE_COUNT (ST_L2_8+1)
+
+static char    *strL2State[] =
+{
+	"ST_L2_1",
+	"ST_L2_3",
+	"ST_L2_4",
+	"ST_L2_5",
+	"ST_L2_6",
+	"ST_L2_7",
+	"ST_L2_8",
+};
+
+enum {
+	EV_L2_UI,
+	EV_L2_SABMX,
+	EV_L2_UA,
+	EV_L2_DISC,
+	EV_L2_I,
+	EV_L2_RR,
+	EV_L2_REJ,
+	EV_L2_FRMR,
+	EV_L2_DL_DATA,
+	EV_L2_DL_ESTABLISH,
+	EV_L2_MDL_ASSIGN,
+	EV_L2_DL_UNIT_DATA,
+	EV_L2_DL_RELEASE,
+	EV_L2_MDL_NOTEIPROC,
+	EV_L2_T200,
+	EV_L2_ACK_PULL,
+	EV_L2_T203,
+	EV_L2_RNR,
+};
+
+#define L2_EVENT_COUNT (EV_L2_RNR+1)
+
+static char    *strL2Event[] =
+{
+	"EV_L2_UI",
+	"EV_L2_SABMX",
+	"EV_L2_UA",
+	"EV_L2_DISC",
+	"EV_L2_I",
+	"EV_L2_RR",
+	"EV_L2_REJ",
+	"EV_L2_FRMR",
+	"EV_L2_DL_DATA",
+	"EV_L2_DL_ESTABLISH",
+	"EV_L2_MDL_ASSIGN",
+	"EV_L2_DL_UNIT_DATA",
+	"EV_L2_DL_RELEASE",
+	"EV_L2_MDL_NOTEIPROC",
+	"EV_L2_T200",
+	"EV_L2_ACK_PULL",
+	"EV_L2_T203",
+	"EV_L2_RNR",
+};
+
+int             errcount = 0;
+
+static int      l2addrsize(struct Layer2 *tsp);
+
+static int
+cansend(struct PStack *st)
+{
+	int             p1;
+
+	p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
+	return (st->l2.vs != p1);
+}
+
+static void
+discard_i_queue(struct PStack *st)
+{
+	struct BufHeader *ibh;
+
+	while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
+		BufPoolRelease(ibh);
+}
+
+int
+l2headersize(struct Layer2 *tsp, int ui)
+{
+	return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+}
+
+int
+l2addrsize(struct Layer2 *tsp)
+{
+	return (tsp->laptype == LAPD ? 2 : 1);
+}
+
+static int
+sethdraddr(struct Layer2 *tsp,
+	   struct BufHeader *ibh, int rsp)
+{
+	byte           *ptr = DATAPTR(ibh);
+	int             crbit;
+
+	if (tsp->laptype == LAPD) {
+		crbit = rsp;
+		if (!tsp->orig)
+			crbit = !crbit;
+		*ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
+		*ptr++ = (tsp->tei << 1) | 1;
+		return (2);
+	} else {
+		crbit = rsp;
+		if (tsp->orig)
+			crbit = !crbit;
+		if (crbit)
+			*ptr++ = 1;
+		else
+			*ptr++ = 3;
+		return (1);
+	}
+}
+
+static void
+enqueue_ui(struct PStack *st,
+	   struct BufHeader *ibh)
+{
+	st->l2.l2l1(st, PH_DATA, ibh);
+}
+
+static void
+enqueue_super(struct PStack *st,
+	      struct BufHeader *ibh)
+{
+	st->l2.l2l1(st, PH_DATA, ibh);
+}
+
+static int
+legalnr(struct PStack *st, int nr)
+{
+	struct Layer2  *l2 = &st->l2;
+	int             lnr, lvs;
+
+	lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
+	lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
+	return (lnr <= lvs);
+}
+
+static void
+setva(struct PStack *st, int nr)
+{
+	struct Layer2  *l2 = &st->l2;
+
+	if (l2->va != nr) {
+                while (l2->va != nr) {
+                        l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
+                        BufPoolRelease(l2->windowar[l2->sow]);
+                        l2->sow = (l2->sow + 1) % l2->window;
+                }
+                if (st->l4.l2writewakeup)
+                        st->l4.l2writewakeup(st);
+        }
+}
+
+static void
+l2s1(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
+	FsmChangeState(fi, ST_L2_3);
+}
+
+static void
+l2s2(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+
+	byte           *ptr;
+	int             i;
+
+	i = sethdraddr(&(st->l2), ibh, CMD);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = UI;
+
+	enqueue_ui(st, ibh);
+}
+
+static void
+l2s3(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+
+	st->l2.l2l3(st, DL_UNIT_DATA, ibh);
+}
+
+static void
+establishlink(struct FsmInst *fi)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh;
+	int             i;
+	byte           *ptr;
+
+	FsmChangeState(fi, ST_L2_5);
+	st->l2.rc = 0;
+
+	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 1");
+
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
+		return;
+	i = sethdraddr(&st->l2, ibh, CMD);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	if (st->l2.extended)
+		*ptr = SABME | 0x10;
+	else
+		*ptr = 0x3f;
+	ibh->datasize = i + 1;
+
+	enqueue_super(st, ibh);
+}
+
+static void
+l2s11(struct FsmInst *fi, int event, void *arg)
+{
+	establishlink(fi);
+}
+
+static void
+l2s13(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	byte           *ptr;
+	struct BufHeader *ibh;
+	int             i;
+
+	FsmChangeState(fi, ST_L2_6);
+
+	FsmDelTimer(&st->l2.t203_timer, 1);
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 2);
+		st->l2.t200_running = 0;
+	}
+	st->l2.rc = 0;
+	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 2");
+
+
+	if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
+		goto nodisc;
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
+		return;
+	i = sethdraddr(&(st->l2), ibh, CMD);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = DISC | 0x10;
+	ibh->datasize = i + 1;
+	enqueue_super(st, ibh);
+
+      nodisc:
+	discard_i_queue(st);
+}
+
+static void
+l2s12(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	byte           *ptr;
+	int             i, p;
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(&(st->l2));
+	p = (*ptr) & 0x10;
+	BufPoolRelease(ibh);
+
+	st->l2.vs = 0;
+	st->l2.va = 0;
+	st->l2.vr = 0;
+	st->l2.sow = 0;
+	FsmChangeState(fi, ST_L2_7);
+	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 3");
+
+	st->l2.l2man(st, DL_ESTABLISH, NULL);
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
+		return;
+	i = sethdraddr(&(st->l2), ibh, RSP);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = UA | p;
+	ibh->datasize = i + 1;
+	enqueue_super(st, ibh);
+
+}
+
+static void
+l2s14(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	struct Channel *chanp = st->l4.userdata;
+	byte           *ptr;
+	int             i, p;
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(&(st->l2));
+	p = (*ptr) & 0x10;
+	BufPoolRelease(ibh);
+
+	FsmChangeState(fi, ST_L2_4);
+
+	FsmDelTimer(&st->l2.t203_timer, 3);
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 4);
+		st->l2.t200_running = 0;
+	}
+	if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
+		goto noresponse;
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
+		return;
+	i = sethdraddr(&(st->l2), ibh, RSP);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = UA | p;
+	ibh->datasize = i + 1;
+	enqueue_super(st, ibh);
+
+      noresponse:
+	st->l2.l2man(st, DL_RELEASE, NULL);
+
+}
+
+static void
+l2s14_1(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	struct Channel *chanp = st->l4.userdata;
+	byte           *ptr;
+	int             i, p;
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(&(st->l2));
+	p = (*ptr) & 0x10;
+	BufPoolRelease(ibh);
+
+	if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
+		goto noresponse;
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
+		return;
+	i = sethdraddr(&(st->l2), ibh, RSP);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = DM | (p ? 0x10 : 0x0);
+
+	ibh->datasize = i + 1;
+	enqueue_super(st, ibh);
+
+      noresponse:
+
+}
+
+static void
+l2s5(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             f;
+	byte           *data;
+
+	data = DATAPTR(ibh);
+	data += l2addrsize(&(st->l2));
+
+	f = *data & 0x10;
+	BufPoolRelease(ibh);
+
+	if (f) {
+		st->l2.vs = 0;
+		st->l2.va = 0;
+		st->l2.vr = 0;
+		st->l2.sow = 0;
+		FsmChangeState(fi, ST_L2_7);
+
+		FsmDelTimer(&st->l2.t200_timer, 5);
+		if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 4");
+
+
+		st->l2.l2man(st, DL_ESTABLISH, NULL);
+	}
+}
+
+static void
+l2s15(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             f;
+	byte           *data;
+
+	data = DATAPTR(ibh);
+	data += l2addrsize(&st->l2);
+
+	f = *data & 0x10;
+	BufPoolRelease(ibh);
+
+	if (f) {
+		FsmDelTimer(&st->l2.t200_timer, 6);
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	}
+}
+
+static void
+enquiry_response(struct PStack *st)
+{
+	struct BufHeader *ibh2;
+	int             i;
+	byte           *ptr;
+	struct Layer2  *l2;
+
+	l2 = &st->l2;
+	if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
+		i = sethdraddr(l2, ibh2, RSP);
+		ptr = DATAPTR(ibh2);
+		ptr += i;
+
+		if (l2->extended) {
+			*ptr++ = RR;
+			*ptr++ = (l2->vr << 1) | 0x1;
+			i += 2;
+		} else {
+			*ptr++ = (l2->vr << 5) | 0x1 | 0x10;
+			i += 1;
+		}
+		ibh2->datasize = i;
+		enqueue_super(st, ibh2);
+	}
+}
+
+static void
+nrerrorrecovery(struct FsmInst *fi)
+{
+  /* should log error here */
+        establishlink(fi);
+}
+
+static void
+l2s6(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	struct BufHeader *ibh = arg;
+	int             p, seq, rsp;
+	byte           *ptr;
+	struct Layer2  *l2;
+
+	l2 = &st->l2;
+	ptr = DATAPTR(ibh);
+
+	if (l2->laptype == LAPD) {
+		rsp = ptr[0] & 0x2;
+		if (l2->orig)
+			rsp = !rsp;
+	} else {
+		rsp = ptr[0] == 0x3;
+		if (l2->orig)
+			rsp = !rsp;
+	}
+
+	ptr += l2addrsize(l2);
+
+	if (l2->extended) {
+		p = (ptr[1] & 0x1) == 0x1;
+		seq = ptr[1] >> 1;
+	} else {
+		p = (ptr[0] & 0x10);
+		seq = (ptr[0] >> 5) & 0x7;
+	}
+	BufPoolRelease(ibh);
+
+	if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
+		goto noresp;
+
+	if ((!rsp) && p)
+	        enquiry_response(st);
+
+      noresp:
+	if (legalnr(st, seq)) {
+		if (seq == st->l2.vs) {
+			setva(st, seq);
+			FsmDelTimer(&st->l2.t200_timer, 7);
+			st->l2.t200_running = 0;
+			FsmDelTimer(&st->l2.t203_timer, 8);
+			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 5");
+
+			if (st->l2.i_queue.head)
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		} else if (st->l2.va != seq) {
+			setva(st, seq);
+			FsmDelTimer(&st->l2.t200_timer, 9);
+			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 6");
+
+			if (st->l2.i_queue.head)
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		}
+	}
+	else
+	      nrerrorrecovery(fi);
+
+	if ((fi->userint & LC_FLUSH_WAIT) && rsp && !l2->i_queue.head) {
+	        fi->userint &= ~LC_FLUSH_WAIT;
+	        st->l2.l2man(st, DL_FLUSH, NULL);
+	}
+}
+
+static void
+l2s7(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             i;
+	byte           *ptr;
+	struct IsdnCardState *sp = st->l1.hardware;
+	char            str[64];
+
+	i = sethdraddr(&st->l2, ibh, CMD);
+	ptr = DATAPTR(ibh);
+
+	if (st->l2.laptype == LAPD)
+		if (sp->dlogflag) {
+			LogFrame(sp, ptr, ibh->datasize);
+			sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+			dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+				  str);
+		}
+	BufQueueLink(&st->l2.i_queue, ibh);
+
+	st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static int
+icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr)
+{
+	struct PStack  *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	struct BufHeader *ibh = arg;
+	byte           *ptr;
+	struct BufHeader *ibh2;
+	struct IsdnCardState *sp = st->l1.hardware;
+	struct Layer2  *l2 = &(st->l2);
+	int             i, p, seq, wasok;
+	char            str[64];
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(l2);
+	if (l2->extended) {
+		p = (ptr[1] & 0x1) == 0x1;
+		seq = ptr[0] >> 1;
+		*nr = (ptr[1] >> 1) & 0x7f;
+	} else {
+		p = (ptr[0] & 0x10);
+		seq = (ptr[0] >> 1) & 0x7;
+		*nr = (ptr[0] >> 5) & 0x7;
+	}
+
+	if (l2->vr == seq) {
+		wasok = !0;
+
+		l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
+		l2->rejexp = 0;
+
+		ptr = DATAPTR(ibh);
+		if (st->l2.laptype == LAPD)
+			if (sp->dlogflag) {
+				LogFrame(st->l1.hardware, ptr, ibh->datasize);
+				sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
+				dlogframe(st->l1.hardware, ptr + l2->ihsize,
+					ibh->datasize - l2->ihsize, str);
+			}
+	      label8_1:
+		if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
+			goto noRR;
+
+		if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
+			i = sethdraddr(&(st->l2), ibh2, RSP);
+			ptr = DATAPTR(ibh2);
+			ptr += i;
+
+			if (l2->extended) {
+				*ptr++ = RR;
+				*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
+				i += 2;
+			} else {
+				*ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
+				i += 1;
+			}
+			ibh2->datasize = i;
+			enqueue_super(st, ibh2);
+		      noRR:
+		}
+	} else {
+	        /* n(s)!=v(r) */
+		wasok = 0;
+		BufPoolRelease(ibh);
+		if (st->l2.rejexp) {
+			if (p)
+				goto label8_1;
+		} else {
+			st->l2.rejexp = !0;
+			if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
+				i = sethdraddr(&(st->l2), ibh2, RSP);
+				ptr = DATAPTR(ibh2);
+				ptr += i;
+
+				if (l2->extended) {
+					*ptr++ = REJ;
+					*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
+					i += 2;
+				} else {
+					*ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
+					i += 1;
+				}
+				ibh2->datasize = i;
+				enqueue_super(st, ibh2);
+			}
+		}
+	}
+
+	return wasok;
+
+}
+
+static void
+l2s8(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             nr, wasok;
+
+	wasok = icommandreceived(fi, event, arg, &nr);
+
+	if (legalnr(st, nr)) {
+		if (nr == st->l2.vs) {
+			setva(st, nr);
+			FsmDelTimer(&st->l2.t200_timer, 10);
+			st->l2.t200_running = 0;
+			FsmDelTimer(&st->l2.t203_timer, 11);
+			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 5");
+
+			if (st->l2.i_queue.head)
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		} else if (nr != st->l2.va) {
+			setva(st, nr);
+			FsmDelTimer(&st->l2.t200_timer, 12);
+			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 6");
+
+			if (st->l2.i_queue.head)
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		}
+	}
+	else
+	      nrerrorrecovery(fi);
+  
+	if (wasok)
+	        st->l2.l2l3(st, DL_DATA, ibh);
+}
+
+static void
+l2s8_1(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             nr, wasok;
+
+	wasok = icommandreceived(fi, event, arg, &nr);
+
+	if (legalnr(st, nr)) {
+			setva(st, nr);
+			if (st->l2.i_queue.head)
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+	}
+	else
+	      nrerrorrecovery(fi);
+  
+	if (wasok)
+	        st->l2.l2l3(st, DL_DATA, ibh);
+}
+
+static void
+l2s17(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	st->l2.tei = (int) arg;
+	establishlink(fi);
+}
+
+static void
+invoke_retransmission(struct PStack *st, int nr)
+{
+	struct Layer2  *l2 = &st->l2;
+	int             p1;
+
+	if (l2->vs != nr) {
+		while (l2->vs != nr) {
+
+			l2->vs = l2->vs - 1;
+			if (l2->vs < 0)
+				l2->vs += l2->extended ? 128 : 8;
+
+			p1 = l2->vs - l2->va;
+			if (p1 < 0)
+				p1 += l2->extended ? 128 : 8;
+			p1 = (p1 + l2->sow) % l2->window;
+
+			BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
+		}
+		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+	}
+}
+
+static void
+l2s16(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             p, seq, rsp;
+	byte           *ptr;
+	struct Layer2  *l2;
+
+	l2 = &(st->l2);
+	ptr = DATAPTR(ibh);
+
+	if (l2->laptype == LAPD) {
+		rsp = ptr[0] & 0x2;
+		if (l2->orig)
+			rsp = !rsp;
+	} else {
+		rsp = ptr[0] == 0x3;
+		if (l2->orig)
+			rsp = !rsp;
+	}
+
+
+	ptr += l2addrsize(l2);
+
+	if (l2->extended) {
+		p = (ptr[1] & 0x1) == 0x1;
+		seq = ptr[1] >> 1;
+	} else {
+		p = (ptr[0] & 0x10);
+		seq = (ptr[0] >> 5) & 0x7;
+	}
+	BufPoolRelease(ibh);
+
+	if ((!rsp) && p)
+		enquiry_response(st);
+
+	if (!legalnr(st, seq))
+		return;
+
+	setva(st, seq);
+	invoke_retransmission(st, seq);
+
+}
+
+static void
+l2s19(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2s20(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	int             i;
+	struct BufHeader *ibh;
+	byte           *ptr;
+
+	if (st->l2.rc == st->l2.n200) {
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	} else {
+		st->l2.rc++;
+
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 7");
+
+		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
+			return;
+
+		i = sethdraddr(&st->l2, ibh, CMD);
+		ptr = DATAPTR(ibh);
+		ptr += i;
+		if (st->l2.extended)
+			*ptr = SABME | 0x10;
+		else
+			*ptr = 0x3f;
+		ibh->datasize = i + 1;
+		enqueue_super(st, ibh);
+	}
+}
+
+static void
+l2s21(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	int             i;
+	struct BufHeader *ibh;
+	byte           *ptr;
+
+	if (st->l2.rc == st->l2.n200) {
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	} else {
+		st->l2.rc++;
+
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 8");
+
+
+		if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
+			goto nodisc;
+
+		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
+			return;
+
+		i = sethdraddr(&st->l2, ibh, CMD);
+		ptr = DATAPTR(ibh);
+		ptr += i;
+		*ptr = DISC | 0x10;
+		ibh->datasize = i + 1;
+		enqueue_super(st, ibh);
+	      nodisc:
+
+	}
+}
+
+static void
+l2s22(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh;
+	struct Layer2  *l2 = &st->l2;
+	byte           *ptr;
+	int             p1;
+
+	if (!cansend(st))
+		return;
+
+	if (BufQueueUnlink(&ibh, &l2->i_queue))
+		return;
+
+
+	p1 = l2->vs - l2->va;
+	if (p1 < 0)
+		p1 += l2->extended ? 128 : 8;
+	p1 = (p1 + l2->sow) % l2->window;
+	l2->windowar[p1] = ibh;
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(l2);
+
+	if (l2->extended) {
+		*ptr++ = l2->vs << 1;
+		*ptr++ = l2->vr << 1;
+		l2->vs = (l2->vs + 1) % 128;
+	} else {
+		*ptr++ = (l2->vr << 5) | (l2->vs << 1);
+		l2->vs = (l2->vs + 1) % 8;
+	}
+
+	st->l2.l2l1(st, PH_DATA_PULLED, ibh);
+
+	if (!st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t203_timer, 13);
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 9");
+
+		st->l2.t200_running = !0;
+	}
+
+	if (l2->i_queue.head && cansend(st))
+		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+transmit_enquiry(struct PStack *st)
+{
+	struct BufHeader *ibh;
+	byte           *ptr;
+
+	if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
+		ptr = DATAPTR(ibh);
+		ptr += sethdraddr(&st->l2, ibh, CMD);
+
+		if (st->l2.extended) {
+			*ptr++ = RR;
+			*ptr++ = (st->l2.vr << 1) | 1;
+		} else {
+			*ptr++ = (st->l2.vr << 5) | 0x11;
+		}
+		ibh->datasize = ptr - DATAPTR(ibh);
+		enqueue_super(st, ibh);
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 10");
+
+		st->l2.t200_running = !0;
+	}
+}
+
+static void
+l2s23(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	st->l2.t200_running = 0;
+
+	st->l2.rc = 1;
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(st);
+}
+
+static void
+l2s24(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	int             p, seq, rsp;
+	byte           *ptr;
+	struct Layer2  *l2;
+
+	l2 = &st->l2;
+	ptr = DATAPTR(ibh);
+
+	if (l2->laptype == LAPD) {
+		rsp = ptr[0] & 0x2;
+		if (l2->orig)
+			rsp = !rsp;
+	} else {
+		rsp = ptr[0] == 0x3;
+		if (l2->orig)
+			rsp = !rsp;
+	}
+
+
+	ptr += l2addrsize(l2);
+
+	if (l2->extended) {
+		p = (ptr[1] & 0x1) == 0x1;
+		seq = ptr[1] >> 1;
+	} else {
+		p = (ptr[0] & 0x10);
+		seq = (ptr[0] >> 5) & 0x7;
+	}
+	BufPoolRelease(ibh);
+
+	if (rsp && p) {
+		if (legalnr(st, seq)) {
+			FsmChangeState(fi, ST_L2_7);
+			setva(st, seq);
+			if (st->l2.t200_running) {
+				FsmDelTimer(&st->l2.t200_timer, 14);
+				st->l2.t200_running = 0;
+			}
+			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 11");
+
+			invoke_retransmission(st, seq);
+
+			if (l2->i_queue.head && cansend(st))
+			        st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+			else if (fi->userint & LC_FLUSH_WAIT) {
+			        fi->userint &= ~LC_FLUSH_WAIT;
+			        st->l2.l2man(st, DL_FLUSH, NULL);
+			}
+		}
+	} else {
+		if (!rsp && p)
+			enquiry_response(st);
+		if (legalnr(st, seq)) {
+			setva(st, seq);
+		}
+	}
+}
+
+static void
+l2s25(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	st->l2.rc = 0;
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(st);
+}
+
+static void
+l2s26(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	if (st->l2.rc == st->l2.n200) {
+	        establishlink(fi);
+	} else {
+		st->l2.rc++;
+		transmit_enquiry(st);
+	}
+}
+
+static void
+l2s27(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	byte           *ptr;
+	int             i, p, est;
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(&st->l2);
+
+	p = ptr[0] & 0x10;
+
+	BufPoolRelease(ibh);
+
+	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
+		return;
+	i = sethdraddr(&st->l2, ibh, RSP);
+	ptr = DATAPTR(ibh);
+	ptr += i;
+	*ptr = UA | p;
+	ibh->datasize = i + 1;
+	enqueue_super(st, ibh);
+
+	if (st->l2.vs != st->l2.va) {
+		discard_i_queue(st);
+		est = !0;
+	} else
+		est = 0;
+
+	FsmDelTimer(&st->l2.t200_timer, 15);
+	st->l2.t200_running = 0;
+
+	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 12");
+
+	st->l2.vs = 0;
+	st->l2.va = 0;
+	st->l2.vr = 0;
+	st->l2.sow = 0;
+
+
+	if (est)
+		st->l2.l2man(st, DL_ESTABLISH, NULL);
+
+}
+
+static void
+l2s27_1(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+
+	FsmChangeState(fi, ST_L2_7);
+	l2s27(fi,event,arg);
+
+	if (st->l2.i_queue.head && cansend(st))
+		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+l2s28(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack  *st = fi->userdata;
+	struct BufHeader *ibh = arg;
+	byte           *ptr;
+	char            tmp[64];
+
+	ptr = DATAPTR(ibh);
+	ptr += l2addrsize(&st->l2);
+	ptr++;
+
+	if (st->l2.l2m.debug) {
+		if (st->l2.extended)
+			sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
+				ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
+		else
+			sprintf(tmp, "FRMR information %2x %2x %2x",
+				ptr[0], ptr[1], ptr[2]);
+
+		l2m_debug(&st->l2.l2m, tmp);
+	}
+	BufPoolRelease(ibh);
+}
+
+static int
+IsUI(byte * data, int ext)
+{
+	return ((data[0] & 0xef) == UI);
+}
+
+static int
+IsUA(byte * data, int ext)
+{
+	return ((data[0] & 0xef) == UA);
+}
+
+static int
+IsDISC(byte * data, int ext)
+{
+	return ((data[0] & 0xef) == DISC);
+}
+
+static int
+IsRR(byte * data, int ext)
+{
+	if (ext)
+		return (data[0] == RR);
+	else
+		return ((data[0] & 0xf) == 1);
+}
+
+static int
+IsI(byte * data, int ext)
+{
+	return ((data[0] & 0x1) == 0x0);
+}
+
+static int
+IsSABMX(byte * data, int ext)
+{
+	return (ext ? (data[0] & ~0x10) == SABME : data[0] == 0x3f);
+}
+
+static int
+IsREJ(byte * data, int ext)
+{
+	return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9);
+}
+
+static int
+IsFRMR(byte * data, int ext)
+{
+	return ((data[0] & 0xef) == FRMR);
+}
+
+static int
+IsRNR(byte * data, int ext)
+{
+	if (ext)
+		return (data[0] == RNR);
+	else
+		return ((data[0] & 0xf) == 5);
+}
+
+static struct FsmNode L2FnList[] =
+{
+	{ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
+	{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
+	{ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
+	{ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
+	{ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
+	{ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
+	{ST_L2_7, EV_L2_DL_DATA, l2s7},
+	{ST_L2_7, EV_L2_DL_RELEASE, l2s13},
+	{ST_L2_7, EV_L2_ACK_PULL, l2s22},
+	{ST_L2_8, EV_L2_DL_DATA, l2s7},
+	{ST_L2_8, EV_L2_DL_RELEASE, l2s13},
+
+	{ST_L2_1, EV_L2_UI, l2s3},
+	{ST_L2_4, EV_L2_UI, l2s3},
+	{ST_L2_4, EV_L2_SABMX, l2s12},
+	{ST_L2_4, EV_L2_DISC, l2s14_1},
+	{ST_L2_5, EV_L2_UA, l2s5},
+	{ST_L2_6, EV_L2_UA, l2s15},
+	{ST_L2_7, EV_L2_UI, l2s3},
+	{ST_L2_7, EV_L2_DISC, l2s14},
+	{ST_L2_7, EV_L2_I, l2s8},
+	{ST_L2_7, EV_L2_RR, l2s6},
+	{ST_L2_7, EV_L2_REJ, l2s16},
+	{ST_L2_7, EV_L2_SABMX, l2s27},
+	{ST_L2_7, EV_L2_FRMR, l2s28},
+	{ST_L2_8, EV_L2_RR, l2s24},
+	{ST_L2_8, EV_L2_REJ, l2s24},
+	{ST_L2_8, EV_L2_SABMX, l2s27_1},
+	{ST_L2_8, EV_L2_DISC, l2s14},
+	{ST_L2_8, EV_L2_FRMR, l2s28},
+	{ST_L2_8, EV_L2_I, l2s8_1},
+
+	{ST_L2_5, EV_L2_T200, l2s20},
+	{ST_L2_6, EV_L2_T200, l2s21},
+	{ST_L2_7, EV_L2_T200, l2s23},
+	{ST_L2_7, EV_L2_T203, l2s25},
+	{ST_L2_8, EV_L2_T200, l2s26},
+};
+
+#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
+
+static void
+isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
+{
+	struct BufHeader *ibh;
+	byte           *datap;
+	int             ret = !0;
+
+	switch (pr) {
+	  case (PH_DATA):
+
+		  ibh = arg;
+		  datap = DATAPTR(ibh);
+		  datap += l2addrsize(&st->l2);
+
+		  if (IsI(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
+		  else if (IsRR(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
+		  else if (IsUI(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
+		  else if (IsSABMX(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
+		  else if (IsUA(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
+		  else if (IsDISC(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
+		  else if (IsREJ(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
+		  else if (IsFRMR(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
+		  else if (IsRNR(datap, st->l2.extended))
+			  ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
+
+		  if (ret)
+			  BufPoolRelease(ibh);
+
+		  break;
+	  case (PH_PULL_ACK):
+		  FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
+		  break;
+	}
+}
+
+static void
+isdnl2_l3l2(struct PStack *st, int pr,
+	    void *arg)
+{
+	switch (pr) {
+	  case (DL_DATA):
+		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
+			  BufPoolRelease((struct BufHeader *) arg);
+		  break;
+	  case (DL_UNIT_DATA):
+		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
+			  BufPoolRelease((struct BufHeader *) arg);
+		  break;
+	}
+}
+
+static void
+isdnl2_manl2(struct PStack *st, int pr,
+	     void *arg)
+{
+	switch (pr) {
+	  case (DL_ESTABLISH):
+		  FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+		  break;
+	  case (DL_RELEASE):
+		  FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
+		  break;
+	  case (MDL_NOTEIPROC):
+		  FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
+		  break;
+	  case (DL_FLUSH):
+	          (&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
+		  break;
+	}
+}
+
+static void
+isdnl2_teil2(struct PStack *st, int pr,
+	     void *arg)
+{
+	switch (pr) {
+	  case (MDL_ASSIGN):
+		  FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
+		  break;
+	}
+}
+
+void
+releasestack_isdnl2(struct PStack *st)
+{
+	FsmDelTimer(&st->l2.t200_timer, 15);
+	FsmDelTimer(&st->l2.t203_timer, 16);
+}
+
+static void
+l2m_debug(struct FsmInst *fi, char *s)
+{
+	struct PStack  *st = fi->userdata;
+	char            tm[32], str[256];
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
+	HiSax_putstatus(str);
+}
+
+
+void
+setstack_isdnl2(struct PStack *st, char *debug_id)
+{
+	st->l1.l1l2 = isdnl2_l1l2;
+	st->l3.l3l2 = isdnl2_l3l2;
+	st->ma.manl2 = isdnl2_manl2;
+	st->ma.teil2 = isdnl2_teil2;
+
+	st->l2.uihsize = l2headersize(&st->l2, !0);
+	st->l2.ihsize = l2headersize(&st->l2, 0);
+	BufQueueInit(&(st->l2.i_queue));
+	st->l2.rejexp = 0;
+	st->l2.debug = 1;
+
+	st->l2.l2m.fsm = &l2fsm;
+	st->l2.l2m.state = ST_L2_1;
+	st->l2.l2m.debug = 0;
+	st->l2.l2m.userdata = st;
+	st->l2.l2m.userint = 0;
+	st->l2.l2m.printdebug = l2m_debug;
+	strcpy(st->l2.debug_id, debug_id);
+
+	FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
+	FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
+	st->l2.t200_running = 0;
+}
+
+void
+setstack_transl2(struct PStack *st)
+{
+}
+
+void
+releasestack_transl2(struct PStack *st)
+{
+}
+
+void
+Isdnl2New(void)
+{
+	l2fsm.state_count = L2_STATE_COUNT;
+	l2fsm.event_count = L2_EVENT_COUNT;
+	l2fsm.strEvent = strL2Event;
+	l2fsm.strState = strL2State;
+	FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+}
+
+void
+Isdnl2Free(void)
+{
+	FsmFree(&l2fsm);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl2.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl2.h	Mon Dec  9 00:11:21 1996
@@ -0,0 +1,17 @@
+/* isdnl2.h */
+
+#define RR     0x01
+#define RNR    0x05
+#define REJ    0x09
+#define SABME  0x6f
+#define DM     0x0f
+#define UI     0x03
+#define DISC   0x43
+#define UA     0x63
+#define FRMR   0x87
+#define XID    0xaf
+
+#define CMD    0
+#define RSP    1
+
+#define LC_FLUSH_WAIT 1
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl3.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl3.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,93 @@
+/* $Id: isdnl3.c,v 1.2 1996/11/05 19:42:04 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: isdnl3.c,v $
+ * Revision 1.2  1996/11/05 19:42:04  keil
+ * using config.h
+ *
+ * Revision 1.1  1996/10/13 20:04:54  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include <linux/config.h>
+
+void
+l3_debug(struct PStack *st, char *s)
+{
+        char            str[256], tm[32];
+
+        jiftime(tm, jiffies);
+        sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
+        HiSax_putstatus(str);
+}
+
+
+
+void
+newl3state(struct PStack *st, int state)
+{
+	char tmp[80];
+
+	if (st->l3.debug & L3_DEB_STATE) {
+		sprintf(tmp,"newstate  %d --> %d",st->l3.state, state);
+		l3_debug(st, tmp);
+	}
+	st->l3.state = state;
+}
+static void
+no_l3_proto(struct PStack *st, int pr, void *arg) {
+	struct BufHeader *ibh = arg;
+	
+	l3_debug(st, "no protocol");
+	if (ibh)
+		BufPoolRelease(ibh);
+}
+
+#ifdef	CONFIG_HISAX_EURO
+extern	void setstack_dss1(struct PStack *st);
+#endif
+
+#ifdef	CONFIG_HISAX_1TR6
+extern	void setstack_1tr6(struct PStack *st);
+#endif
+
+void
+setstack_isdnl3(struct PStack *st, int chan)
+{
+	char	tmp[64];
+
+
+	st->l3.debug   = L3_DEB_WARN;
+	st->l3.channr  = chan;
+
+#ifdef	CONFIG_HISAX_EURO
+	if (st->protocol == ISDN_PTYPE_EURO) {
+		setstack_dss1(st);
+	} else 
+#endif
+#ifdef	CONFIG_HISAX_1TR6
+	if (st->protocol == ISDN_PTYPE_1TR6) {
+		setstack_1tr6(st);
+	} else 
+#endif
+	{
+		sprintf(tmp,"protocol %s not supported",
+			(st->protocol==ISDN_PTYPE_1TR6)?"1tr6":"euro");
+		l3_debug(st,tmp);
+		st->l4.l4l3 = no_l3_proto;
+		st->l2.l2l3 = no_l3_proto;
+		st->protocol = -1;
+	}
+	st->l3.state   = 0;
+	st->l3.callref = 0;
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h
--- linux-2.0.26.org/drivers/isdn/hisax/isdnl3.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/isdnl3.h	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,27 @@
+/* $Id: isdnl3.h,v 1.1 1996/10/13 20:03:47 keil Exp $
+ *
+ * $Log: isdnl3.h,v $
+ * Revision 1.1  1996/10/13 20:03:47  keil
+ * Initial revision
+ *
+ *
+ */
+    
+#define SBIT(state) (1<<state)
+#define ALL_STATES  0x00ffffff
+
+#define	PROTO_DIS_EURO	0x08
+
+#define L3_DEB_WARN	0x01
+#define	L3_DEB_PROTERR	0x02
+#define	L3_DEB_STATE	0x04
+#define	L3_DEB_CHARGE	0x08
+
+struct stateentry {
+	int             state;
+	byte            primitive;
+	void            (*rout) (struct PStack *, byte, void *);
+};
+
+extern void l3_debug(struct PStack *st, char *s);
+extern void newl3state(struct PStack *st, int state);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c
--- linux-2.0.26.org/drivers/isdn/hisax/l3_1tr6.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/l3_1tr6.c	Mon Dec  9 00:09:29 1996
@@ -0,0 +1,607 @@
+/* $Id: l3_1tr6.c,v 1.5 1996/12/08 19:55:17 keil Exp $
+ *
+ *  German 1TR6 D-channel protocol
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: l3_1tr6.c,v $
+ * Revision 1.5  1996/12/08 19:55:17  keil
+ * change CC_REJECT_REQ routine
+ *
+ * Revision 1.4  1996/10/30 10:18:01  keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.3  1996/10/27 22:15:37  keil
+ * bugfix reject handling
+ *
+ * Revision 1.2  1996/10/13 23:08:56  keil
+ * added missing state for callback reject
+ *
+ * Revision 1.1  1996/10/13 20:04:55  keil
+ * Initial revision
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+#include "isdnl3.h"
+
+#define MsgHead(ptr, cref, mty, dis) \
+	*ptr++ = dis; \
+	*ptr++ = 0x1; \
+	*ptr++ = cref; \
+	*ptr++ = mty
+
+static void
+l3_1TR6_message(struct PStack *st, byte mt, byte pd)
+{
+	struct BufHeader *dibh;
+	byte           *p;
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, mt, pd);
+
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+}
+
+static void
+l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh;
+	byte           *p;
+	char           *teln;
+
+	st->l3.callref = st->pa->callref;
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1);
+
+	if ('S' == (st->pa->called[0] & 0x5f)) {	/* SPV ??? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->info; /* 0 for all Services */
+		*p++ = st->pa->info2; /* 0 for all Services */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV (default) */
+		*p++ = st->pa->info; /* 0 for all Services */
+		*p++ = st->pa->info2; /* 0 for all Services */
+	}
+	if (st->pa->calling[0] != '\0') {
+		*p++ = WE0_origAddr;
+		*p++ = strlen(st->pa->calling) + 1;
+		/* Classify as AnyPref. */
+		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		teln = st->pa->calling;
+		while (*teln)
+			*p++ = *teln++ & 0x7f;
+	}
+	*p++ = WE0_destAddr;
+	teln = st->pa->called;
+	if ('S' != (st->pa->called[0] & 0x5f)) {	/* Keine SPV ??? */
+		*p++ = strlen(st->pa->called) + 1;
+		st->pa->spv = 0;
+	} else {		/* SPV */
+		*p++ = strlen(st->pa->called);
+		teln++;		/* skip S */
+		st->pa->spv = 1;
+	}
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+	while (*teln)
+		*p++ = *teln++ & 0x7f;
+
+	*p++ = WE_Shift_F6;
+	/* Codesatz 6 fuer Service */
+	*p++ = WE6_serviceInd;
+	*p++ = 2;		/* len=2 info,info2 */
+	*p++ = st->pa->info;
+	*p++ = st->pa->info2;
+
+	dibh->datasize = p - DATAPTR(dibh);
+
+	newl3state(st, 1);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+}
+
+static void
+l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	int		bcfound = 0;
+	char		tmp[80];
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	p += st->l2.uihsize;
+	st->pa->callref = getcallref(p);
+	st->l3.callref = 0x80 + st->pa->callref;
+
+	/* Channel Identification */
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		bcfound++;
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup without bchannel");
+
+	p = DATAPTR(ibh);
+
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
+		st->pa->info = p[2];
+		st->pa->info2 = p[3];
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup without service indicator");
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			WE0_destAddr, 0)))
+		iecpy(st->pa->called, p, 1);
+	else
+		strcpy(st->pa->called, "");
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			WE0_origAddr, 0))) {
+		iecpy(st->pa->calling, p, 1);
+	} else
+		strcpy(st->pa->calling, "");
+
+	p = DATAPTR(ibh);
+	st->pa->spv = 0;
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			WE0_netSpecFac, 0))) {
+		if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
+			st->pa->spv = 1;
+	}
+	BufPoolRelease(ibh);
+
+        /* Signal all services, linklevel takes care of Service-Indicator */
+        if (bcfound) {
+		if ((st->pa->info != 7) && (st->l3.debug & L3_DEB_WARN)) {
+                        sprintf(tmp, "non-digital call: %s -> %s",
+                               st->pa->calling,
+                               st->pa->called);
+			l3_debug(st, tmp);
+		}
+        	newl3state(st, 6);
+        	st->l3.l3l4(st, CC_SETUP_IND, NULL);
+        }
+}
+
+static void
+l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup answer without bchannel");
+
+	BufPoolRelease(ibh);
+	newl3state(st, 2);
+}
+
+static void
+l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup answer without bchannel");
+
+	BufPoolRelease(ibh);
+	newl3state(st, 3);
+	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 4);
+	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	int             i,tmpcharge=0;
+	char            a_charge[8], tmp[32];
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			WE6_chargingInfo, 6))) {
+		iecpy(a_charge, p, 1);
+                for (i = 0; i < strlen (a_charge); i++) {
+     	                tmpcharge *= 10;
+     	                tmpcharge += a_charge[i] & 0xf;
+     	        }
+                if (tmpcharge > st->pa->chargeinfo) {
+     	                st->pa->chargeinfo = tmpcharge;
+     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
+     	        }
+		if (st->l3.debug & L3_DEB_CHARGE) {
+			sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+			l3_debug(st, tmp);
+		}
+	} else if (st->l3.debug & L3_DEB_CHARGE) 
+		l3_debug(st, "charging info not found");
+
+	BufPoolRelease(ibh);
+}
+
+static void
+l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+}
+
+static void
+l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+        st->pa->chargeinfo=0;
+	BufPoolRelease(ibh);
+	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+	newl3state(st, 10);
+}
+
+static void
+l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+	newl3state(st, 0);
+}
+
+static void
+l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 0);
+	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+	byte           *p;
+	int             i,tmpcharge=0;
+	char            a_charge[8], tmp[32];
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			WE6_chargingInfo, 6))) {
+		iecpy(a_charge, p, 1);
+                for (i = 0; i < strlen (a_charge); i++) {
+     	                tmpcharge *= 10;
+     	                tmpcharge += a_charge[i] & 0xf;
+     	        }
+                if (tmpcharge > st->pa->chargeinfo) {
+     	                st->pa->chargeinfo = tmpcharge;
+     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
+     	        }
+		if (st->l3.debug & L3_DEB_CHARGE) {
+			sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+			l3_debug(st, tmp);
+		}
+	} else if (st->l3.debug & L3_DEB_CHARGE) 
+		l3_debug(st, "charging info not found");
+
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			WE0_cause, 0))) {
+		if (p[1] > 0) {
+			st->pa->cause = p[2];
+		} else {
+			st->pa->cause = 0;
+		}
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "cause not found");
+
+	BufPoolRelease(ibh);
+	newl3state(st, 12);
+	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+
+static void
+l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	st->pa->chargeinfo = 0;
+	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+	newl3state(st, 10);
+}
+
+static void
+l3_1tr6_alert(struct PStack *st, byte pr,
+	      void *arg)
+{
+	l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
+	newl3state(st, 7);
+}
+
+static void
+l3_1tr6_conn(struct PStack *st, byte pr,
+	     void *arg)
+{
+	struct BufHeader *dibh;
+	byte *p;
+
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1);
+
+	if (st->pa->spv) {	/* SPV ??? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->info;
+		*p++ = st->pa->info2;
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV */
+		*p++ = st->pa->info;
+		*p++ = st->pa->info2;
+	}
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+	newl3state(st, 8);
+}
+
+static void
+l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
+{
+	newl3state(st, 0);
+}
+
+static void
+l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh;
+	byte             *p;
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
+
+        if ((st->l3.state & 0xfe) == 6) {
+                *p++ = WE0_cause;       /* Anruf abweisen                */
+                *p++ = 0x01;            /* Laenge = 1                    */
+                *p++ = CAUSE_CallRejected;
+        } else {
+                *p++ = WE0_cause;
+                *p++ = 0x0;             /* Laenge = 0 normales Ausloesen */
+        }
+
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+        newl3state(st, 11);
+}
+
+static void
+l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
+{
+	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
+	newl3state(st, 19);
+}
+
+static struct stateentry downstl[] =
+{
+	{SBIT(0),
+		CC_SETUP_REQ, l3_1tr6_setup},
+	{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)|
+		SBIT(10),
+		CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
+	{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)|
+		SBIT(10)| SBIT(12),
+		CC_RELEASE_REQ, l3_1tr6_rel_req},
+        {SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)|
+         	SBIT(10)| SBIT(12)| SBIT(19),
+        	CC_DLRL, l3_1tr6_reset},
+	{SBIT(6),
+		CC_REJECT_REQ, l3_1tr6_disconn_req},
+	{SBIT(6)|SBIT(7),
+		CC_SETUP_RSP, l3_1tr6_conn},
+	{SBIT(6),
+		CC_ALERTING_REQ, l3_1tr6_alert},
+};
+
+static int      downstl_len = sizeof(downstl) /
+sizeof(struct stateentry);
+
+static struct stateentry datastln1[] =
+{
+	{SBIT(0),
+		MT_N1_SETUP, l3_1tr6_tu_setup},
+	{SBIT(0)| SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)|
+		SBIT(10)| SBIT(11)| SBIT(12),
+		MT_N1_REL, l3_1tr6_tu_rel},
+	{SBIT(1),
+		MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
+	{SBIT(1),
+		MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
+	{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10),
+		MT_N1_DISC, l3_1tr6_tu_disc},
+	{SBIT(2), MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
+	{SBIT(2)| SBIT(3)| SBIT(4),
+		MT_N1_ALERT, l3_1tr6_tu_alert},
+	{SBIT(2)| SBIT(3)| SBIT(4),
+		MT_N1_CONN, l3_1tr6_tu_connect},
+	{SBIT(2),
+		MT_N1_INFO, l3_1tr6_tu_info_s2},
+	{SBIT(8),
+		MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
+	{SBIT(10), 
+		MT_N1_INFO, l3_1tr6_tu_info},
+	{SBIT(19),
+		MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
+};
+
+
+static int      datastln1_len = sizeof(datastln1) /
+sizeof(struct stateentry);
+
+static void
+up1tr6(struct PStack *st,
+     int pr, void *arg)
+{
+	int             i, mt, size;
+	byte           *ptr;
+	struct BufHeader *ibh = arg;
+	char	tmp[80];
+        
+	if (pr == DL_DATA) {
+		ptr = DATAPTR(ibh);
+		ptr += st->l2.ihsize;
+		size = ibh->datasize - st->l2.ihsize;
+	} else if (pr == DL_UNIT_DATA) {
+		ptr = DATAPTR(ibh);
+		ptr += st->l2.uihsize;
+		size = ibh->datasize - st->l2.uihsize;
+	} else {
+        	if (st->l3.debug & L3_DEB_WARN) {
+        		sprintf(tmp, "up1tr6 unknown data typ %d state %d",
+        		 	pr, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		BufPoolRelease(ibh);
+		return;
+	}
+	if ((ptr[0] & 0xfe) != PROTO_DIS_N0) {
+        	if (st->l3.debug & L3_DEB_PROTERR) {
+        		sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d",
+        			(pr==DL_DATA)?" ":"(broadcast) ",
+        			ptr[0], size, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		BufPoolRelease(ibh);
+		return;
+	}
+	mt = ptr[3];
+	
+	if (ptr[0]  == PROTO_DIS_N0) {
+		BufPoolRelease(ibh); 
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"up1tr6%s N0 state %d mt %x unhandled",
+        			(pr==DL_DATA)?" ":"(broadcast) ",
+        			st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+	} else if (ptr[0]  == PROTO_DIS_N1) {
+		for (i = 0; i < datastln1_len; i++)
+			if ((mt == datastln1[i].primitive) &&
+				((1<< st->l3.state) & datastln1[i].state))
+				break;
+		if (i == datastln1_len) {
+			BufPoolRelease(ibh); 
+        		if (st->l3.debug & L3_DEB_STATE) {
+        			sprintf(tmp,"up1tr6%sstate %d mt %x unhandled",
+        				(pr==DL_DATA)?" ":"(broadcast) ",
+        				st->l3.state, mt);
+				l3_debug(st, tmp);
+			}
+			return;
+		} else {
+        		if (st->l3.debug & L3_DEB_STATE) {
+        			sprintf(tmp,"up1tr6%sstate %d mt %x",
+        				(pr==DL_DATA)?" ":"(broadcast) ",
+        				st->l3.state, mt);
+				l3_debug(st, tmp);
+			}
+			datastln1[i].rout(st, pr, ibh);
+		}
+	}
+}
+
+static void
+down1tr6(struct PStack *st,
+       int pr, void *arg)
+{
+	int             i;
+	struct BufHeader *ibh = arg;
+	char	tmp[80];
+        
+	for (i = 0; i < downstl_len; i++)
+		if ((pr == downstl[i].primitive)&&
+			((1<< st->l3.state) & downstl[i].state))
+			break;
+	if (i == downstl_len) {
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"down1tr6 state %d prim %d unhandled",
+        			st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+	} else {
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"down1tr6 state %d prim %d",
+        			st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+		downstl[i].rout(st, pr, ibh);
+	}
+}
+
+void
+setstack_1tr6(struct PStack *st)
+{
+	st->l4.l4l3 = down1tr6;
+	st->l2.l2l3 = up1tr6;
+}
+ 
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h
--- linux-2.0.26.org/drivers/isdn/hisax/l3_1tr6.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/l3_1tr6.h	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,160 @@
+/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+ *
+ *  German 1TR6 D-channel protocol defines
+ *
+ * $Log: l3_1tr6.h,v $
+ * Revision 1.1  1996/10/13 20:03:48  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#ifndef l3_1tr6
+#define l3_1tr6
+
+#define PROTO_DIS_N0 0x40
+#define PROTO_DIS_N1 0x41
+
+/*
+ * MsgType N0
+ */
+#define MT_N0_REG_IND 0x61
+#define MT_N0_CANC_IND 0x62
+#define MT_N0_FAC_STA 0x63
+#define MT_N0_STA_ACK 0x64
+#define MT_N0_STA_REJ 0x65
+#define MT_N0_FAC_INF 0x66
+#define MT_N0_INF_ACK 0x67
+#define MT_N0_INF_REJ 0x68
+#define MT_N0_CLOSE   0x75
+#define MT_N0_CLO_ACK 0x77
+
+
+/*
+ * MsgType N1
+ */
+
+#define MT_N1_ESC 0x00
+#define MT_N1_ALERT 0x01
+#define MT_N1_CALL_SENT 0x02
+#define MT_N1_CONN 0x07
+#define MT_N1_CONN_ACK 0x0F
+#define MT_N1_SETUP 0x05
+#define MT_N1_SETUP_ACK 0x0D
+#define MT_N1_RES 0x26
+#define MT_N1_RES_ACK 0x2E
+#define MT_N1_RES_REJ 0x22
+#define MT_N1_SUSP 0x25
+#define MT_N1_SUSP_ACK 0x2D
+#define MT_N1_SUSP_REJ 0x21
+#define MT_N1_USER_INFO 0x20
+#define MT_N1_DET 0x40
+#define MT_N1_DISC 0x45
+#define MT_N1_REL 0x4D
+#define MT_N1_REL_ACK 0x5A
+#define MT_N1_CANC_ACK 0x6E
+#define MT_N1_CANC_REJ 0x67
+#define MT_N1_CON_CON 0x69
+#define MT_N1_FAC 0x60
+#define MT_N1_FAC_ACK 0x68
+#define MT_N1_FAC_CAN 0x66
+#define MT_N1_FAC_REG 0x64
+#define MT_N1_FAC_REJ 0x65
+#define MT_N1_INFO 0x6D
+#define MT_N1_REG_ACK 0x6C
+#define MT_N1_REG_REJ 0x6F
+#define MT_N1_STAT 0x63
+
+
+
+/*
+ * W Elemente
+ */
+
+#define WE_Shift_F0 0x90
+#define WE_Shift_F6 0x96
+#define WE_Shift_OF0 0x98
+#define WE_Shift_OF6 0x9E
+
+#define WE0_cause 0x08
+#define WE0_connAddr 0x0C
+#define WE0_callID 0x10
+#define WE0_chanID 0x18
+#define WE0_netSpecFac 0x20
+#define WE0_display 0x28
+#define WE0_keypad 0x2C
+#define WE0_origAddr 0x6C
+#define WE0_destAddr 0x70
+#define WE0_userInfo 0x7E
+
+#define WE0_moreData 0xA0
+#define WE0_congestLevel 0xB0
+
+#define WE6_serviceInd 0x01
+#define WE6_chargingInfo 0x02
+#define WE6_date 0x03
+#define WE6_facSelect 0x05
+#define WE6_facStatus 0x06
+#define WE6_statusCalled 0x07
+#define WE6_addTransAttr 0x08
+
+/*
+ * FacCodes
+ */
+#define FAC_Sperre 0x01
+#define FAC_Sperre_All 0x02
+#define FAC_Sperre_Fern 0x03
+#define FAC_Sperre_Intl 0x04
+#define FAC_Sperre_Interk 0x05
+
+#define FAC_Forward1 0x02
+#define FAC_Forward2 0x03
+#define FAC_Konferenz 0x06
+#define FAC_GrabBchan 0x0F
+#define FAC_Reactivate 0x10
+#define FAC_Konferenz3 0x11
+#define FAC_Dienstwechsel1 0x12
+#define FAC_Dienstwechsel2 0x13
+#define FAC_NummernIdent 0x14
+#define FAC_GBG 0x15
+#define FAC_DisplayUebergeben 0x17
+#define FAC_DisplayUmgeleitet 0x1A
+#define FAC_Unterdruecke 0x1B
+#define FAC_Deactivate 0x1E
+#define FAC_Activate 0x1D
+#define FAC_SPV 0x1F
+#define FAC_Rueckwechsel 0x23
+#define FAC_Umleitung 0x24
+
+/*
+ * Cause codes
+ */
+#define CAUSE_InvCRef 0x01
+#define CAUSE_BearerNotImpl 0x03
+#define CAUSE_CIDunknown 0x07
+#define CAUSE_CIDinUse 0x08
+#define CAUSE_NoChans 0x0A
+#define CAUSE_FacNotImpl 0x10
+#define CAUSE_FacNotSubscr 0x11
+#define CAUSE_OutgoingBarred 0x20
+#define CAUSE_UserAccessBusy 0x21
+#define CAUSE_NegativeGBG 0x22
+#define CAUSE_UnknownGBG 0x23
+#define CAUSE_NoSPVknown 0x25
+#define CAUSE_DestNotObtain 0x35
+#define CAUSE_NumberChanged 0x38
+#define CAUSE_OutOfOrder 0x39
+#define CAUSE_NoUserResponse 0x3A
+#define CAUSE_UserBusy 0x3B
+#define CAUSE_IncomingBarred 0x3D
+#define CAUSE_CallRejected 0x3E
+#define CAUSE_NetworkCongestion 0x59
+#define CAUSE_RemoteUser 0x5A
+#define CAUSE_LocalProcErr 0x70
+#define CAUSE_RemoteProcErr 0x71
+#define CAUSE_RemoteUserSuspend 0x72
+#define CAUSE_RemoteUserResumed 0x73
+#define CAUSE_UserInfoDiscarded 0x7F
+
+
+#endif
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c
--- linux-2.0.26.org/drivers/isdn/hisax/l3dss1.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/l3dss1.c	Mon Dec  9 00:11:21 1996
@@ -0,0 +1,559 @@
+/* $Id: l3dss1.c,v 1.6 1996/12/08 22:59:16 keil Exp $
+ *
+ * EURO/DSS1 D-channel protocol
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: l3dss1.c,v $
+ * Revision 1.6  1996/12/08 22:59:16  keil
+ * fixed calling party number without octet 3a
+ *
+ * Revision 1.5  1996/12/08 19:53:31  keil
+ * fixes from Pekka Sarnila
+ *
+ * Revision 1.4  1996/11/05 19:44:36  keil
+ * some fixes from Henner Eisen
+ *
+ * Revision 1.3  1996/10/30 10:18:01  keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.2  1996/10/27 22:15:16  keil
+ * bugfix reject handling
+ *
+ * Revision 1.1  1996/10/13 20:04:55  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+ 
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	*ptr++ = 0x1; \
+	*ptr++ = cref; \
+	*ptr++ = mty  
+
+static void
+l3_message(struct PStack *st, byte mt)
+{
+	struct BufHeader *dibh;
+	byte             *p;
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+	
+	MsgHead(p, st->l3.callref, mt);
+	
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+}
+
+static void
+l3s3(struct PStack *st, byte pr, void *arg)
+{
+	l3_message(st, MT_RELEASE);
+	newl3state(st, 19);
+}
+
+static void
+l3s4(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 0);
+	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3s4_1(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 19);
+	l3_message(st, MT_RELEASE);
+	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3s5(struct PStack *st, byte pr,
+     void *arg)
+{
+	struct BufHeader *dibh;
+	byte           *p;
+	char           *teln;
+
+	st->l3.callref = st->pa->callref;
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_SETUP);
+
+	/*
+         * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
+         */
+	*p++ = 0xa1;
+	switch (st->pa->info) {
+	  case 1:		/* Telephony                               */
+		  *p++ = 0x4;	/* BC-IE-code                              */
+		  *p++ = 0x3;	/* Length                                  */
+		  *p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
+		  *p++ = 0x90;	/* Circuit-Mode 64kbps                     */
+		  *p++ = 0xa3;	/* A-Law Audio                             */
+		  break;
+	  case 5:		/* Datatransmission 64k, BTX               */
+	  case 7:		/* Datatransmission 64k                    */
+	  default:
+		  *p++ = 0x4;	/* BC-IE-code                              */
+		  *p++ = 0x2;	/* Length                                  */
+		  *p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */
+		  *p++ = 0x90;	/* Circuit-Mode 64kbps                      */
+		  break;
+	}
+	/*
+	 * What about info2? Mapping to High-Layer-Compatibility?
+	 */
+	if (st->pa->calling[0] != '\0') {
+		*p++ = 0x6c;
+		*p++ = strlen(st->pa->calling) + 1;
+		/* Classify as AnyPref. */
+		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		teln = st->pa->calling;
+		while (*teln)
+			*p++ = *teln++ & 0x7f;
+	}
+	*p++ = 0x70;
+	*p++ = strlen(st->pa->called) + 1;
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+
+	teln = st->pa->called;
+	while (*teln)
+		*p++ = *teln++ & 0x7f;
+
+
+	dibh->datasize = p - DATAPTR(dibh);
+
+	newl3state(st, 1);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+}
+
+static void
+l3s6(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
+			0x18, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+	} else 
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup answer without bchannel");
+	
+	BufPoolRelease(ibh);
+	newl3state(st, 3);
+	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3s7(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 12);
+	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+static void
+l3s8(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+	newl3state(st, 10);
+}
+
+static void
+l3s11(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 4);
+	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3s12(struct PStack *st, byte pr, void *arg)
+{
+	byte           *p;
+	int		bcfound = 0;
+	char		tmp[80];
+	struct BufHeader *ibh = arg;
+
+	p = DATAPTR(ibh);
+	p += st->l2.uihsize;
+	st->pa->callref = getcallref(p);
+	st->l3.callref = 0x80 + st->pa->callref;
+
+	/*
+         * Channel Identification
+         */
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			0x18, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		bcfound++ ;
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup without bchannel");
+
+	p = DATAPTR(ibh);
+	/*
+        * Bearer Capabilities
+        */
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
+		switch (p[2] & 0x1f) {
+		  case 0x00:
+                	/* Speech */
+		  case 0x10:
+                        /* 3.1 Khz audio */
+			st->pa->info = 1;
+			break;
+		  case 0x08:
+                	/* Unrestricted digital information */
+			st->pa->info = 7;
+			break;
+		  case 0x09:
+                 	/* Restricted digital information */
+			st->pa->info = 2;
+			break;
+		  case 0x11:
+                 	/* Unrestr. digital information  with tones/announcements */
+			st->pa->info = 3;
+			break;
+		  case 0x18:
+                 	/* Video */
+			st->pa->info = 4;
+			break;
+		  default:
+			st->pa->info = 0;
+		}
+	} else
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup without bearer capabilities");
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			0x70, 0)))
+		iecpy(st->pa->called, p, 1);
+	else
+		strcpy(st->pa->called, "");
+
+	p = DATAPTR(ibh);
+	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
+			0x6c, 0))) 
+		if (p[2] & 0x80) 
+			iecpy(st->pa->calling, p, 1);
+		else
+			iecpy(st->pa->calling, p, 2);
+	else
+		strcpy(st->pa->calling, "");
+	BufPoolRelease(ibh);
+
+        if (bcfound) {
+                if ((st->pa->info != 7) && (st->l3.debug & L3_DEB_WARN)) {
+                        sprintf(tmp, "non-digital call: %s -> %s",
+                               st->pa->calling,
+                               st->pa->called);
+			l3_debug(st, tmp);
+                }
+                newl3state(st, 6);
+                st->l3.l3l4(st, CC_SETUP_IND, NULL);
+        }
+}
+
+static void
+l3s13(struct PStack *st, byte pr, void *arg)
+{
+	newl3state(st, 0);
+}
+
+static void
+l3s16(struct PStack *st, byte pr,
+      void *arg)
+{
+	st->l3.callref = 0x80 + st->pa->callref;
+	l3_message(st, MT_CONNECT);
+	newl3state(st, 8);
+}
+
+static void
+l3s17(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+	newl3state(st, 10);
+}
+
+static void
+l3s18(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh;
+	byte           *p;
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_DISCONNECT);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = 0x90;
+
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+	newl3state(st, 11);
+}
+
+static void
+l3s18_6(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh;
+	byte           *p;
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE);
+
+	/* we should really get the cause from call control:
+	   busy, incomp. facility ...   (psa) */
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = 0x95;  /* Call rejected */
+
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+	newl3state(st, 0);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3s19(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *ibh = arg;
+
+	BufPoolRelease(ibh);
+	newl3state(st, 0);
+	l3_message(st, MT_RELEASE_COMPLETE);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3s20(struct PStack *st, byte pr,
+      void *arg)
+{
+	l3_message(st, MT_ALERTING);
+	newl3state(st, 7);
+}
+
+/* Status enquire answer */
+static void
+l3s21(struct PStack *st, byte pr, void *arg)
+{
+	struct BufHeader *dibh = arg;
+	byte           *p;
+
+	BufPoolRelease(dibh);
+
+	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 22);
+	p = DATAPTR(dibh);
+	p += st->l2.ihsize;
+
+	MsgHead(p, st->l3.callref, MT_STATUS);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = 0x9E; /* answer status enquire */
+
+	*p++ = 0x14; /* CallState */
+	*p++ = 0x1;
+	*p++ = st->l3.state & 0x3f;
+
+	dibh->datasize = p - DATAPTR(dibh);
+	st->l3.l3l2(st, DL_DATA, dibh);
+
+}
+
+static struct stateentry downstatelist[] =
+{
+        {SBIT(0),
+        	CC_SETUP_REQ,l3s5},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10),
+        	CC_DISCONNECT_REQ,l3s18},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)| SBIT(10)| 
+        	SBIT(11)| SBIT(12),
+        	CC_RELEASE_REQ,l3s3},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)| SBIT(10)|
+        	SBIT(19),
+        	CC_DLRL,l3s13},
+        {SBIT(6),
+        	CC_REJECT_REQ,l3s18_6},
+        {SBIT(6),
+        	CC_ALERTING_REQ,l3s20},
+        {SBIT(6)| SBIT(7),
+        	CC_SETUP_RSP,l3s16},
+};
+
+static int      downsllen = sizeof(downstatelist) /
+sizeof(struct stateentry);
+
+static struct stateentry datastatelist[] =
+{
+        {ALL_STATES,
+        	MT_STATUS_ENQUIRY,l3s21},
+        {SBIT(0)| SBIT(6),
+        	MT_SETUP,l3s12},
+        {SBIT(1),
+        	MT_CALL_PROCEEDING,l3s6},
+        {SBIT(1),
+        	MT_SETUP_ACKNOWLEDGE,l3s6},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(11)| SBIT(19),
+        	MT_RELEASE_COMPLETE,l3s4},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10)| SBIT(11),
+        	MT_RELEASE,l3s19},
+        {SBIT(1)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10),
+        	MT_DISCONNECT,l3s7},
+        {SBIT(3)| SBIT(4),
+        	MT_CONNECT,l3s8},
+        {SBIT(3),
+        	MT_ALERTING,l3s11},
+        {SBIT(7)| SBIT(8)| SBIT(10),
+        	MT_RELEASE_COMPLETE,l3s4_1},
+        {SBIT(8),
+        	MT_CONNECT_ACKNOWLEDGE,l3s17},
+};
+
+static int      datasllen = sizeof(datastatelist) /
+sizeof(struct stateentry);
+
+static void
+dss1up(struct PStack *st,
+     int pr, void *arg)
+{
+	int             i, mt, size;
+	byte           *ptr;
+	struct BufHeader *ibh = arg;
+	char	tmp[80];
+        
+	if (pr == DL_DATA) {
+		ptr = DATAPTR(ibh);
+		ptr += st->l2.ihsize;
+		size = ibh->datasize - st->l2.ihsize;
+	} else if (pr == DL_UNIT_DATA) {
+		ptr = DATAPTR(ibh);
+		ptr += st->l2.uihsize;
+		size = ibh->datasize - st->l2.uihsize;
+	} else {
+        	if (st->l3.debug & L3_DEB_WARN) {
+        		sprintf(tmp, "dss1up unknown data typ %d state %d",
+        		 	pr, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		BufPoolRelease(ibh);
+		return;
+	}
+	if (ptr[0] != PROTO_DIS_EURO) {
+        	if (st->l3.debug & L3_DEB_PROTERR) {
+        		sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d state %d",
+        			(pr==DL_DATA)?" ":"(broadcast) ",
+        			ptr[0], size, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		BufPoolRelease(ibh);
+		return;
+	}
+	mt = ptr[3];
+	for (i = 0; i < datasllen; i++)
+		if ((mt == datastatelist[i].primitive) &&
+			((1<< st->l3.state) & datastatelist[i].state))
+			break;
+	if (i == datasllen) {
+		BufPoolRelease(ibh);
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"dss1up%sstate %d mt %x unhandled",
+        			(pr==DL_DATA)?" ":"(broadcast) ",
+        			st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+		return;
+	} else {
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"dss1up%sstate %d mt %x",
+        			(pr==DL_DATA)?" ":"(broadcast) ",
+        			st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+		datastatelist[i].rout(st, pr, ibh);
+	}
+}
+
+static void
+dss1down(struct PStack *st,
+       int pr, void *arg)
+{
+	int             i;
+	struct BufHeader *ibh = arg;
+	char	tmp[80];
+        
+	for (i = 0; i < downsllen; i++)
+		if ((pr == downstatelist[i].primitive)&&
+			((1<< st->l3.state) & downstatelist[i].state))
+			break;
+	if (i == downsllen) {
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"dss1down state %d prim %d unhandled",
+        			st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+	} else {
+        	if (st->l3.debug & L3_DEB_STATE) {
+        		sprintf(tmp,"dss1down state %d prim %d",
+        			st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+		downstatelist[i].rout(st, pr, ibh);
+	}
+}
+
+void
+setstack_dss1(struct PStack *st)
+{
+	st->l4.l4l3 = dss1down;
+	st->l2.l2l3 = dss1up;
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/llglue.c linux/drivers/isdn/hisax/llglue.c
--- linux-2.0.26.org/drivers/isdn/hisax/llglue.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/llglue.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,167 @@
+/* $Id: llglue.c,v 1.3 1996/11/05 19:35:47 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: llglue.c,v $
+ * Revision 1.3  1996/11/05 19:35:47  keil
+ * using config.h
+ *
+ * Revision 1.2  1996/10/22 23:14:07  fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.1  1996/10/13 20:04:56  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include <linux/config.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+
+
+extern struct Channel *chanlist;
+int     	HiSax_Installed=0;
+int             drid;
+char            *HiSax_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+isdn_if         iif;
+
+#define HISAX_STATUS_BUFSIZE 4096
+static byte    *HiSax_status_buf = NULL;
+static byte    *HiSax_status_read = NULL;
+static byte    *HiSax_status_write = NULL;
+static byte    *HiSax_status_end = NULL;
+
+int
+HiSax_readstatus(byte * buf, int len, int user, int id, int channel)
+{
+	int             count;
+	byte           *p;
+
+	for (p = buf, count = 0; count < len; p++, count++) {
+		if (user)
+			put_user(*HiSax_status_read++, p);
+		else
+			*p++ = *HiSax_status_read++;
+		if (HiSax_status_read > HiSax_status_end)
+			HiSax_status_read = HiSax_status_buf;
+	}
+	return count;
+}
+
+void
+HiSax_putstatus(char *buf)
+{
+	long            flags;
+	int             len, count, i;
+	byte           *p;
+	isdn_ctrl       ic;
+
+	save_flags(flags);
+	cli();
+	count = 0;
+	len = strlen(buf);
+	if (!HiSax_Installed) {
+		printk(KERN_DEBUG "HiSax: %s", buf);
+		restore_flags(flags);
+		return;
+	}
+	for (p = buf, i = len; i > 0; i--, p++) {
+		*HiSax_status_write++ = *p;
+		if (HiSax_status_write > HiSax_status_end)
+			HiSax_status_write = HiSax_status_buf;
+		count++;
+	}
+	restore_flags(flags);
+	if (count) {
+		ic.command = ISDN_STAT_STAVAIL;
+		ic.driver = drid;
+		ic.arg = count;
+		iif.statcallb(&ic);
+	}
+}
+
+
+int
+ll_init(void)
+{
+	long            flags;
+	isdn_ctrl       ic;
+
+	save_flags(flags);
+	cli();
+	HiSax_status_buf = Smalloc(HISAX_STATUS_BUFSIZE,
+				   GFP_KERNEL, "HiSax_status_buf");
+	if (!HiSax_status_buf) {
+		printk(KERN_ERR "HiSax: Could not allocate status-buffer\n");
+		restore_flags(flags);
+		return (-EIO);
+	} else {
+		HiSax_status_read = HiSax_status_buf;
+		HiSax_status_write = HiSax_status_buf;
+		HiSax_status_end = HiSax_status_buf + HISAX_STATUS_BUFSIZE - 1;
+	}
+	iif.channels = CallcNewChan();
+	iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
+	iif.features =
+	    ISDN_FEATURE_L2_X75I |
+	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L2_TRANS |
+	    ISDN_FEATURE_L3_TRANS |
+#ifdef	CONFIG_HISAX_EURO
+	    ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef	CONFIG_HISAX_EURO
+	    ISDN_FEATURE_P_EURO |
+#endif
+	    0;
+	    
+
+	iif.command = HiSax_command;
+	iif.writebuf = HiSax_writebuf;
+	iif.writecmd = NULL;
+	iif.readstat = HiSax_readstatus;
+	strncpy(iif.id, HiSax_id, sizeof(iif.id) - 1);
+	register_isdn(&iif);
+
+
+	drid = iif.channels;
+	ic.driver = drid;
+	ic.command = ISDN_STAT_RUN;
+	iif.statcallb(&ic);
+	restore_flags(flags);
+	return 0;
+}
+
+void
+ll_stop(void)
+{
+	isdn_ctrl       ic;
+
+	ic.command = ISDN_STAT_STOP;
+	ic.driver = drid;
+	iif.statcallb(&ic);
+
+	CallcFreeChan();
+}
+
+void
+ll_unload(void)
+{
+	isdn_ctrl       ic;
+
+	ic.command = ISDN_STAT_UNLOAD;
+	ic.driver = drid;
+	iif.statcallb(&ic);
+	if (HiSax_status_buf) 
+		Sfree(HiSax_status_buf);
+	HiSax_status_read  = NULL;
+	HiSax_status_write = NULL;
+	HiSax_status_end   = NULL;
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c
--- linux-2.0.26.org/drivers/isdn/hisax/q931.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/q931.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,1171 @@
+/* $Id: q931.c,v 1.2 1996/10/27 22:12:45 keil Exp $
+ *
+ * q931.c	code to decode ITU Q.931 call control messages
+ * 
+ * Author       Jan den Ouden
+ * 
+ * Changelog
+ * 
+ * Pauline Middelink    general improvements
+ * 
+ * Beat Doebeli         cause texts, display information element
+ * 
+ * Karsten Keil         cause texts, display information element for 1TR6 
+ *
+ * 
+ * $Log: q931.c,v $
+ * Revision 1.2  1996/10/27 22:12:45  keil
+ * reporting unknown level 3 protocol ids
+ *
+ * Revision 1.1  1996/10/13 20:04:56  keil
+ * Initial revision
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+
+byte           *
+findie(byte * p, int size, byte ie, int wanted_set)
+{
+	int             l, codeset, maincodeset;
+	byte           *pend = p + size;
+
+	/* skip protocol discriminator, callref and message type */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	p++;
+	codeset = 0;
+	maincodeset = 0;
+	/* while there are bytes left... */
+	while (p < pend) {
+		if ((*p & 0xf0) == 0x90) {
+			codeset = *p & 0x07;
+			if (!(*p & 0x08))
+				maincodeset = codeset;
+		}
+		if (*p & 0x80)
+			p++;
+		else {
+			if (codeset == wanted_set) {
+				if (*p == ie)
+					return (p);
+				if (*p > ie)
+					return (NULL);
+			}
+			p++;
+			l = *p++;
+			p += l;
+			codeset = maincodeset;
+		}
+	}
+	return (NULL);
+}
+
+void
+iecpy(byte * dest, byte * iestart, int ieoffset)
+{
+	byte           *p;
+	int             l;
+
+	p = iestart + ieoffset + 2;
+	l = iestart[1] - ieoffset;
+	while (l--)
+		*dest++ = *p++;
+	*dest++ = '\0';
+}
+
+int
+getcallref(byte * p)
+{
+	p++;			/* prot discr */
+	p++;			/* callref length */
+	return (*p);		/* assuming one-byte callref */
+}
+
+/*
+ * According to Table 4-2/Q.931
+ */
+static
+struct MessageType {
+	byte            nr;
+	char           *descr;
+} mtlist[] = {
+
+	{
+		0x1, "ALERTING"
+	},
+	{
+		0x2, "CALL PROCEEDING"
+	},
+	{
+		0x7, "CONNECT"
+	},
+	{
+		0xf, "CONNECT ACKNOWLEDGE"
+	},
+	{
+		0x3, "PROGRESS"
+	},
+	{
+		0x5, "SETUP"
+	},
+	{
+		0xd, "SETUP ACKNOWLEDGE"
+	},
+	{
+		0x26, "RESUME"
+	},
+	{
+		0x2e, "RESUME ACKNOWLEDGE"
+	},
+	{
+		0x22, "RESUME REJECT"
+	},
+	{
+		0x25, "SUSPEND"
+	},
+	{
+		0x2d, "SUSPEND ACKNOWLEDGE"
+	},
+	{
+		0x21, "SUSPEND REJECT"
+	},
+	{
+		0x20, "USER INFORMATION"
+	},
+	{
+		0x45, "DISCONNECT"
+	},
+	{
+		0x4d, "RELEASE"
+	},
+	{
+		0x5a, "RELEASE COMPLETE"
+	},
+	{
+		0x46, "RESTART"
+	},
+	{
+		0x4e, "RESTART ACKNOWLEDGE"
+	},
+	{
+		0x60, "SEGMENT"
+	},
+	{
+		0x79, "CONGESTION CONTROL"
+	},
+	{
+		0x7b, "INFORMATION"
+	},
+	{
+		0x62, "FACILITY"
+	},
+	{
+		0x6e, "NOTIFY"
+	},
+	{
+		0x7d, "STATUS"
+	},
+	{
+		0x75, "STATUS ENQUIRY"
+	}
+};
+
+#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
+
+static
+struct MessageType mt_n0[] =
+{
+	{MT_N0_REG_IND, "REGister INDication"},
+	{MT_N0_CANC_IND, "CANCel INDication"},
+	{MT_N0_FAC_STA, "FACility STAtus"},
+	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
+	{MT_N0_STA_REJ, "STAtus REJect"},
+	{MT_N0_FAC_INF, "FACility INFormation"},
+	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
+	{MT_N0_INF_REJ, "INFormation REJect"},
+	{MT_N0_CLOSE, "CLOSE"},
+	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
+};
+
+int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
+
+static
+struct MessageType mt_n1[] =
+{
+	{MT_N1_ESC, "ESCape"},
+	{MT_N1_ALERT, "ALERT"},
+	{MT_N1_CALL_SENT, "CALL SENT"},
+	{MT_N1_CONN, "CONNect"},
+	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
+	{MT_N1_SETUP, "SETUP"},
+	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
+	{MT_N1_RES, "RESume"},
+	{MT_N1_RES_ACK, "RESume ACKnowledge"},
+	{MT_N1_RES_REJ, "RESume REJect"},
+	{MT_N1_SUSP, "SUSPend"},
+	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
+	{MT_N1_SUSP_REJ, "SUSPend REJect"},
+	{MT_N1_USER_INFO, "USER INFO"},
+	{MT_N1_DET, "DETach"},
+	{MT_N1_DISC, "DISConnect"},
+	{MT_N1_REL, "RELease"},
+	{MT_N1_REL_ACK, "RELease ACKnowledge"},
+	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
+	{MT_N1_CANC_REJ, "CANCel REJect"},
+	{MT_N1_CON_CON, "CONgestion CONtrol"},
+	{MT_N1_FAC, "FACility"},
+	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
+	{MT_N1_FAC_CAN, "FACility CANcel"},
+	{MT_N1_FAC_REG, "FACility REGister"},
+	{MT_N1_FAC_REJ, "FACility REJect"},
+	{MT_N1_INFO, "INFOrmation"},
+	{MT_N1_REG_ACK, "REGister ACKnowledge"},
+	{MT_N1_REG_REJ, "REGister REJect"},
+	{MT_N1_STAT, "STATus"}
+};
+
+int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
+
+static struct MessageType fac_1tr6[] =
+{
+	{FAC_Sperre, "Sperre"},
+	{FAC_Forward1, "Forward 1"},
+	{FAC_Forward2, "Forward 2"},
+	{FAC_Konferenz, "Konferenz"},
+	{FAC_GrabBchan, "Grab Bchannel"},
+	{FAC_Reactivate, "Reactivate"},
+	{FAC_Konferenz3, "Dreier Konferenz"},
+	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
+	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
+	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
+	{FAC_GBG, "GBG"},
+	{FAC_DisplayUebergeben, "Display Uebergeben"},
+	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
+	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
+	{FAC_Deactivate, "Deactivate"},
+	{FAC_Activate, "Activate"},
+	{FAC_SPV, "SPV"},
+	{FAC_Rueckwechsel, "Rueckwechsel"},
+	{FAC_Umleitung, "Umleitung"}
+};
+int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
+
+
+
+static int 
+prbits(char *dest, byte b, int start, int len)
+{
+	char           *dp = dest;
+
+	b = b << (8 - start);
+	while (len--) {
+		if (b & 0x80)
+			*dp++ = '1';
+		else
+			*dp++ = '0';
+		b = b << 1;
+	}
+	return (dp - dest);
+}
+
+static
+byte           *
+skipext(byte * p)
+{
+	while (!(*p++ & 0x80));
+	return (p);
+}
+
+/*
+ * Cause Values According to Q.850
+ * edescr: English description
+ * ddescr: German description used by Swissnet II (Swiss Telecom
+ *         not yet written...
+ */
+
+static
+struct CauseValue {
+	byte            nr;
+	char           *edescr;
+	char           *ddescr;
+} cvlist[] = {
+
+	{
+		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
+	},
+	{
+		0x02, "No route to specified transit network", ""
+	},
+	{
+		0x03, "No route to destination", ""
+	},
+	{
+		0x04, "Send special information tone", ""
+	},
+	{
+		0x05, "Misdialled trunk prefix", ""
+	},
+	{
+		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
+	},
+	{
+		0x07, "Channel awarded and being delivered in an established channel", ""
+	},
+	{
+		0x08, "Preemption", ""
+	},
+	{
+		0x09, "Preemption - circuit reserved for reuse", ""
+	},
+	{
+		0x10, "Normal call clearing", "Normale Ausloesung"
+	},
+	{
+		0x11, "User busy", "TNB besetzt"
+	},
+	{
+		0x12, "No user responding", ""
+	},
+	{
+		0x13, "No answer from user (user alerted)", ""
+	},
+	{
+		0x14, "Subscriber absent", ""
+	},
+	{
+		0x15, "Call rejected", ""
+	},
+	{
+		0x16, "Number changed", ""
+	},
+	{
+		0x1a, "non-selected user clearing", ""
+	},
+	{
+		0x1b, "Destination out of order", ""
+	},
+	{
+		0x1c, "Invalid number format (address incomplete)", ""
+	},
+	{
+		0x1d, "Facility rejected", ""
+	},
+	{
+		0x1e, "Response to Status enquiry", ""
+	},
+	{
+		0x1f, "Normal, unspecified", ""
+	},
+	{
+		0x22, "No circuit/channel available", ""
+	},
+	{
+		0x26, "Network out of order", ""
+	},
+	{
+		0x27, "Permanent frame mode connection out-of-service", ""
+	},
+	{
+		0x28, "Permanent frame mode connection operational", ""
+	},
+	{
+		0x29, "Temporary failure", ""
+	},
+	{
+		0x2a, "Switching equipment congestion", ""
+	},
+	{
+		0x2b, "Access information discarded", ""
+	},
+	{
+		0x2c, "Requested circuit/channel not available", ""
+	},
+	{
+		0x2e, "Precedence call blocked", ""
+	},
+	{
+		0x2f, "Resource unavailable, unspecified", ""
+	},
+	{
+		0x31, "Quality of service unavailable", ""
+	},
+	{
+		0x32, "Requested facility not subscribed", ""
+	},
+	{
+		0x35, "Outgoing calls barred within CUG", ""
+	},
+	{
+		0x37, "Incoming calls barred within CUG", ""
+	},
+	{
+		0x39, "Bearer capability not authorized", ""
+	},
+	{
+		0x3a, "Bearer capability not presently available", ""
+	},
+	{
+		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
+	},
+	{
+		0x3f, "Service or option not available, unspecified", ""
+	},
+	{
+		0x41, "Bearer capability not implemented", ""
+	},
+	{
+		0x42, "Channel type not implemented", ""
+	},
+	{
+		0x43, "Requested facility not implemented", ""
+	},
+	{
+		0x44, "Only restricted digital information bearer capability is available", ""
+	},
+	{
+		0x4f, "Service or option not implemented", ""
+	},
+	{
+		0x51, "Invalid call reference value", ""
+	},
+	{
+		0x52, "Identified channel does not exist", ""
+	},
+	{
+		0x53, "A suspended call exists, but this call identity does not", ""
+	},
+	{
+		0x54, "Call identity in use", ""
+	},
+	{
+		0x55, "No call suspended", ""
+	},
+	{
+		0x56, "Call having the requested call identity has been cleared", ""
+	},
+	{
+		0x57, "User not member of CUG", ""
+	},
+	{
+		0x58, "Incompatible destination", ""
+	},
+	{
+		0x5a, "Non-existent CUG", ""
+	},
+	{
+		0x5b, "Invalid transit network selection", ""
+	},
+	{
+		0x5f, "Invalid message, unspecified", ""
+	},
+	{
+		0x60, "Mandatory information element is missing", ""
+	},
+	{
+		0x61, "Message type non-existent or not implemented", ""
+	},
+	{
+		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
+	},
+	{
+		0x63, "Information element/parameter non-existent or not implemented", ""
+	},
+	{
+		0x64, "Invalid information element contents", ""
+	},
+	{
+		0x65, "Message not compatible with call state", ""
+	},
+	{
+		0x66, "Recovery on timer expiry", ""
+	},
+	{
+		0x67, "Parameter non-existent or not implemented - passed on", ""
+	},
+	{
+		0x6e, "Message with unrecognized parameter discarded", ""
+	},
+	{
+		0x6f, "Protocol error, unspecified", ""
+	},
+	{
+		0x7f, "Interworking, unspecified", ""
+	},
+};
+
+#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
+
+static
+int
+prcause(char *dest, byte * p)
+{
+	byte           *end;
+	char           *dp = dest;
+	int             i, cause;
+
+	end = p + p[1] + 1;
+	p += 2;
+	dp += sprintf(dp, "    coding ");
+	dp += prbits(dp, *p, 7, 2);
+	dp += sprintf(dp, " location ");
+	dp += prbits(dp, *p, 4, 4);
+	*dp++ = '\n';
+	p = skipext(p);
+
+	cause = 0x7f & *p++;
+
+	/* locate cause value */
+	for (i = 0; i < CVSIZE; i++)
+		if (cvlist[i].nr == cause)
+			break;
+
+	/* display cause value if it exists */
+	if (i == CVSIZE)
+		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+	else
+		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
+
+	while (!0) {
+		if (p > end)
+			break;
+		dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
+		dp += sprintf(dp, " rej %d ", *p & 0x7f);
+		if (*p & 0x80) {
+			*dp++ = '\n';
+			break;
+		} else
+			dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
+	}
+	return (dp - dest);
+
+}
+
+static
+struct MessageType cause_1tr6[] =
+{
+	{CAUSE_InvCRef, "Invalid Call Reference"},
+	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
+	{CAUSE_CIDunknown, "Caller Identity unknown"},
+	{CAUSE_CIDinUse, "Caller Identity in Use"},
+	{CAUSE_NoChans, "No Channels available"},
+	{CAUSE_FacNotImpl, "Facility Not Implemented"},
+	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
+	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
+	{CAUSE_UserAccessBusy, "User Access Busy"},
+	{CAUSE_NegativeGBG, "Negative GBG"},
+	{CAUSE_UnknownGBG, "Unknown  GBG"},
+	{CAUSE_NoSPVknown, "No SPV known"},
+	{CAUSE_DestNotObtain, "Destination not obtainable"},
+	{CAUSE_NumberChanged, "Number changed"},
+	{CAUSE_OutOfOrder, "Out Of Order"},
+	{CAUSE_NoUserResponse, "No User Response"},
+	{CAUSE_UserBusy, "User Busy"},
+	{CAUSE_IncomingBarred, "Incoming Barred"},
+	{CAUSE_CallRejected, "Call Rejected"},
+	{CAUSE_NetworkCongestion, "Network Congestion"},
+	{CAUSE_RemoteUser, "Remote User initiated"},
+	{CAUSE_LocalProcErr, "Local Procedure Error"},
+	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
+	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
+	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
+	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
+};
+
+int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+
+static int
+prcause_1tr6(char *dest, byte * p) 
+{
+	char           *dp = dest;
+	int i, cause;
+
+	p++;
+	if (0 == *p) {
+		dp += sprintf(dp, "   OK (cause length=0)\n");
+		return (dp - dest);
+	} else if (*p > 1) {
+		dp += sprintf(dp, "    coding ");
+		dp += prbits(dp, p[2], 7, 2);
+		dp += sprintf(dp, " location ");
+		dp += prbits(dp, p[2], 4, 4);
+		*dp++ = '\n';
+	}
+	p++;
+	cause = 0x7f & *p;
+
+	/* locate cause value */
+	for (i = 0; i < cause_1tr6_len; i++)
+		if (cause_1tr6[i].nr == cause)
+			break;
+
+	/* display cause value if it exists */
+	if (i == cause_1tr6_len)
+		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+	else
+		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
+
+	return (dp - dest);
+
+}
+
+static int
+prchident(char *dest, byte * p) {
+	char *dp = dest;
+
+	p += 2;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+static int
+prcalled(char *dest, byte * p) {
+	int             l;
+	char           *dp = dest;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p++, 8, 8);
+	*dp++ = '\n';
+	dp += sprintf(dp, "    number digits ");
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+prcalling(char *dest, byte * p) {
+	int             l;
+	char           *dp = dest;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	if (!(*p & 0x80)) {
+		dp += sprintf(dp, "    octet 3a ");
+		dp += prbits(dp, *++p, 8, 8);
+		*dp++ = '\n';
+		l--;
+	};
+	p++;
+
+	dp += sprintf(dp, "    number digits ");
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+static
+int
+prbearer(char *dest, byte * p)
+{
+	char           *dp = dest, ch;
+
+	p += 2;
+	dp += sprintf(dp, "    octet 3  ");
+	dp += prbits(dp, *p++, 8, 8);
+	*dp++ = '\n';
+	dp += sprintf(dp, "    octet 4  ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	if ((*p++ & 0x1f) == 0x18) {
+		dp += sprintf(dp, "    octet 4.1 ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	/* check for user information layer 1 */
+	if ((*p & 0x60) == 0x20) {
+		ch = ' ';
+		do {
+			dp += sprintf(dp, "    octet 5%c ", ch);
+			dp += prbits(dp, *p, 8, 8);
+			*dp++ = '\n';
+			if (ch == ' ')
+				ch = 'a';
+			else
+				ch++;
+		}
+		while (!(*p++ & 0x80));
+	}
+	/* check for user information layer 2 */
+	if ((*p & 0x60) == 0x40) {
+		dp += sprintf(dp, "    octet 6  ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	/* check for user information layer 3 */
+	if ((*p & 0x60) == 0x60) {
+		dp += sprintf(dp, "    octet 7  ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	return (dp - dest);
+}
+
+static int
+general(char *dest, byte * p) {
+	char           *dp = dest;
+	char            ch = ' ';
+	int             l, octet = 3;
+
+	p++;
+	l = *p++;
+	/* Iterate over all octets in the information element */
+	while (l--) {
+		dp += sprintf(dp, "    octet %d%c ", octet, ch);
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+
+		/* last octet in group? */
+		if (*p & 0x80) {
+			octet++;
+			ch = ' ';
+		} else if (ch == ' ')
+			ch = 'a';
+		else
+			ch++;
+	}
+	return (dp - dest);
+}
+
+static int
+prcharge(char *dest, byte * p) {
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    GEA ");
+	dp += prbits(dp, *p++, 8, 8);
+	dp += sprintf(dp, "  Anzahl: ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+} 
+static int
+prtext(char *dest, byte * p) {
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++;
+	dp += sprintf(dp, "    ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+display(char *dest, byte * p) {
+	char           *dp = dest;
+	char            ch = ' ';
+	int             l, octet = 3;
+
+	p++;
+	l = *p++;
+	/* Iterate over all octets in the * display-information element */
+	dp += sprintf(dp, "   \"");
+	while (l--) {
+		dp += sprintf(dp, "%c", *p++);
+
+		/* last octet in group? */
+		if (*p & 0x80) {
+			octet++;
+			ch = ' ';
+		} else if (ch == ' ')
+			ch = 'a';
+
+		else
+			ch++;
+	}
+	*dp++ = '\"';
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+int
+prfacility(char *dest, byte * p)
+{
+	char           *dp = dest;
+	int             l, l2;
+
+	p++;
+	l = *p++;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p++, 8, 8);
+	dp += sprintf(dp, "\n");
+	l -= 1;
+
+	while (l > 0) {
+		dp += sprintf(dp, "   octet 4 ");
+		dp += prbits(dp, *p++, 8, 8);
+		dp += sprintf(dp, "\n");
+		dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
+		l -= 2;
+		dp += sprintf(dp, "   contents ");
+		while (l2--) {
+			dp += sprintf(dp, "%2x ", *p++);
+			l--;
+		}
+		dp += sprintf(dp, "\n");
+	}
+
+	return (dp - dest);
+}
+
+static
+struct InformationElement {
+	byte            nr;
+	char           *descr;
+	int             (*f) (char *, byte *);
+} ielist[] = {
+
+	{
+		0x00, "Segmented message", general
+	},
+	{
+		0x04, "Bearer capability", prbearer
+	},
+	{
+		0x08, "Cause", prcause
+	},
+	{
+		0x10, "Call identity", general
+	},
+	{
+		0x14, "Call state", general
+	},
+	{
+		0x18, "Channel identification", prchident
+	},
+	{
+		0x1c, "Facility", prfacility
+	},
+	{
+		0x1e, "Progress indicator", general
+	},
+	{
+		0x20, "Network-specific facilities", general
+	},
+	{
+		0x27, "Notification indicator", general
+	},
+	{
+		0x28, "Display", display
+	},
+	{
+		0x29, "Date/Time", general
+	},
+	{
+		0x2c, "Keypad facility", general
+	},
+	{
+		0x34, "Signal", general
+	},
+	{
+		0x40, "Information rate", general
+	},
+	{
+		0x42, "End-to-end delay", general
+	},
+	{
+		0x43, "Transit delay selection and indication", general
+	},
+	{
+		0x44, "Packet layer binary parameters", general
+	},
+	{
+		0x45, "Packet layer window size", general
+	},
+	{
+		0x46, "Packet size", general
+	},
+	{
+		0x47, "Closed user group", general
+	},
+	{
+		0x4a, "Reverse charge indication", general
+	},
+	{
+		0x6c, "Calling party number", prcalling
+	},
+	{
+		0x6d, "Calling party subaddress", general
+	},
+	{
+		0x70, "Called party number", prcalled
+	},
+	{
+		0x71, "Called party subaddress", general
+	},
+	{
+		0x74, "Redirecting number", general
+	},
+	{
+		0x78, "Transit network selection", general
+	},
+	{
+		0x79, "Restart indicator", general
+	},
+	{
+		0x7c, "Low layer compatibility", general
+	},
+	{
+		0x7d, "High layer compatibility", general
+	},
+	{
+		0x7e, "User-user", general
+	},
+	{
+		0x7f, "Escape for extension", general
+	},
+};
+
+
+#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+
+static struct InformationElement we_0[] =
+{
+	{WE0_cause, "Cause", prcause_1tr6},
+	{WE0_connAddr, "Connecting Address", prcalled},
+	{WE0_callID, "Call IDentity", general},
+	{WE0_chanID, "Channel IDentity", general},
+	{WE0_netSpecFac, "Network Specific Facility", general},
+	{WE0_display, "Display", general},
+	{WE0_keypad, "Keypad", general},
+	{WE0_origAddr, "Origination Address", prcalled},
+	{WE0_destAddr, "Destination Address", prcalled},
+	{WE0_userInfo, "User Info", general}
+};
+
+static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
+
+static struct InformationElement we_6[] =
+{
+	{WE6_serviceInd, "Service Indicator", general},
+	{WE6_chargingInfo, "Charging Information", prcharge},
+	{WE6_date, "Date", prtext},
+	{WE6_facSelect, "Facility Select", general},
+	{WE6_facStatus, "Facility Status", general},
+	{WE6_statusCalled, "Status Called", general},
+	{WE6_addTransAttr, "Additional Transmission Attributes", general}
+};
+static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
+
+int QuickHex(char *txt, byte *p, int cnt) 
+{
+	register int  i;
+	register char *t=txt;
+	register byte w;
+
+	for (i=0;i<cnt;i++) {
+		*t++ = ' ';
+		w = (p[i]>>4)&0x0f;
+		if (w<10) *t++ = '0'+w;
+		else *t++ = 'A'-10 +w;
+		w = p[i]&0x0f;
+		if (w<10) *t++ = '0'+w;
+		else *t++ = 'A'-10 +w;
+	}
+	*t++=0;
+	return(t - txt);
+}
+
+void
+LogFrame(struct IsdnCardState *sp, byte * buf, int size) {
+	char           *dp;
+
+	if (size<1) return;
+	dp = sp-> dlogspace;
+	if (size<4096/3 -10) {
+		dp += sprintf(dp, "HEX:");
+		dp += QuickHex(dp, buf, size);
+		dp--;
+		*dp++ = '\n';
+		*dp=0;
+	} else 
+		sprintf(dp, "LogFrame: warning Frame too big (%d)\n",
+			size);
+	HiSax_putstatus(sp->dlogspace);
+}
+
+void
+dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
+	byte           *bend = buf + size;
+	char           *dp;
+	int i, cs = 0, cs_old = 0, cs_fest = 0;
+
+	if (size<1) return;
+	/* display header */
+	dp = sp->dlogspace;
+	dp += sprintf(dp, "%s\n", comment);
+
+	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
+		/* locate message type */
+		if (buf[0] == PROTO_DIS_N0) {	/* N0 */
+			for (i = 0; i < mt_n0_len; i++)
+				if (mt_n0[i].nr == buf[3])
+					break;
+			/* display message type iff it exists */
+			if (i == mt_n0_len)
+				dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
+			else
+				dp += sprintf(dp, "call reference %d size %d message type %s\n",
+					      buf[2], size, mt_n0[i].descr);
+		} else {	/* N1 */
+			for (i = 0; i < mt_n1_len; i++)
+				if (mt_n1[i].nr == buf[3])
+					break;
+			/* display message type iff it exists */
+			if (i == mt_n1_len)
+				dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
+			else
+				dp += sprintf(dp, "call reference %d size %d message type %s\n",
+					      buf[2], size, mt_n1[i].descr);
+		}
+
+		/* display each information element */
+		buf += 4;
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+				  case 1:
+					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+					cs_old = cs;
+					cs = *buf & 7;
+					cs_fest = *buf & 8;
+					break;
+				  case 3:
+					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+					break;
+				  case 2:
+					if (*buf == 0xa0) {
+						dp += sprintf(dp, "  More data\n");
+						break;
+					}
+					if (*buf == 0xa1) {
+						dp += sprintf(dp, "  Sending complete\n");
+					}
+					break;
+				  /* fall through */
+				  default:
+					dp += sprintf(dp, "  Reserved %x\n", *buf);
+					break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			if (cs == 0) {
+				for (i = 0; i < we_0_len; i++)
+					if (*buf == we_0[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_0_len) {
+					dp += sprintf(dp, "  %s\n", we_0[i].descr);
+					dp += we_0[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else if (cs == 6) {
+				for (i = 0; i < we_6_len; i++)
+					if (*buf == we_6[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_6_len) {
+					dp += sprintf(dp, "  %s\n", we_6[i].descr);
+					dp += we_6[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else
+				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			/* Skip to next element */
+			if (cs_fest == 8) {
+				cs = cs_old;
+				cs_old = 0;
+				cs_fest = 0;
+			}
+			buf += buf[1] + 2;
+		}
+	} else if (buf[0] == 8) {	/* EURO */
+		/* locate message type */
+		for (i = 0; i < MTSIZE; i++)
+			if (mtlist[i].nr == buf[3])
+				break;
+
+		/* display message type iff it exists */
+		if (i == MTSIZE)
+			dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
+		else
+			dp += sprintf(dp, "call reference %d size %d message type %s\n",
+		buf[2], size, mtlist[i].descr);
+
+		/* display each information element */
+		buf += 4;
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+				  case 1:
+					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+					break;
+				  case 3:
+					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+					break;
+				  case 5:
+					dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
+					break;
+				  case 2:
+					if (*buf == 0xa0) {
+						dp += sprintf(dp, "  More data\n");
+						break;
+					}
+					if (*buf == 0xa1) {
+						dp += sprintf(dp, "  Sending complete\n");
+					}
+					break;
+				  /* fall through */
+				  default:
+					dp += sprintf(dp, "  Reserved %x\n", *buf);
+					break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			for (i = 0; i < IESIZE; i++)
+				if (*buf == ielist[i].nr)
+					break;
+
+			/* When not found, give appropriate msg */
+			if (i != IESIZE) {
+				dp += sprintf(dp, "  %s\n", ielist[i].descr);
+				dp += ielist[i].f(dp, buf);
+			} else
+				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+
+			/* Skip to next element */
+			buf += buf[1] + 2;
+		}
+	} else {
+		dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
+	}
+	dp += sprintf(dp, "\n");
+	HiSax_putstatus(sp->dlogspace);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/siemens.h linux/drivers/isdn/hisax/siemens.h
--- linux-2.0.26.org/drivers/isdn/hisax/siemens.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/siemens.h	Mon Dec  9 00:09:29 1996
@@ -0,0 +1,68 @@
+/* $Id: siemens.h,v 1.3 1996/12/08 19:48:34 keil Exp $
+ *
+ * siemens.h   ISAC and HSCX spezific Macros
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * 
+ * $Log: siemens.h,v $
+ * Revision 1.3  1996/12/08 19:48:34  keil
+ * adding Monitor channel registers
+ *
+ * Revision 1.2  1996/10/27 22:24:00  keil
+ * HSCX version code removed
+ *
+ * Revision 1.1  1996/10/12 21:39:39  keil
+ * Initial revision
+ *
+ *
+*/
+
+
+/* All Registers without FIFOs (original Siemens Spec - 20 hex) */
+
+#define ISAC_MASK 0x0
+#define ISAC_ISTA 0x0
+#define ISAC_STAR 0x1
+#define ISAC_CMDR 0x1
+#define ISAC_EXIR 0x4
+#define ISAC_RBCH 0xa
+#define ISAC_ADF2 0x19
+#define ISAC_SPCR 0x10
+#define ISAC_ADF1 0x18
+#define ISAC_CIR0 0x11
+#define ISAC_CIX0 0x11
+#define ISAC_STCR 0x17
+#define ISAC_MODE 0x2
+#define ISAC_RSTA 0x7
+#define ISAC_RBCL 0x5
+#define ISAC_TIMR 0x3
+#define ISAC_SQXR 0x1b
+#define ISAC_MOSR 0x1a
+#define ISAC_MOCR 0x1a
+#define ISAC_MOR0 0x12
+#define ISAC_MOX0 0x12
+#define ISAC_MOR1 0x14
+#define ISAC_MOX1 0x14
+
+#define HSCX_ISTA 0x0
+#define HSCX_CCR1 0xf
+#define HSCX_CCR2 0xc
+#define HSCX_TSAR 0x11
+#define HSCX_TSAX 0x10
+#define HSCX_XCCR 0x12
+#define HSCX_RCCR 0x13
+#define HSCX_MODE 0x2
+#define HSCX_CMDR 0x1
+#define HSCX_EXIR 0x4
+#define HSCX_XAD1 0x4
+#define HSCX_XAD2 0x5
+#define HSCX_RAH2 0x7
+#define HSCX_RSTA 0x7
+#define HSCX_TIMR 0x3
+#define HSCX_STAR 0x1
+#define HSCX_RBCL 0x5
+#define HSCX_XBCH 0xd
+#define HSCX_VSTR 0xe
+#define HSCX_RLCR 0xe
+#define HSCX_MASK 0x0
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- linux-2.0.26.org/drivers/isdn/hisax/tei.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/tei.c	Mon Dec  9 00:11:21 1996
@@ -0,0 +1,258 @@
+/* $Id: tei.c,v 1.2 1996/12/08 19:52:39 keil Exp $
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: tei.c,v $
+ * Revision 1.2  1996/12/08 19:52:39  keil
+ * minor debug fix
+ *
+ * Revision 1.1  1996/10/13 20:04:57  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+extern struct IsdnCard cards[];
+extern int      nrcards;
+
+static struct PStack *
+findces(struct PStack *st, int ces)
+{
+	struct PStack  *ptr = *(st->l1.stlistp);
+
+	while (ptr)
+		if (ptr->l2.ces == ces)
+			return (ptr);
+		else
+			ptr = ptr->next;
+	return (NULL);
+}
+
+static struct PStack *
+findtei(struct PStack *st, int tei)
+{
+	struct PStack  *ptr = *(st->l1.stlistp);
+
+	if (tei == 127)
+		return (NULL);
+
+	while (ptr)
+		if (ptr->l2.tei == tei)
+			return (ptr);
+		else
+			ptr = ptr->next;
+	return (NULL);
+}
+
+void 
+tei_handler(struct PStack *st,
+	    byte pr, struct BufHeader *ibh)
+{
+	byte           *bp;
+	unsigned int    tces;
+	struct PStack  *otsp, *ptr;
+	unsigned int    data;
+
+	if (st->l2.debug)
+		printk(KERN_DEBUG "teihandler %d\n", pr);
+
+	switch (pr) {
+	  case (MDL_ASSIGN):
+		  data = (unsigned int) ibh;
+		  BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
+		  if (!ibh)
+			  return;
+		  bp = DATAPTR(ibh);
+		  bp += st->l2.uihsize;
+		  bp[0] = 0xf;
+		  bp[1] = data >> 8;
+		  bp[2] = data & 0xff;
+		  bp[3] = 0x1;
+		  bp[4] = 0xff;
+		  ibh->datasize = 8;
+		  st->l3.l3l2(st, DL_UNIT_DATA, ibh);
+		  break;
+	  case (DL_UNIT_DATA):
+		  bp = DATAPTR(ibh);
+		  bp += 3;
+		  if (bp[0] != 0xf)
+			  break;
+		  switch (bp[3]) {
+		    case (2):
+			    tces = (bp[1] << 8) | bp[2];
+			    BufPoolRelease(ibh);
+			    if (st->l3.debug)
+				    printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
+					   bp[4] >> 1);
+			    if ((otsp = findces(st, tces)))
+				    otsp->ma.teil2(otsp, MDL_ASSIGN,
+						   (void *)(bp[4] >> 1));
+			    break;
+		    case (4):
+			    if (st->l3.debug)
+				    printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
+			    if (bp[4] >> 1 == 0x7f) {
+				    BufPoolRelease(ibh);
+				    ptr = *(st->l1.stlistp);
+				    while (ptr) {
+					    if ((ptr->l2.tei & 0x7f) != 0x7f) {
+						    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
+							    break;
+						    bp = DATAPTR(ibh);
+						    bp += 3;
+						    bp[0] = 0xf;
+						    bp[1] = ptr->l2.ces >> 8;
+						    bp[2] = ptr->l2.ces & 0xff;
+						    bp[3] = 0x5;
+						    bp[4] = (ptr->l2.tei << 1) | 1;
+						    ibh->datasize = 8;
+						    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
+					    }
+					    ptr = ptr->next;
+				    }
+			    } else {
+				    otsp = findtei(st, bp[4] >> 1);
+				    BufPoolRelease(ibh);
+				    if (!otsp)
+					    break;
+				    if (st->l3.debug)
+					    printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
+				    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
+					    break;
+				    bp = DATAPTR(ibh);
+				    bp += 3;
+				    bp[0] = 0xf;
+				    bp[1] = otsp->l2.ces >> 8;
+				    bp[2] = otsp->l2.ces & 0xff;
+				    bp[3] = 0x5;
+				    bp[4] = (otsp->l2.tei << 1) | 1;
+				    ibh->datasize = 8;
+				    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
+			    }
+			    break;
+		    default:
+			    BufPoolRelease(ibh);
+			    if (st->l3.debug)
+				    printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
+		  }
+		  break;
+	  default:
+		  printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
+		  break;
+	}
+}
+
+unsigned int 
+randomces(void)
+{
+	int             x = jiffies & 0xffff;
+
+	return (x);
+}
+
+static void 
+tei_man(struct PStack *sp, int i, void *v)
+{
+	printk(KERN_DEBUG "tei_man\n");
+}
+
+static void 
+tei_l2tei(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *sp = st->l1.hardware;
+
+	tei_handler(sp->teistack, pr, arg);
+}
+
+void 
+setstack_tei(struct PStack *st)
+{
+	st->l2.l2tei = tei_l2tei;
+}
+
+static void 
+init_tei(struct IsdnCardState *sp, int protocol)
+{
+	struct PStack  *st;
+	char            tmp[128];
+
+#define DIRTY_HACK_AGAINST_SIGSEGV
+
+	st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
+				       "struct PStack");
+
+#ifdef DIRTY_HACK_AGAINST_SIGSEGV
+	sp->teistack = st;	                /* struct is not initialized yet */
+	sp->teistack->protocol = protocol;	/* struct is not initialized yet */
+#endif	                                        /* DIRTY_HACK_AGAINST_SIGSEGV    */
+
+
+	setstack_HiSax(st, sp);
+
+	st->l2.extended = !0;
+	st->l2.laptype = LAPD;
+	st->l2.window = 1;
+	st->l2.orig = !0;
+	st->protocol = protocol;
+
+/*
+ * the following is not necessary for tei mng. (broadcast only)
+ */
+
+	st->l2.t200 = 500;	/* 500 milliseconds */
+	st->l2.n200 = 4;	/* try 4 times */
+
+	st->l2.sap = 63;
+	st->l2.tei = 127;
+
+	sprintf(tmp, "Card %d tei ", sp->cardnr+1);
+	setstack_isdnl2(st, tmp);
+	st->l2.debug = 0;
+	st->l3.debug = 0;
+
+	st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+
+	st->l2.l2l3 = (void *) tei_handler;
+	st->l1.l1man = tei_man;
+	st->l2.l2man = tei_man;
+	st->l4.l2writewakeup = NULL;
+	
+	HiSax_addlist(sp, st);
+	sp->teistack = st;
+}
+
+static void 
+release_tei(struct IsdnCardState *sp)
+{
+	struct PStack  *st = sp->teistack;
+
+	HiSax_rmlist(sp, st);
+	Sfree((void *) st);
+}
+
+void 
+TeiNew(void)
+{
+	int             i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp)
+			init_tei(cards[i].sp, cards[i].protocol);
+}
+
+void 
+TeiFree(void)
+{
+	int             i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp)
+			release_tei(cards[i].sp);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- linux-2.0.26.org/drivers/isdn/hisax/teles0.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/teles0.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,990 @@
+/* $Id: teles0.c,v 1.4 1996/11/05 19:41:27 keil Exp $
+ *
+ * teles0.c     low level stuff for Teles Memory IO isdn cards
+ *              based on the teles driver from Jan den Ouden
+ * 
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to	Jan den Ouden
+ *	        Fritz Elfert	
+ * 	        Beat Doebeli
+ * 
+ * $Log: teles0.c,v $
+ * Revision 1.4  1996/11/05 19:41:27  keil
+ * more changes for 2.1
+ *
+ * Revision 1.3  1996/10/30 10:22:58  keil
+ * Changes for 2.1 kernels
+ *
+ * Revision 1.2  1996/10/27 22:08:34  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:58  keil
+ * Initial revision
+ *
+ *
+ *
+*/
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles0.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const   char    *CardType[];
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline byte
+readisac(unsigned int adr, byte off)
+{
+	return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writeisac(unsigned int adr, byte off, byte data)
+{
+	writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+
+static inline byte
+readhscx(unsigned int adr, int hscx, byte off)
+{
+	return readb(adr +(hscx? 0x1e0: 0x1a0) +
+		((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writehscx(unsigned int adr, int hscx, byte off, byte data)
+{
+	writeb(data, adr +(hscx ? 0x1e0: 0x1a0) +
+		((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, byte * data, int size)
+{
+	register int  i;
+	register byte *ad = (byte *) (adr + 0x100);
+	for (i=0;i<size;i++)
+	    data[i] = readb(ad);
+}
+        
+static void
+write_fifo_isac(unsigned int adr, byte * data, int size)
+{
+	register int  i;
+	register byte *ad = (byte *) (adr + 0x100);
+	for (i=0;i<size;i++)
+		writeb(data[i], ad);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
+{
+	register int  i;
+	register byte *ad = (byte *) (adr +(hscx ? 0x1c0: 0x180));
+	for (i=0;i<size;i++)
+	    data[i] =  readb(ad);
+}
+        
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
+{
+	int  i;
+	register byte *ad = (byte *) (adr +(hscx ? 0x1c0: 0x180));
+	for (i=0;i<size;i++)
+		writeb(data[i], ad);
+}
+static inline void
+waitforCEC(int adr, int hscx)
+{
+	int            to = 50;
+
+	while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
+}
+
+    
+static inline void
+waitforXFW(int adr, int hscx)
+{
+	int            to = 50;
+
+	while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, byte data)
+{
+	long            flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr, hscx);
+	writehscx(adr, hscx, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+        printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR));
+}
+
+void
+teles0_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	byte			*ptr;
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh = hsp->rcvibh;
+	long 			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
+					      HSCX_RBUF_BPPS)) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->rcvptr;
+
+	hsp->rcvptr += count;
+	save_flags(flags);
+	cli();
+        read_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+        writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_empty_fifo %c cnt %d",
+			hsp->hscx?'B':'A',count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh;
+	int			more, count;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	ibh = hsp->xmtibh;
+	if (!ibh)
+                return;
+
+	count = ibh->datasize - hsp->sendptr;
+	if (count <= 0)
+                return;
+
+	more = (hsp->mode == 1)?1:0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->sendptr;
+	hsp->sendptr += count;
+
+        waitforXFW(sp->membase, hsp->hscx);
+	save_flags(flags);
+	cli();
+        write_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+        writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_fill_fifo %c cnt %d",
+			hsp->hscx?'B':'A', count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
+{
+	byte             r;
+	struct HscxState *hsp = sp->hs + hscx;
+	int              count, err;
+	char		 tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode) 
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			if (hsp->rcvibh)
+				BufPoolRelease(hsp->rcvibh);
+			hsp->rcvibh = NULL;
+			writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+			goto afterRME;
+		}
+		if (!hsp->rcvibh)
+			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+                                       GFP_ATOMIC, (void *) 1, 1)) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RME out of buffers");
+				writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+				goto afterRME;
+			} else
+				hsp->rcvptr = 0;
+
+		count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		hscx_empty_fifo(hsp, count);
+		hsp->rcvibh->datasize = hsp->rcvptr - 1;
+		BufQueueLink(&hsp->rq, hsp->rcvibh);
+		hsp->rcvibh = NULL;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+      afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!hsp->rcvibh) {
+			if (hsp->mode == 1)
+				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
+					GFP_ATOMIC, (void *)1, 2);
+			else
+				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+					GFP_ATOMIC, (void *)1, 2);
+			
+			if (err) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RPF out of buffers");
+				writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+				goto afterRPF;
+			} else
+				hsp->rcvptr = 0;
+		}
+		
+		hscx_empty_fifo(hsp, 32);
+                if (hsp->mode == 1) {
+                        /* receive audio data */
+                        hsp->rcvibh->datasize = hsp->rcvptr;
+                        BufQueueLink(&hsp->rq, hsp->rcvibh);
+                        hsp->rcvibh = NULL;
+                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+                }
+                
+	}
+      afterRPF:
+	if (val & 0x10) {	/* XPR */
+		if (hsp->xmtibh)
+			if (hsp->xmtibh->datasize > hsp->sendptr) {
+				hscx_fill_fifo(hsp);
+				goto afterXPR;
+			} else {
+				if (hsp->releasebuf)
+					BufPoolRelease(hsp->xmtibh);
+				hsp->sendptr = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->xmtibh = NULL;
+			}
+		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
+			hsp->releasebuf = !0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+      afterXPR:
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	byte			*ptr;
+	struct BufHeader	*ibh = sp->rcvibh;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_empty_fifo"); 
+
+	if (sp->rcvptr >= 3072) {
+		if (sp->debug & L1_DEB_WARN) {
+			char		 tmp[40];
+			sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
+        		debugl1(sp, tmp); 
+		}
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->rcvptr;
+	sp->rcvptr += count;
+
+	save_flags(flags);
+	cli();
+        read_fifo_isac(sp->membase, ptr, count);
+        writeisac(sp->membase, ISAC_CMDR, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_empty_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	struct BufHeader	*ibh;
+	int			count, more;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_fill_fifo"); 
+
+	ibh = sp->xmtibh;
+	if (!ibh)
+		return;
+
+	count = ibh->datasize - sp->sendptr;
+	if (count <= 0)
+		return;
+	if (count >= 3072)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->sendptr;
+	sp->sendptr += count;
+
+	save_flags(flags);
+	cli();
+	write_fifo_isac(sp->membase, ptr, count);
+        writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_fill_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char	tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+        	debugl1(sp, tmp);
+        } 
+	writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, byte val) {
+	byte		exval;
+	unsigned int    count;
+	char		tmp[32];    
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+        	debugl1(sp, tmp); 
+        }
+	if (val & 0x80) {	/* RME */
+		exval = readisac(sp->membase, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC CRC error");
+			if (sp->rcvibh)
+				BufPoolRelease(sp->rcvibh);
+			sp->rcvibh = NULL;
+			writeisac(sp->membase, ISAC_CMDR, 0x80);
+			goto afterRME;
+		}
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC,(void *) 1, 3)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writeisac(sp->membase, ISAC_CMDR, 0x80);
+				goto afterRME;
+			} else
+				sp->rcvptr = 0;
+		count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(sp, count);
+		sp->rcvibh->datasize = sp->rcvptr;
+		BufQueueLink(&(sp->rq), sp->rcvibh);
+		sp->rcvibh = NULL;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC, (void *) 1, 4)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writeisac(sp->membase, ISAC_CMDR, 0x80);
+				goto afterRPF;
+			} else
+				sp->rcvptr = 0;
+		isac_empty_fifo(sp, 32);
+	}
+	afterRPF:
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->xmtibh)
+			if (sp->xmtibh->datasize > sp->sendptr) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				if (sp->releasebuf)
+					BufPoolRelease(sp->xmtibh);
+				sp->xmtibh = NULL;
+				sp->sendptr = 0;
+			}
+		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
+			sp->releasebuf = !0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+	afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2) 
+				& 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+        		sprintf(tmp, "l1state %d", sp->ph_state);
+        		debugl1(sp, tmp);
+        	}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readisac(sp->membase, ISAC_EXIR); 
+		if (sp->debug & L1_DEB_WARN) {
+        		sprintf(tmp, "ISAC EXIR %02x", exval);
+        		debugl1(sp, tmp);
+        	}
+
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, byte val) {
+
+	byte    		exval;
+	struct HscxState	*hsp;
+	char			tmp[32];
+	
+		
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+        	exval = readhscx(sp->membase, 1, HSCX_EXIR);
+	        if (exval == 0x40) {
+                	if (hsp->mode == 1)
+        	        	hscx_fill_fifo(hsp);
+	                else {
+                        	/* Here we lost an TX interrupt, so
+                        	* restart transmitting the whole frame.
+                	        */
+        	                hsp->sendptr = 0;
+				writehscxCMDR(sp->membase, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+                        }
+                } else
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX B EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+        		debugl1(sp, tmp); 
+        	}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+                exval = readhscx(sp->membase, 0, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+	                	/* Here we lost an TX interrupt, so
+        	        	* restart transmitting the whole frame.
+                		*/
+                		hsp->sendptr = 0;
+				writehscxCMDR(sp->membase, hsp->hscx,0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+        		}
+		} else 
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX A EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+        if (val & 0x04) {
+                exval = readhscx(sp->membase, 0, HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+        		debugl1(sp, tmp); 
+        	}
+        	hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	byte                 val, stat=0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	
+	if (!sp) {
+		printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
+		return;
+	}
+	
+	val = readhscx(sp->membase, 1, HSCX_ISTA);
+	Start_HSCX:
+	if (val) {
+		hscx_int_main(sp,val);
+		stat |= 1;
+	}
+	val = readisac(sp->membase, ISAC_ISTA);
+	Start_ISAC:
+	if (val) { 
+		isac_interrupt(sp,val);
+		stat |= 2;
+	}
+
+	val = readhscx(sp->membase, 1, HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX) 
+        		debugl1(sp, "HSCX IntStat after IntRoutine"); 
+		goto Start_HSCX;
+	}
+	val = readisac(sp->membase, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC) 
+        		debugl1(sp, "ISAC IntStat after IntRoutine"); 
+		goto Start_ISAC;
+	}
+	if (stat & 1) {
+		writehscx(sp->membase, 0, HSCX_MASK, 0xFF);
+		writehscx(sp->membase, 1, HSCX_MASK, 0xFF);
+		writehscx(sp->membase, 0, HSCX_MASK, 0x0);
+		writehscx(sp->membase, 1, HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writeisac(sp->membase, ISAC_MASK, 0xFF);
+		writeisac(sp->membase, ISAC_MASK, 0x0);
+	}
+
+}
+
+
+static void
+initisac(struct IsdnCardState    *sp)
+{
+	unsigned int	adr=sp->membase;
+	
+	/* 16.0 IOM 1 Mode */
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_ADF2, 0x0);
+	writeisac(adr, ISAC_SPCR, 0xa);
+	writeisac(adr, ISAC_ADF1, 0x2);
+	writeisac(adr, ISAC_STCR, 0x70);
+	writeisac(adr, ISAC_MODE, 0xc9);
+	writeisac(adr, ISAC_CMDR, 0x41);
+	writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int             hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char  tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+	        	'A'+hscx, mode, ichan);
+        	debugl1(sp, tmp);
+        } 
+        hs->mode = mode;
+        writehscx(sp->membase, hscx, HSCX_CCR1, 0x85);
+        writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF);
+        writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF);
+        writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF);
+        writehscx(sp->membase, hscx, HSCX_XBCH, 0x0);
+
+        /* Switch IOM 1 SSI */
+	if (hscx == 0)
+		ichan = 1 - ichan;
+
+        switch (mode) {
+	case (0):
+        	writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+		writehscx(sp->membase, hscx, HSCX_TSAX, 0xff);
+		writehscx(sp->membase, hscx, HSCX_TSAR, 0xff);
+		writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+		writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+		writehscx(sp->membase, hscx, HSCX_MODE, 0x84);
+        	break;
+	case (1):
+                if (ichan == 0) {
+                	writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+			writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+			writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+			writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+                } else {
+			writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+			writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+			writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+			writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+                }
+		writehscx(sp->membase, hscx, HSCX_MODE, 0xe4);
+		writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+        	break;
+	case (2):
+                if (ichan == 0) {
+			writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+			writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+			writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+			writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+                } else {
+			writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+			writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+			writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+			writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+                }
+		writehscx(sp->membase, hscx, HSCX_MODE, 0x8c);
+		writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+        	break;
+        }
+	writehscx(sp->membase, hscx, HSCX_ISTA, 0x00);
+}
+
+void release_io_teles0(struct IsdnCard *card) {
+	if (card->sp->cfg_reg) 
+		release_region(card->sp->cfg_reg, 8);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int	val;
+	char	tmp[64];
+	
+        val = readhscx(sp->membase, 1, HSCX_ISTA);
+        sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readhscx(sp->membase, 1, HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x02) {
+        	val = readhscx(sp->membase, 0, HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+        }
+        val = readhscx(sp->membase, 0, HSCX_ISTA);
+        sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+        val = readhscx(sp->membase, 1, HSCX_STAR);
+        sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+        val = readhscx(sp->membase, 0, HSCX_STAR);
+        sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+        val = readisac(sp->membase, ISAC_STAR);
+        sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+        val = readisac(sp->membase, ISAC_MODE);
+        sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+        val = readisac(sp->membase, ISAC_ADF2);
+        sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+        val = readisac(sp->membase, ISAC_ISTA);
+        sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readisac(sp->membase, ISAC_EXIR);
+                sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x04) {
+        	val = readisac(sp->membase, ISAC_CIR0);
+                sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+        }
+        writeisac(sp->membase, ISAC_MASK, 0);
+        writeisac(sp->membase, ISAC_CMDR, 0x41);
+}
+
+int
+initteles0(struct IsdnCardState *sp)
+{
+	int	ret;
+	char  tmp[40];
+	
+	sp->counter = kstat.interrupts[sp->irq]; 
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr,&telesS0_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+        	debugl1(sp, tmp);
+        	if (kstat.interrupts[sp->irq]==sp->counter) {
+        		printk(KERN_WARNING 
+        		"Teles0: IRQ(%d) getting no interrupts during init\n",
+        		sp->irq);
+        		irq2dev_map[sp->irq] = NULL;
+        		free_irq(sp->irq, NULL);
+        		return(0); 
+        	}
+	}
+	return(ret);
+}
+
+int
+setup_teles0(struct IsdnCard *card)
+{
+	int			timout;
+	byte			cfval, val, verA, verB;
+	struct IsdnCardState 	*sp = card->sp;
+        
+	if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0)) 
+		return(0);
+		
+        if (sp->typ == ISDN_CTYPE_16_0) 
+          	sp->cfg_reg = card->para[2];
+        else /* 8.0 */
+        	sp->cfg_reg = 0;
+        	
+        if (card->para[1] < 0x10000) {
+        	card->para[1] <<= 4;
+                printk(KERN_INFO
+                	"Teles0: membase configured DOSish, assuming 0x%lx\n",
+                        (unsigned long)card->para[1]);
+        }
+        sp->membase = card->para[1];
+        sp->irq     = card->para[0];
+        if (sp->cfg_reg) {
+        	if (check_region((sp->cfg_reg) ,8)) {
+                	printk(KERN_WARNING
+                  		"HiSax: %s config port %x-%x already in use\n",
+                  		CardType[card->typ],
+                               	sp->cfg_reg,
+                               	sp->cfg_reg + 8);
+                        return (0);
+        	} else {
+                	request_region(sp->cfg_reg, 8, "teles cfg");
+		}
+	} 
+        switch (sp->irq) {
+                case 2:
+                        cfval = 0x00;
+                        break;
+                case 3:
+                        cfval = 0x02;
+                        break;
+                case 4:
+                        cfval = 0x04;
+                        break;
+                case 5:
+                        cfval = 0x06;
+                        break;
+                case 10:
+                        cfval = 0x08;
+                        break;
+                case 11:
+                        cfval = 0x0A;
+                        break;
+                case 12:
+                        cfval = 0x0C;
+                        break;
+                case 15:
+                        cfval = 0x0E;
+                        break;
+                default:
+                        cfval = 0x00;
+                        break;
+        }
+        cfval |= ((card->para[1] >> 9) & 0xF0);
+        if (sp->cfg_reg) {
+        	if ((val=bytein(sp->cfg_reg + 0)) != 0x51) {
+                	printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+                        	sp->cfg_reg + 0, val);
+			release_region(sp->cfg_reg, 8);
+                        return(0);
+                }
+                if ((val=bytein(sp->cfg_reg  + 1)) != 0x93) {
+                	printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+                        	sp->cfg_reg + 1, val);
+			release_region(sp->cfg_reg, 8);
+                        return (0);
+                }
+                val = bytein(sp->cfg_reg + 2);/* 0x1e=without AB
+                                                * 0x1f=with AB
+                                                * 0x1c 16.3 ???
+                                                */
+                if (val != 0x1e && val != 0x1f) {
+                	printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+                        	sp->cfg_reg + 2, val);
+			release_region(sp->cfg_reg, 8);
+                        return (0);
+                }
+                cli();
+                timout = jiffies + (HZ / 10) + 1;
+                byteout(sp->cfg_reg + 4, cfval);
+                sti();
+                while (jiffies <= timout);
+                cli();
+                timout = jiffies + (HZ / 10) + 1;
+                byteout(sp->cfg_reg + 4, cfval | 1);
+                sti();
+                while (jiffies <= timout);
+	}
+        printk(KERN_NOTICE
+        	"HiSax: %s found,irq:%d mem:%x cfg:%x\n",
+                CardType[sp->typ], sp->irq,              
+                sp->membase,sp->cfg_reg);
+        verA=readhscx(sp->membase, 0,HSCX_VSTR) & 0xf;
+        verB=readhscx(sp->membase, 1,HSCX_VSTR) & 0xf;
+        printk(KERN_INFO "Teles0: HSCX version A: %s  B: %s\n",
+        	HscxVersion(verA), HscxVersion(verB));
+        val = readisac(sp->membase, ISAC_RBCH);
+        printk(KERN_INFO "Teles0: ISAC %s\n",
+        	ISACVersion(val));
+
+	if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
+        	printk(KERN_WARNING 
+        		"Teles0: wrong HSCX versions check IO/MEM addresses\n");
+		release_io_teles0(card);
+                return (0);
+	}
+        cli();
+        timout = jiffies + (HZ / 5) + 1;
+        writeb(0, sp->membase + 0x80);
+        sti();
+        while (jiffies <= timout);
+        cli();
+        writeb(1, sp->membase + 0x80);
+        timout = jiffies + (HZ / 5) + 1;
+        sti();
+        while (jiffies <= timout);
+        
+        sp->modehscx       = &modehscx;
+        sp->ph_command     = &ph_command;
+        sp->hscx_fill_fifo = &hscx_fill_fifo;
+        sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/teles0.h linux/drivers/isdn/hisax/teles0.h
--- linux-2.0.26.org/drivers/isdn/hisax/teles0.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/teles0.h	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,18 @@
+/* $Id: teles0.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+ *
+ * teles0.h   Header for Teles 16.0 8.0 & compatible
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * 
+ * $Log: teles0.h,v $
+ * Revision 1.1  1996/10/13 20:03:48  keil
+ * Initial revision
+ *
+ *
+*/
+
+extern	void teles0_report(struct IsdnCardState *sp);
+extern  void release_io_teles0(struct IsdnCard *card);
+extern	int  setup_teles0(struct IsdnCard *card);
+extern  int  initteles0(struct IsdnCardState *sp);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- linux-2.0.26.org/drivers/isdn/hisax/teles3.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/teles3.c	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,998 @@
+/* $Id: teles3.c,v 1.3 1996/11/05 19:56:54 keil Exp $
+ *
+ * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
+ *
+ *              based on the teles driver from Jan den Ouden
+ * 
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to	Jan den Ouden
+ *	        Fritz Elfert	
+ * 	        Beat Doebeli
+ * 
+ * $Log: teles3.c,v $
+ * Revision 1.3  1996/11/05 19:56:54  keil
+ * debug output fixed
+ *
+ * Revision 1.2  1996/10/27 22:09:15  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:59  keil
+ * Initial revision
+ *
+ *
+ *
+*/
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles3.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const   char    *CardType[];
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline byte
+readreg(unsigned int adr, byte off)
+{
+        return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, byte off, byte data)
+{
+	byteout(adr +off , data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, byte * data, int size)
+{
+	insb(adr +0x1e , data, size);
+}
+        
+static void
+write_fifo(unsigned int adr, byte * data, int size)
+{
+	outsb(adr +0x1e , data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+	int            to = 50;
+
+	while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles3: waitforCEC timeout\n");
+}
+
+    
+static inline void
+waitforXFW(int adr)
+{
+	int            to = 50;
+
+	while ((!(readreg(adr, HSCX_STAR) & 0x44)==0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
+}
+static inline void
+writehscxCMDR(int adr, byte data)
+{
+	long            flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr);
+	writereg(adr, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+        printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+teles3_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	byte			*ptr;
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh = hsp->rcvibh;
+	long 			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
+					      HSCX_RBUF_BPPS)) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->rcvptr;
+
+	hsp->rcvptr += count;
+	save_flags(flags);
+	cli();
+        read_fifo(sp->hscx[hsp->hscx], ptr, count);
+        writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_empty_fifo %c cnt %d",
+			hsp->hscx?'B':'A',count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState	*sp = hsp->sp;
+	struct BufHeader 	*ibh;
+	int			more, count;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	ibh = hsp->xmtibh;
+	if (!ibh)
+                return;
+
+	count = ibh->datasize - hsp->sendptr;
+	if (count <= 0)
+                return;
+
+	more = (hsp->mode == 1)?1:0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += hsp->sendptr;
+	hsp->sendptr += count;
+
+        waitforXFW(sp->hscx[hsp->hscx]);
+	save_flags(flags);
+	cli();
+        write_fifo(sp->hscx[hsp->hscx], ptr, count);
+        writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"hscx_fill_fifo %c cnt %d",
+			hsp->hscx?'B':'A', count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
+{
+	byte             r;
+	struct HscxState *hsp = sp->hs + hscx;
+	int              count, err;
+	char		 tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode) 
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			if (hsp->rcvibh)
+				BufPoolRelease(hsp->rcvibh);
+			hsp->rcvibh = NULL;
+			writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+			goto afterRME;
+		}
+		if (!hsp->rcvibh)
+			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+                                       GFP_ATOMIC, (void *) 1, 1)) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RME out of buffers");
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+				goto afterRME;
+			} else
+				hsp->rcvptr = 0;
+
+		count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		hscx_empty_fifo(hsp, count);
+		hsp->rcvibh->datasize = hsp->rcvptr - 1;
+		BufQueueLink(&hsp->rq, hsp->rcvibh);
+		hsp->rcvibh = NULL;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+      afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!hsp->rcvibh) {
+			if (hsp->mode == 1)
+				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
+					GFP_ATOMIC, (void *)1, 2);
+			else
+				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
+					GFP_ATOMIC, (void *)1, 2);
+			
+			if (err) {
+				if (sp->debug & L1_DEB_WARN)
+                                       debugl1(sp, "HSCX RPF out of buffers");
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+				goto afterRPF;
+			} else
+				hsp->rcvptr = 0;
+		}
+		
+		hscx_empty_fifo(hsp, 32);
+                if (hsp->mode == 1) {
+                        /* receive audio data */
+                        hsp->rcvibh->datasize = hsp->rcvptr;
+                        BufQueueLink(&hsp->rq, hsp->rcvibh);
+                        hsp->rcvibh = NULL;
+                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+                }
+                
+	}
+      afterRPF:
+	if (val & 0x10) {	/* XPR */
+		if (hsp->xmtibh)
+			if (hsp->xmtibh->datasize > hsp->sendptr) {
+				hscx_fill_fifo(hsp);
+				goto afterXPR;
+			} else {
+				if (hsp->releasebuf)
+					BufPoolRelease(hsp->xmtibh);
+				hsp->sendptr = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->xmtibh = NULL;
+			}
+		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
+			hsp->releasebuf = !0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+      afterXPR:
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	byte			*ptr;
+	struct BufHeader	*ibh = sp->rcvibh;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+	if (sp->debug & L1_DEB_ISAC)
+        	debugl1(sp, "isac_empty_fifo"); 
+
+	if (sp->rcvptr >= 3072) {
+		if (sp->debug & L1_DEB_WARN) {
+			char		 tmp[40];
+			sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
+        		debugl1(sp, tmp); 
+		}
+		return;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->rcvptr;
+	sp->rcvptr += count;
+
+	save_flags(flags);
+	cli();
+        read_fifo(sp->isac, ptr, count);
+        writereg(sp->isac, ISAC_CMDR, 0x80);
+        restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_empty_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	struct BufHeader	*ibh;
+	int			count, more;
+	byte			*ptr;
+	long			flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+        	debugl1(sp, "isac_fill_fifo"); 
+
+	ibh = sp->xmtibh;
+	if (!ibh)
+		return;
+
+	count = ibh->datasize - sp->sendptr;
+	if (count <= 0)
+		return;
+	if (count >= 3072)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	ptr = DATAPTR(ibh);
+	ptr += sp->sendptr;
+	sp->sendptr += count;
+
+	save_flags(flags);
+	cli();
+	write_fifo(sp->isac, ptr, count);
+        writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char	tmp[128];
+		char	*t=tmp;
+		
+		t += sprintf(t,"isac_fill_fifo cnt %d", count);
+		QuickHex(t,ptr,count);        
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char	tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+        	debugl1(sp, tmp);
+        } 
+	writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, byte val) {
+	byte		exval;
+	unsigned int    count;
+	char		tmp[32];    
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+        	debugl1(sp, tmp); 
+        }
+	if (val & 0x80) {	/* RME */
+		exval = readreg(sp->isac, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC CRC error");
+			if (sp->rcvibh)
+				BufPoolRelease(sp->rcvibh);
+			sp->rcvibh = NULL;
+			writereg(sp->isac, ISAC_CMDR, 0x80);
+			goto afterRME;
+		}
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC,(void *) 1, 3)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writereg(sp->isac, ISAC_CMDR, 0x80);
+				goto afterRME;
+			} else
+				sp->rcvptr = 0;
+		count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+		if (count == 0)
+			count = 32;
+		isac_empty_fifo(sp, count);
+		sp->rcvibh->datasize = sp->rcvptr;
+		BufQueueLink(&(sp->rq), sp->rcvibh);
+		sp->rcvibh = NULL;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	afterRME:
+	if (val & 0x40) {	/* RPF */
+		if (!sp->rcvibh)
+			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
+                        	GFP_ATOMIC, (void *) 1, 4)) {
+				if (sp->debug & L1_DEB_WARN)
+        				debugl1(sp, "ISAC RME out of buffers!");
+				writereg(sp->isac, ISAC_CMDR, 0x80);
+				goto afterRPF;
+			} else
+				sp->rcvptr = 0;
+		isac_empty_fifo(sp, 32);
+	}
+	afterRPF:
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->xmtibh)
+			if (sp->xmtibh->datasize > sp->sendptr) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				if (sp->releasebuf)
+					BufPoolRelease(sp->xmtibh);
+				sp->xmtibh = NULL;
+				sp->sendptr = 0;
+			}
+		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
+			sp->releasebuf = !0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+	afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2) 
+				& 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+        		sprintf(tmp, "l1state %d", sp->ph_state);
+        		debugl1(sp, tmp);
+        	}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+        		debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readreg(sp->isac, ISAC_EXIR); 
+		if (sp->debug & L1_DEB_WARN) {
+        		sprintf(tmp, "ISAC EXIR %02x", exval);
+        		debugl1(sp, tmp);
+        	}
+
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, byte val) {
+
+	byte    		exval;
+	struct HscxState	*hsp;
+	char			tmp[32];
+	
+		
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+        	exval = readreg(sp->hscx[1], HSCX_EXIR);
+	        if (exval == 0x40) {
+                	if (hsp->mode == 1)
+        	        	hscx_fill_fifo(hsp);
+	                else {
+                        	/* Here we lost an TX interrupt, so
+                        	* restart transmitting the whole frame.
+                	        */
+        	                hsp->sendptr = 0;
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+                        }
+                } else
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX B EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+        		debugl1(sp, tmp); 
+        	}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+                exval = readreg(sp->hscx[0], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+	                	/* Here we lost an TX interrupt, so
+        	        	* restart transmitting the whole frame.
+                		*/
+                		hsp->sendptr = 0;
+				writehscxCMDR(sp->hscx[hsp->hscx],0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+        				debugl1(sp, tmp); 
+        			}
+        		}
+		} else 
+			if (sp->debug & L1_DEB_HSCX) {
+				sprintf(tmp, "HSCX A EXIR %x", exval);
+        			debugl1(sp, tmp); 
+        		}
+	}
+        if (val & 0x04) {
+                exval = readreg(sp->hscx[0], HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+        		debugl1(sp, tmp); 
+        	}
+        	hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	byte                 val, stat=0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+	
+	if (!sp) {
+		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+		return;
+	}
+	
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+	Start_HSCX:
+	if (val) {
+		hscx_int_main(sp,val);
+		stat |= 1;
+	}
+	val = readreg(sp->isac, ISAC_ISTA);
+	Start_ISAC:
+	if (val) { 
+		isac_interrupt(sp,val);
+		stat |= 2;
+	}
+
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX) 
+        		debugl1(sp, "HSCX IntStat after IntRoutine"); 
+		goto Start_HSCX;
+	}
+	val = readreg(sp->isac, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC) 
+        		debugl1(sp, "ISAC IntStat after IntRoutine"); 
+		goto Start_ISAC;
+	}
+	if (stat & 1) {
+		writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[0], HSCX_MASK, 0x0);
+		writereg(sp->hscx[1], HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writereg(sp->isac, ISAC_MASK, 0xFF);
+		writereg(sp->isac, ISAC_MASK, 0x0);
+	}
+
+}
+
+
+static void
+initisac(struct IsdnCardState    *sp)
+{
+	unsigned int	adr=sp->isac;
+	
+	/* 16.3 IOM 2 Mode */
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_ADF2, 0x80);
+	writereg(adr, ISAC_SQXR, 0x2f);
+	writereg(adr, ISAC_SPCR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x2);
+	writereg(adr, ISAC_STCR, 0x70);
+	writereg(adr, ISAC_MODE, 0xc9);
+	writereg(adr, ISAC_TIMR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x0);
+	writereg(adr, ISAC_CMDR, 0x41);
+	writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int             hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char  tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+	        	'A'+hscx, mode, ichan);
+        	debugl1(sp, tmp);
+        } 
+        hs->mode = mode;
+        writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+        writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+        writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+        writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+        switch (mode) {
+	case (0):
+        	writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+		writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+		writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+		writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+		writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+		writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+        	break;
+	case (1):
+                if (ichan == 0) {
+                	writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                } else {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                }
+		writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+		writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+        	break;
+	case (2):
+                if (ichan == 0) {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                } else {
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+                }
+		writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+		writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+        	break;
+        }
+	writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask) {
+        if (mask & 1) release_region(card->sp->isac, 32);
+        if (mask & 2) release_region(card->sp->hscx[0], 32);
+        if (mask & 4) release_region(card->sp->hscx[1], 32);
+}
+
+void release_io_teles3(struct IsdnCard *card) {
+	if (card->sp->cfg_reg) 
+		release_region(card->sp->cfg_reg, 8);
+	release_ioregs(card, 0x7);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int	val;
+	char	tmp[64];
+	
+        val = readreg(sp->hscx[1], HSCX_ISTA);
+        sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readreg(sp->hscx[1], HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x02) {
+        	val = readreg(sp->hscx[0], HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+        }
+        val = readreg(sp->hscx[0], HSCX_ISTA);
+        sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->hscx[1], HSCX_STAR);
+        sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->hscx[0], HSCX_STAR);
+        sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_STAR);
+        sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_MODE);
+        sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_ADF2);
+        sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+        val = readreg(sp->isac, ISAC_ISTA);
+        sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+        if (val & 0x01) {
+        	val = readreg(sp->isac, ISAC_EXIR);
+                sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+        } else if (val & 0x04) {
+        	val = readreg(sp->isac, ISAC_CIR0);
+                sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+        }
+        writereg(sp->isac, ISAC_MASK, 0);
+        writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initteles3(struct IsdnCardState *sp)
+{
+	int	ret;
+	char  tmp[40];
+	
+	sp->counter = kstat.interrupts[sp->irq]; 
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr,&teles3_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+        	debugl1(sp, tmp);
+        	if (kstat.interrupts[sp->irq]==sp->counter) {
+        		printk(KERN_WARNING 
+        		"Teles3: IRQ(%d) getting no interrupts during init\n",
+        		sp->irq);
+        		irq2dev_map[sp->irq] = NULL;
+        		free_irq(sp->irq, NULL);
+        		return(0); 
+        	}
+	}
+	return(ret);
+}
+
+int
+setup_teles3(struct IsdnCard *card)
+{
+	int			timout;
+	byte			cfval, val, verA, verB;
+	struct IsdnCardState 	*sp = card->sp;
+        
+
+	if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP)) 
+		return(0);
+		
+        if (sp->typ == ISDN_CTYPE_16_3) {
+          	sp->cfg_reg = card->para[1];
+                switch (sp->cfg_reg) {
+                        case 0x180:
+                        case 0x280:
+                        case 0x380:
+                                sp->cfg_reg |= 0xc00;
+                                break;
+                }
+                sp->isac    = sp->cfg_reg - 0x400; 
+                sp->hscx[0] = sp->cfg_reg - 0xc00;
+                sp->hscx[1] = sp->cfg_reg - 0x800;
+        } else { /* PNP */
+        	sp->cfg_reg = 0;
+                sp->isac    = card->para[1];
+                sp->hscx[0] = card->para[2];
+                sp->hscx[1] = card->para[2] + 0x20;
+        }
+        sp->irq     = card->para[0];
+        if (sp->cfg_reg) {
+        	if (check_region((sp->cfg_reg) ,8)) {
+                	printk(KERN_WARNING
+                  		"HiSax: %s config port %x-%x already in use\n",
+                  		CardType[card->typ],
+                               	sp->cfg_reg,
+                               	sp->cfg_reg + 8);
+                        return (0);
+        	} else {
+                	request_region(sp->cfg_reg, 8, "teles3 cfg");
+		}
+	} 
+        if (check_region((sp->isac) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s isac ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->isac,
+                        sp->isac + 32);
+		if (sp->cfg_reg) {
+			release_region(sp->cfg_reg, 8);
+		}
+                return(0);
+        } else {
+        	request_region(sp->isac, 32, "HiSax isac");
+	}
+        if (check_region((sp->hscx[0]) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx A ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[0],
+                        sp->hscx[0] + 32);
+		if (sp->cfg_reg) {
+			release_region(sp->cfg_reg, 8);
+		}
+		release_ioregs(card, 1);
+                return(0);
+        } else {
+        	request_region(sp->hscx[0], 32, "HiSax hscx A");
+	}
+        if (check_region((sp->hscx[1]) , 32)) {
+        	printk(KERN_WARNING
+                	"HiSax: %s hscx B ports %x-%x already in use\n",
+                  	CardType[sp->typ],
+                        sp->hscx[1],
+                        sp->hscx[1] + 32);
+		if (sp->cfg_reg) {
+			release_region(sp->cfg_reg, 8);
+		}
+		release_ioregs(card, 3);
+                return(0);
+        } else {
+        	request_region(sp->hscx[1], 32, "HiSax hscx B");
+	}
+        switch (sp->irq) {
+                case 2:
+                        cfval = 0x00;
+                        break;
+                case 3:
+                        cfval = 0x02;
+                        break;
+                case 4:
+                        cfval = 0x04;
+                        break;
+                case 5:
+                        cfval = 0x06;
+                        break;
+                case 10:
+                        cfval = 0x08;
+                        break;
+                case 11:
+                        cfval = 0x0A;
+                        break;
+                case 12:
+                        cfval = 0x0C;
+                        break;
+                case 15:
+                        cfval = 0x0E;
+                        break;
+                default:
+                        cfval = 0x00;
+                        break;
+        }
+        if (sp->cfg_reg) {
+        	if ((val=bytein(sp->cfg_reg + 0)) != 0x51) {
+                	printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+                        	sp->cfg_reg + 0, val);
+			release_io_teles3(card);
+                        return(0);
+                }
+                if ((val=bytein(sp->cfg_reg  + 1)) != 0x93) {
+                	printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+                        	sp->cfg_reg + 1, val);
+			release_io_teles3(card);
+                        return (0);
+                }
+                val = bytein(sp->cfg_reg + 2);/* 0x1e=without AB
+                                                * 0x1f=with AB
+                                                * 0x1c 16.3 ???
+                                                */
+                if (val != 0x1c && val != 0x1e && val != 0x1f) {
+                	printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+                        	sp->cfg_reg + 2, val);
+			release_io_teles3(card);
+                        return (0);
+                }
+                cli();
+                timout = jiffies + (HZ / 10) + 1;
+                byteout(sp->cfg_reg + 4, cfval);
+                sti();
+                while (jiffies <= timout);
+                cli();
+                timout = jiffies + (HZ / 10) + 1;
+                byteout(sp->cfg_reg + 4, cfval | 1);
+                sti();
+                while (jiffies <= timout);
+	}
+        printk(KERN_NOTICE
+        	"HiSax: %s found,irq:%d isac:%x  cfg:%x\n",
+                CardType[sp->typ], sp->irq,              
+                sp->isac,sp->cfg_reg);
+        printk(KERN_NOTICE
+        	"HiSax: hscx A:%x  hscx B:%x\n",
+                 sp->hscx[0], sp->hscx[1]);
+        verA = readreg(sp->hscx[0],HSCX_VSTR) & 0xf;
+        verB = readreg(sp->hscx[1],HSCX_VSTR) & 0xf;
+        printk(KERN_INFO "Teles3: HSCX version A: %s  B: %s\n",
+        	HscxVersion(verA), HscxVersion(verB));
+        val = readreg(sp->isac, ISAC_RBCH);
+        printk(KERN_INFO "Teles3: ISAC %s\n",
+        	ISACVersion(val));
+	if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
+        	printk(KERN_WARNING 
+        		"Teles3: wrong HSCX versions check IO address\n");
+		release_io_teles3(card);
+                return (0);
+	}
+
+        sp->modehscx       = &modehscx;
+        sp->ph_command     = &ph_command;
+        sp->hscx_fill_fifo = &hscx_fill_fifo;
+        sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/hisax/teles3.h linux/drivers/isdn/hisax/teles3.h
--- linux-2.0.26.org/drivers/isdn/hisax/teles3.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/isdn/hisax/teles3.h	Fri Nov 22 19:06:39 1996
@@ -0,0 +1,18 @@
+/* $Id: teles3.h,v 1.1 1996/10/13 20:03:49 keil Exp $
+ *
+ * teles3.h   Header for Teles 16.3 PNP & compatible
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * 
+ * $Log: teles3.h,v $
+ * Revision 1.1  1996/10/13 20:03:49  keil
+ * Initial revision
+ *
+ *
+*/
+
+extern	void teles3_report(struct IsdnCardState *sp);
+extern  void release_io_teles3(struct IsdnCard *card);
+extern	int  setup_teles3(struct IsdnCard *card);
+extern  int  initteles3(struct IsdnCardState *sp);
diff -u --recursive --new-file linux-2.0.26.org/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux-2.0.26.org/drivers/isdn/isdn_net.c	Fri Nov 22 19:04:51 1996
+++ linux/drivers/isdn/isdn_net.c	Tue Nov 26 19:06:12 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.29 1996/11/13 02:31:38 fritz Exp $
+/* $Id: isdn_net.c,v 1.30 1996/11/25 17:20:50 hipp Exp $
  *
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.30  1996/11/25 17:20:50  hipp
+ * fixed pppbind bug in isdn_net_find_icall()
+ *
  * Revision 1.29  1996/11/13 02:31:38  fritz
  * Minor cleanup.
  *
@@ -159,7 +162,7 @@
  
 extern void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
 
-char *isdn_net_revision = "$Revision: 1.29 $";
+char *isdn_net_revision = "$Revision: 1.30 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -1780,7 +1783,6 @@
 					p->local.isdn_device = di;
 					p->local.isdn_channel = ch;
 					p->local.ppp_slot = -1;
-					p->local.pppbind = -1;
 					p->local.flags |= ISDN_NET_CONNECTED;
 					p->local.dialstate = 7;
 					p->local.dtimer = 0;
diff -u --recursive --new-file linux-2.0.26.org/init/main.c linux/init/main.c
--- linux-2.0.26.org/init/main.c	Fri Nov 22 19:21:20 1996
+++ linux/init/main.c	Fri Nov 22 19:06:39 1996
@@ -147,6 +147,9 @@
 #ifdef CONFIG_ISDN_DRV_TELES
 extern void teles_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_ISDN_DRV_HISAX
+extern void HiSax_setup(char *str, int *ints);
+#endif
 
 #ifdef CONFIG_ATARIMOUSE
 extern void atari_mouse_setup (char *str, int *ints);
@@ -386,6 +389,10 @@
 #endif
 #ifdef CONFIG_ISDN_DRV_TELES
 	{ "teles=", teles_setup },
+#endif
+#ifdef CONFIG_ISDN_DRV_HISAX
+	{ "hisax=", HiSax_setup },
+	{ "HiSax=", HiSax_setup },
 #endif
 #ifdef CONFIG_ISDN_DRV_PCBIT
 	{ "pcbit=", pcbit_setup },
