## Automatically generated incremental diff
## From:   linux-2.2.15-pre4
## To:     linux-2.2.15-pre5
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.15-pre4/CREDITS linux/CREDITS
--- linux-2.2.15-pre4/CREDITS	Mon Dec  3 21:58:24 2001
+++ linux/CREDITS	Mon Dec  3 21:58:30 2001
@@ -1901,6 +1901,13 @@
 S: Cliffwood, New Jersey 07721
 S: USA
 
+N: Andrew Stanley-Jones
+E: asj@lanmedia.com
+D: LanMedia Corp. Device WAN card device driver
+S: #102, 686 W. Maude Ave
+S: Sunyvale, CA 94086
+S: USA
+
 N: Henrik Storner
 E: storner@image.dk
 W: http://www.image.dk/~storner/
diff -urN linux-2.2.15-pre4/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.15-pre4/Documentation/Configure.help	Mon Dec  3 21:58:24 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 21:58:30 2001
@@ -5490,6 +5490,31 @@
   The module will be called cosa.o. For general information about
   modules read Documentation/modules.txt.
 
+Lan Media sync serial boards support
+CONFIG_LANMEDIA
+  This is a driver for the following Lan Media family of serial boards.
+
+  LMC 1000 board allows you to connect synchronous serial devices (for
+  example base-band modems, or any other device with the X.21, V.24,
+  V.35 or V.36 interface) to your Linux box. 
+
+  LMC 1200 with on board DSU board allows you to connect your Linux
+  box dirrectly to a T1 or E1 circuit. 
+
+  LMC 5200 board provides a HSSI interface capable of runnig up to
+  52 mbits per second.
+
+  LMC 5245 board connects directly to a T3 circuit saving the
+  additional external hardware.
+
+  To change setting such as syncPPP vs cisco HDLC or clock source you
+  will need lmcctl.  It it available at ftp.lanmedia.com.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called lmc.o. For general information about
+  modules read Documentation/modules.txt.
+
 Red Creek Hardware VPN (EXPERIMENTAL)
 CONFIG_RCPCI
   This is a driver for hardware which provides a Virtual Private
@@ -10304,11 +10329,16 @@
   If you have trouble with some ugly exchanges try to select this
   option.
 
+Disable keypad protocol option
+CONFIG_HISAX_NO_KEYPAD
+  If you like to send special dialstrings including * or # without
+  using the keypad protocol, select this option.
+
 HiSax Support for german 1TR6
 CONFIG_HISAX_1TR6
   Enable this if you have a old german 1TR6 line.
 
-HiSax Support for Teles 16.0/8.0
+Teles 16.0/8.0
 CONFIG_HISAX_16_0
   This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
   and many compatibles. 
@@ -10317,7 +10347,7 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port/shmem settings.
 
-HiSax Support for Teles 16.3 or PNP or PCMCIA
+Teles 16.3 or PNP or PCMCIA
 CONFIG_HISAX_16_3
   This enables HiSax support for the Teles ISDN-cards S0-16.3 the
   Teles/Creatix PnP and the Teles PCMCIA.
@@ -10326,17 +10356,17 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for Teles PCI
+Teles PCI
 CONFIG_HISAX_TELESPCI
   This enables HiSax support for the Teles PCI.
   See Documentation/isdn/README.HiSax on how to configure it.
 
-HiSax Support for Teles S0Box
+Teles S0Box
 CONFIG_HISAX_S0BOX
   This enables HiSax support for the Teles/Creatix parallel port
   S0BOX.  See Documentation/isdn/README.HiSax on how to configure it.
 
-HiSax Support for AVM A1 (Fritz)
+AVM A1 (Fritz)
 CONFIG_HISAX_AVM_A1
   This enables HiSax support for the AVM A1 (aka "Fritz").
   
@@ -10344,17 +10374,17 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for AVM PnP/PCI (Fritz!PNP/PCI)
+AVM PnP/PCI (Fritz!PNP/PCI)
 CONFIG_HISAX_FRITZPCI
   This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
   See Documentation/isdn/README.HiSax on how to configure it.
 
-HiSax Support for AVM A1 PCMCIA (Fritz)
+AVM A1 PCMCIA (Fritz)
 CONFIG_HISAX_AVM_A1_PCMCIA
   This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
   See Documentation/isdn/README.HiSax on how to configure it.
 
-HiSax Support for Elsa cards
+Elsa cards
 CONFIG_HISAX_ELSA
   This enables HiSax support for the Elsa Mircolink ISA cards, for the
   Elsa Quickstep series cards and Elsa PCMCIA.
@@ -10363,7 +10393,7 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for ITK ix1-micro Revision 2
+ITK ix1-micro Revision 2
 CONFIG_HISAX_IX1MICROR2
   This enables HiSax support for the ITK ix1-micro Revision 2 card.
 
@@ -10371,7 +10401,7 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for Eicon.Diehl Diva cards
+Eicon.Diehl Diva cards
 CONFIG_HISAX_DIEHLDIVA
   This enables HiSax support for the Eicon.Diehl Diva none PRO
   versions passive ISDN cards.
@@ -10380,16 +10410,16 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for ASUSCOM cards
+ASUSCOM ISA cards
 CONFIG_HISAX_ASUSCOM
   This enables HiSax support for the AsusCom and their OEM versions
-  passive ISDN cards.
+  passive ISDN ISA cards.
 
   See Documentation/isdn/README.HiSax on how to configure it using the
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for TELEINT cards
+TELEINT cards
 CONFIG_HISAX_TELEINT
   This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
 
@@ -10397,7 +10427,7 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for HFC-S based cards
+HFC-S based cards
 CONFIG_HISAX_HFCS
   This enables HiSax support for the HFC-S 2BDS0 based cards, like
   teles 16.3c.
@@ -10406,7 +10436,7 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for Sedlbauer cards
+Sedlbauer cards
 CONFIG_HISAX_SEDLBAUER
   This enables HiSax support for the Sedlbauer passive ISDN cards.
 
@@ -10414,21 +10444,21 @@
   different cards, a different D-channel protocol, or non-standard
   IRQ/port settings.
 
-HiSax Support for USR Sportster internal TA
+USR Sportster internal TA
 CONFIG_HISAX_SPORTSTER
   This enables HiSax support for the USR Sportster internal TA card.
 
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for MIC card
+MIC card
 CONFIG_HISAX_MIC
   This enables HiSax support for the ITH MIC card. 
 
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for NETjet card
+NETjet card
 CONFIG_HISAX_NETJET
   This enables HiSax support for the NetJet from Traverse
   Technologies.
@@ -10436,62 +10466,67 @@
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Niccy PnP/PCI card
+Niccy PnP/PCI card
 CONFIG_HISAX_NICCY
   This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. 
 
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Siemens I-Surf card
+Siemens I-Surf card
 CONFIG_HISAX_ISURF
   This enables HiSax support for the Siemens I-Talk/I-Surf card with
   ISAR chip.
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for HST Saphir card
+HST Saphir card
 CONFIG_HISAX_HSTSAPHIR
   This enables HiSax support for the HST Saphir card.
   
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Telekom A4T card
+Telekom A4T card
 CONFIG_HISAX_BKM_A4T
   This enables HiSax support for the Telekom A4T card.
   
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Scitel Quadro card
+Scitel Quadro card
 CONFIG_HISAX_SCT_QUADRO
   This enables HiSax support for the Scitel Quadro card.
   
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Gazel cards
+Gazel cards
 CONFIG_HISAX_GAZEL
   This enables HiSax support for the Gazel cards.
 
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for HFC PCI-Bus cards
+HFC PCI-Bus cards
 CONFIG_HISAX_HFC_PCI
   This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
   
   For more informations see under Documentation/isdn/README.hfc-pci.
 
-HiSax Support for Winbond W6692 based cards
+Winbond W6692 based cards
 CONFIG_HISAX_W6692
   This enables HiSax support for Winbond W6692 based PCI ISDN cards.
   
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
-HiSax Support for Am7930 (EXPERIMENTAL)
+HFC-S+, HFC-SP, HFC-PCMCIA cards (EXPERIMENTAL)
+CONFIG_HISAX_HFC_SX
+  This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards.
+  This code is not finished yet.
+
+Am7930 (EXPERIMENTAL)
 CONFIG_HISAX_AMD7930
   This enables HiSax support for the AMD7930 chips on some SPARCs.
   This code is not finished yet.
@@ -11248,11 +11283,6 @@
   Choose Y here if you have this FM radio card, and then fill in the 
   port address below.
 
-  If you have GemTeks combined (PnP) sound- and radio card you must use
-  this driver as a module and setup the card with isapnptools. You must
-  also pass the module a suitable io parameter, 0x248 has been reported
-  to be used by these cards.
-
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
@@ -11436,6 +11466,12 @@
   Choose Y here if you have this FM radio card, and then fill in the 
   port address below.
 
+  If you have GemTeks combined (PnP) sound- and radio card you might want
+  to use this driver as a module and setup the card with isapnptools. You
+  must also pass the module a suitable io parameter. If you have trouble
+  getting the driver to work with the card as a module, please try building
+  it into the kernel by answering Y.
+
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
@@ -11450,8 +11486,9 @@
 
 GemTek i/o port
 CONFIG_RADIO_GEMTEK_PORT
-  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
-  0x34c, if you haven't changed the jumper setting on the card.
+  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. 0x20c and 0x248 have
+  been reported to work with the combined sound/radio card. The card
+  default is 0x34c, if you haven't changed the jumper setting on the card.
 
 Trust FM Radio Card
 CONFIG_RADIO_TRUST
diff -urN linux-2.2.15-pre4/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax
--- linux-2.2.15-pre4/Documentation/isdn/README.HiSax	Tue Oct 26 17:53:39 1999
+++ linux/Documentation/isdn/README.HiSax	Mon Dec  3 21:58:30 2001
@@ -64,6 +64,7 @@
 Gazel ISDN cards
 HFC-PCI based cards
 Winbond W6692 based cards
+HFC-S+, HFC-SP/PCMCIA cards
 
 Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
       PCC-8: not tested yet
@@ -72,6 +73,7 @@
       Teles PCI is EXPERIMENTAL
       Teles S0Box is EXPERIMENTAL
       Eicon.Diehl Diva U interface not tested
+      HFC-S+, HFC-SP/PCMCIA are experimental
 
 If you know other passive cards with the Siemens chipset, please let me know.
 To use the PNP cards you need the isapnptools.
@@ -184,6 +186,7 @@
    34	Gazel ISDN cards (PCI)   none
    35	HFC 2BDS0 PCI            none
    36	W6692 based PCI cards    none
+   37   HFC 2BDS0 S+, SP/PCMCIA  irq,io (pcmcia must be set with cardmgr)
 
 
 At the moment IRQ sharing is only possible with PCI cards. Please make sure
@@ -288,6 +291,7 @@
    34	Gazel ISDN cards (PCI)  no parameter
    35	HFC 2BDS0 PCI           no parameter
    36	W6692 based PCI cards   none
+   37   HFC 2BDS0 S+,SP/PCMCIA  pa=irq, pb=io
 
 Running the driver
 ------------------
diff -urN linux-2.2.15-pre4/Documentation/networking/bonding.txt linux/Documentation/networking/bonding.txt
--- linux-2.2.15-pre4/Documentation/networking/bonding.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/networking/bonding.txt	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,128 @@
+Installation:
+
+Apply patch.  (if your reading this in
+/usr/src/linux/Documentation/network/bonding.txt, then it's already
+applied.)
+
+Run make menuconfig/xconfig/config, and select 'bonding device' in
+network devices.
+
+Build the new kernel/modules.
+
+Get update ifenslave.c (included in tar file.) (location to be determined.)
+
+install ifenslave.c; do:
+	gcc -O2 -o ifenslave ifenslave.c
+	cp ifenslave /sbin/ifenslave
+
+Modify /etc/conf.modules by adding the line:
+	alias bond0 bonding
+
+If you running a RH5.0 or newer distribution, do:
+
+cd /etc/sysconfig/network-scripts
+cp ifcfg-eth0 ifcfg-bond0
+edit ifcfg-bond0, and make it look the following:
+
+DEVICE=bond0
+USERCTL=no
+ONBOOT=yes
+BOOTPROTO=none
+BROADCAST=XXX.XXX.XXX.255
+NETWORK=XXX.XXX.XXX.0
+NETMASK=255.255.255.0
+IPADDR=XXX.XXX.XXX.XXX
+
+(put the approiate values for you network in where the XXX's are at.)
+
+Then, edit ifcfg-eth0/ifcfg-eth1 (and all the other slave devices), and make them
+look like this:
+
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+MASTER=bond0
+SLAVE=yes
+BOOTPROTO=none
+
+Reboot, and the network should come up bonded together.
+
+For other distributions, you need to do something like:
+
+/sbin/ifconfig bond0 addresss netmask xxx.xxx.xxx.xxx broadcast xxx.xxx.xxx.xxx up
+/sbin/ifenslave bond0 eth0
+/sbin/ifenslave bond0 eth1
+
+When properly configured, it will look this:
+
+[root]# /sbin/ifconfig
+bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
+          RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0
+          collisions:0 txqueuelen:0 
+
+eth0      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
+          RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0
+          collisions:0 txqueuelen:100 
+          Interrupt:10 Base address:0x1080 
+
+eth1      Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
+          inet addr:XXX.XXX.XXX.YYY  Bcast:XXX.XXX.XXX.255  Mask:255.255.252.0
+          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
+          RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:100 
+          Interrupt:9 Base address:0x1400 
+
+Questions:
+
+1.  Is it SMP safe?
+
+	Yes.  The old 2.0.xx channel bonding patch wasn't SMP safe.
+This one was designed from the start to be SMP safe.
+
+2.  What type of cards can it work with it?
+
+	Any Ethernet type cards (ie, you can even mix cards - a tulip
+and a 3com 3c905, for example).  You can even bond together Gigabit
+Ethernet cards!
+
+3.  How many bond devices can I have?
+
+	Just one at this time.
+
+4.  How many slaves can a bond device have?
+
+	Limited by the number of cards you can place in your system.
+
+5.  What happens when a slave dies?
+
+	Currently, the ethernet drivers don't really handle this
+situation very well.  The tulip driver never stalls; it just starts to
+throw packets away!
+
+6.  If this was fixed, can bonding be used for High Availability?
+
+	Yes!
+
+7.  Which switches/systems does it work with?
+
+	Cisco 5500 series (look for EtherChannel support).
+	SunTrunking software.
+
+8.  Where does the bond0 device get it's mac address from?
+
+	It's taken from the first slave device.  If you remove that
+first slave device, the MAC address continues to be associated with
+it.  If you wish to remove that MAC address, you have to ifconfig
+bond0 down, and then modprobe -r bonding.  If you wish, you can also
+assign a MAC address when you ifconfig the bond0 device.
+
+9.  Which transmit policy is used?
+
+	Round robin, based on order of enslaving.
\ No newline at end of file
diff -urN linux-2.2.15-pre4/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.15-pre4/MAINTAINERS	Mon Dec  3 21:58:24 2001
+++ linux/MAINTAINERS	Mon Dec  3 21:58:30 2001
@@ -476,6 +476,12 @@
 W:	http://csua.berkeley.edu/~gam3/knfsd
 S:	Maintained
 
+LANMEDIA WAN CARD DRIVER
+P:	Andrew Stanley-Jones
+M:	asj@lanmedia.com
+W:      http://www.lanmedia.com/
+S:	Supported
+
 LAPB module
 P:	Henner Eisen
 M:	eis@baty.hanse.de
diff -urN linux-2.2.15-pre4/Makefile linux/Makefile
--- linux-2.2.15-pre4/Makefile	Mon Dec  3 21:58:24 2001
+++ linux/Makefile	Mon Dec  3 21:58:30 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 15
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.15-pre4/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- linux-2.2.15-pre4/arch/ppc/kernel/prom.c	Mon Dec  3 21:58:24 2001
+++ linux/arch/ppc/kernel/prom.c	Mon Dec  3 21:58:30 2001
@@ -608,6 +608,7 @@
 		else
 			prom_print(RELOC("...failed\n"));
 	}
+#endif /* CONFIG_SMP */
 	
 	/* If OpenFirmware version >= 3, then use quiesce call */
 	if (RELOC(prom_version) >= 3) {
@@ -617,7 +618,6 @@
 	    phys = offset + KERNELBASE;
 	}
 
-#endif	
 	return phys;
 }
 
diff -urN linux-2.2.15-pre4/arch/sparc64/kernel/sys32.S linux/arch/sparc64/kernel/sys32.S
--- linux-2.2.15-pre4/arch/sparc64/kernel/sys32.S	Mon Nov 16 10:37:28 1998
+++ linux/arch/sparc64/kernel/sys32.S	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $
+/* $Id: sys32.S,v 1.8.2.1 2000/01/24 11:36:55 jj Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
@@ -20,7 +20,7 @@
 
 	.align		32
 	.globl		sys32_lseek
-	.globl		sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod
+	.globl		sys32_chmod, sys32_mknod
 sys32_lseek:
 	sra		%o1, 0, %o1
 	sethi		%hi(sys_lseek), %g1
@@ -32,20 +32,6 @@
 	orcc		%g2, %lo(0xffff), %g2
 	jmpl		%g1 + %lo(sys_chmod), %g0
 	 and		%o1, %g2, %o1
-sys32_chown:
-	sethi		%hi(0xffff), %g2
-	sethi		%hi(sys_chown), %g1
-	orcc		%g2, %lo(0xffff), %g2
-	and		%o1, %g2, %o1
-	jmpl		%g1 + %lo(sys_chown), %g0
-	 and		%o2, %g2, %o2
-sys32_lchown:
-	sethi		%hi(0xffff), %g2
-	sethi		%hi(sys_lchown), %g1
-	orcc		%g2, %lo(0xffff), %g2
-	and		%o1, %g2, %o1
-	jmpl		%g1 + %lo(sys_lchown), %g0
-	 and		%o2, %g2, %o2
 sys32_mknod:
 	sethi		%hi(0xffff), %g2
 	sethi		%hi(sys_mknod), %g1
diff -urN linux-2.2.15-pre4/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.2.15-pre4/arch/sparc64/kernel/sys_sparc32.c	Mon Dec  3 21:58:24 2001
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.5 1999/11/12 11:17:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.7 2000/01/24 11:36:50 jj Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1890,15 +1890,14 @@
 	return ret;
 }
 
+#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
+#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
+
 extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid);
 
 asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
 {
-	uid_t sruid, seuid;
-
-	sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	return sys_setreuid(sruid, seuid);
+	return sys_setreuid(low2highuid(ruid), low2highuid(euid));
 }
 
 extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
@@ -1907,12 +1906,7 @@
 			       __kernel_uid_t32 euid,
 			       __kernel_uid_t32 suid)
 {
-	uid_t sruid, seuid, ssuid;
-
-	sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid);
-	return sys_setresuid(sruid, seuid, ssuid);
+	return sys_setresuid(low2highuid(ruid), low2highuid(euid), low2highuid(suid));
 }
 
 extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
@@ -1935,11 +1929,7 @@
 
 asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
 {
-	gid_t srgid, segid;
-
-	srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	return sys_setregid(srgid, segid);
+	return sys_setregid(low2highgid(rgid), low2highgid(egid));
 }
 
 extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
@@ -1948,12 +1938,7 @@
 			       __kernel_gid_t32 egid,
 			       __kernel_gid_t32 sgid)
 {
-	gid_t srgid, segid, ssgid;
-
-	srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
-	return sys_setresgid(srgid, segid, ssgid);
+	return sys_setresgid(low2highgid(rgid), low2highgid(egid), low2highgid(sgid));
 }
 
 extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
@@ -1973,6 +1958,25 @@
 		ret |= put_user (c, sgid);
 	}
 	return ret;
+}
+
+extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
+
+asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group)
+{
+	return sys_chown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group)
+{
+	return sys_lchown(filename, low2highuid(user), low2highgid(group));
+}
+                
+asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+{
+	return sys_fchown(fd, low2highuid(user), low2highgid(group));
 }
 
 struct tms32 {
diff -urN linux-2.2.15-pre4/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- linux-2.2.15-pre4/arch/sparc64/kernel/systbls.S	Tue Oct 26 17:53:39 1999
+++ linux/arch/sparc64/kernel/systbls.S	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.53.2.1 1999/09/22 11:37:39 jj Exp $
+/* $Id: systbls.S,v 1.53.2.3 2000/01/24 22:14:40 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -21,8 +21,8 @@
 sys_call_table32:
 /*0*/	.word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/	.word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
-/*15*/	.word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod
+/*15*/	.word sys32_chmod, sys32_lchown16, sparc_brk, sys_perfctr, sys32_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/	.word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
 /*30*/	.word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -43,7 +43,7 @@
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
 /*110*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+/*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall
@@ -143,7 +143,7 @@
 	.word sys_close, sunos_wait4, sys_creat
 	.word sys_link, sys_unlink, sunos_execv
 	.word sys_chdir, sunos_nosys, sys32_mknod
-	.word sys32_chmod, sys32_lchown, sunos_brk
+	.word sys32_chmod, sys32_lchown16, sunos_brk
 	.word sunos_nosys, sys32_lseek, sunos_getpid
 	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_getuid, sunos_nosys, sys_ptrace
@@ -179,7 +179,7 @@
 	.word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
 	.word sunos_nosys, sys32_gettimeofday, sys32_getrusage
 	.word sunos_getsockopt, sunos_nosys, sunos_readv
-	.word sunos_writev, sys32_settimeofday, sys_fchown
+	.word sunos_writev, sys32_settimeofday, sys32_fchown16
 	.word sys_fchmod, sys32_recvfrom, sys32_setreuid
 	.word sys_setregid, sys_rename, sys_truncate
 	.word sys_ftruncate, sys_flock, sunos_nosys
diff -urN linux-2.2.15-pre4/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- linux-2.2.15-pre4/drivers/block/ide-cd.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/block/ide-cd.c	Mon Dec  3 21:58:30 2001
@@ -2567,14 +2567,51 @@
 	return cdrom_lockdoor (drive, lock, NULL);
 }
 
+/*
+ * the buffer struct used by ide_cdrom_get_capabilities()
+ */
+struct get_capabilities_buf {
+	char pad[8];
+	struct atapi_capabilities_page cap;	/* this is 4 bytes short of ATAPI standard */
+	char extra_cap[4];			/* Acer 50X needs the regulation size buffer */
+};
+
+static
+int ide_cdrom_get_capabilities (ide_drive_t *drive, struct get_capabilities_buf *buf)
+{
+	int stat, attempts = 3, buflen = sizeof(*buf);
+
+	/*
+	 * Most drives don't care about the buffer size; they return as much info as there's room for.
+	 * But some older drives (?) had trouble with the standard size, preferring 4 bytes less.
+	 * And the modern Acer 50X rejects anything smaller than the standard size.
+	 */
+	if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX")))
+		buflen -= sizeof(buf->extra_cap);	/* for all drives except Acer 50X */
+
+	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+		stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, (char *)buf, buflen, NULL);
+		if (stat == 0) {
+			/*
+			 * The ACER/AOpen 24X cdrom has the speed fields byte-swapped from the standard.
+			 */
+			if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) {
+				buf->cap.curspeed = ntohs(buf->cap.curspeed);
+				buf->cap.maxspeed = ntohs(buf->cap.maxspeed);
+			}
+			CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176;
+			CDROM_CONFIG_FLAGS(drive)->max_speed     = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176;
+			return 0;
+		}
+	} while (--attempts);
+	return stat;
+}
+
 static
 int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
 {
-        int stat, attempts = 3;
-        struct {
-                char pad[8];
-                struct atapi_capabilities_page cap;
-        } buf;
+	int stat;
+	struct get_capabilities_buf	buf;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct atapi_request_sense reqbuf;
 	stat=cdrom_select_speed (drive, speed, &reqbuf);
@@ -2582,25 +2619,9 @@
 		return stat;
 
 	/* Now with that done, update the speed fields */
-        do {    /* we seem to get stat=0x01,err=0x00 the first time (??) */
-                if (attempts-- <= 0)
-                        return 0;
-                stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
-                                        (char *)&buf, sizeof (buf), NULL);
-        } while (stat);
-
-        /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-        if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-                CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
-        } else {
-                CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
-                CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
-        }
+	if (ide_cdrom_get_capabilities(drive,&buf))
+		return 0;
+
         cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
         return 0;
 }
@@ -2894,11 +2915,8 @@
 static
 int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
-	int stat, nslots = 0, attempts = 3;
- 	struct {
-		char pad[8];
-		struct atapi_capabilities_page cap;
-	} buf;
+	int stat, nslots = 0;
+	struct get_capabilities_buf	buf;
 
 	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
 		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
@@ -2906,13 +2924,8 @@
 		return nslots;
 	}
 
-	do {	/* we seem to get stat=0x01,err=0x00 the first time (??) */
-		if (attempts-- <= 0)
-			return 0;
-		stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
-				 	(char *)&buf, sizeof (buf), NULL);
-	} while (stat);
-
+	if (ide_cdrom_get_capabilities(drive,&buf))
+		return 0;
 	if (buf.cap.lock == 0)
 		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
 	if (buf.cap.eject)
@@ -2953,19 +2966,6 @@
 			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
 			nslots = mechbuf.nslots;
 		}
-	}
-
-	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
-	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
-			(ntohs(buf.cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
-			(ntohs(buf.cap.maxspeed) + (176/2)) / 176;
 	}
 
 	printk ("%s: ATAPI %dX %s", 
diff -urN linux-2.2.15-pre4/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- linux-2.2.15-pre4/drivers/block/ide-probe.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/block/ide-probe.c	Mon Dec  3 21:58:30 2001
@@ -279,6 +279,7 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
+	delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
 	SELECT_DRIVE(hwif,drive);
 	delay_50ms();
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
diff -urN linux-2.2.15-pre4/drivers/char/Config.in linux/drivers/char/Config.in
--- linux-2.2.15-pre4/drivers/char/Config.in	Mon Dec  3 21:58:24 2001
+++ linux/drivers/char/Config.in	Mon Dec  3 21:58:30 2001
@@ -141,7 +141,7 @@
   dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
   dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
-    hex '  GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+    hex '  GemTek i/o port (0x20c, 0x24c, 0x248, 0x30c, or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
   fi
   dep_tristate 'Trust FM Radio' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
diff -urN linux-2.2.15-pre4/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux-2.2.15-pre4/drivers/char/n_tty.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/char/n_tty.c	Mon Dec  3 21:58:30 2001
@@ -1094,7 +1094,9 @@
 				nr -= num;
 				if (nr == 0)
 					break;
+				current->state = TASK_RUNNING;
 				get_user(c, b);
+				current->state = TASK_INTERRUPTIBLE;
 				if (opost(c, tty) < 0)
 					break;
 				b++; nr--;
@@ -1102,7 +1104,9 @@
 			if (tty->driver.flush_chars)
 				tty->driver.flush_chars(tty);
 		} else {
+			current->state = TASK_RUNNING;
 			c = tty->driver.write(tty, 1, b, nr);
+			current->state = TASK_INTERRUPTIBLE;
 			if (c < 0) {
 				retval = c;
 				goto break_out;
diff -urN linux-2.2.15-pre4/drivers/char/radio-gemtek.c linux/drivers/char/radio-gemtek.c
--- linux-2.2.15-pre4/drivers/char/radio-gemtek.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/char/radio-gemtek.c	Mon Dec  3 21:58:30 2001
@@ -282,7 +282,7 @@
 MODULE_AUTHOR("Jonas Munsin");
 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
 MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (or 0x248 for the combined sound/radiocard))");
+MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
 
 EXPORT_NO_SYMBOLS;
 
@@ -290,7 +290,7 @@
 {
 	if(io==-1)
 	{
-		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n");
+		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x20c or io=0x248 for the combined sound/radiocard)\n");
 		return -EINVAL;
 	}
 	return gemtek_init(NULL);
diff -urN linux-2.2.15-pre4/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- linux-2.2.15-pre4/drivers/isdn/Config.in	Tue Jan  4 10:12:15 2000
+++ linux/drivers/isdn/Config.in	Mon Dec  3 21:58:30 2001
@@ -12,68 +12,87 @@
 if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
    bool '    Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
 fi
-bool '  Support isdn diversion services' CONFIG_ISDN_DIVERSION
 if [ "$CONFIG_X25" != "n" ]; then
    bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
 fi
-dep_tristate '  ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate '  isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate '  PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate '  HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+
+mainmenu_option next_comment
+comment 'ISDN feature submodules'
+   dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+   bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+endmenu
+
+comment 'low-level hardware drivers'
+
+mainmenu_option next_comment
+comment 'Passive ISDN cards'
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
-   bool '    HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+   comment '  D-channel protocol features'
+   bool '  HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
    if [ "$CONFIG_HISAX_EURO" != "n" ]; then
-      bool '      Support for german chargeinfo' CONFIG_DE_AOC
-      bool '      Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
-      bool '      Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+      bool '    Support for german chargeinfo' CONFIG_DE_AOC
+      bool '    Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+      bool '    Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+      bool '    Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
    fi
-   bool '    HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
-   bool '    HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
-   bool '    HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
-   bool '    HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI 
-   bool '    HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
-   bool '    HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
-   bool '    HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
-   bool '    HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
-   bool '    HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
-   bool '    HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
-   bool '    HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
-   bool '    HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
-   bool '    HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
-   bool '    HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
-   bool '    HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
-   bool '    HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
-   bool '    HiSax Support for MIC card' CONFIG_HISAX_MIC
-   bool '    HiSax Support for NETjet card' CONFIG_HISAX_NETJET
-   bool '    HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
-   bool '    HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
-   bool '    HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
-   bool '    HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
-   bool '    HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
-   bool '    HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
-   bool '    HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
-   bool '    HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692
+   bool '  HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+   comment '  HiSax supported cards'
+   bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
+   bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+   bool '  Teles PCI' CONFIG_HISAX_TELESPCI 
+   bool '  Teles S0Box' CONFIG_HISAX_S0BOX 
+   bool '  AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+   bool '  AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+   bool '  AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+   bool '  Elsa cards' CONFIG_HISAX_ELSA
+   bool '  ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+   bool '  Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+   bool '  ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+   bool '  TELEINT cards' CONFIG_HISAX_TELEINT
+   bool '  HFC-S based cards' CONFIG_HISAX_HFCS
+   bool '  Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+   bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+   bool '  MIC card' CONFIG_HISAX_MIC
+   bool '  NETjet card' CONFIG_HISAX_NETJET
+   bool '  Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+   bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
+   bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+   bool '  Telekom A4T card' CONFIG_HISAX_BKM_A4T
+   bool '  Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+   bool '  Gazel cards' CONFIG_HISAX_GAZEL
+   bool '  HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+   bool '  Winbond W6692 based cards' CONFIG_HISAX_W6692
    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-#      bool '    HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      bool '  HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
+#      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-	 bool '    HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
    fi
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Active ISDN cards'
+dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-   dep_tristate '  Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
-   dep_tristate '  IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+   dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+   dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
 fi
-dep_tristate '  Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
-   bool '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+   bool '  Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
 fi
-dep_tristate '  AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
-   bool '    AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
-   bool '    AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
-   bool '    AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
-   bool '    AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-   bool '    AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
-   bool '    Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   bool '  AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+   bool '  AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+   bool '  AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+   bool '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+   bool '  AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+   bool '  AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4
+   bool '  Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
 fi
+endmenu
diff -urN linux-2.2.15-pre4/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- linux-2.2.15-pre4/drivers/isdn/avmb1/c4.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/avmb1/c4.c	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,1316 @@
+/*
+ * $Id: c4.c,v 1.2 2000/01/21 20:52:58 keil Exp $
+ * 
+ * Module for AVM C4 card.
+ * 
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: c4.c,v $
+ * Revision 1.2  2000/01/21 20:52:58  keil
+ * pci_find_subsys as local function for 2.2.X kernel
+ *
+ * Revision 1.1  2000/01/20 10:51:37  calle
+ * Added driver for C4.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.2 $";
+
+#undef CONFIG_C4_DEBUG
+#undef CONFIG_C4_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_DEC
+#define PCI_VENDOR_ID_DEC	0x1011
+#endif
+
+#ifndef PCI_DEVICE_ID_DEC_21285
+#define PCI_DEVICE_ID_DEC_21285	0x1065
+#endif
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM	0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_C4
+#define PCI_DEVICE_ID_AVM_C4	0x0800
+#endif
+
+/* ------------------------------------------------------------- */
+
+int suppress_pollack = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+#define DC21285_DRAM_A0MR	0x40000000
+#define DC21285_DRAM_A1MR	0x40004000
+#define DC21285_DRAM_A2MR	0x40008000
+#define DC21285_DRAM_A3MR	0x4000C000
+
+#define	CAS_OFFSET	0x88
+
+#define DC21285_ARMCSR_BASE	0x42000000
+
+#define	PCI_OUT_INT_STATUS	0x30
+#define	PCI_OUT_INT_MASK	0x34
+#define	MAILBOX_0		0x50
+#define	MAILBOX_1		0x54
+#define	MAILBOX_2		0x58
+#define	MAILBOX_3		0x5C
+#define	DOORBELL		0x60
+#define	DOORBELL_SETUP		0x64
+
+#define CHAN_1_CONTROL		0x90
+#define CHAN_2_CONTROL		0xB0
+#define DRAM_TIMING		0x10C
+#define DRAM_ADDR_SIZE_0	0x110
+#define DRAM_ADDR_SIZE_1	0x114
+#define DRAM_ADDR_SIZE_2	0x118
+#define DRAM_ADDR_SIZE_3	0x11C
+#define	SA_CONTROL		0x13C
+#define	XBUS_CYCLE		0x148
+#define	XBUS_STROBE		0x14C
+#define	DBELL_PCI_MASK		0x150
+#define DBELL_SA_MASK		0x154
+
+#define SDRAM_SIZE		0x1000000
+
+/* ------------------------------------------------------------- */
+
+#define	MBOX_PEEK_POKE		MAILBOX_0
+
+#define DBELL_ADDR		0x01
+#define DBELL_DATA		0x02
+#define DBELL_RNWR		0x40
+#define DBELL_INIT		0x80
+
+/* ------------------------------------------------------------- */
+
+#define	MBOX_UP_ADDR		MAILBOX_0
+#define	MBOX_UP_LEN		MAILBOX_1
+#define	MBOX_DOWN_ADDR		MAILBOX_2
+#define	MBOX_DOWN_LEN		MAILBOX_3
+
+#define	DBELL_UP_HOST		0x00000100
+#define	DBELL_UP_ARM		0x00000200
+#define	DBELL_DOWN_HOST		0x00000400
+#define	DBELL_DOWN_ARM		0x00000800
+#define	DBELL_RESET_HOST	0x40000000
+#define	DBELL_RESET_ARM		0x80000000
+
+/* ------------------------------------------------------------- */
+
+#define	DRAM_TIMING_DEF		0x001A01A5
+#define DRAM_AD_SZ_DEF0		0x00000045
+#define DRAM_AD_SZ_NULL		0x00000000
+
+#define SA_CTL_ALLRIGHT		0x64AA0271
+
+#define	INIT_XBUS_CYCLE		0x100016DB
+#define	INIT_XBUS_STROBE	0xF1F1F1F1
+
+/* ------------------------------------------------------------- */
+
+#define	RESET_TIMEOUT		(15*HZ)	/* 15 sec */
+#define	PEEK_POKE_TIMEOUT	(HZ/10)	/* 0.1 sec */
+
+/* ------------------------------------------------------------- */
+
+#define c4outmeml(addr, value)	writel(value, addr)
+#define c4inmeml(addr)	readl(addr)
+#define c4outmemw(addr, value)	writew(value, addr)
+#define c4inmemw(addr)	readw(addr)
+#define c4outmemb(addr, value)	writeb(value, addr)
+#define c4inmemb(addr)	readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int wait_for_doorbell(avmcard *card, unsigned long t)
+{
+	unsigned long stop;
+
+	stop = jiffies + t;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return -1;
+	}
+	return 0;
+}
+
+static int c4_poke(avmcard *card,  unsigned long off, unsigned long value)
+{
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+	
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+	c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, value);
+	c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR);
+
+	return 0;
+}
+
+static int c4_peek(avmcard *card,  unsigned long off, unsigned long *valuep)
+{
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+	c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR);
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	*valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
+{
+	__u32 val;
+	unsigned char *dp;
+	int left, retval;
+	__u32 loadoff = 0;
+
+	dp = t4file->data;
+	left = t4file->len;
+	while (left >= sizeof(__u32)) {
+	        if (t4file->user) {
+			retval = copy_from_user(&val, dp, sizeof(val));
+			if (retval)
+				return -EFAULT;
+		} else {
+			memcpy(&val, dp, sizeof(val));
+		}
+		if (c4_poke(card, loadoff, val)) {
+			printk(KERN_ERR "%s: corrupted firmware file ?\n",
+					card->name);
+			return -EIO;
+		}
+		left -= sizeof(__u32);
+		dp += sizeof(__u32);
+		loadoff += sizeof(__u32);
+	}
+	if (left) {
+		val = 0;
+		if (t4file->user) {
+			retval = copy_from_user(&val, dp, left);
+			if (retval)
+				return -EFAULT;
+		} else {
+			memcpy(&val, dp, left);
+		}
+		if (c4_poke(card, loadoff, val)) {
+			printk(KERN_ERR "%s: corrupted firmware file ?\n",
+					card->name);
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+	__u8 *s = *pp;
+	*s++ = val;
+	*pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+	__u8 *s = *pp;
+	*s++ = val & 0xff;
+	*s++ = (val >> 8) & 0xff;
+	*s++ = (val >> 16) & 0xff;
+	*s++ = (val >> 24) & 0xff;
+	*pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+	unsigned i = len;
+	_put_word(pp, i);
+	while (i-- > 0)
+		_put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+	__u8 *s = *pp;
+	__u8 val;
+	val = *s++;
+	*pp = s;
+	return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+	__u8 *s = *pp;
+	__u32 val;
+	val = *s++;
+	val |= (*s++ << 8);
+	val |= (*s++ << 16);
+	val |= (*s++ << 24);
+	*pp = s;
+	return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+	unsigned int len, i;
+
+	len = i = _get_word(pp);
+	while (i-- > 0) *dp++ = _get_byte(pp);
+	return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_reset(avmcard *card)
+{
+	unsigned long stop;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+	stop = jiffies + HZ*10;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return;
+		c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+	}
+
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_detect(avmcard *card)
+{
+	unsigned long stop, dummy;
+
+	c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+	if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c)
+		return	1;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+	stop = jiffies + HZ*10;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return 2;
+		c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+	}
+
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+
+	c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa);
+	if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3;
+
+	c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55);
+	if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4;
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT))
+		return 7;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE))
+		return 8;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE))
+		return 8;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
+
+        udelay(1000);
+
+	if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
+	if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
+	if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
+	if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
+
+	if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14;
+	if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15;
+	if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
+	if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
+
+        udelay(1000);
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
+		return 18;
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0))
+		return 19;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL))
+		return 20;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL))
+		return 21;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL))
+		return 22;
+
+	/* Transputer test */
+	
+	if (   c4_poke(card, 0x000000, 0x11111111)
+	    || c4_poke(card, 0x400000, 0x22222222)
+	    || c4_poke(card, 0x800000, 0x33333333)
+	    || c4_poke(card, 0xC00000, 0x44444444))
+		return 23;
+
+	if (   c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
+	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
+	    || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
+	    || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
+		return 24;
+
+	if (   c4_poke(card, 0x000000, 0x55555555)
+	    || c4_poke(card, 0x400000, 0x66666666)
+	    || c4_poke(card, 0x800000, 0x77777777)
+	    || c4_poke(card, 0xC00000, 0x88888888))
+		return 25;
+
+	if (   c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
+	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
+	    || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
+	    || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
+		return 26;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	unsigned long flags;
+	struct sk_buff *skb;
+	__u8 cmd, subcmd;
+	__u16 len;
+	__u32 txlen;
+	void *p;
+	
+	save_flags(flags);
+	cli();
+
+	if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
+	        restore_flags(flags);
+		return;
+	}
+
+	skb = skb_dequeue(&dma->send_queue);
+	if (!skb) {
+#ifdef CONFIG_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx underrun\n", card->name);
+#endif
+	        restore_flags(flags);
+		return;
+	}
+
+	len = CAPIMSG_LEN(skb->data);
+
+	if (len) {
+		cmd = CAPIMSG_COMMAND(skb->data);
+		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+		p = dma->sendbuf;
+
+		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+			__u16 dlen = CAPIMSG_DATALEN(skb->data);
+			_put_byte(&p, SEND_DATA_B3_REQ);
+			_put_slice(&p, skb->data, len);
+			_put_slice(&p, skb->data + len, dlen);
+		} else {
+			_put_byte(&p, SEND_MESSAGE);
+			_put_slice(&p, skb->data, len);
+		}
+		txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
+#endif
+	} else {
+		txlen = skb->len-2;
+#ifdef CONFIG_C4_POLLDEBUG
+		if (skb->data[2] == SEND_POLLACK)
+			printk(KERN_INFO "%s: ack to c4\n", card->name);
+#endif
+#ifdef CONFIG_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
+				card->name, skb->data[2], txlen);
+#endif
+		memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+	}
+	txlen = (txlen + 3) & ~3;
+
+	c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf));
+	c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
+
+	card->csr |= DBELL_DOWN_ARM;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
+
+	restore_flags(flags);
+	dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(3, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_POLLACK);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_rx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	struct capi_ctr *ctrl;
+	avmctrl_info *cinfo;
+	struct sk_buff *skb;
+	void *p = dma->recvbuf;
+	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	__u8 b1cmd =  _get_byte(&p);
+	__u32 cidx;
+
+
+#ifdef CONFIG_C4_DEBUG
+	printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
+				b1cmd, (unsigned long)dma->recvlen);
+#endif
+	
+	switch (b1cmd) {
+	case RECEIVE_DATA_B3_IND:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		DataB3Len = _get_slice(&p, card->databuf);
+		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+		if (cidx > 3) cidx = 0;
+		ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+		if (MsgLen < 30) { /* not CAPI 64Bit */
+			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+			MsgLen = 30;
+			CAPIMSG_SETLEN(card->msgbuf, 30);
+		}
+		if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+			ctrl->handle_capimsg(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_MESSAGE:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+		if (cidx > 3) cidx = 0;
+		ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			ctrl->handle_capimsg(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_NEW_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+		WindowSize = _get_word(&p);
+		cidx = (NCCI&0x7f) - card->cardnr;
+		if (cidx > 3) cidx = 0;
+		ctrl = card->ctrlinfo[cidx].capi_ctrl;
+
+		ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+		break;
+
+	case RECEIVE_FREE_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+
+		if (NCCI != 0xffffffff) {
+			cidx = (NCCI&0x7f) - card->cardnr;
+			if (cidx > 3) cidx = 0;
+			ctrl = card->ctrlinfo[cidx].capi_ctrl;
+			ctrl->free_ncci(ctrl, ApplId, NCCI);
+		} else {
+			for (cidx=0; cidx < 4; cidx++) {
+				ctrl = card->ctrlinfo[cidx].capi_ctrl;
+				ctrl->appl_released(ctrl, ApplId);
+			}
+		}
+		break;
+
+	case RECEIVE_START:
+#ifdef CONFIG_C4_POLLDEBUG
+		printk(KERN_INFO "%s: poll from c4\n", card->name);
+#endif
+		if (!suppress_pollack)
+			queue_pollack(card);
+		for (cidx=0; cidx < 4; cidx++) {
+			ctrl = card->ctrlinfo[cidx].capi_ctrl;
+			ctrl->resume_output(ctrl);
+		}
+		break;
+
+	case RECEIVE_STOP:
+		for (cidx=0; cidx < 4; cidx++) {
+			ctrl = card->ctrlinfo[cidx].capi_ctrl;
+			ctrl->suspend_output(ctrl);
+		}
+		break;
+
+	case RECEIVE_INIT:
+
+	        cidx = card->nlogcontr++;
+	        cinfo = &card->ctrlinfo[cidx];
+		ctrl = cinfo->capi_ctrl;
+		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+		b1_parse_version(cinfo);
+		printk(KERN_INFO "%s: %s-card (%s) now active\n",
+		       card->name,
+		       cinfo->version[VER_CARDTYPE],
+		       cinfo->version[VER_DRIVER]);
+		ctrl->ready(cinfo->capi_ctrl);
+		break;
+
+	case RECEIVE_TASK_READY:
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen--] = 0;
+		while (    MsgLen >= 0
+		       && (   card->msgbuf[MsgLen] == '\n'
+			   || card->msgbuf[MsgLen] == '\r'))
+			card->msgbuf[MsgLen--] = 0;
+		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+				card->name, ApplId, card->msgbuf);
+		break;
+
+	case RECEIVE_DEBUGMSG:
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen--] = 0;
+		while (    MsgLen >= 0
+		       && (   card->msgbuf[MsgLen] == '\n'
+			   || card->msgbuf[MsgLen] == '\r'))
+			card->msgbuf[MsgLen--] = 0;
+		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+		break;
+
+	default:
+		printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n",
+				card->name, b1cmd);
+		return;
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_interrupt(avmcard *card)
+{
+	__u32 status = c4inmeml(card->mbase+DOORBELL);
+
+	if (status & DBELL_RESET_HOST) {
+		int i;
+		c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+		printk(KERN_ERR "%s: unexpected reset\n", card->name);
+                for (i=0; i < 4; i++) {
+			avmctrl_info *cinfo = &card->ctrlinfo[i];
+			memset(cinfo->version, 0, sizeof(cinfo->version));
+			if (cinfo->capi_ctrl)
+				cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+		}
+		return;
+	}
+
+	status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
+	if (!status)
+		return;
+	c4outmeml(card->mbase+DOORBELL, status);
+
+	if ((status & DBELL_UP_HOST) != 0) {
+		card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN);
+		c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+		c4_handle_rx(card);
+		card->dma->recvlen = 0;
+		c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+		c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+	}
+
+	if ((status & DBELL_DOWN_HOST) != 0) {
+		card->csr &= ~DBELL_DOWN_ARM;
+	        c4_dispatch_tx(card);
+	} else if (card->csr & DBELL_DOWN_HOST) {
+		if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) {
+		        card->csr &= ~DBELL_DOWN_ARM;
+			c4_dispatch_tx(card);
+		}
+	}
+}
+
+static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+	avmcard *card;
+
+	card = (avmcard *) devptr;
+
+	if (!card) {
+		printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name);
+		return;
+	}
+	if (card->interrupt) {
+		printk(KERN_ERR "%s: reentering interrupt hander\n",
+				card->name);
+		return;
+	}
+
+	card->interrupt = 1;
+
+	c4_handle_interrupt(card);
+
+	card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_send_init(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(15, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_INIT);
+	_put_word(&p, AVM_NAPPS);
+	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+	_put_word(&p, card->cardnr - 1);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+	struct sk_buff *skb;
+	__u8 val[sizeof(__u32)];
+	void *p;
+	unsigned char *dp;
+	int left, retval;
+	
+	skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, can't send config.\n",
+					card->name);
+		return	-ENOMEM;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_CONFIG);
+	_put_word(&p, 1);
+	_put_byte(&p, SEND_CONFIG);
+	_put_word(&p, config->len);	/* 12 */
+
+	dp = config->data;
+	left = config->len;
+	while (left >= sizeof(__u32)) {
+	        if (config->user) {
+			retval = copy_from_user(val, dp, sizeof(val));
+			if (retval) {
+				dev_kfree_skb(skb);
+				return -EFAULT;
+			}
+		} else {
+			memcpy(val, dp, sizeof(val));
+		}
+		_put_byte(&p, SEND_CONFIG);
+		_put_byte(&p, val[0]);
+		_put_byte(&p, val[1]);
+		_put_byte(&p, val[2]);
+		_put_byte(&p, val[3]);
+		left -= sizeof(val);
+		dp += sizeof(val);
+	}
+	if (left) {
+		memset(val, 0, sizeof(val));
+		if (config->user) {
+			retval = copy_from_user(&val, dp, left);
+			if (retval) {
+				dev_kfree_skb(skb);
+				return -EFAULT;
+			}
+		} else {
+			memcpy(&val, dp, left);
+		}
+		_put_byte(&p, SEND_CONFIG);
+		_put_byte(&p, val[0]);
+		_put_byte(&p, val[1]);
+		_put_byte(&p, val[2]);
+		_put_byte(&p, val[3]);
+	}
+
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+
+	return 0;
+}
+
+static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned long flags;
+	int retval;
+
+	if ((retval = c4_load_t4file(card, &data->firmware))) {
+		printk(KERN_ERR "%s: failed to load t4file!!\n",
+					card->name);
+		c4_reset(card);
+		return retval;
+	}
+
+	save_flags(flags);
+	cli();
+
+	card->csr = 0;
+	c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+	c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
+	c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
+	udelay(1000);
+	c4outmeml(card->mbase+DOORBELL,
+			DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
+
+	c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
+
+	card->dma->recvlen = 0;
+	c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf));
+	c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf));
+	c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+	restore_flags(flags);
+
+	if (data->configuration.len > 0 && data->configuration.data)
+		c4_send_config(card, &data->configuration);
+
+        c4_send_init(card);
+
+	return 0;
+}
+
+
+void c4_reset_ctr(struct capi_ctr *ctrl)
+{
+	avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+	avmctrl_info *cinfo;
+	int i;
+
+ 	c4_reset(card);
+
+        for (i=0; i < 4; i++) {
+		cinfo = &card->ctrlinfo[i];
+		memset(cinfo->version, 0, sizeof(cinfo->version));
+		if (cinfo->capi_ctrl)
+			cinfo->capi_ctrl->reseted(cinfo->capi_ctrl);
+	}
+}
+
+static void c4_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+	avmctrl_info *cinfo;
+	int i;
+
+ 	c4_reset(card);
+
+        for (i=0; i <= 4; i++) {
+		cinfo = &card->ctrlinfo[i];
+		if (cinfo->capi_ctrl)
+			di->detach_ctr(cinfo->capi_ctrl);
+	}
+
+	free_irq(card->irq, card);
+	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	kfree(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+
+void c4_register_appl(struct capi_ctr *ctrl,
+				__u16 appl,
+				capi_register_params *rp)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	int want = rp->level3cnt;
+	int nconn;
+	void *p;
+
+	if (ctrl->cnr == card->cardnr) {
+
+		if (want > 0) nconn = want;
+		else nconn = ctrl->profile.nbchannel * 4 * -want;
+		if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
+
+		skb = alloc_skb(23, GFP_ATOMIC);
+		if (!skb) {
+			printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+						card->name);
+			return;
+		}
+		p = skb->data;
+		_put_byte(&p, 0);
+		_put_byte(&p, 0);
+		_put_byte(&p, SEND_REGISTER);
+		_put_word(&p, appl);
+		_put_word(&p, 1024 * (nconn+1));
+		_put_word(&p, nconn);
+		_put_word(&p, rp->datablkcnt);
+		_put_word(&p, rp->datablklen);
+		skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+		skb_queue_tail(&card->dma->send_queue, skb);
+		c4_dispatch_tx(card);
+	}
+
+	ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void c4_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	void *p;
+
+	if (ctrl->cnr == card->cardnr) {
+		skb = alloc_skb(7, GFP_ATOMIC);
+		if (!skb) {
+			printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+						card->name);
+			return;
+		}
+		p = skb->data;
+		_put_byte(&p, 0);
+		_put_byte(&p, 0);
+		_put_byte(&p, SEND_RELEASE);
+		_put_word(&p, appl);
+
+		skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+		skb_queue_tail(&card->dma->send_queue, skb);
+		c4_dispatch_tx(card);
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+
+static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *c4_procinfo(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->membase : 0
+		);
+	return cinfo->infobuf;
+}
+
+static int c4_read_proc(char *page, char **start, off_t off,
+        		int count, int *eof, struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	__u8 flag;
+	int len = 0;
+	char *s;
+
+	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+	len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+	len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+	switch (card->cardtype) {
+	case avm_b1isa: s = "B1 ISA"; break;
+	case avm_b1pci: s = "B1 PCI"; break;
+	case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+	case avm_m1: s = "M1"; break;
+	case avm_m2: s = "M2"; break;
+	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+	case avm_t1pci: s = "T1 PCI"; break;
+	case avm_c4: s = "C4"; break;
+	default: s = "???"; break;
+	}
+	len += sprintf(page+len, "%-16s %s\n", "type", s);
+	if ((s = cinfo->version[VER_DRIVER]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+	if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+	if ((s = cinfo->version[VER_SERIAL]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+	if (card->cardtype != avm_m1) {
+        	flag = ((__u8 *)(ctrl->profile.manu))[3];
+        	if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+			"protocol",
+			(flag & 0x01) ? " DSS1" : "",
+			(flag & 0x02) ? " CT1" : "",
+			(flag & 0x04) ? " VN3" : "",
+			(flag & 0x08) ? " NI1" : "",
+			(flag & 0x10) ? " AUSTEL" : "",
+			(flag & 0x20) ? " ESS" : "",
+			(flag & 0x40) ? " 1TR6" : ""
+			);
+	}
+	if (card->cardtype != avm_m1) {
+        	flag = ((__u8 *)(ctrl->profile.manu))[5];
+		if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s\n",
+			"linetype",
+			(flag & 0x01) ? " point to point" : "",
+			(flag & 0x02) ? " point to multipoint" : "",
+			(flag & 0x08) ? " leased line without D-channel" : "",
+			(flag & 0x04) ? " leased line with D-channel" : ""
+			);
+	}
+	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+	if (off+count >= len)
+	   *eof = 1;
+	if (len < off)
+           return 0;
+	*start = page + off;
+	return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+	unsigned long page_offset, base;
+	avmctrl_info *cinfo;
+	avmcard *card;
+	int retval;
+	int i;
+
+	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+	if (!card) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(avmcard));
+	card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+	if (!card->dma) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(card->dma, 0, sizeof(avmcard_dmainfo));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
+	if (!cinfo) {
+		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -ENOMEM;
+	}
+	memset(cinfo, 0, sizeof(avmctrl_info)*4);
+	card->ctrlinfo = cinfo;
+	for (i=0; i < 4; i++) {
+		cinfo = &card->ctrlinfo[i];
+		cinfo->card = card;
+	}
+	sprintf(card->name, "c4-%x", p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->membase = p->membase;
+	card->cardtype = avm_c4;
+
+	if (check_region(card->port, AVMB1_PORTLEN)) {
+		printk(KERN_WARNING
+		       "%s: ports 0x%03x-0x%03x in use.\n",
+		       driver->name, card->port, card->port + AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EBUSY;
+	}
+
+        base = card->membase & PAGE_MASK;
+	page_offset = card->membase - base;
+	card->mbase = ioremap_nocache(base, page_offset + 64);
+
+	if ((retval = c4_detect(card)) != 0) {
+		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EIO;
+	}
+	c4_reset(card);
+
+	request_region(p->port, AVMB1_PORTLEN, card->name);
+
+	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+				driver->name, card->irq);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+		release_region(card->port, AVMB1_PORTLEN);
+	        kfree(card->ctrlinfo);
+		kfree(card->dma);
+		kfree(card);
+		return -EBUSY;
+	}
+
+	for (i=0; i < 4; i++) {
+		cinfo = &card->ctrlinfo[i];
+		cinfo->card = card;
+		cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+		if (!cinfo->capi_ctrl) {
+			printk(KERN_ERR "%s: attach controller failed (%d).\n",
+					driver->name, i);
+			for (i--; i >= 0; i--) {
+				cinfo = &card->ctrlinfo[i];
+				di->detach_ctr(cinfo->capi_ctrl);
+			}
+                	iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+			free_irq(card->irq, card);
+			release_region(card->port, AVMB1_PORTLEN);
+	        	kfree(card->dma);
+	        	kfree(card->ctrlinfo);
+			kfree(card);
+			return -EBUSY;
+		}
+		if (i == 0)
+			card->cardnr = cinfo->capi_ctrl->cnr;
+	}
+
+	skb_queue_head_init(&card->dma->send_queue);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver c4_driver = {
+    "c4",
+    "0.0",
+    c4_load_firmware,
+    c4_reset_ctr,
+    c4_remove_ctr,
+    c4_register_appl,
+    c4_release_appl,
+    c4_send_message,
+
+    c4_procinfo,
+    c4_read_proc,
+    0,	/* use standard driver_read_proc */
+
+    0, /* no add_card function */
+};
+
+#ifdef MODULE
+#define c4_init init_module
+void cleanup_module(void);
+#endif
+
+#ifndef PCI_ANY_ID
+#define PCI_ANY_ID (~0)
+#endif
+
+static struct pci_dev *
+pci_find_subsys(unsigned int vendor, unsigned int device,
+		unsigned int ss_vendor, unsigned int ss_device,
+		struct pci_dev *from)
+{
+	unsigned short subsystem_vendor, subsystem_device;
+
+	while ((from = pci_find_device(vendor, device, from))) {
+		pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+		pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device);
+		if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || subsystem_device == ss_device))
+			return from;
+	}
+	return NULL;
+}
+
+static int ncards = 0;
+
+int c4_init(void)
+{
+	struct capi_driver *driver = &c4_driver;
+	struct pci_dev *dev = NULL;
+	char *p;
+	int retval;
+
+	if ((p = strchr(revision, ':'))) {
+		strncpy(driver->revision, p + 1, sizeof(driver->revision));
+		p = strchr(driver->revision, '$');
+		*p = 0;
+	}
+
+	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+        di = attach_capi_driver(driver);
+
+	if (!di) {
+		printk(KERN_ERR "%s: failed to attach capi_driver\n",
+				driver->name);
+		return -EIO;
+	}
+
+#ifdef CONFIG_PCI
+	if (!pci_present()) {
+		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+    		detach_capi_driver(driver);
+		return -EIO;
+	}
+
+	while ((dev = pci_find_subsys(
+			PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
+			PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
+		struct capicardparams param;
+
+		param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+		param.irq = dev->irq;
+		param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
+
+		printk(KERN_INFO
+			"%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
+			driver->name, param.port, param.irq, param.membase);
+		retval = c4_add_card(driver, &param);
+		if (retval != 0) {
+		        printk(KERN_ERR
+			"%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n",
+			driver->name, param.port, param.irq, param.membase);
+#ifdef MODULE
+			cleanup_module();
+#endif
+			return retval;
+		}
+		ncards++;
+	}
+	if (ncards) {
+		printk(KERN_INFO "%s: %d C4 card(s) detected\n",
+				driver->name, ncards);
+		return 0;
+	}
+	printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
+	return -ESRCH;
+#else
+	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+    detach_capi_driver(&c4_driver);
+}
+#endif
diff -urN linux-2.2.15-pre4/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
--- linux-2.2.15-pre4/drivers/isdn/eicon/eicon_idi.c	Tue Jan  4 10:12:15 2000
+++ linux/drivers/isdn/eicon/eicon_idi.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.27 1999/11/29 13:12:03 armin Exp $
+/* $Id: eicon_idi.c,v 1.28 2000/01/20 19:55:34 keil Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  *        IDI interface 
@@ -26,6 +26,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_idi.c,v $
+ * Revision 1.28  2000/01/20 19:55:34  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.27  1999/11/29 13:12:03  armin
  * Autoconnect on L2_TRANS doesn't work with link_level correctly,
  * changed back to former mode.
@@ -142,7 +145,7 @@
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.27 $";
+char *eicon_idi_revision = "$Revision: 1.28 $";
 
 eicon_manifbuf *manbuf;
 
@@ -224,7 +227,7 @@
 			reqbuf->XBuffer.P[l++] = 1;
 	}
 	switch(chan->l3prot) {
-		case ISDN_PROTO_L3_FAX:
+		case ISDN_PROTO_L3_FCLASS2:
 #ifdef CONFIG_ISDN_TTY_FAX
 			reqbuf->XBuffer.P[l++] = 6;
 			reqbuf->XBuffer.P[l++] = NLC;
diff -urN linux-2.2.15-pre4/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c
--- linux-2.2.15-pre4/drivers/isdn/eicon/eicon_mod.c	Tue Jan  4 10:12:15 2000
+++ linux/drivers/isdn/eicon/eicon_mod.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.22 1999/11/27 12:56:19 armin Exp $
+/* $Id: eicon_mod.c,v 1.23 2000/01/20 19:55:34 keil Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  * 
@@ -31,6 +31,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_mod.c,v $
+ * Revision 1.23  2000/01/20 19:55:34  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.22  1999/11/27 12:56:19  armin
  * Forgot some iomem changes for last ioremap compat.
  *
@@ -133,7 +136,7 @@
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.22 $";
+static char *eicon_revision = "$Revision: 1.23 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
@@ -669,7 +672,7 @@
 				break;
 			chan->l3prot = (c->arg >> 8);
 #ifdef CONFIG_ISDN_TTY_FAX
-			if (chan->l3prot == ISDN_PROTO_L3_FAX)
+			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
 				chan->fax = c->parm.fax;
 #endif
 			return 0;
@@ -1086,7 +1089,7 @@
 					ISDN_FEATURE_L2_MODEM |
 					ISDN_FEATURE_L2_FAX | 
 					ISDN_FEATURE_L3_TRANSDSP |
-					ISDN_FEATURE_L3_FAX;
+					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
 				card->hwif.pci.PCIreg = pcic->PCIreg;
 				card->hwif.pci.PCIcfg = pcic->PCIcfg;
@@ -1110,7 +1113,7 @@
 					ISDN_FEATURE_L2_MODEM |
 					ISDN_FEATURE_L2_FAX |
 					ISDN_FEATURE_L3_TRANSDSP |
-					ISDN_FEATURE_L3_FAX;
+					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
                                 card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
 				card->hwif.pci.PCIreg = pcic->PCIreg;
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- linux-2.2.15-pre4/drivers/isdn/hisax/Makefile	Tue Oct 26 17:53:40 1999
+++ linux/drivers/isdn/hisax/Makefile	Mon Dec  3 21:58:30 2001
@@ -137,6 +137,10 @@
 	 HFC_2BDS0 += hfc_pci.o
 endif
 
+ifeq ($(CONFIG_HISAX_HFC_SX),y)
+	 HFC_2BDS0 += hfc_sx.o
+endif
+
 ifeq ($(CONFIG_HISAX_NICCY),y)
 	 O_OBJS += niccy.o
 	 ISAC_OBJ := isac.o
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/config.c	Tue Jan  4 10:12:15 2000
+++ linux/drivers/isdn/hisax/config.c	Mon Dec  3 21:58:30 2001
@@ -1,14 +1,21 @@
-/* $Id: config.c,v 2.42 1999/12/19 13:09:41 keil Exp $
+/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
+ * Revision 2.43  2000/01/20 19:49:36  keil
+ * Support teles 13.3c vendor version 2.1
+ *
  * Revision 2.42  1999/12/19 13:09:41  keil
  * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
  * signal proof delays
  *
+ * Revision 2.41  1999/11/18 00:00:43  werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
  * Revision 2.40  1999/10/30 13:09:45  keil
  * Version 3.3c
  *
@@ -205,6 +212,7 @@
  *   34	Gazel ISDN cards
  *   35 HFC 2BDS0 PCI           none
  *   36 Winbond 6692 PCI        none
+ *   37 HFC 2BDS0 S+/SP         p0=irq p1=iobase
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
@@ -220,6 +228,7 @@
  "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
  "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
  "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+ "HFC 2BDS0 SX",
 };
 
 void HiSax_closecard(int cardnr);
@@ -355,6 +364,13 @@
 #define DEFAULT_CFG {0,0,0,0}
 #endif
 
+#ifdef CONFIG_HISAX_HFC_SX
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_HFC_SX
+#define DEFAULT_CFG {5,0x2E0,0,0}
+#endif
+
 
 #ifdef CONFIG_HISAX_AMD7930
 #undef DEFAULT_CARD
@@ -532,9 +548,9 @@
 
 	printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
 #ifdef MODULE
-	printk(KERN_INFO "HiSax: Version 3.3c (module)\n");
+	printk(KERN_INFO "HiSax: Version 3.3d (module)\n");
 #else
-	printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n");
+	printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n");
 #endif
 	strcpy(tmp, l1_revision);
 	printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -682,6 +698,10 @@
 extern int setup_hfcpci(struct IsdnCard *card);
 #endif
 
+#if CARD_HFC_SX
+extern int setup_hfcsx(struct IsdnCard *card);
+#endif
+
 #if CARD_AMD7930
 extern int setup_amd7930(struct IsdnCard *card);
 #endif
@@ -1203,6 +1223,11 @@
 				ret = setup_hfcpci(card);
 				break;
 #endif
+#if CARD_HFC_SX
+		        case ISDN_CTYPE_HFC_SX: 
+				ret = setup_hfcsx(card);
+				break;
+#endif
 #if CARD_NICCY
 			case ISDN_CTYPE_NICCY:
 				ret = setup_niccy(card);
@@ -1510,6 +1535,7 @@
 			case ISDN_CTYPE_FRITZPCI:
 			case ISDN_CTYPE_HSTSAPHIR:
 			case ISDN_CTYPE_GAZEL:
+		        case ISDN_CTYPE_HFC_SX:
 				cards[i].para[0] = irq[i];
 				cards[i].para[1] = io[i];
 				break;
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/hfc_sx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hfc_sx.c	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,1584 @@
+/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $
+
+ * hfc_sx.c     low level driver for CCD´s hfc-s+/sp based cards
+ *
+ * Author     Werner Cornelius (werner@isdn4linux.de)
+ *            based on existing driver for CCD HFC PCI cards
+ *
+ * Copyright 1999  by Werner Cornelius (werner@isdn4linux.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hfc_sx.c,v $
+ * Revision 1.3  2000/01/20 19:49:36  keil
+ * Support teles 13.3c vendor version 2.1
+ *
+ * Revision 1.2  1999/12/19 13:09:42  keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.1  1999/11/18 00:09:18  werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_sx.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+extern const char *CardType[];
+
+static const char *hfcsx_revision = "$Revision: 1.3 $";
+
+/***************************************/
+/* IRQ-table for CCDs demo board       */
+/* IRQs 6,5,10,11,12,15 are supported  */
+/***************************************/
+
+/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
+ *
+ * Thanks to Uwe Wisniewski
+ *
+ * ISA-SLOT  Signal      PIN
+ * B25        IRQ3     92 IRQ_G
+ * B23        IRQ5     94 IRQ_A
+ * B4         IRQ2/9   95 IRQ_B
+ * D3         IRQ10    96 IRQ_C
+ * D4         IRQ11    97 IRQ_D
+ * D5         IRQ12    98 IRQ_E
+ * D6         IRQ15    99 IRQ_F
+ */
+
+#undef CCD_DEMO_BOARD
+#ifdef CCD_DEMO_BOARD
+static u_char ccd_sp_irqtab[16] = {
+  0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
+};
+#else /* Teles 16.3c */
+static u_char ccd_sp_irqtab[16] = {
+  0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
+};
+#endif
+#define NT_T1_COUNT 20		/* number of 3.125ms interrupts for G2 timeout */
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/******************************/
+/* In/Out access to registers */
+/******************************/
+static inline void
+Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
+{       register int flags;
+
+        save_flags(flags);
+	cli();
+        byteout(cs->hw.hfcsx.base+1, regnum);
+	byteout(cs->hw.hfcsx.base, val);
+	restore_flags(flags);
+} 
+
+static inline u_char
+Read_hfc(struct IsdnCardState *cs, u_char regnum)
+{       register int flags;
+        register u_char ret; 
+
+        save_flags(flags);
+	cli();
+        byteout(cs->hw.hfcsx.base+1, regnum);
+	ret = bytein(cs->hw.hfcsx.base);
+	restore_flags(flags);
+	return(ret);
+} 
+
+
+/**************************************************/
+/* select a fifo and remember which one for reuse */
+/**************************************************/
+static void
+fifo_select(struct IsdnCardState *cs, u_char fifo)
+{       int flags;
+
+        if (fifo == cs->hw.hfcsx.last_fifo) 
+	  return; /* still valid */
+
+	save_flags(flags);
+	cli();
+        byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL);
+	byteout(cs->hw.hfcsx.base, fifo);
+	while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+	udelay(4);
+	byteout(cs->hw.hfcsx.base, fifo);
+	while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+	restore_flags(flags);
+}
+
+/******************************************/
+/* reset the specified fifo to defaults.  */
+/* If its a send fifo init needed markers */
+/******************************************/
+static void
+reset_fifo(struct IsdnCardState *cs, u_char fifo)
+{       int flags;
+
+        save_flags(flags); 
+	cli();
+	fifo_select(cs, fifo); /* first select the fifo */
+	byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
+	byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
+	udelay(1);
+	while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+	restore_flags(flags);
+} 
+
+
+/*************************************************************/
+/* write_fifo writes the skb contents to the desired fifo    */
+/* if no space is available or an error occurs 0 is returned */
+/* the skb is not released in any way.                       */
+/*************************************************************/
+static int
+write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
+{       unsigned short *msp;
+        int fifo_size, count, z1, z2;
+	u_char f_msk, f1, f2, *src;
+
+	if (skb->len <= 0) return(0);
+        if (fifo & 1) return(0); /* no write fifo */
+
+	fifo_select(cs, fifo);
+	if (fifo & 4) {
+	  fifo_size = D_FIFO_SIZE; /* D-channel */
+	  f_msk = MAX_D_FRAMES;
+	  if (trans_max) return(0); /* only HDLC */
+	}
+	else {
+	  fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+	  f_msk = MAX_B_FRAMES;
+	}
+
+        z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+	z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+
+	/* Check for transparent mode */
+	if (trans_max) {
+	  z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+	  z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+	  count = z2 - z1;
+	  if (count <= 0)
+	    count += fifo_size; /* free bytes */
+	  if (count < skb->len+1) return(0); /* no room */
+	  count = fifo_size - count; /* bytes still not send */
+	  if (count > 2 * trans_max) return(0); /* delay to long */
+	  count = skb->len;
+	  src = skb->data;
+	  while (count--)
+	    Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+	  return(1); /* success */
+	}
+
+        msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
+	msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1));
+	f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+	f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+	count = f1 - f2; /* frame count actually buffered */
+	if (count < 0)
+		count += (f_msk + 1);	/* if wrap around */
+	if (count > f_msk-1) {
+	  if (cs->debug & L1_DEB_ISAC_FIFO)
+	    debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1);
+	  return(0);
+	}
+
+	*(msp + f1) = z1; /* remember marker */
+
+	if (cs->debug & L1_DEB_ISAC_FIFO)
+		debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
+			fifo, f1, f2, z1);
+	/* now determine free bytes in FIFO buffer */
+	count = *(msp + f2) - z1;
+	if (count <= 0)
+	  count += fifo_size;	/* count now contains available bytes */
+
+	if (cs->debug & L1_DEB_ISAC_FIFO)
+	  debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
+		  fifo, skb->len, count);
+	if (count < skb->len) {
+	  if (cs->debug & L1_DEB_ISAC_FIFO)
+	    debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
+	  return(0);
+	}
+	
+	count = skb->len; /* get frame len */
+	src = skb->data;	/* source pointer */
+	while (count--)
+	  Write_hfc(cs, HFCSX_FIF_DWR, *src++);
+	
+	Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
+	udelay(1);
+	while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+	return(1);
+} 
+
+/***************************************************************/
+/* read_fifo reads data to an skb from the desired fifo        */
+/* if no data is available or an error occurs NULL is returned */
+/* the skb is not released in any way.                         */
+/***************************************************************/
+static struct sk_buff * 
+read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
+{       int fifo_size, count, z1, z2;
+	u_char f_msk, f1, f2, *dst;
+	struct sk_buff *skb;
+
+        if (!(fifo & 1)) return(NULL); /* no read fifo */
+	fifo_select(cs, fifo);
+	if (fifo & 4) {
+	  fifo_size = D_FIFO_SIZE; /* D-channel */
+	  f_msk = MAX_D_FRAMES;
+	  if (trans_max) return(NULL); /* only hdlc */
+	}
+	else {
+	  fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
+	  f_msk = MAX_B_FRAMES;
+	}
+
+	/* transparent mode */
+	if (trans_max) {
+	  z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+	  z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+	  z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+	  z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+	  /* now determine bytes in actual FIFO buffer */
+	  count = z1 - z2;
+	  if (count <= 0)
+	    count += fifo_size;	/* count now contains buffered bytes */
+	  count++;
+	  if (count > trans_max) 
+	    count = trans_max; /* limit length */
+	    if ((skb = dev_alloc_skb(count))) {
+	      dst = skb_put(skb, count);
+	      while (count--) 
+		*dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+	      return(skb);
+	    }
+	    else return(NULL); /* no memory */
+	}
+
+	do {
+	  f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
+	  f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
+
+	  if (f1 == f2) return(NULL); /* no frame available */
+
+	  z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
+	  z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
+	  z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
+	  z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
+
+	  if (cs->debug & L1_DEB_ISAC_FIFO)
+	    debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)",
+			fifo, f1, f2, z1, z2);
+	  /* now determine bytes in actual FIFO buffer */
+	  count = z1 - z2;
+	  if (count <= 0)
+	    count += fifo_size;	/* count now contains buffered bytes */
+	  count++;
+
+	  if (cs->debug & L1_DEB_ISAC_FIFO)
+	    debugl1(cs, "hfcsx_read_fifo %d count %ld)",
+		    fifo, count);
+
+	  if ((count > fifo_size) || (count < 4)) {
+	    if (cs->debug & L1_DEB_WARN)
+	      debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count);
+	    while (count) {
+	      count--; /* empty fifo */
+	      Read_hfc(cs, HFCSX_FIF_DRD);
+	    }
+	    skb = NULL;
+	  } else 
+	    if ((skb = dev_alloc_skb(count - 3))) {
+	      count -= 3;
+	      dst = skb_put(skb, count);
+
+	      while (count--) 
+		*dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
+		    
+	      Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
+	      Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
+	      if (Read_hfc(cs, HFCSX_FIF_DRD)) {
+		dev_kfree_skb(skb);
+		if (cs->debug & L1_DEB_ISAC_FIFO)
+		  debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
+		skb = NULL;
+	      }
+	    } else {
+	      printk(KERN_WARNING "HFC-SX: receive out of memory\n");
+	      return(NULL);
+	    }
+
+	  Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */
+	  udelay(1);
+	  while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
+	  udelay(1);
+	} while (!skb); /* retry in case of crc error */
+	return(skb);
+} 
+
+/******************************************/
+/* free hardware resources used by driver */
+/******************************************/
+void
+release_io_hfcsx(struct IsdnCardState *cs)
+{
+	int flags;
+
+	save_flags(flags);
+	cli();
+	cs->hw.hfcsx.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+	restore_flags(flags);
+	Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET);	/* Reset On */
+	sti();
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	Write_hfc(cs, HFCSX_CIRM, 0);	/* Reset Off */
+	del_timer(&cs->hw.hfcsx.timer);
+	release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */
+	kfree(cs->hw.hfcsx.extra);
+	cs->hw.hfcsx.extra = NULL;
+}
+
+/**********************************************************/
+/* set_fifo_size determines the size of the RAM and FIFOs */
+/* returning 0 -> need to reset the chip again.           */
+/**********************************************************/
+static int set_fifo_size(struct IsdnCardState *cs)
+{
+        
+        if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */
+
+	if ((cs->hw.hfcsx.chip >> 4) == 9) {
+	  cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K;
+	  return(1);
+	}
+
+	  cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K;
+	  cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */
+	  return(0);
+
+}
+
+/********************************************************************************/
+/* function called to reset the HFC SX chip. A complete software reset of chip */
+/* and fifos is done.                                                           */
+/********************************************************************************/
+static void
+reset_hfcsx(struct IsdnCardState *cs)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	cs->hw.hfcsx.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+
+	printk(KERN_INFO "HFC_SX: resetting card\n");
+	while (1) {
+	  Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
+	  sti();
+	  current->state = TASK_UNINTERRUPTIBLE;
+	  schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	  Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
+	  current->state = TASK_UNINTERRUPTIBLE;
+	  schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+	  if (Read_hfc(cs, HFCSX_STATUS) & 2)
+	    printk(KERN_WARNING "HFC-SX init bit busy\n");
+	  cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */
+	  if (!set_fifo_size(cs)) continue;
+	  break;
+	}
+
+	cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK;	/* no echo connect , threshold */
+	Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+
+	Write_hfc(cs, HFCSX_CLKDEL, 0x0e);	/* ST-Bit delay for TE-Mode */
+	cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE;
+	Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);	/* S/T Auto awake */
+	cs->hw.hfcsx.bswapped = 0;	/* no exchange */
+	cs->hw.hfcsx.nt_mode = 0;	/* we are in TE mode */
+	cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER;
+	Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+
+	cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | 
+	    HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER;
+	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+
+	/* Clear already pending ints */
+	if (Read_hfc(cs, HFCSX_INT_S1));
+
+	Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2);	/* HFC ST 2 */
+	udelay(10);
+	Write_hfc(cs, HFCSX_STATES, 2);	/* HFC ST 2 */
+	cs->hw.hfcsx.mst_m = HFCSX_MASTER;	/* HFC Master Mode */
+
+	Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+	cs->hw.hfcsx.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
+	Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+	cs->hw.hfcsx.sctrl_r = 0;
+	Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+
+	/* Init GCI/IOM2 in master mode */
+	/* Slots 0 and 1 are set for B-chan 1 and 2 */
+	/* D- and monitor/CI channel are not enabled */
+	/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
+	/* STIO2 is used as data input, B1+B2 from IOM->ST */
+	/* ST B-channel send disabled -> continous 1s */
+	/* The IOM slots are always enabled */
+	cs->hw.hfcsx.conn = 0x36;	/* set data flow directions */
+	Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+	Write_hfc(cs, HFCSX_B1_SSL, 0x80);	/* B1-Slot 0 STIO1 out enabled */
+	Write_hfc(cs, HFCSX_B2_SSL, 0x81);	/* B2-Slot 1 STIO1 out enabled */
+	Write_hfc(cs, HFCSX_B1_RSL, 0x80);	/* B1-Slot 0 STIO2 in enabled */
+	Write_hfc(cs, HFCSX_B2_RSL, 0x81);	/* B2-Slot 1 STIO2 in enabled */
+
+	/* Finally enable IRQ output */
+	cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
+	Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+	if (Read_hfc(cs, HFCSX_INT_S2));
+	restore_flags(flags);
+}
+
+/***************************************************/
+/* Timer function called when kernel timer expires */
+/***************************************************/
+static void
+hfcsx_Timer(struct IsdnCardState *cs)
+{
+	cs->hw.hfcsx.timer.expires = jiffies + 75;
+	/* WD RESET */
+/*      WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80);
+   add_timer(&cs->hw.hfcsx.timer);
+ */
+}
+
+
+/*********************************/
+/* schedule a new D-channel task */
+/*********************************/
+static void
+sched_event_D_sx(struct IsdnCardState *cs, int event)
+{
+	test_and_set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*********************************/
+/* schedule a new b_channel task */
+/*********************************/
+static void
+hfcsx_sched_event(struct BCState *bcs, int event)
+{
+	bcs->event |= 1 << event;
+	queue_task(&bcs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/************************************************/
+/* select a b-channel entry matching and active */
+/************************************************/
+static
+struct BCState *
+Sel_BCS(struct IsdnCardState *cs, int channel)
+{
+	if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
+		return (&cs->bcs[0]);
+	else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
+		return (&cs->bcs[1]);
+	else
+		return (NULL);
+}
+
+/*******************************/
+/* D-channel receive procedure */
+/*******************************/
+static
+int
+receive_dmsg(struct IsdnCardState *cs)
+{
+	struct sk_buff *skb;
+	int count = 5;
+
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_dmsg blocked");
+		return (1);
+	}
+
+	do {
+	  skb = read_fifo(cs, HFCSX_SEL_D_RX, 0);
+	  if (skb) {
+	    skb_queue_tail(&cs->rq, skb);
+	    sched_event_D_sx(cs, D_RCVBUFREADY);
+	  }
+	} while (--count && skb);
+
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	return (1);
+}
+
+/**********************************/
+/* B-channel main receive routine */
+/**********************************/
+void
+main_rec_hfcsx(struct BCState *bcs)
+{
+	long flags;
+	struct IsdnCardState *cs = bcs->cs;
+	int count = 5;
+	struct sk_buff *skb;
+
+	save_flags(flags);
+	  
+      Begin:
+	count--;
+	cli();
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "rec_data %d blocked", bcs->channel);
+		restore_flags(flags);
+		return;
+	}
+	sti();
+	skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? 
+			HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX,
+			(bcs->mode == L1_MODE_TRANS) ? 
+			HFCSX_BTRANS_THRESHOLD : 0);
+
+	if (skb) {
+	  cli();
+	  skb_queue_tail(&bcs->rqueue, skb);
+	  sti();
+	  hfcsx_sched_event(bcs, B_RCVBUFREADY);
+	}
+
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	if (count && skb)
+		goto Begin;
+	restore_flags(flags);
+	return;
+}
+
+/**************************/
+/* D-channel send routine */
+/**************************/
+static void
+hfcsx_fill_dfifo(struct IsdnCardState *cs)
+{
+	if (!cs->tx_skb)
+		return;
+	if (cs->tx_skb->len <= 0)
+		return;
+
+	if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
+	  dev_kfree_skb(cs->tx_skb);
+	  cs->tx_skb = NULL;
+	}
+	return;
+}
+
+/**************************/
+/* B-channel send routine */
+/**************************/
+static void
+hfcsx_fill_fifo(struct BCState *bcs)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	int flags;
+
+	if (!bcs->tx_skb)
+		return;
+	if (bcs->tx_skb->len <= 0)
+		return;
+
+	save_flags(flags);
+	sti();
+
+	if (write_fifo(cs, bcs->tx_skb, 
+		       ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? 
+		       HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX,
+		       (bcs->mode == L1_MODE_TRANS) ? 
+		       HFCSX_BTRANS_THRESHOLD : 0)) {
+
+	  bcs->tx_cnt -= bcs->tx_skb->len;
+	  if (bcs->st->lli.l1writewakeup &&
+	      (PACKET_NOACK != bcs->tx_skb->pkt_type))
+	    bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+	  dev_kfree_skb(bcs->tx_skb);
+	  bcs->tx_skb = NULL;
+	  test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	}
+
+	cli();
+	restore_flags(flags);
+	return;
+}
+
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+		case (PH_PULL | REQUEST):
+		case (PH_PULL | INDICATION):
+			st->l1.l1hw(st, pr, arg);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			break;
+		case (PH_TESTLOOP | REQUEST):
+			if (1 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B1");
+			if (2 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B2");
+			if (!(3 & (long) arg))
+				debugl1(cs, "PH_TEST_LOOP DISABLED");
+			st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+			break;
+		default:
+			if (cs->debug)
+				debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+			break;
+	}
+}
+
+
+
+/***********************/
+/* set/reset echo mode */
+/***********************/
+static int
+hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
+{
+	int flags;
+	int i = *(unsigned int *) ic->parm.num;
+
+	if ((ic->arg == 98) &&
+	    (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) {
+		save_flags(flags);
+		cli();
+		Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0);	/* HFC ST G0 */
+		udelay(10);
+		cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT;
+		Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);	/* set NT-mode */
+		udelay(10);
+		Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1);	/* HFC ST G1 */
+		udelay(10);
+		Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+		cs->dc.hfcsx.ph_state = 1;
+		cs->hw.hfcsx.nt_mode = 1;
+		cs->hw.hfcsx.nt_timer = 0;
+		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		restore_flags(flags);
+		debugl1(cs, "NT mode activated");
+		return (0);
+	}
+	if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) ||
+	    (cs->hw.hfcsx.nt_mode) || (ic->arg != 12))
+		return (-EINVAL);
+
+	save_flags(flags);
+	cli();
+	if (i) {
+		cs->logecho = 1;
+		cs->hw.hfcsx.trm |= 0x20;	/* enable echo chan */
+		cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC;
+		/* reset Channel !!!!! */
+	} else {
+		cs->logecho = 0;
+		cs->hw.hfcsx.trm &= ~0x20;	/* disable echo chan */
+		cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC;
+	}
+	cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+	cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+	cs->hw.hfcsx.conn |= 0x10;	/* B2-IOM -> B2-ST */
+	cs->hw.hfcsx.ctmt &= ~2;
+	Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+	Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+	Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+	Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+	Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+	restore_flags(flags);
+	return (0);
+}				/* hfcsx_auxcmd */
+
+/*****************************/
+/* E-channel receive routine */
+/*****************************/
+static void
+receive_emsg(struct IsdnCardState *cs)
+{
+	int flags;
+	int count = 5;
+	u_char *ptr;
+	struct sk_buff *skb;
+
+
+	save_flags(flags);
+	cli();
+	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+		debugl1(cs, "echo_rec_data blocked");
+		restore_flags(flags);
+		return;
+	}
+	sti();
+
+	do {
+	  skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0);
+	  if (skb) {
+	    if (cs->debug & DEB_DLOG_HEX) {
+	      ptr = cs->dlog;
+	      if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
+		*ptr++ = 'E';
+		*ptr++ = 'C';
+		*ptr++ = 'H';
+		*ptr++ = 'O';
+		*ptr++ = ':';
+		ptr += QuickHex(ptr, skb->data, skb->len);
+		ptr--;
+		*ptr++ = '\n';
+		*ptr = 0;
+		HiSax_putstatus(cs, NULL, cs->dlog);
+	      } else
+		HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
+	    }
+	    dev_kfree_skb(skb);
+	  }
+	} while (--count && skb);
+
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	restore_flags(flags);
+	return;
+}				/* receive_emsg */
+
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static void
+hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char exval;
+	struct BCState *bcs;
+	int count = 15;
+	long flags;
+	u_char val, stat;
+
+	if (!cs) {
+		printk(KERN_WARNING "HFC-SX: Spurious interrupt!\n");
+		return;
+	}
+	if (!(cs->hw.hfcsx.int_m2 & 0x08))
+		return;		/* not initialised */
+
+	if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) {
+		val = Read_hfc(cs, HFCSX_INT_S1);
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val);
+	} else
+		return;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "HFC-SX irq %x %s", val,
+			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+			"locked" : "unlocked");
+	val &= cs->hw.hfcsx.int_m1;
+	if (val & 0x40) {	/* state machine irq */
+		exval = Read_hfc(cs, HFCSX_STATES) & 0xf;
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state,
+				exval);
+		cs->dc.hfcsx.ph_state = exval;
+		sched_event_D_sx(cs, D_L1STATECHANGE);
+		val &= ~0x40;
+	}
+	if (val & 0x80) {	/* timer irq */
+		if (cs->hw.hfcsx.nt_mode) {
+			if ((--cs->hw.hfcsx.nt_timer) < 0)
+				sched_event_D_sx(cs, D_L1STATECHANGE);
+		}
+		val &= ~0x80;
+		Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+	}
+	while (val) {
+		save_flags(flags);
+		cli();
+		if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			cs->hw.hfcsx.int_s1 |= val;
+			restore_flags(flags);
+			return;
+		}
+		if (cs->hw.hfcsx.int_s1 & 0x18) {
+			exval = val;
+			val = cs->hw.hfcsx.int_s1;
+			cs->hw.hfcsx.int_s1 = exval;
+		}
+		if (val & 0x08) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+				if (cs->debug)
+					debugl1(cs, "hfcsx spurious 0x08 IRQ");
+			} else
+				main_rec_hfcsx(bcs);
+		}
+		if (val & 0x10) {
+			if (cs->logecho)
+				receive_emsg(cs);
+			else if (!(bcs = Sel_BCS(cs, 1))) {
+				if (cs->debug)
+					debugl1(cs, "hfcsx spurious 0x10 IRQ");
+			} else
+				main_rec_hfcsx(bcs);
+		}
+		if (val & 0x01) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) {
+				if (cs->debug)
+					debugl1(cs, "hfcsx spurious 0x01 IRQ");
+			} else {
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcsx_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						hfcsx_sched_event(bcs, B_XMTBUFREADY);
+					}
+				}
+			}
+		}
+		if (val & 0x02) {
+			if (!(bcs = Sel_BCS(cs, 1))) {
+				if (cs->debug)
+					debugl1(cs, "hfcsx spurious 0x02 IRQ");
+			} else {
+				if (bcs->tx_skb) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_fifo(bcs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else
+						debugl1(cs, "fill_data %d blocked", bcs->channel);
+				} else {
+					if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+						if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+							hfcsx_fill_fifo(bcs);
+							test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+						} else
+							debugl1(cs, "fill_data %d blocked", bcs->channel);
+					} else {
+						hfcsx_sched_event(bcs, B_XMTBUFREADY);
+					}
+				}
+			}
+		}
+		if (val & 0x20) {	/* receive dframe */
+			receive_dmsg(cs);
+		}
+		if (val & 0x04) {	/* dframe transmitted */
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				sched_event_D_sx(cs, D_CLEARBUSY);
+			if (cs->tx_skb) {
+				if (cs->tx_skb->len) {
+					if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+						hfcsx_fill_dfifo(cs);
+						test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+					} else {
+						debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+					}
+					goto afterXPR;
+				} else {
+					dev_kfree_skb(cs->tx_skb);
+					cs->tx_cnt = 0;
+					cs->tx_skb = NULL;
+				}
+			}
+			if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+				cs->tx_cnt = 0;
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+					hfcsx_fill_dfifo(cs);
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else {
+					debugl1(cs, "hfcsx_fill_dfifo irq blocked");
+				}
+			} else
+				sched_event_D_sx(cs, D_XMTBUFREADY);
+		}
+	      afterXPR:
+		if (cs->hw.hfcsx.int_s1 && count--) {
+			val = cs->hw.hfcsx.int_s1;
+			cs->hw.hfcsx.int_s1 = 0;
+			if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count);
+		} else
+			val = 0;
+		restore_flags(flags);
+	}
+}
+
+/********************************************************************/
+/* timer callback for D-chan busy resolution. Currently no function */
+/********************************************************************/
+static void
+hfcsx_dbusy_timer(struct IsdnCardState *cs)
+{
+}
+
+/*************************************/
+/* Layer 1 D-channel hardware access */
+/*************************************/
+static void
+HFCSX_l1hw(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+	int flags;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				        hfcsx_fill_dfifo(cs); 
+					test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+				} else
+					debugl1(cs, "hfcsx_fill_dfifo blocked");
+
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+				hfcsx_fill_dfifo(cs); 
+				test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+			} else
+				debugl1(cs, "hfcsx_fill_dfifo blocked");
+			break;
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (HW_RESET | REQUEST):
+			Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3);	/* HFC ST 3 */
+			udelay(6);
+			Write_hfc(cs, HFCSX_STATES, 3);	/* HFC ST 2 */
+			cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+			break;
+		case (HW_ENABLE | REQUEST):
+			Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION);
+			break;
+		case (HW_DEACTIVATE | REQUEST):
+			cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER;
+			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			break;
+		case (HW_INFO3 | REQUEST):
+			cs->hw.hfcsx.mst_m |= HFCSX_MASTER;
+			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			break;
+		case (HW_TESTLOOP | REQUEST):
+			switch ((int) arg) {
+				case (1):
+					Write_hfc(cs, HFCSX_B1_SSL, 0x80);	/* tx slot */
+					Write_hfc(cs, HFCSX_B1_RSL, 0x80);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1;
+					Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+					restore_flags(flags);
+					break;
+
+				case (2):
+					Write_hfc(cs, HFCSX_B2_SSL, 0x81);	/* tx slot */
+					Write_hfc(cs, HFCSX_B2_RSL, 0x81);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08;
+					Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+					restore_flags(flags);
+					break;
+
+				default:
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
+					return;
+			}
+			save_flags(flags);
+			cli();
+			cs->hw.hfcsx.trm |= 0x80;	/* enable IOM-loop */
+			Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm);
+			restore_flags(flags);
+			break;
+		default:
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr);
+			break;
+	}
+}
+
+/***********************************************/
+/* called during init setting l1 stack pointer */
+/***********************************************/
+void
+setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
+{
+	st->l1.l1hw = HFCSX_l1hw;
+}
+
+/**************************************/
+/* send B-channel data if not blocked */
+/**************************************/
+static void
+hfcsx_send_data(struct BCState *bcs)
+{
+	struct IsdnCardState *cs = bcs->cs;
+
+	if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+	  hfcsx_fill_fifo(bcs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		debugl1(cs, "send_data %d blocked", bcs->channel);
+}
+
+/***************************************************************/
+/* activate/deactivate hardware for selected channels and mode */
+/***************************************************************/
+void
+mode_hfcsx(struct BCState *bcs, int mode, int bc)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	int flags, fifo2;
+
+	if (cs->debug & L1_DEB_HSCX)
+		debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d",
+			mode, bc, bcs->channel);
+	bcs->mode = mode;
+	bcs->channel = bc;
+	fifo2 = bc;
+	save_flags(flags);
+	cli();
+	if (cs->chanlimit > 1) {
+		cs->hw.hfcsx.bswapped = 0;	/* B1 and B2 normal mode */
+		cs->hw.hfcsx.sctrl_e &= ~0x80;
+	} else {
+		if (bc) {
+			if (mode != L1_MODE_NULL) {
+				cs->hw.hfcsx.bswapped = 1;	/* B1 and B2 exchanged */
+				cs->hw.hfcsx.sctrl_e |= 0x80;
+			} else {
+				cs->hw.hfcsx.bswapped = 0;	/* B1 and B2 normal mode */
+				cs->hw.hfcsx.sctrl_e &= ~0x80;
+			}
+			fifo2 = 0;
+		} else {
+			cs->hw.hfcsx.bswapped = 0;	/* B1 and B2 normal mode */
+			cs->hw.hfcsx.sctrl_e &= ~0x80;
+		}
+	}
+	switch (mode) {
+		case (L1_MODE_NULL):
+			if (bc) {
+				cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA;
+				cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA;
+			} else {
+				cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA;
+				cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+			} else {
+				cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+			}
+			break;
+		case (L1_MODE_TRANS):
+			if (bc) {
+				cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+			} else {
+				cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+				cs->hw.hfcsx.ctmt |= 2;
+				cs->hw.hfcsx.conn &= ~0x18;
+			} else {
+				cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+				cs->hw.hfcsx.ctmt |= 1;
+				cs->hw.hfcsx.conn &= ~0x03;
+			}
+			break;
+		case (L1_MODE_HDLC):
+			if (bc) {
+				cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+			} else {
+				cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+				cs->hw.hfcsx.ctmt &= ~2;
+				cs->hw.hfcsx.conn &= ~0x18;
+			} else {
+				cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+				cs->hw.hfcsx.ctmt &= ~1;
+				cs->hw.hfcsx.conn &= ~0x03;
+			}
+			break;
+		case (L1_MODE_EXTRN):
+			if (bc) {
+				cs->hw.hfcsx.conn |= 0x10;
+				cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA;
+				cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC);
+			} else {
+				cs->hw.hfcsx.conn |= 0x02;
+				cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA;
+				cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA;
+				cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC);
+			}
+			break;
+	}
+	Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e);
+	Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+	Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl);
+	Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r);
+	Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt);
+	Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn);
+	if (mode != L1_MODE_EXTRN) {
+	  reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX);
+	  reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX);
+	}
+	restore_flags(flags);
+}
+
+/******************************/
+/* Layer2 -> Layer 1 Transfer */
+/******************************/
+static void
+hfcsx_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	long flags;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+			save_flags(flags);
+			cli();
+			if (st->l1.bcs->tx_skb) {
+				skb_queue_tail(&st->l1.bcs->squeue, skb);
+				restore_flags(flags);
+			} else {
+				st->l1.bcs->tx_skb = skb;
+/*                              test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+				restore_flags(flags);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (st->l1.bcs->tx_skb) {
+				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+				break;
+			}
+			save_flags(flags);
+			cli();
+/*                      test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ */ st->l1.bcs->tx_skb = skb;
+			st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+			restore_flags(flags);
+			break;
+		case (PH_PULL | REQUEST):
+			if (!st->l1.bcs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			mode_hfcsx(st->l1.bcs, st->l1.mode, st->l1.bc);
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | REQUEST):
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | CONFIRM):
+			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			mode_hfcsx(st->l1.bcs, 0, st->l1.bc);
+			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			break;
+	}
+}
+
+/******************************************/
+/* deactivate B-channel access and queues */
+/******************************************/
+static void
+close_hfcsx(struct BCState *bcs)
+{
+	mode_hfcsx(bcs, 0, bcs->channel);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		discard_queue(&bcs->rqueue);
+		discard_queue(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
+}
+
+/*************************************/
+/* init B-channel queues and control */
+/*************************************/
+static int
+open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->tx_cnt = 0;
+	return (0);
+}
+
+/*********************************/
+/* inits the stack for B-channel */
+/*********************************/
+static int
+setstack_2b(struct PStack *st, struct BCState *bcs)
+{
+	bcs->channel = st->l1.bc;
+	if (open_hfcsxstate(st->l1.hardware, bcs))
+		return (-1);
+	st->l1.bcs = bcs;
+	st->l2.l2l1 = hfcsx_l2l1;
+	setstack_manager(st);
+	bcs->st = st;
+	setstack_l1_B(st);
+	return (0);
+}
+
+/***************************/
+/* handle L1 state changes */
+/***************************/
+static void
+hfcsx_bh(struct IsdnCardState *cs)
+{
+	int flags;
+/*      struct PStack *stptr;
+ */
+	if (!cs)
+		return;
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+		if (!cs->hw.hfcsx.nt_mode)
+			switch (cs->dc.hfcsx.ph_state) {
+				case (0):
+					l1_msg(cs, HW_RESET | INDICATION, NULL);
+					break;
+				case (3):
+					l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+					break;
+				case (8):
+					l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+					break;
+				case (6):
+					l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+					break;
+				case (7):
+					l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+					break;
+				default:
+					break;
+		} else {
+			switch (cs->dc.hfcsx.ph_state) {
+				case (2):
+					save_flags(flags);
+					cli();
+					if (cs->hw.hfcsx.nt_timer < 0) {
+						cs->hw.hfcsx.nt_timer = 0;
+						cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+						Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+						/* Clear already pending ints */
+						if (Read_hfc(cs, HFCSX_INT_S1));
+
+						Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
+						udelay(10);
+						Write_hfc(cs, HFCSX_STATES, 4);
+						cs->dc.hfcsx.ph_state = 4;
+					} else {
+						cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER;
+						Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+						cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER;
+						cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125;
+						Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+						Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER);
+						cs->hw.hfcsx.nt_timer = NT_T1_COUNT;
+						Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3);	/* allow G2 -> G3 transition */
+					}
+					restore_flags(flags);
+					break;
+				case (1):
+				case (3):
+				case (4):
+					save_flags(flags);
+					cli();
+					cs->hw.hfcsx.nt_timer = 0;
+					cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+					Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+					restore_flags(flags);
+					break;
+				default:
+					break;
+			}
+		}
+	}
+	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+		DChannel_proc_rcv(cs);
+	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+		DChannel_proc_xmt(cs);
+}
+
+
+/********************************/
+/* called for card init message */
+/********************************/
+__initfunc(void
+	   inithfcsx(struct IsdnCardState *cs))
+{
+	cs->setstack_d = setstack_hfcsx;
+	cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+	cs->tqueue.routine = (void *) (void *) hfcsx_bh;
+	cs->BC_Send_Data = &hfcsx_send_data;
+	cs->bcs[0].BC_SetStack = setstack_2b;
+	cs->bcs[1].BC_SetStack = setstack_2b;
+	cs->bcs[0].BC_Close = close_hfcsx;
+	cs->bcs[1].BC_Close = close_hfcsx;
+	mode_hfcsx(cs->bcs, 0, 0);
+	mode_hfcsx(cs->bcs + 1, 0, 1);
+}
+
+
+
+/*******************************************/
+/* handle card messages from control layer */
+/*******************************************/
+static int
+hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	long flags;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "HFCSX: card_msg %x", mt);
+	switch (mt) {
+		case CARD_RESET:
+			reset_hfcsx(cs);
+			return (0);
+		case CARD_RELEASE:
+			release_io_hfcsx(cs);
+			return (0);
+		case CARD_INIT:
+			inithfcsx(cs);
+			save_flags(flags);
+			sti();
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
+			/* now switch timer interrupt off */
+			cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
+			Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+			/* reinit mode reg */
+			Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m);
+			restore_flags(flags);
+			return (0);
+		case CARD_TEST:
+			return (0);
+	}
+	return (0);
+}
+
+
+
+__initfunc(int
+	   setup_hfcsx(struct IsdnCard *card))
+{
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	int flags;
+
+	strcpy(tmp, hfcsx_revision);
+	printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
+	cs->irq = card->para[0];
+	cs->hw.hfcsx.int_s1 = 0;
+	cs->dc.hfcsx.ph_state = 0;
+	cs->hw.hfcsx.fifo = 255;
+	if (cs->typ == ISDN_CTYPE_HFC_SX) {
+	        if ((!cs->hw.hfcsx.base) || 
+		    check_region((cs->hw.hfcsx.base), 2)) {
+		  printk(KERN_WARNING
+			 "HiSax: HFC-SX io-base 0x%x already in use\n",
+		          cs->hw.hfcsx.base);
+		  return(0);
+		} else {
+		  request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn");
+		}
+		byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF);
+		byteout(cs->hw.hfcsx.base + 1,
+			((cs->hw.hfcsx.base >> 8) & 3) | 0x54);
+		udelay(10);
+	        cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID);
+                switch (cs->hw.hfcsx.chip >> 4) {
+		  case 1: 
+		    tmp[0] ='+';
+		    break;
+		  case 9: 
+		    tmp[0] ='P';
+		    break;
+		  default:
+		    printk(KERN_WARNING
+			   "HFC-SX: invalid chip id 0x%x\n",
+			   cs->hw.hfcsx.chip >> 4);
+		    release_region(cs->hw.hfcsx.base, 2);
+		    return(0);
+		}  
+		if (!ccd_sp_irqtab[cs->irq & 0xF]) {
+		  printk(KERN_WARNING 
+			 "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF);
+		  release_region(cs->hw.hfcsx.base, 2);
+		  return(0);
+		}  
+		save_flags(flags);
+		cli();
+		if (!(cs->hw.hfcsx.extra = (void *)
+		      kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
+		  restore_flags(flags);
+		  release_region(cs->hw.hfcsx.base, 2);
+		  printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
+		  return(0);
+		}
+		restore_flags(flags);
+
+		printk(KERN_INFO
+		       "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n",
+		       tmp[0], (u_int) cs->hw.hfcsx.base,
+		       cs->irq, HZ);
+		cs->hw.hfcsx.int_m2 = 0;	/* disable alle interrupts */
+		cs->hw.hfcsx.int_m1 = 0;
+		Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
+		Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
+	} else
+		return (0);	/* no valid card type */
+
+	cs->readisac = NULL;
+	cs->writeisac = NULL;
+	cs->readisacfifo = NULL;
+	cs->writeisacfifo = NULL;
+	cs->BC_Read_Reg = NULL;
+	cs->BC_Write_Reg = NULL;
+	cs->irq_func = &hfcsx_interrupt;
+
+	cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer;
+	cs->hw.hfcsx.timer.data = (long) cs;
+	cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */
+	cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */
+	init_timer(&cs->hw.hfcsx.timer);
+
+	reset_hfcsx(cs);
+	cs->cardmsg = &hfcsx_card_msg;
+	cs->auxcmd = &hfcsx_auxcmd;
+	return (1);
+}
+
+
+
+
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/hfc_sx.h linux/drivers/isdn/hisax/hfc_sx.h
--- linux-2.2.15-pre4/drivers/isdn/hisax/hfc_sx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/hfc_sx.h	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,216 @@
+/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $
+
+ *  specific defines for CCD's HFC 2BDS0 S+,SP chips
+ *
+ * Author     Werner Cornelius (werner@isdn4linux.de)      
+ *
+ * Copyright 1999  by Werner Cornelius (werner@isdn4linux.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: hfc_sx.h,v $
+ * Revision 1.1  1999/11/18 00:09:18  werner
+ *
+ * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
+ * Audio and Echo are supported.
+ *
+ *
+ *
+ */
+
+/*********************************************/
+/* thresholds for transparent B-channel mode */
+/* change mask and threshold simultaneously  */
+/*********************************************/
+#define HFCSX_BTRANS_THRESHOLD 128
+#define HFCSX_BTRANS_THRESMASK 0x00
+
+/* GCI/IOM bus monitor registers */
+
+#define HFCSX_C_I       0x02
+#define HFCSX_TRxR      0x03
+#define HFCSX_MON1_D    0x0A
+#define HFCSX_MON2_D    0x0B
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define HFCSX_B1_SSL    0x20
+#define HFCSX_B2_SSL    0x21
+#define HFCSX_AUX1_SSL  0x22
+#define HFCSX_AUX2_SSL  0x23
+#define HFCSX_B1_RSL    0x24
+#define HFCSX_B2_RSL    0x25
+#define HFCSX_AUX1_RSL  0x26
+#define HFCSX_AUX2_RSL  0x27
+
+/* GCI/IOM bus data registers */
+
+#define HFCSX_B1_D      0x28
+#define HFCSX_B2_D      0x29
+#define HFCSX_AUX1_D    0x2A
+#define HFCSX_AUX2_D    0x2B
+
+/* GCI/IOM bus configuration registers */
+
+#define HFCSX_MST_EMOD  0x2D
+#define HFCSX_MST_MODE	0x2E
+#define HFCSX_CONNECT 	0x2F
+
+
+/* Interrupt and status registers */
+
+#define HFCSX_TRM       0x12
+#define HFCSX_B_MODE    0x13
+#define HFCSX_CHIP_ID   0x16
+#define HFCSX_CIRM  	0x18
+#define HFCSX_CTMT	0x19
+#define HFCSX_INT_M1  	0x1A
+#define HFCSX_INT_M2  	0x1B
+#define HFCSX_INT_S1  	0x1E
+#define HFCSX_INT_S2  	0x1F
+#define HFCSX_STATUS  	0x1C
+
+/* S/T section registers */
+
+#define HFCSX_STATES  	0x30
+#define HFCSX_SCTRL  	0x31
+#define HFCSX_SCTRL_E   0x32
+#define HFCSX_SCTRL_R   0x33
+#define HFCSX_SQ  	0x34
+#define HFCSX_CLKDEL  	0x37
+#define HFCSX_B1_REC    0x3C
+#define HFCSX_B1_SEND   0x3C
+#define HFCSX_B2_REC    0x3D
+#define HFCSX_B2_SEND   0x3D
+#define HFCSX_D_REC     0x3E
+#define HFCSX_D_SEND    0x3E
+#define HFCSX_E_REC     0x3F
+
+/****************/
+/* FIFO section */
+/****************/
+#define HFCSX_FIF_SEL   0x10
+#define HFCSX_FIF_Z1L   0x80
+#define HFCSX_FIF_Z1H   0x84
+#define HFCSX_FIF_Z2L   0x88
+#define HFCSX_FIF_Z2H   0x8C
+#define HFCSX_FIF_INCF1 0xA8
+#define HFCSX_FIF_DWR   0xAC
+#define HFCSX_FIF_F1    0xB0
+#define HFCSX_FIF_F2    0xB4
+#define HFCSX_FIF_INCF2 0xB8
+#define HFCSX_FIF_DRD   0xBC
+
+/* bits in status register (READ) */
+#define HFCSX_SX_PROC    0x02
+#define HFCSX_NBUSY	 0x04 
+#define HFCSX_TIMER_ELAP 0x10
+#define HFCSX_STATINT	 0x20
+#define HFCSX_FRAMEINT	 0x40
+#define HFCSX_ANYINT	 0x80
+
+/* bits in CTMT (Write) */
+#define HFCSX_CLTIMER    0x80
+#define HFCSX_TIM3_125   0x04
+#define HFCSX_TIM25      0x10
+#define HFCSX_TIM50      0x14
+#define HFCSX_TIM400     0x18
+#define HFCSX_TIM800     0x1C
+#define HFCSX_AUTO_TIMER 0x20
+#define HFCSX_TRANSB2    0x02
+#define HFCSX_TRANSB1    0x01
+
+/* bits in CIRM (Write) */
+#define HFCSX_IRQ_SELMSK 0x07
+#define HFCSX_IRQ_SELDIS 0x00
+#define HFCSX_RESET  	 0x08
+#define HFCSX_FIFO_RESET 0x80
+
+
+/* bits in INT_M1 and INT_S1 */
+#define HFCSX_INTS_B1TRANS  0x01
+#define HFCSX_INTS_B2TRANS  0x02
+#define HFCSX_INTS_DTRANS   0x04
+#define HFCSX_INTS_B1REC    0x08
+#define HFCSX_INTS_B2REC    0x10
+#define HFCSX_INTS_DREC     0x20
+#define HFCSX_INTS_L1STATE  0x40
+#define HFCSX_INTS_TIMER    0x80
+
+/* bits in INT_M2 */
+#define HFCSX_PROC_TRANS    0x01
+#define HFCSX_GCI_I_CHG     0x02
+#define HFCSX_GCI_MON_REC   0x04
+#define HFCSX_IRQ_ENABLE    0x08
+
+/* bits in STATES */
+#define HFCSX_STATE_MSK     0x0F
+#define HFCSX_LOAD_STATE    0x10
+#define HFCSX_ACTIVATE	    0x20
+#define HFCSX_DO_ACTION     0x40
+#define HFCSX_NT_G2_G3      0x80
+
+/* bits in HFCD_MST_MODE */
+#define HFCSX_MASTER	    0x01
+#define HFCSX_SLAVE         0x00
+/* remaining bits are for codecs control */
+
+/* bits in HFCD_SCTRL */
+#define SCTRL_B1_ENA	    0x01
+#define SCTRL_B2_ENA	    0x02
+#define SCTRL_MODE_TE       0x00
+#define SCTRL_MODE_NT       0x04
+#define SCTRL_LOW_PRIO	    0x08
+#define SCTRL_SQ_ENA	    0x10
+#define SCTRL_TEST	    0x20
+#define SCTRL_NONE_CAP	    0x40
+#define SCTRL_PWR_DOWN	    0x80
+
+/* bits in SCTRL_E  */
+#define HFCSX_AUTO_AWAKE    0x01
+#define HFCSX_DBIT_1        0x04
+#define HFCSX_IGNORE_COL    0x08
+#define HFCSX_CHG_B1_B2     0x80
+
+/**********************************/
+/* definitions for FIFO selection */
+/**********************************/
+#define HFCSX_SEL_D_RX      5
+#define HFCSX_SEL_D_TX      4
+#define HFCSX_SEL_B1_RX     1
+#define HFCSX_SEL_B1_TX     0
+#define HFCSX_SEL_B2_RX     3
+#define HFCSX_SEL_B2_TX     2
+
+#define MAX_D_FRAMES 15
+#define MAX_B_FRAMES 31
+#define B_SUB_VAL_32K       0x0200
+#define B_FIFO_SIZE_32K    (0x2000 - B_SUB_VAL_32K)
+#define B_SUB_VAL_8K        0x1A00
+#define B_FIFO_SIZE_8K     (0x2000 - B_SUB_VAL_8K)
+#define D_FIFO_SIZE  512
+#define D_FREG_MASK  0xF
+
+/************************************************************/
+/* structure holding additional dynamic data -> send marker */
+/************************************************************/
+struct hfcsx_extra {
+  unsigned short marker[2*(MAX_B_FRAMES+1) + (MAX_D_FRAMES+1)];
+};
+
+extern void main_irq_hfcsx(struct BCState *bcs);
+extern void inithfcsx(struct IsdnCardState *cs);
+extern void releasehfcsx(struct IsdnCardState *cs);
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- linux-2.2.15-pre4/drivers/isdn/hisax/hisax.h	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/hisax.h	Mon Dec  3 21:58:30 2001
@@ -1,8 +1,16 @@
-/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $
+/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
+ * Revision 2.40  2000/01/20 19:51:46  keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
+ * Revision 2.39  1999/11/18 00:00:43  werner
+ *
+ * Added support for HFC-S+ and HFC-SP cards
+ *
  * Revision 2.38  1999/11/14 23:37:03  keil
  * new ISA memory mapped IO
  *
@@ -784,6 +792,31 @@
 	struct timer_list timer;
 };
 
+struct hfcSX_hw {
+        unsigned int  base;
+	unsigned char cirm;
+	unsigned char ctmt;
+	unsigned char conn;
+	unsigned char mst_m;
+	unsigned char int_m1;
+	unsigned char int_m2;
+	unsigned char int_s1;
+	unsigned char sctrl;
+        unsigned char sctrl_r;
+        unsigned char sctrl_e;
+        unsigned char trm;
+	unsigned char stat;
+	unsigned char fifo;
+        unsigned char bswapped;
+        unsigned char nt_mode;
+        unsigned char chip;
+        int b_fifo_size;
+        unsigned char last_fifo;
+        void *extra;
+        int nt_timer;
+	struct timer_list timer;
+};
+
 struct hfcD_hw {
 	unsigned int addr;
 	unsigned int bfifosize;
@@ -894,6 +927,10 @@
 	int ph_state;
 };
 
+struct hfcsx_chip {
+	int ph_state;
+};
+
 struct w6692_chip {
 	int ph_state;
 };
@@ -934,6 +971,7 @@
 		struct njet_hw njet;
 		struct hfcD_hw hfcD;
 		struct hfcPCI_hw hfcpci;
+		struct hfcSX_hw hfcsx;
 		struct ix1_hw niccy;
 		struct isurf_hw isurf;
 		struct saphir_hw saphir;
@@ -973,6 +1011,7 @@
 		struct isac_chip isac;
 		struct hfcd_chip hfcd;
 		struct hfcpci_chip hfcpci;
+		struct hfcsx_chip hfcsx;
 		struct w6692_chip w6692;
 	} dc;
 	u_char *rcvbuf;
@@ -1032,7 +1071,8 @@
 #define  ISDN_CTYPE_GAZEL	34
 #define  ISDN_CTYPE_HFC_PCI	35
 #define  ISDN_CTYPE_W6692	36
-#define  ISDN_CTYPE_COUNT	36
+#define  ISDN_CTYPE_HFC_SX      37
+#define  ISDN_CTYPE_COUNT	37
 
 
 #ifdef ISDN_CHIP_ISAC
@@ -1201,6 +1241,12 @@
 #define  CARD_HFC_PCI 0
 #endif
 
+#ifdef	CONFIG_HISAX_HFC_SX
+#define  CARD_HFC_SX 1
+#else
+#define  CARD_HFC_SX 0
+#endif
+
 #ifdef  CONFIG_HISAX_AMD7930
 #define CARD_AMD7930 1
 #else
@@ -1298,19 +1344,6 @@
 #ifdef CONFIG_HISAX_EURO
 #undef TEI_PER_CARD
 #define TEI_PER_CARD 1
-#define HISAX_EURO_SENDCOMPLETE 1
-#define EXT_BEARER_CAPS 1
-#define HISAX_SEND_STD_LLC_IE 1
-#ifdef	CONFIG_HISAX_NO_SENDCOMPLETE
-#undef HISAX_EURO_SENDCOMPLETE
-#endif
-#ifdef	CONFIG_HISAX_NO_LLC
-#undef HISAX_SEND_STD_LLC_IE
-#endif
-#undef HISAX_DE_AOC
-#ifdef CONFIG_DE_AOC
-#define HISAX_DE_AOC 1
-#endif
 #endif
 
 /* L1 Debug */
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/isar.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/isar.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.8 1999/12/19 13:00:56 keil Exp $
+/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $
 
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: isar.c,v $
+ * Revision 1.9  2000/01/20 19:47:45  keil
+ * Add Fax Class 1 support
+ *
  * Revision 1.8  1999/12/19 13:00:56  keil
  * Fix races in setting a new mode
  *
@@ -45,7 +48,17 @@
 
 #define MIN(a,b) ((a<b)?a:b)
 
+#define DLE	0x10
+#define ETX	0x03
+
+
+const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; 
+const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; 
+#define FAXMODCNT 13
+
 void isar_setup(struct IsdnCardState *cs);
+static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
+static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status);
 
 static inline int
 waitforHIA(struct IsdnCardState *cs, int timeout)
@@ -435,6 +448,12 @@
 isar_bh(struct BCState *bcs)
 {
 	BChannel_bh(bcs);
+	if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
+		ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
+	if (test_and_clear_bit(B_LL_CONNECT, &bcs->event))
+		ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+	if (test_and_clear_bit(B_LL_OK, &bcs->event))
+		ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);
 }
 
 static void
@@ -446,6 +465,42 @@
 }
 
 static inline void
+send_DLE_ETX(struct BCState *bcs)
+{
+	u_char dleetx[2] = {DLE,ETX};
+	struct sk_buff *skb;
+	
+	if ((skb = dev_alloc_skb(2))) {
+		memcpy(skb_put(skb, 2), dleetx, 2);
+		skb_queue_tail(&bcs->rqueue, skb);
+		isar_sched_event(bcs, B_RCVBUFREADY);
+	} else {
+		printk(KERN_WARNING "HiSax: skb out of memory\n");
+	}
+}
+
+static inline int
+dle_count(unsigned char *buf, int len)
+{
+	int count = 0;
+
+	while (len--)
+		if (*buf++ == DLE)
+			count++;
+	return count;
+}
+
+static inline void
+insert_dle(unsigned char *dest, unsigned char *src, int count) {
+	/* <DLE> in input stream have to be flagged as <DLE><DLE> */
+	while (count--) {
+		*dest++ = *src;
+		if (*src++ == DLE)
+			*dest++ = DLE;
+	}
+}
+ 
+static inline void
 isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
 {
 	u_char *ptr;
@@ -515,6 +570,88 @@
 			}
 		}
 		break;
+	case L1_MODE_FAX:
+		if (bcs->hw.isar.state != STFAX_ACTIV) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "isar_rcv_frame: not ACTIV");
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			bcs->hw.isar.rcvidx = 0;
+			break;
+		}
+		if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+			rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf);
+			bcs->hw.isar.rcvidx = ireg->clsb +
+				dle_count(bcs->hw.isar.rcvbuf, ireg->clsb);
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)",
+					ireg->clsb, bcs->hw.isar.rcvidx);
+			if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+				insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx),
+					bcs->hw.isar.rcvbuf, ireg->clsb);
+				skb_queue_tail(&bcs->rqueue, skb);
+				isar_sched_event(bcs, B_RCVBUFREADY);
+				if (ireg->cmsb & SART_NMD) { /* ABORT */
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "isar_rcv_frame: no more data");
+					cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+					bcs->hw.isar.rcvidx = 0;
+					send_DLE_ETX(bcs);
+					sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+						ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+						0, NULL);
+					bcs->hw.isar.state = STFAX_ESCAPE;
+					isar_sched_event(bcs, B_LL_NOCARRIER);
+				}
+			} else {
+				printk(KERN_WARNING "HiSax: skb out of memory\n");
+				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			}
+			break;
+		}
+		if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "isar_rcv_frame: unknown fax mode %x",
+					bcs->hw.isar.cmd);
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			bcs->hw.isar.rcvidx = 0;
+			break;
+		}
+		/* PCTRL_CMD_FRH */
+		if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "isar_rcv_frame: incoming packet too large");
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			bcs->hw.isar.rcvidx = 0;
+		} else if (ireg->cmsb & HDLC_ERROR) {
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "isar frame error %x len %d",
+					ireg->cmsb, ireg->clsb);
+			bcs->hw.isar.rcvidx = 0;
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+		} else {
+			if (ireg->cmsb & HDLC_FSD)
+				bcs->hw.isar.rcvidx = 0;
+			ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
+			bcs->hw.isar.rcvidx += ireg->clsb;
+			rcv_mbox(cs, ireg, ptr);
+			if (ireg->cmsb & HDLC_FED) {
+				if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
+					printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
+						bcs->hw.isar.rcvidx);
+				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+					printk(KERN_WARNING "ISAR: receive out of memory\n");
+				} else {
+					memcpy(skb_put(skb, bcs->hw.isar.rcvidx),
+						bcs->hw.isar.rcvbuf,
+						bcs->hw.isar.rcvidx);
+					skb_queue_tail(&bcs->rqueue, skb);
+					isar_sched_event(bcs, B_RCVBUFREADY);
+					send_DLE_ETX(bcs);
+					isar_sched_event(bcs, B_LL_OK);
+				}
+			}
+		}
+		break;
 	default:
 		printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
 		cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
@@ -547,38 +684,57 @@
 		count = bcs->tx_skb->len;
 		msb = HDLC_FED;
 	}
-	if (!bcs->hw.isar.txcnt)
-		msb |= HDLC_FST;
 	save_flags(flags);
 	cli();
 	ptr = bcs->tx_skb->data;
+	if (!bcs->hw.isar.txcnt) {
+		msb |= HDLC_FST;
+		if ((bcs->mode == L1_MODE_FAX) &&
+			(bcs->hw.isar.cmd == PCTRL_CMD_FTH)) {
+			if (bcs->tx_skb->len > 1) {
+				if ((ptr[0]== 0xff) && (ptr[1] == 0x13))
+					/* last frame */
+					test_and_set_bit(BC_FLG_LASTDATA,
+						&bcs->Flag);
+			}  
+		}
+	}
 	skb_pull(bcs->tx_skb, count);
 	bcs->tx_cnt -= count;
 	bcs->hw.isar.txcnt += count;
 	switch (bcs->mode) {
-	case L1_MODE_NULL:
-		printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
-		break;
-	case L1_MODE_TRANS:
-	case L1_MODE_V32:
-		if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
-			0, count, ptr)) {
-			if (cs->debug)
-				debugl1(cs, "isar bin data send dp%d failed",
-					bcs->hw.isar.dpath);
-		}
-		break;
-	case L1_MODE_HDLC:
-		if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
-			msb, count, ptr)) {
+		case L1_MODE_NULL:
+			printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
+			break;
+		case L1_MODE_TRANS:
+		case L1_MODE_V32:
+			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+				0, count, ptr);
+			break;
+		case L1_MODE_HDLC:
+			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+				msb, count, ptr);
+			break;
+		case L1_MODE_FAX:
+			if (bcs->hw.isar.state != STFAX_ACTIV) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "isar_fill_fifo: not ACTIV");
+			} else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { 
+				sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+					msb, count, ptr);
+			} else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+				sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+					0, count, ptr);
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "isar_fill_fifo: not FTH/FTM");
+			}
+			break;
+		default:
 			if (cs->debug)
-				debugl1(cs, "isar hdlc data send dp%d failed",
-					bcs->hw.isar.dpath);
-		}
-		break;
-	default:
-		printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode);
-		break;
+				debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode);
+			printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
+			break;
 	}
 	restore_flags(flags);
 }
@@ -606,6 +762,18 @@
 			if (bcs->st->lli.l1writewakeup &&
 				(PACKET_NOACK != bcs->tx_skb->pkt_type))
 					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt);
+			if (bcs->mode == L1_MODE_FAX) {
+				if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+					if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+						test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+					}
+				} else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) {
+					if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+						test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag);
+						test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag);
+					}
+				}
+			}
 			dev_kfree_skb(bcs->tx_skb);
 			bcs->hw.isar.txcnt = 0; 
 			bcs->tx_skb = NULL;
@@ -616,6 +784,18 @@
 		test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
 		isar_fill_fifo(bcs);
 	} else {
+		if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) {
+			if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
+				if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) {
+					u_char dummy = 0;
+					sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) |
+						ISAR_HIS_SDATA, 0x01, 1, &dummy);
+				}
+				test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag);
+			} else {
+				isar_sched_event(bcs, B_LL_CONNECT);
+			}
+		}
 		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 		isar_sched_event(bcs, B_XMTBUFREADY);
 	}
@@ -642,6 +822,7 @@
 	}
 	
 }
+
 const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
 			"300", "600", "1200", "2400", "4800", "7200",
 			"9600nt", "9600t", "12000", "14400", "WRONG"};
@@ -703,7 +884,7 @@
 }
 
 static void
-isar_pump_status_ev(struct BCState *bcs, u_char devt) {
+isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
 	struct IsdnCardState *cs = bcs->cs;
 	u_char dps = SET_DPS(bcs->hw.isar.dpath);
 
@@ -772,6 +953,192 @@
 	}
 }
 
+static inline void
+ll_deliver_faxstat(struct BCState *bcs, u_char status)
+{
+        isdn_ctrl ic;
+	struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
+ 
+	if (bcs->cs->debug & L1_DEB_HSCX)
+		debugl1(bcs->cs, "HL->LL FAXIND %x", status);
+	ic.driver = bcs->cs->myid;
+	ic.command = ISDN_STAT_FAXIND;
+	ic.arg = chanp->chan;
+	ic.parm.aux.cmd = status;
+	bcs->cs->iif.statcallb(&ic);
+}
+
+static void
+isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
+	struct IsdnCardState *cs = bcs->cs;
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char p1;
+
+	switch(devt) {
+		case PSEV_10MS_TIMER:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev TIMER");
+			break;
+		case PSEV_RSP_READY:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev RSP_READY");
+			bcs->hw.isar.state = STFAX_READY;
+			l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL);
+			if (test_bit(BC_FLG_ORIG, &bcs->Flag)) {
+				isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3);
+			} else {
+				isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3);
+			}
+			break;
+		case PSEV_LINE_TX_H:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev LINE_TX_H");
+				bcs->hw.isar.state = STFAX_CONT;
+				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "pump stev LINE_TX_H wrong st %x",
+						bcs->hw.isar.state);
+			}
+			break;
+		case PSEV_LINE_RX_H:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev LINE_RX_H");
+				bcs->hw.isar.state = STFAX_CONT;
+				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "pump stev LINE_RX_H wrong st %x",
+						bcs->hw.isar.state);
+			}
+			break;
+		case PSEV_LINE_TX_B:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev LINE_TX_B");
+				bcs->hw.isar.state = STFAX_CONT;
+				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "pump stev LINE_TX_B wrong st %x",
+						bcs->hw.isar.state);
+			}
+			break;
+		case PSEV_LINE_RX_B:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev LINE_RX_B");
+				bcs->hw.isar.state = STFAX_CONT;
+				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL);
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "pump stev LINE_RX_B wrong st %x",
+						bcs->hw.isar.state);
+			}
+			break;
+		case PSEV_RSP_CONN:
+			if (bcs->hw.isar.state == STFAX_CONT) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev RSP_CONN");
+				bcs->hw.isar.state = STFAX_ACTIV;
+				test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags);
+				sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+				if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
+					/* 1s Flags before data */
+					if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag))
+						del_timer(&bcs->hw.isar.ftimer);
+					/* 1000 ms */
+					bcs->hw.isar.ftimer.expires =
+						jiffies + ((1000 * HZ)/1000);
+					test_and_set_bit(BC_FLG_LL_CONN,
+						&bcs->Flag);
+					add_timer(&bcs->hw.isar.ftimer);
+				} else {
+					isar_sched_event(bcs, B_LL_CONNECT);
+				}
+			} else {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "pump stev RSP_CONN wrong st %x",
+						bcs->hw.isar.state);
+			}
+			break;
+		case PSEV_FLAGS_DET:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev FLAGS_DET");
+			break;
+		case PSEV_RSP_DISC:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev RSP_DISC");
+			if (bcs->hw.isar.state == STFAX_ESCAPE) {
+				switch(bcs->hw.isar.newcmd) {
+					case PCTRL_CMD_FTH:
+					case PCTRL_CMD_FTM:
+						p1 = 10;
+						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+							PCTRL_CMD_SILON, 1, &p1);
+						bcs->hw.isar.state = STFAX_SILDET;
+						break;
+					case PCTRL_CMD_FRH:
+					case PCTRL_CMD_FRM:
+						p1 = bcs->hw.isar.newmod;
+						bcs->hw.isar.newmod = 0;
+						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+						bcs->hw.isar.newcmd = 0;
+						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+							bcs->hw.isar.cmd, 1, &p1);
+						bcs->hw.isar.state = STFAX_LINE;
+						break;
+					default:
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd);
+						break;
+				}
+			} else if (bcs->hw.isar.state == STFAX_ACTIV) {
+				if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) {
+					isar_sched_event(bcs, B_LL_OK);
+				} else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) {
+					send_DLE_ETX(bcs);
+					isar_sched_event(bcs, B_LL_NOCARRIER);
+				} else {
+					ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+				}
+				bcs->hw.isar.state = STFAX_READY;
+			} else {
+				bcs->hw.isar.state = STFAX_READY;
+				ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+			}
+			break;
+		case PSEV_RSP_SILDET:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev RSP_SILDET");
+			if (bcs->hw.isar.state == STFAX_SILDET) {
+				p1 = bcs->hw.isar.newmod;
+				bcs->hw.isar.newmod = 0;
+				bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+				bcs->hw.isar.newcmd = 0;
+				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+					bcs->hw.isar.cmd, 1, &p1);
+				bcs->hw.isar.state = STFAX_LINE;
+			}
+			break;
+		case PSEV_RSP_SILOFF:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev RSP_SILOFF");
+			break;
+		case PSEV_RSP_FCERR:
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "pump stev RSP_FCERR");
+			bcs->hw.isar.state = STFAX_ESCAPE;
+			sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+			ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR);
+			break;
+		default:
+			break;
+	}
+}
+
 static char debbuf[128];
 
 void
@@ -791,8 +1158,6 @@
 			} else {
 				debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n",
-					ireg->iis, ireg->cmsb, ireg->clsb);
 				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
@@ -818,12 +1183,18 @@
 		case ISAR_IIS_PSTEV:
 			if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
 				rcv_mbox(cs, ireg, (u_char *)ireg->par);
-				isar_pump_status_ev(bcs, ireg->cmsb);
+				if (bcs->mode == L1_MODE_V32) {
+					isar_pump_statev_modem(bcs, ireg->cmsb);
+				} else if (bcs->mode == L1_MODE_FAX) {
+					isar_pump_statev_fax(bcs, ireg->cmsb);
+				} else {
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
+							bcs->mode, ireg->cmsb);
+				}
 			} else {
 				debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				printk(KERN_WARNING"isar spurious IIS_PSTEV %x/%x/%x\n",
-					ireg->iis, ireg->cmsb, ireg->clsb);
 				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
@@ -834,8 +1205,6 @@
 			} else {
 				debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x",
 					ireg->iis, ireg->cmsb, ireg->clsb);
-				printk(KERN_WARNING"isar spurious IIS_PSTRSP %x/%x/%x\n",
-					ireg->iis, ireg->cmsb, ireg->clsb);
 				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
@@ -870,6 +1239,17 @@
 }
 
 static void
+ftimer_handler(struct BCState *bcs) {
+	if (bcs->cs->debug)
+		debugl1(bcs->cs, "ftimer flags %04x",
+			bcs->Flag);
+	test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
+	if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
+		isar_sched_event(bcs, B_LL_CONNECT);
+	}
+}
+
+static void
 setup_pump(struct BCState *bcs) {
 	struct IsdnCardState *cs = bcs->cs;
 	u_char dps = SET_DPS(bcs->hw.isar.dpath);
@@ -879,11 +1259,7 @@
 		case L1_MODE_NULL:
 		case L1_MODE_TRANS:
 		case L1_MODE_HDLC:
-			if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) {
-				if (cs->debug)
-					debugl1(cs, "isar pump bypass cfg dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
 			break;
 		case L1_MODE_V32:
 			ctrl = PMOD_DATAMODEM;
@@ -899,11 +1275,7 @@
 			param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
 			param[3] = PV32P4_UT144;
 			param[4] = PV32P5_UT144;
-			if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) {
-				if (cs->debug)
-					debugl1(cs, "isar pump datamodem cfg dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
 			break;
 		case L1_MODE_FAX:
 			ctrl = PMOD_FAX;
@@ -914,11 +1286,11 @@
 				param[1] = PFAXP2_ATN;
 			}
 			param[0] = 6; /* 6 db */
-			if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) {
-				if (cs->debug)
-					debugl1(cs, "isar pump faxmodem cfg dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+			bcs->hw.isar.state = STFAX_NULL;
+			bcs->hw.isar.newcmd = 0;
+			bcs->hw.isar.newmod = 0;
+			test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag);
 			break;
 	}
 	udelay(1000);
@@ -934,37 +1306,25 @@
 	
 	switch (bcs->mode) {
 		case L1_MODE_NULL:
-			if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) {
-				if (cs->debug)
-					debugl1(cs, "isar sart disable dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0,
+				NULL);
 			break;
 		case L1_MODE_TRANS:
-			if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) {
-				if (cs->debug)
-					debugl1(cs, "isar sart binary dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2,
+				"\0\0");
 			break;
 		case L1_MODE_HDLC:
 		case L1_MODE_FAX:
 			param[0] = 0;
-			if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) {
-				if (cs->debug)
-					debugl1(cs, "isar sart hdlc dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
+				param);
 			break;
 		case L1_MODE_V32:
 			ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
 			param[0] = S_P1_CHS_8;
 			param[1] = S_P2_BFT_DEF;
-			if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param)) {
-				if (cs->debug)
-					debugl1(cs, "isar sart v14 dp%d failed",
-						bcs->hw.isar.dpath);
-			}
+			sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
+				param);
 			break;
 	}
 	udelay(1000);
@@ -1035,8 +1395,8 @@
 					&bcs->hw.isar.reg->Flags))
 					bcs->hw.isar.dpath = 1;
 				else {
-					printk(KERN_WARNING"isar modeisar analog works only with DP1\n");
-					debugl1(cs, "isar modeisar analog works only with DP1");
+					printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
+					debugl1(cs, "isar modeisar analog funktions only with DP1");
 					return(1);
 				}
 				break;
@@ -1060,6 +1420,107 @@
 	return(0);
 }
 
+static void
+isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) 
+{
+	struct IsdnCardState *cs = bcs->cs;
+	u_char dps = SET_DPS(bcs->hw.isar.dpath);
+	u_char ctrl = 0, nom = 0, p1 = 0;
+
+	switch(cmd) {
+		case ISDN_FAX_CLASS1_FTM:
+			if (bcs->hw.isar.state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FTM;
+				nom = 1;
+				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.cmd = ctrl;
+				bcs->hw.isar.mod = para;
+				bcs->hw.isar.newmod = 0;
+				bcs->hw.isar.newcmd = 0;
+			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+				(bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
+				(bcs->hw.isar.mod == para)) {
+				ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+			} else {
+				bcs->hw.isar.newmod = para;
+				bcs->hw.isar.newcmd = PCTRL_CMD_FTM;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				bcs->hw.isar.state = STFAX_ESCAPE; 
+			}
+			break;
+		case ISDN_FAX_CLASS1_FTH:
+			if (bcs->hw.isar.state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FTH;
+				nom = 1;
+				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.cmd = ctrl;
+				bcs->hw.isar.mod = para;
+				bcs->hw.isar.newmod = 0;
+				bcs->hw.isar.newcmd = 0;
+			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+				(bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
+				(bcs->hw.isar.mod == para)) {
+				ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+			} else {
+				bcs->hw.isar.newmod = para;
+				bcs->hw.isar.newcmd = PCTRL_CMD_FTH;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				bcs->hw.isar.state = STFAX_ESCAPE; 
+			}
+			break;
+		case ISDN_FAX_CLASS1_FRM:
+			if (bcs->hw.isar.state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FRM;
+				nom = 1;
+				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.cmd = ctrl;
+				bcs->hw.isar.mod = para;
+				bcs->hw.isar.newmod = 0;
+				bcs->hw.isar.newcmd = 0;
+			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+				(bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
+				(bcs->hw.isar.mod == para)) {
+				ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+			} else {
+				bcs->hw.isar.newmod = para;
+				bcs->hw.isar.newcmd = PCTRL_CMD_FRM;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				bcs->hw.isar.state = STFAX_ESCAPE; 
+			}
+			break;
+		case ISDN_FAX_CLASS1_FRH:
+			if (bcs->hw.isar.state == STFAX_READY) {
+				p1 = para;
+				ctrl = PCTRL_CMD_FRH;
+				nom = 1;
+				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.cmd = ctrl;
+				bcs->hw.isar.mod = para;
+				bcs->hw.isar.newmod = 0;
+				bcs->hw.isar.newcmd = 0;
+			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
+				(bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
+				(bcs->hw.isar.mod == para)) {
+				ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT);
+			} else {
+				bcs->hw.isar.newmod = para;
+				bcs->hw.isar.newcmd = PCTRL_CMD_FRH;
+				nom = 0;
+				ctrl = PCTRL_CMD_ESC;
+				bcs->hw.isar.state = STFAX_ESCAPE; 
+			}
+			break;
+	}
+	if (ctrl)
+		sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
 void
 isar_setup(struct IsdnCardState *cs)
 {
@@ -1070,11 +1531,8 @@
 	msg = 61;
 	for (i=0; i<2; i++) {
 		/* Buffer Config */
-		if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
-			ISAR_HIS_P12CFG, 4, 1, &msg)) {
-			if (cs->debug)
-				debugl1(cs, "isar P%dCFG failed", i+1);
-		}
+		sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+			ISAR_HIS_P12CFG, 4, 1, &msg);
 		cs->bcs[i].hw.isar.mml = msg;
 		cs->bcs[i].mode = 0;
 		cs->bcs[i].hw.isar.dpath = i + 1;
@@ -1141,6 +1599,7 @@
 						l1_msg_b(st, PH_ACTIVATE | REQUEST, arg);
 					break;
 				case L1_MODE_V32:
+				case L1_MODE_FAX:
 					if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc))
 						l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg);
 					break;
@@ -1179,6 +1638,7 @@
 				debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
 		}
 	}
+	del_timer(&bcs->hw.isar.ftimer);
 }
 
 int
@@ -1200,6 +1660,9 @@
 	bcs->event = 0;
 	bcs->hw.isar.rcvidx = 0;
 	bcs->tx_cnt = 0;
+	bcs->hw.isar.ftimer.function = (void *) ftimer_handler;
+	bcs->hw.isar.ftimer.data = (long) bcs;
+	init_timer(&bcs->hw.isar.ftimer);
 	return (0);
 }
 
@@ -1220,15 +1683,66 @@
 int
 isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
 	u_long adr;
-	int features;
+	int features, i;
+	struct BCState *bcs;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
 	switch (ic->command) {
+		case (ISDN_CMD_FAXCMD):
+			bcs = cs->channel[ic->arg].bcs;
+			if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d",
+					ic->parm.aux.cmd, ic->parm.aux.subcmd);
+			switch(ic->parm.aux.cmd) {
+				case ISDN_FAX_CLASS1_CTRL:
+					if (ic->parm.aux.subcmd == ETX)
+						test_and_set_bit(BC_FLG_DLEETX,
+							&bcs->Flag);
+					break;
+				case ISDN_FAX_CLASS1_FRM:
+				case ISDN_FAX_CLASS1_FRH:
+				case ISDN_FAX_CLASS1_FTM:
+				case ISDN_FAX_CLASS1_FTH:
+					if (ic->parm.aux.subcmd == AT_QUERY) {
+						sprintf(ic->parm.aux.para,
+							"%d", bcs->hw.isar.mod);
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+						strcpy(ic->parm.aux.para, faxmodulation_s);
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						for(i=0;i<FAXMODCNT;i++)
+							if (faxmodulation[i]==ic->parm.aux.para[0])
+								break;
+						if ((FAXMODCNT > i) && 
+							test_bit(BC_FLG_INIT, &bcs->Flag)) {
+							isar_pump_cmd(bcs,
+								ic->parm.aux.cmd,
+								ic->parm.aux.para[0]);
+							return(0);
+						}
+					}
+					/* wrong modulation or not activ */
+					/* fall through */
+				default:
+					ic->command = ISDN_STAT_FAXIND;
+					ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+					cs->iif.statcallb(ic);
+			}
+			break;
 		case (ISDN_CMD_IOCTL):
 			switch (ic->arg) {
 				case (9): /* load firmware */
-					features = ISDN_FEATURE_L2_MODEM;
+					features = ISDN_FEATURE_L2_MODEM |
+						ISDN_FEATURE_L2_FAX |
+						ISDN_FEATURE_L3_FCLASS1;
 					memcpy(&adr, ic->parm.num, sizeof(ulong));
 					if (isar_load_firmware(cs, (u_char *)adr))
 						return(1);
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h
--- linux-2.2.15-pre4/drivers/isdn/hisax/isar.h	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/isar.h	Mon Dec  3 21:58:30 2001
@@ -1,10 +1,13 @@
-/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $
+/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $
  * isar.h   ISAR (Siemens PSB 7110) specific defines
  *
  * Author Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: isar.h,v $
+ * Revision 1.7  2000/01/20 19:47:45  keil
+ * Add Fax Class 1 support
+ *
  * Revision 1.6  1999/10/14 20:25:29  keil
  * add a statistic for error monitoring
  *
@@ -145,6 +148,28 @@
 #define PSEV_REM_REN	0xcd
 #define PSEV_GSTN_CLR	0xd4
 
+#define PSEV_RSP_READY	0xbc
+#define PSEV_LINE_TX_H	0xb3
+#define PSEV_LINE_TX_B	0xb2
+#define PSEV_LINE_RX_H	0xb1
+#define PSEV_LINE_RX_B	0xb0
+#define PSEV_RSP_CONN	0xb5
+#define PSEV_RSP_DISC	0xb7
+#define PSEV_RSP_FCERR	0xb9
+#define PSEV_RSP_SILDET	0xbe
+#define PSEV_RSP_SILOFF	0xab
+#define PSEV_FLAGS_DET	0xba
+
+#define PCTRL_CMD_FTH	0xa7
+#define PCTRL_CMD_FRH	0xa5
+#define PCTRL_CMD_FTM	0xa8
+#define PCTRL_CMD_FRM	0xa6
+#define PCTRL_CMD_SILON	0xac
+#define PCTRL_CMD_CONT	0xa2
+#define PCTRL_CMD_ESC	0xa4
+#define PCTRL_CMD_SILOFF 0xab
+#define PCTRL_CMD_HALT	0xa9
+
 #define PCTRL_LOC_RET	0xcf
 #define PCTRL_LOC_REN	0xce
 
@@ -192,6 +217,15 @@
 #define BSTAT_RDM3	0x8
 #define BSTEV_TBO	0x1f
 #define BSTEV_RBO	0x2f
+
+/* FAX State Machine */
+#define STFAX_NULL	0
+#define STFAX_READY	1
+#define STFAX_LINE	2
+#define STFAX_CONT	3
+#define STFAX_ACTIV	4
+#define STFAX_ESCAPE	5
+#define STFAX_SILDET	6
 
 extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/isdnl1.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $
+/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 keil Exp $
 
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
@@ -15,6 +15,10 @@
  *
  *
  * $Log: isdnl1.c,v $
+ * Revision 2.37  2000/01/20 19:51:46  keil
+ * Fix AddTimer message
+ * Change CONFIG defines
+ *
  * Revision 2.36  1999/08/25 16:50:57  keil
  * Fix bugs which cause 2.3.14 hangs (waitqueue init)
  *
@@ -138,7 +142,7 @@
  *
  */
 
-const char *l1_revision = "$Revision: 2.36 $";
+const char *l1_revision = "$Revision: 2.37 $";
 
 #define __NO_VERSION__
 #include "hisax.h"
@@ -362,7 +366,8 @@
 					stptr = stptr->next;
 			if (!found)
 				dev_kfree_skb(skb);
-		}
+		} else
+			dev_kfree_skb(skb);
 	}
 }
 
@@ -559,11 +564,8 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_F3);
-//	if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
-		FsmDelTimer(&st->l1.timer, 1);
-		FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
-		test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
-//	}
+	FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+	test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
 }
 
 static void
@@ -574,8 +576,7 @@
 	if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
 		FsmChangeState(fi, ST_L1_F4);
 		st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
-		FsmDelTimer(&st->l1.timer, 1);
-		FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+		FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
 		test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
 	} else
 		FsmChangeState(fi, ST_L1_F3);
@@ -614,7 +615,7 @@
 	if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
 		if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
 			FsmDelTimer(&st->l1.timer, 3);
-		FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
+		FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
 		test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
 	}
 }
@@ -729,7 +730,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_WAIT_ACT);
-	FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
+	FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
 }
 
 static void
@@ -738,7 +739,7 @@
 	struct PStack *st = fi->userdata;
 
 	FsmChangeState(fi, ST_L1_WAIT_DEACT);
-	FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
+	FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
 }
 
 static void
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/l3_1tr6.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/isdn/hisax/l3_1tr6.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 2.9 1999/07/01 08:11:55 keil Exp $
+/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $
 
  *  German 1TR6 D-channel protocol
  *
@@ -10,6 +10,9 @@
  *
  *
  * $Log: l3_1tr6.c,v $
+ * Revision 2.10  2000/01/20 19:42:01  keil
+ * Fixed uninitialiesed location
+ *
  * Revision 2.9  1999/07/01 08:11:55  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -59,7 +62,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.9 $";
+const char *l3_1tr6_revision = "$Revision: 2.10 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
 	*ptr++ = dis; \
@@ -699,6 +702,7 @@
 {
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
+        pc->para.loc = 0;
         pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/l3dss1.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/l3dss1.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.21 1999/12/19 20:25:17 keil Exp $
+/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
@@ -13,6 +13,12 @@
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
+ * Revision 2.22  2000/01/20 19:44:20  keil
+ * Fixed uninitialiesed location
+ * Fixed redirecting number IE in Setup
+ * Changes from certification
+ * option for disabling use of KEYPAD protocol
+ *
  * Revision 2.21  1999/12/19 20:25:17  keil
  * fixed LLC for outgoing analog calls
  * IE Signal is valid on older local switches
@@ -95,9 +101,10 @@
 #include "isdnl3.h"
 #include "l3dss1.h"
 #include <linux/ctype.h>
+#include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.21 $";
+const char *dss1_revision = "$Revision: 2.22 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -698,8 +705,8 @@
 static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER  | IE_MANDATORY,
 		IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
 		IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
-		IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC,
-		IE_USER_USER, -1};
+		IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+		IE_LLC, IE_HLC, IE_USER_USER, -1};
 static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
 		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
 static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
@@ -1278,6 +1285,7 @@
 	u_char tmp[128];
 	u_char *p = tmp;
 	u_char channel = 0;
+
         u_char send_keypad;
 	u_char screen = 0x80;
 	u_char *teln;
@@ -1289,14 +1297,18 @@
 	MsgHead(p, pc->callref, MT_SETUP);
 
 	teln = pc->para.setup.phone;
+#ifndef CONFIG_HISAX_NO_KEYPAD
         send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0; 
+#else
+	send_keypad = 0;
+#endif
+#ifndef CONFIG_HISAX_NO_SENDCOMPLETE
+	if (!send_keypad)
+		*p++ = 0xa1;		/* complete indicator */
+#endif
 	/*
 	 * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
 	 */
-#if HISAX_EURO_SENDCOMPLETE
-	if (!send_keypad)
-	  *p++ = 0xa1;		/* complete indicator */
-#endif
         if (!send_keypad)
 	  switch (pc->para.setup.si1) {
 		case 1:	/* Telephony                               */
@@ -1458,7 +1470,7 @@
 		*p++ = 0x90;
 		*p++ = 0x21;
 		p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
-#if HISAX_SEND_STD_LLC_IE
+#ifndef CONFIG_HISAX_NO_LLC
 	} else {
 	  switch (pc->para.setup.si1) {
 		case 1:	/* Telephony                               */
@@ -2757,6 +2769,7 @@
 l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
 {
         pc->para.cause = 0x29;          /* Temporary failure */
+        pc->para.loc = 0;
         l3dss1_disconnect_req(pc, pr, NULL);
         pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
@@ -2766,6 +2779,7 @@
 {
         newl3state(pc, 0);
         pc->para.cause = 0x1b;          /* Destination out of order */
+        pc->para.loc = 0;
         pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
         release_l3_process(pc);
 }
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h
--- linux-2.2.15-pre4/drivers/isdn/hisax/l3dss1.h	Mon Aug  9 12:04:39 1999
+++ linux/drivers/isdn/hisax/l3dss1.h	Mon Dec  3 21:58:30 2001
@@ -1,8 +1,11 @@
-/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $
+/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $
  *
  *  DSS1 (Euro) D-channel protocol defines
  *
  * $Log: l3dss1.h,v $
+ * Revision 1.8  2000/01/20 19:46:15  keil
+ * Changes from certification
+ *
  * Revision 1.7  1999/07/01 08:12:02  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -35,6 +38,8 @@
 #define T304	30000
 #define T305	30000
 #define T308	4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
 #define T309	40000
 #define T310	30000
 #define T313	4000
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc
--- linux-2.2.15-pre4/drivers/isdn/hisax/md5sums.asc	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/md5sums.asc	Mon Dec  3 21:58:30 2001
@@ -7,14 +7,14 @@
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
 3c2b1c96274cba97a8261d1cecc662b8  isac.c
-a9a15d069dbacb383cc24c238cb5ebbe  isdnl1.c
+dd3955847bbf680b41233478fe521d88  isdnl1.c
 bb51bd223040b511c18f091da5ab6456  isdnl2.c
 b7aa7f97b2374967a4aca7c52991142c  isdnl3.c
 a23fbf8879c1432b04640b8b04bdf419  tei.c
 ce248e56c2e1326012d0b25f92bbf99b  callc.c
 bf9605b36429898f7be6630034e83230  cert.c
-2dbd5fadc33657c654f71385ff84127a  l3dss1.c
-2d748ced0eea375b21fe7ea91ca7917c  l3_1tr6.c
+233960fa9fc46aaffcaa883b5b59cf4e  l3dss1.c
+a3a570781f828b6d59e6b231653133de  l3_1tr6.c
 8188deeb4a1b34c574cd51638cd214d0  elsa.c
 a3c2b8e9d2c623658888b5f1d4317c2a  diva.c
 # end of md5sums
@@ -23,9 +23,9 @@
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBOGUfJzpxHvX/mS9tAQFpwwP/UFR+IP3URpDrRPJgWdzaP+Ho/nu4uOQM
-+l2d0MNZlBPIPiRJnP921mcSXUw37OsuXf8cfqihuCgc+2+ExNZe9s9o/Wz5TttA
-L1fhoP85OXy6m5Ap77Feh1tzxAQodRwIzzFvrXqUUN82JW32Q931dJzxVbYtgP16
-SkErM8N2GbM=
-=QeLI
+iQCVAwUBOIdqVzpxHvX/mS9tAQGaWQP+Pj0oVxbhusXnlNOQ+FV6YOGj1HGMXPsO
+C/9555qSbvcKg64OO8VdU1LWq/RCsAwBkJ3eSizF5LbWD8lhCHUpkNlzEv4fIaHe
+fAA9zLnC8Vk4h/YLwUNfZxezYvf22NGSydXGZH4VvLAigF0OGRlKaewsR61KZ/Fh
+4GnVqcxYaH8=
+=eINS
 -----END PGP SIGNATURE-----
diff -urN linux-2.2.15-pre4/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- linux-2.2.15-pre4/drivers/isdn/hisax/sedlbauer.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/hisax/sedlbauer.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.19 1999/12/19 13:09:42 keil Exp $
+/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $
 
  * sedlbauer.c  low level stuff for Sedlbauer cards
  *              includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,9 @@
  *            Edgar Toernig
  *
  * $Log: sedlbauer.c,v $
+ * Revision 1.20  2000/01/20 19:47:45  keil
+ * Add Fax Class 1 support
+ *
  * Revision 1.19  1999/12/19 13:09:42  keil
  * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
  * signal proof delays
@@ -114,7 +117,7 @@
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.19 $";
+const char *Sedlbauer_revision = "$Revision: 1.20 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+", 
@@ -663,15 +666,13 @@
 			(sub_id == PCI_SUB_ID_SPEEDFAXP)) {
 			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
 			cs->subtyp = SEDL_SPEEDFAX_PCI;
-			cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
-						SEDL_ISAR_PCI_ISAR_RESET_ON;
-			cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
-						SEDL_ISAR_PCI_ISAR_RESET_OFF;
 		} else {
 			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
 			cs->subtyp = SEDL_SPEED_PCI;
 		}
 		bytecnt = 256;
+		cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+		cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
 		byteout(cs->hw.sedl.cfg_reg, 0xff);
 		byteout(cs->hw.sedl.cfg_reg, 0x00);
 		byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- linux-2.2.15-pre4/drivers/isdn/isdn_common.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/isdn_common.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $
+/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,32 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.97  2000/01/23 18:45:37  keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.96  2000/01/20 19:55:33  keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.95  2000/01/09 20:43:13  detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.94  1999/11/20 22:14:13  detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * 	to many connection's in short time.
+ * 	config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * 	or remote side.
+ * 	wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
  * Revision 1.93  1999/11/04 13:11:36  keil
  * Reinit of v110 structs
  *
@@ -416,7 +442,7 @@
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.93 $";
+static char *isdn_revision = "$Revision: 1.97 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -438,6 +464,7 @@
 
 
 static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+static void set_global_features(void);
 
 void
 isdn_MOD_INC_USE_COUNT(void)
@@ -720,29 +747,33 @@
 int
 isdn_command(isdn_ctrl *cmd)
 {
+	if (cmd->driver == -1) {
+		printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
+		return(1);
+	}
 	if (cmd->command == ISDN_CMD_SETL2) {
-			int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
-			unsigned long l2prot = (cmd->arg >> 8) & 255;
-			unsigned long features = (dev->drv[cmd->driver]->interface->features
-						 >> ISDN_FEATURE_L2_SHIFT) &
-				ISDN_FEATURE_L2_MASK;
-			unsigned long l2_feature = (1 << l2prot);
-
-			switch (l2prot) {
-				case ISDN_PROTO_L2_V11096:
-				case ISDN_PROTO_L2_V11019:
-				case ISDN_PROTO_L2_V11038:
-						/* If V.110 requested, but not supported by
-						 * HL-driver, set emulator-flag and change
-						 * Layer-2 to transparent
-						 */
-					if (!(features & l2_feature)) {
-						dev->v110emu[idx] = l2prot;
-						cmd->arg = (cmd->arg & 255) |
-								   (ISDN_PROTO_L2_TRANS << 8);
-					} else
-						dev->v110emu[idx] = 0;
-			}
+		int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+		unsigned long l2prot = (cmd->arg >> 8) & 255;
+		unsigned long features = (dev->drv[cmd->driver]->interface->features
+						>> ISDN_FEATURE_L2_SHIFT) &
+						ISDN_FEATURE_L2_MASK;
+		unsigned long l2_feature = (1 << l2prot);
+
+		switch (l2prot) {
+			case ISDN_PROTO_L2_V11096:
+			case ISDN_PROTO_L2_V11019:
+			case ISDN_PROTO_L2_V11038:
+			/* If V.110 requested, but not supported by
+			 * HL-driver, set emulator-flag and change
+			 * Layer-2 to transparent
+			 */
+				if (!(features & l2_feature)) {
+					dev->v110emu[idx] = l2prot;
+					cmd->arg = (cmd->arg & 255) |
+						(ISDN_PROTO_L2_TRANS << 8);
+				} else
+					dev->v110emu[idx] = 0;
+		}
 	}
 	return dev->drv[cmd->driver]->interface->command(cmd);
 }
@@ -822,6 +853,7 @@
 			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 				if (dev->drvmap[i] == di)
 					isdn_all_eaz(di, dev->chanmap[i]);
+			set_global_features();
 			break;
 		case ISDN_STAT_STOP:
 			dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
@@ -1079,6 +1111,7 @@
 			dev->drv[di] = NULL;
 			dev->drvid[di][0] = '\0';
 			isdn_info_update();
+			set_global_features();
 			restore_flags(flags);
 			return 0;
 		case ISDN_STAT_L1ERR:
@@ -1564,6 +1597,9 @@
  * are serialized by means of a semaphore.
  */
 		switch (cmd) {
+			case IIOCNETDWRSET:
+				printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+				return(-EINVAL);
 			case IIOCNETLCR:
 				printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
 				return -ENODEV;
@@ -1855,7 +1891,7 @@
 						for (i = 0; i < 10; i++) {
 							sprintf(bname, "%s%s",
 								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-								dev->drv[drvidx]->msn2eaz[i] : "-",
+								dev->drv[drvidx]->msn2eaz[i] : "_",
 								(i < 9) ? "," : "\0");
 							if (copy_to_user(p, bname, strlen(bname) + 1))
 								return -EFAULT;
@@ -2061,7 +2097,7 @@
 
 int
 isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
-		      ,int pre_chan)
+		      ,int pre_chan, char *msn)
 {
 	int i;
 	ulong flags;
@@ -2084,6 +2120,8 @@
 			if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
 			((pre_dev != d) || (pre_chan != dev->chanmap[i])))
 				continue;
+			if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
+				continue;
 			if (dev->usage[i] & ISDN_USAGE_DISABLED)
 			        continue; /* usage not allowed */
 			if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
@@ -2374,6 +2412,19 @@
  * Low-level-driver registration
  */
 
+static void
+set_global_features(void)
+{
+	int drvidx;
+
+	dev->global_features = 0;
+	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+		if (!dev->drv[drvidx])
+			continue;
+		if (dev->drv[drvidx]->interface)
+			dev->global_features |= dev->drv[drvidx]->interface->features;
+	}
+}
 
 #ifdef CONFIG_ISDN_DIVERSION
 extern isdn_divert_if *divert_if;
@@ -2487,6 +2538,7 @@
 	strcpy(dev->drvid[drvidx], i->id);
 	isdn_info_update();
 	dev->drivers++;
+	set_global_features();
 	restore_flags(flags);
 	return 1;
 }
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- linux-2.2.15-pre4/drivers/isdn/isdn_common.h	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/isdn_common.h	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_common.h,v 1.18 2000/01/23 18:45:37 keil Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.18  2000/01/23 18:45:37  keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
  * Revision 1.17  1999/10/27 21:21:17  detabc
  * Added support for building logically-bind-group's per interface.
  * usefull for outgoing call's with more then one isdn-card.
@@ -128,7 +131,7 @@
 extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
 extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
-extern int isdn_get_free_channel(int, int, int, int, int);
+extern int isdn_get_free_channel(int, int, int, int, int, char *);
 extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int register_isdn(isdn_if * i);
 extern int isdn_wildmat(char *, char *);
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux-2.2.15-pre4/drivers/isdn/isdn_net.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/isdn_net.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
+/* $Id: isdn_net.c,v 1.103 2000/01/23 18:45:37 keil Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,46 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.103  2000/01/23 18:45:37  keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.102  2000/01/09 20:43:14  detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.101  1999/12/05 16:06:08  detabc
+ * add resethandling for rawip-compression.
+ * at now all B2-Protocols are usable with rawip-compression
+ *
+ * Revision 1.100  1999/12/04 15:05:25  detabc
+ * bugfix abc-rawip-bsdcompress with channel-bundeling
+ *
+ * Revision 1.99  1999/11/30 11:29:06  detabc
+ * add a on the fly frame-counter and limit
+ *
+ * Revision 1.98  1999/11/28 14:49:07  detabc
+ * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the
+ * uncompressed size.
+ *
+ * Revision 1.97  1999/11/26 15:54:59  detabc
+ * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol.
+ *
+ * Revision 1.96  1999/11/20 22:14:13  detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * 	to many connection's in short time.
+ * 	config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * 	or remote side.
+ * 	wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
  * Revision 1.95  1999/10/27 21:21:17  detabc
  * Added support for building logically-bind-group's per interface.
  * usefull for outgoing call's with more then one isdn-card.
@@ -443,7 +483,7 @@
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
 
-char *isdn_net_revision = "$Revision: 1.95 $";
+char *isdn_net_revision = "$Revision: 1.103 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -1259,14 +1299,16 @@
 					strcpy(addinfo, " IDP");
 					break;
 			}
-			printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+			printk(KERN_INFO
+				"OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
 
 			       p[12], p[13], p[14], p[15],
 			       p[16], p[17], p[18], p[19],
 			       addinfo);
 			break;
 		case ETH_P_ARP:
-			printk(KERN_INFO "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
+			printk(KERN_INFO
+				"OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
 			       p[14], p[15], p[16], p[17],
 			       p[24], p[25], p[26], p[27]);
 			break;
@@ -1286,8 +1328,8 @@
  */
 #endif
 int
-isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
-		  struct sk_buff *skb)
+isdn_net_send_skb
+		(struct device *ndev, isdn_net_local * lp,struct sk_buff *skb)
 {
 	int ret;
 	int len = skb->len;     /* save len */
@@ -1484,7 +1526,6 @@
 					} else
 						lp->dialwait_timer = 0;
 				}
-
 				/* Grab a free ISDN-Channel */
 				if (((chi =
 				     isdn_get_free_channel(
@@ -1492,7 +1533,8 @@
 							lp->l2_proto,
 							lp->l3_proto,
 							lp->pre_device,
-						 	lp->pre_channel)
+						 	lp->pre_channel,
+							lp->msn)
 							) < 0) &&
 					((chi =
 				     isdn_get_free_channel(
@@ -1500,7 +1542,8 @@
 							lp->l2_proto,
 							lp->l3_proto,
 							lp->pre_device,
-						    lp->pre_channel^1)
+							lp->pre_channel^1,
+							lp->msn)
 							) < 0)) {
 					restore_flags(flags);
 					isdn_net_unreachable(ndev, skb,
@@ -2389,7 +2432,7 @@
 						p = (isdn_net_dev *) p->next;
 						continue;
 					}
-				}
+				} 
 				if (lp->flags & ISDN_NET_CALLBACK) {
 					int chi;
 					/*
@@ -2411,9 +2454,10 @@
 							isdn_get_free_channel(
 								ISDN_USAGE_NET,
 								lp->l2_proto,
-							    lp->l3_proto,
+								lp->l3_proto,
 							  	lp->pre_device,
-						 		lp->pre_channel)
+						 		lp->pre_channel,
+						 		lp->msn)
 								) < 0) {
 
 							printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
@@ -2528,7 +2572,8 @@
 							lp->l2_proto,
 							lp->l3_proto,
 							lp->pre_device,
-						 	lp->pre_channel)
+						 	lp->pre_channel,
+							lp->msn)
 							) < 0) {
 				printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
 				restore_flags(flags);
@@ -2837,10 +2882,9 @@
 
 			/* If binding is exclusive, try to grab the channel */
 			save_flags(flags);
-			if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
-						       lp->l3_proto,
-						       drvidx,
-						       chidx)) < 0) {
+			if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+				lp->l2_proto, lp->l3_proto, drvidx,
+				chidx, lp->msn)) < 0) {
 				/* Grab failed, because desired channel is in use */
 				lp->exclusive = -1;
 				restore_flags(flags);
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- linux-2.2.15-pre4/drivers/isdn/isdn_ppp.c	Tue Jan  4 10:12:16 2000
+++ linux/drivers/isdn/isdn_ppp.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $
+/* $Id: isdn_ppp.c,v 1.61 1999/11/20 22:14:14 detabc Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,22 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.61  1999/11/20 22:14:14  detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * 	to many connection's in short time.
+ * 	config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * 	or remote side.
+ * 	wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
  * Revision 1.60  1999/11/04 20:29:55  he
  * applied Andre Beck's reset_free fix
  *
@@ -306,7 +322,7 @@
 static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision = "$Revision: 1.60 $";
+char *isdn_ppp_revision = "$Revision: 1.61 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- linux-2.2.15-pre4/drivers/isdn/isdn_tty.c	Tue Jan  4 10:12:17 2000
+++ linux/drivers/isdn/isdn_tty.c	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $
+/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -20,6 +20,12 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.82  2000/01/23 18:45:37  keil
+ * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
+ *
+ * Revision 1.81  2000/01/20 19:55:33  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.80  1999/11/07 13:34:30  armin
  * Fixed AT command line editor
  *
@@ -348,6 +354,7 @@
 #endif
 
 #define FIX_FILE_TRANSFER
+#define	DUMMY_HAYES_AT
 
 /* Prototypes */
 
@@ -372,7 +379,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.80 $";
+char *isdn_tty_revision = "$Revision: 1.82 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -976,7 +983,7 @@
 	m->mdmreg[REG_SI1I] = si2bit[si];
 	save_flags(flags);
 	cli();
-	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 	if (i < 0) {
 		restore_flags(flags);
 		isdn_tty_modem_result(6, info);
@@ -1187,7 +1194,7 @@
 	m->mdmreg[REG_SI1I] = si2bit[si];
 	save_flags(flags);
 	cli();
-	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 	if (i < 0) {
 		restore_flags(flags);
 		isdn_tty_modem_result(6, info);
@@ -1281,7 +1288,7 @@
 	m->mdmreg[REG_SI1I] = si2bit[si];
 	save_flags(flags);
 	cli();
-	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+	i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 	if (i < 0) {
 		restore_flags(flags);
 		isdn_tty_modem_result(6, info);
@@ -1555,6 +1562,23 @@
 					}
 				}
 			} else
+			if (TTY_IS_FCLASS1(info)) {
+				int cc = isdn_tty_handleDLEdown(info, m, c);
+				
+				if (info->vonline & 4) { /* ETX seen */
+					isdn_ctrl c;
+
+					c.command = ISDN_CMD_FAXCMD;
+					c.driver = info->isdn_driver;
+					c.arg = info->isdn_channel;
+					c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
+					c.parm.aux.subcmd = ETX;
+					isdn_command(&c);
+				}
+				info->vonline = 0;
+				printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c);
+				info->xmit_count += cc;
+			} else
 #endif
 				info->xmit_count += c;
 		} else {
@@ -2568,7 +2592,7 @@
 	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
 
 int
-isdn_tty_stat_callback(int i, isdn_ctrl * c)
+isdn_tty_stat_callback(int i, isdn_ctrl *c)
 {
 	int mi;
 	modem_info *info;
@@ -2669,8 +2693,7 @@
 						if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
 							strcpy(info->emu.connmsg, c->parm.num);
 							isdn_tty_modem_result(1, info);
-						}
-						else
+						} else
 							isdn_tty_modem_result(5, info);
 					}
 					if (USG_VOICE(dev->usage[i]))
@@ -2721,7 +2744,7 @@
 #ifdef CONFIG_ISDN_TTY_FAX
 			case ISDN_STAT_FAXIND:
 				if (TTY_IS_ACTIVE(info)) {
-					isdn_tty_fax_command(info); 
+					isdn_tty_fax_command(info, c); 
 				}
 				break;
 #endif
@@ -3248,8 +3271,22 @@
 					info->xmit_size /= 10;		
 			}
 			break;
+		case 'C':
+			/* &C - DCD Status */
+			p[0]++;
+			switch (isdn_getnum(p)) {
+				case 0:
+					m->mdmreg[REG_DCD] &= ~BIT_DCD;
+					break;
+				case 1:
+					m->mdmreg[REG_DCD] |= BIT_DCD;
+					break;
+				default:
+					PARSE_ERROR1
+			}
+			break;
 		case 'D':
-			/* &D - Set DCD-Low-behavior */
+			/* &D - Set DTR-Low-behavior */
 			p[0]++;
 			switch (isdn_getnum(p)) {
 				case 0:
@@ -3281,6 +3318,14 @@
 			isdn_tty_reset_profile(m);
 			isdn_tty_modem_reset_regs(info, 1);
 			break;
+#ifdef DUMMY_HAYES_AT
+		case 'K':
+			/* only for be compilant with common scripts */
+			/* &K Flowcontrol - no function */
+			p[0]++;
+			isdn_getnum(p);
+			break;
+#endif
 		case 'L':
 			/* &L -Set Numbers to listen on */
 			p[0]++;
@@ -3566,8 +3611,10 @@
 				sprintf(rs, "\r\n%d",
 					(m->mdmreg[REG_SI1] & 1) ? 8 : 0);
 #ifdef CONFIG_ISDN_TTY_FAX
-				if (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX)
-				sprintf(rs, "\r\n2");
+				if (TTY_IS_FCLASS2(info))
+						sprintf(rs, "\r\n2");
+				else if (TTY_IS_FCLASS1(info))
+						sprintf(rs, "\r\n1");
 #endif
 				isdn_tty_at_cout(rs, info);
 				break;
@@ -3583,11 +3630,25 @@
 						    m->mdmreg[REG_PSIZE] * 16;
 						break;
 #ifdef CONFIG_ISDN_TTY_FAX
+					case '1':
+						p[0]++;
+						if (!(dev->global_features &
+							ISDN_FEATURE_L3_FCLASS1))
+							PARSE_ERROR1;
+						m->mdmreg[REG_SI1] = 1;
+						m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
+						m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
+						info->xmit_size =
+						    m->mdmreg[REG_PSIZE] * 16;
+						break;
 					case '2':
 						p[0]++;
+						if (!(dev->global_features &
+							ISDN_FEATURE_L3_FCLASS2))
+							PARSE_ERROR1;
 						m->mdmreg[REG_SI1] = 1;
 						m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
-						m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX;
+						m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
 						info->xmit_size =
 						    m->mdmreg[REG_PSIZE] * 16;
 						break;
@@ -3602,11 +3663,17 @@
 						break;
 					case '?':
 						p[0]++;
+						strcpy(rs, "\r\n0,");
 #ifdef CONFIG_ISDN_TTY_FAX
-						isdn_tty_at_cout("\r\n0,2,8", info);
-#else
-						isdn_tty_at_cout("\r\n0,8", info);
+						if (dev->global_features &
+							ISDN_FEATURE_L3_FCLASS1)
+							strcat(rs, "1,");
+						if (dev->global_features &
+							ISDN_FEATURE_L3_FCLASS2)
+							strcat(rs, "2,");
 #endif
+						strcat(rs, "8");
+						isdn_tty_at_cout(rs, info);
 						break;
 					default:
 						PARSE_ERROR1;
@@ -3996,6 +4063,15 @@
 					default:
 				}
 				break;
+#ifdef DUMMY_HAYES_AT
+			case 'L':
+			case 'M':
+				/* only for be compilant with common scripts */
+				/* no function */
+				p++;
+				isdn_getnum(&p);
+				break;
+#endif
 			case 'O':
 				/* O - Go online */
 				p++;
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h
--- linux-2.2.15-pre4/drivers/isdn/isdn_tty.h	Tue Oct 26 17:53:40 1999
+++ linux/drivers/isdn/isdn_tty.h	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.17 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $
 
  * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
@@ -20,6 +20,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.h,v $
+ * Revision 1.18  2000/01/20 19:55:33  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.17  1999/09/21 19:00:35  armin
  * Extended FCON message with added CPN
  * can now be activated with Bit 1 of Reg 23.
@@ -160,6 +163,13 @@
 #define BIT_CPN       1
 #define BIT_CPNFCON   2
 
+#define TTY_IS_FCLASS1(info) \
+	((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+	 (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
+#define TTY_IS_FCLASS2(info) \
+	((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+	 (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
+
 extern void isdn_tty_modem_escape(void);
 extern void isdn_tty_modem_ring(void);
 extern void isdn_tty_carrier_timeout(void);
@@ -175,6 +185,6 @@
 extern void isdn_tty_modem_hup(modem_info *, int);
 #ifdef CONFIG_ISDN_TTY_FAX
 extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
-extern int isdn_tty_fax_command(modem_info *);
+extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
 extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
 #endif
diff -urN linux-2.2.15-pre4/drivers/isdn/isdn_ttyfax.c linux/drivers/isdn/isdn_ttyfax.c
--- linux-2.2.15-pre4/drivers/isdn/isdn_ttyfax.c	Tue Oct 26 17:53:40 1999
+++ linux/drivers/isdn/isdn_ttyfax.c	Mon Dec  3 21:58:30 2001
@@ -1,9 +1,9 @@
-/* $Id: isdn_ttyfax.c,v 1.4 1999/09/21 19:00:35 armin Exp $
+/* $Id: isdn_ttyfax.c,v 1.6 2000/01/26 00:41:13 keil Exp $
  * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
  *
  * Copyright 1999    by Armin Schindler (mac@melware.de)
  * Copyright 1999    by Ralf Spachmann (mel@melware.de)
- * Copyright 1999    by Cytronics & Melware 
+ * Copyright 1999    by Cytronics & Melware
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +20,12 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ttyfax.c,v $
+ * Revision 1.6  2000/01/26 00:41:13  keil
+ * add "00" as dummy msn in isdn_get_free_channel call
+ *
+ * Revision 1.5  2000/01/20 19:55:33  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.4  1999/09/21 19:00:35  armin
  * Extended FCON message with added CPN
  * can now be activated with Bit 1 of Reg 23.
@@ -50,31 +56,32 @@
 #include "isdn_ttyfax.h"
 
 
-static char *isdn_tty_fax_revision = "$Revision: 1.4 $";
+static char *isdn_tty_fax_revision = "$Revision: 1.6 $";
 
 #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
 
 static char *
 isdn_getrev(const char *revision)
 {
-        char *rev;
-        char *p;
+	char *rev;
+	char *p;
 
-        if ((p = strchr(revision, ':'))) {
-                rev = p + 2;
-                p = strchr(rev, '$');
-                *--p = 0;
-        } else
-                rev = "???";
-        return rev;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
 }
 
-
 /*
  * Fax Class 2 Modem results
  *
  */
-static void isdn_tty_fax_modem_result(int code, modem_info * info)
+
+static void
+isdn_tty_fax_modem_result(int code, modem_info * info)
 {
 	atemu *m = &info->emu;
 	T30_s *f = info->fax;
@@ -85,7 +92,7 @@
 	static char *msg[] =
 	{"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
 	 "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
-	 "+FCFR", "+FPTS:", "+FET:" };
+	 "+FCFR", "+FPTS:", "+FET:"};
 
 
 	isdn_tty_at_cout("\r\n", info);
@@ -115,12 +122,12 @@
 		case 3:	/* +FCSI */
 		case 8:	/* +FTSI */
 			sprintf(rs, "\"%s\"", f->r_id);
-			isdn_tty_at_cout(rs, info); 
+			isdn_tty_at_cout(rs, info);
 			break;
 		case 4:	/* +FDIS */
 			rs[0] = 0;
 			rp = &f->r_resolution;
-			for(i = 0; i < 8; i++) {
+			for (i = 0; i < 8; i++) {
 				sprintf(rss, "%c%s", rp[i] + 48,
 					(i < 7) ? "," : "");
 				strcat(rs, rss);
@@ -128,18 +135,18 @@
 			isdn_tty_at_cout(rs, info);
 #ifdef ISDN_TTY_FAX_CMD_DEBUG
 			printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
-				rs, info->line);
+			       rs, info->line);
 #endif
 			break;
 		case 5:	/* +FHNG */
 			sprintf(rs, "%d", f->code);
-			isdn_tty_at_cout(rs, info); 
+			isdn_tty_at_cout(rs, info);
 			info->faxonline = 0;
 			break;
 		case 6:	/* +FDCS */
 			rs[0] = 0;
 			rp = &f->r_resolution;
-			for(i = 0; i < 8; i++) {
+			for (i = 0; i < 8; i++) {
 				sprintf(rss, "%c%s", rp[i] + 48,
 					(i < 7) ? "," : "");
 				strcat(rs, rss);
@@ -147,127 +154,169 @@
 			isdn_tty_at_cout(rs, info);
 #ifdef ISDN_TTY_FAX_CMD_DEBUG
 			printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
-				rs, info->line);
+			       rs, info->line);
 #endif
 			break;
 		case 7:	/* CONNECT */
 			info->faxonline |= 2;
 			break;
-		case 9: /* FCFR */
+		case 9:	/* FCFR */
 			break;
-		case 10: /* FPTS */
+		case 10:	/* FPTS */
 			isdn_tty_at_cout("1", info);
 			break;
-		case 11: /* FET */
+		case 11:	/* FET */
 			sprintf(rs, "%d", f->fet);
-			isdn_tty_at_cout(rs, info); 
+			isdn_tty_at_cout(rs, info);
 			break;
 	}
 
 	isdn_tty_at_cout("\r\n", info);
 
 	switch (code) {
-		case 7: /* CONNECT */
+		case 7:	/* CONNECT */
 			info->online = 2;
 			if (info->faxonline & 1) {
 				sprintf(rs, "%c", XON);
-				isdn_tty_at_cout(rs, info); 
+				isdn_tty_at_cout(rs, info);
 			}
 			break;
 	}
 }
 
 int
-isdn_tty_fax_command(modem_info * info)
+isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
+{
+	static char *msg[] =
+	{"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+	printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
+#endif
+	if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
+		if (info->online)
+			info->online = 1;
+		isdn_tty_at_cout("\r\n", info);
+		isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
+		isdn_tty_at_cout("\r\n", info);
+	}
+	switch (c->parm.aux.cmd) {
+		case ISDN_FAX_CLASS1_CONNECT:
+			info->online = 2;
+			break;
+		case ISDN_FAX_CLASS1_OK:
+		case ISDN_FAX_CLASS1_FCERROR:
+		case ISDN_FAX_CLASS1_ERROR:
+		case ISDN_FAX_CLASS1_NOCARR:
+			break;
+		case ISDN_FAX_CLASS1_QUERY:
+			isdn_tty_at_cout("\r\n", info);
+			if (!c->parm.aux.para[0]) {
+				isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
+				isdn_tty_at_cout("\r\n", info);
+			} else {
+				isdn_tty_at_cout(c->parm.aux.para, info);
+				isdn_tty_at_cout("\r\nOK\r\n", info);
+			}
+			break;
+	}
+	return (0);
+}
+
+int
+isdn_tty_fax_command(modem_info * info, isdn_ctrl * c)
 {
 	T30_s *f = info->fax;
 	char rs[10];
 
+	if (TTY_IS_FCLASS1(info))
+		return (isdn_tty_fax_command1(info, c));
+
 #ifdef ISDN_TTY_FAX_CMD_DEBUG
 	printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
-		f->r_code, info->line);
+	       f->r_code, info->line);
 #endif
-	switch(f->r_code) {
+	switch (f->r_code) {
 		case ISDN_TTY_FAX_FCON:
 			info->faxonline = 1;
-			isdn_tty_fax_modem_result(2, info); /* +FCON */
-			return(0);
+			isdn_tty_fax_modem_result(2, info);	/* +FCON */
+			return (0);
 		case ISDN_TTY_FAX_FCON_I:
 			info->faxonline = 16;
-			isdn_tty_fax_modem_result(2, info); /* +FCON */
-			return(0);
+			isdn_tty_fax_modem_result(2, info);	/* +FCON */
+			return (0);
 		case ISDN_TTY_FAX_RID:
 			if (info->faxonline & 1)
-				isdn_tty_fax_modem_result(3, info); /* +FCSI */
+				isdn_tty_fax_modem_result(3, info);	/* +FCSI */
 			if (info->faxonline & 16)
-				isdn_tty_fax_modem_result(8, info); /* +FTSI */
-			return(0);
+				isdn_tty_fax_modem_result(8, info);	/* +FTSI */
+			return (0);
 		case ISDN_TTY_FAX_DIS:
-			isdn_tty_fax_modem_result(4, info); /* +FDIS */
-			return(0);
+			isdn_tty_fax_modem_result(4, info);	/* +FDIS */
+			return (0);
 		case ISDN_TTY_FAX_HNG:
 			if (f->phase == ISDN_FAX_PHASE_C) {
 				if (f->direction == ISDN_TTY_FAX_CONN_IN) {
 					sprintf(rs, "%c%c", DLE, ETX);
-					isdn_tty_at_cout(rs, info); 
+					isdn_tty_at_cout(rs, info);
 				} else {
 					sprintf(rs, "%c", 0x18);
-					isdn_tty_at_cout(rs, info); 
+					isdn_tty_at_cout(rs, info);
 				}
-				info->faxonline &= ~2; /* leave data mode */
+				info->faxonline &= ~2;	/* leave data mode */
 				info->online = 1;
 			}
 			f->phase = ISDN_FAX_PHASE_E;
-			isdn_tty_fax_modem_result(5, info); /* +FHNG */
-			isdn_tty_fax_modem_result(0, info); /* OK */
-			return(0);
+			isdn_tty_fax_modem_result(5, info);	/* +FHNG */
+			isdn_tty_fax_modem_result(0, info);	/* OK */
+			return (0);
 		case ISDN_TTY_FAX_DCS:
-			isdn_tty_fax_modem_result(6, info); /* +FDCS */
-			isdn_tty_fax_modem_result(7, info); /* CONNECT */
+			isdn_tty_fax_modem_result(6, info);	/* +FDCS */
+			isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 			f->phase = ISDN_FAX_PHASE_C;
-			return(0);
+			return (0);
 		case ISDN_TTY_FAX_TRAIN_OK:
-			isdn_tty_fax_modem_result(6, info); /* +FDCS */
-			isdn_tty_fax_modem_result(0, info); /* OK */
-			return(0);
+			isdn_tty_fax_modem_result(6, info);	/* +FDCS */
+			isdn_tty_fax_modem_result(0, info);	/* OK */
+			return (0);
 		case ISDN_TTY_FAX_SENT:
-			isdn_tty_fax_modem_result(0, info); /* OK */
-			return(0);
+			isdn_tty_fax_modem_result(0, info);	/* OK */
+			return (0);
 		case ISDN_TTY_FAX_CFR:
-			isdn_tty_fax_modem_result(9, info); /* +FCFR */
-			return(0);
+			isdn_tty_fax_modem_result(9, info);	/* +FCFR */
+			return (0);
 		case ISDN_TTY_FAX_ET:
 			sprintf(rs, "%c%c", DLE, ETX);
-			isdn_tty_at_cout(rs, info); 
-			isdn_tty_fax_modem_result(10, info); /* +FPTS */
-			isdn_tty_fax_modem_result(11, info); /* +FET */
-			isdn_tty_fax_modem_result(0, info); /* OK */
-			info->faxonline &= ~2; /* leave data mode */
+			isdn_tty_at_cout(rs, info);
+			isdn_tty_fax_modem_result(10, info);	/* +FPTS */
+			isdn_tty_fax_modem_result(11, info);	/* +FET */
+			isdn_tty_fax_modem_result(0, info);	/* OK */
+			info->faxonline &= ~2;	/* leave data mode */
 			info->online = 1;
 			f->phase = ISDN_FAX_PHASE_D;
-			return(0);
+			return (0);
 		case ISDN_TTY_FAX_PTS:
-			isdn_tty_fax_modem_result(10, info); /* +FPTS */
+			isdn_tty_fax_modem_result(10, info);	/* +FPTS */
 			if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
 				if (f->fet == 1)
 					f->phase = ISDN_FAX_PHASE_B;
 				if (f->fet == 0)
-					isdn_tty_fax_modem_result(0, info); /* OK */
+					isdn_tty_fax_modem_result(0, info);	/* OK */
 			}
-			return(0);
+			return (0);
 		case ISDN_TTY_FAX_EOP:
-			info->faxonline &= ~2; /* leave data mode */
+			info->faxonline &= ~2;	/* leave data mode */
 			info->online = 1;
 			f->phase = ISDN_FAX_PHASE_D;
-			return(0);
+			return (0);
 
 	}
-	return(-1);
+	return (-1);
 }
 
 
 void
-isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
+isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
 {
 	__u8 LeftMask;
 	__u8 RightMask;
@@ -276,13 +325,13 @@
 	int i;
 
 	if (!info->fax->bor) {
-		for(i = 0; i < skb->len; i++) {
+		for (i = 0; i < skb->len; i++) {
 			Data = skb->data[i];
 			for (
-				LeftMask = 0x80, RightMask = 0x01;
-				LeftMask > RightMask;
-				LeftMask >>= 1, RightMask <<= 1
-			) {
+				    LeftMask = 0x80, RightMask = 0x01;
+				    LeftMask > RightMask;
+				    LeftMask >>= 1, RightMask <<= 1
+			    ) {
 				fBit = (Data & LeftMask);
 				if (Data & RightMask)
 					Data |= LeftMask;
@@ -300,10 +349,103 @@
 }
 
 /*
+ * Parse AT+F.. FAX class 1 commands
+ */
+
+int
+isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
+{
+	static char *cmd[] =
+	{"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
+	isdn_ctrl c;
+	int par, i;
+	long flags;
+
+	for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
+		if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
+			break;
+
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+	printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
+#endif
+	if (c.parm.aux.cmd == 7)
+		PARSE_ERROR1;
+
+	p[0] += 2;
+	switch (*p[0]) {
+		case '?':
+			p[0]++;
+			c.parm.aux.subcmd = AT_QUERY;
+			break;
+		case '=':
+			p[0]++;
+			if (*p[0] == '?') {
+				p[0]++;
+				c.parm.aux.subcmd = AT_EQ_QUERY;
+			} else {
+				par = isdn_getnum(p);
+				if ((par < 0) || (par > 255))
+					PARSE_ERROR1;
+				c.parm.aux.subcmd = AT_EQ_VALUE;
+				c.parm.aux.para[0] = par;
+			}
+			break;
+		case 0:
+			c.parm.aux.subcmd = AT_COMMAND;
+			break;
+		default:
+			PARSE_ERROR1;
+	}
+	c.command = ISDN_CMD_FAXCMD;
+#ifdef ISDN_TTY_FAX_CMD_DEBUG
+	printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
+	       c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
+#endif
+	if (info->isdn_driver < 0) {
+		save_flags(flags);
+		cli();
+		if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
+		    (c.parm.aux.subcmd == AT_COMMAND)) {
+			restore_flags(flags);
+			PARSE_ERROR1;
+		}
+		/* get a temporary connection to the first free fax driver */
+		i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
+					  ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
+		if (i < 0) {
+			restore_flags(flags);
+			PARSE_ERROR1;
+		}
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		c.driver = info->isdn_driver;
+		c.arg = info->isdn_channel;
+		isdn_command(&c);
+		isdn_free_channel(info->isdn_driver, info->isdn_channel,
+				  ISDN_USAGE_FAX);
+		info->isdn_driver = -1;
+		info->isdn_channel = -1;
+		if (info->drv_index >= 0) {
+			dev->m_idx[info->drv_index] = -1;
+			info->drv_index = -1;
+		}
+		restore_flags(flags);
+	} else {
+		c.driver = info->isdn_driver;
+		c.arg = info->isdn_channel;
+		isdn_command(&c);
+	}
+	return 1;
+}
+
+/*
  * Parse AT+F.. FAX class 2 commands
  */
 
-int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+int
+isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
 {
 	atemu *m = &info->emu;
 	T30_s *f = info->fax;
@@ -311,10 +453,11 @@
 	int par;
 	char rs[50];
 	char rss[50];
-	int maxdccval[]={1,5,2,2,3,2,0,7};
+	int maxdccval[] =
+	{1, 5, 2, 2, 3, 2, 0, 7};
 
 	/* FAA still unchanged */
-        if (!strncmp(p[0], "AA", 2)) { /* TODO */
+	if (!strncmp(p[0], "AA", 2)) {	/* TODO */
 		p[0] += 2;
 		switch (*p[0]) {
 			case '?':
@@ -332,399 +475,363 @@
 				PARSE_ERROR1;
 		}
 		return 0;
-       }
-
+	}
 	/* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
-        if (!strncmp(p[0], "BADLIN", 6)) {
-            p[0] += 6;
+	if (!strncmp(p[0], "BADLIN", 6)) {
+		p[0] += 6;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->badlin);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->badlin);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0-255");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 255))
-                                            PARSE_ERROR1;
-                                        f->badlin = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0-255");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 255))
+						PARSE_ERROR1;
+					f->badlin = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
 #endif
-                                    }
-                                break;
+				}
+				break;
 			default:
-			        PARSE_ERROR1;
+				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */
-        if (!strncmp(p[0], "BADMUL", 6)){
-            p[0] +=6;
+	if (!strncmp(p[0], "BADMUL", 6)) {
+		p[0] += 6;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d", f->badmul);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->badmul);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0-255");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 255))
-                                            PARSE_ERROR1;
-                                        f->badmul = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0-255");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 255))
+						PARSE_ERROR1;
+					f->badmul = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* BOR=n - Phase C bit order, 0=direct, 1=reverse */
-        if (!strncmp(p[0], "BOR", 3)){
-            p[0] +=3;
+	if (!strncmp(p[0], "BOR", 3)) {
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d", f->bor);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->bor);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,1");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 1))
-                                            PARSE_ERROR1;
-                                        f->bor = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
-#endif
-                                    }
-                                break;
-                        default:
-                                PARSE_ERROR1;
-                                }
-                       return 0;
-        }
-
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,1");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 1))
+						PARSE_ERROR1;
+					f->bor = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+					printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
+#endif
+				}
+				break;
+			default:
+				PARSE_ERROR1;
+		}
+		return 0;
+	}
 	/* NBC=n - No Best Capabilities */
-        if (!strncmp(p[0], "NBC", 3)){
-            p[0] +=3;
+	if (!strncmp(p[0], "NBC", 3)) {
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d", f->nbc);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->nbc);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,1");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 1))
-                                            PARSE_ERROR1;
-                                        f->nbc = par;
-#ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
-#endif
-                                    }
-                                break;
-                        default:
-                                PARSE_ERROR1;
-                                }
-                       return 0;
-        }
-
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,1");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 1))
+						PARSE_ERROR1;
+					f->nbc = par;
+#ifdef ISDN_TTY_FAX_STAT_DEBUG
+					printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
+#endif
+				}
+				break;
+			default:
+				PARSE_ERROR1;
+		}
+		return 0;
+	}
 	/* BUF? - Readonly buffersize readout  */
-        if (!strncmp(p[0], "BUF?", 4)) {
-                p[0] += 4;
+	if (!strncmp(p[0], "BUF?", 4)) {
+		p[0] += 4;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
+		printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
 #endif
-                                p[0]++;
-                                 sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
-                                isdn_tty_at_cout(rs, info);
-                return 0;
-        }
-        
+		p[0]++;
+		sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
+		isdn_tty_at_cout(rs, info);
+		return 0;
+	}
 	/* CIG=string - local fax station id string for polling rx */
-        if (!strncmp(p[0], "CIG", 3)) {
+	if (!strncmp(p[0], "CIG", 3)) {
 		int i, r;
-                p[0] += 3;
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
 				sprintf(rs, "\r\n\"%s\"", f->pollid);
-                                isdn_tty_at_cout(rs, info);
-                                break;
+				isdn_tty_at_cout(rs, info);
+				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n\"STRING\"");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        if (*p[0] =='"')
-                                            p[0]++;
-                                        for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
-                                        {
-                                            f->pollid[i] = *p[0]++;
-                                        }
-                                        if (*p[0] =='"')
-                                            p[0]++;
-                                        for(r=i; r < FAXIDLEN; r++)
-                                        {
-                                        	f->pollid[r] = 32;
-                                        }
-                                        f->pollid[FAXIDLEN-1] = 0;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n\"STRING\"");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					if (*p[0] == '"')
+						p[0]++;
+					for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
+						f->pollid[i] = *p[0]++;
+					}
+					if (*p[0] == '"')
+						p[0]++;
+					for (r = i; r < FAXIDLEN; r++) {
+						f->pollid[r] = 32;
+					}
+					f->pollid[FAXIDLEN - 1] = 0;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                       printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
+					printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
 #endif
-                                    }
-                                break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
-        if (!strncmp(p[0], "CQ", 2)) {
-                p[0] += 2;
+	if (!strncmp(p[0], "CQ", 2)) {
+		p[0] += 2;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d", f->cq);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->cq);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,1,2");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 2))
-                                            PARSE_ERROR1;
-                                        f->cq = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,1,2");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 2))
+						PARSE_ERROR1;
+					f->cq = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
-        if (!strncmp(p[0], "CR", 2)) {
-                p[0] += 2;
+	if (!strncmp(p[0], "CR", 2)) {
+		p[0] += 2;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->cr);	/* read actual value from struct and print */
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,1"); /* display online help */
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 1))
-                                            PARSE_ERROR1;
-                                        f->cr = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,1");		/* display online help */
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 1))
+						PARSE_ERROR1;
+					f->cr = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* CTCRTY=value - ECM retry count */
-        if (!strncmp(p[0], "CTCRTY", 6)){
-            p[0] +=6;
+	if (!strncmp(p[0], "CTCRTY", 6)) {
+		p[0] += 6;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->ctcrty);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->ctcrty);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0-255");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 255))
-                                            PARSE_ERROR1;
-                                        f->ctcrty = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0-255");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 255))
+						PARSE_ERROR1;
+					f->ctcrty = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
-        if (!strncmp(p[0], "DCC", 3)) {
+	if (!strncmp(p[0], "DCC", 3)) {
 		char *rp = &f->resolution;
 		int i;
 
-                p[0] += 3;
-		switch(*p[0]) {
+		p[0] += 3;
+		switch (*p[0]) {
 			case '?':
 				p[0]++;
-	                        strcpy(rs, "\r\n");
-	                        for(i = 0; i < 8; i++) {
-        	                        sprintf(rss, "%c%s", rp[i] + 48,
-                	                        (i < 7) ? "," : "");
-                        	        strcat(rs, rss);
-	                        }
-        	                isdn_tty_at_cout(rs, info);
+				strcpy(rs, "\r\n");
+				for (i = 0; i < 8; i++) {
+					sprintf(rss, "%c%s", rp[i] + 48,
+						(i < 7) ? "," : "");
+					strcat(rs, rss);
+				}
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-		                if (*p[0] == '?') {
-					isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
-                                	p[0]++;
-		                } else {
-					for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+				p[0]++;
+				if (*p[0] == '?') {
+					isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
+					p[0]++;
+				} else {
+					for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
 						if (*p[0] != ',') {
 							if ((*p[0] - 48) > maxdccval[i]) {
 								PARSE_ERROR1;
 							}
 							rp[i] = *p[0] - 48;
 							p[0]++;
-							if (*p[0] == ',') 
+							if (*p[0] == ',')
 								p[0]++;
-						} else p[0]++;
+						} else
+							p[0]++;
 					}
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-				printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
-				       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+					printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
+					       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
 #endif
-        		        }
+				}
 				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-       
+		return 0;
+	}
 	/* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
-        if (!strncmp(p[0], "DIS", 3)) {
+	if (!strncmp(p[0], "DIS", 3)) {
 		char *rp = &f->resolution;
 		int i;
 
-                p[0] += 3;
-		switch(*p[0]) {
+		p[0] += 3;
+		switch (*p[0]) {
 			case '?':
 				p[0]++;
-	                        strcpy(rs, "\r\n");
-	                        for(i = 0; i < 8; i++) {
-        	                        sprintf(rss, "%c%s", rp[i] + 48,
-                	                        (i < 7) ? "," : "");
-                        	        strcat(rs, rss);
-	                        }
-        	                isdn_tty_at_cout(rs, info);
+				strcpy(rs, "\r\n");
+				for (i = 0; i < 8; i++) {
+					sprintf(rss, "%c%s", rp[i] + 48,
+						(i < 7) ? "," : "");
+					strcat(rs, rss);
+				}
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-		                if (*p[0] == '?') {
-					isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info);
-                                	p[0]++;
-		                } else {
-					for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) {
+				p[0]++;
+				if (*p[0] == '?') {
+					isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
+					p[0]++;
+				} else {
+					for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
 						if (*p[0] != ',') {
 							if ((*p[0] - 48) > maxdccval[i]) {
 								PARSE_ERROR1;
 							}
 							rp[i] = *p[0] - 48;
 							p[0]++;
-							if (*p[0] == ',') 
+							if (*p[0] == ',')
 								p[0]++;
-						} else p[0]++;
+						} else
+							p[0]++;
 					}
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-				printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
-				       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
+					printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
+					       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
 #endif
-        		        }
+				}
 				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-       
-	/* DR - Receive Phase C data command, initiates document reception */ 
-        if (!strncmp(p[0], "DR", 2)) {
-                p[0] += 2;
+		return 0;
+	}
+	/* DR - Receive Phase C data command, initiates document reception */
+	if (!strncmp(p[0], "DR", 2)) {
+		p[0] += 2;
 		if ((info->faxonline & 16) &&	/* incoming connection */
-   		   ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
+		    ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
 			printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
 #endif
@@ -735,11 +842,11 @@
 			isdn_command(&cmd);
 			if (f->phase == ISDN_FAX_PHASE_B) {
 				f->phase = ISDN_FAX_PHASE_C;
-			} else if (f->phase == ISDN_FAX_PHASE_D) { 
-				switch(f->fet) {
+			} else if (f->phase == ISDN_FAX_PHASE_D) {
+				switch (f->fet) {
 					case 0:	/* next page will be received */
 						f->phase = ISDN_FAX_PHASE_C;
-						isdn_tty_fax_modem_result(7, info); /* CONNECT */
+						isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 						break;
 					case 1:	/* next doc will be received */
 						f->phase = ISDN_FAX_PHASE_B;
@@ -747,35 +854,36 @@
 					case 2:	/* fax session is terminating */
 						f->phase = ISDN_FAX_PHASE_E;
 						break;
-					default:	
+					default:
 						PARSE_ERROR1;
 				}
 			}
 		} else {
 			PARSE_ERROR1;
 		}
-                return 1;
+		return 1;
 	}
- 
 	/* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
-        if (!strncmp(p[0], "DT", 2)) {
-		int i, val[]={4,0,2,3};
+	if (!strncmp(p[0], "DT", 2)) {
+		int i, val[] =
+		{4, 0, 2, 3};
 		char *rp = &f->resolution;
 
-                p[0] += 2;
-		if (!info->faxonline & 1) 	/* not outgoing connection */
+		p[0] += 2;
+		if (!info->faxonline & 1)	/* not outgoing connection */
 			PARSE_ERROR1;
 
-		for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<4); i++) {
+		for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
 			if (*p[0] != ',') {
 				if ((*p[0] - 48) > maxdccval[val[i]]) {
 					PARSE_ERROR1;
 				}
 				rp[val[i]] = *p[0] - 48;
 				p[0]++;
-				if (*p[0] == ',') 
+				if (*p[0] == ',')
 					p[0]++;
-			} else p[0]++;
+			} else
+				p[0]++;
 		}
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
 		printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
@@ -789,48 +897,43 @@
 			isdn_command(&cmd);
 			if (f->phase == ISDN_FAX_PHASE_D) {
 				f->phase = ISDN_FAX_PHASE_C;
-				isdn_tty_fax_modem_result(7, info); /* CONNECT */
+				isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 			}
 		} else {
 			PARSE_ERROR1;
 		}
-                return 1;
-        }
-
+		return 1;
+	}
 	/* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
-        if (!strncmp(p[0], "ECM", 3)) {
-                p[0] += 3;
+	if (!strncmp(p[0], "ECM", 3)) {
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->ecm);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->ecm);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,2");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par != 0) && (par != 2))
-                                            PARSE_ERROR1;
-                                        f->ecm = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,2");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par != 0) && (par != 2))
+						PARSE_ERROR1;
+					f->ecm = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* ET=n - End of page or document */
 	if (!strncmp(p[0], "ET=", 3)) {
 		p[0] += 3;
@@ -857,7 +960,6 @@
 		}
 		return 0;
 	}
-
 	/* K - terminate */
 	if (!strncmp(p[0], "K", 1)) {
 		p[0] += 1;
@@ -866,205 +968,191 @@
 		isdn_tty_modem_hup(info, 1);
 		return 1;
 	}
-
 	/* LID=string - local fax ID */
-        if (!strncmp(p[0], "LID", 3)) {
+	if (!strncmp(p[0], "LID", 3)) {
 		int i, r;
-                p[0] += 3;
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
 				sprintf(rs, "\r\n\"%s\"", f->id);
-                                isdn_tty_at_cout(rs, info);
-                                break;
+				isdn_tty_at_cout(rs, info);
+				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n\"STRING\"");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        if (*p[0] =='"')
-                                            p[0]++;
-                                        for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++)
-                                        {
-                                            f->id[i] = *p[0]++;
-                                        }
-                                        if (*p[0] =='"')
-                                            p[0]++;
-                                        for(r=i; r < FAXIDLEN; r++)
-                                        {
-                                        	f->id[r] = 32;
-                                        }
-                                        f->id[FAXIDLEN-1] = 0;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n\"STRING\"");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					if (*p[0] == '"')
+						p[0]++;
+					for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
+						f->id[i] = *p[0]++;
+					}
+					if (*p[0] == '"')
+						p[0]++;
+					for (r = i; r < FAXIDLEN; r++) {
+						f->id[r] = 32;
+					}
+					f->id[FAXIDLEN - 1] = 0;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                       printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
+					printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
 #endif
-                                    }
-                                break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 
 	/* MDL? - DCE Model       */
-        if (!strncmp(p[0], "MDL?", 4)) {
-                p[0] += 4;
+	if (!strncmp(p[0], "MDL?", 4)) {
+		p[0] += 4;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+		printk(KERN_DEBUG "isdn_tty: FMDL?\n");
 #endif
-                isdn_tty_at_cout("\r\nisdn4linux", info);
-                return 0;
-        }
-
+		isdn_tty_at_cout("\r\nisdn4linux", info);
+		return 0;
+	}
 	/* MFR? - DCE Manufacturer */
-        if (!strncmp(p[0], "MFR?", 4)) {
-                p[0] += 4;
+	if (!strncmp(p[0], "MFR?", 4)) {
+		p[0] += 4;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+		printk(KERN_DEBUG "isdn_tty: FMFR?\n");
 #endif
-                isdn_tty_at_cout("\r\nisdn4linux", info);
-                return 0;
-        }
-
+		isdn_tty_at_cout("\r\nisdn4linux", info);
+		return 0;
+	}
 	/* MINSP=n - Minimum Speed for Phase C */
-        if (!strncmp(p[0], "MINSP", 5)) {
-                p[0] += 5;
+	if (!strncmp(p[0], "MINSP", 5)) {
+		p[0] += 5;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->minsp);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->minsp);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0-5");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 5))
-                                            PARSE_ERROR1;
-                                        f->minsp = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0-5");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 5))
+						PARSE_ERROR1;
+					f->minsp = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* PHCTO=value - DTE phase C timeout */
-        if (!strncmp(p[0], "PHCTO", 5)){
-            p[0] +=5;
+	if (!strncmp(p[0], "PHCTO", 5)) {
+		p[0] += 5;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->phcto);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->phcto);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0-255");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 255))
-                                            PARSE_ERROR1;
-                                        f->phcto = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0-255");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 255))
+						PARSE_ERROR1;
+					f->phcto = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 
 	/* REL=n - Phase C received EOL alignment */
-        if (!strncmp(p[0], "REL", 3)) {
-                p[0] += 3;
+	if (!strncmp(p[0], "REL", 3)) {
+		p[0] += 3;
 		switch (*p[0]) {
 			case '?':
 				p[0]++;
-                                sprintf(rs, "\r\n%d",f->rel);
-                                isdn_tty_at_cout(rs, info);
+				sprintf(rs, "\r\n%d", f->rel);
+				isdn_tty_at_cout(rs, info);
 				break;
 			case '=':
-                                p[0]++;
-                                if (*p[0] == '?')
-                                    {
-                                     p[0]++;
-                                     sprintf(rs, "\r\n0,1");
-                       		     isdn_tty_at_cout(rs, info);
-                                    }
-                                    else
-                                    {
-                                        par = isdn_getnum(p);
-                                        if ((par < 0) || (par > 1))
-                                            PARSE_ERROR1;
-                                        f->rel = par;
+				p[0]++;
+				if (*p[0] == '?') {
+					p[0]++;
+					sprintf(rs, "\r\n0,1");
+					isdn_tty_at_cout(rs, info);
+				} else {
+					par = isdn_getnum(p);
+					if ((par < 0) || (par > 1))
+						PARSE_ERROR1;
+					f->rel = par;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                                        printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
+					printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
 #endif
-                                    }
-                                    break;
+				}
+				break;
 			default:
 				PARSE_ERROR1;
 		}
-                return 0;
-        }
-
+		return 0;
+	}
 	/* REV? - DCE Revision */
-        if (!strncmp(p[0], "REV?", 4)) {
-                p[0] += 4;
+	if (!strncmp(p[0], "REV?", 4)) {
+		p[0] += 4;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                printk(KERN_DEBUG "isdn_tty: FREV?\n");
+		printk(KERN_DEBUG "isdn_tty: FREV?\n");
 #endif
 		strcpy(rss, isdn_tty_fax_revision);
 		sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
-                isdn_tty_at_cout(rs, info);
-                return 0;
-        }
-
+		isdn_tty_at_cout(rs, info);
+		return 0;
+	}
 
 	/* Phase C Transmit Data Block Size */
-	if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
+	if (!strncmp(p[0], "TBC=", 4)) {	/* dummy, not used */
 		p[0] += 4;
 #ifdef ISDN_TTY_FAX_STAT_DEBUG
-                printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
+		printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
 #endif
-                switch (*p[0]) {
-                        case '0':
-                                p[0]++;
-                                break;
-                        default:
-                                PARSE_ERROR1;
-                }
-                return 0;
+		switch (*p[0]) {
+			case '0':
+				p[0]++;
+				break;
+			default:
+				PARSE_ERROR1;
+		}
+		return 0;
 	}
-
-        printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
+	printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
 	PARSE_ERROR1;
 }
 
+int
+isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
+{
+	if (TTY_IS_FCLASS2(info))
+		return (isdn_tty_cmd_FCLASS2(p, info));
+	else if (TTY_IS_FCLASS1(info))
+		return (isdn_tty_cmd_FCLASS1(p, info));
+	PARSE_ERROR1;
+}
diff -urN linux-2.2.15-pre4/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- linux-2.2.15-pre4/drivers/misc/parport_pc.c	Tue Jan  4 10:12:17 2000
+++ linux/drivers/misc/parport_pc.c	Mon Dec  3 21:58:30 2001
@@ -839,11 +839,6 @@
 		 * Put the ECP detected port in the more PS2 like mode.
 		 */
 		parport_pc_write_econtrol(p, 0x34);
-	parport_pc_write_control(p, 0x8);
-	parport_pc_write_data(p, 0);
-	udelay (50);
-	parport_pc_write_control(p, 0xc);
-	udelay (50);
 
 	if (parport_probe_hook)
 		(*parport_probe_hook)(p);
diff -urN linux-2.2.15-pre4/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.2.15-pre4/drivers/net/Config.in	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 21:58:30 2001
@@ -18,6 +18,7 @@
 endmenu
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
+tristate 'Bonding driver support' CONFIG_BONDING
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   if [ "$CONFIG_NETLINK" = "y" ]; then
diff -urN linux-2.2.15-pre4/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-2.2.15-pre4/drivers/net/Makefile	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/Makefile	Mon Dec  3 21:58:30 2001
@@ -366,6 +366,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_BONDING),y)
+L_OBJS += bonding.o
+else
+  ifeq ($(CONFIG_BONDING),m)
+  M_OBJS += bonding.o
+  endif
+endif
+
 ifeq ($(CONFIG_DE600),y)
 L_OBJS += de600.o
 else
diff -urN linux-2.2.15-pre4/drivers/net/Space.c linux/drivers/net/Space.c
--- linux-2.2.15-pre4/drivers/net/Space.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/Space.c	Mon Dec  3 21:58:30 2001
@@ -120,7 +120,7 @@
 extern int tc515_probe(struct device *dev);
 extern int lance_probe(struct device *dev);
 extern int rcpci_probe(struct device *);
-extern int dmfe_reg_board(struct device *);
+extern int dmfe_probe(struct device *);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -227,7 +227,7 @@
 #endif
 
 #ifdef CONFIG_DM9102
-	{dmfe_reg_board, 0}, 
+	{dmfe_probe, 0}, 
 #endif
 
 #ifdef CONFIG_YELLOWFIN
@@ -243,7 +243,7 @@
 	{via_rhine_probe, 0},
 #endif
 #ifdef CONFI_NET_DM9102
-	{dmfe_reg_board, 0},
+	{dmfe_probe, 0},
 #endif	
 	{NULL, 0},
 };
diff -urN linux-2.2.15-pre4/drivers/net/bonding.c linux/drivers/net/bonding.c
--- linux-2.2.15-pre4/drivers/net/bonding.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/bonding.c	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,353 @@
+/*
+ * originally based on the dummy device.
+ *
+ * Copyright 1999, Thomas Davis, tadavis@lbl.gov.  
+ * Licensed under the GPL. Based on dummy.c, and eql.c devices.
+ *
+ * bond.c: a bonding/etherchannel/sun trunking net driver
+ *
+ * This is useful to talk to a Cisco 5500, running Etherchannel, aka:
+ *	Linux Channel Bonding
+ *	Sun Trunking (Solaris)
+ *
+ * How it works:
+ *    ifconfig bond0 ipaddress netmask up
+ *      will setup a network device, with an ip address.  No mac address 
+ *	will be assigned at this time.  The hw mac address will come from 
+ *	the first slave bonded to the channel.  All slaves will then use 
+ *	this hw mac address.
+ *
+ *    ifconfig bond0 down
+ *         will release all slaves, marking them as down.
+ *
+ *    ifenslave bond0 eth0
+ *	will attache eth0 to bond0 as a slave.  eth0 hw mac address will either
+ *	a: be used as initial mac address
+ *	b: if a hw mac address already is there, eth0's hw mac address 
+ *	   will then  be set from bond0.
+ *
+ * v0.1 - first working version.
+ * v0.2 - changed stats to be calculated by summing slaves stats.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/if_bonding.h>
+
+static int bond_xmit(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bond_get_stats(struct device *dev);
+
+static int bond_open(struct device *dev)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int bond_close(struct device *master)
+{
+	bonding_t *private = (struct bonding *) master->priv;
+	slave_queue_t *queue = (struct slave_queue *) private->queue;
+	slave_t *slave, *next;
+
+	for( slave=queue->head; slave != NULL; slave=next) {
+#ifdef BONDING_DEBUG
+		printk("freeing = %s\n", slave->dev->name);
+#endif
+		slave->dev->flags &= ~IFF_SLAVE;
+		slave->dev->slave = NULL;
+		next = slave->next;
+		kfree(slave);
+		queue->num_slaves++;
+	}
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* fake multicast ability */
+static void set_multicast_list(struct device *dev)
+{
+}
+
+static int bond_enslave(struct device *master, struct device *slave)
+{
+	bonding_t *private = (struct bonding *) master->priv;
+	slave_queue_t *queue = (struct slave_queue *) private->queue;
+	slave_t *new_slave;
+	int flags;
+	
+	if (master == NULL || slave == NULL) 
+		return -ENODEV;
+
+#ifdef BONDING_DEBUG
+	printk (KERN_WARNING "%s: enslaving '%s'\n", master->name, slave->name);
+#endif
+
+	save_flags(flags);
+	cli();
+
+	/* not running. */
+	if ((slave->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+		restore_flags(flags);
+		return -EINVAL;
+	}
+
+	/* already enslaved */
+	if (master->flags & IFF_SLAVE || slave->flags & IFF_SLAVE) {
+		restore_flags(flags);
+		return -EBUSY;
+	}
+		   
+	slave->slave = master;     /* save the master in slave->slave */
+	slave->flags |= IFF_SLAVE;
+
+	if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
+		return -ENOMEM;
+	}
+	memset(new_slave, 0, sizeof(slave_t));
+
+	new_slave->dev = slave;
+
+	if (queue->head == NULL) {
+		queue->head = new_slave;
+		queue->current_slave = queue->head;
+	} else {
+		queue->tail->next = new_slave;
+	}
+
+	queue->tail = new_slave;
+	queue->num_slaves++;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+static int bond_release(struct device *master, struct device *slave)
+{
+	printk (KERN_DEBUG "%s: releasing `%s`\n", master->name, slave->name);
+
+	return -EINVAL;
+}
+
+static int bond_sethwaddr(struct device *master, struct device *slave)
+{
+	memcpy(master->dev_addr, slave->dev_addr, slave->addr_len);
+	return 0;
+}
+
+static int bond_ioctl(struct device *master, struct ifreq *ifr, int cmd)
+{
+	struct device *slave = dev_get(ifr->ifr_slave);
+
+#ifdef BONDING_DEBUG
+	printk("master=%s, slave=%s\n", master->name, slave->name);
+#endif
+
+	switch (cmd) {
+	case BOND_ENSLAVE:
+		return bond_enslave(master, slave);
+	case BOND_RELEASE:
+		return bond_release(master, slave);
+	case BOND_SETHWADDR:
+		return bond_sethwaddr(master, slave);
+	default:
+			return -EOPNOTSUPP;
+	}
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+static int bond_accept_fastpath(struct device *dev, struct dst_entry *dst)
+{
+	return -1;
+}
+#endif
+
+__initfunc(int bond_init(struct device *dev))
+{
+	bonding_t *bond;
+
+	/* Initialize the device structure. */
+	dev->hard_start_xmit = bond_xmit;
+
+	dev->priv = kmalloc(sizeof(struct bonding), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+
+	memset(dev->priv, 0, sizeof(struct bonding));
+
+	bond = (struct bonding *) dev->priv;
+
+	bond->queue = kmalloc(sizeof(struct slave_queue), GFP_KERNEL);
+	if (bond->queue == NULL)
+		return -ENOMEM;
+
+	memset(bond->queue, 0, sizeof(struct slave_queue));
+
+	bond->stats = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	if (bond->stats == NULL)
+		return -ENOMEM;
+
+	memset(bond->stats, 0, sizeof(struct enet_statistics));
+
+	dev->get_stats	= bond_get_stats;
+
+	dev->open = bond_open;
+	dev->stop = bond_close;
+	dev->set_multicast_list = set_multicast_list;
+
+	dev->do_ioctl = bond_ioctl;
+
+	/* Fill in the fields of the device structure with ethernet-generic 
+	   values. */
+	ether_setup(dev);
+	dev->tx_queue_len = 0;
+	dev->flags |= (IFF_MASTER|IFF_MULTICAST);
+#ifdef CONFIG_NET_FASTROUTE
+	dev->accept_fastpath = bond_accept_fastpath;
+#endif
+
+	return 0;
+}
+
+static int bond_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct device *slave;
+	struct bonding *bond = (struct bonding *) dev->priv;
+	struct slave_queue *queue = bond->queue;
+	int good = 0;
+	
+	while (good == 0) {
+		slave = queue->current_slave->dev;
+		if (slave->flags & (IFF_UP|IFF_RUNNING)) {
+			skb->dev = slave;
+			skb->priority = 1;
+			dev_queue_xmit(skb);
+			good = 1;
+		}
+		if (queue->current_slave->next != NULL) {
+			queue->current_slave = queue->current_slave->next;
+		} else {
+			queue->current_slave = queue->head;
+		}
+	}
+
+	return 0;
+}
+
+static struct net_device_stats *bond_get_stats(struct device *dev)
+{
+	bonding_t *private = dev->priv;
+	slave_queue_t *queue = private->queue;
+	struct net_device_stats *stats = private->stats, *sstats;
+	slave_t *slave;
+	
+	memset(private->stats, 0, sizeof(struct net_device_stats));
+	for (slave=queue->head; slave != NULL; slave=slave->next) {
+		sstats = slave->dev->get_stats(slave->dev);
+ 
+		stats->rx_packets += sstats->rx_packets;
+		stats->rx_bytes += sstats->rx_bytes;
+		stats->rx_errors += sstats->rx_errors;
+		stats->rx_dropped += sstats->rx_dropped;
+
+		stats->tx_packets += sstats->tx_packets;
+		stats->tx_bytes += sstats->tx_bytes;
+		stats->tx_errors += sstats->tx_errors;
+		stats->tx_dropped += sstats->tx_dropped;
+
+		stats->multicast += sstats->multicast;
+		stats->collisions += sstats->collisions;
+
+		stats->rx_length_errors += sstats->rx_length_errors;
+		stats->rx_over_errors += sstats->rx_over_errors;
+		stats->rx_crc_errors += sstats->rx_crc_errors;
+		stats->rx_frame_errors += sstats->rx_frame_errors;
+		stats->rx_fifo_errors += sstats->rx_fifo_errors;	
+		stats->rx_missed_errors += sstats->rx_missed_errors;
+	
+		stats->tx_aborted_errors += sstats->tx_aborted_errors;
+		stats->tx_carrier_errors += sstats->tx_carrier_errors;
+		stats->tx_fifo_errors += sstats->tx_fifo_errors;
+		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+		stats->tx_window_errors += sstats->tx_window_errors;
+
+	}
+
+	return stats;
+}
+
+#ifdef MODULE
+
+__initfunc(static int bond_probe(struct device *dev))
+{
+	bond_init(dev);
+	return 0;
+}
+
+static char bond_name[16];
+
+static struct device dev_bond = {
+		bond_name, 	/* Needs to be writeable */
+		0, 0, 0, 0,
+	 	0x0, 0,
+	 	0, 0, 0, NULL, bond_probe };
+
+int init_module(void)
+{
+	/* Find a name for this unit */
+	int err=dev_alloc_name(&dev_bond,"bond%d");
+
+	if (err<0)
+		return err;
+
+	if (register_netdev(&dev_bond) != 0)
+		return -EIO;
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	struct bonding *bond = (struct bonding *) dev_bond.priv;
+
+	unregister_netdev(&dev_bond);
+
+	kfree(bond->queue);
+	kfree(bond->stats);
+	kfree(dev_bond.priv);
+
+	dev_bond.priv = NULL;
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.15-pre4/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- linux-2.2.15-pre4/drivers/net/dmfe.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/dmfe.c	Mon Dec  3 21:58:30 2001
@@ -283,7 +283,7 @@
 };
 
 /* function declaration ------------------------------------- */
-static int dmfe_probe(struct device *);
+int dmfe_probe(struct device *);
 static int dmfe_open(struct device *);
 static int dmfe_start_xmit(struct sk_buff *, struct device *);
 static int dmfe_stop(struct device *);
diff -urN linux-2.2.15-pre4/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.2.15-pre4/drivers/net/irda/nsc-ircc.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Dec  3 21:58:30 2001
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Wed Jan 19 08:59:16 2000
+ * Modified at:   Wed Jan 26 13:00:29 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -163,10 +163,6 @@
 	int reg;
 	int i = 0;
 
-#ifdef CONFIG_APM
-	apm_register_callback(nsc_ircc_apmproc);
-#endif /* CONFIG_APM */
-
 	/* Probe for all the NSC chipsets we know about */
 	for (chip=chips; chip->name ; chip++,i++) {
 		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
@@ -219,6 +215,12 @@
 		} 
 		
 	}
+#ifdef CONFIG_APM
+	/* Make sure at least one chip was found before enabling APM */
+	if (ret == 0)
+		apm_register_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
 	return ret;
 }
 
@@ -1207,7 +1209,7 @@
 	}
  out:
 	/* Not busy transmitting anymore if window is not full */
-	if (self->tx_fifo.free < MAX_WINDOW)
+	if (self->tx_fifo.free < MAX_TX_WINDOW)
 		dev->tbusy = 0;
 
 	/* Restore bank register */
@@ -1354,7 +1356,7 @@
 	}
 
 	/* Make sure we have room for more frames */
-	if (self->tx_fifo.free < MAX_WINDOW) {
+	if (self->tx_fifo.free < MAX_TX_WINDOW) {
 		/* Not busy transmitting anymore */
 		self->netdev->tbusy = 0;
 
@@ -1442,20 +1444,21 @@
 	
 	/* Read all entries in status FIFO */
 	switch_bank(iobase, BANK5);
-	while (((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) && 
-	       (st_fifo->tail < MAX_WINDOW))
-	{
-		st_fifo->entries[st_fifo->tail].status = status;
+	while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
+		/* We must empty the status FIFO no matter what */
+		len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
 
-		len = inb(iobase+RFLFL) | (inb(iobase+RFLFH) << 8);
-		
+		if (st_fifo->tail >= MAX_RX_WINDOW)
+			continue;
+			
+		st_fifo->entries[st_fifo->tail].status = status;
 		st_fifo->entries[st_fifo->tail].len = len;
 		st_fifo->pending_bytes += len;
 		st_fifo->tail++;
 		st_fifo->len++;
 	}
 	/* Try to process all entries in status FIFO */
-	while (st_fifo->len) {
+	while (st_fifo->len > 0) {
 		/* Get first entry */
 		status = st_fifo->entries[st_fifo->head].status;
 		len    = st_fifo->entries[st_fifo->head].len;
@@ -1662,8 +1665,8 @@
 
 	bank = inb(iobase+BSR);
 	
-	/* Status event, or end of frame detected in FIFO */
-	if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
+	/* Status FIFO event*/
+	if (eir & EIR_SFIF_EV) {
 		if (nsc_ircc_dma_receive_complete(self, iobase)) {
 			/* Wait for next status FIFO interrupt */
 			self->ier = IER_SFIF_IE;
@@ -1678,7 +1681,7 @@
 
 			/* Start timer */
 			outb(IRCR1_TMR_EN, iobase+IRCR1);
-			self->ier = IER_TMR_IE;
+			self->ier = IER_TMR_IE | IER_SFIF_IE;
 		}
 	} else if (eir & EIR_TMR_EV) { /* Timer finished */
 		/* Disable timer */
@@ -1709,7 +1712,7 @@
 				/* Prepare for receive */
 				nsc_ircc_dma_receive(self);
 			
-				self->ier = IER_LS_IE|IER_SFIF_IE;
+				self->ier = IER_SFIF_IE;
 			}
 		} else {
 			/*  Not finished yet, so interrupt on DMA again */
diff -urN linux-2.2.15-pre4/drivers/net/lmc/lmc_main.c linux/drivers/net/lmc/lmc_main.c
--- linux-2.2.15-pre4/drivers/net/lmc/lmc_main.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/net/lmc/lmc_main.c	Mon Dec  3 21:58:30 2001
@@ -313,7 +313,7 @@
 
 
 /* the watchdog process that cruises around */
-static void lmc_watchdog (unsigned long data) /*FOLD00*/
+static void lmc_watchdog (unsigned long data) /*fold00*/
 {
     struct device *dev = (struct device *) data;
     lmc_softc_t *sc;
@@ -483,9 +483,9 @@
 	/*
 	 *	Switch to common hdlc%d naming. We name by type not by vendor
 	 */
-    dev->name = (char *)(dev+1);
+    dev->name = (char *) (((u32) (dev)) + sizeof (struct ppp_device));
     dev_alloc_name(dev, "hdlc%d");
-    
+
     Lmc_Count++;
 
     if(lmc_first_load == 0){
@@ -504,10 +504,7 @@
      * Allocate space for the private data structure
      */
 
-    /* FIXME: we adjust to 8 byte align, but we then kfree the adjusted value
-       BUG BUG BUG - fortunately kmalloc will be 8 byte aligned.. */
-       
-    sc = (void *) (((long) kmalloc (sizeof (lmc_softc_t), GFP_KERNEL) + 7) & ~7);
+    sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL);
     if (sc == NULL) {
         printk (KERN_WARNING "%s: Cannot allocate memory for device state\n",
                 dev->name);
@@ -923,7 +920,6 @@
     del_timer (&sc->timer);
     sppp_close (dev);
     lmc_ifdown (dev);
-    printk(KERN_DEBUG "%s: Close ran\n", dev->name);
 
     return 0;
 }
@@ -1315,7 +1311,7 @@
 }
 
 
-static int lmc_rx (struct device *dev) /*FOLD00*/
+static int lmc_rx (struct device *dev) /*fold00*/
 {
     lmc_softc_t *sc;
     int i;
diff -urN linux-2.2.15-pre4/drivers/net/olympic.c linux/drivers/net/olympic.c
--- linux-2.2.15-pre4/drivers/net/olympic.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/net/olympic.c	Mon Dec  3 21:58:30 2001
@@ -23,10 +23,11 @@
  *  6/8/99  - Official Release 0.2.0   
  *            Merged into the kernel code 
  *  
- *  To Do:
- *
- *  Sanitize for smp
+ *  1/10/00 - Added Spinlocks for smp.
  *
+ *  To Do:
+ *	IPv6 Multicast 
+ *	
  *  If Problems do Occur
  *  Most problems can be rectified by either closing and opening the interface
  *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
@@ -71,6 +72,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
+#include <asm/spinlock.h>
 
 #include "olympic.h"
 
@@ -83,7 +85,7 @@
  */
 
 static char *version = 
-"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v0.2.1 1/10/00 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -245,6 +247,8 @@
 		}
 	}
 
+	spin_lock_init(&olympic_priv->olympic_lock) ; 
+
 #if OLYMPIC_DEBUG
 	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
 	printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -751,6 +755,8 @@
 	if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ 
 		return ;
 
+	spin_lock(&olympic_priv->olympic_lock) ; 
+
 	if (dev->interrupt) 
 		printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; 
 
@@ -829,15 +835,19 @@
 	dev->interrupt = 0 ;  
 
 	writel(SISR_MI,olympic_mmio+SISR_MASK_SUM);
-
+	spin_unlock(&olympic_priv->olympic_lock) ; 
 }	
 
 static int olympic_xmit(struct sk_buff *skb, struct device *dev) 
 {
 	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
-    __u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	__u8 *olympic_mmio=olympic_priv->olympic_mmio;
+	unsigned long flags ; 
+
+	spin_lock_irqsave(&olympic_priv->olympic_lock, flags) ; 
 
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; 
 		return 1;
 	}
 
@@ -854,10 +864,12 @@
 		writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
 
 		dev->tbusy=0;		
-
+		spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; 
 		return 0;
-	} else 
+	} else {
+		spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; 
 		return 1;
+	} 
 
 }
 	
diff -urN linux-2.2.15-pre4/drivers/net/olympic.h linux/drivers/net/olympic.h
--- linux-2.2.15-pre4/drivers/net/olympic.h	Mon Aug  9 12:04:39 1999
+++ linux/drivers/net/olympic.h	Mon Dec  3 21:58:30 2001
@@ -244,6 +244,8 @@
 	__u8 *olympic_mmio;
 	__u8 *olympic_lap;
 
+	spinlock_t	olympic_lock ; 
+
 	volatile int srb_queued;    /* True if an SRB is still posted */	
 	struct wait_queue *srb_wait;
 
diff -urN linux-2.2.15-pre4/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- linux-2.2.15-pre4/drivers/pnp/parport_probe.c	Wed Jan 20 13:29:18 1999
+++ linux/drivers/pnp/parport_probe.c	Mon Dec  3 21:58:30 2001
@@ -96,6 +96,7 @@
 	struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev);
 
 	int result = 0;
+	int lives = 1;
 
 	if (!dev) {
 		printk("%s: unable to register for probe.\n", port->name);
@@ -104,6 +105,7 @@
 
 	parport_claim_or_block(dev);
 
+ try_again:
 	switch (parport_ieee1284_nibble_mode_ok(port, 4)) {
 	case 2:
 		current->state=TASK_INTERRUPTIBLE;
@@ -115,6 +117,20 @@
 		result = -EIO;
 		break;
 	}
+
+	if (result < 1 && lives--) {
+		/* Reset the peripherals and try again. */
+		parport_pc_write_control(port, 0x8);
+		parport_pc_write_data(port, 0);
+		udelay (50);
+		parport_pc_write_control(port, 0xc);
+		udelay (500);
+		goto try_again;
+	}
+
+	printk (KERN_DEBUG "parport_probe: %s%s\n",
+		lives ? "" : "after reset: ",
+		result < 1 ? "failed" : "succeeded");
 
 	parport_release(dev);
 	parport_unregister_device(dev);
diff -urN linux-2.2.15-pre4/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- linux-2.2.15-pre4/drivers/scsi/aic7xxx.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/scsi/aic7xxx.c	Mon Dec  3 21:58:30 2001
@@ -10393,7 +10393,7 @@
          * instead of slowing down if those exist.  That's hard to do with simple
          * checksums though.
          */
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
         {
           printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
                  "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -10424,7 +10424,7 @@
       }
       else
       {
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION) 
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
         {
           printk(INFO_LEAD "Performing Domain validation.\n",
                  p->host_no, CTL_OF_CMD(cmd));
@@ -10449,7 +10449,7 @@
     } 
     else
     {
-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
           (p->needdv & (1<<tindex)) )
       {
         printk(INFO_LEAD "Successfully completed Domain validation.\n",
diff -urN linux-2.2.15-pre4/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux-2.2.15-pre4/drivers/scsi/scsi.c	Mon Dec  3 21:58:24 2001
+++ linux/drivers/scsi/scsi.c	Mon Dec  3 21:58:30 2001
@@ -290,6 +290,7 @@
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN},
+{"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
diff -urN linux-2.2.15-pre4/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- linux-2.2.15-pre4/drivers/scsi/sd.c	Tue Jan  4 10:12:21 2000
+++ linux/drivers/scsi/sd.c	Mon Dec  3 21:58:30 2001
@@ -483,11 +483,16 @@
 	 * would be a ten byte read where only a six byte read was supported.
 	 * Also, on a system where READ CAPACITY failed, we have have read
 	 * past the end of the disk.
+	 *
+	 * Don't screw with the ten byte flag unless we are certain that
+	 * the drive does not understand the command /axboe
 	 */
 
 	if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
 	    if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) {
-		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
+		if (SCpnt->cmnd[0] == READ_10 || SCpnt->cmnd[0] == WRITE_10 ||
+		    SCpnt->sense_buffer[12] == 0x20)
+		    rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
 		requeue_sd_request(SCpnt);
 		result = 0;
 	    } else {
@@ -1016,7 +1021,7 @@
 	this_count = this_count << 1;
     }
 
-    if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
+    if (((this_count > 0xff) ||  (block > 0x1fffff)) || rscsi_disks[dev].ten)
     {
 	if (this_count > 0xffff)
 	    this_count = 0xffff;
diff -urN linux-2.2.15-pre4/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- linux-2.2.15-pre4/fs/qnx4/dir.c	Mon Dec  3 21:58:25 2001
+++ linux/fs/qnx4/dir.c	Mon Dec  3 21:58:30 2001
@@ -35,13 +35,13 @@
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
 
 	while (filp->f_pos < inode->i_size) {
-		blknum = qnx4_block_map( inode, filp->f_pos / QNX4_BLOCK_SIZE );
+		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT );
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
 		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
 		}
-		ix = (filp->f_pos / QNX4_DIR_ENTRY_SIZE - (filp->f_pos / QNX4_BLOCK_SIZE) * QNX4_INODES_PER_BLOCK) % QNX4_INODES_PER_BLOCK;
+		ix = ( (filp->f_pos >> QNX4_DIR_ENTRY_SIZE_SHIFT) - (filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT) * QNX4_INODES_PER_BLOCK) & QNX4_INODES_PER_BLOCK_MASK;
 		while (ix < QNX4_INODES_PER_BLOCK) {
 			offset = ix * QNX4_DIR_ENTRY_SIZE;
 			de = (struct qnx4_inode_entry *) (bh->b_data + offset);
diff -urN linux-2.2.15-pre4/include/linux/if_bonding.h linux/include/linux/if_bonding.h
--- linux-2.2.15-pre4/include/linux/if_bonding.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_bonding.h	Mon Dec  3 21:58:30 2001
@@ -0,0 +1,59 @@
+/*
+ * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'.
+ *
+ * 
+ * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Management, Inc.
+ *
+ * BUT, I'm the one who modified it for ethernet, so:
+ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ * 
+ */
+
+#ifndef _LINUX_IF_BONDING_H
+#define _LINUX_IF_BONDING_H
+
+#include <linux/timer.h>
+
+#define BOND_ENSLAVE     (SIOCDEVPRIVATE)
+#define BOND_RELEASE     (SIOCDEVPRIVATE + 1)
+#define BOND_SETHWADDR   (SIOCDEVPRIVATE + 2)
+
+typedef struct slave {
+	struct device *dev;
+	struct slave *next;
+	struct slave *prev;
+} slave_t;
+
+typedef struct slave_queue {
+	slave_t *head;
+	slave_t *tail;
+	slave_t *current_slave;
+	int num_slaves;
+	struct device *master_dev;
+	char lock;
+} slave_queue_t;
+
+typedef struct bonding {
+	slave_queue_t *queue;
+	int min_slaves;
+	int max_slaves;
+	struct net_device_stats *stats;
+	struct timer_list timer;
+	char timer_on;
+} bonding_t;  
+
+#endif /* _LINUX_BOND_H */
+
+/*
+ * Local variables:
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.15-pre4/include/linux/isdn.h linux/include/linux/isdn.h
--- linux-2.2.15-pre4/include/linux/isdn.h	Tue Jan  4 10:12:25 2000
+++ linux/include/linux/isdn.h	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.81 1999/10/27 21:21:18 detabc Exp $
+/* $Id: isdn.h,v 1.88 2000/01/20 19:59:43 keil Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,43 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.88  2000/01/20 19:59:43  keil
+ * Add FAX Class 1 support
+ *
+ * Revision 1.87  2000/01/09 20:43:15  detabc
+ * exand logical bind-group's for both call's (in and out).
+ * add first part of kernel-config-help for abc-extension.
+ *
+ * Revision 1.86  1999/12/05 16:06:09  detabc
+ * add resethandling for rawip-compression.
+ * at now all B2-Protocols are usable with rawip-compression
+ *
+ * Revision 1.85  1999/11/30 11:29:06  detabc
+ * add a on the fly frame-counter and limit
+ *
+ * Revision 1.84  1999/11/28 14:49:08  detabc
+ * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the
+ * uncompressed size.
+ *
+ * Revision 1.83  1999/11/26 15:54:59  detabc
+ * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol.
+ *
+ * Revision 1.82  1999/11/20 22:14:14  detabc
+ * added channel dial-skip in case of external use
+ * (isdn phone or another isdn device) on the same NTBA.
+ * usefull with two or more card's connected the different NTBA's.
+ * global switchable in kernel-config and also per netinterface.
+ *
+ * add auto disable of netinterface's in case of:
+ * 	to many connection's in short time.
+ * 	config mistakes (wrong encapsulation, B2-protokoll or so on) on local
+ * 	or remote side.
+ * 	wrong password's or something else to a ISP (syncppp).
+ *
+ * possible encapsulations for this future are:
+ * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
+ * and ISDN_NET_ENCAP_CISCOHDLCK.
+ *
  * Revision 1.81  1999/10/27 21:21:18  detabc
  * Added support for building logically-bind-group's per interface.
  * usefull for outgoing call's with more then one isdn-card.
@@ -333,6 +370,10 @@
 #undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
 #undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
 #undef CONFIG_ISDN_WITH_ABC_ICALL_BIND
+#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
+#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
+#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
+#undef CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
 
 
 /* New ioctl-codes */
@@ -359,6 +400,7 @@
 #define IIOCGETCPS  _IO('I',21)
 #define IIOCGETDVR  _IO('I',22)
 #define IIOCNETLCR  _IO('I',23) /* dwabc ioctl for LCR from isdnlog */
+#define IIOCNETDWRSET  _IO('I',24) /* dwabc ioctl to reset abc-values to default on a net-interface */
 
 #define IIOCNETALN  _IO('I',32)
 #define IIOCNETDLN  _IO('I',33)
@@ -923,6 +965,7 @@
 	isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
 	struct semaphore  sem;                       /* serialize list access*/
 	isdn_module       *modules;
+	unsigned long     global_features;
 } isdn_dev;
 
 extern isdn_dev *dev;
diff -urN linux-2.2.15-pre4/include/linux/isdnif.h linux/include/linux/isdnif.h
--- linux-2.2.15-pre4/include/linux/isdnif.h	Tue Jan  4 10:12:25 2000
+++ linux/include/linux/isdnif.h	Mon Dec  3 21:58:30 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.32 1999/10/11 22:03:00 keil Exp $
+/* $Id: isdnif.h,v 1.33 2000/01/20 19:59:43 keil Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.33  2000/01/20 19:59:43  keil
+ * Add FAX Class 1 support
+ *
  * Revision 1.32  1999/10/11 22:03:00  keil
  * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
  *
@@ -175,10 +178,11 @@
 /*
  * Values for Layer-3-protocol-selection
  */
-#define ISDN_PROTO_L3_TRANS  0   /* Transparent                 */
-#define ISDN_PROTO_L3_TRANSDSP 1   /* Transparent with DSP    */
-#define ISDN_PROTO_L3_FAX    2   /* Fax Group 2/3             */
-#define ISDN_PROTO_L3_MAX    7   /* Max. 8 Protocols            */
+#define ISDN_PROTO_L3_TRANS	0	/* Transparent */
+#define ISDN_PROTO_L3_TRANSDSP	1	/* Transparent with DSP */
+#define ISDN_PROTO_L3_FCLASS2	2	/* Fax Group 2/3 CLASS 2 */
+#define ISDN_PROTO_L3_FCLASS1	3	/* Fax Group 2/3 CLASS 1 */
+#define ISDN_PROTO_L3_MAX	7	/* Max. 8 Protocols */
 
 #ifdef __KERNEL__
 
@@ -362,7 +366,8 @@
 /* Layer 3 */
 #define ISDN_FEATURE_L3_TRANS   (0x10000 << ISDN_PROTO_L3_TRANS)
 #define ISDN_FEATURE_L3_TRANSDSP (0x10000 << ISDN_PROTO_L3_TRANSDSP)
-#define ISDN_FEATURE_L3_FAX	(0x10000 << ISDN_PROTO_L3_FAX)
+#define ISDN_FEATURE_L3_FCLASS2	(0x10000 << ISDN_PROTO_L3_FCLASS2)
+#define ISDN_FEATURE_L3_FCLASS1	(0x10000 << ISDN_PROTO_L3_FCLASS1)
 
 #define ISDN_FEATURE_L3_MASK    (0x0FF0000) /* Max. 8 Protocols */
 #define ISDN_FEATURE_L3_SHIFT   (16)
@@ -463,6 +468,33 @@
 
 #endif /* TTY_FAX */
 
+#define ISDN_FAX_CLASS1_FAE	0
+#define ISDN_FAX_CLASS1_FTS	1
+#define ISDN_FAX_CLASS1_FRS	2
+#define ISDN_FAX_CLASS1_FTM	3
+#define ISDN_FAX_CLASS1_FRM	4
+#define ISDN_FAX_CLASS1_FTH	5
+#define ISDN_FAX_CLASS1_FRH	6
+#define ISDN_FAX_CLASS1_CTRL	7
+
+#define ISDN_FAX_CLASS1_OK	0
+#define ISDN_FAX_CLASS1_CONNECT	1
+#define ISDN_FAX_CLASS1_NOCARR	2
+#define ISDN_FAX_CLASS1_ERROR	3
+#define ISDN_FAX_CLASS1_FCERROR	4
+#define ISDN_FAX_CLASS1_QUERY	5
+
+typedef struct {
+	__u8	cmd;
+	__u8	subcmd;
+	__u8	para[50];
+} aux_s;
+
+#define AT_COMMAND	0
+#define AT_EQ_VALUE	1
+#define AT_QUERY	2
+#define AT_EQ_QUERY	3
+
 /* CAPI structs */
 
 /* this is compatible to the old union size */
@@ -494,13 +526,14 @@
 	int   command;		/* Command or Status (see above) */
 	ulong arg;		/* Additional Data               */
 	union {
-		ulong errcode;	/* Type of error with STAT_L1ERR         */
-		int length;	/* Amount of bytes sent with STAT_BSENT  */
-		u_char num[50];/* Additional Data			*/
+		ulong errcode;	/* Type of error with STAT_L1ERR	*/
+		int length;	/* Amount of bytes sent with STAT_BSENT	*/
+		u_char num[50];	/* Additional Data			*/
 		setup_parm setup;/* For SETUP msg			*/
 		capi_msg cmsg;	/* For CAPI like messages		*/
-		char display[85];/* display message data          */ 
-		dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */
+		char display[85];/* display message data		*/ 
+		dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result	*/
+		aux_s aux;	/* for modem commands/indications	*/
 #ifdef CONFIG_ISDN_TTY_FAX
 		T30_s	*fax;	/* Pointer to ttys fax struct		*/
 #endif
diff -urN linux-2.2.15-pre4/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- linux-2.2.15-pre4/include/linux/qnx4_fs.h	Mon Dec  3 21:58:25 2001
+++ linux/include/linux/qnx4_fs.h	Mon Dec  3 21:58:30 2001
@@ -29,10 +29,12 @@
 #define QNX4_VALID_FS		0x0001	/* Clean fs. */
 #define QNX4_ERROR_FS		0x0002	/* fs has errors. */
 #define QNX4_BLOCK_SIZE         0x200	/* blocksize of 512 bytes */
-#define QNX4_DIR_ENTRY_SIZE     0x040	/* dir entry size */
+#define QNX4_BLOCK_SIZE_SHIFT	9
+#define QNX4_DIR_ENTRY_SIZE     0x040	/* dir entry size of 64 bytes */
+#define QNX4_DIR_ENTRY_SIZE_SHIFT 6
 #define QNX4_XBLK_ENTRY_SIZE    0x200	/* xblk entry size */
 #define QNX4_INODES_PER_BLOCK   0x08	/* 512 / 64 */
-
+#define QNX4_INODES_PER_BLOCK_MASK 0x07
 /* for filenames */
 #define QNX4_SHORT_NAME_MAX	16
 #define QNX4_NAME_MAX		48
diff -urN linux-2.2.15-pre4/include/net/irda/nsc-ircc.h linux/include/net/irda/nsc-ircc.h
--- linux-2.2.15-pre4/include/net/irda/nsc-ircc.h	Mon Dec  3 21:58:25 2001
+++ linux/include/net/irda/nsc-ircc.h	Mon Dec  3 21:58:30 2001
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Nov 13 14:37:40 1998
- * Modified at:   Thu Jan 13 18:27:38 2000
+ * Modified at:   Sun Jan 23 17:47:00 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -204,10 +204,11 @@
 	int len;
 };
 
-#define MAX_WINDOW 7
+#define MAX_TX_WINDOW 7
+#define MAX_RX_WINDOW 7
 
 struct st_fifo {
-	struct st_fifo_entry entries[MAX_WINDOW];
+	struct st_fifo_entry entries[MAX_RX_WINDOW];
 	int pending_bytes;
 	int head;
 	int tail;
@@ -220,20 +221,17 @@
 };
 
 struct tx_fifo {
-	struct frame_cb queue[MAX_WINDOW]; /* Info about frames in queue */
-	int             ptr;               /* Currently being sent */
-	int             len;               /* Lenght of queue */
-	int             free;              /* Next free slot */
-	void           *tail;              /* Next free start in DMA mem */
+	struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
+	int             ptr;                  /* Currently being sent */
+	int             len;                  /* Lenght of queue */
+	int             free;                 /* Next free slot */
+	void           *tail;                 /* Next free start in DMA mem */
 };
 
 /* Private data for each instance */
 struct nsc_ircc_cb {
 	struct st_fifo st_fifo;    /* Info about received frames */
 	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
-
-	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
-	int tx_len;                /* Number of frames in tx_buff */
 
 	struct device *netdev;     /* Yes! we are some kind of netdevice */
 	struct net_device_stats stats;
diff -urN linux-2.2.15-pre4/kernel/exit.c linux/kernel/exit.c
--- linux-2.2.15-pre4/kernel/exit.c	Tue Jan  4 10:12:25 2000
+++ linux/kernel/exit.c	Mon Dec  3 21:58:30 2001
@@ -473,6 +473,7 @@
 				if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
 					continue;
 				read_unlock(&tasklist_lock);
+				current->state = TASK_RUNNING;	/* We *must* do this before touching userspace! */
 				retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; 
 				if (!retval && stat_addr) 
 					retval = put_user((p->exit_code << 8) | 0x7f, stat_addr);
@@ -485,6 +486,7 @@
 				current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime;
 				current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime;
 				read_unlock(&tasklist_lock);
+				current->state = TASK_RUNNING;	/* We *must* do this before touching userspace! */
 				retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
 				if (!retval && stat_addr)
 					retval = put_user(p->exit_code, stat_addr);
diff -urN linux-2.2.15-pre4/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.2.15-pre4/mm/page_alloc.c	Mon Dec  3 21:58:25 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 21:58:30 2001
@@ -210,6 +210,12 @@
 	 */
 	if (!(current->flags & PF_MEMALLOC)) {
 		int freed;
+		if (current->state != TASK_RUNNING && (gfp_mask & __GFP_WAIT)) {
+			printk("gfp called by non-running (%d) task from %p!\n",
+				current->state, __builtin_return_address(0));
+			/* if we're not running, we can't sleep */
+			gfp_mask &= ~__GFP_WAIT;
+		}
 
 		if (nr_free_pages <= freepages.low) {
 			wake_up_interruptible(&kswapd_wait);
@@ -224,6 +230,9 @@
 		current->flags |= PF_MEMALLOC;
 		freed = try_to_free_pages(gfp_mask);
 		current->flags &= ~PF_MEMALLOC;
+
+		if ((gfp_mask & __GFP_MED) && nr_free_pages > freepages.min / 2)
+			goto ok_to_allocate;
 
 		if (!freed && !(gfp_mask & __GFP_HIGH))
 			goto nopage;
diff -urN linux-2.2.15-pre4/net/core/dev.c linux/net/core/dev.c
--- linux-2.2.15-pre4/net/core/dev.c	Tue Jan  4 10:12:26 2000
+++ linux/net/core/dev.c	Mon Dec  3 21:58:30 2001
@@ -784,6 +784,9 @@
 #else
 		netdev_dropping = 0;
 #endif
+		if (skb->dev->flags & IFF_SLAVE  &&  skb->dev->slave) {
+			skb->dev = skb->dev->slave;
+		}
 		skb_queue_tail(&backlog,skb);
 		mark_bh(NET_BH);
 		return;
diff -urN linux-2.2.15-pre4/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux-2.2.15-pre4/net/ipv4/tcp.c	Mon Dec  3 21:58:25 2001
+++ linux/net/ipv4/tcp.c	Mon Dec  3 21:58:30 2001
@@ -1283,6 +1283,9 @@
 		continue;
 
 	found_ok_skb:
+		/* Below we'll be accessing user memory, which might sleep, so... */
+		current->state = TASK_RUNNING;
+
 		/*	Lock the buffer. We can be fairly relaxed as
 		 *	an interrupt will never steal a buffer we are
 		 *	using unless I've missed something serious in
@@ -1364,15 +1367,15 @@
 		break;
 	}
 
+	remove_wait_queue(sk->sleep, &wait);
+	current->state = TASK_RUNNING;
+
 	if(copied >= 0 && msg->msg_name) {
 		tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
 					       msg->msg_name);       
 		if(addr_len)
 			*addr_len = tp->af_specific->sockaddr_len;
 	}
-
-	remove_wait_queue(sk->sleep, &wait);
-	current->state = TASK_RUNNING;
 
 	/* Clean up data we have read: This will do ACK frames. */
 	cleanup_rbuf(sk, copied);
diff -urN linux-2.2.15-pre4/net/irda/irda_device.c linux/net/irda/irda_device.c
--- linux-2.2.15-pre4/net/irda/irda_device.c	Mon Dec  3 21:58:25 2001
+++ linux/net/irda/irda_device.c	Mon Dec  3 21:58:30 2001
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Oct  9 09:22:27 1999
- * Modified at:   Sun Dec 12 12:24:32 1999
+ * Modified at:   Sun Jan 23 09:16:36 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -55,7 +55,8 @@
 #include <net/irda/wrapper.h>
 
 extern int irtty_init(void);
-extern int pc87108_init(void);
+extern int nsc_ircc_init(void);
+extern int ircc_init(void);
 extern int w83977af_init(void);
 extern int esi_init(void);
 extern int tekram_init(void);
@@ -121,7 +122,7 @@
 	w83977af_init();
 #endif
 #ifdef CONFIG_NSC_FIR
-	pc87108_init();
+	nsc_ircc_init();
 #endif
 #ifdef CONFIG_TOSHIBA_FIR
 	toshoboe_init();
@@ -143,9 +144,6 @@
 #endif
 #ifdef CONFIG_LITELINK_DONGLE
 	litelink_init();
-#endif
-#ifdef CONFIG_AIRPORT_DONGLE
- 	airport_init();
 #endif
 #ifdef CONFIG_OLD_BELKIN
  	old_belkin_init();
