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

diff -urN linux-2.0.31-pre2/arch/alpha/defconfig linux-2.0.31-pre3/arch/alpha/defconfig
--- linux-2.0.31-pre2/arch/alpha/defconfig	2003-08-15 15:03:52.000000000 -0700
+++ linux-2.0.31-pre3/arch/alpha/defconfig	2003-08-15 15:03:53.000000000 -0700
@@ -169,6 +169,7 @@
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
 
 #
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
diff -urN linux-2.0.31-pre2/arch/i386/defconfig linux-2.0.31-pre3/arch/i386/defconfig
--- linux-2.0.31-pre2/arch/i386/defconfig	2003-08-15 15:03:52.000000000 -0700
+++ linux-2.0.31-pre3/arch/i386/defconfig	2003-08-15 15:03:53.000000000 -0700
@@ -124,6 +124,7 @@
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
 
 #
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
diff -urN linux-2.0.31-pre2/Documentation/Configure.help linux-2.0.31-pre3/Documentation/Configure.help
--- linux-2.0.31-pre2/Documentation/Configure.help	2003-08-15 15:03:52.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/Configure.help	2003-08-15 15:03:53.000000000 -0700
@@ -1747,6 +1747,15 @@
   available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
 
+GDT SCSI Disk Array Controller support
+CONFIG_SCSI_GDTH
+  This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) 
+  manufactured by ICP vortex. It is documented in the kernel source in
+  drivers/scsi/gdth.c and drivers/scsi/gdth.h. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile 
+  it as a module, say M here and read Documentation/modules.txt. 	
+
 IOMEGA Parallel Port ZIP drive SCSI support
 CONFIG_SCSI_PPA
   This driver supports the parallel port version of IOMEGA's ZIP drive
@@ -3828,8 +3837,8 @@
   (mgetty+sendfax by gert@greenie.muc.de with an extension, available
   with the ISDN utility package for example), you will be able
   to use your Linux box as an ISDN-answering machine. Of course, this
-  must be supported by the lowlevel driver also. Currently, the Teles
-  driver is the only voice-supporting one. See
+  must be supported by the lowlevel driver also. Currently HiSax 
+  driver is the only voice-supporting drivers. See
   Documentation/isdn/README.audio for more information.
 
 ICN 2B and 4B support
@@ -3842,14 +3851,89 @@
   separately.  See Documentation/isdn/README and README.icn for more
   information.
 
-Teles, NICCY1016PC, Creatix support
-CONFIG_ISDN_DRV_TELES
-  This enables support for the Teles ISDN-cards S0-16.0, S0-16.3, S0-8
-  and many compatibles. By default, the driver is configured to
-  support a 16.0-type using EDSS1-protocol. See
-  Documentation/isdn/README on how to configure it using 16.3, a
-  different D-channel protocol, or non-standard irq/port/shmem
-  settings.
+HiSax SiemensChipSet driver support
+CONFIG_ISDN_DRV_HISAX
+  This driver replaces the old Teles driver. It supports the Siemens
+  chipset in a more general way. This chipset is used on various
+  ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0,
+  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and 
+  many compatibles). It's a complete rewrite of the original Teles 
+  driver.
+  See Documentation/isdn/README.HiSax for further informations on
+  using this driver.
+
+HiSax Support for 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.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for 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.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for AVM A1 (Fritz)
+CONFIG_HISAX_AVM_A1
+  This enables HiSax support for the AVM A1 (aka "Fritz").
+  See Documentation/isdn/README.HiSax on how to configure it
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for Elsa ISA cards
+CONFIG_HISAX_ELSA_PCC
+  This enables HiSax support for the Elsa Mircolink cards and
+  for the Elsa Quickstep series cards for the ISA bus.
+  You don't have to select "HiSax Support for Elsa PCMCIA card"
+  at the same time.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for Elsa PCMCIA card
+CONFIG_HISAX_ELSA_PCMCIA
+  This enables HiSax support for the Elsa PCMCIA card.
+  You don't have to select "HiSax Support for Elsa ISA cards" at
+  the same time.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for ITK ix1-micro Revision 2
+CONFIG_HISAX_IX1MICROR2
+  This enables HiSax support for the ITK ix1-micro Revision 2 card.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
+HiSax Support for EURO/DSS1
+CONFIG_HISAX_EURO
+  You should choose your D-channel protocol your local
+  telephone service provider uses here by saying Y or N.
+  NOTE: This is mutually exclusive with HiSax Support for
+  german 1TR6 and US/NI-1 if you have only one ISDN card
+  installed.
+
+HiSax Support for US/NI-1
+CONFIG_HISAX_NI1
+  You should choose your D-channel protocol your local
+  telephone service provider uses here by saying Y or N.
+  NOTE: This is mutually exclusive with HiSax Support for
+  german 1TR6 and EURO/DSS1 if you have only one ISDN card
+  installed. (not working yet, under developement)
+
+HiSax Support for german 1TR6
+CONFIG_HISAX_1TR6
+  You should choose your D-channel protocol your local
+  telephone service provider uses here by saying Y or N.
+  NOTE: This is mutually exclusive with HiSax Support for
+  EURO/DSS1 and US/NI-1 if you have only one ISDN card
+  installed.
 
 PCBIT-D support
 CONFIG_ISDN_DRV_PCBIT
@@ -3860,6 +3944,21 @@
   Documentation/isdn/README and Documentation/isdn/README.pcbit for
   more information.
 
+Spellcaster support (EXPERIMENTAL)
+CONFIG_ISDN_DRV_SC
+  This enables support for the Spellcaster BRI boards. This driver
+  currently builds in a modularized version only.
+  See Documentation/isdn/README.sc and http://www.spellcast.com
+  for more information.
+
+AVM-B1 with CAPI2.0 support
+CONFIG_ISDN_DRV_AVMB1
+  This enables support for the AVM B1 card and also adds a CAPI2.0
+  interface for this card. For running this card, additional firmware
+  is necessary, which has to be downloaded into the card using a
+  utility which is distributed separately.
+  See Documentation/isdn/README.avmb1 for more information.
+
 Support for AP1000 multicomputer
 CONFIG_AP1000
   This enables support for a sparc based parallel multi-computer
diff -urN linux-2.0.31-pre2/Documentation/isdn/00-INDEX linux-2.0.31-pre3/Documentation/isdn/00-INDEX
--- linux-2.0.31-pre2/Documentation/isdn/00-INDEX	1996-06-06 04:57:43.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/00-INDEX	2003-08-15 15:03:53.000000000 -0700
@@ -10,12 +10,13 @@
 	- info for running audio over ISDN.
 README.icn
 	- info on the ICN-ISDN-card and its driver.
+README.HiSax
+	- info on the HiSax driver which replaces the old teles.
 README.pcbit
 	- info on the PCBIT-D ISDN adapter and driver.
 README.syncppp
 	- info on running Sync PPP over ISDN.
-README.teles
-	- info on driver for Teles compatible ISDN cards.
 syncPPP.FAQ
 	- frequently asked questions about running PPP over ISDN.
-
+README.avmb1
+	- info on driver for AVM-B1 ISDN card
diff -urN linux-2.0.31-pre2/Documentation/isdn/CREDITS linux-2.0.31-pre3/Documentation/isdn/CREDITS
--- linux-2.0.31-pre2/Documentation/isdn/CREDITS	1996-04-21 01:56:13.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/CREDITS	2003-08-15 15:03:53.000000000 -0700
@@ -12,11 +12,18 @@
   For contribution of man-pages, the imontty-tool and a perfect
   maintaining of the mailing-list at hub-wue.
 
+Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de)
+  For maintaining the FAQ.
+
+Michael 'Ghandi' Herold (michael@abadonna.franken.de)
+  For contribution of the vbox answering machine.
+
 Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
   For his Sync-PPP-code.
 
 Karsten Keil (isdn4@temic-ech.spacenet.de)
   For adding 1TR6-support to the Teles-driver.
+  For the HiSax-driver.
 
 Michael Knigge (knick@cove.han.de)
   For contributing the imon-tool
@@ -39,7 +46,9 @@
 Gerhard 'Fido' Schneider (fido@wuff.franken.de)
   For heavy-duty-beta-testing with his BBS ;)
 
-Thomas Uhl (uhl@hn-net.de)
+Thomas Uhl (uhl@think.de)
   For distributing the cards.
   For pushing me to work ;-)
 
+Carsten Paeth (calle@calle.in-berlin.de)
+  For the AVM-B1-CAPI2.0 driver
diff -urN linux-2.0.31-pre2/Documentation/isdn/INTERFACE linux-2.0.31-pre3/Documentation/isdn/INTERFACE
--- linux-2.0.31-pre2/Documentation/isdn/INTERFACE	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/Documentation/isdn/INTERFACE	2003-08-15 15:03:53.000000000 -0700
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.5 1996/11/06 17:40:47 keil Exp $
+$Id: INTERFACE,v 1.6 1997/02/10 22:40:57 fritz Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -140,7 +140,7 @@
 
   int (*writebuf)(int, int, u_char*, int, int);
 
-    ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function
+    ***CHANGED1.14: Declared obsolete. Do NOT use this field/function
                     anymore, since it will be removed when all current
                     LL drivers have been changed accordingly. Set this
                     field to NULL and use writebuf_skb instead.
@@ -199,7 +199,7 @@
       int     driver-Id.
       int     channel-number locally to the HL-driver. (starts with 0)
 
-***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
+***CHANGED1.14: The driver-Id and channel-number are new since this revision.
 
     Returnvalue:
       Length of data accepted on success, else error-code (-EINVAL etc.)
@@ -223,7 +223,7 @@
       int     driver-Id.
       int     channel-number locally to the HL-driver. (starts with 0)
 
-***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
+***CHANGED1.14: The driver-Id and channel-number are new since this revision.
 
     Returnvalue:
       Length of data on success, else error-code (-EINVAL etc.)
@@ -249,6 +249,9 @@
 
    Until now, the following commands are defined:
 
+***CHANGED1.34: The parameter "num" has been replaced by a union "para" containing
+                the old "num" and a new setup_type struct used for ISDN_CMD_DIAL
+                and ISDN_STAT_ICALL callback.
 
    ISDN_CMD_IOCTL:
 
@@ -262,10 +265,10 @@
        called with the field command set to 1.
 
      Parameter:
-       driver  = driver-Id.
-       command = ISDN_CMD_IOCTL
-       arg     = Original ioctl-cmd - IIOCDRVCTL
-       num     = first bytes filled with (unsigned long)arg
+       driver   = driver-Id.
+       command  = ISDN_CMD_IOCTL
+       arg      = Original ioctl-cmd - IIOCDRVCTL
+       para.num = first bytes filled with (unsigned long)arg
    
      Returnvalue:
        Depending on driver.
@@ -280,12 +283,14 @@
       driver      = driver-Id.
       command     = ISDN_CMD_DIAL
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = An ASCII-String containing the number to dial, the own
-                    EAZ or MSN, the Service-Indicator and the Additional
-                    Info. Format:
-                    "%s,%s,%d,%d" RemotePhoneNumber,EazOrMsn,SI,AI
+      
+      para.setup.phone  = An ASCII-String containing the number to dial.
+      para.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN.
+      para.setup.si1    = The Service-Indicator.
+      para.setup.si2    = Additional Service-Indicator.
+
                     If the Line has been designed as SPV (a special german
-                    feature, meaning semi-leased-line) the number has to
+                    feature, meaning semi-leased-line) the phone has to
                     start with an "S".
       ***CHANGE0.6: In previous versions the EAZ has been given in the
                     highbyte of arg.
@@ -300,7 +305,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_ACCEPTD
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_ACCEPTB:
 
@@ -311,7 +316,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_ACCEPTB
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_HANGUP:
 
@@ -323,7 +328,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_HANGUP
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_CLREAZ:
 
@@ -334,7 +339,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_CLREAZ
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_SETEAZ:
 
@@ -345,7 +350,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_SETEAZ
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = ASCII-String, containing the desired EAZ's/MSN's
+      para.num    = ASCII-String, containing the desired EAZ's/MSN's
                     (comma-separated). If an empty String is given, the
                     HL-driver should respond to ALL incoming calls,
                     regardless of the destination-address.
@@ -360,7 +365,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_GETEAZ
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = ASCII-String, containing the current EAZ's/MSN's
+      para.num    = ASCII-String, containing the current EAZ's/MSN's
 
   ISDN_CMD_SETSIL: (currently unused)
 
@@ -371,7 +376,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_SETSIL
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = ASCII-String, containing the desired Service-Indicators.
+      para.num    = ASCII-String, containing the desired Service-Indicators.
 
   ISDN_CMD_GETSIL: (currently unused)
 
@@ -382,7 +387,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_SETSIL
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = ASCII-String, containing the current Service-Indicators.
+      para.num    = ASCII-String, containing the current Service-Indicators.
 
   ISDN_CMD_SETL2:
 
@@ -397,7 +402,7 @@
       arg         = channel-number locally to the driver. (starting with 0)
                     logical or'ed with (protocol-Id << 8)
                     protocol-Id is one of the constants ISDN_PROTO_L2...
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_GETL2: (currently unused)
 
@@ -408,7 +413,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_GETL2
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
     Returnvalue:
       current protocol-Id (one of the constants ISDN_L2_PROTO)
 
@@ -425,7 +430,7 @@
       arg         = channel-number locally to the driver. (starting with 0)
                     logical or'ed with (protocol-Id << 8)
                     protocol-Id is one of the constants ISDN_PROTO_L3...
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_GETL2: (currently unused)
 
@@ -436,7 +441,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_GETL3
       arg         = channel-number locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
     Returnvalue:
       current protocol-Id (one of the constants ISDN_L3_PROTO)
 
@@ -450,7 +455,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_LOCK
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_UNLOCK:
 
@@ -462,7 +467,7 @@
       driver      = driver-Id.
       command     = ISDN_CMD_UNLOCK
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
 3. Description of the events to be signaled by the HL-driver to th LL.
 
@@ -484,19 +489,23 @@
       driver      = driver-Id
       command     = ISDN_STAT_STAVAIL
       arg         = length of available data.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_ICALL:
 
     With this call, the HL-driver signals an incoming call to the LL.
 
     Parameter:
-      driver      = driver-Id
-      command     = ISDN_STAT_ICALL
-      arg         = channel-number, locally to the driver. (starting with 0)
-      num         = ASCII-String in the following format:
-                    "%s,%d,%d,%s",CallerNumber,ServiceIndicator,AddInfo,
-                    CalledNumber.
+      driver            = driver-Id
+      command           = ISDN_STAT_ICALL
+      arg               = channel-number, locally to the driver. (starting with 0)
+      para.setup.phone  = Callernumber.
+      para.setup.eazmsn = CalledNumber.
+      para.setup.si1    = Service Indicator.
+      para.setup.si2    = Additional Service Indicator.
+      para.setup.plan   = octet 3 from Calling party number Information Element.
+      para.setup.screen = octet 3a from Calling party number Information Element.
+
     Return:
       0           = No device matching this call.
       1           = At least one device matching this call (RING on ttyI).
@@ -513,7 +522,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_RUN
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_STOP:
 
@@ -524,7 +533,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_STOP
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_DCONN:
 
@@ -535,7 +544,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_DCONN
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_BCONN:
 
@@ -547,7 +556,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_BCONN
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_DHUP:
 
@@ -560,7 +569,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_DHUP
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_BHUP:
 
@@ -572,7 +581,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_BHUP
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_CINF:
 
@@ -583,7 +592,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_CINF
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = ASCII string containing charge-units (digits only).
+      para.num    = ASCII string containing charge-units (digits only).
 
   ISDN_STAT_LOAD: (currently unused)
 
@@ -596,7 +605,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_UNLOAD
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_BSENT:
 
@@ -608,7 +617,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_BSENT
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_NODCH:
 
@@ -619,7 +628,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_NODCH
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_ADDCH: (currently unused)
 
@@ -633,7 +642,7 @@
       driver      = driver-Id
       command     = ISDN_STAT_ADDCH
       arg         = to be defined.
-      num         = to be defined.
+      para        = to be defined.
 
   ISDN_STAT_CAUSE:
 
@@ -646,5 +655,5 @@
       driver      = driver-Id
       command     = ISDN_STAT_NODCH
       arg         = channel-number, locally to the driver. (starting with 0)
-      num         = ASCII string containing CAUSE-message.
+      para.num    = ASCII string containing CAUSE-message.
 
diff -urN linux-2.0.31-pre2/Documentation/isdn/README linux-2.0.31-pre3/Documentation/isdn/README
--- linux-2.0.31-pre2/Documentation/isdn/README	1996-06-07 06:02:39.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/README	2003-08-15 15:03:53.000000000 -0700
@@ -27,7 +27,14 @@
    subscribe isdn4linux <your_email_address>
 
    To write to the mailing-list, write to isdn4linux@hub-wue.franken.de
+
+   This mailinglist is bidirectionally gated to the newsgroup
+
+     de.alt.comm.isdn4linux
    
+  There is also a well maintained FAQ (both english and german) available
+  at ftp.franken.de in /pub/isdn4linux/FAQ/
+  This FAQ is also available at http://www.lrz-muenchen.de/~ui161ab/www/isdn/
 
   1.1 Technical details
 
@@ -53,7 +60,7 @@
   A raw-control-device with the following functions:
      write: raw D-channel-messages (format: depends on driver).
      read:  raw D-channel-messages (format: depends on driver).
-     ioctl: depends on driver, for the ICN-driver, the base-address of
+     ioctl: depends on driver, i.e. for the ICN-driver, the base-address of
             the ports and the shared memory on the card can be set and read
             also the boot-code an the protocol software can be loaded into 
             the card.
@@ -89,6 +96,7 @@
 	       ATI      Return "ISDN for Linux...".
                ATI0        "
                ATI1        "
+			   ATI2 Report of last connection.
                ATO      On line (data mode).
                ATQ0     Enable result codes (default).
                ATQ1     Disable result codes (default).
@@ -99,7 +107,7 @@
 	       ATZ      Load registers and EAZ/MSN from Profile.
 	       AT&Bx    Set Send-Packet-size to x (max. 4000)
                         The real packet-size may be limited by the
-                        low-level-driver used. i.e.: the Teles-Module-
+                        low-level-driver used. i.e.: the HiSax-Module-
                         limit is 2000. You will get NO Error-Message,
                         if you set it to higher Values, because at the
                         time of giving this command the corresponding
@@ -112,8 +120,7 @@
                AT&D3    Same as AT&D2 but also resets all registers.
 	       AT&Ex    Set the EAZ/MSN for this channel to x.
 	       AT&F     Reset all registers and profile to "factory-defaults"
-	       AT&Sx    Set window-size for Teles-driver (x = 1..8) (not yet
-                        implemented)
+	       AT&Sx    Set window-size (x = 1..8) (not yet implemented)
 	       AT&V     Show all settings.
                AT&W0    Write registers and EAZ/MSN to profile. See also
                         iprofd (5.c in this README).
@@ -173,6 +180,10 @@
                                       1 = T.70 protocol (Only for BTX!) on
                             Bit 2:    0 = Don't hangup on DTR low.
                                       1 = Hangup on DTR low.
+			    Bit 3:    0 = Standard response messages
+				      1 = Extended response messages
+                            Bit 4:    0 = CALLER NUMBER before every RING.
+                                      1 = CALLER NUMBER after first RING.
 	     14   0         Layer-2 protocol:
 				      0 = X75/LAPB with I-frames
 				      1 = X75/LAPB with UI-frames
@@ -182,7 +193,7 @@
              15   0         Layer-3 protocol: (at the moment always 0)
                                       0 = transparent
 	     16   250       Send-Packet-size/16
-             17   8         Window-size for Teles-driver (not yet implemented)
+             17   8         Window-size (not yet implemented)
              18   4         Bit coded register, Service-Octet-1 to accept,
                             or to be used on dialout:
                             Bit 0:    Service 1 (audio) when set.
@@ -201,6 +212,14 @@
              20   0         Bit coded register (readonly)
                             Service-Octet-1 of last call.
                             Bit mapping is the same like register 18
+             21   0         Bit coded register (readonly)
+                            Set on incoming call (during RING) to
+                            octet 3 of calling party number IE (Numbering plan)
+                            See section 4.5.10 of ITU Q.931
+             22   0         Bit coded register (readonly)
+                            Set on incoming call (during RING) to
+                            octet 3a of calling party number IE (Screening info)
+                            See section 4.5.10 of ITU Q.931
 
   Last but not least a (at the moment fairly primitive) device to request
   the line-status (/dev/isdninfo) is made available.
@@ -243,124 +262,16 @@
 
 2 System prerequisites:
 
-  ATTENTION! The program "insmod" from the Package "modules-1.2.8" (It's
-             on nearly all newer distributions) has a bug, which makes
-             it impossible to set both driver-Id's when loading the
-             icn-module for the Double-ICN-Card. A patch is supplied
-             in the utility-package called "insmod-1.2.8.patch". Change into
-             the source-directory of insmod, and type
-             "patch < insmod-1.2.8.patch". Then recompile it. This will fix
-             the bug.
-             This bug does NOT occur when using insmod with the Teles-driver
-             or a single ICN-card.
+  ATTENTION!
+
+  Always use the latest module utilities. The current version is
+  named in Documentation/Changes. Some old versions of insmod
+  are not capable of setting the driver-Ids correctly.
  
 3. Lowlevel-driver configuration.
 
-   Configuration depends on how the drivers are built.
-
-   3.1 Drivers built into the kernel.
-
-     3.1.1 Teles driver.
-
-       The Teles driver can be configured using the commandline-feature
-       while loading the kernel with LILO or LOADLIN. It accepts the
-       following syntax:
-
-       teles=p0,i0,m0,d0[,p1,i1,m1,d1 ... ,pn,in,mn,dn][,idstring]
-
-       where
-
-         p0 = portbase of 1st card.                           (default: 0xd80)
-         i0 = irq of 1st card.                                (default: 15)
-         m0 = shared memory of 1st card.                      (default: 0xd0000)
-         d0 = D-channel protocol of 1st card. 1=1TR6, 2=EDSS1 (default: 2)
-
-         p1,i1,m1,d1 = Parameters of second card (defaults: none)
-         pn,in,mn,d1 = Parameters of n'th card (up to 16 cards are supported)
-
-         idstring = Driver-Id for accessing with utilities and identification
-                    when using a Line-monitor. (default: none)
-                    idstring must start with a character!
-
-         The type of the card is determined by the port, irq and shared memory:
-
-           port == 0, shared memory != 0          -> Teles S0-8
-           port != 0, shared memory != 0          -> Teles S0-16.0
-           port != 0, shared memory == 0          -> Teles S0-16.3
-
-       ATTENTION:
-
-       Due to limited hardware-capabilities, there is no way to check the
-       existence of a card. Therefore you need to be sure your card's setup
-       is correct. Also there are bugs in the printed manual of some newer
-       16.3 cards. Have a look to the kernel-syslog. With most of the cards,
-       you should see a line "HSCX version A:5 B:5" there.
-       
-     3.1.2 ICN driver.
-
-       The ICN driver can be configured using the commandline-feature while
-       loading the kernel with LILO or LOADLIN. It accepts the following
-       syntax
-
-       icn=p,m[,idstring1[,idstring2]]
-
-       where
-
-         p = portbase      (default: 0x320)
-         m = shared memory (default: 0xd0000)
-
-       When using the ICN double card, you MUST define TWO idstrings.
-       idstring must start with a character!
-
-       If you like to use more than one card, you can use the program
-       "icnctrl" from the utility-package to configure additional cards.
-       You need to configure shared memory only once, since the icn-driver
-       maps all cards into the same address-space.
-
-       Using the "icnctrl"-utility, portbase and shared memory can also be
-       changed during runtime.
-
-       The D-channel protocol is configured by loading different firmware
-       into the card's memory using the "icnctrl"-utility.
-
-
-   3.2 Drivers built as modules.
-
-     3.2.1 Teles driver.
-
-       The module teles.o can be configured during "insmod'ing" it by
-       appending its parameters to the insmod-commandline. The following
-       syntax is accepted:
-
-       io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring
-
-       where
-
-         m0,i0,p0,d0 ... mn,in,pn,dn have the same meanings like the
-                                     parameters described for the kernel-
-                                     version above. Watch out: different
-                                     sequence!
-
-     3.2.2 ICN driver.
-
-       The module icn.o can be configured during "insmod'ing" it by
-       appending its parameters to the insmod-commandline. The following
-       syntax is accepted:
-
-       portbase=p membase=m icn_id=idstring icn_id2=idstring2
-
-       where p, m, idstring1 and idstring2 have the same meanings like
-                                           parameters described for the kernel-
-                                           version above.
-      
-       When using the ICN double card, you MUST define TWO idstrings.
-       idstring must start with a character!
-
-       Using the "icnctrl"-utility, the same features apply to the modularized
-       version like to the kernel-builtin one.
-
-       The D-channel protocol is configured by loading different firmware
-       into the card's memory using the "icnctrl"-utility.
+   Configuration depends on how the drivers are built. See the
+   README.<yourDriver> for information on driver-specific setup.
 
 4. Device-inodes
 
@@ -371,26 +282,11 @@
      44 for the ISDN-callout-tty's.
      45 for control/info/debug devices.
 
-
 5. Application
 
-   a) (Only for ICN-cards) Load the firmware into the card:
-
-       cd icn
-     For 1TR6:
-       icnctrl [-d IDstring] load download/loadpg.bin download/pc_1t_ca.bin
-     For Euro-ISDN:
-       icnctrl [-d IDstring] load download/loadpg.bin download/pc_eu_ca.bin
-
-     When using the ICN-4B, the protocol-software for the second half of
-     the card must be appended to the command line.
-
-     -> The two LEDs at the back cover of the card (ICN-4B: 4 LEDs) must be
-        blinking intermittently now. If a connection is up, the corresponding
-        led is lit continuously.
-
-     For loading pcbit-firmware, refer to Documentation/isdn/README.pcbit
-     and the pcbit manpage, included in the utility-package.
+   a) For some card-types, firmware has to be loaded into the cards, before
+      proceeding with device-independant setup. See README.<yourDriver>
+      for how to do that.
 
    b) If you only intend to use ttys, you are nearly ready now.
 
@@ -422,8 +318,7 @@
 
    h) additionally you may activate charge-hang-up (= Hang up before 
       next charge-info, this only works, if your isdn-provider transmits
-      the charge-info during and after the connection, it does NOT work
-      with the Teles on an EDSS1-Line.):
+      the charge-info during and after the connection):
        isdnctrl chargehup isdn0 on
 
    i) Setup the interface with ifconfig as usual, and set a route to it.
@@ -527,7 +422,7 @@
 
    "isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>" 
    Selects a layer-2-protocol. 
-   (With the ICN-driver and the Teles-driver, "x75i" and "hdlc" is available.
+   (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
    With other drivers, "x75ui", "x75bui" may be possible too.)
 
    isdnctrl l3_prot <InterfaceName> <L3-ProtocolName> 
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.audio linux-2.0.31-pre3/Documentation/isdn/README.audio
--- linux-2.0.31-pre2/Documentation/isdn/README.audio	1996-06-07 06:02:39.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/README.audio	2003-08-15 15:03:53.000000000 -0700
@@ -1,4 +1,4 @@
-$Id: README.audio,v 1.3 1996/06/05 02:19:36 fritz Exp $
+$Id: README.audio,v 1.5 1997/02/23 23:53:46 fritz Exp $
 
 ISDN subsystem for Linux.
   Description of audio mode.
@@ -12,7 +12,7 @@
 
         AT+FCLASS=8      Enable audio mode.
                          This affects the following registers:
-                           S18: Bits 0 and 3 are set.
+                           S18: Bits 0 and 2 are set.
                            S16: Set to 48 and any further change to
                                 larger values is blocked.
         AT+FCLASS=0      Disable audio mode.
@@ -86,8 +86,11 @@
     starts sending audio data to the application. There are several
     escape sequences defined, all using DLE (0x10) as Escape char:
 
-    <DLE><ETX>              End of audio data. Emulator stops
+    <DLE><ETX>              End of audio data. (i.e. caused by a
+                            hangup of the remote side) Emulator stops
                             recording, responding with VCON.
+	<DLE><DC4>				Abort recording, (send by appl.) Emulator
+							stops recording, sends DLE,ETX.
     <DLE><DLE>              Escape sequence for DLE in data stream.
     <DLE>0                  Touchtone "0" received.
          ...
@@ -107,13 +110,16 @@
     <DLE>s                  silence. Silence detected from the
                             start of recording.
 
-    Any character sent by the application, except XON (0x11) or XOFF (0x13)
-    immediately stops recording.
-
   Audio playback.
 
     When sending audio data, upon AT+VTX command, emulator responds with
     CONNECT, and starts transferring data from application to the phone line.
     The same DLE sequences apply to this mode.
 
+  Full-Duplex-Audio:
+
+    When _both_ commands for recording and playback are given in _one_
+    AT-command-line (i.e.: "AT+VTX+VRX"), full-duplex-mode is selected.
+	In this mode, the only way to stop recording is sending <DLE><DC4>
+    and the only way to stop playback is to send <DLE><ETX>.
 
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.avmb1 linux-2.0.31-pre3/Documentation/isdn/README.avmb1
--- linux-2.0.31-pre2/Documentation/isdn/README.avmb1	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/Documentation/isdn/README.avmb1	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,62 @@
+The driver provides a kernel capi2.0 Interface (kernelcapi) and
+on top of this a User-Level-CAPI2.0-interface (capi)
+and a driver to connect isdn4linux with CAPI2.0 (capidrv).
+
+The Author can be reached at calle@calle.in-berlin.de
+The command avmcapictrl is part of the isdn4linux-utils.
+t4-files can be found at ftp.avm.de.
+
+Installing
+----------
+
+You need at least /dev/capi20 to load the firmware.
+
+mknod /dev/capi20 c 68 0
+mknod /dev/capi20.00 c 68 1
+mknod /dev/capi20.01 c 68 2
+.
+.
+.
+mknod /dev/capi20.19 c 68 20
+
+Running
+-------
+
+To use the card you need the t4-files to download the firmware.
+AVM GmbH provides several t4-files for the different D-channel
+protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn.
+
+If you not compile the driver as modules, you have to add the
+card(s) and load them after booting:
+
+avmcapictrl add 0x150 15
+avmcapictrl load /lib/isdn/b1.t4 1
+
+if you configure as modules you have two possibilities:
+
+insmod /lib/modules/current/misc/capiutil.o
+insmod /lib/modules/current/misc/kernelcapi.o portbase=0x150 irq=15
+insmod /lib/modules/current/misc/capidrv.o
+insmod /lib/modules/current/misc/capi.o
+avmcapictrl load /lib/isdn/b1.t4
+
+or
+
+insmod /lib/modules/current/misc/capiutil.o
+insmod /lib/modules/current/misc/kernelcapi.o
+insmod /lib/modules/current/misc/capidrv.o
+insmod /lib/modules/current/misc/capi.o
+avmcapictrl add 0x150 15
+avmcapictrl load /lib/isdn/b1.t4
+
+Questions
+---------
+Check out the FAQ (ftp.franken.de).
+
+Bugs 
+----
+If you find any please let me know. 
+
+Enjoy,
+
+Carsten Paeth (calle@calle.in-berlin.de)
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.HiSax linux-2.0.31-pre3/Documentation/isdn/README.HiSax
--- linux-2.0.31-pre2/Documentation/isdn/README.HiSax	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/Documentation/isdn/README.HiSax	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,323 @@
+HiSax is a Linux hardware-level driver for passive ISDN cards with Siemens
+chipset (ISAC_S 2085/2086/2186, HSCX SAB 82525). It is based on the Teles
+driver from Jan den Ouden.
+It is meant to be used with isdn4linux, an ISDN link-level module for Linux 
+written by Fritz Elfert.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+Supported cards
+---------------
+
+Teles 8.0/16.0/16.3 and compatible ones
+Teles S0/PCMCIA
+Creatix PnP S0 
+AVM A1 (Fritz)
+ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8
+ELSA Quickstep 1000
+ELSA PCMCIA
+ITK ix1-micro Rev.2
+
+Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
+      PCC-8: not tested yet
+      Teles PCMCIA is EXPERIMENTAL
+
+If you know other passive cards with the Siemens chipset, please let me know.
+To use the PNP cards you need the isapnptools.
+You can combine any card, if there is no conflict between the ressources
+(io, mem, irq), with one exception: The ELSA PCMCIA cannot work with an other
+non PCMCIA ELSA card at the same time. You cannot select ELSA ISA and ELSA
+PCMCIA support at the same time during kernel config.
+
+
+Configuring the driver
+----------------------
+
+The HiSax driver can either be built directly into the kernel or as a module.
+It can be configured using the command line feature while loading the kernel
+with LILO or LOADLIN or, if built as a module, using insmod/modprobe with
+parameters.
+There is also some config needed before you compile the kernel and/or
+modules. It is enclose in the normal "make [menu]config" target at the
+kernel. Don't forget it, especially to select the right D-channel protocol.
+
+Please note: All PnP cards need to be configured with isapnp and will work
+only with the HiSax driver used as a module.
+
+a) when built as a module
+-------------------------
+
+insmod/modprobe  hisax.o \
+  io=iobase irq=IRQ mem=membase type=card_type \
+  protocol=D_channel_protocol id=idstring
+
+or, if several cards are installed:
+
+insmod/modprobe hisax.o \
+  io=iobase1,iobase2,... irq=IRQ1,IRQ2,... mem=membase1,membase2,... \
+  type=card_type1,card_type2,... \
+  protocol=D_channel_protocol1,D_channel_protocol2,... \
+  id=idstring1%idstring2 ...
+
+where "iobaseN" represents the I/O base address of the Nth card, "membaseN"
+the memory base address of the Nth card, etc.
+
+The reason for the delimiter "%" being used in the idstrings is that ","
+won't work with the current modules package.
+
+The parameters may be specified in any order. For example, the "io"
+parameter may precede the "irq" parameter, or vice versa. If several
+cards are installed, the ordering within the comma separated parameter
+lists must of course be consistent.
+
+Only parameters applicable to the card type need to be specified. For
+example, the Teles 16.3 card is not memory-mapped, so the "mem"
+parameter may be omitted for this card. Sometimes it may be necessary
+to specify a dummy parameter, however. This is the case when there is
+a card of a different type later in the list that needs a parameter
+which the preceding card does not. For instance, if a Teles 16.0 card
+is listed after a Teles 16.3 card, a dummy memory base parameter of 0
+must be specified for the 16.3. Instead of a dummy value, the parameter
+can also be skipped by simply omitting the value. For example:
+mem=,0xd0000. See example 6 below.
+
+The parameter for the D-Channel protocol may be omitted if you selected the
+correct one during kernel config. Valid values are "1" for German 1TR6,
+"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel).
+
+The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying 
+the I/O addresses of the ISAC and HSCX chips, respectively.
+
+Card types:
+
+    Type                Required parameters (in addition to type and protocol)
+
+    1   Teles 16.0               irq, mem, io
+    2   Teles  8.0               irq, mem
+    3   Teles 16.3 (non PnP)     irq, io
+    4   Creatix/Teles PnP        irq, io0 (ISAC), io1 (HSCX)
+    5   AVM A1 (Fritz)           irq, io
+    6   ELSA PCC/PCF cards       io or nothing for autodetect (the iobase is
+                                 required only if you have more than one ELSA
+                                 card in your PC)
+    7   ELSA Quickstep 1000	 irq, io  (from isapnp setup)
+    7   ELSA PCMCIA		 irq, io  (set with card manager)
+    8   Teles 16.3 PCMCIA     	 irq, io
+    9   ITK ix1-micro Rev.2      irq, io
+        
+At the moment IRQ sharing is not possible. Please make sure that your IRQ
+is free and enabled for ISA use.
+Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for
+enabling in the moment, then boot linux with loadlin.
+
+
+Examples for module loading
+
+1. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 10
+   modprobe hisax type=3 protocol=2 io=0x280 irq=10
+
+2. Teles 16.0, 1TR6 ISDN, I/O base d80 hex, IRQ 5, Memory d0000 hex
+   modprobe hisax protocol=1 type=1 io=0xd80 mem=0xd0000 irq=5
+
+3. Fritzcard, Euro ISDN, I/O base 340 hex, IRQ 10 and ELSA PCF, Euro ISDN
+   modprobe hisax type=5,6 protocol=2,2 io=0x340 irq=10 id=Fritz%Elsa
+
+4. Any ELSA PCC/PCF card, Euro ISDN
+   modprobe hisax type=6 protocol=2
+
+5. Teles 16.3 PnP, Euro ISDN, with isapnp configured 
+   isapnp config:  (INT 0 (IRQ 10 (MODE +E)))
+ 		   (IO 0 (BASE 0x0580))
+                   (IO 1 (BASE 0x0180))
+   modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
+
+6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
+   Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
+   modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
+
+   Please note the dummy 0 memory address for the Teles 16.3, used as a
+   placeholder as described above, in the last example.
+
+7. Teles PCMCIA, Euro ISDN, I/O base 180 hex, IRQ 15 (default values)
+   modprobe hisax type=8 protocol=2 io=0x180 irq=15
+
+
+b) using LILO/LOADLIN, with the driver compiled directly into the kernel
+------------------------------------------------------------------------
+
+hisax=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... \
+      typn,dpn,pa_n,pb_n,pc_n][,idstring1[,idstring2,...,idstringn]]
+
+where
+     typ1 = type of 1st card (default depends on kernel settings)
+     dp1  = D-Channel protocol of 1st card. 1=1TR6, 2=EDSS1, 3=leased
+     pa_1 = 1st parameter (depending on the type of the card)
+     pb_1 = 2nd parameter (    "     "   "   "   "   "   "  )
+     pc_1 = 3rd parameter (    "     "   "   "   "   "   "  )
+
+     typ2,dp2,pa_2,pb_2,pc_2 = Parameters of the second card (defaults: none)
+     typn,dpn,pa_n,pb_n,pc_n = Parameters of the n'th card (up to 16 cards are
+                                                                     supported)
+
+     idstring = Driver ID for accessing the particular card with utility
+                programs and for identification when using a line monitor
+                (default: "HiSax")
+
+                Note: the ID string must start with an alphabetical character!
+
+Card types:
+       
+  type  
+    1 	Teles 16.0     		pa=irq	pb=membase	pc=iobase
+    2 	Teles  8.0      	pa=irq	pb=membase
+    3 	Teles 16.3      	pa=irq	pb=iobase
+    4 	Creatix/Teles PNP     	ONLY WORKS AS A MODULE !
+    5 	AVM A1 (Fritz)  	pa=irq	pb=iobase
+    6 	ELSA PCC/PCF cards      pa=iobase or nothing for autodetect
+    7   ELSA Quickstep 1000	ONLY WORKS AS A MODULE !
+    7   ELSA PCMCIA		irq, io  (set with card manager)
+    8   Teles S0 PCMCIA    	pa=irq  pb=iobase
+    9   ITK ix1-micro Rev.2     pa=irq  pb=iobase
+
+
+Running the driver
+------------------
+
+When you insmod isdn.o and hisax.o (or with the in-kernel version, during 
+boot time), a few lines should appear in your syslog. Look for something like:
+
+Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards
+Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.1
+Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8
+Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined
+Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0)
+Apr 13 21:01:59 kke01 kernel: HiSax: Elsa driver Rev. 1.13
+...
+Apr 13 21:01:59 kke01 kernel: Elsa: PCF-Pro found at 0x360 Rev.:C IRQ 10
+Apr 13 21:01:59 kke01 kernel: Elsa: timer OK; resetting card
+Apr 13 21:01:59 kke01 kernel: Elsa: HSCX version A: V2.1  B: V2.1
+Apr 13 21:01:59 kke01 kernel: Elsa: ISAC 2086/2186 V1.1
+...
+Apr 13 21:01:59 kke01 kernel: HiSax: DSS1 Rev. 1.14
+Apr 13 21:01:59 kke01 kernel: HiSax: 2 channels added
+
+This means that the card is ready for use.
+Cabling problems or line-downs are not detected, and only ELSA cards can detect
+the S0 power.
+
+Remember that, according to the new strategy for accessing low-level drivers
+from within isdn4linux, you should also define a driver ID while doing
+insmod: Simply append hisax_id=<SomeString> to the insmod command line. This
+string MUST NOT start with a digit or a small 'x'!
+
+At this point you can run a 'cat /dev/isdnctrl0' and view debugging 
+messages. 
+
+At the moment, debugging messages are enabled with the telesctrl tool:
+
+    telesctrl <DriverId> DebugCmd <debugging_flags>
+
+<DriverId> default is HiSax, if you didn't specified one.
+
+DebugCmd is  1  for generic debugging
+            11  for layer 1 development debugging
+            13  for layer 3 development debugging
+
+where <debugging_flags> is the integer sum of the following debugging
+options you wish enabled:
+
+With DebugCmd set to 1:
+
+         1  Link-level <--> hardware-level communication
+         2  Top state machine
+         4  D-Channel Q.931 (call control messages)
+         8  D-Channel Q.921
+        16  B-Channel X.75
+        32  D-Channel l2
+        64  B-Channel l2
+       128  D-Channel link state debugging
+       256  B-Channel link state debugging
+       512  TEI debug
+      1024  LOCK debug in callc.c
+      2048  More paranoid debug in callc.c (not for normal use)
+
+With DebugCmd set to 11:
+
+         1  Warnings (default: on)
+         2  IRQ status
+         4  ISAC
+         8  ISAC FIFO
+        16  HSCX
+        32  HSCX FIFO (attention: full B-Channel output!)
+        64  D-Channel LAPD frame types
+
+With DebugCmd set to 13:
+
+         1  Warnings (default: on)
+         2  l3 protocol discriptor errors
+         4  l3 state machine
+         8  charge info debugging (1TR6)
+
+For example, 'telesctrl HiSax 1 0x3ff' enables full generic debugging.
+
+
+Warning
+-------
+HiSax is a work in progress and may crash your machine. It has not been
+certified and therefore operation on your PTT's ISDN network is probably
+illegal.
+
+
+Limitations
+-----------
+At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines.
+
+
+Bugs 
+----
+If you find any, please let me know. 
+
+
+Thanks
+------
+Special thanks to:
+
+        Emil Stephan for the name HiSax which is a mix of HSCX and ISAC.
+
+        Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein,
+        Andreas Kool, Pekka Sarnila, Sim Yskes, Johan Myrre'en,
+	Klaus-Peter Nischke (ITK AG), Christof Petig, Werner Fehn (ELSA GmbH),
+	Volker Schmidt
+        and more people who are hunting bugs. (If I forgot somebody, please
+	send me a mail). 
+
+        Firma ELSA GmbH
+        
+        My girl friend and partner in life Ute for her patience with me.
+
+
+Enjoy,
+
+Karsten Keil   
+keil@temic-ech.spacenet.de
+
+
+Appendix: Teles PCMCIA driver
+-----------------------------
+
+See 
+   http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
+for instructions.
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.icn linux-2.0.31-pre3/Documentation/isdn/README.icn
--- linux-2.0.31-pre2/Documentation/isdn/README.icn	1996-06-07 06:02:39.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/README.icn	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-$Id: README.icn,v 1.4 1996/06/03 19:57:07 fritz Exp $
+$Id: README.icn,v 1.5 1997/04/23 18:55:55 fritz Exp $
 
 You can get the ICN-ISDN-card from:
 
 Thinking Objects Software GmbH
-Obere Heerbergstr. 17
+Versbacher Röthe 159
 97078 Würzburg
 Tel: +49 931 2877950
 Fax: +49 931 2877951
@@ -62,3 +62,87 @@
       1  1  1  0  0x368
       1  1  1  1  NOT ALLOWED!
 
+The ICN driver either may be build into kernel or as a module. Initialization
+depends on how the drive is built:
+
+Driver built into the kernel:
+
+  The ICN driver can be configured using the commandline-feature while
+  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
+
+  icn=p,m[,idstring1[,idstring2]]
+
+  where
+
+    p = portbase      (default: 0x320)
+    m = shared memory (default: 0xd0000)
+
+  When using the ICN double card (4B), you MUST define TWO idstrings.
+  idstring must start with a character! There is no way for the driver
+  to distinguish between a 2B and 4B type card. Therefore, by supplying
+  TWO idstrings, you tell the driver that you have a 4B installed.
+  
+  If you like to use more than one card, you can use the program
+  "icnctrl" from the utility-package to configure additional cards.
+  You need to configure shared memory only once, since the icn-driver
+  maps all cards into the same address-space.
+
+  Using the "icnctrl"-utility, portbase and shared memory can also be
+  changed during runtime.
+
+  The D-channel protocol is configured by loading different firmware
+  into the card's memory using the "icnctrl"-utility.
+
+
+Driver built as module:
+
+  The module icn.o can be configured during "insmod'ing" it by
+  appending its parameters to the insmod-commandline. The following
+  syntax is accepted:
+
+    portbase=p membase=m icn_id=idstring [icn_id2=idstring2]
+
+  where p, m, idstring1 and idstring2 have the same meanings like
+  parameters described for the kernel-version above.
+      
+  When using the ICN double card (4B), you MUST define TWO idstrings.
+  idstring must start with a character! There is no way for the driver
+  to distinguish between a 2B and 4B type card. Therefore, by supplying
+  TWO idstrings, you tell the driver that you have a 4B installed.
+  
+  Using the "icnctrl"-utility, the same features apply to the modularized
+  version like to the kernel-builtin one.
+
+  The D-channel protocol is configured by loading different firmware
+  into the card's memory using the "icnctrl"-utility.
+
+Loading the firmware into the card:
+
+  The firmware is supplied together with the isdn4k-utils package. It
+  can be found in the subdirectory icnctrl/firmware/
+
+  There are 3 files:
+
+    loadpg.bin   - Image of the bootstrap loader.
+    pc_1t_ca.bin - Image of firmware for german 1TR6 protocol.
+    pc_eu_ca.bin - Image if firmware for EDSS1 (Euro-ISDN) protocol.
+
+  Assumed you have installed the utility-package correctly, the firmware
+  will be downloaded into the 2B-card using the following command:
+
+    icnctrl -d Idstring load /etc/isdn/loadpg.bin /etc/isdn/pc_XX_ca.bin
+
+  where XX is either "1t" or "eu", depending of the D-Channel protocol
+  used on your S0-bus and Idstring is the Name of the card, given during
+  insmod-time or (for kernel-builtin driver) on the kernel commandline.
+
+  To load a 4B-card, the same command is used, except a second firmware
+  file is appended to the commandline of icnctrl.
+
+  -> After dowloading firmware, the two LEDs at the back cover of the card
+     (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection
+     is up, the corresponding led is lit continuously.
+
+  For further documentation (adding more ICN-cards), refer to the manpage
+  icnctrl.8 which is included in the isdn4k-utils package.
+
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.sc linux-2.0.31-pre3/Documentation/isdn/README.sc
--- linux-2.0.31-pre2/Documentation/isdn/README.sc	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/Documentation/isdn/README.sc	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,274 @@
+Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's
+ISA ISDN adapters. Please note this release 2 includes support for the
+DataCommute/BRI and TeleCommute/BRI adapters only and any other use is 
+guaranteed to fail. If you have a DataCommute/PRI installed in the test
+computer, we recommend removing it as it will be detected but will not
+be usable.  To see what we have done to Beta Release 2, see section 3.
+
+Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains
+bugs and defects either known or unknown. Use this software at your own
+risk. There is NO SUPPORT for this software. Some help may be available
+through the web site or the mailing list but such support is totally at
+our own option and without warrantee. If you choose to assume all and
+total risk by using this driver, we encourage you to join the beta
+mailing list.
+
+To join the Linux beta mailing list, send a message to:
+majordomo@spellcast.com with the words "subscribe linux-beta" as the only
+contents of the message. Do not include a signature. If you choose to
+remove yourself from this list at a later date, send another message to
+the same address with the words "unsubscribe linux-beta" as it's only
+contents.
+
+TABLE OF CONTENTS
+-----------------
+	1. Introduction
+	 1.1 What is ISDN4Linux?
+	 1.2 What is different between this driver and previous drivers?
+	 1.3 How do I setup my system with the correct software to use
+	     this driver release?
+	
+	2. Basic Operations
+	 2.1 Unpacking and installing the driver
+	 2.2 Read the man pages!!!
+	 2.3 Installing the driver
+	 2.4 Removing the driver
+	 2.5 What to do if it doesn't load
+	 2.6 How to setup ISDN4Linux with the driver
+
+	3. Beta Change Summaries and Miscellaneous Notes
+
+1. Introduction
+---------------
+
+The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built
+upon ISDN4Linux available seperately or as included in Linux 2.0 and later.
+The driver will support a maximum of 4 adapters in any one system of any
+type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a
+maximum of 92 channels for host. The driver is supplied as a module in
+source form and needs to be complied before it can be used. It has been
+tested on Linux 2.0.20.
+
+1.1 What Is ISDN4Linux
+
+ISDN4Linux is a driver and set of tools used to access and use ISDN devices
+on a Linux platform in a common and standard way. It supports HDLC and PPP
+protocols and offers channel bundling and MLPPP support. To use ISDN4Linux
+you need to configure your kernel for ISDN support and get the ISDN4Linux
+tool kit from our web site.
+
+ISDN4Linux creates a channel pool from all of the available ISDN channels
+and therefore can function across adapters. When an ISDN4Linux compliant
+driver (such as ours) is loaded, all of the channels go into a pool and
+are used on a first-come first-served basis. In addition, individual
+channels can be specifically bound to particular interfaces.
+
+1.2 What is different between this driver and previous drivers?
+
+The revision 2 driver besides adopting the ISDN4Linux architecture has many
+subtle and not so subtle functional differences from previous releases. These
+include:
+	- More efficient shared memory management combined with a simpler
+	  configuration. All adapters now use only 16Kbytes of shared RAM
+	  versus between 16K and 64K. New methods for using the shared RAM
+	  allow us to utilize all of the available RAM on the adapter through
+	  only one 16K page.
+	- Better detection of available upper memory. The probing routines
+	  have been improved to better detect avaialble shared RAM pages and
+	  used pages are now locked.
+	- Decreased loading time and a wider range of I/O ports probed.
+	  We have significantly reduced the amount of time it takes to load
+	  the driver and at the same time doubled the number of I/O ports
+	  probed increasing the likelyhood of finding an adapter.
+	- We now support all ISA adapter models with a single driver instead
+	  of seperate drivers for each model. The revision 2 driver supports
+	  the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any
+	  combination up to a maximum of four adapters per system.
+	- On board PPP protocol support has been removed in favour of the
+	  sync-PPP support used in ISDN4Linux. This means more control of
+	  the protocol parameters, faster negotiation time and a more
+	  familiar interface.
+
+1.3 How do I setup my system with the correct software to use
+    this driver release?
+
+Before you can compile, install and use the SpellCaster ISA ISDN driver, you
+must ensure that the following software is installed, configuraed and running:
+
+	- Linux kernel 2.0.20 or later with the required init and ps
+	  versions. Please see your distribution vendor for the correct
+	  utility packages. The latest kernel is available from
+	  ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/
+
+	- The latest modules package (modules-2.0.0.tar.gz) from
+	  ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
+
+	- The ISDN4Linux tools available from 
+	  ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz
+	  This package may fail to compile for you so you can alternatively
+	  get a pre-compiled version from
+	  ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz
+
+
+2. Basic Operations
+-------------------
+
+2.1 Unpacking and installing the driver
+
+	1. As root, create a directory in a convienient place. We suggest
+	   /usr/src/spellcaster.
+	
+	2. Unpack the archive with :
+		tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster
+	
+	3. Change directory to /usr/src/spellcaster
+
+	4. Read the README and RELNOTES files.
+
+	5. Run 'make' and if all goes well, run 'make install'.
+
+2.2 Read the man pages!!!
+
+Make sure you read the scctrl(8) and sc(4) manual pages before continuing
+any further. Type 'man 8 scctrl' and 'man 4 sc'.
+
+2.3 Installing the driver
+
+To install the driver, type '/sbin/insmod sc' as root. sc(4) details options
+you can specify but you shouldn't need to use any unless this doesn't work.
+
+Make sure the driver loaded and detected all of the adapters by typing
+'dmesg'.
+
+The driver can be configured so that it is loaded upon startup.  To do this, 
+edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name
+"sc" into this file.
+
+2.4 Removing the driver
+
+To remove the driver, delete any interfaces that may exist (see isdnctrl(8)
+for more on this) and then type '/sbin/rmmod sc'.
+
+2.5 What to do if it doesn't load
+
+If, when you try to install the driver, you get a message mentioning
+'register_isdn' then you do not have the ISDN4Linux system installed. Please
+make sure that ISDN support is configured in the kernel.
+
+If you get a message that says 'initialization of sc failed', then the
+driver failed to detect an adapter or failed to find resources needed such
+as a free IRQ line or shared memory segment. If you are sure there are free
+resources available, use the insmod options detailed in sc(4) to override
+the probing function.  
+
+Upon testing, the following problem was noted, the driver would load without
+problems, but the board would not respond beyond that point.  When a check was 
+done with 'cat /proc/interrupts' the interrupt count for sc was 0.  In the event 
+of this problem, change the BIOS settings so that the interrupts in question are
+reserved for ISA use only.   
+
+
+2.6 How to setup ISDN4Linux with the driver
+
+There are two main configurations which you can use with the driver:
+
+A)	Basic HDLC connection
+B)	PPP connection
+C)	MLPPP connection
+
+It should be mentioned here that you may also use a tty connection if you desire. 
+The Documentation directory of the isdn4linux subsystem offers a good documentation
+on this feature.
+
+A) 10 steps to the establishment of a basic HDLC connection
+-----------------------------------------------------------
+
+- please open the isdn-hdlc file in the examples directory and follow along...
+	
+	This file is a script used to configure a BRI ISDN TA to establish a basic HDLC
+	connection between its two channels.  There two network interfaces which are 
+	created and two routes added between the channels.
+
+	i)   using the isdnctrl utitity, add an interface with "addif" and name it "isdn0"
+	ii)  add the outgoing and inbound telephone numbers
+	iii) set the Layer 2 protocol to hdlc
+	iv)  set the eaz of the interface to be the phone number of that specific channel
+	v)   to turn the callback features off, set the callback to "off" and
+	     the callback delay (cbdelay) to 0.
+	vi)  the hangup timeout can be set to a specified number of seconds
+	vii) the hangup upon incomming call can be set on or off 
+	viii) use the ifconfig command to bring-up the network interface with a specific
+	     IP address and point to point address
+	viv) add a route to the IP address through the isdn0 interface
+	x)   a ping should result in the establishment of the connection
+
+	
+B) Establishment of a PPP connection
+------------------------------------
+
+- please open the isdn-ppp file in the examples directory and follow along...
+	
+	This file is a script used to configure a BRI ISDN TA to establish a PPP connection 
+	between the two channels.  The file is almost identical to the HDLC connection
+	example except that the packet ecapsulation type has to be set.
+	
+	use the same procedure as in the HDLC connection from steps i) to iii) then, 
+	after the Layer 2 protocol is set, set the encapsulation  "encap" to syncppp.
+	With this done, the rest of the steps, iv) to x) can be followed from above.
+
+	Then, the ipppd (ippp daemon) must be setup:
+	
+	xi)   use the ipppd function found in /sbin/ipppd to set the following:
+	xii)  take out (minus) VJ compression and bsd compression
+	xiii) set the mru size to 2000
+	xiv)  link the two /dev interfaces to the daemon
+
+NOTE:  A "*" in the inbound telephone number specifies that a call can be accepted
+       on any number.
+
+C) Establishment of a MLPPP connection
+--------------------------------------
+
+- please open the isdn-mppp file in the examples directory and follow along...
+	
+	This file is a script used to configure a BRI ISDN TA to accept a Multi Link PPP
+	connection. 
+	
+	i)   using the isdnctrl utitity, add an interface with "addif" and name it "ippp0"
+	ii)  add the inbound telephone number
+	iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to trans (transparent)
+	iv)  set the packet encapsulation to syncppp
+	v)   set the eaz of the interface to be the phone number of that specific channel
+	vi)   to turn the callback features off, set the callback to "off" and
+	     the callback delay (cbdelay) to 0.
+	vi)  the hangup timeout can be set to a specified number of seconds
+	vii) the hangup upon incomming call can be set on or off 
+	viii) add a slave interface and name it "ippp32" for example
+	viv)  set the similar parameters for the ippp32 interface
+	x)    use the ifconfig command to bring-up the ippp0 interface with a specific
+	     IP address and point to point address
+	xi)  add a route to the IP address through the ippp0 interface
+	xii) use the ipppd function found in /sbin/ipppd to set the following:
+	xiii) take out (minus) bsd compression
+	xiv) set the mru size to 2000
+	xv)  add (+) the multi-link function "+mp"
+	xv)  link the two /dev interfaces to the daemon
+
+NOTE:  To use the MLPPP connection to dial OUT to a MLPPP connection, change the 
+       inbound telephone numbers to the outgoing telephone numbers of the MLPPP 
+       host.
+
+	
+3. Beta Change Summaries and Miscellaneous Notes
+------------------------------------------------
+When using the "scctrl" utility to upload firmware revisions on the board, please
+note that the byte count displayed at the end of the operation may be different 
+than the total number of bytes in the "dcbfwn.nn.sr" file.  Please disregard the 
+displayed byte count.
+
+It was noted that in Beta Release 1, the module would fail to load and result in a
+segmentation fault when insmod"ed".  This problem was created when one of the 
+isdn4linux parameters, (isdn_ctrl, data field) was filled in.  In some cases, this
+data field was NULL, and was left unchecked, so when it was referenced.. segv.  
+The bug has been fixed around line 63-68 of event.c.
+
diff -urN linux-2.0.31-pre2/Documentation/isdn/README.teles linux-2.0.31-pre3/Documentation/isdn/README.teles
--- linux-2.0.31-pre2/Documentation/isdn/README.teles	1996-06-29 10:36:22.000000000 -0700
+++ linux-2.0.31-pre3/Documentation/isdn/README.teles	1969-12-31 16:00:00.000000000 -0800
@@ -1,73 +0,0 @@
-This is my Linux hardware level driver for Teles compatible ISDN cards. It is 
-meant to be used with isdn4isdn4linux, an ISDN Link-level module for Linux written
-by Fritz Elfert.
-
-Isdn4linux can be obtained from ftp.franken.de:/pub/isdn4linux. The most recent 
-Teles driver can be found on my homepage, http://www.xs4all.nl:/~jdo.
-
-Warning
--------
-Teles4isdn4linux is a work in progress and may crash your machine. It has not 
-been certified and therefore operation on your PTT's ISDN network is probably 
-illegal.
-
-Limitations
------------
-Teles4isdn4linux only works on Euro ISDN lines and german 1TR6-lines.
-
-For the B channel transparent (HDLC) protocol and X.75 have been implemented. 
-
-Running
--------
-When you insmod isdn.o and teles.o (or with the kernel-version, during boottime)
-a few lines should appear in your syslog. Look for something like:
-
-Oct 11 16:53:30 jedi kernel: channels 2
-Oct 11 16:53:31 jedi kernel: Teles module installed
-
-Remember, that according to the new strategy for accessing Low-level-drivers
-from within isdn4linux you should also define a driver-id while doing
-insmod: Simply append teles_id=<SomeString> to the insmod-commandline. This
-string MUST NOT start with a digit or a small 'x'!
-
-At this point you can run a 'cat /dev/isdnctrl0' and view debugging 
-messages. Debugging messages are enabled with the telesctrl tool: 
-
-	teles/telesctrl <DriverId> 1 <debugging_flags>
-
-where <debugging_flags> is the integer sum of the following debugging
-options you wish enabled:
-
-	1   Link-level <--> Hardware-level communication
-	2   Top state machine 
-	4   D channel Q.931 (call control messages)
-	8   D channel Q.921 
-	16  B channel X.75
-	32  Lowlevel (irq and Layer1 stuff)
-
-For example 'teles/telesctrl MyTeles 1 63' enables full 
-debugging.
-
-Questions
----------
-Check out the FAQ (ftp.franken.de).
-
-Bugs 
-----
-If you find any please let me know. 
-
-Thanks
-------
-Special thanks to:
-
-	Erik Bos,Beat Doebeli,Fritz Elfert,	
-	Pauline Middelink,Paula de Nie, 	
-	Bernd Oerding,Stephan Seidl,Matthias Urlichs, 
-	Rogier Wolff
-
-
-
-Enjoy,
-
-Jan den Ouden   denouden@groovin.xs4all.nl
-
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/b1capi.c linux-2.0.31-pre3/drivers/isdn/avmb1/b1capi.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/b1capi.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/b1capi.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,946 @@
+/*
+ * $Id: b1capi.c,v 1.4 1997/05/27 15:17:45 fritz Exp $
+ * 
+ * CAPI 2.0 Module for AVM B1-card.
+ * 
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: b1capi.c,v $
+ * Revision 1.4  1997/05/27 15:17:45  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.3  1997/05/18 09:24:09  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2  1997/03/05 21:20:41  fritz
+ * Removed include of config.h (mkdep stated this is unneded).
+ *
+ * Revision 1.1  1997/03/04 21:50:27  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/tqueue.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+#include <linux/kernelcapi.h>
+#include "compat.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+/* ------------------------------------------------------------- */
+
+int portbase = 0x150;
+int irq = 15;
+int showcapimsgs = 0;		/* used in lli.c */
+int loaddebug = 0;
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+MODULE_PARM(portbase, "i");
+MODULE_PARM(irq, "2-15i");
+MODULE_PARM(showcapimsgs, "0-3i");
+MODULE_PARM(loaddebug, "0-1i");
+#endif
+
+/* ------------------------------------------------------------- */
+
+struct msgidqueue {
+	struct msgidqueue *next;
+	__u16 msgid;
+};
+
+typedef struct avmb1_ncci {
+	struct avmb1_ncci *next;
+	__u16 applid;
+	__u32 ncci;
+	__u32 winsize;
+	struct msgidqueue *msgidqueue;
+	struct msgidqueue *msgidlast;
+	struct msgidqueue *msgidfree;
+	struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
+} avmb1_ncci;
+
+typedef struct avmb1_appl {
+	__u16 applid;
+	capi_register_params rparam;
+	int releasing;
+	__u32 param;
+	void (*signal) (__u16 applid, __u32 param);
+	struct sk_buff_head recv_queue;
+	struct avmb1_ncci *nccilist;
+} avmb1_appl;
+
+/* ------------------------------------------------------------- */
+
+static struct capi_version driver_version = {2, 0, 0, 9};
+static char driver_serial[CAPI_SERIAL_LEN] = "4711";
+static char capi_manufakturer[64] = "AVM Berlin";
+
+#define APPL(a)		   (&applications[(a)-1])
+#define	VALID_APPLID(a)	   ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
+#define APPL_IS_FREE(a)    (APPL(a)->applid == 0)
+#define APPL_MARK_FREE(a)  do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
+#define APPL_MARK_USED(a)  do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+
+#define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
+
+#define VALID_CARD(c)	   ((c) > 0 && (c) <= ncards)
+#define CARD(c)		   (&cards[(c)-1])
+#define CARDNR(cp)	   ((cards-(cp))+1)
+
+static avmb1_appl applications[CAPI_MAXAPPL];
+static avmb1_card cards[CAPI_MAXCONTR];
+static int ncards = 0;
+static struct sk_buff_head recv_queue;
+static struct capi_interface_user *capi_users = 0;
+static long notify_up_set = 0;
+static long notify_down_set = 0;
+
+static struct tq_struct tq_state_notify;
+static struct tq_struct tq_recv_notify;
+
+/* -------- util functions ------------------------------------ */
+
+static inline int capi_cmd_valid(__u8 cmd)
+{
+	switch (cmd) {
+	case CAPI_ALERT:
+	case CAPI_CONNECT:
+	case CAPI_CONNECT_ACTIVE:
+	case CAPI_CONNECT_B3_ACTIVE:
+	case CAPI_CONNECT_B3:
+	case CAPI_CONNECT_B3_T90_ACTIVE:
+	case CAPI_DATA_B3:
+	case CAPI_DISCONNECT_B3:
+	case CAPI_DISCONNECT:
+	case CAPI_FACILITY:
+	case CAPI_INFO:
+	case CAPI_LISTEN:
+	case CAPI_MANUFACTURER:
+	case CAPI_RESET_B3:
+	case CAPI_SELECT_B_PROTOCOL:
+		return 1;
+	}
+	return 0;
+}
+
+static inline int capi_subcmd_valid(__u8 subcmd)
+{
+	switch (subcmd) {
+	case CAPI_REQ:
+	case CAPI_CONF:
+	case CAPI_IND:
+	case CAPI_RESP:
+		return 1;
+	}
+	return 0;
+}
+
+/* -------- NCCI Handling ------------------------------------- */
+
+static inline void mq_init(avmb1_ncci * np)
+{
+	int i;
+	np->msgidqueue = 0;
+	np->msgidlast = 0;
+	memset(np->msgidpool, 0, sizeof(np->msgidpool));
+	np->msgidfree = &np->msgidpool[0];
+	for (i = 1; i < np->winsize; i++) {
+		np->msgidpool[i].next = np->msgidfree;
+		np->msgidfree = &np->msgidpool[i];
+	}
+}
+
+static inline int mq_enqueue(avmb1_ncci * np, __u16 msgid)
+{
+	struct msgidqueue *mq;
+	if ((mq = np->msgidfree) == 0)
+		return 0;
+	np->msgidfree = mq->next;
+	mq->msgid = msgid;
+	mq->next = 0;
+	if (np->msgidlast)
+		np->msgidlast->next = mq;
+	np->msgidlast = mq;
+	if (!np->msgidqueue)
+		np->msgidqueue = mq;
+	return 1;
+}
+
+static inline int mq_dequeue(avmb1_ncci * np, __u16 msgid)
+{
+	struct msgidqueue **pp;
+	for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
+		if ((*pp)->msgid == msgid) {
+			struct msgidqueue *mq = *pp;
+			*pp = mq->next;
+			if (mq == np->msgidlast)
+				np->msgidlast = 0;
+			mq->next = np->msgidfree;
+			np->msgidfree = mq;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void avmb1_handle_new_ncci(avmb1_card * card,
+			   __u16 appl, __u32 ncci, __u32 winsize)
+{
+	avmb1_ncci *np;
+	if (!VALID_APPLID(appl)) {
+		printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
+		return;
+	}
+	if ((np = (avmb1_ncci *) kmalloc(sizeof(avmb1_ncci), GFP_ATOMIC)) == 0) {
+		printk(KERN_ERR "avmb1_handle_new_ncci: alloc failed ncci 0x%x\n", ncci);
+		return;
+	}
+	if (winsize > CAPI_MAXDATAWINDOW) {
+		printk(KERN_ERR "avmb1_handle_new_ncci: winsize %d too big, set to %d\n",
+		       winsize, CAPI_MAXDATAWINDOW);
+		winsize = CAPI_MAXDATAWINDOW;
+	}
+	np->applid = appl;
+	np->ncci = ncci;
+	np->winsize = winsize;
+	mq_init(np);
+	np->next = APPL(appl)->nccilist;
+	APPL(appl)->nccilist = np;
+	printk(KERN_INFO "b1capi: appl %d ncci 0x%x up\n", appl, ncci);
+
+}
+
+void avmb1_handle_free_ncci(avmb1_card * card,
+			    __u16 appl, __u32 ncci)
+{
+	if (!VALID_APPLID(appl)) {
+		printk(KERN_ERR "avmb1_handle_free_ncci: illegal appl %d\n", appl);
+		return;
+	}
+	if (ncci != 0xffffffff) {
+		avmb1_ncci **pp;
+		for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) {
+			if ((*pp)->ncci == ncci) {
+				avmb1_ncci *np = *pp;
+				*pp = np->next;
+				kfree(np);
+				printk(KERN_INFO "b1capi: appl %d ncci 0x%x down\n", appl, ncci);
+				return;
+			}
+		}
+		printk(KERN_ERR "avmb1_handle_free_ncci: ncci 0x%x not found\n", ncci);
+	} else {
+		avmb1_ncci **pp, **nextpp;
+		for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+			if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+				avmb1_ncci *np = *pp;
+				*pp = np->next;
+				printk(KERN_INFO "b1capi: appl %d ncci 0x%x down!\n", appl, np->ncci);
+				kfree(np);
+				nextpp = pp;
+			} else {
+				nextpp = &(*pp)->next;
+			}
+		}
+		APPL(appl)->releasing--;
+		if (APPL(appl)->releasing == 0) {
+	                APPL(appl)->signal = 0;
+			APPL_MARK_FREE(appl);
+			printk(KERN_INFO "b1capi: appl %d down\n", appl);
+		}
+	}
+}
+
+static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci)
+{
+	avmb1_ncci *np;
+	for (np = app->nccilist; np; np = np->next) {
+		if (np->ncci == ncci)
+			return np;
+	}
+	return 0;
+}
+
+/* -------- Receiver ------------------------------------------ */
+
+
+static void recv_handler(void *dummy)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&recv_queue)) != 0) {
+		__u16 appl = CAPIMSG_APPID(skb->data);
+		struct avmb1_ncci *np;
+		if (!VALID_APPLID(appl)) {
+			printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n",
+			       appl, capi_message2str(skb->data));
+			kfree_skb(skb, FREE_READ);
+			continue;
+		}
+		if (APPL(appl)->signal == 0) {
+			printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n",
+			       appl);
+			kfree_skb(skb, FREE_READ);
+			continue;
+		}
+		if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+		    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
+	            && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0
+		    && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
+			printk(KERN_ERR "b1capi: msgid %hu ncci 0x%x not on queue\n",
+				CAPIMSG_MSGID(skb->data), np->ncci);
+		}
+		skb_queue_tail(&APPL(appl)->recv_queue, skb);
+		(APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param);
+	}
+}
+
+
+void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb)
+{
+	if (card->cardstate != CARD_RUNNING) {
+		printk(KERN_INFO "b1capi: controller %d not active, got: %s",
+		       card->cnr, capi_message2str(skb->data));
+		goto error;
+		return;
+	}
+	skb_queue_tail(&recv_queue, skb);
+	queue_task(&tq_recv_notify, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	return;
+
+      error:
+	kfree_skb(skb, FREE_READ);
+}
+
+void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+	avmb1_card *card;
+
+	card = (avmb1_card *) devptr;
+
+	if (!card) {
+		printk(KERN_WARNING "avmb1_interrupt: wrong device\n");
+		return;
+	}
+	if (card->interrupt) {
+		printk(KERN_ERR "avmb1_interrupt: reentering interrupt hander\n");
+		return;
+	}
+
+	card->interrupt = 1;
+
+	B1_handle_interrupt(card);
+
+	card->interrupt = 0;
+}
+
+/* -------- Notifier ------------------------------------------ */
+
+static void notify_up(__u16 contr)
+{
+	struct capi_interface_user *p;
+
+	for (p = capi_users; p; p = p->next) {
+		if (p->callback)
+			(*p->callback) (KCI_CONTRUP, contr,
+				(capi_profile *)
+					CARD(contr)->version[VER_PROFILE]);
+	}
+}
+
+static void notify_down(__u16 contr)
+{
+	struct capi_interface_user *p;
+	for (p = capi_users; p; p = p->next) {
+		if (p->callback)
+			(*p->callback) (KCI_CONTRDOWN, contr, 0);
+	}
+}
+
+static void notify_handler(void *dummy)
+{
+	__u16 contr;
+
+	for (contr=1; VALID_CARD(contr); contr++)
+		 if (test_and_clear_bit(contr, &notify_up_set))
+			 notify_up(contr);
+	for (contr=1; VALID_CARD(contr); contr++)
+		 if (test_and_clear_bit(contr, &notify_down_set))
+			 notify_down(contr);
+}
+
+/* -------- card ready callback ------------------------------- */
+
+void avmb1_card_ready(avmb1_card * card)
+{
+	__u16 appl;
+
+	card->cversion.majorversion = 2;
+	card->cversion.minorversion = 0;
+	card->cversion.majormanuversion = (card->version[VER_DRIVER][0] - '0') << 4;
+	card->cversion.majormanuversion |= (card->version[VER_DRIVER][2] - '0');
+	card->cversion.minormanuversion = (card->version[VER_DRIVER][3] - '0') << 4;
+	card->cversion.minormanuversion |= (card->version[VER_DRIVER][5] - '0') * 10;
+	card->cversion.minormanuversion |= (card->version[VER_DRIVER][6] - '0');
+	card->cardstate = CARD_RUNNING;
+
+
+	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+		if (VALID_APPLID(appl) && !APPL(appl)->releasing) {
+			B1_send_register(card->port, appl,
+				1024 * (APPL(appl)->rparam.level3cnt+1),
+				APPL(appl)->rparam.level3cnt,
+				APPL(appl)->rparam.datablkcnt,
+				APPL(appl)->rparam.datablklen);
+		}
+	}
+
+        set_bit(CARDNR(card), &notify_up_set);
+        queue_task(&tq_state_notify, &tq_scheduler);
+}
+
+/* ------------------------------------------------------------- */
+
+int avmb1_addcard(int port, int irq)
+{
+	struct avmb1_card *card;
+	int irqval;
+
+
+	card = &cards[ncards];
+	memset(card, 0, sizeof(avmb1_card));
+	sprintf(card->name, "avmb1-%d", ncards + 1);
+
+	request_region(port, AVMB1_PORTLEN, card->name);
+
+	if ((irqval = request_irq(irq, avmb1_interrupt, SA_SHIRQ, card->name, card)) != 0) {
+		printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n",
+		       irq, irqval);
+		release_region((unsigned short) port, AVMB1_PORTLEN);
+		return -EIO;
+	}
+	ncards++;
+	card->cnr = ncards;
+	card->port = port;
+	card->irq = irq;
+	card->cardstate = CARD_DETECTED;
+	return 0;
+}
+
+int avmb1_probecard(int port, int irq)
+{
+	int rc;
+
+	if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
+		printk(KERN_WARNING
+		       "b1capi: ports 0x%03x-0x%03x in use.\n",
+		       portbase, portbase + AVMB1_PORTLEN);
+		return -EIO;
+	}
+	if (!B1_valid_irq(irq)) {
+		printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq);
+		return -EIO;
+	}
+	if ((rc = B1_detect(port)) != 0) {
+		printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc);
+		return -EIO;
+	}
+	B1_reset(port);
+	printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", port);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+/* -------- CAPI2.0 Interface ---------------------------------- */
+/* ------------------------------------------------------------- */
+
+static int capi_installed(void)
+{
+	int i;
+	for (i = 0; i < ncards; i++) {
+		if (cards[i].cardstate == CARD_RUNNING)
+			return 1;
+	}
+	return 0;
+}
+
+static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
+{
+	int i;
+	int appl;
+
+	if (rparam->datablklen < 128)
+		return CAPI_LOGBLKSIZETOSMALL;
+
+	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+		if (APPL_IS_FREE(appl))
+			break;
+	}
+	if (appl > CAPI_MAXAPPL)
+		return CAPI_TOOMANYAPPLS;
+
+	APPL_MARK_USED(appl);
+	skb_queue_head_init(&APPL(appl)->recv_queue);
+
+	memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
+
+	for (i = 0; i < ncards; i++) {
+		if (cards[i].cardstate != CARD_RUNNING)
+			continue;
+		B1_send_register(cards[i].port, appl,
+			       1024 * (APPL(appl)->rparam.level3cnt + 1),
+				 APPL(appl)->rparam.level3cnt,
+				 APPL(appl)->rparam.datablkcnt,
+				 APPL(appl)->rparam.datablklen);
+	}
+	*applidp = appl;
+	printk(KERN_INFO "b1capi: appl %d up\n", appl);
+
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_release(__u16 applid)
+{
+	struct sk_buff *skb;
+	int i;
+
+	if (ncards == 0)
+		return CAPI_REGNOTINSTALLED;
+	if (!VALID_APPLID(applid) || APPL(applid)->releasing)
+		return CAPI_ILLAPPNR;
+	while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
+		kfree_skb(skb, FREE_READ);
+	for (i = 0; i < ncards; i++) {
+		if (cards[i].cardstate != CARD_RUNNING)
+			continue;
+		APPL(applid)->releasing++;
+		B1_send_release(cards[i].port, applid);
+	}
+	if (APPL(applid)->releasing == 0) {
+	        APPL(applid)->signal = 0;
+		APPL_MARK_FREE(applid);
+		printk(KERN_INFO "b1capi: appl %d down\n", applid);
+	}
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_put_message(__u16 applid, struct sk_buff *skb)
+{
+	avmb1_ncci *np;
+	int contr;
+	if (ncards == 0)
+		return CAPI_REGNOTINSTALLED;
+	if (!VALID_APPLID(applid))
+		return CAPI_ILLAPPNR;
+	if (skb->len < 12
+	    || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
+	    || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
+		return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+	contr = CAPIMSG_CONTROLLER(skb->data);
+	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) {
+		contr = 1;
+	        if (CARD(contr)->cardstate != CARD_RUNNING) 
+			return CAPI_REGNOTINSTALLED;
+	}
+	if (CARD(contr)->blocked)
+		return CAPI_SENDQUEUEFULL;
+
+	if (   CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+	    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ
+	    && (np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0
+	    && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
+		return CAPI_SENDQUEUEFULL;
+
+	B1_send_message(CARD(contr)->port, skb);
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
+{
+	struct sk_buff *skb;
+
+	if (!VALID_APPLID(applid))
+		return CAPI_ILLAPPNR;
+	if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0)
+		return CAPI_RECEIVEQUEUEEMPTY;
+	*msgp = skb;
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_set_signal(__u16 applid,
+			     void (*signal) (__u16 applid, __u32 param),
+			     __u32 param)
+{
+	if (!VALID_APPLID(applid))
+		return CAPI_ILLAPPNR;
+	APPL(applid)->signal = signal;
+	APPL(applid)->param = param;
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN])
+{
+	if (contr == 0) {
+		strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+		return CAPI_NOERROR;
+	}
+	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+		return 0x2002;
+
+	strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_get_version(__u16 contr, struct capi_version *verp)
+{
+	if (contr == 0) {
+		*verp = driver_version;
+		return CAPI_NOERROR;
+	}
+	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+		return 0x2002;
+
+	memcpy((void *) verp, CARD(contr)->version[VER_SERIAL],
+	       sizeof(capi_version));
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN])
+{
+	if (contr == 0) {
+		strncpy(serial, driver_serial, 8);
+		return CAPI_NOERROR;
+	}
+	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+		return 0x2002;
+
+	memcpy((void *) serial, CARD(contr)->version[VER_SERIAL],
+	       CAPI_SERIAL_LEN);
+	serial[CAPI_SERIAL_LEN - 1] = 0;
+	return CAPI_NOERROR;
+}
+
+static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp)
+{
+	if (contr == 0) {
+		profp->ncontroller = ncards;
+		return CAPI_NOERROR;
+	}
+	if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
+		return 0x2002;
+
+	memcpy((void *) profp, CARD(contr)->version[VER_PROFILE],
+	       sizeof(struct capi_profile));
+	return CAPI_NOERROR;
+}
+
+static int capi_manufacturer(unsigned int cmd, void *data)
+{
+	unsigned long flags;
+	avmb1_loaddef ldef;
+	avmb1_carddef cdef;
+	avmb1_resetdef rdef;
+	avmb1_card *card;
+	int rc;
+
+	switch (cmd) {
+	case AVMB1_ADDCARD:
+		if ((rc = copy_from_user((void *) &cdef, data,
+					 sizeof(avmb1_carddef))))
+			return rc;
+		if (!B1_valid_irq(cdef.irq))
+			return -EINVAL;
+
+		if ((rc = avmb1_probecard(cdef.port, cdef.irq)) != 0)
+			return rc;
+
+		return avmb1_addcard(cdef.port, cdef.irq);
+
+	case AVMB1_LOAD:
+
+		if ((rc = copy_from_user((void *) &ldef, data,
+					 sizeof(avmb1_loaddef))))
+			return rc;
+		if (!VALID_CARD(ldef.contr) || ldef.t4file.len <= 0) {
+			if (loaddebug)
+				printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len);
+			return -EINVAL;
+		}
+
+		card = CARD(ldef.contr);
+		save_flags(flags);
+		cli();
+		if (card->cardstate != CARD_DETECTED) {
+			restore_flags(flags);
+			if (loaddebug)
+				printk(KERN_DEBUG "b1capi: load: contr=%d not in detect state\n", ldef.contr);
+			return -EBUSY;
+		}
+		card->cardstate = CARD_LOADING;
+		restore_flags(flags);
+
+		if (loaddebug) {
+			printk(KERN_DEBUG "b1capi: load: reseting contr %d\n",
+				ldef.contr);
+		}
+
+		B1_reset(card->port);
+		if ((rc = B1_load_t4file(card->port, &ldef.t4file))) {
+			B1_reset(card->port);
+			printk(KERN_ERR "b1capi: failed to load t4file!!\n");
+			card->cardstate = CARD_DETECTED;
+			return rc;
+		}
+		B1_disable_irq(card->port);
+		if (loaddebug) {
+			printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n",
+				ldef.contr);
+		}
+
+		if (!B1_loaded(card->port)) {
+			card->cardstate = CARD_DETECTED;
+			printk(KERN_ERR "b1capi: failed to load t4file.\n");
+			return -EIO;
+		}
+		/*
+		 * enable interrupt
+		 */
+
+		card->cardstate = CARD_INITSTATE;
+		save_flags(flags);
+		cli();
+		B1_assign_irq(card->port, card->irq);
+		B1_enable_irq(card->port);
+		restore_flags(flags);
+
+		if (loaddebug) {
+			printk(KERN_DEBUG "b1capi: load: irq enabled contr %d\n",
+				ldef.contr);
+		}
+
+		/*
+		 * init card
+		 */
+		B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1);
+
+		if (loaddebug) {
+			printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n",
+				ldef.contr);
+		}
+
+		while (card->cardstate != CARD_RUNNING) {
+
+			current->timeout = jiffies + HZ / 10;	/* 0.1 sec */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+
+			if (current->signal & ~current->blocked)
+				return -EINTR;
+		}
+		return 0;
+	case AVMB1_RESETCARD:
+		if ((rc = copy_from_user((void *) &rdef, data,
+					 sizeof(avmb1_resetdef))))
+			return rc;
+
+		if (!VALID_CARD(rdef.contr))
+			return -EINVAL;
+
+		card = CARD(rdef.contr);
+
+		if (card->cardstate == CARD_RUNNING)
+			return -EBUSY;
+
+		B1_reset(card->port);
+		B1_reset(card->port);
+
+		card->cardstate = CARD_DETECTED;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+struct capi_interface avmb1_interface =
+{
+	capi_installed,
+	capi_register,
+	capi_release,
+	capi_put_message,
+	capi_get_message,
+	capi_set_signal,
+	capi_get_manufacturer,
+	capi_get_version,
+	capi_get_serial,
+	capi_get_profile,
+	capi_manufacturer
+};
+
+/* ------------------------------------------------------------- */
+/* -------- Exported Functions --------------------------------- */
+/* ------------------------------------------------------------- */
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
+{
+	struct capi_interface_user *p;
+
+	for (p = capi_users; p; p = p->next) {
+		if (p == userp) {
+			printk(KERN_ERR "b1capi: double attach from %s\n",
+			       userp->name);
+			return 0;
+		}
+	}
+	userp->next = capi_users;
+	capi_users = userp;
+	MOD_INC_USE_COUNT;
+
+	return &avmb1_interface;
+}
+
+int detach_capi_interface(struct capi_interface_user *userp)
+{
+	struct capi_interface_user **pp;
+
+	for (pp = &capi_users; *pp; pp = &(*pp)->next) {
+		if (*pp == userp) {
+			*pp = userp->next;
+			userp->next = 0;
+			MOD_DEC_USE_COUNT;
+			return 0;
+		}
+	}
+	printk(KERN_ERR "b1capi: double detach from %s\n", userp->name);
+	return -1;
+}
+
+/* ------------------------------------------------------------- */
+/* -------- Init & Cleanup ------------------------------------- */
+/* ------------------------------------------------------------- */
+
+#ifdef HAS_NEW_SYMTAB
+EXPORT_SYMBOL(attach_capi_interface);
+EXPORT_SYMBOL(detach_capi_interface);
+EXPORT_SYMBOL(avmb1_addcard);
+EXPORT_SYMBOL(avmb1_probecard);
+#else
+static struct symbol_table capidev_syms =
+{
+#include <linux/symtab_begin.h>
+	X(attach_capi_interface),
+	X(detach_capi_interface),
+	X(avmb1_addcard),
+	X(avmb1_probecard),
+#include <linux/symtab_end.h>
+};
+#endif
+
+
+/*
+ * init / exit functions
+ */
+
+#ifdef MODULE
+#define avmb1_init init_module
+#endif
+
+int avmb1_init(void)
+{
+	char *p;
+	char rev[10];
+
+
+#ifndef HAS_NEW_SYMTAB
+	/* No symbols to export, hide all symbols */
+	register_symtab(&capidev_syms);
+#endif
+	skb_queue_head_init(&recv_queue);
+	/* init_bh(CAPI_BH, do_capi_bh); */
+
+	tq_state_notify.routine = notify_handler;
+	tq_state_notify.data = 0;
+
+	tq_recv_notify.routine = recv_handler;
+	tq_recv_notify.data = 0;
+
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else
+		strcpy(rev, " ??? ");
+
+#ifdef MODULE
+	if (portbase) {
+	        int rc;
+		if ((rc = avmb1_probecard(portbase, irq)) != 0)
+			return rc;
+		if ((rc = avmb1_addcard(portbase, irq)) != 0)
+			return rc;
+	} else {
+		printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev);
+	}
+#else
+	printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: started\n", rev);
+#endif
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	char rev[10];
+	char *p;
+	int i;
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else {
+		strcpy(rev, " ??? ");
+	}
+
+	for (i = 0; i < ncards; i++) {
+		/*
+		 * disable card
+		 */
+		B1_disable_irq(cards[i].port);
+		B1_reset(cards[i].port);
+		B1_reset(cards[i].port);
+		/*
+		 * free kernel resources
+		 */
+		free_irq(cards[i].irq, &cards[i]);
+		release_region(cards[i].port, AVMB1_PORTLEN);
+
+	}
+	printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev);
+}
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/b1lli.c linux-2.0.31-pre3/drivers/isdn/avmb1/b1lli.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/b1lli.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/b1lli.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,594 @@
+/*
+ * $Id: b1lli.c,v 1.1 1997/03/04 21:50:28 calle Exp $
+ * 
+ * ISDN lowlevel-module for AVM B1-card.
+ * 
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: b1lli.c,v $
+ * Revision 1.1  1997/03/04 21:50:28  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+
+#include "compat.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+/*
+ * LLI Messages to the ISDN-ControllerISDN Controller 
+ */
+
+#define	SEND_POLL		0x72	/*
+					   * after load <- RECEIVE_POLL 
+					 */
+#define SEND_INIT		0x11	/*
+					   * first message <- RECEIVE_INIT
+					   * int32 NumApplications  int32
+					   * NumNCCIs int32 BoardNumber 
+					 */
+#define SEND_REGISTER		0x12	/*
+					   * register an application int32
+					   * ApplIDId int32 NumMessages
+					   * int32 NumB3Connections int32
+					   * NumB3Blocks int32 B3Size
+					   * 
+					   * AnzB3Connection != 0 &&
+					   * AnzB3Blocks >= 1 && B3Size >= 1 
+					 */
+#define SEND_RELEASE		0x14	/*
+					   * deregister an application int32 
+					   * ApplID 
+					 */
+#define SEND_MESSAGE		0x15	/*
+					   * send capi-message int32 length
+					   * capi-data ... 
+					 */
+#define SEND_DATA_B3_REQ	0x13	/*
+					   * send capi-data-message int32
+					   * MsgLength capi-data ... int32
+					   * B3Length data .... 
+					 */
+
+/*
+ * LLI Messages from the ISDN-ControllerISDN Controller 
+ */
+
+#define RECEIVE_POLL		0x32	/*
+					   * <- after SEND_POLL 
+					 */
+#define RECEIVE_INIT		0x27	/*
+					   * <- after SEND_INIT int32 length
+					   * byte total length b1struct board 
+					   * driver revision b1struct card
+					   * type b1struct reserved b1struct
+					   * serial number b1struct driver
+					   * capability b1struct d-channel
+					   * protocol b1struct CAPI-2.0
+					   * profile b1struct capi version 
+					 */
+#define RECEIVE_MESSAGE		0x21	/*
+					   * <- after SEND_MESSAGE int32
+					   * AppllID int32 Length capi-data
+					   * .... 
+					 */
+#define RECEIVE_DATA_B3_IND	0x22	/*
+					   * received data int32 AppllID
+					   * int32 Length capi-data ...
+					   * int32 B3Length data ... 
+					 */
+#define RECEIVE_START		0x23	/*
+					   * Handshake 
+					 */
+#define RECEIVE_STOP		0x24	/*
+					   * Handshake 
+					 */
+#define RECEIVE_NEW_NCCI	0x25	/*
+					   * int32 AppllID int32 NCCI int32
+					   * WindowSize 
+					 */
+#define RECEIVE_FREE_NCCI	0x26	/*
+					   * int32 AppllID int32 NCCI 
+					 */
+#define RECEIVE_RELEASE		0x26	/*
+					   * int32 AppllID int32 0xffffffff 
+					 */
+
+/*
+ * port offsets
+ */
+
+#define B1_READ			0x00
+#define B1_WRITE		0x01
+#define B1_INSTAT		0x02
+#define B1_OUTSTAT		0x03
+#define B1_RESET		0x10
+#define B1_ANALYSE		0x04
+
+
+
+static inline unsigned char b1outp(unsigned short base,
+				   unsigned short offset,
+				   unsigned char value)
+{
+	outb(value, base + offset);
+	return inb(base + B1_ANALYSE);
+}
+
+static int irq_table[16] =
+{0,
+ 0,
+ 0,
+ 192,				/* irq 3 */
+ 32,				/* irq 4 */
+ 160,				/* irq 5 */
+ 96,				/* irq 6 */
+ 224,				/* irq 7 */
+ 0,
+ 64,				/* irq 9 */
+ 80,				/* irq 10 */
+ 208,				/* irq 11 */
+ 48,				/* irq 12 */
+ 0,
+ 0,
+ 112,				/* irq 15 */
+};
+
+int B1_valid_irq(unsigned irq)
+{
+	return irq_table[irq] != 0;
+}
+
+unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+{
+	return b1outp(base, B1_RESET, irq_table[irq]);
+}
+
+unsigned char B1_enable_irq(unsigned short base)
+{
+	return b1outp(base, B1_INSTAT, 0x02);
+}
+
+unsigned char B1_disable_irq(unsigned short base)
+{
+	return b1outp(base, B1_INSTAT, 0x00);
+}
+
+void B1_reset(unsigned short base)
+{
+	b1outp(base, B1_RESET, 0);
+	udelay(55 * 2 * 1000);	/* 2 TIC's */
+
+	b1outp(base, B1_RESET, 1);
+	udelay(55 * 2 * 1000);	/* 2 TIC's */
+
+	b1outp(base, B1_RESET, 0);
+	udelay(55 * 2 * 1000);	/* 2 TIC's */
+}
+
+int B1_detect(unsigned short base)
+{
+	/*
+	 * Statusregister 0000 00xx 
+	 */
+	if ((inb(base + B1_INSTAT) & 0xfc)
+	    || (inb(base + B1_OUTSTAT) & 0xfc))
+		return 1;
+
+	/*
+	 * Statusregister 0000 001x 
+	 */
+	b1outp(base, B1_INSTAT, 0x2);	/* enable irq */
+	b1outp(base, B1_OUTSTAT, 0x2);
+	if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
+	    || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2)
+		return 2;
+
+	/*
+	 * Statusregister 0000 000x 
+	 */
+	b1outp(base, B1_INSTAT, 0x0);	/* disable irq */
+	b1outp(base, B1_OUTSTAT, 0x0);
+	if ((inb(base + B1_INSTAT) & 0xfe)
+	    || (inb(base + B1_OUTSTAT) & 0xfe))
+		return 3;
+
+	return 0;
+}
+
+static inline int B1_rx_full(unsigned short base)
+{
+	return inb(base + B1_INSTAT) & 0x1;
+}
+
+static inline unsigned char B1_get_byte(unsigned short base)
+{
+	unsigned long i = jiffies + 5 * HZ;	/* maximum wait time 5 sec */
+	while (!B1_rx_full(base) && i > jiffies);
+	if (B1_rx_full(base))
+		return inb(base + B1_READ);
+	printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
+	return 0;
+}
+
+static inline unsigned int B1_get_word(unsigned short base)
+{
+	unsigned int val = 0;
+	val |= B1_get_byte(base);
+	val |= (B1_get_byte(base) << 8);
+	val |= (B1_get_byte(base) << 16);
+	val |= (B1_get_byte(base) << 24);
+	return val;
+}
+
+static inline int B1_tx_empty(unsigned short base)
+{
+	return inb(base + B1_OUTSTAT) & 0x1;
+}
+
+static inline void B1_put_byte(unsigned short base, unsigned char val)
+{
+	while (!B1_tx_empty(base));
+	b1outp(base, B1_WRITE, val);
+}
+
+static inline void B1_put_word(unsigned short base, unsigned int val)
+{
+	B1_put_byte(base, val & 0xff);
+	B1_put_byte(base, (val >> 8) & 0xff);
+	B1_put_byte(base, (val >> 16) & 0xff);
+	B1_put_byte(base, (val >> 24) & 0xff);
+}
+
+static inline unsigned int B1_get_slice(unsigned short base,
+					unsigned char *dp)
+{
+	unsigned int len, i;
+
+	len = i = B1_get_word(base);
+	while (i-- > 0)
+		*dp++ = B1_get_byte(base);
+	return len;
+}
+
+static inline void B1_put_slice(unsigned short base,
+				unsigned char *dp, unsigned int len)
+{
+	B1_put_word(base, len);
+	while (len-- > 0)
+		B1_put_byte(base, *dp++);
+}
+
+extern int loaddebug;
+
+int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
+{
+	/*
+	 * Data is in user space !!!
+	 */
+	unsigned char buf[256];
+	unsigned char *dp;
+	int i, left, retval;
+
+
+	dp = t4file->data;
+	left = t4file->len;
+	while (left > sizeof(buf)) {
+		retval = copy_from_user(buf, dp, sizeof(buf));
+		if (retval)
+			return -EFAULT;
+		if (loaddebug)
+			printk(KERN_DEBUG "b1capi: loading: %d bytes ..", sizeof(buf));
+		for (i = 0; i < sizeof(buf); i++)
+			B1_put_byte(base, buf[i]);
+		if (loaddebug)
+		   printk("ok\n");
+		left -= sizeof(buf);
+		dp += sizeof(buf);
+	}
+	if (left) {
+		retval = copy_from_user(buf, dp, left);
+		if (retval)
+			return -EFAULT;
+		if (loaddebug)
+			printk(KERN_DEBUG "b1capi: loading: %d bytes ..", left);
+		for (i = 0; i < left; i++)
+			B1_put_byte(base, buf[i]);
+		if (loaddebug)
+		   printk("ok\n");
+	}
+	return 0;
+}
+
+int B1_loaded(unsigned short base)
+{
+	int i;
+	unsigned char ans;
+
+	if (loaddebug)
+		printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n");
+	for (i = jiffies + 10 * HZ; i > jiffies;) {
+		if (B1_tx_empty(base))
+			break;
+	}
+	if (!B1_tx_empty(base)) {
+		printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n");
+		return 0;
+	}
+	B1_put_byte(base, SEND_POLL);
+	printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n");
+	for (i = jiffies + 10 * HZ; i > jiffies;) {
+		if (B1_rx_full(base)) {
+			if ((ans = B1_get_byte(base)) == RECEIVE_POLL) {
+				if (loaddebug)
+					printk(KERN_DEBUG "b1capi: loaded: ok\n");
+				return 1;
+			}
+			printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n");
+	return 0;
+}
+
+/*
+ * ------------------------------------------------------------------- 
+ */
+static inline void parse_version(avmb1_card * card)
+{
+	int i, j;
+	for (j = 0; j < AVM_MAXVERSION; j++)
+		card->version[j] = "\0\0" + 1;
+	for (i = 0, j = 0;
+	     j < AVM_MAXVERSION && i < card->versionlen;
+	     j++, i += card->versionbuf[i] + 1)
+		card->version[j] = &card->versionbuf[i + 1];
+}
+/*
+ * ------------------------------------------------------------------- 
+ */
+
+void B1_send_init(unsigned short port,
+	     unsigned int napps, unsigned int nncci, unsigned int cardnr)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	B1_put_byte(port, SEND_INIT);
+	B1_put_word(port, napps);
+	B1_put_word(port, nncci);
+	B1_put_word(port, cardnr);
+	restore_flags(flags);
+}
+
+void B1_send_register(unsigned short port,
+		      __u16 appid, __u32 nmsg,
+		      __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	B1_put_byte(port, SEND_REGISTER);
+	B1_put_word(port, appid);
+	B1_put_word(port, nmsg);
+	B1_put_word(port, nb3conn);
+	B1_put_word(port, nb3blocks);
+	B1_put_word(port, b3bsize);
+	restore_flags(flags);
+}
+
+void B1_send_release(unsigned short port,
+		     __u16 appid)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	B1_put_byte(port, SEND_RELEASE);
+	B1_put_word(port, appid);
+	restore_flags(flags);
+}
+
+extern int showcapimsgs;
+
+void B1_send_message(unsigned short port, struct sk_buff *skb)
+{
+	unsigned long flags;
+	__u16 len = CAPIMSG_LEN(skb->data);
+	__u8 cmd = CAPIMSG_COMMAND(skb->data);
+	__u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+	__u32 contr = CAPIMSG_CONTROL(skb->data);
+
+	if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+		__u16 dlen = CAPIMSG_DATALEN(skb->data);
+
+		if (showcapimsgs > 2) {
+			if (showcapimsgs & 1) {
+				printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+				       (unsigned long) contr,
+				       CAPIMSG_APPID(skb->data),
+				       capi_cmd2str(cmd, subcmd), len);
+			} else {
+				printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+			}
+
+		}
+		save_flags(flags);
+		cli();
+		B1_put_byte(port, SEND_DATA_B3_REQ);
+		B1_put_slice(port, skb->data, len);
+		B1_put_slice(port, skb->data + len, dlen);
+		restore_flags(flags);
+	} else {
+		if (showcapimsgs) {
+
+			if (showcapimsgs & 1) {
+				printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+				       (unsigned long) contr,
+				       CAPIMSG_APPID(skb->data),
+				       capi_cmd2str(cmd, subcmd), len);
+			} else {
+				printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+			}
+		}
+		save_flags(flags);
+		cli();
+		B1_put_byte(port, SEND_MESSAGE);
+		B1_put_slice(port, skb->data, len);
+		restore_flags(flags);
+	}
+	dev_kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ * ------------------------------------------------------------------- 
+ */
+
+void B1_handle_interrupt(avmb1_card * card)
+{
+	unsigned char b1cmd;
+	struct sk_buff *skb;
+
+	unsigned ApplId;
+	unsigned MsgLen;
+	unsigned DataB3Len;
+	unsigned NCCI;
+	unsigned WindowSize;
+
+	if (!B1_rx_full(card->port))
+		return;
+
+	b1cmd = B1_get_byte(card->port);
+
+	switch (b1cmd) {
+
+	case RECEIVE_DATA_B3_IND:
+
+		ApplId = (unsigned) B1_get_word(card->port);
+		MsgLen = B1_get_slice(card->port, card->msgbuf);
+		DataB3Len = B1_get_slice(card->port, card->databuf);
+
+		if (showcapimsgs > 2) {
+			__u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+			__u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+			__u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+			CAPIMSG_SETDATA(card->msgbuf, card->databuf);
+			if (showcapimsgs & 1) {
+				printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u/%u\n",
+				       (unsigned long) contr,
+				       CAPIMSG_APPID(card->msgbuf),
+				       capi_cmd2str(cmd, subcmd),
+				       MsgLen, DataB3Len);
+			} else {
+				printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+			}
+		}
+		if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) {
+			printk(KERN_ERR "b1lli: incoming packet dropped\n");
+		} else {
+			SET_SKB_FREE(skb);
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+			CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
+			avmb1_handle_capimsg(card, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_MESSAGE:
+
+		ApplId = (unsigned) B1_get_word(card->port);
+		MsgLen = B1_get_slice(card->port, card->msgbuf);
+		if (showcapimsgs) {
+			__u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+			__u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+			__u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+			if (showcapimsgs & 1) {
+				printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u\n",
+				       (unsigned long) contr,
+				       CAPIMSG_APPID(card->msgbuf),
+				       capi_cmd2str(cmd, subcmd),
+				       MsgLen);
+			} else {
+				printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+			}
+
+		}
+		if (!(skb = dev_alloc_skb(MsgLen))) {
+			printk(KERN_ERR "b1lli: incoming packet dropped\n");
+		} else {
+			SET_SKB_FREE(skb);
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			avmb1_handle_capimsg(card, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_NEW_NCCI:
+
+		ApplId = B1_get_word(card->port);
+		NCCI = B1_get_word(card->port);
+		WindowSize = B1_get_word(card->port);
+
+		if (showcapimsgs)
+			printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+		avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize);
+
+		break;
+
+	case RECEIVE_FREE_NCCI:
+
+		ApplId = B1_get_word(card->port);
+		NCCI = B1_get_word(card->port);
+
+		if (showcapimsgs)
+			printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+		avmb1_handle_free_ncci(card, ApplId, NCCI);
+		break;
+
+	case RECEIVE_START:
+		if (card->blocked)
+			printk(KERN_DEBUG "b1lli: RESTART\n");
+		card->blocked = 0;
+		break;
+
+	case RECEIVE_STOP:
+		printk(KERN_DEBUG "b1lli: STOP\n");
+		card->blocked = 1;
+		break;
+
+	case RECEIVE_INIT:
+
+		card->versionlen = B1_get_slice(card->port, card->versionbuf);
+		card->cardstate = CARD_ACTIVE;
+		parse_version(card);
+		printk(KERN_INFO "b1lli: %s-card (%s) with %s now active\n",
+		       card->version[VER_CARDTYPE],
+		       card->version[VER_DRIVER],
+		       card->version[VER_PROTO]);
+		avmb1_card_ready(card);
+		break;
+	default:
+		printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd);
+		break;
+	}
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/b1pci.c linux-2.0.31-pre3/drivers/isdn/avmb1/b1pci.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/b1pci.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/b1pci.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,121 @@
+/*
+ * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $
+ * 
+ * Module for AVM B1 PCI-card.
+ * 
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: b1pci.c,v $
+ * Revision 1.2  1997/05/18 09:24:13  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.1  1997/03/30 17:10:42  calle
+ * added support for AVM-B1-PCI card.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include "compat.h"
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM	0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_B1
+#define PCI_DEVICE_ID_AVM_B1	0x700
+#endif
+
+static char *revision = "$Revision: 1.2 $";
+
+/* ------------------------------------------------------------- */
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+#endif
+
+/* ------------------------------------------------------------- */
+
+/* ------------------------------------------------------------- */
+/* -------- Init & Cleanup ------------------------------------- */
+/* ------------------------------------------------------------- */
+
+/*
+ * init / exit functions
+ */
+
+#ifdef MODULE
+#define b1pci_init init_module
+#endif
+
+int b1pci_init(void)
+{
+	char *p;
+	char rev[10];
+	int rc;
+	int pci_index;
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else
+		strcpy(rev, " ??? ");
+
+
+#ifdef CONFIG_PCI
+	if (!pcibios_present()) {
+		printk(KERN_ERR "b1pci: no PCI-BIOS present\n");
+		return -EIO;
+	}
+
+	printk(KERN_INFO "b1pci: revision %s\n", rev);
+
+	for (pci_index = 0; pci_index < 8; pci_index++) {
+		unsigned char pci_bus, pci_device_fn;
+		unsigned int ioaddr;
+		unsigned char irq;
+
+		if (pcibios_find_device (PCI_VENDOR_ID_AVM,
+					PCI_DEVICE_ID_AVM_B1, pci_index,
+					&pci_bus, &pci_device_fn) != 0) {
+			continue;
+		}
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+				PCI_INTERRUPT_LINE, &irq);
+		pcibios_read_config_dword(pci_bus, pci_device_fn,
+				PCI_BASE_ADDRESS_1, &ioaddr);
+		/* Strip the I/O address out of the returned value */
+		ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+		printk(KERN_INFO
+			"b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+			ioaddr, irq);
+		if ((rc = avmb1_probecard(ioaddr, irq)) != 0) {
+		        printk(KERN_ERR
+			"b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
+			ioaddr, irq);
+			return rc;
+		}
+		if ((rc = avmb1_addcard(ioaddr, irq)) != 0)
+			return rc;
+	}
+	return 0;
+#else
+	printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n");
+	return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capi.c linux-2.0.31-pre3/drivers/isdn/avmb1/capi.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capi.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capi.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,540 @@
+/*
+ * $Id: capi.c,v 1.4 1997/05/27 15:17:50 fritz Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capi.c,v $
+ * Revision 1.4  1997/05/27 15:17:50  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.3  1997/05/18 09:24:14  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2  1997/03/05 21:17:59  fritz
+ * Added capi_poll for compiling under 2.1.27
+ *
+ * Revision 1.1  1997/03/04 21:50:29  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/skbuff.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
+#endif
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+
+#include "compat.h"
+#include "capiutil.h"
+#include "capicmd.h"
+#include "capidev.h"
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
+#endif
+
+/* -------- driver information -------------------------------------- */
+
+int capi_major = 68;		/* allocated */
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_PARM(capi_major, "i");
+#endif
+
+/* -------- global variables ---------------------------------------- */
+
+static struct capidev capidevs[CAPI_MAXMINOR + 1];
+struct capi_interface *capifuncs;
+
+/* -------- function called by lower level -------------------------- */
+
+static void capi_signal(__u16 applid, __u32 minor)
+{
+	struct capidev *cdev;
+	struct sk_buff *skb = 0;
+
+	if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
+		printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
+		return;
+	}
+	cdev = &capidevs[minor];
+	(void) (*capifuncs->capi_get_message) (applid, &skb);
+	if (skb) {
+		skb_queue_tail(&cdev->recv_queue, skb);
+		wake_up_interruptible(&cdev->recv_wait);
+	} else {
+		printk(KERN_ERR "BUG: capi_signal: no skb\n");
+	}
+}
+
+/* -------- file_operations ----------------------------------------- */
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_lseek(struct inode *inode, struct file *file,
+		      off_t offset, int origin)
+{
+	return -ESPIPE;
+}
+#else
+static long long capi_llseek(struct inode *inode, struct file *file,
+			     long long offset, int origin)
+{
+	return -ESPIPE;
+}
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_read(struct inode *inode, struct file *file,
+		     char *buf, int count)
+#else
+static long capi_read(struct inode *inode, struct file *file,
+		      char *buf, unsigned long count)
+#endif
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct capidev *cdev;
+	struct sk_buff *skb;
+	int retval;
+	size_t copied;
+
+	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+		return -ENODEV;
+
+	cdev = &capidevs[minor];
+
+	if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
+
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		for (;;) {
+			interruptible_sleep_on(&cdev->recv_wait);
+			if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+				break;
+			if (current->signal & ~current->blocked)
+				break;
+		}
+		if (skb == 0)
+			return -ERESTARTNOHAND;
+	}
+	if (skb->len > count) {
+		skb_queue_head(&cdev->recv_queue, skb);
+		return -EMSGSIZE;
+	}
+	if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+	    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+		CAPIMSG_SETDATA(skb->data, buf + CAPIMSG_LEN(skb->data));
+	retval = copy_to_user(buf, skb->data, skb->len);
+	if (retval) {
+		skb_queue_head(&cdev->recv_queue, skb);
+		return retval;
+	}
+	copied = skb->len;
+
+
+	kfree_skb(skb, FREE_READ);
+
+	return copied;
+}
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_write(struct inode *inode, struct file *file,
+		      const char *buf, int count)
+#else
+static long capi_write(struct inode *inode, struct file *file,
+		       const char *buf, unsigned long count)
+#endif
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct capidev *cdev;
+	struct sk_buff *skb;
+	int retval;
+	__u8 cmd;
+	__u8 subcmd;
+	__u16 mlen;
+
+	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+		return -ENODEV;
+
+	cdev = &capidevs[minor];
+
+	skb = alloc_skb(count, GFP_USER);
+
+	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+		dev_kfree_skb(skb, FREE_WRITE);
+		return retval;
+	}
+	cmd = CAPIMSG_COMMAND(skb->data);
+	subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+	mlen = CAPIMSG_LEN(skb->data);
+	if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
+		__u16 dlen = CAPIMSG_DATALEN(skb->data);
+		if (mlen + dlen != count) {
+			dev_kfree_skb(skb, FREE_WRITE);
+			return -EINVAL;
+		}
+	} else if (mlen != count) {
+		dev_kfree_skb(skb, FREE_WRITE);
+		return -EINVAL;
+	}
+	CAPIMSG_SETAPPID(skb->data, cdev->applid);
+
+	cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);
+
+	if (cdev->errcode) {
+		dev_kfree_skb(skb, FREE_WRITE);
+		return -EIO;
+	}
+	return count;
+}
+
+#if (LINUX_VERSION_CODE < 0x020117)
+static int capi_select(struct inode *inode, struct file *file,
+		       int sel_type, select_table * wait)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct capidev *cdev;
+
+	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+		return -ENODEV;
+
+	cdev = &capidevs[minor];
+
+	switch (sel_type) {
+	case SEL_IN:
+		if (!skb_queue_empty(&cdev->recv_queue))
+			return 1;
+		/* fall througth */
+	case SEL_EX:
+		/* error conditions ? */
+
+		select_wait(&cdev->recv_wait, wait);
+		return 0;
+	case SEL_OUT:
+		/* 
+		   if (!queue_full())
+		   return 1;
+		   select_wait(&cdev->send_wait, wait);
+		   return 0;
+		 */
+		return 1;
+	}
+	return 1;
+}
+#else
+static unsigned int
+capi_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask = 0;
+	unsigned int minor = MINOR(file->f_inode->i_rdev);
+	struct capidev *cdev;
+
+	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+		return POLLERR;
+
+	cdev = &capidevs[minor];
+	poll_wait(&(cdev->recv_wait), wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (!skb_queue_empty(&cdev->recv_queue))
+		mask |= POLLIN | POLLRDNORM;
+	return mask;
+}
+#endif
+
+static int capi_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct capidev *cdev;
+	capi_ioctl_struct data;
+	int retval;
+
+
+	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
+		return -ENODEV;
+
+	cdev = &capidevs[minor];
+
+	switch (cmd) {
+	case CAPI_REGISTER:
+		{
+			if (!minor)
+				return -EINVAL;
+			retval = copy_from_user((void *) &data.rparams,
+						(void *) arg, sizeof(struct capi_register_params));
+			if (retval)
+				return -EFAULT;
+			if (cdev->is_registered)
+				return -EEXIST;
+			cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
+							  &cdev->applid);
+			if (cdev->errcode)
+				return -EIO;
+			(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
+			cdev->is_registered = 1;
+		}
+		return 0;
+
+	case CAPI_GET_VERSION:
+		{
+			retval = copy_from_user((void *) &data.contr,
+						(void *) arg,
+						sizeof(data.contr));
+			if (retval)
+				return -EFAULT;
+		        cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version);
+			if (cdev->errcode)
+				return -EIO;
+			retval = copy_to_user((void *) arg,
+					      (void *) &data.version,
+					      sizeof(data.version));
+			if (retval)
+				return -EFAULT;
+		}
+		return 0;
+
+	case CAPI_GET_SERIAL:
+		{
+			retval = copy_from_user((void *) &data.contr,
+						(void *) arg,
+						sizeof(data.contr));
+			if (retval)
+				return -EFAULT;
+			cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial);
+			if (cdev->errcode)
+				return -EIO;
+			retval = copy_to_user((void *) arg,
+					      (void *) data.serial,
+					      sizeof(data.serial));
+			if (retval)
+				return -EFAULT;
+		}
+		return 0;
+	case CAPI_GET_PROFILE:
+		{
+			retval = copy_from_user((void *) &data.contr,
+						(void *) arg,
+						sizeof(data.contr));
+			if (retval)
+				return -EFAULT;
+
+			if (data.contr == 0) {
+				cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
+				if (cdev->errcode)
+					return -EIO;
+
+				retval = copy_to_user((void *) arg,
+				      (void *) &data.profile.ncontroller,
+				       sizeof(data.profile.ncontroller));
+
+			} else {
+				cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
+				if (cdev->errcode)
+					return -EIO;
+
+				retval = copy_to_user((void *) arg,
+						  (void *) &data.profile,
+						   sizeof(data.profile));
+			}
+			if (retval)
+				return -EFAULT;
+		}
+		return 0;
+
+	case CAPI_GET_MANUFACTURER:
+		{
+			retval = copy_from_user((void *) &data.contr,
+						(void *) arg,
+						sizeof(data.contr));
+			if (retval)
+				return -EFAULT;
+			cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer);
+			if (cdev->errcode)
+				return -EIO;
+
+			retval = copy_to_user((void *) arg, (void *) data.manufacturer,
+					      sizeof(data.manufacturer));
+			if (retval)
+				return -EFAULT;
+
+		}
+		return 0;
+	case CAPI_GET_ERRCODE:
+		data.errcode = cdev->errcode;
+		cdev->errcode = CAPI_NOERROR;
+		if (arg) {
+			retval = copy_to_user((void *) arg,
+					      (void *) &data.errcode,
+					      sizeof(data.errcode));
+			if (retval)
+				return -EFAULT;
+		}
+		return data.errcode;
+
+	case CAPI_INSTALLED:
+		if ((*capifuncs->capi_installed) ())
+			return 0;
+		return -ENXIO;
+
+	case CAPI_MANUFACTURER_CMD:
+		{
+			struct capi_manufacturer_cmd mcmd;
+			if (minor)
+				return -EINVAL;
+			if (!suser())
+				return -EPERM;
+			retval = copy_from_user((void *) &mcmd, (void *) arg,
+						sizeof(mcmd));
+			if (retval)
+				return -EFAULT;
+			return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int capi_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+
+	if (minor >= CAPI_MAXMINOR)
+		return -ENXIO;
+
+	if (minor) {
+		if (capidevs[minor].is_open)
+			return -EEXIST;
+
+		capidevs[minor].is_open = 1;
+		skb_queue_head_init(&capidevs[minor].recv_queue);
+		MOD_INC_USE_COUNT;
+
+	} else {
+
+		if (!capidevs[minor].is_open) {
+			capidevs[minor].is_open = 1;
+			MOD_INC_USE_COUNT;
+		}
+	}
+
+
+	return 0;
+}
+
+static CLOSETYPE
+capi_release(struct inode *inode, struct file *file)
+{
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct capidev *cdev;
+	struct sk_buff *skb;
+
+	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
+		printk(KERN_ERR "capi20: release minor %d ???\n", minor);
+		return CLOSEVAL;
+	}
+	cdev = &capidevs[minor];
+
+	if (minor) {
+
+		if (cdev->is_registered)
+			(*capifuncs->capi_release) (cdev->applid);
+
+		cdev->is_registered = 0;
+		cdev->applid = 0;
+
+		while ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+			kfree_skb(skb, FREE_READ);
+	}
+	cdev->is_open = 0;
+
+	MOD_DEC_USE_COUNT;
+	return CLOSEVAL;
+}
+
+static struct file_operations capi_fops =
+{
+#if LINUX_VERSION_CODE < 0x020100
+	capi_lseek,
+#else
+	capi_llseek,
+#endif
+	capi_read,
+	capi_write,
+	NULL,			/* capi_readdir */
+#if (LINUX_VERSION_CODE < 0x020117)
+	capi_select,
+#else
+	capi_poll,
+#endif
+	capi_ioctl,
+	NULL,			/* capi_mmap */
+	capi_open,
+	capi_release,
+	NULL,			/* capi_fsync */
+	NULL,			/* capi_fasync */
+};
+
+
+/* -------- init function and module interface ---------------------- */
+
+#ifdef MODULE
+#define	 capi_init	init_module
+#endif
+
+static struct capi_interface_user cuser = {
+	"capi20",
+	0,
+};
+
+int capi_init(void)
+{
+	memset(capidevs, 0, sizeof(capidevs));
+
+	if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
+		return -EIO;
+	}
+	printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
+
+	if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+		unregister_chrdev(capi_major, "capi20");
+		return -EIO;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	unregister_chrdev(capi_major, "capi20");
+	(void) detach_capi_interface(&cuser);
+}
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capicmd.h linux-2.0.31-pre3/drivers/isdn/avmb1/capicmd.h
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capicmd.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capicmd.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,119 @@
+/*
+ * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ * 
+ * CAPI 2.0 Interface for Linux
+ * 
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: capicmd.h,v $
+ * Revision 1.1  1997/03/04 21:50:30  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+#ifndef __CAPICMD_H__
+#define __CAPICMD_H__
+
+/*----- CAPI commands -----*/
+#define CAPI_ALERT		    0x01
+#define CAPI_CONNECT		    0x02
+#define CAPI_CONNECT_ACTIVE	    0x03
+#define CAPI_CONNECT_B3_ACTIVE	    0x83
+#define CAPI_CONNECT_B3 	    0x82
+#define CAPI_CONNECT_B3_T90_ACTIVE  0x88
+#define CAPI_DATA_B3		    0x86
+#define CAPI_DISCONNECT_B3	    0x84
+#define CAPI_DISCONNECT 	    0x04
+#define CAPI_FACILITY		    0x80
+#define CAPI_INFO		    0x08
+#define CAPI_LISTEN		    0x05
+#define CAPI_MANUFACTURER	    0xff
+#define CAPI_RESET_B3		    0x87
+#define CAPI_SELECT_B_PROTOCOL	    0x41
+
+/*----- CAPI subcommands -----*/
+
+#define CAPI_REQ    0x80
+#define CAPI_CONF   0x81
+#define CAPI_IND    0x82
+#define CAPI_RESP   0x83
+
+/*----- CAPI combined commands -----*/
+
+#define CAPICMD(cmd,subcmd)	(((cmd)<<8)|(subcmd))
+
+#define CAPI_DISCONNECT_REQ		CAPICMD(CAPI_DISCONNECT,CAPI_REQ)
+#define CAPI_DISCONNECT_CONF		CAPICMD(CAPI_DISCONNECT,CAPI_CONF)
+#define CAPI_DISCONNECT_IND		CAPICMD(CAPI_DISCONNECT,CAPI_IND)
+#define CAPI_DISCONNECT_RESP		CAPICMD(CAPI_DISCONNECT,CAPI_RESP)
+
+#define CAPI_ALERT_REQ			CAPICMD(CAPI_ALERT,CAPI_REQ)
+#define CAPI_ALERT_CONF			CAPICMD(CAPI_ALERT,CAPI_CONF)
+
+#define CAPI_CONNECT_REQ		CAPICMD(CAPI_CONNECT,CAPI_REQ)
+#define CAPI_CONNECT_CONF		CAPICMD(CAPI_CONNECT,CAPI_CONF)
+#define CAPI_CONNECT_IND		CAPICMD(CAPI_CONNECT,CAPI_IND)
+#define CAPI_CONNECT_RESP		CAPICMD(CAPI_CONNECT,CAPI_RESP)
+
+#define CAPI_CONNECT_ACTIVE_REQ		CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ)
+#define CAPI_CONNECT_ACTIVE_CONF	CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF)
+#define CAPI_CONNECT_ACTIVE_IND		CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_ACTIVE_RESP	CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP)
+
+#define CAPI_SELECT_B_PROTOCOL_REQ	CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ)
+#define CAPI_SELECT_B_PROTOCOL_CONF	CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF)
+
+#define CAPI_CONNECT_B3_ACTIVE_REQ	CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ)
+#define CAPI_CONNECT_B3_ACTIVE_CONF	CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF)
+#define CAPI_CONNECT_B3_ACTIVE_IND	CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_B3_ACTIVE_RESP	CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP)
+
+#define CAPI_CONNECT_B3_REQ		CAPICMD(CAPI_CONNECT_B3,CAPI_REQ)
+#define CAPI_CONNECT_B3_CONF		CAPICMD(CAPI_CONNECT_B3,CAPI_CONF)
+#define CAPI_CONNECT_B3_IND		CAPICMD(CAPI_CONNECT_B3,CAPI_IND)
+#define CAPI_CONNECT_B3_RESP		CAPICMD(CAPI_CONNECT_B3,CAPI_RESP)
+
+
+#define CAPI_CONNECT_B3_T90_ACTIVE_IND	CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_B3_T90_ACTIVE_RESP	CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP)
+
+#define CAPI_DATA_B3_REQ		CAPICMD(CAPI_DATA_B3,CAPI_REQ)
+#define CAPI_DATA_B3_CONF		CAPICMD(CAPI_DATA_B3,CAPI_CONF)
+#define CAPI_DATA_B3_IND		CAPICMD(CAPI_DATA_B3,CAPI_IND)
+#define CAPI_DATA_B3_RESP		CAPICMD(CAPI_DATA_B3,CAPI_RESP)
+
+#define CAPI_DISCONNECT_B3_REQ		CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ)
+#define CAPI_DISCONNECT_B3_CONF		CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF)
+#define CAPI_DISCONNECT_B3_IND		CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND)
+#define CAPI_DISCONNECT_B3_RESP		CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP)
+
+#define CAPI_RESET_B3_REQ		CAPICMD(CAPI_RESET_B3,CAPI_REQ)
+#define CAPI_RESET_B3_CONF		CAPICMD(CAPI_RESET_B3,CAPI_CONF)
+#define CAPI_RESET_B3_IND		CAPICMD(CAPI_RESET_B3,CAPI_IND)
+#define CAPI_RESET_B3_RESP		CAPICMD(CAPI_RESET_B3,CAPI_RESP)
+
+#define CAPI_LISTEN_REQ			CAPICMD(CAPI_LISTEN,CAPI_REQ)
+#define CAPI_LISTEN_CONF		CAPICMD(CAPI_LISTEN,CAPI_CONF)
+
+#define CAPI_MANUFACTURER_REQ		CAPICMD(CAPI_MANUFACTURER,CAPI_REQ)
+#define CAPI_MANUFACTURER_CONF		CAPICMD(CAPI_MANUFACTURER,CAPI_CONF)
+#define CAPI_MANUFACTURER_IND		CAPICMD(CAPI_MANUFACTURER,CAPI_IND)
+#define CAPI_MANUFACTURER_RESP		CAPICMD(CAPI_MANUFACTURER,CAPI_RESP)
+
+#define CAPI_FACILITY_REQ		CAPICMD(CAPI_FACILITY,CAPI_REQ)
+#define CAPI_FACILITY_CONF		CAPICMD(CAPI_FACILITY,CAPI_CONF)
+#define CAPI_FACILITY_IND		CAPICMD(CAPI_FACILITY,CAPI_IND)
+#define CAPI_FACILITY_RESP		CAPICMD(CAPI_FACILITY,CAPI_RESP)
+
+#define CAPI_INFO_REQ			CAPICMD(CAPI_INFO,CAPI_REQ)
+#define CAPI_INFO_CONF			CAPICMD(CAPI_INFO,CAPI_CONF)
+#define CAPI_INFO_IND			CAPICMD(CAPI_INFO,CAPI_IND)
+#define CAPI_INFO_RESP			CAPICMD(CAPI_INFO,CAPI_RESP)
+
+#endif				/* __CAPICMD_H__ */
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capidev.h linux-2.0.31-pre3/drivers/isdn/avmb1/capidev.h
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capidev.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capidev.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,29 @@
+/*
+ * $Id: capidev.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidev.h,v $
+ * Revision 1.1  1997/03/04 21:50:30  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+
+struct capidev {
+	int is_open;
+	int is_registered;
+	__u16 applid;
+	struct sk_buff_head recv_queue;
+	struct wait_queue *recv_wait;
+	__u16 errcode;
+};
+
+#define CAPI_MAXMINOR	CAPI_MAXAPPL
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capidrv.c linux-2.0.31-pre3/drivers/isdn/avmb1/capidrv.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capidrv.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capidrv.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1764 @@
+/*
+ * $Id: capidrv.c,v 1.3 1997/05/18 09:24:15 calle Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidrv.c,v $
+ * Revision 1.3  1997/05/18 09:24:15  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2  1997/03/05 21:19:59  fritz
+ * Removed include of config.h (mkdep stated this is unneded).
+ *
+ * Revision 1.1  1997/03/04 21:50:31  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/skbuff.h>
+#include <linux/isdn.h>
+#include <linux/isdnif.h>
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+
+#include "compat.h"
+#include "capiutil.h"
+#include "capicmd.h"
+#include "capidrv.h"
+
+static char *revision = "$Revision: 1.3 $";
+int debugmode = 0;
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+MODULE_PARM(debugmode, "i");
+#endif
+
+/* -------- type definitions ----------------------------------------- */
+
+
+struct capidrv_contr {
+
+	struct capidrv_contr *next;
+
+	__u32 contrnr;
+	char name[20];
+
+	/*
+	 * for isdn4linux
+	 */
+	isdn_if interface;
+	int myid;
+
+	/*
+	 * LISTEN state
+	 */
+	int state;
+	__u32 cipmask;
+	__u32 cipmask2;
+
+	/*
+	 * ID of capi message sent
+	 */
+	__u16 msgid;
+
+	/*
+	 * B-Channels
+	 */
+	int nbchan;
+	struct capidrv_bchan {
+		struct capidrv_contr *contr;
+		__u8 msn[ISDN_MSNLEN];
+		int l2;
+		int l3;
+		__u8 num[ISDN_MSNLEN];
+		__u8 mynum[ISDN_MSNLEN];
+		int si1;
+		int si2;
+		int incoming;
+		int disconnecting;
+		struct capidrv_plci {
+			struct capidrv_plci *next;
+			__u32 plci;
+			__u32 ncci;	/* ncci for CONNECT_ACTIVE_IND */
+			__u16 msgid;	/* to identfy CONNECT_CONF */
+			int chan;
+			int state;
+			struct capidrv_ncci {
+				struct capidrv_ncci *next;
+				struct capidrv_plci *plcip;
+				__u32 ncci;
+				__u16 msgid;	/* to identfy CONNECT_B3_CONF */
+				int chan;
+				int state;
+				int oldstate;
+				/* */
+				__u16 datahandle;
+			} *ncci_list;
+		} *plcip;
+		struct capidrv_ncci *nccip;
+	} *bchans;
+
+	struct capidrv_plci *plci_list;
+};
+
+struct capidrv_data {
+	__u16 appid;
+	int ncontr;
+	struct capidrv_contr *contr_list;
+};
+
+typedef struct capidrv_plci capidrv_plci;
+typedef struct capidrv_ncci capidrv_ncci;
+typedef struct capidrv_contr capidrv_contr;
+typedef struct capidrv_data capidrv_data;
+typedef struct capidrv_bchan capidrv_bchan;
+
+/* -------- data definitions ----------------------------------------- */
+
+static capidrv_data global;
+static struct capi_interface *capifuncs;
+
+/* -------- convert functions ---------------------------------------- */
+
+static inline __u32 b1prot(int l2, int l3)
+{
+	switch (l2) {
+	case ISDN_PROTO_L2_X75I:
+	case ISDN_PROTO_L2_X75UI:
+	case ISDN_PROTO_L2_X75BUI:
+		return 0;
+	case ISDN_PROTO_L2_HDLC:
+	default:
+		return 0;
+	case ISDN_PROTO_L2_TRANS:
+		return 1;
+	}
+}
+
+static inline __u32 b2prot(int l2, int l3)
+{
+	switch (l2) {
+	case ISDN_PROTO_L2_X75I:
+	case ISDN_PROTO_L2_X75UI:
+	case ISDN_PROTO_L2_X75BUI:
+	default:
+		return 0;
+	case ISDN_PROTO_L2_HDLC:
+		return 1;
+	case ISDN_PROTO_L2_TRANS:
+		return 0;
+	}
+}
+
+static inline __u32 b3prot(int l2, int l3)
+{
+	switch (l2) {
+	case ISDN_PROTO_L2_X75I:
+	case ISDN_PROTO_L2_X75UI:
+	case ISDN_PROTO_L2_X75BUI:
+	case ISDN_PROTO_L2_HDLC:
+	case ISDN_PROTO_L2_TRANS:
+	default:
+		return 0;
+	}
+}
+
+static inline __u16 si2cip(__u8 si1, __u8 si2)
+{
+	static const __u8 cip[17][5] =
+	{
+	/*  0  1  2  3  4  */
+		{0, 0, 0, 0, 0},	/*0 */
+		{16, 16, 4, 26, 16},	/*1 */
+		{17, 17, 17, 4, 4},	/*2 */
+		{2, 2, 2, 2, 2},	/*3 */
+		{18, 18, 18, 18, 18},	/*4 */
+		{2, 2, 2, 2, 2},	/*5 */
+		{0, 0, 0, 0, 0},	/*6 */
+		{2, 2, 2, 2, 2},	/*7 */
+		{2, 2, 2, 2, 2},	/*8 */
+		{21, 21, 21, 21, 21},	/*9 */
+		{19, 19, 19, 19, 19},	/*10 */
+		{0, 0, 0, 0, 0},	/*11 */
+		{0, 0, 0, 0, 0},	/*12 */
+		{0, 0, 0, 0, 0},	/*13 */
+		{0, 0, 0, 0, 0},	/*14 */
+		{22, 22, 22, 22, 22},	/*15 */
+		{27, 27, 27, 28, 27}	/*16 */
+	};
+	if (si1 > 16)
+		si1 = 0;
+	if (si2 > 4)
+		si2 = 0;
+
+	return (__u16) cip[si1][si2];
+}
+
+static inline __u8 cip2si1(__u16 cipval)
+{
+	static const __u8 si[32] =
+	{7, 1, 7, 7, 1, 1, 7, 7,	/*0-7 */
+	 7, 1, 0, 0, 0, 0, 0, 0,	/*8-15 */
+	 1, 2, 4, 10, 9, 9, 15, 7,	/*16-23 */
+	 7, 7, 1, 16, 16, 0, 0, 0};	/*24-31 */
+
+	if (cipval > 31)
+		cipval = 0;	/* .... */
+	return si[cipval];
+}
+
+static inline __u8 cip2si2(__u16 cipval)
+{
+	static const __u8 si[32] =
+	{0, 0, 0, 0, 2, 3, 0, 0,	/*0-7 */
+	 0, 3, 0, 0, 0, 0, 0, 0,	/*8-15 */
+	 1, 2, 0, 0, 9, 0, 0, 0,	/*16-23 */
+	 0, 0, 3, 2, 3, 0, 0, 0};	/*24-31 */
+
+	if (cipval > 31)
+		cipval = 0;	/* .... */
+	return si[cipval];
+}
+
+
+/* -------- controller managment ------------------------------------- */
+
+static inline capidrv_contr *findcontrbydriverid(int driverid)
+{
+	capidrv_contr *p = global.contr_list;
+
+	while (p) {
+		if (p->myid == driverid)
+			return p;
+		p = p->next;
+	}
+	return (capidrv_contr *) 0;
+}
+
+static capidrv_contr *findcontrbynumber(__u32 contr)
+{
+	capidrv_contr *p = global.contr_list;
+
+	while (p) {
+		if (p->contrnr == contr)
+			return p;
+		p = p->next;
+	}
+	return (capidrv_contr *) 0;
+}
+
+
+/* -------- plci management ------------------------------------------ */
+
+static capidrv_plci *new_plci(capidrv_contr * card, int chan)
+{
+	capidrv_plci *plcip;
+
+	plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
+
+	if (plcip == 0)
+		return 0;
+
+	memset(plcip, 0, sizeof(capidrv_plci));
+	plcip->state = ST_PLCI_NONE;
+	plcip->plci = 0;
+	plcip->msgid = 0;
+	plcip->chan = chan;
+	plcip->next = card->plci_list;
+	card->plci_list = plcip;
+	card->bchans[chan].plcip = plcip;
+
+	return plcip;
+}
+
+static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
+{
+	capidrv_plci *p;
+	for (p = card->plci_list; p; p = p->next)
+		if (p->plci == plci)
+			return p;
+	return 0;
+}
+
+static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
+{
+	capidrv_plci *p;
+	for (p = card->plci_list; p; p = p->next)
+		if (p->msgid == msgid)
+			return p;
+	return 0;
+}
+
+static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
+{
+	capidrv_plci *p;
+	for (p = card->plci_list; p; p = p->next)
+		if (p->plci == (ncci & 0xffff))
+			return p;
+	return 0;
+}
+
+static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
+{
+	capidrv_plci **pp;
+
+	for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
+		if (*pp == plcip) {
+			*pp = (*pp)->next;
+			card->bchans[plcip->chan].plcip = 0;
+			card->bchans[plcip->chan].disconnecting = 0;
+			card->bchans[plcip->chan].incoming = 0;
+			kfree(plcip);
+			return;
+		}
+	}
+	printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n",
+	       plcip, plcip->plci);
+}
+
+/* -------- ncci management ------------------------------------------ */
+
+static inline capidrv_ncci *new_ncci(capidrv_contr * card,
+				     capidrv_plci * plcip,
+				     __u32 ncci)
+{
+	capidrv_ncci *nccip;
+
+	nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
+
+	if (nccip == 0)
+		return 0;
+
+	memset(nccip, 0, sizeof(capidrv_ncci));
+	nccip->ncci = ncci;
+	nccip->state = ST_NCCI_NONE;
+	nccip->plcip = plcip;
+	nccip->chan = plcip->chan;
+	nccip->datahandle = 0;
+
+	nccip->next = plcip->ncci_list;
+	plcip->ncci_list = nccip;
+
+	card->bchans[plcip->chan].nccip = nccip;
+
+	return nccip;
+}
+
+static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
+{
+	capidrv_plci *plcip;
+	capidrv_ncci *p;
+
+	if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+		return 0;
+
+	for (p = plcip->ncci_list; p; p = p->next)
+		if (p->ncci == ncci)
+			return p;
+	return 0;
+}
+
+static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
+					       __u32 ncci, __u16 msgid)
+{
+	capidrv_plci *plcip;
+	capidrv_ncci *p;
+
+	if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+		return 0;
+
+	for (p = plcip->ncci_list; p; p = p->next)
+		if (p->msgid == msgid)
+			return p;
+	return 0;
+}
+
+static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
+{
+	struct capidrv_ncci **pp;
+
+	for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
+		if (*pp == nccip) {
+			*pp = (*pp)->next;
+			break;
+		}
+	}
+	card->bchans[nccip->chan].nccip = 0;
+	kfree(nccip);
+}
+
+/* -------- convert and send capi message ---------------------------- */
+
+static void send_message(capidrv_contr * card, _cmsg * cmsg)
+{
+	struct sk_buff *skb;
+	size_t len;
+	capi_cmsg2message(cmsg, cmsg->buf);
+	len = CAPIMSG_LEN(cmsg->buf);
+	skb = dev_alloc_skb(len);
+        SET_SKB_FREE(skb);
+	memcpy(skb_put(skb, len), cmsg->buf, len);
+	(*capifuncs->capi_put_message) (global.appid, skb);
+}
+
+/* -------- state machine -------------------------------------------- */
+
+struct listenstatechange {
+	int actstate;
+	int nextstate;
+	int event;
+};
+
+static struct listenstatechange listentable[] =
+{
+	{ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
+	{ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
+	{ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
+    {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
+	{ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+      {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+	{ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+	{ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+	{},
+};
+
+static void listen_change_state(capidrv_contr * card, int event)
+{
+	struct listenstatechange *p = listentable;
+	while (p->event) {
+		if (card->state == p->actstate && p->event == event) {
+			if (debugmode)
+				printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n",
+				       card->state, p->nextstate);
+			card->state = p->nextstate;
+			return;
+		}
+		p++;
+	}
+	printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n",
+	       card->state, event);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static void p0(capidrv_contr * card, capidrv_plci * plci)
+{
+	isdn_ctrl cmd;
+
+	card->bchans[plci->chan].contr = 0;
+	cmd.command = ISDN_STAT_DHUP;
+	cmd.driver = card->myid;
+	cmd.arg = plci->chan;
+	card->interface.statcallb(&cmd);
+	free_plci(card, plci);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct plcistatechange {
+	int actstate;
+	int nextstate;
+	int event;
+	void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
+};
+
+static struct plcistatechange plcitable[] =
+{
+  /* P-0 */
+	{ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
+	{ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
+	{ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
+  /* P-0.1 */
+	{ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
+	{ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
+    {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  /* P-1 */
+      {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+   {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+    {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-ACT */
+      {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+   {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+	{ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-2 */
+    {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+    {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
+	{ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
+    {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+     {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-3 */
+{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+	{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-4 */
+      {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+   {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+    {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-5 */
+{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  /* P-6 */
+	{ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
+	{},
+};
+
+static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
+{
+	struct plcistatechange *p = plcitable;
+	while (p->event) {
+		if (plci->state == p->actstate && p->event == event) {
+			if (debugmode)
+				printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n",
+				  plci->plci, plci->state, p->nextstate);
+			plci->state = p->nextstate;
+			if (p->changefunc)
+				p->changefunc(card, plci);
+			return;
+		}
+		p++;
+	}
+	printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n",
+	       plci->plci, plci->state, event);
+}
+
+/* ------------------------------------------------------------------ */
+
+static _cmsg cmsg;
+
+static void n0(capidrv_contr * card, capidrv_ncci * ncci)
+{
+	isdn_ctrl cmd;
+
+	capi_fill_DISCONNECT_REQ(&cmsg,
+				 global.appid,
+				 card->msgid++,
+				 ncci->plcip->plci,
+				 0,	/* BChannelinformation */
+				 0,	/* Keypadfacility */
+				 0,	/* Useruserdata */
+				 0	/* Facilitydataarray */
+	);
+	send_message(card, &cmsg);
+	plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
+
+	cmd.command = ISDN_STAT_BHUP;
+	cmd.driver = card->myid;
+	cmd.arg = ncci->chan;
+	card->interface.statcallb(&cmd);
+	free_ncci(card, ncci);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct nccistatechange {
+	int actstate;
+	int nextstate;
+	int event;
+	void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
+};
+
+static struct nccistatechange nccitable[] =
+{
+  /* N-0 */
+	{ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
+	{ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
+  /* N-0.1 */
+    {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
+      {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0},
+  /* N-1 */
+ {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
+	{ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
+  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  /* N-2 */
+   {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
+ {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  /* N-ACT */
+	{ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
+    {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+   {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  /* N-3 */
+	{ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
+  {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  /* N-4 */
+	{ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+	{ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0},
+  /* N-5 */
+    {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
+	{},
+};
+
+static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
+{
+	struct nccistatechange *p = nccitable;
+	while (p->event) {
+		if (ncci->state == p->actstate && p->event == event) {
+			if (debugmode)
+				printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n",
+				  ncci->ncci, ncci->state, p->nextstate);
+			if (p->nextstate == ST_NCCI_PREVIOUS) {
+				ncci->state = ncci->oldstate;
+				ncci->oldstate = p->actstate;
+			} else {
+				ncci->oldstate = p->actstate;
+				ncci->state = p->nextstate;
+			}
+			if (p->changefunc)
+				p->changefunc(card, ncci);
+			return;
+		}
+		p++;
+	}
+	printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n",
+	       ncci->ncci, ncci->state, event);
+}
+
+/* ------------------------------------------------------------------- */
+
+static inline int new_bchan(capidrv_contr * card)
+{
+	int i;
+	for (i = 0; i < card->nbchan; i++) {
+		if (card->bchans[i].plcip == 0) {
+			card->bchans[i].disconnecting = 0;
+			return i;
+		}
+	}
+	return -1;
+}
+
+/* ------------------------------------------------------------------- */
+
+static void handle_controller(_cmsg * cmsg)
+{
+	capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+
+	if (!card) {
+		printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrController & 0x7f);
+		return;
+	}
+	switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+	case CAPI_LISTEN_CONF:	/* Controller */
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
+			       cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
+		if (cmsg->Info) {
+			listen_change_state(card, EV_LISTEN_CONF_ERROR);
+		} else if (card->cipmask == 0) {
+			listen_change_state(card, EV_LISTEN_CONF_EMPTY);
+		} else {
+			listen_change_state(card, EV_LISTEN_CONF_OK);
+		}
+		break;
+
+	case CAPI_MANUFACTURER_IND:	/* Controller */
+		goto ignored;
+	case CAPI_MANUFACTURER_CONF:	/* Controller */
+		goto ignored;
+	case CAPI_FACILITY_IND:	/* Controller/plci/ncci */
+		goto ignored;
+	case CAPI_FACILITY_CONF:	/* Controller/plci/ncci */
+		goto ignored;
+	case CAPI_INFO_IND:	/* Controller/plci */
+		goto ignored;
+	case CAPI_INFO_CONF:	/* Controller/plci */
+		goto ignored;
+
+	default:
+		printk(KERN_ERR "capidrv: got %s from controller 0x%x ???",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrController);
+	}
+	return;
+
+      ignored:
+	printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n",
+	       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+	       cmsg->adr.adrController);
+}
+
+static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
+{
+	capidrv_plci *plcip;
+	capidrv_bchan *bchan;
+	isdn_ctrl cmd;
+	int chan;
+
+	if ((chan = new_bchan(card)) == -1) {
+		printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n");
+		return;
+	}
+	bchan = &card->bchans[chan];
+	if ((plcip = new_plci(card, chan)) == 0) {
+		printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n");
+		return;
+	}
+	bchan->incoming = 1;
+	plcip->plci = cmsg->adr.adrPLCI;
+	plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
+
+	cmd.command = ISDN_STAT_ICALL;
+	cmd.driver = card->myid;
+	cmd.arg = chan;
+	memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
+	strncpy(cmd.parm.setup.phone,
+	        cmsg->CallingPartyNumber + 3,
+		cmsg->CallingPartyNumber[0] - 2);
+	strncpy(cmd.parm.setup.eazmsn,
+	        cmsg->CalledPartyNumber + 2,
+		cmsg->CalledPartyNumber[0] - 1);
+	cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
+	cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
+	cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
+	cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
+
+	printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n", 
+			cmd.parm.setup.phone,
+			cmd.parm.setup.si1,
+			cmd.parm.setup.si2,
+			cmd.parm.setup.eazmsn);
+
+	switch (card->interface.statcallb(&cmd)) {
+	case 0:
+		/* No device matching this call.
+		 * and isdn_common.c has send a HANGUP command
+		 * which is ignored in state ST_PLCI_INCOMING,
+		 * so we send RESP to ignore the call
+		 */
+		capi_cmsg_answer(cmsg);
+		cmsg->Reject = 1;	/* ignore */
+		send_message(card, cmsg);
+		plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+		printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n",
+			cmd.parm.setup.phone,
+			cmd.parm.setup.si1,
+			cmd.parm.setup.si2,
+			cmd.parm.setup.eazmsn);
+		break;
+	case 1:
+		/* At least one device matching this call (RING on ttyI)
+		 * HL-driver may send ALERTING on the D-channel in this
+		 * case.
+		 * really means: RING on ttyI or a net interface
+		 * accepted this call already.
+		 *
+		 * If the call was accepted, state has already changed,
+		 * and CONNECT_RESP already sent.
+		 */
+		if (plcip->state == ST_PLCI_INCOMING) {
+			printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n",
+				cmd.parm.setup.phone,
+				cmd.parm.setup.si1,
+				cmd.parm.setup.si2,
+				cmd.parm.setup.eazmsn);
+			capi_fill_ALERT_REQ(cmsg,
+					    global.appid,
+					    card->msgid++,
+					    plcip->plci,	/* adr */
+					    0,	/* BChannelinformation */
+					    0,	/* Keypadfacility */
+					    0,	/* Useruserdata */
+					    0	/* Facilitydataarray */
+			);
+			plcip->msgid = cmsg->Messagenumber;
+			send_message(card, cmsg);
+		} else {
+			printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n",
+				cmd.parm.setup.phone,
+				cmd.parm.setup.si1,
+				cmd.parm.setup.si2,
+				cmd.parm.setup.eazmsn);
+		}
+		break;
+
+	case 2:		/* Call will be rejected. */
+		capi_cmsg_answer(cmsg);
+		cmsg->Reject = 2;	/* reject call, normal call clearing */
+		send_message(card, cmsg);
+		plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+		break;
+
+	default:
+		/* An error happened. (Invalid parameters for example.) */
+		capi_cmsg_answer(cmsg);
+		cmsg->Reject = 8;	/* reject call,
+					   destination out of order */
+		send_message(card, cmsg);
+		plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+		break;
+	}
+	return;
+}
+
+static void handle_plci(_cmsg * cmsg)
+{
+	capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+	capidrv_plci *plcip;
+	isdn_ctrl cmd;
+
+	if (!card) {
+		printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrController & 0x7f);
+		return;
+	}
+	switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+	case CAPI_DISCONNECT_IND:	/* plci */
+		if (cmsg->Reason) {
+			printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
+		}
+		if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
+			capi_cmsg_answer(cmsg);
+			send_message(card, cmsg);
+			goto notfound;
+		}
+		card->bchans[plcip->chan].disconnecting = 1;
+		plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
+		capi_cmsg_answer(cmsg);
+		send_message(card, cmsg);
+		plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
+		break;
+
+	case CAPI_DISCONNECT_CONF:	/* plci */
+		if (cmsg->Info) {
+			printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Info, capi_info2str(cmsg->Info), 
+			       cmsg->adr.adrPLCI);
+		}
+		if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+			goto notfound;
+
+		card->bchans[plcip->chan].disconnecting = 1;
+		break;
+
+	case CAPI_ALERT_CONF:	/* plci */
+		if (cmsg->Info) {
+			printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Info, capi_info2str(cmsg->Info), 
+			       cmsg->adr.adrPLCI);
+		}
+		break;
+
+	case CAPI_CONNECT_IND:	/* plci */
+		handle_incoming_call(card, cmsg);
+		break;
+
+	case CAPI_CONNECT_CONF:	/* plci */
+		if (cmsg->Info) {
+			printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Info, capi_info2str(cmsg->Info), 
+			       cmsg->adr.adrPLCI);
+		}
+		if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
+			goto notfound;
+
+		plcip->plci = cmsg->adr.adrPLCI;
+		if (cmsg->Info) {
+			plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
+		} else {
+			plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
+		}
+		break;
+
+	case CAPI_CONNECT_ACTIVE_IND:	/* plci */
+
+		if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+			goto notfound;
+
+		if (card->bchans[plcip->chan].incoming) {
+			capi_cmsg_answer(cmsg);
+			send_message(card, cmsg);
+			plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
+		} else {
+			capidrv_ncci *nccip;
+			capi_cmsg_answer(cmsg);
+			send_message(card, cmsg);
+
+			nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
+
+			if (!nccip) {
+				printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+				break;	/* $$$$ */
+			}
+			capi_fill_CONNECT_B3_REQ(cmsg,
+						 global.appid,
+						 card->msgid++,
+						 plcip->plci,	/* adr */
+						 0	/* NCPI */
+			);
+			nccip->msgid = cmsg->Messagenumber;
+			send_message(card, cmsg);
+			cmd.command = ISDN_STAT_DCONN;
+			cmd.driver = card->myid;
+			cmd.arg = plcip->chan;
+			card->interface.statcallb(&cmd);
+			plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
+			ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
+		}
+		break;
+
+	case CAPI_INFO_IND:	/* Controller/plci */
+
+		if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+			goto notfound;
+
+		if (cmsg->InfoNumber == 0x4000) {
+			if (cmsg->InfoElement[0] == 4) {
+				cmd.command = ISDN_STAT_CINF;
+				cmd.driver = card->myid;
+				cmd.arg = plcip->chan;
+				sprintf(cmd.parm.num, "%lu",
+					(unsigned long)
+					((__u32) cmsg->InfoElement[1]
+				  | ((__u32) (cmsg->InfoElement[2]) << 8)
+				 | ((__u32) (cmsg->InfoElement[3]) << 16)
+					 | ((__u32) (cmsg->InfoElement[4]) << 24)));
+				card->interface.statcallb(&cmd);
+				break;
+			}
+		}
+		printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg));
+		break;
+
+	case CAPI_CONNECT_ACTIVE_CONF:		/* plci */
+		goto ignored;
+	case CAPI_SELECT_B_PROTOCOL_CONF:	/* plci */
+		goto ignored;
+	case CAPI_FACILITY_IND:	/* Controller/plci/ncci */
+		goto ignored;
+	case CAPI_FACILITY_CONF:	/* Controller/plci/ncci */
+		goto ignored;
+
+	case CAPI_INFO_CONF:	/* Controller/plci */
+		goto ignored;
+
+	default:
+		printk(KERN_ERR "capidrv: got %s for plci 0x%x ???",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrPLCI);
+	}
+	return;
+      ignored:
+	printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n",
+	       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+	       cmsg->adr.adrPLCI);
+	return;
+      notfound:
+	printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n",
+	       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+	       cmsg->adr.adrPLCI);
+	return;
+}
+
+static void handle_ncci(_cmsg * cmsg)
+{
+	capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+	capidrv_plci *plcip;
+	capidrv_ncci *nccip;
+	isdn_ctrl cmd;
+
+	if (!card) {
+		printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrController & 0x7f);
+		return;
+	}
+	switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+	case CAPI_CONNECT_B3_ACTIVE_IND:	/* ncci */
+		if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+			goto notfound;
+
+		capi_cmsg_answer(cmsg);
+		send_message(card, cmsg);
+		ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
+
+		cmd.command = ISDN_STAT_BCONN;
+		cmd.driver = card->myid;
+		cmd.arg = nccip->chan;
+		card->interface.statcallb(&cmd);
+
+		printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n",
+		       nccip->chan, nccip->ncci);
+		break;
+
+	case CAPI_CONNECT_B3_ACTIVE_CONF:	/* ncci */
+		goto ignored;
+
+	case CAPI_CONNECT_B3_IND:	/* ncci */
+
+		plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
+		if (plcip) {
+			nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
+			if (nccip) {
+				ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
+				capi_fill_CONNECT_B3_RESP(cmsg,
+							  global.appid,
+							  card->msgid++,
+							  nccip->ncci,	/* adr */
+							  0,	/* Reject */
+							  0	/* NCPI */
+				);
+				send_message(card, cmsg);
+				ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
+				break;
+			}
+			printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+		} else {
+			printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->adr.adrNCCI);
+		}
+		capi_fill_CONNECT_B3_RESP(cmsg,
+					  global.appid,
+					  card->msgid++,
+					  cmsg->adr.adrNCCI,
+					  2,	/* Reject */
+					  0	/* NCPI */
+		);
+		send_message(card, cmsg);
+		break;
+
+	case CAPI_CONNECT_B3_CONF:	/* ncci */
+
+		if (!(nccip = find_ncci_by_msgid(card,
+						 cmsg->adr.adrNCCI,
+						 cmsg->Messagenumber)))
+			goto notfound;
+
+		nccip->ncci = cmsg->adr.adrNCCI;
+		if (cmsg->Info) {
+			printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Info, capi_info2str(cmsg->Info), 
+			       cmsg->adr.adrNCCI);
+		}
+
+		if (cmsg->Info)
+			ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
+		else
+			ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
+		break;
+
+	case CAPI_CONNECT_B3_T90_ACTIVE_IND:	/* ncci */
+		capi_cmsg_answer(cmsg);
+		send_message(card, cmsg);
+		break;
+
+	case CAPI_DATA_B3_IND:	/* ncci */
+		/* handled in handle_data() */
+		goto ignored;
+
+	case CAPI_DATA_B3_CONF:	/* ncci */
+		if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+			goto notfound;
+
+		cmd.command = ISDN_STAT_BSENT;
+		cmd.driver = card->myid;
+		cmd.arg = nccip->chan;
+		card->interface.statcallb(&cmd);
+
+		break;
+
+	case CAPI_DISCONNECT_B3_IND:	/* ncci */
+		if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+			goto notfound;
+
+		card->bchans[nccip->chan].disconnecting = 1;
+		ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
+		capi_cmsg_answer(cmsg);
+		send_message(card, cmsg);
+		ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
+		break;
+
+	case CAPI_DISCONNECT_B3_CONF:	/* ncci */
+		if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+			goto notfound;
+		if (cmsg->Info) {
+			printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+			   capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+			       cmsg->Info, capi_info2str(cmsg->Info), 
+			       cmsg->adr.adrNCCI);
+			ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
+		}
+		break;
+
+	case CAPI_RESET_B3_IND:	/* ncci */
+		capi_cmsg_answer(cmsg);
+		send_message(card, cmsg);
+		break;
+
+	case CAPI_RESET_B3_CONF:	/* ncci */
+		goto ignored;	/* $$$$ */
+
+	case CAPI_FACILITY_IND:	/* Controller/plci/ncci */
+		goto ignored;
+	case CAPI_FACILITY_CONF:	/* Controller/plci/ncci */
+		goto ignored;
+
+	default:
+		printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrNCCI);
+	}
+	return;
+      ignored:
+	printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n",
+	       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+	       cmsg->adr.adrNCCI);
+	return;
+      notfound:
+	printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+	       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+	       cmsg->adr.adrNCCI);
+}
+
+
+static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
+{
+	capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+	capidrv_ncci *nccip;
+
+	if (!card) {
+		printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrController & 0x7f);
+		return;
+	}
+	if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
+		printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+		       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+		       cmsg->adr.adrNCCI);
+		kfree_skb(skb, FREE_READ);
+		return;
+	}
+	(void) skb_pull(skb, CAPIMSG_LEN(skb->data));
+	card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
+	capi_cmsg_answer(cmsg);
+	send_message(card, cmsg);
+}
+
+static _cmsg s_cmsg;
+
+static void capidrv_signal(__u16 applid, __u32 dummy)
+{
+	struct sk_buff *skb = 0;
+
+	while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
+		capi_message2cmsg(&s_cmsg, skb->data);
+		if (debugmode > 1)
+			printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg));
+
+		if (s_cmsg.Command == CAPI_DATA_B3
+		    && s_cmsg.Subcommand == CAPI_IND) {
+			handle_data(&s_cmsg, skb);
+			continue;
+		}
+		kfree_skb(skb, FREE_READ);
+		if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
+			handle_controller(&s_cmsg);
+		else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
+			handle_plci(&s_cmsg);
+		else
+			handle_ncci(&s_cmsg);
+	}
+}
+
+/* ------------------------------------------------------------------- */
+
+static _cmsg cmdcmsg;
+
+static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
+{
+	switch (c->arg) {
+	default:
+		printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg);
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
+{
+	isdn_ctrl cmd;
+	struct capidrv_bchan *bchan;
+	struct capidrv_plci *plcip;
+
+	if (c->command == ISDN_CMD_IOCTL)
+		return capidrv_ioctl(c, card);
+
+	switch (c->command) {
+	case ISDN_CMD_DIAL:{
+			__u8 calling[ISDN_MSNLEN + 3];
+			__u8 called[ISDN_MSNLEN + 2];
+
+			if (debugmode)
+				printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
+					c->arg,
+				        c->parm.setup.phone,
+				        c->parm.setup.si1,
+				        c->parm.setup.si2,
+				        c->parm.setup.eazmsn);
+
+			bchan = &card->bchans[c->arg % card->nbchan];
+
+			if (bchan->plcip) {
+				printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
+			        	c->arg, 
+				        c->parm.setup.phone,
+				        c->parm.setup.si1,
+				        c->parm.setup.si2,
+				        c->parm.setup.eazmsn,
+				        bchan->plcip->plci);
+				return 0;
+			}
+			bchan->si1 = c->parm.setup.si1;
+			bchan->si2 = c->parm.setup.si2;
+
+			strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
+			strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
+
+			calling[0] = strlen(bchan->mynum) + 2;
+			calling[1] = 0;
+			calling[2] = 0x80;
+			strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
+
+			called[0] = strlen(bchan->num) + 1;
+			called[1] = 0x80;
+			strncpy(called + 2, bchan->num, ISDN_MSNLEN);
+
+			capi_fill_CONNECT_REQ(&cmdcmsg,
+					      global.appid,
+					      card->msgid++,
+					      1,	/* adr */
+					  si2cip(bchan->si1, bchan->si2),	/* cipvalue */
+					      called,	/* CalledPartyNumber */
+					      calling,	/* CallingPartyNumber */
+					      0,	/* CalledPartySubaddress */
+					      0,	/* CallingPartySubaddress */
+					    b1prot(bchan->l2, bchan->l3),	/* B1protocol */
+					    b2prot(bchan->l2, bchan->l3),	/* B2protocol */
+					    b3prot(bchan->l2, bchan->l3),	/* B3protocol */
+					      0,	/* B1configuration */
+					      0,	/* B2configuration */
+					      0,	/* B3configuration */
+					      0,	/* BC */
+					      0,	/* LLC */
+					      0,	/* HLC */
+					      0,	/* BChannelinformation */
+					      0,	/* Keypadfacility */
+					      0,	/* Useruserdata */
+					      0		/* Facilitydataarray */
+			    );
+			if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
+				cmd.command = ISDN_STAT_DHUP;
+				cmd.driver = card->myid;
+				cmd.arg = (c->arg % card->nbchan);
+				card->interface.statcallb(&cmd);
+				return -1;
+			}
+			plcip->msgid = cmdcmsg.Messagenumber;
+			plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
+			send_message(card, &cmdcmsg);
+			return 0;
+		}
+
+	case ISDN_CMD_ACCEPTD:
+
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n",
+			       c->arg);
+		bchan = &card->bchans[c->arg % card->nbchan];
+
+		capi_fill_CONNECT_RESP(&cmdcmsg,
+				       global.appid,
+				       card->msgid++,
+				       bchan->plcip->plci,	/* adr */
+				       0,	/* Reject */
+				       b1prot(bchan->l2, bchan->l3),	/* B1protocol */
+				       b2prot(bchan->l2, bchan->l3),	/* B2protocol */
+				       b3prot(bchan->l2, bchan->l3),	/* B3protocol */
+				       0,	/* B1configuration */
+				       0,	/* B2configuration */
+				       0,	/* B3configuration */
+				       0,	/* ConnectedNumber */
+				       0,	/* ConnectedSubaddress */
+				       0,	/* LLC */
+				       0,	/* BChannelinformation */
+				       0,	/* Keypadfacility */
+				       0,	/* Useruserdata */
+				       0	/* Facilitydataarray */
+		);
+		capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
+		plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
+		send_message(card, &cmdcmsg);
+		return 0;
+
+	case ISDN_CMD_ACCEPTB:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n",
+			       c->arg);
+		return -ENOSYS;
+
+	case ISDN_CMD_HANGUP:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n",
+			       c->arg);
+		bchan = &card->bchans[c->arg % card->nbchan];
+
+		if (bchan->disconnecting) {
+			if (debugmode)
+				printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n",
+				       c->arg);
+			return 0;
+		}
+		if (bchan->nccip) {
+			bchan->disconnecting = 1;
+			capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
+						    global.appid,
+						    card->msgid++,
+						    bchan->nccip->ncci,
+						    0	/* NCPI */
+			);
+			ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
+			send_message(card, &cmdcmsg);
+		} else if (bchan->plcip) {
+			bchan->disconnecting = 1;
+			if (bchan->plcip->state == ST_PLCI_INCOMING) {
+				/* just ignore, we a called from isdn_status_callback(),
+				 * which will return 0 or 2, this is handled by the
+				 * CONNECT_IND handler
+				 */
+			} else {
+				capi_fill_DISCONNECT_REQ(&cmdcmsg,
+							 global.appid,
+							 card->msgid++,
+						      bchan->plcip->plci,
+							 0,	/* BChannelinformation */
+							 0,	/* Keypadfacility */
+							 0,	/* Useruserdata */
+							 0	/* Facilitydataarray */
+				);
+				plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
+				send_message(card, &cmdcmsg);
+			}
+		}
+/* ready */
+
+	case ISDN_CMD_SETL2:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n",
+			       (c->arg & 0xff), (c->arg >> 8));
+		bchan = &card->bchans[c->arg % card->nbchan];
+		bchan->l2 = (c->arg >> 8);
+		return 0;
+
+	case ISDN_CMD_SETL3:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n",
+			       (c->arg & 0xff), (c->arg >> 8));
+		bchan = &card->bchans[c->arg % card->nbchan];
+		bchan->l3 = (c->arg >> 8);
+		return 0;
+
+	case ISDN_CMD_SETEAZ:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n",
+			       c->parm.num, c->arg);
+		bchan = &card->bchans[c->arg % card->nbchan];
+		strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
+		return 0;
+
+	case ISDN_CMD_CLREAZ:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg);
+		bchan = &card->bchans[c->arg % card->nbchan];
+		bchan->msn[0] = 0;
+		return 0;
+
+	case ISDN_CMD_LOCK:
+		if (debugmode > 1)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg);
+		MOD_INC_USE_COUNT;
+		break;
+
+	case ISDN_CMD_UNLOCK:
+		if (debugmode > 1)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg);
+		MOD_DEC_USE_COUNT;
+		break;
+
+/* never called */
+	case ISDN_CMD_GETL2:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n");
+		return -ENODEV;
+	case ISDN_CMD_GETL3:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n");
+		return -ENODEV;
+	case ISDN_CMD_GETEAZ:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n");
+		return -ENODEV;
+	case ISDN_CMD_SETSIL:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n");
+		return -ENODEV;
+	case ISDN_CMD_GETSIL:
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n");
+		return -ENODEV;
+	default:
+		printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int if_command(isdn_ctrl * c)
+{
+	capidrv_contr *card = findcontrbydriverid(c->driver);
+
+	if (card)
+		return capidrv_command(c, card);
+
+	printk(KERN_ERR
+	     "capidrv: if_command %d called with invalid driverId %d!\n",
+	       c->command, c->driver);
+	return -ENODEV;
+}
+
+static _cmsg sendcmsg;
+
+static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+{
+	capidrv_contr *card = findcontrbydriverid(id);
+	capidrv_bchan *bchan;
+	capidrv_ncci *nccip;
+	int len = skb->len;
+	size_t msglen;
+	__u16 errcode;
+
+	if (!card) {
+		printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
+		       id);
+		return 0;
+	}
+	bchan = &card->bchans[channel % card->nbchan];
+	nccip = bchan->nccip;
+	if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
+		printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n",
+		       card->name, channel);
+		return 0;
+	}
+	capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
+			      nccip->ncci,	/* adr */
+			      (__u32) skb->data,	/* Data */
+			      skb->len,		/* DataLength */
+			      nccip->datahandle++,	/* DataHandle */
+			      0	/* Flags */
+	    );
+	capi_cmsg2message(&sendcmsg, sendcmsg.buf);
+	msglen = CAPIMSG_LEN(sendcmsg.buf);
+	if (skb_headroom(skb) < msglen) {
+		struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len);
+		if (!nskb) {
+			printk(KERN_ERR "capidrv: if_sendbuf: no memory\n");
+			return 0;
+		}
+#if 0
+		printk(KERN_DEBUG "capidrv: only %d bytes headroom\n",
+		       skb_headroom(skb));
+#endif
+                SET_SKB_FREE(nskb);
+		memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
+		memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
+		errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
+		switch (errcode) {
+		case CAPI_NOERROR:
+			dev_kfree_skb(skb, FREE_WRITE);
+			return len;
+		case CAPI_SENDQUEUEFULL:
+			dev_kfree_skb(nskb, FREE_WRITE);
+			return 0;
+		default:
+			return -1;
+		}
+	} else {
+		memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
+		errcode = (*capifuncs->capi_put_message) (global.appid, skb);
+		switch (errcode) {
+		case CAPI_NOERROR:
+			return len;
+		case CAPI_SENDQUEUEFULL:
+			return 0;
+		default:
+			return -1;
+		}
+	}
+}
+
+static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
+{
+	capidrv_contr *card;
+	isdn_ctrl cmd;
+	char id[20];
+	int i;
+
+	sprintf(id, "capidrv-%d", contr);
+	if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		 "capidrv: (%s) Could not allocate contr-struct.\n", id);
+		return -1;
+	}
+	memset(card, 0, sizeof(capidrv_contr));
+	strcpy(card->name, id);
+	card->contrnr = contr;
+	card->nbchan = profp->nbchannel;
+	card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
+	if (!card->bchans) {
+		printk(KERN_WARNING
+		"capidrv: (%s) Could not allocate bchan-structs.\n", id);
+		kfree(card);
+		return -1;
+	}
+	card->interface.channels = profp->nbchannel;
+	card->interface.maxbufsize = 2048;
+	card->interface.command = if_command;
+	card->interface.writebuf_skb = if_sendbuf;
+	card->interface.writecmd = 0;
+	card->interface.readstat = 0;
+	card->interface.features = ISDN_FEATURE_L2_X75I |
+	    ISDN_FEATURE_L2_X75UI |
+	    ISDN_FEATURE_L2_X75BUI |
+	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L2_TRANS |
+	    ISDN_FEATURE_L3_TRANS |
+	    ISDN_FEATURE_P_UNKNOWN;
+	card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
+	strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+	card->next = global.contr_list;
+	global.contr_list = card;
+	global.ncontr++;
+
+	if (!register_isdn(&card->interface)) {
+		global.contr_list = global.contr_list->next;
+		printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
+		kfree(card->bchans);
+		kfree(card);
+		return -1;
+	}
+	card->myid = card->interface.channels;
+
+	memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
+	for (i = 0; i < card->nbchan; i++) {
+		card->bchans[i].contr = card;
+	}
+
+	cmd.driver = card->myid;
+	cmd.command = ISDN_STAT_RUN;
+	card->interface.statcallb(&cmd);
+
+	card->cipmask = 1;	/* any */
+	card->cipmask2 = 0;
+
+	capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
+			     card->msgid++,
+			     contr,	/* controller */
+			     1 << 6,	/* Infomask */
+			     card->cipmask,
+			     card->cipmask2,
+			     0, 0);
+	send_message(card, &cmdcmsg);
+	listen_change_state(card, EV_LISTEN_REQ);
+
+	printk(KERN_INFO "%s: now up (%d B channels)\n",
+		card->name, card->nbchan);
+
+	return 0;
+}
+
+static int capidrv_delcontr(__u16 contr)
+{
+	capidrv_contr **pp, *card;
+	isdn_ctrl cmd;
+	int i;
+
+	for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
+		if ((*pp)->contrnr == contr)
+			break;
+	}
+	if (!*pp) {
+		printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
+		return -1;
+	}
+	card = *pp;
+	*pp = (*pp)->next;
+	global.ncontr--;
+
+	for (i = 0; i < card->nbchan; i++) {
+		if (card->bchans[i].nccip)
+			free_ncci(card, card->bchans[i].nccip);
+		if (card->bchans[i].plcip)
+			free_plci(card, card->bchans[i].plcip);
+		if (card->plci_list)
+			printk(KERN_ERR "capidrv: bug in free_plci()\n");
+	}
+	kfree(card->bchans);
+
+	cmd.command = ISDN_STAT_UNLOAD;
+	cmd.driver = card->myid;
+	card->interface.statcallb(&cmd);
+
+	printk(KERN_INFO "%s: now down.\n", card->name);
+
+	kfree(card);
+
+	return 0;
+}
+
+
+static void lower_callback(unsigned int cmd, __u16 contr, void *data)
+{
+	switch (cmd) {
+	case KCI_CONTRUP:
+		(void) capidrv_addcontr(contr, (capi_profile *) data);
+		break;
+	case KCI_CONTRDOWN:
+		(void) capidrv_delcontr(contr);
+		break;
+	}
+}
+
+static struct capi_interface_user cuser = {
+	"capidrv",
+	lower_callback
+};
+
+#ifdef MODULE
+#define capidrv_init init_module
+#endif
+
+int capidrv_init(void)
+{
+	struct capi_register_params rparam;
+	capi_profile profile;
+	char rev[10];
+	char *p;
+	__u32 ncontr, contr;
+	__u16 errcode;
+
+	capifuncs = attach_capi_interface(&cuser);
+
+	if (!capifuncs)
+		return -EIO;
+
+#ifndef HAS_NEW_SYMTAB
+	/* No symbols to export, hide all symbols */
+	register_symtab(NULL);
+#endif
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else
+		strcpy(rev, " ??? ");
+
+	rparam.level3cnt = 2;
+	rparam.datablkcnt = 8;
+	rparam.datablklen = 2048;
+	errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
+	if (errcode) {
+		detach_capi_interface(&cuser);
+		return -EIO;
+	}
+
+	errcode = (*capifuncs->capi_get_profile) (0, &profile);
+	if (errcode != CAPI_NOERROR) {
+		(void) (*capifuncs->capi_release) (global.appid);
+		detach_capi_interface(&cuser);
+		return -EIO;
+	}
+
+	(void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0);
+
+	ncontr = profile.ncontroller;
+	for (contr = 1; contr <= ncontr; contr++) {
+		errcode = (*capifuncs->capi_get_profile) (contr, &profile);
+		if (errcode != CAPI_NOERROR)
+			continue;
+		(void) capidrv_addcontr(contr, &profile);
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	capidrv_contr *card, *next;
+	char rev[10];
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else {
+		strcpy(rev, " ??? ");
+	}
+
+	for (card = global.contr_list; card; card = next) {
+		next = card->next;
+		capidrv_delcontr(card->contrnr);
+	}
+
+	(void) (*capifuncs->capi_release) (global.appid);
+	detach_capi_interface(&cuser);
+
+	printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
+}
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capidrv.h linux-2.0.31-pre3/drivers/isdn/avmb1/capidrv.h
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capidrv.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capidrv.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,111 @@
+/*
+ * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidrv.h,v $
+ * Revision 1.1  1997/03/04 21:50:33  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+#ifndef __CAPIDRV_H__
+#define __CAPIDRV_H__
+
+/*
+ * LISTEN state machine
+ */
+#define ST_LISTEN_NONE			0	/* L-0 */
+#define ST_LISTEN_WAIT_CONF		1	/* L-0.1 */
+#define ST_LISTEN_ACTIVE		2	/* L-1 */
+#define ST_LISTEN_ACTIVE_WAIT_CONF	3	/* L-1.1 */
+
+
+#define EV_LISTEN_REQ			1	/* L-0 -> L-0.1
+						   L-1 -> L-1.1 */
+#define EV_LISTEN_CONF_ERROR		2	/* L-0.1 -> L-0
+						   L-1.1 -> L-1 */
+#define EV_LISTEN_CONF_EMPTY		3	/* L-0.1 -> L-0
+						   L-1.1 -> L-0 */
+#define EV_LISTEN_CONF_OK		4	/* L-0.1 -> L-1
+						   L-1.1 -> L.1 */
+
+/*
+ * per plci state machine
+ */
+#define ST_PLCI_NONE			0	/* P-0 */
+#define ST_PLCI_OUTGOING 		1	/* P-0.1 */
+#define ST_PLCI_ALLOCATED		2	/* P-1 */
+#define ST_PLCI_ACTIVE			3	/* P-ACT */
+#define ST_PLCI_INCOMING		4	/* P-2 */
+#define ST_PLCI_FACILITY_IND		5	/* P-3 */
+#define ST_PLCI_ACCEPTING		6	/* P-4 */
+#define ST_PLCI_DISCONNECTING		7	/* P-5 */
+#define ST_PLCI_DISCONNECTED		8	/* P-6 */
+
+#define EV_PLCI_CONNECT_REQ		1	/* P-0 -> P-0.1 */
+#define EV_PLCI_CONNECT_CONF_ERROR	2	/* P-0.1 -> P-0 */
+#define EV_PLCI_CONNECT_CONF_OK		3	/* P-0.1 -> P-1 */
+#define EV_PLCI_FACILITY_IND_UP		4	/* P-0 -> P-1 */
+#define EV_PLCI_CONNECT_IND		5	/* P-0 -> P-2 */
+#define EV_PLCI_CONNECT_ACTIVE_IND	6	/* P-1 -> P-ACT */
+#define EV_PLCI_CONNECT_REJECT		7	/* P-2 -> P-5
+						   P-3 -> P-5 */
+#define EV_PLCI_DISCONNECT_REQ		8	/* P-1 -> P-5
+						   P-2 -> P-5
+						   P-3 -> P-5
+						   P-4 -> P-5
+						   P-ACT -> P-5 */
+#define EV_PLCI_DISCONNECT_IND		9	/* P-1 -> P-6
+						   P-2 -> P-6
+						   P-3 -> P-6
+						   P-4 -> P-6
+						   P-5 -> P-6
+						   P-ACT -> P-6 */
+#define EV_PLCI_FACILITY_IND_DOWN	10	/* P-0.1 -> P-5
+						   P-1 -> P-5
+						   P-ACT -> P-5
+						   P-2 -> P-5
+						   P-3 -> P-5
+						   P-4 -> P-5 */
+#define EV_PLCI_DISCONNECT_RESP		11	/* P-6 -> P-0 */
+#define EV_PLCI_CONNECT_RESP		12	/* P-6 -> P-0 */
+
+/*
+ * per ncci state machine
+ */
+#define ST_NCCI_PREVIOUS			-1
+#define ST_NCCI_NONE				0	/* N-0 */
+#define ST_NCCI_OUTGOING			1	/* N-0.1 */
+#define ST_NCCI_INCOMING			2	/* N-1 */
+#define ST_NCCI_ALLOCATED			3	/* N-2 */
+#define ST_NCCI_ACTIVE				4	/* N-ACT */
+#define ST_NCCI_RESETING			5	/* N-3 */
+#define ST_NCCI_DISCONNECTING			6	/* N-4 */
+#define ST_NCCI_DISCONNECTED			7	/* N-5 */
+
+#define EV_NCCI_CONNECT_B3_REQ			1	/* N-0 -> N-0.1 */
+#define EV_NCCI_CONNECT_B3_IND			2	/* N-0 -> N.1 */
+#define EV_NCCI_CONNECT_B3_CONF_OK		3	/* N-0.1 -> N.2 */
+#define EV_NCCI_CONNECT_B3_CONF_ERROR		4	/* N-0.1 -> N.0 */
+#define EV_NCCI_CONNECT_B3_REJECT		5	/* N-1 -> N-4 */
+#define EV_NCCI_CONNECT_B3_RESP			6	/* N-1 -> N-2 */
+#define EV_NCCI_CONNECT_B3_ACTIVE_IND		7	/* N-2 -> N-ACT */
+#define EV_NCCI_RESET_B3_REQ			8	/* N-ACT -> N-3 */
+#define EV_NCCI_RESET_B3_IND			9	/* N-3 -> N-ACT */
+#define EV_NCCI_DISCONNECT_B3_IND		10	/* N-4 -> N.5 */
+#define EV_NCCI_DISCONNECT_B3_CONF_ERROR	11	/* N-4 -> previous */
+#define EV_NCCI_DISCONNECT_B3_REQ		12	/* N-1 -> N-4
+							   N-2 -> N-4
+							   N-3 -> N-4
+							   N-ACT -> N-4 */
+#define EV_NCCI_DISCONNECT_B3_RESP		13	/* N-5 -> N-0 */
+
+#endif				/* __CAPIDRV_H__ */
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capiutil.c linux-2.0.31-pre3/drivers/isdn/avmb1/capiutil.c
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capiutil.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capiutil.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,974 @@
+/*
+ * $Id: capiutil.c,v 1.3 1997/05/18 09:24:18 calle Exp $
+ *
+ * CAPI 2.0 convert capi message to capi message struct
+ *
+ * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
+ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capiutil.c,v $
+ * Revision 1.3  1997/05/18 09:24:18  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2  1997/03/05 21:22:13  fritz
+ * Fix: Symbols have to be exported unconditionally.
+ *
+ * Revision 1.1  1997/03/04 21:50:34  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+
+#include "compat.h"
+#include "capiutil.h"
+
+/* from CAPI2.0 DDK AVM Berlin GmbH */
+
+#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+char *capi_info2str(__u16 reason)
+{
+    return "..";
+}
+#else
+char *capi_info2str(__u16 reason)
+{
+    switch (reason) {
+
+/*-- informative values (corresponding message was processed) -----*/
+	case 0x0001:
+	   return "NCPI not supported by current protocol, NCPI ignored";
+	case 0x0002:
+	   return "Flags not supported by current protocol, flags ignored";
+	case 0x0003:
+	   return "Alert already sent by another application";
+
+/*-- error information concerning CAPI_REGISTER -----*/
+	case 0x1001:
+	   return "Too many applications";
+	case 0x1002:
+	   return "Logical block size to small, must be at least 128 Bytes";
+	case 0x1003:
+	   return "Buffer exceeds 64 kByte";
+	case 0x1004:
+	   return "Message buffer size too small, must be at least 1024 Bytes";
+	case 0x1005:
+	   return "Max. number of logical connections not supported";
+	case 0x1006:
+	   return "Reserved";
+	case 0x1007:
+	   return "The message could not be accepted because of an internal busy condition";
+	case 0x1008:
+	   return "OS resource error (no memory ?)";
+	case 0x1009:
+	   return "CAPI not installed";
+	case 0x100A:
+	   return "Controller does not support external equipment";
+	case 0x100B:
+	   return "Controller does only support external equipment";
+
+/*-- error information concerning message exchange functions -----*/
+	case 0x1101:
+	   return "Illegal application number";
+	case 0x1102:
+	   return "Illegal command or subcommand or message length less than 12 bytes";
+	case 0x1103:
+	   return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
+	case 0x1104:
+	   return "Queue is empty";
+	case 0x1105:
+	   return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
+	case 0x1106:
+	   return "Unknown notification parameter";
+	case 0x1107:
+	   return "The Message could not be accepted because of an internal busy condition";
+	case 0x1108:
+	   return "OS Resource error (no memory ?)";
+	case 0x1109:
+	   return "CAPI not installed";
+	case 0x110A:
+	   return "Controller does not support external equipment";
+	case 0x110B:
+	   return "Controller does only support external equipment";
+
+/*-- error information concerning resource / coding problems -----*/
+	case 0x2001:
+	   return "Message not supported in current state";
+	case 0x2002:
+	   return "Illegal Controller / PLCI / NCCI";
+	case 0x2003:
+	   return "Out of PLCI";
+	case 0x2004:
+	   return "Out of NCCI";
+	case 0x2005:
+	   return "Out of LISTEN";
+	case 0x2006:
+	   return "Out of FAX resources (protocol T.30)";
+	case 0x2007:
+	   return "Illegal message parameter coding";
+
+/*-- error information concerning requested services  -----*/
+	case 0x3001:
+	   return "B1 protocol not supported";
+	case 0x3002: 
+	   return "B2 protocol not supported";
+	case 0x3003: 
+	   return "B3 protocol not supported";
+	case 0x3004: 
+	   return "B1 protocol parameter not supported";
+	case 0x3005: 
+	   return "B2 protocol parameter not supported";
+	case 0x3006: 
+	   return "B3 protocol parameter not supported";
+	case 0x3007: 
+	   return "B protocol combination not supported";
+	case 0x3008: 
+	   return "NCPI not supported";
+	case 0x3009: 
+	   return "CIP Value unknown";
+	case 0x300A: 
+	   return "Flags not supported (reserved bits)";
+	case 0x300B: 
+	   return "Facility not supported";
+	case 0x300C: 
+	   return "Data length not supported by current protocol";
+	case 0x300D: 
+	   return "Reset procedure not supported by current protocol";
+
+/*-- informations about the clearing of a physical connection -----*/
+	case 0x3301: 
+	   return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
+	case 0x3302: 
+	   return "Protocol error layer 2";
+	case 0x3303: 
+	   return "Protocol error layer 3";
+	case 0x3304: 
+	   return "Another application got that call";
+/*-- T.30 specific reasons -----*/
+	case 0x3311: 
+	   return "Connecting not successful (remote station is no FAX G3 machine)";
+	case 0x3312: 
+	   return "Connecting not successful (training error)";
+	case 0x3313: 
+	   return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
+	case 0x3314: 
+	   return "Disconnected during transfer (remote abort)";
+	case 0x3315: 
+	   return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
+	case 0x3316: 
+	   return "Disconnected during transfer (local tx data underrun)";
+	case 0x3317: 
+	   return "Disconnected during transfer (local rx data overflow)";
+	case 0x3318: 
+	   return "Disconnected during transfer (local abort)";
+	case 0x3319: 
+	   return "Illegal parameter coding (e.g. SFF coding error)";
+
+/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
+	case 0x3481: return "Unallocated (unassigned) number";
+	case 0x3482: return "No route to specified transit network";
+	case 0x3483: return "No route to destination";
+	case 0x3486: return "Channel unacceptable";
+	case 0x3487: 
+	   return "Call awarded and being delivered in an established channel";
+	case 0x3490: return "Normal call clearing";
+	case 0x3491: return "User busy";
+	case 0x3492: return "No user responding";
+	case 0x3493: return "No answer from user (user alerted)";
+	case 0x3495: return "Call rejected";
+	case 0x3496: return "Number changed";
+	case 0x349A: return "Non-selected user clearing";
+	case 0x349B: return "Destination out of order";
+	case 0x349C: return "Invalid number format";
+	case 0x349D: return "Facility rejected";
+	case 0x349E: return "Response to STATUS ENQUIRY";
+	case 0x349F: return "Normal, unspecified";
+	case 0x34A2: return "No circuit / channel available";
+	case 0x34A6: return "Network out of order";
+	case 0x34A9: return "Temporary failure";
+	case 0x34AA: return "Switching equipment congestion";
+	case 0x34AB: return "Access information discarded";
+	case 0x34AC: return "Requested circuit / channel not available";
+	case 0x34AF: return "Resources unavailable, unspecified";
+	case 0x34B1: return "Quality of service unavailable";
+	case 0x34B2: return "Requested facility not subscribed";
+	case 0x34B9: return "Bearer capability not authorized";
+	case 0x34BA: return "Bearer capability not presently available";
+	case 0x34BF: return "Service or option not available, unspecified";
+	case 0x34C1: return "Bearer capability not implemented";
+	case 0x34C2: return "Channel type not implemented";
+	case 0x34C5: return "Requested facility not implemented";
+	case 0x34C6: return "Only restricted digital information bearer capability is available";
+	case 0x34CF: return "Service or option not implemented, unspecified";
+	case 0x34D1: return "Invalid call reference value";
+	case 0x34D2: return "Identified channel does not exist";
+	case 0x34D3: return "A suspended call exists, but this call identity does not";
+	case 0x34D4: return "Call identity in use";
+	case 0x34D5: return "No call suspended";
+	case 0x34D6: return "Call having the requested call identity has been cleared";
+	case 0x34D8: return "Incompatible destination";
+	case 0x34DB: return "Invalid transit network selection";
+	case 0x34DF: return "Invalid message, unspecified";
+	case 0x34E0: return "Mandatory information element is missing";
+	case 0x34E1: return "Message type non-existent or not implemented";
+	case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
+	case 0x34E3: return "Information element non-existent or not implemented";
+	case 0x34E4: return "Invalid information element contents";
+	case 0x34E5: return "Message not compatible with call state";
+	case 0x34E6: return "Recovery on timer expiry";
+	case 0x34EF: return "Protocol error, unspecified";
+	case 0x34FF: return "Interworking, unspecified";
+
+	default: return "No additional information";
+    }
+}
+#endif
+
+typedef struct {
+	int typ;
+	size_t off;
+} _cdef;
+
+#define _CBYTE	       1
+#define _CWORD	       2
+#define _CDWORD        3
+#define _CSTRUCT       4
+#define _CMSTRUCT      5
+#define _CEND	       6
+
+static _cdef cdef[] =
+{
+    /*00 */ 
+ {_CEND},
+    /*01 */ 
+ {_CEND},
+    /*02 */ 
+ {_CEND},
+    /*03 */ 
+ {_CDWORD, offsetof(_cmsg, adr.adrController)},
+    /*04 */ 
+ {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
+    /*05 */ 
+ {_CSTRUCT, offsetof(_cmsg, B1configuration)},
+    /*06 */ 
+ {_CWORD, offsetof(_cmsg, B1protocol)},
+    /*07 */ 
+ {_CSTRUCT, offsetof(_cmsg, B2configuration)},
+    /*08 */ 
+ {_CWORD, offsetof(_cmsg, B2protocol)},
+    /*09 */ 
+ {_CSTRUCT, offsetof(_cmsg, B3configuration)},
+    /*0a */ 
+ {_CWORD, offsetof(_cmsg, B3protocol)},
+    /*0b */ 
+ {_CSTRUCT, offsetof(_cmsg, BC)},
+    /*0c */ 
+ {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
+    /*0d */ 
+ {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
+    /*0e */ 
+ {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
+    /*0f */ 
+ {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
+    /*10 */ 
+ {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
+    /*11 */ 
+ {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
+    /*12 */ 
+ {_CDWORD, offsetof(_cmsg, CIPmask)},
+    /*13 */ 
+ {_CDWORD, offsetof(_cmsg, CIPmask2)},
+    /*14 */ 
+ {_CWORD, offsetof(_cmsg, CIPValue)},
+    /*15 */ 
+ {_CDWORD, offsetof(_cmsg, Class)},
+    /*16 */ 
+ {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
+    /*17 */ 
+ {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
+    /*18 */ 
+ {_CDWORD, offsetof(_cmsg, Data)},
+    /*19 */ 
+ {_CWORD, offsetof(_cmsg, DataHandle)},
+    /*1a */ 
+ {_CWORD, offsetof(_cmsg, DataLength)},
+    /*1b */ 
+ {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
+    /*1c */ 
+ {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
+    /*1d */ 
+ {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
+    /*1e */ 
+ {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
+    /*1f */ 
+ {_CWORD, offsetof(_cmsg, FacilitySelector)},
+    /*20 */ 
+ {_CWORD, offsetof(_cmsg, Flags)},
+    /*21 */ 
+ {_CDWORD, offsetof(_cmsg, Function)},
+    /*22 */ 
+ {_CSTRUCT, offsetof(_cmsg, HLC)},
+    /*23 */ 
+ {_CWORD, offsetof(_cmsg, Info)},
+    /*24 */ 
+ {_CSTRUCT, offsetof(_cmsg, InfoElement)},
+    /*25 */ 
+ {_CDWORD, offsetof(_cmsg, InfoMask)},
+    /*26 */ 
+ {_CWORD, offsetof(_cmsg, InfoNumber)},
+    /*27 */ 
+ {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
+    /*28 */ 
+ {_CSTRUCT, offsetof(_cmsg, LLC)},
+    /*29 */ 
+ {_CSTRUCT, offsetof(_cmsg, ManuData)},
+    /*2a */ 
+ {_CDWORD, offsetof(_cmsg, ManuID)},
+    /*2b */ 
+ {_CSTRUCT, offsetof(_cmsg, NCPI)},
+    /*2c */ 
+ {_CWORD, offsetof(_cmsg, Reason)},
+    /*2d */ 
+ {_CWORD, offsetof(_cmsg, Reason_B3)},
+    /*2e */ 
+ {_CWORD, offsetof(_cmsg, Reject)},
+    /*2f */ 
+ {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
+};
+
+static unsigned char *cpars[] =
+{
+    /*00 */ 0,
+    /*01 ALERT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*02 CONNECT_REQ */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*03 */ 0,
+    /*04 DISCONNECT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*05 LISTEN_REQ */ (unsigned char *) "\x03\x25\x12\x13\x10\x11\x01",
+    /*06 */ 0,
+    /*07 */ 0,
+    /*08 INFO_REQ */ (unsigned char *) "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*09 FACILITY_REQ */ (unsigned char *) "\x03\x1f\x1e\x01",
+    /*0a SELECT_B_PROTOCOL_REQ */ (unsigned char *) "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
+    /*0b CONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+    /*0c */ 0,
+    /*0d DISCONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+    /*0e */ 0,
+    /*0f DATA_B3_REQ */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
+    /*10 RESET_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+    /*11 */ 0,
+    /*12 */ 0,
+    /*13 ALERT_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*14 CONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*15 */ 0,
+    /*16 DISCONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*17 LISTEN_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*18 MANUFACTURER_REQ */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+    /*19 */ 0,
+    /*1a INFO_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*1b FACILITY_CONF */ (unsigned char *) "\x03\x23\x1f\x1b\x01",
+    /*1c SELECT_B_PROTOCOL_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*1d CONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*1e */ 0,
+    /*1f DISCONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*20 */ 0,
+    /*21 DATA_B3_CONF */ (unsigned char *) "\x03\x19\x23\x01",
+    /*22 RESET_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+    /*23 */ 0,
+    /*24 */ 0,
+    /*25 */ 0,
+    /*26 CONNECT_IND */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*27 CONNECT_ACTIVE_IND */ (unsigned char *) "\x03\x16\x17\x28\x01",
+    /*28 DISCONNECT_IND */ (unsigned char *) "\x03\x2c\x01",
+    /*29 */ 0,
+    /*2a MANUFACTURER_CONF */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+    /*2b */ 0,
+    /*2c INFO_IND */ (unsigned char *) "\x03\x26\x24\x01",
+    /*2d FACILITY_IND */ (unsigned char *) "\x03\x1f\x1d\x01",
+    /*2e */ 0,
+    /*2f CONNECT_B3_IND */ (unsigned char *) "\x03\x2b\x01",
+    /*30 CONNECT_B3_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
+    /*31 DISCONNECT_B3_IND */ (unsigned char *) "\x03\x2d\x2b\x01",
+    /*32 */ 0,
+    /*33 DATA_B3_IND */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
+    /*34 RESET_B3_IND */ (unsigned char *) "\x03\x2b\x01",
+    /*35 CONNECT_B3_T90_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
+    /*36 */ 0,
+    /*37 */ 0,
+    /*38 CONNECT_RESP */ (unsigned char *) "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
+    /*39 CONNECT_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+    /*3a DISCONNECT_RESP */ (unsigned char *) "\x03\x01",
+    /*3b */ 0,
+    /*3c MANUFACTURER_IND */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+    /*3d */ 0,
+    /*3e INFO_RESP */ (unsigned char *) "\x03\x01",
+    /*3f FACILITY_RESP */ (unsigned char *) "\x03\x1f\x01",
+    /*40 */ 0,
+    /*41 CONNECT_B3_RESP */ (unsigned char *) "\x03\x2e\x2b\x01",
+    /*42 CONNECT_B3_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+    /*43 DISCONNECT_B3_RESP */ (unsigned char *) "\x03\x01",
+    /*44 */ 0,
+    /*45 DATA_B3_RESP */ (unsigned char *) "\x03\x19\x01",
+    /*46 RESET_B3_RESP */ (unsigned char *) "\x03\x01",
+    /*47 CONNECT_B3_T90_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+    /*48 */ 0,
+    /*49 */ 0,
+    /*4a */ 0,
+    /*4b */ 0,
+    /*4c */ 0,
+    /*4d */ 0,
+    /*4e MANUFACTURER_RESP */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+};
+
+/*-------------------------------------------------------*/
+
+#define byteTLcpy(x,y)        *(__u8 *)(x)=*(__u8 *)(y);
+#define wordTLcpy(x,y)        *(__u16 *)(x)=*(__u16 *)(y);
+#define dwordTLcpy(x,y)       memcpy(x,y,4);
+#define structTLcpy(x,y,l)    memcpy (x,y,l)
+#define structTLcpyovl(x,y,l) memmove (x,y,l)
+
+#define byteTRcpy(x,y)        *(__u8 *)(y)=*(__u8 *)(x);
+#define wordTRcpy(x,y)        *(__u16 *)(y)=*(__u16 *)(x);
+#define dwordTRcpy(x,y)       memcpy(y,x,4);
+#define structTRcpy(x,y,l)    memcpy (y,x,l)
+#define structTRcpyovl(x,y,l) memmove (y,x,l)
+
+/*-------------------------------------------------------*/
+static unsigned command_2_index(unsigned c, unsigned sc)
+{
+	if (c & 0x80)
+		c = 0x9 + (c & 0x0f);
+	else if (c <= 0x0f);
+	else if (c == 0x41)
+		c = 0x9 + 0x1;
+	else if (c == 0xff)
+		c = 0x00;
+	return (sc & 3) * (0x9 + 0x9) + c;
+}
+
+/*-------------------------------------------------------*/
+#define TYP (cdef[cmsg->par[cmsg->p]].typ)
+#define OFF (((__u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
+
+static void jumpcstruct(_cmsg * cmsg)
+{
+	unsigned layer;
+	for (cmsg->p++, layer = 1; layer;) {
+		/* $$$$$ assert (cmsg->p); */
+		cmsg->p++;
+		switch (TYP) {
+		case _CMSTRUCT:
+			layer++;
+			break;
+		case _CEND:
+			layer--;
+			break;
+		}
+	}
+}
+/*-------------------------------------------------------*/
+static void pars_2_message(_cmsg * cmsg)
+{
+
+	for (; TYP != _CEND; cmsg->p++) {
+		switch (TYP) {
+		case _CBYTE:
+			byteTLcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l++;
+			break;
+		case _CWORD:
+			wordTLcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l += 2;
+			break;
+		case _CDWORD:
+			dwordTLcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l += 4;
+			break;
+		case _CSTRUCT:
+			if (*(__u8 **) OFF == 0) {
+				*(cmsg->m + cmsg->l) = '\0';
+				cmsg->l++;
+			} else if (**(_cstruct *) OFF != 0xff) {
+				structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF);
+				cmsg->l += 1 + **(_cstruct *) OFF;
+			} else {
+				_cstruct s = *(_cstruct *) OFF;
+				structTLcpy(cmsg->m + cmsg->l, s, 3 + *(__u16 *) (s + 1));
+				cmsg->l += 3 + *(__u16 *) (s + 1);
+			}
+			break;
+		case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+			if (*(_cmstruct *) OFF == CAPI_DEFAULT) {
+				*(cmsg->m + cmsg->l) = '\0';
+				cmsg->l++;
+				jumpcstruct(cmsg);
+			}
+/*----- Metastruktur wird composed -----*/
+			else {
+				unsigned _l = cmsg->l;
+				unsigned _ls;
+				cmsg->l++;
+				cmsg->p++;
+				pars_2_message(cmsg);
+				_ls = cmsg->l - _l - 1;
+				if (_ls < 255)
+					(cmsg->m + _l)[0] = (__u8) _ls;
+				else {
+					structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
+					(cmsg->m + _l)[0] = 0xff;
+					wordTLcpy(cmsg->m + _l + 1, &_ls);
+				}
+			}
+			break;
+		}
+	}
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg)
+{
+	cmsg->m = msg;
+	cmsg->l = 8;
+	cmsg->p = 0;
+	cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
+
+	pars_2_message(cmsg);
+
+	wordTLcpy(msg + 0, &cmsg->l);
+	byteTLcpy(cmsg->m + 4, &cmsg->Command);
+	byteTLcpy(cmsg->m + 5, &cmsg->Subcommand);
+	wordTLcpy(cmsg->m + 2, &cmsg->ApplId);
+	wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber);
+
+	return 0;
+}
+
+/*-------------------------------------------------------*/
+static void message_2_pars(_cmsg * cmsg)
+{
+	for (; TYP != _CEND; cmsg->p++) {
+
+		switch (TYP) {
+		case _CBYTE:
+			byteTRcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l++;
+			break;
+		case _CWORD:
+			wordTRcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l += 2;
+			break;
+		case _CDWORD:
+			dwordTRcpy(cmsg->m + cmsg->l, OFF);
+			cmsg->l += 4;
+			break;
+		case _CSTRUCT:
+			*(__u8 **) OFF = cmsg->m + cmsg->l;
+
+			if (cmsg->m[cmsg->l] != 0xff)
+				cmsg->l += 1 + cmsg->m[cmsg->l];
+			else
+				cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+			break;
+		case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+			if (cmsg->m[cmsg->l] == '\0') {
+				*(_cmstruct *) OFF = CAPI_DEFAULT;
+				cmsg->l++;
+				jumpcstruct(cmsg);
+			} else {
+				unsigned _l = cmsg->l;
+				*(_cmstruct *) OFF = CAPI_COMPOSE;
+				cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
+				cmsg->p++;
+				message_2_pars(cmsg);
+			}
+			break;
+		}
+	}
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg)
+{
+	memset(cmsg, 0, sizeof(_cmsg));
+	cmsg->m = msg;
+	cmsg->l = 8;
+	cmsg->p = 0;
+	byteTRcpy(cmsg->m + 4, &cmsg->Command);
+	byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
+	cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
+
+	message_2_pars(cmsg);
+
+	wordTRcpy(msg + 0, &cmsg->l);
+	wordTRcpy(cmsg->m + 2, &cmsg->ApplId);
+	wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber);
+
+	return 0;
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
+			  __u8 _Command, __u8 _Subcommand,
+			  __u16 _Messagenumber, __u32 _Controller)
+{
+	memset(cmsg, 0, sizeof(_cmsg));
+	cmsg->ApplId = _ApplId;
+	cmsg->Command = _Command;
+	cmsg->Subcommand = _Subcommand;
+	cmsg->Messagenumber = _Messagenumber;
+	cmsg->adr.adrController = _Controller;
+	return 0;
+}
+
+/*-------------------------------------------------------*/
+
+static char *mnames[] =
+{
+	0,
+	"ALERT_REQ",
+	"CONNECT_REQ",
+	0,
+	"DISCONNECT_REQ",
+	"LISTEN_REQ",
+	0,
+	0,
+	"INFO_REQ",
+	"FACILITY_REQ",
+	"SELECT_B_PROTOCOL_REQ",
+	"CONNECT_B3_REQ",
+	0,
+	"DISCONNECT_B3_REQ",
+	0,
+	"DATA_B3_REQ",
+	"RESET_B3_REQ",
+	0,
+	0,
+	"ALERT_CONF",
+	"CONNECT_CONF",
+	0,
+	"DISCONNECT_CONF",
+	"LISTEN_CONF",
+	"MANUFACTURER_REQ",
+	0,
+	"INFO_CONF",
+	"FACILITY_CONF",
+	"SELECT_B_PROTOCOL_CONF",
+	"CONNECT_B3_CONF",
+	0,
+	"DISCONNECT_B3_CONF",
+	0,
+	"DATA_B3_CONF",
+	"RESET_B3_CONF",
+	0,
+	0,
+	0,
+	"CONNECT_IND",
+	"CONNECT_ACTIVE_IND",
+	"DISCONNECT_IND",
+	0,
+	"MANUFACTURER_CONF",
+	0,
+	"INFO_IND",
+	"FACILITY_IND",
+	0,
+	"CONNECT_B3_IND",
+	"CONNECT_B3_ACTIVE_IND",
+	"DISCONNECT_B3_IND",
+	0,
+	"DATA_B3_IND",
+	"RESET_B3_IND",
+	"CONNECT_B3_T90_ACTIVE_IND",
+	0,
+	0,
+	"CONNECT_RESP",
+	"CONNECT_ACTIVE_RESP",
+	"DISCONNECT_RESP",
+	0,
+	"MANUFACTURER_IND",
+	0,
+	"INFO_RESP",
+	"FACILITY_RESP",
+	0,
+	"CONNECT_B3_RESP",
+	"CONNECT_B3_ACTIVE_RESP",
+	"DISCONNECT_B3_RESP",
+	0,
+	"DATA_B3_RESP",
+	"RESET_B3_RESP",
+	"CONNECT_B3_T90_ACTIVE_RESP",
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	"MANUFACTURER_RESP"
+};
+
+char *capi_cmd2str(__u8 cmd, __u8 subcmd)
+{
+	return mnames[command_2_index(cmd, subcmd)];
+}
+
+
+/*-------------------------------------------------------*/
+/*-------------------------------------------------------*/
+
+static char *pnames[] =
+{
+    /*00 */ 0,
+    /*01 */ 0,
+    /*02 */ 0,
+    /*03 */ "Controller/PLCI/NCCI",
+    /*04 */ "AdditionalInfo",
+    /*05 */ "B1configuration",
+    /*06 */ "B1protocol",
+    /*07 */ "B2configuration",
+    /*08 */ "B2protocol",
+    /*09 */ "B3configuration",
+    /*0a */ "B3protocol",
+    /*0b */ "BC",
+    /*0c */ "BChannelinformation",
+    /*0d */ "BProtocol",
+    /*0e */ "CalledPartyNumber",
+    /*0f */ "CalledPartySubaddress",
+    /*10 */ "CallingPartyNumber",
+    /*11 */ "CallingPartySubaddress",
+    /*12 */ "CIPmask",
+    /*13 */ "CIPmask2",
+    /*14 */ "CIPValue",
+    /*15 */ "Class",
+    /*16 */ "ConnectedNumber",
+    /*17 */ "ConnectedSubaddress",
+    /*18 */ "Data",
+    /*19 */ "DataHandle",
+    /*1a */ "DataLength",
+    /*1b */ "FacilityConfirmationParameter",
+    /*1c */ "Facilitydataarray",
+    /*1d */ "FacilityIndicationParameter",
+    /*1e */ "FacilityRequestParameter",
+    /*1f */ "FacilitySelector",
+    /*20 */ "Flags",
+    /*21 */ "Function",
+    /*22 */ "HLC",
+    /*23 */ "Info",
+    /*24 */ "InfoElement",
+    /*25 */ "InfoMask",
+    /*26 */ "InfoNumber",
+    /*27 */ "Keypadfacility",
+    /*28 */ "LLC",
+    /*29 */ "ManuData",
+    /*2a */ "ManuID",
+    /*2b */ "NCPI",
+    /*2c */ "Reason",
+    /*2d */ "Reason_B3",
+    /*2e */ "Reject",
+    /*2f */ "Useruserdata"
+};
+
+
+static char buf[8192];
+static char *p = 0;
+
+#include <stdarg.h>
+
+/*-------------------------------------------------------*/
+static void bufprint(char *fmt,...)
+{
+	va_list f;
+	va_start(f, fmt);
+	vsprintf(p, fmt, f);
+	va_end(f);
+	p += strlen(p);
+}
+
+static void printstructlen(__u8 * m, unsigned len)
+{
+	unsigned hex = 0;
+	for (; len; len--, m++)
+		if (isalnum(*m) || *m == ' ') {
+			if (hex)
+				bufprint(">");
+			bufprint("%c", *m);
+			hex = 0;
+		} else {
+			if (!hex)
+				bufprint("<%02x", *m);
+			else
+				bufprint(" %02x", *m);
+			hex = 1;
+		}
+	if (hex)
+		bufprint(">");
+}
+
+static void printstruct(__u8 * m)
+{
+	unsigned len;
+	if (m[0] != 0xff) {
+		len = m[0];
+		m += 1;
+	} else {
+		len = ((__u16 *) (m + 1))[0];
+		m += 3;
+	}
+	printstructlen(m, len);
+}
+
+/*-------------------------------------------------------*/
+#define NAME (pnames[cmsg->par[cmsg->p]])
+
+static void protocol_message_2_pars(_cmsg * cmsg, int level)
+{
+	for (; TYP != _CEND; cmsg->p++) {
+		int slen = 29 + 3 - level;
+		int i;
+
+		bufprint("  ");
+		for (i = 0; i < level - 1; i++)
+			bufprint(" ");
+
+		switch (TYP) {
+		case _CBYTE:
+			bufprint("%-*s = 0x%x\n", slen, NAME, *(__u8 *) (cmsg->m + cmsg->l));
+			cmsg->l++;
+			break;
+		case _CWORD:
+			bufprint("%-*s = 0x%x\n", slen, NAME, *(__u16 *) (cmsg->m + cmsg->l));
+			cmsg->l += 2;
+			break;
+		case _CDWORD:
+			if (strcmp(NAME, "Data") == 0) {
+				bufprint("%-*s = ", slen, NAME);
+				printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
+					       *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
+				bufprint("\n");
+			} else
+				bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+			cmsg->l += 4;
+			break;
+		case _CSTRUCT:
+			bufprint("%-*s = ", slen, NAME);
+			if (cmsg->m[cmsg->l] == '\0')
+				bufprint("default");
+			else
+				printstruct(cmsg->m + cmsg->l);
+			bufprint("\n");
+			if (cmsg->m[cmsg->l] != 0xff)
+				cmsg->l += 1 + cmsg->m[cmsg->l];
+			else
+				cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+
+			break;
+
+		case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+			if (cmsg->m[cmsg->l] == '\0') {
+				bufprint("%-*s = default\n", slen, NAME);
+				cmsg->l++;
+				jumpcstruct(cmsg);
+			} else {
+				char *name = NAME;
+				unsigned _l = cmsg->l;
+				bufprint("%-*s\n", slen, name);
+				cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
+				cmsg->p++;
+				protocol_message_2_pars(cmsg, level + 1);
+			}
+			break;
+		}
+	}
+}
+/*-------------------------------------------------------*/
+char *capi_message2str(__u8 * msg)
+{
+
+	_cmsg cmsg;
+	p = buf;
+	p[0] = 0;
+
+	cmsg.m = msg;
+	cmsg.l = 8;
+	cmsg.p = 0;
+	byteTRcpy(cmsg.m + 4, &cmsg.Command);
+	byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
+	cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
+
+	bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
+		 mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
+		 ((unsigned short *) msg)[1],
+		 ((unsigned short *) msg)[3],
+		 ((unsigned short *) msg)[0]);
+
+	protocol_message_2_pars(&cmsg, 1);
+	return buf;
+}
+
+char *capi_cmsg2str(_cmsg * cmsg)
+{
+	p = buf;
+	p[0] = 0;
+	cmsg->l = 8;
+	cmsg->p = 0;
+	bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
+		 mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
+		 ((__u16 *) cmsg->m)[1],
+		 ((__u16 *) cmsg->m)[3],
+		 ((__u16 *) cmsg->m)[0]);
+	protocol_message_2_pars(cmsg, 1);
+	return buf;
+}
+
+
+#ifdef HAS_NEW_SYMTAB
+EXPORT_SYMBOL(capi_cmsg2message);
+EXPORT_SYMBOL(capi_message2cmsg);
+EXPORT_SYMBOL(capi_cmsg_header);
+EXPORT_SYMBOL(capi_cmd2str);
+EXPORT_SYMBOL(capi_cmsg2str);
+EXPORT_SYMBOL(capi_message2str);
+#else
+static struct symbol_table capifunc_syms =
+{
+#include <linux/symtab_begin.h>
+	X(capi_cmsg2message),
+	X(capi_message2cmsg),
+	X(capi_cmsg_header),
+	X(capi_cmd2str),
+	X(capi_cmsg2str),
+	X(capi_message2str),
+	X(capi_info2str),
+#include <linux/symtab_end.h>
+};
+#endif
+
+#ifdef MODULE
+
+int init_module(void)
+{
+#ifndef HAS_NEW_SYMTAB
+	register_symtab(&capifunc_syms);
+#endif
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/capiutil.h linux-2.0.31-pre3/drivers/isdn/avmb1/capiutil.h
--- linux-2.0.31-pre2/drivers/isdn/avmb1/capiutil.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/capiutil.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,501 @@
+/*
+ * $Id: capiutil.h,v 1.2 1997/05/18 09:24:19 calle Exp $
+ * 
+ * CAPI 2.0 defines & types
+ * 
+ * From CAPI 2.0 Development Kit AVM 1995 (capi20.h)
+ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: capiutil.h,v $
+ * Revision 1.2  1997/05/18 09:24:19  calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.1  1997/03/04 21:50:35  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+#ifndef __CAPIUTIL_H__
+#define __CAPIUTIL_H__
+
+#include <asm/types.h>
+
+#define	CAPIMSG_LEN(m)		(m[0] | (m[1] << 8))
+#define	CAPIMSG_APPID(m)	(m[2] | (m[3] << 8))
+#define	CAPIMSG_COMMAND(m)	(m[4])
+#define	CAPIMSG_SUBCOMMAND(m)	(m[5])
+#define	CAPIMSG_MSGID(m)	(m[6] | (m[7] << 8))
+#define CAPIMSG_CONTROLLER(m)	(m[8] & 0x7f)
+#define CAPIMSG_CONTROL(m)	(m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
+#define CAPIMSG_NCCI(m)		CAPIMSG_CONTROL(m)
+#define CAPIMSG_DATA(m)		(m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
+#define CAPIMSG_DATALEN(m)	(m[16] | (m[17]<<8))
+
+#define	CAPIMSG_SETAPPID(m, applid) \
+	do { \
+		((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
+		((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
+	} while (0)
+
+#define	CAPIMSG_SETDATA(m, data) \
+	do { \
+		((__u8 *)m)[12] = (__u32)(data) & 0xff; \
+		((__u8 *)m)[13] = ((__u32)(data) >> 8) & 0xff; \
+		((__u8 *)m)[14] = ((__u32)(data) >> 16) & 0xff; \
+		((__u8 *)m)[15] = ((__u32)(data) >> 24) & 0xff; \
+	} while (0)
+
+/*----- basic-type definitions -----*/
+
+typedef __u8 *_cstruct;
+
+typedef enum {
+	CAPI_COMPOSE,
+	CAPI_DEFAULT
+} _cmstruct;
+
+/*
+   The _cmsg structure contains all possible CAPI 2.0 parameter.
+   All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE
+   assembles the parameter and builds CAPI2.0 conform messages.
+   CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the
+   parameter in the _cmsg structure
+ */
+
+typedef struct {
+	/* Header */
+	__u16 ApplId;
+	__u8 Command;
+	__u8 Subcommand;
+	__u16 Messagenumber;
+
+	/* Parameter */
+	union {
+		__u32 adrController;
+		__u32 adrPLCI;
+		__u32 adrNCCI;
+	} adr;
+
+	_cmstruct AdditionalInfo;
+	_cstruct B1configuration;
+	__u16 B1protocol;
+	_cstruct B2configuration;
+	__u16 B2protocol;
+	_cstruct B3configuration;
+	__u16 B3protocol;
+	_cstruct BC;
+	_cstruct BChannelinformation;
+	_cmstruct BProtocol;
+	_cstruct CalledPartyNumber;
+	_cstruct CalledPartySubaddress;
+	_cstruct CallingPartyNumber;
+	_cstruct CallingPartySubaddress;
+	__u32 CIPmask;
+	__u32 CIPmask2;
+	__u16 CIPValue;
+	__u32 Class;
+	_cstruct ConnectedNumber;
+	_cstruct ConnectedSubaddress;
+	__u32 Data;
+	__u16 DataHandle;
+	__u16 DataLength;
+	_cstruct FacilityConfirmationParameter;
+	_cstruct Facilitydataarray;
+	_cstruct FacilityIndicationParameter;
+	_cstruct FacilityRequestParameter;
+	__u16 FacilitySelector;
+	__u16 Flags;
+	__u32 Function;
+	_cstruct HLC;
+	__u16 Info;
+	_cstruct InfoElement;
+	__u32 InfoMask;
+	__u16 InfoNumber;
+	_cstruct Keypadfacility;
+	_cstruct LLC;
+	_cstruct ManuData;
+	__u32 ManuID;
+	_cstruct NCPI;
+	__u16 Reason;
+	__u16 Reason_B3;
+	__u16 Reject;
+	_cstruct Useruserdata;
+
+	/* intern */
+	unsigned l, p;
+	unsigned char *par;
+	__u8 *m;
+
+	/* buffer to construct message */
+	__u8 buf[180];
+
+} _cmsg;
+
+/*
+ * capi_cmsg2message() assembles the parameter from _cmsg to a CAPI 2.0
+ * conform message
+ */
+unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg);
+
+/*
+ *  capi_message2cmsg disassembles a CAPI message an writes the parameter
+ *  into _cmsg for easy access
+ */
+unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg);
+
+/*
+ * capi_cmsg_header() fills the _cmsg structure with default values, so only
+ * parameter with non default values must be changed before sending the
+ * message.
+ */
+unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
+			  __u8 _Command, __u8 _Subcommand,
+			  __u16 _Messagenumber, __u32 _Controller);
+
+/*
+ * capi_info2str generated a readable string for Capi2.0 reasons.
+ */
+char *capi_info2str(__u16 reason);
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * Debugging / Tracing functions
+ */
+char *capi_cmd2str(__u8 cmd, __u8 subcmd);
+char *capi_cmsg2str(_cmsg * cmsg);
+char *capi_message2str(__u8 * msg);
+
+/*-----------------------------------------------------------------------*/
+
+static inline void capi_cmsg_answer(_cmsg * cmsg)
+{
+	cmsg->Subcommand |= 0x01;
+}
+
+/*-----------------------------------------------------------------------*/
+
+static inline void capi_fill_CONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					    __u32 adr,
+					    _cstruct NCPI)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x82, 0x80, Messagenumber, adr);
+	cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_FACILITY_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					  __u32 adr,
+					  __u16 FacilitySelector,
+				       _cstruct FacilityRequestParameter)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x80, 0x80, Messagenumber, adr);
+	cmsg->FacilitySelector = FacilitySelector;
+	cmsg->FacilityRequestParameter = FacilityRequestParameter;
+}
+
+static inline void capi_fill_INFO_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+				      __u32 adr,
+				      _cstruct CalledPartyNumber,
+				      _cstruct BChannelinformation,
+				      _cstruct Keypadfacility,
+				      _cstruct Useruserdata,
+				      _cstruct Facilitydataarray)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x08, 0x80, Messagenumber, adr);
+	cmsg->CalledPartyNumber = CalledPartyNumber;
+	cmsg->BChannelinformation = BChannelinformation;
+	cmsg->Keypadfacility = Keypadfacility;
+	cmsg->Useruserdata = Useruserdata;
+	cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_LISTEN_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					__u32 adr,
+					__u32 InfoMask,
+					__u32 CIPmask,
+					__u32 CIPmask2,
+					_cstruct CallingPartyNumber,
+					_cstruct CallingPartySubaddress)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x05, 0x80, Messagenumber, adr);
+	cmsg->InfoMask = InfoMask;
+	cmsg->CIPmask = CIPmask;
+	cmsg->CIPmask2 = CIPmask2;
+	cmsg->CallingPartyNumber = CallingPartyNumber;
+	cmsg->CallingPartySubaddress = CallingPartySubaddress;
+}
+
+static inline void capi_fill_ALERT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+				       __u32 adr,
+				       _cstruct BChannelinformation,
+				       _cstruct Keypadfacility,
+				       _cstruct Useruserdata,
+				       _cstruct Facilitydataarray)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x01, 0x80, Messagenumber, adr);
+	cmsg->BChannelinformation = BChannelinformation;
+	cmsg->Keypadfacility = Keypadfacility;
+	cmsg->Useruserdata = Useruserdata;
+	cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_CONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					 __u32 adr,
+					 __u16 CIPValue,
+					 _cstruct CalledPartyNumber,
+					 _cstruct CallingPartyNumber,
+					 _cstruct CalledPartySubaddress,
+					 _cstruct CallingPartySubaddress,
+					 __u16 B1protocol,
+					 __u16 B2protocol,
+					 __u16 B3protocol,
+					 _cstruct B1configuration,
+					 _cstruct B2configuration,
+					 _cstruct B3configuration,
+					 _cstruct BC,
+					 _cstruct LLC,
+					 _cstruct HLC,
+					 _cstruct BChannelinformation,
+					 _cstruct Keypadfacility,
+					 _cstruct Useruserdata,
+					 _cstruct Facilitydataarray)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x02, 0x80, Messagenumber, adr);
+	cmsg->CIPValue = CIPValue;
+	cmsg->CalledPartyNumber = CalledPartyNumber;
+	cmsg->CallingPartyNumber = CallingPartyNumber;
+	cmsg->CalledPartySubaddress = CalledPartySubaddress;
+	cmsg->CallingPartySubaddress = CallingPartySubaddress;
+	cmsg->B1protocol = B1protocol;
+	cmsg->B2protocol = B2protocol;
+	cmsg->B3protocol = B3protocol;
+	cmsg->B1configuration = B1configuration;
+	cmsg->B2configuration = B2configuration;
+	cmsg->B3configuration = B3configuration;
+	cmsg->BC = BC;
+	cmsg->LLC = LLC;
+	cmsg->HLC = HLC;
+	cmsg->BChannelinformation = BChannelinformation;
+	cmsg->Keypadfacility = Keypadfacility;
+	cmsg->Useruserdata = Useruserdata;
+	cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_DATA_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					 __u32 adr,
+					 __u32 Data,
+					 __u16 DataLength,
+					 __u16 DataHandle,
+					 __u16 Flags)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x86, 0x80, Messagenumber, adr);
+	cmsg->Data = Data;
+	cmsg->DataLength = DataLength;
+	cmsg->DataHandle = DataHandle;
+	cmsg->Flags = Flags;
+}
+
+static inline void capi_fill_DISCONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					    __u32 adr,
+					    _cstruct BChannelinformation,
+					    _cstruct Keypadfacility,
+					    _cstruct Useruserdata,
+					    _cstruct Facilitydataarray)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x04, 0x80, Messagenumber, adr);
+	cmsg->BChannelinformation = BChannelinformation;
+	cmsg->Keypadfacility = Keypadfacility;
+	cmsg->Useruserdata = Useruserdata;
+	cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_DISCONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					       __u32 adr,
+					       _cstruct NCPI)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x84, 0x80, Messagenumber, adr);
+	cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_MANUFACTURER_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					      __u32 adr,
+					      __u32 ManuID,
+					      __u32 Class,
+					      __u32 Function,
+					      _cstruct ManuData)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0xff, 0x80, Messagenumber, adr);
+	cmsg->ManuID = ManuID;
+	cmsg->Class = Class;
+	cmsg->Function = Function;
+	cmsg->ManuData = ManuData;
+}
+
+static inline void capi_fill_RESET_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					  __u32 adr,
+					  _cstruct NCPI)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x87, 0x80, Messagenumber, adr);
+	cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_SELECT_B_PROTOCOL_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+						   __u32 adr,
+						   __u16 B1protocol,
+						   __u16 B2protocol,
+						   __u16 B3protocol,
+						_cstruct B1configuration,
+						_cstruct B2configuration,
+						_cstruct B3configuration)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x41, 0x80, Messagenumber, adr);
+	cmsg->B1protocol = B1protocol;
+	cmsg->B2protocol = B2protocol;
+	cmsg->B3protocol = B3protocol;
+	cmsg->B1configuration = B1configuration;
+	cmsg->B2configuration = B2configuration;
+	cmsg->B3configuration = B3configuration;
+}
+
+static inline void capi_fill_CONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					  __u32 adr,
+					  __u16 Reject,
+					  __u16 B1protocol,
+					  __u16 B2protocol,
+					  __u16 B3protocol,
+					  _cstruct B1configuration,
+					  _cstruct B2configuration,
+					  _cstruct B3configuration,
+					  _cstruct ConnectedNumber,
+					  _cstruct ConnectedSubaddress,
+					  _cstruct LLC,
+					  _cstruct BChannelinformation,
+					  _cstruct Keypadfacility,
+					  _cstruct Useruserdata,
+					  _cstruct Facilitydataarray)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x02, 0x83, Messagenumber, adr);
+	cmsg->Reject = Reject;
+	cmsg->B1protocol = B1protocol;
+	cmsg->B2protocol = B2protocol;
+	cmsg->B3protocol = B3protocol;
+	cmsg->B1configuration = B1configuration;
+	cmsg->B2configuration = B2configuration;
+	cmsg->B3configuration = B3configuration;
+	cmsg->ConnectedNumber = ConnectedNumber;
+	cmsg->ConnectedSubaddress = ConnectedSubaddress;
+	cmsg->LLC = LLC;
+	cmsg->BChannelinformation = BChannelinformation;
+	cmsg->Keypadfacility = Keypadfacility;
+	cmsg->Useruserdata = Useruserdata;
+	cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_CONNECT_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+						 __u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x03, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_CONNECT_B3_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+						    __u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x83, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_CONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					     __u32 adr,
+					     __u16 Reject,
+					     _cstruct NCPI)
+{
+	capi_cmsg_header(cmsg, ApplId, 0x82, 0x83, Messagenumber, adr);
+	cmsg->Reject = Reject;
+	cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_CONNECT_B3_T90_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+							__u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x88, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_DATA_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					  __u32 adr,
+					  __u16 DataHandle)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x86, 0x83, Messagenumber, adr);
+	cmsg->DataHandle = DataHandle;
+}
+
+static inline void capi_fill_DISCONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+						__u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x84, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_DISCONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					     __u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x04, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_FACILITY_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					   __u32 adr,
+					   __u16 FacilitySelector)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x80, 0x83, Messagenumber, adr);
+	cmsg->FacilitySelector = FacilitySelector;
+}
+
+static inline void capi_fill_INFO_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+				       __u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x08, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_MANUFACTURER_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					       __u32 adr,
+					       __u32 ManuID,
+					       __u32 Class,
+					       __u32 Function,
+					       _cstruct ManuData)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0xff, 0x83, Messagenumber, adr);
+	cmsg->ManuID = ManuID;
+	cmsg->Class = Class;
+	cmsg->Function = Function;
+	cmsg->ManuData = ManuData;
+}
+
+static inline void capi_fill_RESET_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+					   __u32 adr)
+{
+
+	capi_cmsg_header(cmsg, ApplId, 0x87, 0x83, Messagenumber, adr);
+}
+
+#endif				/* __CAPIUTIL_H__ */
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/compat.h linux-2.0.31-pre3/drivers/isdn/avmb1/compat.h
--- linux-2.0.31-pre2/drivers/isdn/avmb1/compat.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/compat.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,30 @@
+/*
+ * $Id: compat.h,v 1.1 1997/03/04 21:50:36 calle Exp $
+ * 
+ * Headerfile for Compartibility between different kernel versions
+ * 
+ * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: compat.h,v $
+ * Revision 1.1  1997/03/04 21:50:36  calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+#ifndef __COMPAT_H__
+#define __COMPAT_H__
+
+#include <linux/version.h>
+#include <linux/isdnif.h>
+
+#if LINUX_VERSION_CODE >= 0x020112	/* 2.1.18 */
+#define HAS_NEW_SYMTAB
+#endif
+
+#endif				/* __COMPAT_H__ */
diff -urN linux-2.0.31-pre2/drivers/isdn/avmb1/Makefile linux-2.0.31-pre3/drivers/isdn/avmb1/Makefile
--- linux-2.0.31-pre2/drivers/isdn/avmb1/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/avmb1/Makefile	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,77 @@
+#
+# $Id: Makefile,v 1.4 1997/03/30 17:10:40 calle Exp $
+#
+# Makefile for the CAPI and AVM-B1 device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+# $Log: Makefile,v $
+# Revision 1.4  1997/03/30 17:10:40  calle
+# added support for AVM-B1-PCI card.
+#
+# Revision 1.3  1997/03/22 02:00:57  fritz
+# -Reworked toplevel Makefile. From now on, no different Makefiles
+#  for standalone- and in-kernel-compilation are needed any more.
+# -Added local Rules.make for above reason.
+# -Experimental changes in teles3.c for enhanced IRQ-checking with
+#  2.1.X and SMP kernels.
+# -Removed diffstd-script, same functionality is in stddiff -r.
+# -Enhanced scripts std2kern and stddiff.
+#
+# Revision 1.1  1997/03/05 21:26:14  fritz
+# Renamed, according naming conventions in CVS tree.
+#
+# Revision 1.1  1997/03/04 21:50:26  calle
+# Frirst version in isdn4linux
+#
+# Revision 2.2  1997/02/12 09:31:39  calle
+#
+# Revision 1.1  1997/01/31 10:32:20  calle
+# Initial revision
+#
+#
+
+#
+# Objects that don't export a symtab
+#
+L_OBJS := # used as component of an L_TARGET
+O_OBJS := # used as component of an O_TARGET
+M_OBJS := # used as module
+#
+# Objects that do export a symtab
+#
+LX_OBJS := # used as component of an L_TARGET
+OX_OBJS := # used as component of an O_TARGET
+MX_OBJS := # used as module
+#
+# Targets, created by linking others
+#
+O_TARGET := # used for .o targets (from O and OX objects)
+L_TARGET := # used for .a targets (from L and LX objects)
+
+ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+  O_TARGET += avmb1.o
+  O_OBJS   += capi.o b1lli.o
+  OX_OBJS  += capiutil.o b1capi.o capidrv.o
+  ifdef CONFIG_PCI
+  OX_OBJS  += b1pci.o
+  endif
+else
+  ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
+  O_TARGET += kernelcapi.o
+  O_OBJS   += b1lli.o
+  OX_OBJS  += b1capi.o
+  M_OBJS   += capi.o kernelcapi.o
+  MX_OBJS  += capiutil.o capidrv.o
+  ifdef CONFIG_PCI
+  MX_OBJS  += b1pci.o
+  endif
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.0.31-pre2/drivers/isdn/Config.in linux-2.0.31-pre3/drivers/isdn/Config.in
--- linux-2.0.31-pre2/drivers/isdn/Config.in	1996-05-19 05:29:29.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/Config.in	2003-08-15 15:03:53.000000000 -0700
@@ -11,4 +11,21 @@
 bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
 dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
 dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+    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 AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+    bool 'HiSax Support for Elsa ISA cards' CONFIG_HISAX_ELSA_PCC
+    bool 'HiSax Support for Elsa PCMCIA card' CONFIG_HISAX_ELSA_PCMCIA
+    bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+fi
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+	dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+fi
+dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
+    bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+fi
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/avm_a1.c linux-2.0.31-pre3/drivers/isdn/hisax/avm_a1.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/avm_a1.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/avm_a1.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,960 @@
+/* $Id: avm_a1.c,v 1.6 1997/04/13 19:54:07 keil Exp $
+
+ * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: avm_a1.c,v $
+ * Revision 1.6  1997/04/13 19:54:07  keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.5  1997/04/06 22:54:10  keil
+ * Using SKB's
+ *
+ * Revision 1.4  1997/01/27 15:50:21  keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.3  1997/01/21 22:14:20  keil
+ * cleanups
+ *
+ * Revision 1.2  1996/10/27 22:07:31  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:49  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "avm_a1.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *avm_revision = "$Revision: 1.6 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readreg(unsigned int adr, u_char off)
+{
+	return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, u_char off, u_char data)
+{
+	byteout(adr + off, data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+	insb(adr - 0x400, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+	outsb(adr - 0x400, data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+	int to = 50;
+
+	while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "AVM A1: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr)
+{
+	int to = 50;
+
+	while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "AVM A1: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr);
+	writereg(adr, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+avm_a1_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *sp = hsp->sp;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvidx + count > HSCX_BUFMAX) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		hsp->rcvidx = 0;
+		return;
+	}
+	ptr = hsp->rcvbuf + hsp->rcvidx;
+	hsp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo(sp->hscx[hsp->hscx], ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState *sp = hsp->sp;
+	int more, count;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	if (!hsp->tx_skb)
+		return;
+	if (hsp->tx_skb->len <= 0)
+		return;
+
+	more = (hsp->mode == 1) ? 1 : 0;
+	if (hsp->tx_skb->len > 32) {
+		more = !0;
+		count = 32;
+	} else
+		count = hsp->tx_skb->len;
+
+	waitforXFW(sp->hscx[hsp->hscx]);
+	save_flags(flags);
+	cli();
+	ptr = hsp->tx_skb->data;
+	skb_pull(hsp->tx_skb, count);
+	hsp->tx_cnt -= count;
+	hsp->count += count;
+	write_fifo(sp->hscx[hsp->hscx], ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+	u_char r;
+	struct HscxState *hsp = sp->hs + hscx;
+	struct sk_buff *skb;
+	int count;
+	char tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode)
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		} else {
+			count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			hscx_empty_fifo(hsp, count);
+			if ((count = hsp->rcvidx - 1) > 0) {
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "AVM: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+					skb_queue_tail(&hsp->rqueue, skb);
+				}
+			}
+		}
+		hsp->rcvidx = 0;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		hscx_empty_fifo(hsp, 32);
+		if (hsp->mode == 1) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(32)))
+				printk(KERN_WARNING "AVM: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+				skb_queue_tail(&hsp->rqueue, skb);
+			}
+			hsp->rcvidx = 0;
+			hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (hsp->tx_skb)
+			if (hsp->tx_skb->len) {
+				hscx_fill_fifo(hsp);
+				return;
+			} else {
+				dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+				hsp->count = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->tx_skb = NULL;
+			}
+		if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+			hsp->count = 0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "isac_empty_fifo");
+
+	if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+		if (sp->debug & L1_DEB_WARN) {
+			char tmp[40];
+			sprintf(tmp, "isac_empty_fifo overrun %d",
+				sp->rcvidx + count);
+			debugl1(sp, tmp);
+		}
+		writereg(sp->isac, ISAC_CMDR, 0x80);
+		sp->rcvidx = 0;
+		return;
+	}
+	ptr = sp->rcvbuf + sp->rcvidx;
+	sp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo(sp->isac, ptr, count);
+	writereg(sp->isac, ISAC_CMDR, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_fill_fifo");
+
+	if (!sp->tx_skb)
+		return;
+
+	count = sp->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = sp->tx_skb->data;
+	skb_pull(sp->tx_skb, count);
+	sp->tx_cnt += count;
+	write_fifo(sp->isac, ptr, count);
+	writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+		debugl1(sp, tmp);
+	}
+	writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+	u_char exval;
+	struct sk_buff *skb;
+	unsigned int count;
+	char tmp[32];
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+		debugl1(sp, tmp);
+	}
+	if (val & 0x80) {	/* RME */
+		exval = readreg(sp->isac, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC CRC error");
+			writereg(sp->isac, ISAC_CMDR, 0x80);
+		} else {
+			count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			isac_empty_fifo(sp, count);
+			if ((count = sp->rcvidx) > 0) {
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "AVM: D receive out of memory\n");
+				else {
+					SET_SKB_FREE(skb);
+					memcpy(skb_put(skb, count), sp->rcvbuf, count);
+					skb_queue_tail(&sp->rq, skb);
+				}
+			}
+		}
+		sp->rcvidx = 0;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		isac_empty_fifo(sp, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->tx_skb)
+			if (sp->tx_skb->len) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+				sp->tx_cnt = 0;
+				sp->tx_skb = NULL;
+			}
+		if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+			sp->tx_cnt = 0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
+		    & 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+			sprintf(tmp, "l1state %d", sp->ph_state);
+			debugl1(sp, tmp);
+		}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readreg(sp->isac, ISAC_EXIR);
+		if (sp->debug & L1_DEB_WARN) {
+			sprintf(tmp, "ISAC EXIR %02x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+	u_char exval;
+	struct HscxState *hsp;
+	char tmp[32];
+
+
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+		exval = readreg(sp->hscx[1], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+		exval = readreg(sp->hscx[0], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0x04) {
+		exval = readreg(sp->hscx[0], HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	u_char val, sval, stat = 0;
+	char tmp[32];
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+	if (!sp) {
+		printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
+		return;
+	}
+	while (((sval = bytein(sp->cfg_reg)) & 0xf) != 0x7) {
+		if (!(sval & AVM_A1_STAT_TIMER)) {
+			byteout(sp->cfg_reg, 0x14);
+			byteout(sp->cfg_reg, 0x18);
+			sval = bytein(sp->cfg_reg);
+		} else if (sp->debug & L1_DEB_INTSTAT) {
+			sprintf(tmp, "avm IntStatus %x", sval);
+			debugl1(sp, tmp);
+		}
+		if (!(sval & AVM_A1_STAT_HSCX)) {
+			val = readreg(sp->hscx[1], HSCX_ISTA);
+			if (val) {
+				hscx_int_main(sp, val);
+				stat |= 1;
+			}
+		}
+		if (!(sval & AVM_A1_STAT_ISAC)) {
+			val = readreg(sp->isac, ISAC_ISTA);
+			if (val) {
+				isac_interrupt(sp, val);
+				stat |= 2;
+			}
+		}
+	}
+	if (stat & 1) {
+		writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[0], HSCX_MASK, 0x0);
+		writereg(sp->hscx[1], HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writereg(sp->isac, ISAC_MASK, 0xFF);
+		writereg(sp->isac, ISAC_MASK, 0x0);
+	}
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+	unsigned int adr = sp->isac;
+
+	/* 16.3 IOM 2 Mode */
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_ADF2, 0x80);
+	writereg(adr, ISAC_SQXR, 0x2f);
+	writereg(adr, ISAC_SPCR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x2);
+	writereg(adr, ISAC_STCR, 0x70);
+	writereg(adr, ISAC_MODE, 0xc9);
+	writereg(adr, ISAC_TIMR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x0);
+	writereg(adr, ISAC_CMDR, 0x41);
+	writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+			'A' + hscx, mode, ichan);
+		debugl1(sp, tmp);
+	}
+	hs->mode = mode;
+	writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+	writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+	writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+	switch (mode) {
+		case (0):
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+			break;
+		case (1):
+			if (ichan == 0) {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			} else {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			}
+			writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+			writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+			break;
+		case (2):
+			if (ichan == 0) {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			} else {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			}
+			writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+			writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+			break;
+	}
+	writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask)
+{
+	release_region(card->sp->cfg_reg, 8);
+	if (mask & 1)
+		release_region(card->sp->isac, 32);
+	if (mask & 2)
+		release_region(card->sp->isac - 0x400, 1);
+	if (mask & 4)
+		release_region(card->sp->hscx[0], 32);
+	if (mask & 8)
+		release_region(card->sp->hscx[0] - 0x400, 1);
+	if (mask & 0x10)
+		release_region(card->sp->hscx[1], 32);
+	if (mask & 0x20)
+		release_region(card->sp->hscx[1] - 0x400, 1);
+}
+
+void
+release_io_avm_a1(struct IsdnCard *card)
+{
+	release_ioregs(card, 0x3f);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int val;
+	char tmp[64];
+
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+	sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readreg(sp->hscx[1], HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x02) {
+		val = readreg(sp->hscx[0], HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+	}
+	val = readreg(sp->hscx[0], HSCX_ISTA);
+	sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->hscx[1], HSCX_STAR);
+	sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->hscx[0], HSCX_STAR);
+	sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_STAR);
+	sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_MODE);
+	sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_ADF2);
+	sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_ISTA);
+	sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readreg(sp->isac, ISAC_EXIR);
+		sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x04) {
+		val = readreg(sp->isac, ISAC_CIR0);
+		sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+	}
+	writereg(sp->isac, ISAC_MASK, 0);
+	writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initavm_a1(struct IsdnCardState *sp)
+{
+	int ret;
+	int loop = 0;
+	char tmp[40];
+
+	sp->counter = kstat.interrupts[sp->irq];
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr, &avm_a1_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		while (loop++ < 10) {
+			/* At least 1-3 irqs must happen
+			 * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+			 */
+			if (kstat.interrupts[sp->irq] > sp->counter)
+				break;
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 1;
+			schedule();
+		}
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+		debugl1(sp, tmp);
+		if (kstat.interrupts[sp->irq] == sp->counter) {
+			printk(KERN_WARNING
+			       "AVM A1: IRQ(%d) getting no interrupts during init\n",
+			       sp->irq);
+			irq2dev_map[sp->irq] = NULL;
+			free_irq(sp->irq, NULL);
+			return (0);
+		}
+	}
+	return (ret);
+}
+
+int
+setup_avm_a1(struct IsdnCard *card)
+{
+	u_char val, verA, verB;
+	struct IsdnCardState *sp = card->sp;
+	long flags;
+	char tmp[64];
+
+	strcpy(tmp, avm_revision);
+	printk(KERN_NOTICE "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
+	if (sp->typ != ISDN_CTYPE_A1)
+		return (0);
+
+	sp->cfg_reg = card->para[1] + 0x1800;
+	sp->isac = card->para[1] + 0x1400;
+	sp->hscx[0] = card->para[1] + 0x400;
+	sp->hscx[1] = card->para[1] + 0xc00;
+	sp->irq = card->para[0];
+	if (check_region((sp->cfg_reg), 8)) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       sp->cfg_reg,
+		       sp->cfg_reg + 8);
+		return (0);
+	} else {
+		request_region(sp->cfg_reg, 8, "avm cfg");
+	}
+	if (check_region((sp->isac), 32)) {
+		printk(KERN_WARNING
+		       "HiSax: %s isac ports %x-%x already in use\n",
+		       CardType[sp->typ],
+		       sp->isac,
+		       sp->isac + 32);
+		release_ioregs(card, 0);
+		return (0);
+	} else {
+		request_region(sp->isac, 32, "HiSax isac");
+	}
+	if (check_region((sp->isac - 0x400), 1)) {
+		printk(KERN_WARNING
+		       "HiSax: %s isac fifo port %x already in use\n",
+		       CardType[sp->typ],
+		       sp->isac - 0x400);
+		release_ioregs(card, 1);
+		return (0);
+	} else {
+		request_region(sp->isac - 0x400, 1, "HiSax isac fifo");
+	}
+	if (check_region((sp->hscx[0]), 32)) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx A ports %x-%x already in use\n",
+		       CardType[sp->typ],
+		       sp->hscx[0],
+		       sp->hscx[0] + 32);
+		release_ioregs(card, 3);
+		return (0);
+	} else {
+		request_region(sp->hscx[0], 32, "HiSax hscx A");
+	}
+	if (check_region((sp->hscx[0] - 0x400), 1)) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx A fifo port %x already in use\n",
+		       CardType[sp->typ],
+		       sp->hscx[0] - 0x400);
+		release_ioregs(card, 7);
+		return (0);
+	} else {
+		request_region(sp->hscx[0] - 0x400, 1, "HiSax hscx A fifo");
+	}
+	if (check_region((sp->hscx[1]), 32)) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx B ports %x-%x already in use\n",
+		       CardType[sp->typ],
+		       sp->hscx[1],
+		       sp->hscx[1] + 32);
+		release_ioregs(card, 0xf);
+		return (0);
+	} else {
+		request_region(sp->hscx[1], 32, "HiSax hscx B");
+	}
+	if (check_region((sp->hscx[1] - 0x400), 1)) {
+		printk(KERN_WARNING
+		       "HiSax: %s hscx B fifo port %x already in use\n",
+		       CardType[sp->typ],
+		       sp->hscx[1] - 0x400);
+		release_ioregs(card, 0x1f);
+		return (0);
+	} else {
+		request_region(sp->hscx[1] - 0x400, 1, "HiSax hscx B fifo");
+	}
+	save_flags(flags);
+	byteout(sp->cfg_reg, 0x0);
+	sti();
+	HZDELAY(HZ / 5 + 1);
+	byteout(sp->cfg_reg, 0x1);
+	HZDELAY(HZ / 5 + 1);
+	byteout(sp->cfg_reg, 0x0);
+	HZDELAY(HZ / 5 + 1);
+	val = sp->irq;
+	if (val == 9)
+		val = 2;
+	byteout(sp->cfg_reg + 1, val);
+	HZDELAY(HZ / 5 + 1);
+	byteout(sp->cfg_reg, 0x0);
+	HZDELAY(HZ / 5 + 1);
+	restore_flags(flags);
+
+	val = bytein(sp->cfg_reg);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       sp->cfg_reg, val);
+	val = bytein(sp->cfg_reg + 3);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       sp->cfg_reg + 3, val);
+	val = bytein(sp->cfg_reg + 2);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       sp->cfg_reg + 2, val);
+	byteout(sp->cfg_reg, 0x14);
+	byteout(sp->cfg_reg, 0x18);
+	val = bytein(sp->cfg_reg);
+	printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+	       sp->cfg_reg, val);
+
+	printk(KERN_NOTICE
+	       "HiSax: %s config irq:%d cfg:%x\n",
+	       CardType[sp->typ], sp->irq,
+	       sp->cfg_reg);
+	printk(KERN_NOTICE
+	       "HiSax: isac:%x/%x\n",
+	       sp->isac, sp->isac - 0x400);
+	printk(KERN_NOTICE
+	       "HiSax: hscx A:%x/%x  hscx B:%x/%x\n",
+	       sp->hscx[0], sp->hscx[0] - 0x400,
+	       sp->hscx[1], sp->hscx[1] - 0x400);
+	verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
+	verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
+	printk(KERN_INFO "AVM A1: HSCX version A: %s  B: %s\n",
+	       HscxVersion(verA), HscxVersion(verB));
+	val = readreg(sp->isac, ISAC_RBCH);
+	printk(KERN_INFO "AVM A1: ISAC %s\n",
+	       ISACVersion(val));
+	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+		printk(KERN_WARNING
+		       "AVM A1: wrong HSCX versions check IO address\n");
+		release_io_avm_a1(card);
+		return (0);
+	}
+	sp->modehscx = &modehscx;
+	sp->ph_command = &ph_command;
+	sp->hscx_fill_fifo = &hscx_fill_fifo;
+	sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/avm_a1.h linux-2.0.31-pre3/drivers/isdn/hisax/avm_a1.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/avm_a1.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/avm_a1.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,25 @@
+/* $Id: avm_a1.h,v 1.2 1997/01/21 22:14:36 keil Exp $
+ *
+ * avm_a1.h   Header for AVM A1 (Fritz) ISDN card
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: avm_a1.h,v $
+ * Revision 1.2  1997/01/21 22:14:36  keil
+ * cleanups
+ *
+ * Revision 1.1  1996/10/12 21:42:40  keil
+ * Initial revision
+ *
+ *
+*/
+
+#define	 AVM_A1_STAT_ISAC	0x01
+#define	 AVM_A1_STAT_HSCX	0x02
+#define	 AVM_A1_STAT_TIMER	0x04
+
+extern	void avm_a1_report(struct IsdnCardState *sp);
+extern  void release_io_avm_a1(struct IsdnCard *card);
+extern	int  setup_avm_a1(struct IsdnCard *card);
+extern  int  initavm_a1(struct IsdnCardState *sp);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/callc.c linux-2.0.31-pre3/drivers/isdn/hisax/callc.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/callc.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/callc.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1975 @@
+/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: callc.c,v $
+ * Revision 1.30  1997/05/29 10:40:43  keil
+ * chanp->impair was uninitialised
+ *
+ * Revision 1.29  1997/04/23 20:09:49  fritz
+ * Removed tmp, used by removed debugging code.
+ *
+ * Revision 1.28  1997/04/21 13:42:25  keil
+ * Remove unneeded debug
+ *
+ * Revision 1.27  1997/04/16 14:21:01  keil
+ * remove unused variable
+ *
+ * Revision 1.26  1997/04/13 19:55:21  keil
+ * Changes in debugging code
+ *
+ * Revision 1.25  1997/04/06 22:54:08  keil
+ * Using SKB's
+ *
+ * Revision 1.24  1997/03/05 11:28:03  keil
+ * fixed undefined l2tei procedure
+ * a layer1 release delete now the drel timer
+ *
+ * Revision 1.23  1997/03/04 23:07:42  keil
+ * bugfix dial parameter
+ *
+ * Revision 1.22  1997/02/27 13:51:55  keil
+ * Reset B-channel (dlc) statemachine in every release
+ *
+ * Revision 1.21  1997/02/19 09:24:27  keil
+ * Bugfix: Hangup to LL if a ttyI rings
+ *
+ * Revision 1.20  1997/02/17 00:32:47  keil
+ * Bugfix: No Busy reported to LL
+ *
+ * Revision 1.19  1997/02/14 12:23:10  fritz
+ * Added support for new insmod parameter handling.
+ *
+ * Revision 1.18  1997/02/11 01:36:58  keil
+ * Changed setup-interface (incoming and outgoing), cause reporting
+ *
+ * Revision 1.17  1997/02/09 00:23:10  keil
+ * new interface handling, one interface per card
+ * some changes in debug and leased line mode
+ *
+ * Revision 1.16  1997/01/27 23:17:03  keil
+ * delete timers while unloading
+ *
+ * Revision 1.15  1997/01/27 16:00:38  keil
+ * D-channel shutdown delay; improved callback
+ *
+ * Revision 1.14  1997/01/21 22:16:39  keil
+ * new statemachine; leased line support; cleanup for 2.0
+ *
+ * Revision 1.13  1996/12/08 19:51:17  keil
+ * bugfixes from Pekka Sarnila
+ *
+ * Revision 1.12  1996/11/26 20:20:03  keil
+ * fixed warning while compile
+ *
+ * Revision 1.11  1996/11/26 18:43:17  keil
+ * change ioctl 555 --> 55 (555 didn't work)
+ *
+ * Revision 1.10  1996/11/26 18:06:07  keil
+ * fixed missing break statement,ioctl 555 reset modcount
+ *
+ * Revision 1.9  1996/11/18 20:23:19  keil
+ * log writebuf channel not open changed
+ *
+ * Revision 1.8  1996/11/06 17:43:17  keil
+ * more changes for 2.1.X;block fixed ST_PRO_W
+ *
+ * Revision 1.7  1996/11/06 15:13:51  keil
+ * typo 0x64 --->64 in debug code
+ *
+ * Revision 1.6  1996/11/05 19:40:33  keil
+ * X.75 windowsize
+ *
+ * Revision 1.5  1996/10/30 10:11:06  keil
+ * debugging LOCK changed;ST_REL_W EV_HANGUP added
+ *
+ * Revision 1.4  1996/10/27 22:20:16  keil
+ * alerting bugfixes
+ * no static b-channel<->channel mapping
+ *
+ * Revision 1.2  1996/10/16 21:29:45  keil
+ * compile bug as "not module"
+ * Callback with euro
+ *
+ * Revision 1.1  1996/10/13 20:04:50  keil
+ * Initial revision
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x020111)
+extern long mod_use_count_;
+#define MOD_USE_COUNT mod_use_count_
+#else
+#define MOD_USE_COUNT ((&__this_module)->usecount)
+#endif
+#endif				/* MODULE */
+
+const char *l4_revision = "$Revision: 1.30 $";
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+extern void HiSax_mod_dec_use_count(void);
+extern void HiSax_mod_inc_use_count(void);
+
+static int init_ds(struct Channel *chanp, int incoming);
+static void release_ds(struct Channel *chanp);
+
+static struct Fsm callcfsm =
+{NULL, 0, 0};
+static struct Fsm lcfsm =
+{NULL, 0, 0};
+
+static int chancount = 0;
+
+/* Flags for remembering action done in l4 */
+
+#define  FLG_START_D	0x0001
+#define  FLG_ESTAB_D	0x0002
+#define  FLG_CALL_SEND	0x0004
+#define  FLG_CALL_REC   0x0008
+#define  FLG_CALL_ALERT	0x0010
+#define  FLG_START_B	0x0020
+#define  FLG_CONNECT_B	0x0040
+#define  FLG_LL_DCONN	0x0080
+#define  FLG_LL_BCONN	0x0100
+#define  FLG_DISC_SEND	0x0200
+#define  FLG_DISC_REC	0x0400
+#define  FLG_REL_REC	0x0800
+
+#define  SETBIT(flg, item)  flg |= item
+#define  RESBIT(flg, item)  flg &= (~item)
+
+/*
+ * Because of callback it's a good idea to delay the shutdown of the d-channel
+ */
+#define	DREL_TIMER_VALUE 30000
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*
+hisax_findcard(int driverid)
+{
+	int i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp)
+			if (cards[i].sp->myid == driverid)
+				return (cards[i].sp);
+	return (struct IsdnCardState *) 0;
+}
+
+static void
+link_debug(struct Channel *chanp, char *s, int direction)
+{
+	char tmp[100], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan,
+		direction ? "LL->HL" : "HL->LL", s);
+	HiSax_putstatus(chanp->sp, tmp);
+}
+
+
+enum {
+	ST_NULL,		/*  0 inactive */
+	ST_OUT_WAIT_D,		/*  1 outgoing, awaiting d-channel establishment */
+	ST_IN_WAIT_D,		/*  2 incoming, awaiting d-channel establishment */
+	ST_OUT_DIAL,		/*  3 outgoing, SETUP send; awaiting confirm */
+	ST_IN_WAIT_LL,		/*  4 incoming call received; wait for LL confirm */
+	ST_IN_ALERT_SEND,	/*  5 incoming call received; ALERT send */
+	ST_IN_WAIT_CONN_ACK,	/*  6 incoming CONNECT send; awaiting CONN_ACK */
+	ST_WAIT_BCONN,		/*  7 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
+	ST_ACTIVE,		/*  8 active, b channel prot. established */
+	ST_WAIT_BRELEASE,	/*  9 call clear. (initiator), awaiting b channel prot. rel. */
+	ST_WAIT_BREL_DISC,	/* 10 call clear. (receiver), DISCONNECT req. received */
+	ST_WAIT_DCOMMAND,	/* 11 call clear. (receiver), awaiting DCHANNEL message */
+	ST_WAIT_DRELEASE,	/* 12 DISCONNECT sent, awaiting RELEASE */
+	ST_WAIT_D_REL_CNF,	/* 13 RELEASE sent, awaiting RELEASE confirm */
+	ST_WAIT_DSHUTDOWN,	/*  14 awaiting d-channel shutdown */
+};
+
+#define STATE_COUNT (ST_WAIT_DSHUTDOWN +1)
+
+static char *strState[] =
+{
+	"ST_NULL",
+	"ST_OUT_WAIT_D",
+	"ST_IN_WAIT_D",
+	"ST_OUT_DIAL",
+	"ST_IN_WAIT_LL",
+	"ST_IN_ALERT_SEND",
+	"ST_IN_WAIT_CONN_ACK",
+	"ST_WAIT_BCONN",
+	"ST_ACTIVE",
+	"ST_WAIT_BRELEASE",
+	"ST_WAIT_BREL_DISC",
+	"ST_WAIT_DCOMMAND",
+	"ST_WAIT_DRELEASE",
+	"ST_WAIT_D_REL_CNF",
+	"ST_WAIT_DSHUTDOWN",
+};
+
+enum {
+	EV_DIAL,		/*  0 */
+	EV_SETUP_CNF,		/*  1 */
+	EV_ACCEPTB,		/*  2 */
+	EV_DISCONNECT_IND,	/*  3 */
+	EV_RELEASE_CNF,		/*  4 */
+	EV_DLEST,		/*  5 */
+	EV_DLRL,		/*  6 */
+	EV_SETUP_IND,		/*  7 */
+	EV_RELEASE_IND,		/*  8 */
+	EV_ACCEPTD,		/*  9 */
+	EV_SETUP_CMPL_IND,	/* 10 */
+	EV_BC_EST,		/* 11 */
+	EV_WRITEBUF,		/* 12 */
+	EV_DATAIN,		/* 13 */
+	EV_HANGUP,		/* 14 */
+	EV_BC_REL,		/* 15 */
+	EV_CINF,		/* 16 */
+	EV_SUSPEND,		/* 17 */
+	EV_RESUME,		/* 18 */
+	EV_SHUTDOWN_D,		/* 19 */
+	EV_NOSETUP_RSP,		/* 20 */
+	EV_SETUP_ERR,		/* 21 */
+	EV_CONNECT_ERR,		/* 22 */
+	EV_RELEASE_ERR,		/* 23 */
+};
+
+#define EVENT_COUNT (EV_RELEASE_ERR +1)
+
+static char *strEvent[] =
+{
+	"EV_DIAL",
+	"EV_SETUP_CNF",
+	"EV_ACCEPTB",
+	"EV_DISCONNECT_IND",
+	"EV_RELEASE_CNF",
+	"EV_DLEST",
+	"EV_DLRL",
+	"EV_SETUP_IND",
+	"EV_RELEASE_IND",
+	"EV_ACCEPTD",
+	"EV_SETUP_CMPL_IND",
+	"EV_BC_EST",
+	"EV_WRITEBUF",
+	"EV_DATAIN",
+	"EV_HANGUP",
+	"EV_BC_REL",
+	"EV_CINF",
+	"EV_SUSPEND",
+	"EV_RESUME",
+	"EV_SHUTDOWN_D",
+	"EV_NOSETUP_RSP",
+	"EV_SETUP_ERR",
+	"EV_CONNECT_ERR",
+	"EV_RELEASE_ERR",
+};
+
+enum {
+	ST_LC_NULL,
+	ST_LC_ACTIVATE_WAIT,
+	ST_LC_DELAY,
+	ST_LC_ESTABLISH_WAIT,
+	ST_LC_CONNECTED,
+	ST_LC_FLUSH_WAIT,
+	ST_LC_FLUSH_DELAY,
+	ST_LC_RELEASE_WAIT,
+};
+
+#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
+
+static char *strLcState[] =
+{
+	"ST_LC_NULL",
+	"ST_LC_ACTIVATE_WAIT",
+	"ST_LC_DELAY",
+	"ST_LC_ESTABLISH_WAIT",
+	"ST_LC_CONNECTED",
+	"ST_LC_FLUSH_WAIT",
+	"ST_LC_FLUSH_DELAY",
+	"ST_LC_RELEASE_WAIT",
+};
+
+enum {
+	EV_LC_ESTABLISH,
+	EV_LC_PH_ACTIVATE,
+	EV_LC_PH_DEACTIVATE,
+	EV_LC_DL_ESTABLISH,
+	EV_LC_TIMER,
+	EV_LC_DL_FLUSH,
+	EV_LC_DL_RELEASE,
+	EV_LC_FLUSH,
+	EV_LC_RELEASE,
+};
+
+#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
+
+static char *strLcEvent[] =
+{
+	"EV_LC_ESTABLISH",
+	"EV_LC_PH_ACTIVATE",
+	"EV_LC_PH_DEACTIVATE",
+	"EV_LC_DL_ESTABLISH",
+	"EV_LC_TIMER",
+	"EV_LC_DL_FLUSH",
+	"EV_LC_DL_RELEASE",
+	"EV_LC_FLUSH",
+	"EV_LC_RELEASE",
+};
+
+#define LC_D  0
+#define LC_B  1
+
+static inline void
+l4_deliver_cause(struct Channel *chanp)
+{
+	isdn_ctrl ic;
+
+	if (chanp->para.cause < 0)
+		return;
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_CAUSE;
+	ic.arg = chanp->chan;
+	if (chanp->sp->protocol == ISDN_PTYPE_EURO)
+		sprintf(ic.parm.num, "E%02X%02X", chanp->para.loc & 0x7f,
+			chanp->para.cause & 0x7f);
+	else
+		sprintf(ic.parm.num, "%02X%02X", chanp->para.loc & 0x7f,
+			chanp->para.cause & 0x7f);
+	chanp->sp->iif.statcallb(&ic);
+}
+
+/*
+ * Dial out
+ */
+static void
+l4_prep_dialout(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_OUT_WAIT_D);
+	FsmDelTimer(&chanp->drel_timer, 60);
+	FsmDelTimer(&chanp->dial_timer, 73);
+
+	chanp->l2_active_protocol = chanp->l2_protocol;
+	chanp->incoming = 0;
+	chanp->lc_b.l2_start = !0;
+	switch (chanp->l2_active_protocol) {
+		case (ISDN_PROTO_L2_X75I):
+			chanp->lc_b.l2_establish = !0;
+			break;
+		case (ISDN_PROTO_L2_HDLC):
+		case (ISDN_PROTO_L2_TRANS):
+			chanp->lc_b.l2_establish = 0;
+			break;
+		default:
+			printk(KERN_WARNING "l4_prep_dialout unknown protocol\n");
+			break;
+	}
+	if (chanp->Flags & FLG_ESTAB_D) {
+		FsmEvent(fi, EV_DLEST, NULL);
+	} else {
+		chanp->Flags = FLG_START_D;
+		if (chanp->leased) {
+			chanp->lc_d.l2_establish = 0;
+		}
+		FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+	}
+}
+
+static void
+l4_do_dialout(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_OUT_DIAL);
+	if (chanp->leased) {
+		chanp->para.bchannel = (chanp->chan & 1) + 1;
+		FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+	} else {
+		SETBIT(chanp->Flags, FLG_ESTAB_D);
+		chanp->para.callref = chanp->outcallref;
+		chanp->outcallref++;
+		if (chanp->outcallref == 128)
+			chanp->outcallref = 64;
+		chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
+		SETBIT(chanp->Flags, FLG_CALL_SEND);
+	}
+}
+
+static void
+l4_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_BCONN);
+	SETBIT(chanp->Flags, FLG_LL_DCONN);
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_DCONN", 0);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_DCONN;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+	init_ds(chanp, 0);
+	SETBIT(chanp->Flags, FLG_START_B);
+	FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+l4_go_active(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_ACTIVE);
+	chanp->data_open = !0;
+	SETBIT(chanp->Flags, FLG_CONNECT_B);
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_BCONN", 0);
+	SETBIT(chanp->Flags, FLG_LL_BCONN);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_BCONN;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+}
+
+/* incomming call */
+
+static void
+l4_start_dchan(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_IN_WAIT_D);
+	FsmDelTimer(&chanp->drel_timer, 61);
+	if (chanp->Flags & FLG_ESTAB_D) {
+		FsmEvent(fi, EV_DLEST, NULL);
+	} else {
+		chanp->Flags = FLG_START_D;
+		FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+	}
+}
+
+static void
+l4_deliver_call(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+	int ret;
+	char txt[32];
+
+	/*
+	 * Report incoming calls only once to linklevel, use CallFlags
+	 * which is set to 3 with each broadcast message in isdnl1.c
+	 * and resetted if a interface  answered the STAT_ICALL.
+	 */
+	if ((chanp->sp) && (chanp->sp->CallFlags == 3)) {
+		FsmChangeState(fi, ST_IN_WAIT_LL);
+		SETBIT(chanp->Flags, FLG_ESTAB_D);
+		SETBIT(chanp->Flags, FLG_CALL_REC);
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_ICALL", 0);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_ICALL;
+		ic.arg = chanp->chan;
+		/*
+		 * No need to return "unknown" for calls without OAD,
+		 * cause that's handled in linklevel now (replaced by '0')
+		 */
+		ic.parm.setup = chanp->para.setup;
+		ret = chanp->sp->iif.statcallb(&ic);
+		if (chanp->debug & 1) {
+			sprintf(txt, "statcallb ret=%d", ret);
+			link_debug(chanp, txt, 1);
+		}
+		if (ret)	/* if a interface knows this call, reset the CallFlag
+				   * to avoid a second Call report to the linklevel
+				 */
+			chanp->sp->CallFlags &= ~(chanp->chan + 1);
+		switch (ret) {
+			case 1:	/* OK, anybody likes this call */
+				FsmChangeState(fi, ST_IN_ALERT_SEND);
+				SETBIT(chanp->Flags, FLG_CALL_ALERT);
+				chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
+				break;
+			case 2:	/* Rejecting Call */
+				RESBIT(chanp->Flags, FLG_CALL_REC);
+				break;
+			case 0:	/* OK, nobody likes this call */
+			default:	/* statcallb problems */
+				chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+				FsmChangeState(fi, ST_NULL);
+				chanp->Flags = FLG_ESTAB_D;
+				FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+				break;
+		}
+	} else {
+		chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+		FsmChangeState(fi, ST_NULL);
+		chanp->Flags = FLG_ESTAB_D;
+		FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+	}
+}
+
+static void
+l4_send_dconnect(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+	chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
+}
+
+static void
+l4_init_bchan_in(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_BCONN);
+	SETBIT(chanp->Flags, FLG_LL_DCONN);
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_DCONN", 0);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_DCONN;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+	chanp->l2_active_protocol = chanp->l2_protocol;
+	chanp->incoming = !0;
+	chanp->lc_b.l2_start = 0;
+	switch (chanp->l2_active_protocol) {
+		case (ISDN_PROTO_L2_X75I):
+			chanp->lc_b.l2_establish = !0;
+			break;
+		case (ISDN_PROTO_L2_HDLC):
+		case (ISDN_PROTO_L2_TRANS):
+			chanp->lc_b.l2_establish = 0;
+			break;
+		default:
+			printk(KERN_WARNING "r9 unknown protocol\n");
+			break;
+	}
+	init_ds(chanp, !0);
+	SETBIT(chanp->Flags, FLG_START_B);
+	FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+/* Call clearing */
+
+static void
+l4_reject_call(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_WAIT_DRELEASE);
+	chanp->para.cause = 0x15;	/* Call Rejected */
+	chanp->is.l4.l4l3(&chanp->is, CC_REJECT_REQ, NULL);
+	SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_cancel_call(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_DRELEASE);
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	chanp->para.cause = 0x10;	/* Normal Call Clearing */
+	chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+	SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_shutdown_d(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+	FsmDelTimer(&chanp->drel_timer, 62);
+	RESBIT(chanp->Flags, FLG_ESTAB_D);
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_timeout_d(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	if (chanp->Flags & FLG_LL_DCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_DCONN);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	FsmChangeState(fi, ST_NULL);
+	chanp->Flags = FLG_ESTAB_D;
+	FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+}
+
+static void
+l4_go_null(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	FsmChangeState(fi, ST_NULL);
+	chanp->Flags = 0;
+	FsmDelTimer(&chanp->drel_timer, 63);
+}
+
+static void
+l4_disconn_bchan(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	chanp->data_open = 0;
+	FsmChangeState(fi, ST_WAIT_BRELEASE);
+	RESBIT(chanp->Flags, FLG_CONNECT_B);
+	FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_send_d_disc(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+
+	if (chanp->Flags & (FLG_DISC_REC | FLG_REL_REC))
+		return;
+	FsmChangeState(fi, ST_WAIT_DRELEASE);
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	chanp->para.cause = 0x10;	/* Normal Call Clearing */
+	chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+	SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_released_bchan(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_DCOMMAND);
+	chanp->data_open = 0;
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	release_ds(chanp);
+	RESBIT(chanp->Flags, FLG_START_B);
+}
+
+
+static void
+l4_release_bchan(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	chanp->data_open = 0;
+	SETBIT(chanp->Flags, FLG_DISC_REC);
+	FsmChangeState(fi, ST_WAIT_BREL_DISC);
+	RESBIT(chanp->Flags, FLG_CONNECT_B);
+	FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_received_d_rel(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	chanp->data_open = 0;
+	FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+	SETBIT(chanp->Flags, FLG_REL_REC);
+	if (chanp->Flags & FLG_CONNECT_B) {
+		chanp->lc_b.l2_establish = 0;	/* direct reset in lc_b.lcfi */
+		FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+		RESBIT(chanp->Flags, FLG_CONNECT_B);
+	}
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL);
+	RESBIT(chanp->Flags, FLG_ESTAB_D);
+	RESBIT(chanp->Flags, FLG_DISC_SEND);
+	RESBIT(chanp->Flags, FLG_CALL_REC);
+	RESBIT(chanp->Flags, FLG_CALL_ALERT);
+	RESBIT(chanp->Flags, FLG_LL_DCONN);
+	RESBIT(chanp->Flags, FLG_CALL_SEND);
+}
+
+static void
+l4_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	chanp->data_open = 0;
+	FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+	if (chanp->Flags & FLG_CONNECT_B) {
+		chanp->lc_b.l2_establish = 0;	/* direct reset in lc_b.lcfi */
+		FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+		RESBIT(chanp->Flags, FLG_CONNECT_B);
+	}
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+	RESBIT(chanp->Flags, FLG_ESTAB_D);
+	RESBIT(chanp->Flags, FLG_DISC_SEND);
+	RESBIT(chanp->Flags, FLG_CALL_REC);
+	RESBIT(chanp->Flags, FLG_CALL_ALERT);
+	RESBIT(chanp->Flags, FLG_LL_DCONN);
+	RESBIT(chanp->Flags, FLG_CALL_SEND);
+}
+
+static void
+l4_received_d_disc(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	chanp->data_open = 0;
+	FsmChangeState(fi, ST_WAIT_D_REL_CNF);
+	SETBIT(chanp->Flags, FLG_DISC_REC);
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	RESBIT(chanp->Flags, FLG_LL_DCONN);
+	RESBIT(chanp->Flags, FLG_CALL_SEND);
+	RESBIT(chanp->Flags, FLG_CALL_ALERT);
+	chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+}
+
+/* processing charge info */
+static void
+l4_charge_info(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_CINF;
+	ic.arg = chanp->chan;
+	sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
+	chanp->sp->iif.statcallb(&ic);
+}
+
+/* error procedures */
+
+static void
+l4_no_dchan(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_NODCH", 0);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_NODCH;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+	chanp->Flags = 0;
+	FsmChangeState(fi, ST_NULL);
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_DHUP", 0);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_DHUP;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+}
+
+static void
+l4_no_dchan_in(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+
+	chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+	chanp->Flags = 0;
+	FsmChangeState(fi, ST_NULL);
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	chanp->Flags = 0;
+	FsmChangeState(fi, ST_NULL);
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+	if (chanp->debug & 1)
+		link_debug(chanp, "STAT_DHUP", 0);
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_DHUP;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+}
+
+static void
+l4_setup_err(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_DRELEASE);
+	if (chanp->Flags & FLG_LL_DCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_DCONN);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	SETBIT(chanp->Flags, FLG_DISC_SEND);	/* DISCONN was sent from L3 */
+}
+
+static void
+l4_connect_err(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	FsmChangeState(fi, ST_WAIT_DRELEASE);
+	if (chanp->Flags & FLG_LL_DCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_DCONN);
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	SETBIT(chanp->Flags, FLG_DISC_SEND);	/* DISCONN was sent from L3 */
+}
+
+static void
+l4_active_dlrl(struct FsmInst *fi, int event, void *arg)
+{
+	struct Channel *chanp = fi->userdata;
+	isdn_ctrl ic;
+
+	chanp->data_open = 0;
+	FsmChangeState(fi, ST_NULL);
+	if (chanp->Flags & FLG_CONNECT_B) {
+		chanp->lc_b.l2_establish = 0;	/* direct reset in lc_b.lcfi */
+		FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+		RESBIT(chanp->Flags, FLG_CONNECT_B);
+	}
+	if (chanp->Flags & FLG_LL_BCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_BHUP", 0);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_BHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+		RESBIT(chanp->Flags, FLG_LL_BCONN);
+	}
+	if (chanp->Flags & FLG_START_B) {
+		release_ds(chanp);
+		RESBIT(chanp->Flags, FLG_START_B);
+	}
+	if (chanp->Flags & FLG_LL_DCONN) {
+		if (chanp->debug & 1)
+			link_debug(chanp, "STAT_DHUP", 0);
+		RESBIT(chanp->Flags, FLG_LL_DCONN);
+		if (chanp->sp->protocol == ISDN_PTYPE_EURO) {
+			chanp->para.cause = 0x2f;
+			chanp->para.loc = 0;
+		} else {
+			chanp->para.cause = 0x70;
+			chanp->para.loc = 0;
+		}
+		l4_deliver_cause(chanp);
+		ic.driver = chanp->sp->myid;
+		ic.command = ISDN_STAT_DHUP;
+		ic.arg = chanp->chan;
+		chanp->sp->iif.statcallb(&ic);
+	}
+	chanp->Flags = 0;
+	chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+/* *INDENT-OFF* */
+static struct FsmNode fnlist[] =
+{
+	{ST_NULL,		EV_DIAL,		l4_prep_dialout},
+	{ST_NULL,		EV_SETUP_IND,		l4_start_dchan},
+	{ST_NULL,		EV_SHUTDOWN_D,		l4_shutdown_d},
+	{ST_NULL,		EV_DLRL,		l4_go_null},
+	{ST_OUT_WAIT_D,		EV_DLEST,		l4_do_dialout},
+	{ST_OUT_WAIT_D,		EV_DLRL,		l4_no_dchan},
+	{ST_OUT_WAIT_D,		EV_HANGUP,		l4_no_dchan},
+	{ST_IN_WAIT_D,		EV_DLEST,		l4_deliver_call},
+	{ST_IN_WAIT_D,		EV_DLRL,		l4_no_dchan_in},
+	{ST_IN_WAIT_D,		EV_HANGUP,		l4_no_dchan_in},
+	{ST_OUT_DIAL,		EV_SETUP_CNF,		l4_init_bchan_out},
+	{ST_OUT_DIAL,		EV_HANGUP,		l4_cancel_call},
+	{ST_OUT_DIAL,		EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_OUT_DIAL,		EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_OUT_DIAL,		EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_OUT_DIAL,		EV_NOSETUP_RSP,		l4_no_setup_rsp},
+	{ST_OUT_DIAL,		EV_SETUP_ERR,		l4_setup_err},
+	{ST_IN_WAIT_LL,		EV_SETUP_CMPL_IND,	l4_init_bchan_in},
+	{ST_IN_WAIT_LL,		EV_ACCEPTD,		l4_send_dconnect},
+	{ST_IN_WAIT_LL,		EV_HANGUP,		l4_reject_call},
+	{ST_IN_WAIT_LL,		EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_IN_WAIT_LL,		EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_IN_WAIT_LL,		EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_IN_ALERT_SEND,	EV_SETUP_CMPL_IND,	l4_init_bchan_in},
+	{ST_IN_ALERT_SEND,	EV_ACCEPTD,		l4_send_dconnect},
+	{ST_IN_ALERT_SEND,	EV_HANGUP,		l4_send_d_disc},
+	{ST_IN_ALERT_SEND,	EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_IN_ALERT_SEND,	EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_IN_ALERT_SEND,	EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_IN_WAIT_CONN_ACK,	EV_SETUP_CMPL_IND,	l4_init_bchan_in},
+	{ST_IN_WAIT_CONN_ACK,	EV_HANGUP,		l4_send_d_disc},
+	{ST_IN_WAIT_CONN_ACK,	EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_IN_WAIT_CONN_ACK,	EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_IN_WAIT_CONN_ACK,	EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_IN_WAIT_CONN_ACK,	EV_CONNECT_ERR,		l4_connect_err},
+	{ST_WAIT_BCONN,		EV_BC_EST,		l4_go_active},
+	{ST_WAIT_BCONN,		EV_BC_REL,		l4_send_d_disc},
+	{ST_WAIT_BCONN,		EV_HANGUP,		l4_send_d_disc},
+	{ST_WAIT_BCONN,		EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_WAIT_BCONN,		EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_WAIT_BCONN,		EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_ACTIVE,		EV_CINF,		l4_charge_info},
+	{ST_ACTIVE,		EV_BC_REL,		l4_released_bchan},
+	{ST_ACTIVE,		EV_HANGUP,		l4_disconn_bchan},
+	{ST_ACTIVE,		EV_DISCONNECT_IND,	l4_release_bchan},
+	{ST_ACTIVE,		EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_ACTIVE,		EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_ACTIVE,		EV_DLRL,		l4_active_dlrl},
+	{ST_WAIT_BRELEASE,	EV_BC_REL,		l4_send_d_disc},
+	{ST_WAIT_BRELEASE,	EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_WAIT_BRELEASE,	EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_WAIT_BRELEASE,	EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_WAIT_BREL_DISC,	EV_BC_REL,		l4_received_d_disc},
+	{ST_WAIT_BREL_DISC,	EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_WAIT_BREL_DISC,	EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_WAIT_DCOMMAND,	EV_HANGUP,		l4_send_d_disc},
+	{ST_WAIT_DCOMMAND,	EV_DISCONNECT_IND,	l4_received_d_disc},
+	{ST_WAIT_DCOMMAND,	EV_RELEASE_CNF,		l4_received_d_relcnf},
+	{ST_WAIT_DCOMMAND,	EV_RELEASE_IND,		l4_received_d_rel},
+	{ST_WAIT_DRELEASE,	EV_RELEASE_IND,		l4_timeout_d},
+	{ST_WAIT_DRELEASE,	EV_RELEASE_CNF,		l4_timeout_d},
+	{ST_WAIT_DRELEASE,	EV_RELEASE_ERR,		l4_timeout_d},
+	{ST_WAIT_DRELEASE,	EV_DIAL,		l4_no_dchan_ready},
+	{ST_WAIT_D_REL_CNF,	EV_RELEASE_CNF,		l4_timeout_d},
+	{ST_WAIT_D_REL_CNF,	EV_RELEASE_ERR,		l4_timeout_d},
+	{ST_WAIT_D_REL_CNF,	EV_DIAL,		l4_no_dchan_ready},
+	{ST_WAIT_DSHUTDOWN,	EV_DLRL,		l4_go_null},
+	{ST_WAIT_DSHUTDOWN,	EV_DIAL,		l4_prep_dialout},
+	{ST_WAIT_DSHUTDOWN,	EV_SETUP_IND,		l4_start_dchan},
+};
+/* *INDENT-ON* */
+
+
+
+
+#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
+
+static void
+lc_r1(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
+	FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
+	lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
+
+}
+
+static void
+lc_r6(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmDelTimer(&lf->act_timer, 50);
+	FsmChangeState(fi, ST_LC_DELAY);
+	FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
+}
+
+static void
+lc_r2(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	if (lf->l2_establish) {
+		FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
+		if (lf->l2_start)
+			lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
+	} else {
+		FsmChangeState(fi, ST_LC_CONNECTED);
+		lf->lccall(lf, LC_ESTABLISH, NULL);
+	}
+}
+
+static void
+lc_r3(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmChangeState(fi, ST_LC_CONNECTED);
+	lf->lccall(lf, LC_ESTABLISH, NULL);
+}
+
+static void
+lc_r7(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmChangeState(fi, ST_LC_FLUSH_WAIT);
+	lf->st->ma.manl2(lf->st, DL_FLUSH, NULL);
+}
+
+static void
+lc_r4(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	if (lf->l2_establish) {
+		FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+		lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
+		/* This timer is for releasing the channel even
+		 * there is a hang in layer 2 ; 5 sec are a try
+		 */
+		FsmAddTimer(&lf->act_timer, 5000, EV_LC_TIMER, NULL, 53);
+	} else {
+		FsmChangeState(fi, ST_LC_NULL);
+		lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+		lf->lccall(lf, LC_RELEASE, NULL);
+	}
+}
+
+static void
+lc_r4_1(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmChangeState(fi, ST_LC_FLUSH_DELAY);
+	FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52);
+}
+
+static void
+lc_r5_1(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+	/* This delay is needed for send out the UA frame before
+	 * PH_DEACTIVATE the interface
+	 */
+	FsmAddTimer(&lf->act_timer, 10, EV_LC_TIMER, NULL, 54);
+}
+
+static void
+lc_r5(struct FsmInst *fi, int event, void *arg)
+{
+	struct LcFsm *lf = fi->userdata;
+
+	FsmDelTimer(&lf->act_timer, 54);
+	FsmChangeState(fi, ST_LC_NULL);
+	lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+	lf->lccall(lf, LC_RELEASE, NULL);
+}
+/* *INDENT-OFF* */
+static struct FsmNode LcFnList[] =
+{
+	{ST_LC_NULL,  		EV_LC_ESTABLISH,	lc_r1},
+	{ST_LC_ACTIVATE_WAIT,	EV_LC_PH_ACTIVATE,	lc_r6},
+	{ST_LC_DELAY,		EV_LC_TIMER,		lc_r2},
+	{ST_LC_DELAY,		EV_LC_DL_ESTABLISH,	lc_r3},
+	{ST_LC_ESTABLISH_WAIT,	EV_LC_DL_ESTABLISH,	lc_r3},
+	{ST_LC_ESTABLISH_WAIT,	EV_LC_RELEASE,		lc_r5},
+	{ST_LC_CONNECTED,	EV_LC_FLUSH,		lc_r7},
+	{ST_LC_CONNECTED,	EV_LC_RELEASE,		lc_r4},
+	{ST_LC_CONNECTED,	EV_LC_DL_RELEASE,	lc_r5_1},
+	{ST_LC_FLUSH_WAIT,	EV_LC_DL_FLUSH,		lc_r4_1},
+	{ST_LC_FLUSH_DELAY,	EV_LC_TIMER,		lc_r4},
+	{ST_LC_RELEASE_WAIT,	EV_LC_DL_RELEASE,	lc_r5},
+	{ST_LC_RELEASE_WAIT,	EV_LC_TIMER,		lc_r5},
+	{ST_LC_ACTIVATE_WAIT,	EV_LC_TIMER,		lc_r5},
+	{ST_LC_ESTABLISH_WAIT,	EV_LC_DL_RELEASE,	lc_r5},
+};
+/* *INDENT-ON* */
+
+
+
+
+
+
+
+
+
+
+#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
+
+void
+CallcNew(void)
+{
+	callcfsm.state_count = STATE_COUNT;
+	callcfsm.event_count = EVENT_COUNT;
+	callcfsm.strEvent = strEvent;
+	callcfsm.strState = strState;
+	FsmNew(&callcfsm, fnlist, FNCOUNT);
+
+	lcfsm.state_count = LC_STATE_COUNT;
+	lcfsm.event_count = LC_EVENT_COUNT;
+	lcfsm.strEvent = strLcEvent;
+	lcfsm.strState = strLcState;
+	FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
+}
+
+void
+CallcFree(void)
+{
+	FsmFree(&lcfsm);
+	FsmFree(&callcfsm);
+}
+
+static void
+release_ds(struct Channel *chanp)
+{
+	struct PStack *st = &chanp->ds;
+	struct IsdnCardState *sp;
+	struct HscxState *hsp;
+
+	sp = st->l1.hardware;
+	hsp = sp->hs + chanp->hscx;
+
+	close_hscxstate(hsp);
+
+	switch (chanp->l2_active_protocol) {
+		case (ISDN_PROTO_L2_X75I):
+			releasestack_isdnl2(st);
+			break;
+		case (ISDN_PROTO_L2_HDLC):
+		case (ISDN_PROTO_L2_TRANS):
+			releasestack_transl2(st);
+			break;
+	}
+	/* Reset B-Channel Statemachine */
+	FsmDelTimer(&chanp->lc_b.act_timer, 79);
+	FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL);
+}
+
+static void
+cc_l1man(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+	switch (pr) {
+		case (PH_ACTIVATE):
+			FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
+			break;
+		case (PH_DEACTIVATE):
+			FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+			break;
+	}
+}
+
+static void
+cc_l2man(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+	switch (pr) {
+		case (DL_ESTABLISH):
+			FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
+			break;
+		case (DL_RELEASE):
+			FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
+			break;
+		case (DL_FLUSH):
+			FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL);
+			break;
+	}
+}
+
+static void
+dcc_l1man(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+	switch (pr) {
+		case (PH_ACTIVATE):
+			FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
+			break;
+		case (PH_DEACTIVATE):
+			FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+			break;
+	}
+}
+
+static void
+dcc_l2man(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+	switch (pr) {
+		case (DL_ESTABLISH):
+			FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+			break;
+		case (DL_RELEASE):
+			FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+			break;
+	}
+}
+
+static void
+l2tei_dummy(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+	char tmp[64], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr);
+	HiSax_putstatus(chanp->sp, tmp);
+}
+
+static void
+ll_handler(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+	char tmp[64], tm[32];
+
+	switch (pr) {
+		case (CC_DISCONNECT_IND):
+			FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
+			break;
+		case (CC_RELEASE_CNF):
+			FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+			break;
+		case (CC_SETUP_IND):
+			FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+			break;
+		case (CC_RELEASE_IND):
+			FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
+			break;
+		case (CC_SETUP_COMPLETE_IND):
+			FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
+			break;
+		case (CC_SETUP_CNF):
+			FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+			break;
+		case (CC_INFO_CHARGE):
+			FsmEvent(&chanp->fi, EV_CINF, NULL);
+			break;
+		case (CC_NOSETUP_RSP_ERR):
+			FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL);
+			break;
+		case (CC_SETUP_ERR):
+			FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL);
+			break;
+		case (CC_CONNECT_ERR):
+			FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL);
+			break;
+		case (CC_RELEASE_ERR):
+			FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
+			break;
+		default:
+			if (chanp->debug & 2048) {
+				jiftime(tm, jiffies);
+				sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n",
+					tm, chanp->chan, pr);
+				HiSax_putstatus(chanp->sp, tmp);
+			}
+	}
+}
+
+static void
+init_is(struct Channel *chanp, unsigned int ces)
+{
+	struct PStack *st = &chanp->is;
+	struct IsdnCardState *sp = chanp->sp;
+	char tmp[128];
+
+	setstack_HiSax(st, sp);
+	st->l2.sap = 0;
+	st->l2.tei = 255;
+	st->l2.ces = ces;
+	st->l2.extended = !0;
+	st->l2.laptype = LAPD;
+	st->l2.window = 1;
+	st->l2.orig = !0;
+	st->l2.t200 = 1000;	/* 1000 milliseconds  */
+	if (st->protocol == ISDN_PTYPE_1TR6) {
+		st->l2.n200 = 3;	/* try 3 times        */
+		st->l2.t203 = 10000;	/* 10000 milliseconds */
+	} else {
+		st->l2.n200 = 4;	/* try 4 times        */
+		st->l2.t203 = 5000;	/* 5000 milliseconds  */
+	}
+	sprintf(tmp, "Channel %d q.921", chanp->chan);
+	setstack_isdnl2(st, tmp);
+	setstack_isdnl3(st, chanp);
+	st->l4.userdata = chanp;
+	st->l4.l2writewakeup = NULL;
+	st->l3.l3l4 = ll_handler;
+	st->l1.l1man = cc_l1man;
+	st->l2.l2man = cc_l2man;
+	st->pa = &chanp->para;
+	HiSax_addlist(sp, st);
+}
+
+static void
+callc_debug(struct FsmInst *fi, char *s)
+{
+	char str[80], tm[32];
+	struct Channel *chanp = fi->userdata;
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
+	HiSax_putstatus(chanp->sp, str);
+}
+
+static void
+lc_debug(struct FsmInst *fi, char *s)
+{
+	char str[256], tm[32];
+	struct LcFsm *lf = fi->userdata;
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
+	HiSax_putstatus(lf->ch->sp, str);
+}
+
+static void
+dlc_debug(struct FsmInst *fi, char *s)
+{
+	char str[256], tm[32];
+	struct LcFsm *lf = fi->userdata;
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
+	HiSax_putstatus(lf->ch->sp, str);
+}
+
+static void
+lccall_d(struct LcFsm *lf, int pr, void *arg)
+{
+	struct Channel *chanp = lf->ch;
+
+	switch (pr) {
+		case (LC_ESTABLISH):
+			FsmEvent(&chanp->fi, EV_DLEST, NULL);
+			break;
+		case (LC_RELEASE):
+			FsmEvent(&chanp->fi, EV_DLRL, NULL);
+			break;
+	}
+}
+
+static void
+lccall_b(struct LcFsm *lf, int pr, void *arg)
+{
+	struct Channel *chanp = lf->ch;
+
+	switch (pr) {
+		case (LC_ESTABLISH):
+			FsmEvent(&chanp->fi, EV_BC_EST, NULL);
+			break;
+		case (LC_RELEASE):
+			FsmEvent(&chanp->fi, EV_BC_REL, NULL);
+			break;
+	}
+}
+
+static void
+init_chan(int chan, struct IsdnCardState *csta, int hscx,
+	  unsigned int ces)
+{
+	struct Channel *chanp = csta->channel + chan;
+
+	chanp->sp = csta;
+	chanp->hscx = hscx;
+	chanp->chan = chan;
+	chanp->incoming = 0;
+	chanp->debug = 0;
+	chanp->Flags = 0;
+	chanp->leased = 0;
+	chanp->impair = 0;
+	init_is(chanp, ces);
+
+	chanp->fi.fsm = &callcfsm;
+	chanp->fi.state = ST_NULL;
+	chanp->fi.debug = 0;
+	chanp->fi.userdata = chanp;
+	chanp->fi.printdebug = callc_debug;
+	FsmInitTimer(&chanp->fi, &chanp->dial_timer);
+	FsmInitTimer(&chanp->fi, &chanp->drel_timer);
+
+	chanp->lc_d.lcfi.fsm = &lcfsm;
+	chanp->lc_d.lcfi.state = ST_LC_NULL;
+	chanp->lc_d.lcfi.debug = 0;
+	chanp->lc_d.lcfi.userdata = &chanp->lc_d;
+	chanp->lc_d.lcfi.printdebug = lc_debug;
+	chanp->lc_d.type = LC_D;
+	chanp->lc_d.ch = chanp;
+	chanp->lc_d.st = &chanp->is;
+	chanp->lc_d.l2_establish = !0;
+	chanp->lc_d.l2_start = !0;
+	chanp->lc_d.lccall = lccall_d;
+	FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
+
+	chanp->lc_b.lcfi.fsm = &lcfsm;
+	chanp->lc_b.lcfi.state = ST_LC_NULL;
+	chanp->lc_b.lcfi.debug = 0;
+	chanp->lc_b.lcfi.userdata = &chanp->lc_b;
+	chanp->lc_b.lcfi.printdebug = dlc_debug;
+	chanp->lc_b.type = LC_B;
+	chanp->lc_b.ch = chanp;
+	chanp->lc_b.st = &chanp->ds;
+	chanp->lc_b.l2_establish = !0;
+	chanp->lc_b.l2_start = !0;
+	chanp->lc_b.lccall = lccall_b;
+	FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
+	chanp->outcallref = 64;
+	chanp->data_open = 0;
+}
+
+int
+CallcNewChan(struct IsdnCardState *csta)
+{
+	int ces;
+
+	chancount += 2;
+	ces = randomces();
+	init_chan(0, csta, 1, ces++);
+	ces %= 0xffff;
+	init_chan(1, csta, 0, ces++);
+	printk(KERN_INFO "HiSax: 2 channels added\n");
+	return (2);
+}
+
+static void
+release_is(struct Channel *chanp)
+{
+	struct PStack *st = &chanp->is;
+
+	releasestack_isdnl2(st);
+	releasestack_isdnl3(st);
+	HiSax_rmlist(st->l1.hardware, st);
+}
+
+void
+CallcFreeChan(struct IsdnCardState *csta)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		FsmDelTimer(&csta->channel[i].drel_timer, 74);
+		FsmDelTimer(&csta->channel[i].dial_timer, 75);
+		FsmDelTimer(&csta->channel[i].lc_b.act_timer, 76);
+		FsmDelTimer(&csta->channel[i].lc_d.act_timer, 77);
+		if (csta->channel[i].Flags & FLG_START_B) {
+			release_ds(csta->channel + i);
+		}
+		release_is(csta->channel + i);
+	}
+}
+
+static void
+lldata_handler(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+	struct sk_buff *skb = arg;
+
+	switch (pr) {
+		case (DL_DATA):
+			if (chanp->data_open)
+				chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+			else {
+				SET_SKB_FREE(skb);
+				dev_kfree_skb(skb, FREE_READ);
+			}
+			break;
+		default:
+			printk(KERN_WARNING "lldata_handler unknown primitive %d\n",
+			       pr);
+			break;
+	}
+}
+
+static void
+lltrans_handler(struct PStack *st, int pr, void *arg)
+{
+	struct Channel *chanp = (struct Channel *) st->l4.userdata;
+	struct sk_buff *skb = arg;
+
+	switch (pr) {
+		case (PH_DATA):
+			if (chanp->data_open)
+				chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+			else {
+				SET_SKB_FREE(skb);
+				dev_kfree_skb(skb, FREE_READ);
+			}
+			break;
+		default:
+			printk(KERN_WARNING "lltrans_handler unknown primitive %d\n",
+			       pr);
+			break;
+	}
+}
+
+static void
+ll_writewakeup(struct PStack *st)
+{
+	struct Channel *chanp = st->l4.userdata;
+	isdn_ctrl ic;
+
+	ic.driver = chanp->sp->myid;
+	ic.command = ISDN_STAT_BSENT;
+	ic.arg = chanp->chan;
+	chanp->sp->iif.statcallb(&ic);
+}
+
+static int
+init_ds(struct Channel *chanp, int incoming)
+{
+	struct PStack *st = &chanp->ds;
+	struct IsdnCardState *sp = chanp->sp;
+	struct HscxState *hsp = sp->hs + chanp->hscx;
+	char tmp[128];
+
+	st->l1.hardware = sp;
+
+	hsp->mode = 2;
+
+	if (setstack_hscx(st, hsp))
+		return (-1);
+
+	st->l2.extended = 0;
+	st->l2.laptype = LAPB;
+	st->l2.orig = !incoming;
+	st->l2.t200 = 1000;	/* 1000 milliseconds */
+	st->l2.window = 7;
+	st->l2.n200 = 4;	/* try 4 times       */
+	st->l2.t203 = 5000;	/* 5000 milliseconds */
+
+	st->l3.debug = 0;
+	switch (chanp->l2_active_protocol) {
+		case (ISDN_PROTO_L2_X75I):
+			sprintf(tmp, "Channel %d x.75", chanp->chan);
+			setstack_isdnl2(st, tmp);
+			st->l2.l2l3 = lldata_handler;
+			st->l1.l1man = dcc_l1man;
+			st->l2.l2man = dcc_l2man;
+			st->l2.l2tei = l2tei_dummy;
+			st->l4.userdata = chanp;
+			st->l4.l1writewakeup = NULL;
+			st->l4.l2writewakeup = ll_writewakeup;
+			st->l2.l2m.debug = chanp->debug & 16;
+			st->l2.debug = chanp->debug & 64;
+			st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+			st->l1.hscxmode = 2;	/* Packet-Mode ? */
+			st->l1.hscxchannel = chanp->para.bchannel - 1;
+			break;
+		case (ISDN_PROTO_L2_HDLC):
+			st->l1.l1l2 = lltrans_handler;
+			st->l1.l1man = dcc_l1man;
+			st->l4.userdata = chanp;
+			st->l4.l1writewakeup = ll_writewakeup;
+			st->l1.hscxmode = 2;
+			st->l1.hscxchannel = chanp->para.bchannel - 1;
+			break;
+		case (ISDN_PROTO_L2_TRANS):
+			st->l1.l1l2 = lltrans_handler;
+			st->l1.l1man = dcc_l1man;
+			st->l4.userdata = chanp;
+			st->l4.l1writewakeup = ll_writewakeup;
+			st->l1.hscxmode = 1;
+			st->l1.hscxchannel = chanp->para.bchannel - 1;
+			break;
+	}
+	return (0);
+}
+
+static void
+channel_report(struct Channel *chanp)
+{
+}
+
+static void
+distr_debug(struct IsdnCardState *csta, int debugflags)
+{
+	int i;
+	struct Channel *chanp = csta->channel;
+
+	for (i = 0; i < 2; i++) {
+		chanp[i].debug = debugflags;
+		chanp[i].fi.debug = debugflags & 2;
+		chanp[i].is.l2.l2m.debug = debugflags & 8;
+		chanp[i].ds.l2.l2m.debug = debugflags & 16;
+		chanp[i].is.l2.debug = debugflags & 32;
+		chanp[i].ds.l2.debug = debugflags & 64;
+		chanp[i].lc_d.lcfi.debug = debugflags & 128;
+		chanp[i].lc_b.lcfi.debug = debugflags & 256;
+	}
+	csta->dlogflag = debugflags & 4;
+	csta->teistack->l2.l2m.debug = debugflags & 512;
+}
+
+int
+HiSax_command(isdn_ctrl * ic)
+{
+	struct IsdnCardState *csta = hisax_findcard(ic->driver);
+	struct Channel *chanp;
+	char tmp[128];
+	int i;
+	unsigned int num;
+
+	if (!csta) {
+		printk(KERN_ERR
+		"HiSax: if_command %d called with invalid driverId %d!\n",
+		       ic->command, ic->driver);
+		return -ENODEV;
+	}
+	switch (ic->command) {
+		case (ISDN_CMD_SETEAZ):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1)
+				link_debug(chanp, "SETEAZ", 1);
+			break;
+		case (ISDN_CMD_SETL2):
+			chanp = csta->channel + (ic->arg & 0xff);
+			if (chanp->debug & 1) {
+				sprintf(tmp, "SETL2 card %d %ld", csta->cardnr + 1,
+					ic->arg >> 8);
+				link_debug(chanp, tmp, 1);
+			}
+			chanp->l2_protocol = ic->arg >> 8;
+			break;
+		case (ISDN_CMD_DIAL):
+			chanp = csta->channel + (ic->arg & 0xff);
+			if (chanp->debug & 1) {
+				sprintf(tmp, "DIAL %s -> %s (%d,%d)",
+					ic->parm.setup.eazmsn, ic->parm.setup.phone,
+				 ic->parm.setup.si1, ic->parm.setup.si2);
+				link_debug(chanp, tmp, 1);
+			}
+			chanp->para.setup = ic->parm.setup;
+			if (!strcmp(chanp->para.setup.eazmsn, "0"))
+				chanp->para.setup.eazmsn[0] = '\0';
+			/* this solution is dirty and may be change, if
+			 * we make a callreference based callmanager */
+			if (chanp->fi.state == ST_NULL) {
+				FsmEvent(&chanp->fi, EV_DIAL, NULL);
+			} else {
+				FsmDelTimer(&chanp->dial_timer, 70);
+				FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71);
+			}
+			break;
+		case (ISDN_CMD_ACCEPTB):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1)
+				link_debug(chanp, "ACCEPTB", 1);
+			FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
+			break;
+		case (ISDN_CMD_ACCEPTD):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1)
+				link_debug(chanp, "ACCEPTD", 1);
+			FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
+			break;
+		case (ISDN_CMD_HANGUP):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1)
+				link_debug(chanp, "HANGUP", 1);
+			FsmEvent(&chanp->fi, EV_HANGUP, NULL);
+			break;
+		case (ISDN_CMD_SUSPEND):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1) {
+				sprintf(tmp, "SUSPEND %s", ic->parm.num);
+				link_debug(chanp, tmp, 1);
+			}
+			FsmEvent(&chanp->fi, EV_SUSPEND, ic);
+			break;
+		case (ISDN_CMD_RESUME):
+			chanp = csta->channel + ic->arg;
+			if (chanp->debug & 1) {
+				sprintf(tmp, "RESUME %s", ic->parm.num);
+				link_debug(chanp, tmp, 1);
+			}
+			FsmEvent(&chanp->fi, EV_RESUME, ic);
+			break;
+		case (ISDN_CMD_LOCK):
+			HiSax_mod_inc_use_count();
+#ifdef MODULE
+			if (csta->channel[0].debug & 1024) {
+				jiftime(tmp, jiffies);
+				i = strlen(tmp);
+				sprintf(tmp + i, "   LOCK modcnt %lx\n", MOD_USE_COUNT);
+				HiSax_putstatus(csta, tmp);
+			}
+#endif				/* MODULE */
+			break;
+		case (ISDN_CMD_UNLOCK):
+			HiSax_mod_dec_use_count();
+#ifdef MODULE
+			if (csta->channel[0].debug & 1024) {
+				jiftime(tmp, jiffies);
+				i = strlen(tmp);
+				sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT);
+				HiSax_putstatus(csta, tmp);
+			}
+#endif				/* MODULE */
+			break;
+		case (ISDN_CMD_IOCTL):
+			switch (ic->arg) {
+				case (0):
+					HiSax_reportcard(csta->cardnr);
+					for (i = 0; i < 2; i++)
+						channel_report(&csta->channel[i]);
+					break;
+				case (1):
+					num = *(unsigned int *) ic->parm.num;
+					distr_debug(csta, num);
+					sprintf(tmp, "debugging flags card %d set to %x\n",
+						csta->cardnr + 1, num);
+					HiSax_putstatus(csta, tmp);
+					printk(KERN_DEBUG "HiSax: %s", tmp);
+					break;
+				case (2):
+					num = *(unsigned int *) ic->parm.num;
+					i = num >> 8;
+					if (i >= 2)
+						break;
+					chanp = csta->channel + i;
+					chanp->impair = num & 0xff;
+					if (chanp->debug & 1) {
+						sprintf(tmp, "IMPAIR %x", chanp->impair);
+						link_debug(chanp, tmp, 1);
+					}
+					break;
+				case (3):
+					for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
+						HiSax_mod_dec_use_count();
+					break;
+				case (4):
+					for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
+						HiSax_mod_inc_use_count();
+					break;
+				case (5):	/* set card in leased mode */
+					csta->channel[0].leased = 1;
+					csta->channel[1].leased = 1;
+					sprintf(tmp, "card %d set into leased mode\n",
+						csta->cardnr + 1);
+					HiSax_putstatus(csta, tmp);
+					break;
+#ifdef MODULE
+				case (55):
+#if (LINUX_VERSION_CODE < 0x020111)
+					MOD_USE_COUNT = MOD_VISITED;
+#else
+					MOD_USE_COUNT = 0;
+#endif
+					HiSax_mod_inc_use_count();
+					break;
+#endif				/* MODULE */
+				case (11):
+					csta->debug = *(unsigned int *) ic->parm.num;
+					sprintf(tmp, "l1 debugging flags card %d set to %x\n",
+					  csta->cardnr + 1, csta->debug);
+					HiSax_putstatus(cards[0].sp, tmp);
+					printk(KERN_DEBUG "HiSax: %s", tmp);
+					break;
+				case (13):
+					csta->channel[0].is.l3.debug = *(unsigned int *) ic->parm.num;
+					csta->channel[1].is.l3.debug = *(unsigned int *) ic->parm.num;
+					sprintf(tmp, "l3 debugging flags card %d set to %x\n",
+						csta->cardnr + 1, *(unsigned int *) ic->parm.num);
+					HiSax_putstatus(cards[0].sp, tmp);
+					printk(KERN_DEBUG "HiSax: %s", tmp);
+					break;
+				default:
+					printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
+					       (int) ic->arg);
+					return (-EINVAL);
+			}
+			break;
+		default:
+			break;
+	}
+
+	return (0);
+}
+
+int
+HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
+{
+	struct IsdnCardState *csta = hisax_findcard(id);
+	struct Channel *chanp;
+	struct PStack *st;
+	int len = skb->len;
+	unsigned long flags;
+	struct sk_buff *nskb;
+	char tmp[64];
+
+	if (!csta) {
+		printk(KERN_ERR
+		    "HiSax: if_sendbuf called with invalid driverId!\n");
+		return -ENODEV;
+	}
+	chanp = csta->channel + chan;
+	st = &chanp->ds;
+	if (!chanp->data_open) {
+		link_debug(chanp, "writebuf: channel not open", 1);
+		return -EIO;
+	}
+	if (len > MAX_DATA_SIZE) {
+		sprintf(tmp, "writebuf: packet too large (%d bytes)", len);
+		printk(KERN_WARNING "HiSax_%s !\n", tmp);
+		link_debug(chanp, tmp, 1);
+		return -EINVAL;
+	}
+	if (len) {
+		if ((len + csta->hs[chanp->hscx].tx_cnt) > MAX_DATA_MEM) {
+			/* Must return 0 here, since this is not an error
+			 * but a temporary lack of resources.
+			 */
+			if (chanp->debug & 2048) {
+				sprintf(tmp, "writebuf: no buffers for %d bytes", len);
+				link_debug(chanp, tmp, 1);
+			}
+			return 0;
+		}
+		save_flags(flags);
+		cli();
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (nskb) {
+			if (chanp->lc_b.l2_establish) {
+				csta->hs[chanp->hscx].tx_cnt += len + st->l2.ihsize;
+				chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, nskb);
+			} else {
+				csta->hs[chanp->hscx].tx_cnt += len;
+				chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, nskb);
+			}
+			dev_kfree_skb(skb, FREE_WRITE);
+		} else
+			len = 0;
+		restore_flags(flags);
+	}
+	return (len);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/config.c linux-2.0.31-pre3/drivers/isdn/hisax/config.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/config.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/config.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,425 @@
+/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ *
+ * $Log: config.c,v $
+ * Revision 1.15  1997/04/06 22:57:24  keil
+ * Hisax version 2.1
+ *
+ * Revision 1.14  1997/03/25 23:11:22  keil
+ * US NI-1 protocol
+ *
+ * Revision 1.13  1997/03/23 21:45:49  keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.12  1997/03/11 21:01:43  keil
+ * nzproto is only used with modules
+ *
+ * Revision 1.11  1997/02/14 12:23:12  fritz
+ * Added support for new insmod parameter handling.
+ *
+ * Revision 1.10  1997/02/14 09:22:09  keil
+ * Final 2.0 version
+ *
+ * Revision 1.9  1997/02/10 11:45:09  fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.8  1997/02/09 00:28:05  keil
+ * new interface handling, one interface per card
+ * default protocol now works again
+ *
+ * Revision 1.7  1997/01/27 15:56:57  keil
+ * Teles PCMCIA ITK ix1 micro added
+ *
+ * Revision 1.6  1997/01/21 22:17:56  keil
+ * new module load syntax
+ *
+ * Revision 1.5  1997/01/09 18:28:20  keil
+ * cosmetic cleanups
+ *
+ * Revision 1.4  1996/11/05 19:35:17  keil
+ * using config.h; some spelling fixes
+ *
+ * Revision 1.3  1996/10/23 17:23:28  keil
+ * default config changes
+ *
+ * Revision 1.2  1996/10/23 11:58:48  fritz
+ * Changed default setup to reflect user's selection of supported
+ * cards/protocols.
+ *
+ * Revision 1.1  1996/10/13 20:04:51  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include "hisax.h"
+
+/*
+ * This structure array contains one entry per card. An entry looks
+ * like this:
+ *
+ * { type, protocol, p0, p1, p2, NULL }
+ *
+ * type
+ *    1 Teles 16.0      p0=irq p1=membase p2=iobase
+ *    2 Teles  8.0      p0=irq p1=membase
+ *    3 Teles 16.3      p0=irq p1=iobase
+ *    4 Creatix PNP     p0=irq p1=IO0 (ISAC)  p2=IO1 (HSCX)
+ *    5 AVM A1 (Fritz)  p0=irq p1=iobase
+ *    6 ELSA PC         [p0=iobase] or nothing (autodetect)
+ *    7 ELSA Quickstep  p0=irq p1=iobase
+ *      ELSA PCMCIA     p0=irq p1=iobase
+ *    8 Teles PCMCIA    p0=irq p1=iobase
+ *    9 ITK ix1-micro   p0=irq p1=iobase
+ *
+ *
+ * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
+ *
+ *
+ */
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+#define DEFAULT_CARD ISDN_CTYPE_ELSA
+#define DEFAULT_CFG {0,0,0}
+#endif
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+#define DEFAULT_CARD ISDN_CTYPE_ELSA_QS1000
+#define DEFAULT_CFG {3,0x2f8,0}
+#endif
+#ifdef CONFIG_HISAX_AVM_A1
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_A1
+#define DEFAULT_CFG {10,0x340,0}
+#endif
+#ifdef CONFIG_HISAX_16_3
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_3
+#define DEFAULT_CFG {15,0x180,0}
+#endif
+#ifdef CONFIG_HISAX_16_0
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_0
+#define DEFAULT_CFG {15,0xd0000,0xd80}
+#endif
+
+#ifdef CONFIG_HISAX_IX1MICROR2
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
+#define DEFAULT_CFG {5,0x390,0}
+#endif
+
+#ifdef CONFIG_HISAX_1TR6
+#define DEFAULT_PROTO ISDN_PTYPE_1TR6
+#define DEFAULT_PROTO_NAME "1TR6"
+#endif
+#ifdef CONFIG_HISAX_EURO
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_EURO
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "EURO"
+#endif
+#ifdef CONFIG_HISAX_NI1
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_NI1
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "NI1"
+#endif
+#ifndef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
+#define DEFAULT_PROTO_NAME "UNKNOWN"
+#endif
+#ifndef DEFAULT_CARD
+#error "HiSax: No cards configured"
+#endif
+
+#define FIRST_CARD { \
+  DEFAULT_CARD, \
+  DEFAULT_PROTO, \
+  DEFAULT_CFG, \
+  NULL, \
+}
+
+#define EMPTY_CARD	{0, DEFAULT_PROTO, {0, 0, 0}, NULL}
+
+struct IsdnCard cards[] =
+{
+	FIRST_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+	EMPTY_CARD,
+};
+
+static char HiSaxID[96] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+char *HiSax_id = HiSaxID;
+#ifdef MODULE
+/* Variables for insmod */
+int type[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int protocol[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int io[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#ifdef CONFIG_HISAX_16_3	/* For Creatix/Teles PnP */
+int io0[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int io1[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+int irq[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int mem[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+char *id = HiSaxID;
+
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_AUTHOR("Karsten Keil");
+MODULE_PARM(type, "1-16i");
+MODULE_PARM(protocol, "1-16i");
+MODULE_PARM(io, "1-16i");
+MODULE_PARM(irq, "1-16i");
+MODULE_PARM(mem, "1-16i");
+MODULE_PARM(id, "s");
+#ifdef CONFIG_HISAX_16_3	/* For Creatix/Teles PnP */
+MODULE_PARM(io0, "1-16i");
+MODULE_PARM(io1, "1-16i");
+#endif
+#endif
+
+#endif
+
+extern char *l1_revision;
+extern char *l2_revision;
+extern char *l3_revision;
+extern char *l4_revision;
+extern char *tei_revision;
+
+char *
+HiSax_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
+}
+
+int nrcards;
+
+void
+HiSax_mod_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+void
+HiSax_mod_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+#ifdef MODULE
+#define HiSax_init init_module
+#else
+void
+HiSax_setup(char *str, int *ints)
+{
+	int i, j, argc;
+
+	argc = ints[0];
+	i = 0;
+	j = 1;
+	while (argc && (i < 16)) {
+		if (argc) {
+			cards[i].typ = ints[j];
+			j++;
+			argc--;
+		}
+		if (argc) {
+			cards[i].protocol = ints[j];
+			j++;
+			argc--;
+		}
+		if (argc) {
+			cards[i].para[0] = ints[j];
+			j++;
+			argc--;
+		}
+		if (argc) {
+			cards[i].para[1] = ints[j];
+			j++;
+			argc--;
+		}
+		if (argc) {
+			cards[i].para[2] = ints[j];
+			j++;
+			argc--;
+		}
+		i++;
+	}
+	if (strlen(str)) {
+		strcpy(HiSaxID, str);
+		HiSax_id = HiSaxID;
+	} else {
+		strcpy(HiSaxID, "HiSax");
+		HiSax_id = HiSaxID;
+	}
+}
+#endif
+
+int
+HiSax_init(void)
+{
+	int i;
+	char tmp[64], rev[64];
+	char *r = rev;
+#ifdef MODULE
+	int nzproto = 0;
+#endif
+	nrcards = 0;
+	strcpy(tmp, l1_revision);
+	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	strcpy(tmp, l2_revision);
+	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	strcpy(tmp, l3_revision);
+	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	strcpy(tmp, l4_revision);
+	r += sprintf(r, "%s/", HiSax_getrev(tmp));
+	strcpy(tmp, tei_revision);
+	r += sprintf(r, "%s", HiSax_getrev(tmp));
+
+	printk(KERN_NOTICE "HiSax: Driver for Siemens chip set ISDN cards\n");
+	printk(KERN_NOTICE "HiSax: Version 2.1\n");
+	printk(KERN_NOTICE "HiSax: Revisions %s\n", rev);
+
+#ifdef MODULE
+	if (id)			/* If id= string used */
+		HiSax_id = id;
+	for (i = 0; i < 16; i++) {
+		cards[i].typ = type[i];
+		if (protocol[i]) {
+			cards[i].protocol = protocol[i];
+			nzproto++;
+		}
+		switch (type[i]) {
+			case ISDN_CTYPE_16_0:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = mem[i];
+				cards[i].para[2] = io[i];
+				break;
+
+			case ISDN_CTYPE_8_0:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = mem[i];
+				break;
+
+			case ISDN_CTYPE_16_3:
+			case ISDN_CTYPE_TELESPCMCIA:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = io[i];
+				break;
+
+#ifdef CONFIG_HISAX_16_3	/* For Creatix/Teles PnP */
+			case ISDN_CTYPE_PNP:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = io0[i];
+				cards[i].para[2] = io1[i];
+				break;
+#endif
+			case ISDN_CTYPE_A1:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = io[i];
+				break;
+
+			case ISDN_CTYPE_ELSA:
+				cards[i].para[0] = io[i];
+				break;
+			case ISDN_CTYPE_ELSA_QS1000:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = io[i];
+				break;
+
+			case ISDN_CTYPE_IX1MICROR2:
+				cards[i].para[0] = irq[i];
+				cards[i].para[1] = io[i];
+				break;
+
+		}
+	}
+	if (!nzproto) {
+		printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
+		printk(KERN_WARNING "HiSax: Note! module load syntax has changed.\n");
+		printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
+	}
+#endif
+	if (!HiSax_id)
+		HiSax_id = HiSaxID;
+	if (!HiSaxID[0])
+		strcpy(HiSaxID, "HiSax");
+	for (i = 0; i < 16; i++)
+		if (cards[i].typ > 0)
+			nrcards++;
+	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+	       nrcards, (nrcards > 1) ? "s" : "");
+
+	CallcNew();
+	Isdnl2New();
+	if (HiSax_inithardware()) {
+		/* Install only, if at least one card found */
+		/* No symbols to export, hide all symbols */
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x020111)
+		register_symtab(NULL);
+#else
+		EXPORT_NO_SYMBOLS;
+#endif
+		printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+		return (0);
+	} else {
+		Isdnl2Free();
+		CallcFree();
+		return -EIO;
+	}
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+	HiSax_closehardware();
+	printk(KERN_NOTICE "HiSax module removed\n");
+}
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/elsa.c linux-2.0.31-pre3/drivers/isdn/hisax/elsa.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/elsa.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/elsa.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1487 @@
+/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+
+ * elsa.c     low level stuff for Elsa isdn cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Elsa GmbH for documents and informations
+ *
+ *
+ * $Log: elsa.c,v $
+ * Revision 1.14  1997/04/13 19:53:25  keil
+ * Fixed QS1000 init, change in IRQ check delay for SMP
+ *
+ * Revision 1.13  1997/04/07 22:58:07  keil
+ * need include config.h
+ *
+ * Revision 1.12  1997/04/06 22:54:14  keil
+ * Using SKB's
+ *
+ * Revision 1.11  1997/03/23 21:45:46  keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.10  1997/03/12 21:42:19  keil
+ * Bugfix: IRQ hangs with QS1000
+ *
+ * Revision 1.9  1997/03/04 15:57:39  keil
+ * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ *
+ * Revision 1.8  1997/01/27 15:51:48  keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.7  1997/01/21 22:20:48  keil
+ * Elsa Quickstep support
+ *
+ * Revision 1.6  1997/01/09 18:22:46  keil
+ * one more PCC-8 fix
+ *
+ * Revision 1.5  1996/12/08 19:46:14  keil
+ * PCC-8 correct IRQs; starting ARCOFI support
+ *
+ * Revision 1.4  1996/11/18 20:50:54  keil
+ * with PCF Pro release 16 Byte IO
+ *
+ * Revision 1.3  1996/11/18 15:33:04  keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.2  1996/10/27 22:08:03  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:52  keil
+ * Initial revision
+ *
+ *
+ */
+
+#define ARCOFI_USE	0
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "siemens.h"
+#include "hisax.h"
+#include "elsa.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+
+const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_Types[] =
+{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
+ "PCMCIA", "QS 1000", "QS 3000"};
+
+const char *ITACVer[] =
+{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
+ "B1", "A1"};
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readhscx(unsigned int adr, int hscx, u_char off)
+{
+	register u_char ret;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
+	ret = bytein(adr + CARD_HSCX);
+	restore_flags(flags);
+	return (ret);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+	/* fifo read without cli because it's allready done  */
+
+	byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
+	insb(adr + CARD_HSCX, data, size);
+}
+
+
+static inline void
+writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
+	byteout(adr + CARD_HSCX, data);
+	restore_flags(flags);
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+	/* fifo write without cli because it's allready done  */
+	byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
+	outsb(adr + CARD_HSCX, data, size);
+}
+
+static inline u_char
+readisac(unsigned int adr, u_char off)
+{
+	register u_char ret;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off + 0x20);
+	ret = bytein(adr + CARD_ISAC);
+	restore_flags(flags);
+	return (ret);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+	/* fifo read without cli because it's allready done  */
+
+	byteout(adr + CARD_ALE, 0);
+	insb(adr + CARD_ISAC, data, size);
+}
+
+
+static inline void
+writeisac(unsigned int adr, u_char off, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off + 0x20);
+	byteout(adr + CARD_ISAC, data);
+	restore_flags(flags);
+}
+
+static inline void
+write_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+	/* fifo write without cli because it's allready done  */
+
+	byteout(adr + CARD_ALE, 0);
+	outsb(adr + CARD_ISAC, data, size);
+}
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+static inline u_char
+readitac(unsigned int adr, u_char off)
+{
+	register u_char ret;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off);
+	ret = bytein(adr + CARD_ITAC);
+	restore_flags(flags);
+	return (ret);
+}
+
+static inline void
+writeitac(unsigned int adr, u_char off, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	byteout(adr + CARD_ALE, off);
+	byteout(adr + CARD_ITAC, data);
+	restore_flags(flags);
+}
+
+static inline int
+TimerRun(struct IsdnCardState *sp)
+{
+	register u_char val;
+
+	val = bytein(sp->cfg_reg + CARD_CONFIG);
+	if (sp->subtyp == ELSA_QS1000)
+		return (0 == (val & TIMER_RUN));
+	else if (sp->subtyp == ELSA_PCC8)
+		return (val & TIMER_RUN_PCC8);
+	return (val & TIMER_RUN);
+}
+
+static inline void
+elsa_led_handler(struct IsdnCardState *sp)
+{
+
+	u_char outval = 0xf0;
+	int stat = 0, cval;
+
+
+	if ((sp->ph_state == 0) || (sp->ph_state == 15)) {
+		stat = 1;
+	} else {
+		if (sp->hs[0].mode != 0)
+			stat |= 2;
+		if (sp->hs[1].mode != 0)
+			stat |= 4;
+	}
+	cval = (sp->counter >> 6) & 3;
+	switch (cval) {
+		case 0:
+			if (!stat)
+				outval |= STAT_LED;
+			else if (stat == 1)
+				outval |= LINE_LED | STAT_LED;
+			else {
+				if (stat & 2)
+					outval |= STAT_LED;
+				if (stat & 4)
+					outval |= LINE_LED;
+			}
+			break;
+		case 1:
+			if (!stat)
+				outval |= LINE_LED;
+			else if (stat == 1)
+				outval |= LINE_LED | STAT_LED;
+			else {
+				if (stat & 2)
+					outval |= STAT_LED;
+				if (stat & 4)
+					outval |= LINE_LED;
+			}
+			break;
+		case 2:
+			if (!stat)
+				outval |= STAT_LED;
+			else if (stat == 1)
+				outval |= 0;
+			else {
+				if (stat & 2)
+					outval |= STAT_LED;
+				if (stat & 4)
+					outval |= LINE_LED;
+			}
+			break;
+		case 3:
+			if (!stat)
+				outval |= LINE_LED;
+			break;
+	}
+	byteout(sp->cfg_reg + CARD_CONTROL, outval);
+}
+#endif
+
+static inline void
+waitforCEC(int adr, int hscx)
+{
+	int to = 50;
+
+	while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int hscx)
+{
+	int to = 50;
+
+	while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr, hscx);
+	writehscx(adr, hscx, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+	printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR));
+}
+
+void
+elsa_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *sp = hsp->sp;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvidx + count > HSCX_BUFMAX) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+		hsp->rcvidx = 0;
+		return;
+	}
+	ptr = hsp->rcvbuf + hsp->rcvidx;
+	hsp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+	writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState *sp = hsp->sp;
+	int more, count;
+	u_char *ptr;
+	long flags;
+
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	if (!hsp->tx_skb)
+		return;
+	if (hsp->tx_skb->len <= 0)
+		return;
+
+	more = (hsp->mode == 1) ? 1 : 0;
+	if (hsp->tx_skb->len > 32) {
+		more = !0;
+		count = 32;
+	} else
+		count = hsp->tx_skb->len;
+
+	waitforXFW(sp->cfg_reg, hsp->hscx);
+	save_flags(flags);
+	cli();
+	ptr = hsp->tx_skb->data;
+	skb_pull(hsp->tx_skb, count);
+	hsp->tx_cnt -= count;
+	hsp->count += count;
+	write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+	writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+	u_char r;
+	struct HscxState *hsp = sp->hs + hscx;
+	struct sk_buff *skb;
+	int count;
+	char tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode)
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+		} else {
+			count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			hscx_empty_fifo(hsp, count);
+			if ((count = hsp->rcvidx - 1) > 0) {
+				if (sp->debug & L1_DEB_HSCX_FIFO) {
+					sprintf(tmp, "HX Frame %d", count);
+					debugl1(sp, tmp);
+				}
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "Elsa: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+					skb_queue_tail(&hsp->rqueue, skb);
+				}
+			}
+		}
+		hsp->rcvidx = 0;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		hscx_empty_fifo(hsp, 32);
+		if (hsp->mode == 1) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(32)))
+				printk(KERN_WARNING "elsa: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+				skb_queue_tail(&hsp->rqueue, skb);
+			}
+			hsp->rcvidx = 0;
+			hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (hsp->tx_skb)
+			if (hsp->tx_skb->len) {
+				hscx_fill_fifo(hsp);
+				return;
+			} else {
+				dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+				hsp->count = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->tx_skb = NULL;
+			}
+		if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+			hsp->count = 0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_empty_fifo");
+
+	if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+		if (sp->debug & L1_DEB_WARN) {
+			char tmp[40];
+			sprintf(tmp, "isac_empty_fifo overrun %d",
+				sp->rcvidx + count);
+			debugl1(sp, tmp);
+		}
+		writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+		sp->rcvidx = 0;
+		return;
+	}
+	ptr = sp->rcvbuf + sp->rcvidx;
+	sp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo_isac(sp->cfg_reg, ptr, count);
+	writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_fill_fifo");
+
+	if (!sp->tx_skb)
+		return;
+
+	count = sp->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = sp->tx_skb->data;
+	skb_pull(sp->tx_skb, count);
+	sp->tx_cnt += count;
+	write_fifo_isac(sp->cfg_reg, ptr, count);
+	writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+		debugl1(sp, tmp);
+	}
+	writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+	u_char exval, v1;
+	struct sk_buff *skb;
+	unsigned int count;
+	char tmp[32];
+#if ARCOFI_USE
+	struct BufHeader *ibh;
+	u_char *ptr;
+#endif
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+		debugl1(sp, tmp);
+	}
+	if (val & 0x80) {	/* RME */
+		exval = readisac(sp->cfg_reg, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC CRC error");
+			writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+		} else {
+			count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			isac_empty_fifo(sp, count);
+			if ((count = sp->rcvidx) > 0) {
+				sp->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "Elsa: D receive out of memory\n");
+				else {
+					SET_SKB_FREE(skb);
+					memcpy(skb_put(skb, count), sp->rcvbuf, count);
+					skb_queue_tail(&sp->rq, skb);
+				}
+			}
+		}
+		sp->rcvidx = 0;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		isac_empty_fifo(sp, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->tx_skb)
+			if (sp->tx_skb->len) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+				sp->tx_cnt = 0;
+				sp->tx_skb = NULL;
+			}
+		if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+			sp->tx_cnt = 0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2)
+		    & 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+			sprintf(tmp, "l1state %d", sp->ph_state);
+			debugl1(sp, tmp);
+		}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readisac(sp->cfg_reg, ISAC_EXIR);
+		if (sp->debug & L1_DEB_WARN) {
+			sprintf(tmp, "ISAC EXIR %02x", exval);
+			debugl1(sp, tmp);
+		}
+		if (exval & 0x08) {
+			v1 = readisac(sp->cfg_reg, ISAC_MOSR);
+			if (sp->debug & L1_DEB_WARN) {
+				sprintf(tmp, "ISAC MOSR %02x", v1);
+				debugl1(sp, tmp);
+			}
+#if ARCOFI_USE
+			if (v1 & 0x08) {
+				if (!sp->mon_rx)
+					if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+					    GFP_ATOMIC, (void *) 1, 3)) {
+						if (sp->debug & L1_DEB_WARN)
+							debugl1(sp, "ISAC MON RX out of buffers!");
+						writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+						goto afterMONR0;
+					} else
+						sp->mon_rxp = 0;
+				ibh = sp->mon_rx;
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_rxp;
+				sp->mon_rxp++;
+				if (sp->mon_rxp >= 3072) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+					sp->mon_rxp = 0;
+					if (sp->debug & L1_DEB_WARN)
+						debugl1(sp, "ISAC MON RX overflow!");
+					goto afterMONR0;
+				}
+				*ptr = readisac(sp->cfg_reg, ISAC_MOR0);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "ISAC MOR0 %02x", *ptr);
+					debugl1(sp, tmp);
+				}
+			}
+		      afterMONR0:
+			if (v1 & 0x80) {
+				if (!sp->mon_rx)
+					if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+					    GFP_ATOMIC, (void *) 1, 3)) {
+						if (sp->debug & L1_DEB_WARN)
+							debugl1(sp, "ISAC MON RX out of buffers!");
+						writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+						goto afterMONR1;
+					} else
+						sp->mon_rxp = 0;
+				ibh = sp->mon_rx;
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_rxp;
+				sp->mon_rxp++;
+				if (sp->mon_rxp >= 3072) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+					sp->mon_rxp = 0;
+					if (sp->debug & L1_DEB_WARN)
+						debugl1(sp, "ISAC MON RX overflow!");
+					goto afterMONR1;
+				}
+				*ptr = readisac(sp->cfg_reg, ISAC_MOR1);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "ISAC MOR1 %02x", *ptr);
+					debugl1(sp, tmp);
+				}
+			}
+		      afterMONR1:
+			if (v1 & 0x04) {
+				writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+				sp->mon_rx->datasize = sp->mon_rxp;
+				sp->mon_flg |= MON0_RX;
+			}
+			if (v1 & 0x40) {
+				writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+				sp->mon_rx->datasize = sp->mon_rxp;
+				sp->mon_flg |= MON1_RX;
+			}
+			if (v1 == 0x02) {
+				ibh = sp->mon_tx;
+				if (!ibh) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+					goto AfterMOX0;
+				}
+				count = ibh->datasize - sp->mon_txp;
+				if (count <= 0) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
+					BufPoolRelease(sp->mon_tx);
+					sp->mon_tx = NULL;
+					sp->mon_txp = 0;
+					sp->mon_flg |= MON0_TX;
+					goto AfterMOX0;
+				}
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_txp;
+				sp->mon_txp++;
+				writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
+			}
+		      AfterMOX0:
+			if (v1 == 0x20) {
+				ibh = sp->mon_tx;
+				if (!ibh) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+					goto AfterMOX1;
+				}
+				count = ibh->datasize - sp->mon_txp;
+				if (count <= 0) {
+					writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
+					BufPoolRelease(sp->mon_tx);
+					sp->mon_tx = NULL;
+					sp->mon_txp = 0;
+					sp->mon_flg |= MON1_TX;
+					goto AfterMOX1;
+				}
+				ptr = DATAPTR(ibh);
+				ptr += sp->mon_txp;
+				sp->mon_txp++;
+				writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
+			}
+		      AfterMOX1:
+#endif
+		}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+	u_char exval;
+	struct HscxState *hsp;
+	char tmp[32];
+
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+		exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+		exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0x04) {
+		exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	u_char val;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+	if (!sp) {
+		printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+		return;
+	}
+#ifdef CONFIG_HISAX_ELSA_PCC
+      INT_RESTART:
+	if (!TimerRun(sp)) {
+		/* Timer Restart */
+		byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+		if (!(sp->counter++ & 0x3f)) {
+			/* Call LEDs all 64 tics */
+			elsa_led_handler(sp);
+		}
+	}
+#endif
+	val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+      Start_HSCX:
+	if (val) {
+		hscx_int_main(sp, val);
+	}
+	val = readisac(sp->cfg_reg, ISAC_ISTA);
+      Start_ISAC:
+	if (val) {
+		isac_interrupt(sp, val);
+	}
+#ifdef CONFIG_HISAX_ELSA_PCC
+	if (!TimerRun(sp))
+		goto INT_RESTART;
+#endif
+	val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX)
+			debugl1(sp, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readisac(sp->cfg_reg, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
+	writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
+	writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
+#ifdef CONFIG_HISAX_ELSA_PCC
+	if (sp->subtyp == ELSA_QS1000) {
+		byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+		byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+	}
+#endif
+	writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
+	writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
+	writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+	unsigned int adr = sp->cfg_reg;
+
+	/* Elsa IOM 2 Mode */
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_ADF2, 0x80);
+	writeisac(adr, ISAC_SQXR, 0x2f);
+	writeisac(adr, ISAC_SPCR, 0x00);
+	writeisac(adr, ISAC_STCR, 0x70);
+	writeisac(adr, ISAC_MODE, 0xc9);
+	writeisac(adr, ISAC_TIMR, 0x00);
+	writeisac(adr, ISAC_ADF1, 0x00);
+	writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+			'A' + hscx, mode, ichan);
+		debugl1(sp, tmp);
+	}
+	hs->mode = mode;
+	writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85);
+	writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF);
+	writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF);
+	writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF);
+	writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0);
+	writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0);
+	writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30);
+
+	switch (mode) {
+		case (0):
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff);
+			writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff);
+			writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84);
+			break;
+		case (1):
+			if (ichan == 0) {
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+			} else {
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+			}
+			writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4);
+			writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+			break;
+		case (2):
+			if (ichan == 0) {
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+			} else {
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+				writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+			}
+			writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+			writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c);
+			writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+			break;
+	}
+	writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_elsa(struct IsdnCard *card)
+{
+	int bytecnt = 8;
+
+	if (card->sp->subtyp == ELSA_PCFPRO)
+		bytecnt = 16;
+	if (card->sp->cfg_reg)
+		release_region(card->sp->cfg_reg, bytecnt);
+}
+
+static void
+reset_elsa(struct IsdnCardState *sp)
+{
+#ifdef CONFIG_HISAX_ELSA_PCC
+	/* Wait 1 Timer */
+	byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+	while (TimerRun(sp));
+	byteout(sp->cfg_reg + CARD_CONTROL, 0x00);	/* Reset On */
+	/* Wait 1 Timer */
+	byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+	while (TimerRun(sp));
+	byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET);	/* Reset Off */
+	/* Wait 1 Timer */
+	byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+	while (TimerRun(sp));
+	byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+#endif
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+	int val;
+	char tmp[64];
+
+	val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+	sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x02) {
+		val = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+	}
+	val = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
+	sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+	val = readhscx(sp->cfg_reg, 1, HSCX_STAR);
+	sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+	val = readhscx(sp->cfg_reg, 0, HSCX_STAR);
+	sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->cfg_reg, ISAC_STAR);
+	sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->cfg_reg, ISAC_MODE);
+	sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->cfg_reg, ISAC_ADF2);
+	sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->cfg_reg, ISAC_ISTA);
+	sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readisac(sp->cfg_reg, ISAC_EXIR);
+		sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x04) {
+		val = readisac(sp->cfg_reg, ISAC_CIR0);
+		sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+	}
+#endif
+	writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
+	writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
+	writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
+#ifdef CONFIG_HISAX_ELSA_PCC
+	if (sp->subtyp == ELSA_QS1000) {
+		byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+		byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+	}
+#endif
+	writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
+	writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
+	writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+	writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
+}
+
+static void
+check_arcofi(struct IsdnCardState *sp)
+{
+#if 0
+	u_char val;
+	char tmp[40];
+	char *t;
+	long flags;
+	u_char *p;
+
+	if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool),
+		       GFP_ATOMIC, (void *) 1, 3)) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC MON TX out of buffers!");
+		return;
+	} else
+		sp->mon_txp = 0;
+	p = DATAPTR(sp->mon_tx);
+	*p++ = 0xa0;
+	*p++ = 0x0;
+	sp->mon_tx->datasize = 2;
+	sp->mon_txp = 1;
+	sp->mon_flg = 0;
+	writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+	val = readisac(sp->cfg_reg, ISAC_MOSR);
+	writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0);
+	writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0);
+	save_flags(flags);
+	sti();
+	HZDELAY(3);
+	restore_flags(flags);
+	if (sp->mon_flg & MON1_TX) {
+		if (sp->mon_flg & MON1_RX) {
+			sprintf(tmp, "Arcofi response received %d bytes", sp->mon_rx->datasize);
+			debugl1(sp, tmp);
+			p = DATAPTR(sp->mon_rx);
+			t = tmp;
+			t += sprintf(tmp, "Arcofi data");
+			QuickHex(t, p, sp->mon_rx->datasize);
+			debugl1(sp, tmp);
+			BufPoolRelease(sp->mon_rx);
+			sp->mon_rx = NULL;
+			sp->mon_rxp = 0;
+			sp->mon_flg = 0;
+		}
+	} else if (sp->mon_tx) {
+		BufPoolRelease(sp->mon_tx);
+		sp->mon_tx = NULL;
+		sp->mon_txp = 0;
+		sprintf(tmp, "Arcofi not detected");
+		debugl1(sp, tmp);
+	}
+	sp->mon_flg = 0;
+#endif
+}
+
+int
+initelsa(struct IsdnCardState *sp)
+{
+	int ret, irq_cnt, cnt = 3;
+	long flags;
+
+	irq_cnt = kstat.interrupts[sp->irq];
+	printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt);
+	ret = get_irq(sp->cardnr, &elsa_interrupt);
+#ifdef CONFIG_HISAX_ELSA_PCC
+	byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+#endif
+	while (ret && cnt) {
+		sp->counter = 0;
+		clear_pending_ints(sp);
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		save_flags(flags);
+		sp->counter = 0;
+		sti();
+#ifdef CONFIG_HISAX_ELSA_PCC
+		byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT);
+		byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + (110 * HZ) / 1000;		/* Timeout 110ms */
+		schedule();
+		restore_flags(flags);
+		printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
+		       sp->counter);
+		if (abs(sp->counter - 13) < 3) {
+			printk(KERN_INFO "Elsa: timer and irq OK\n");
+		} else {
+			printk(KERN_WARNING
+			       "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+			       sp->counter, sp->irq);
+		}
+#endif
+		printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq,
+		       kstat.interrupts[sp->irq]);
+		if (kstat.interrupts[sp->irq] == irq_cnt) {
+			printk(KERN_WARNING
+			       "Elsa: IRQ(%d) getting no interrupts during init %d\n",
+			       sp->irq, 4 - cnt);
+			if (cnt == 1) {
+				irq2dev_map[sp->irq] = NULL;
+				free_irq(sp->irq, NULL);
+				return (0);
+			} else {
+				reset_elsa(sp);
+				cnt--;
+			}
+		} else {
+			check_arcofi(sp);
+			cnt = 0;
+		}
+	}
+	sp->counter = 0;
+	return (ret);
+}
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+static unsigned char
+probe_elsa_adr(unsigned int adr)
+{
+	int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
+	 pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
+	long flags;
+
+	if (check_region(adr, 8)) {
+		printk(KERN_WARNING
+		       "Elsa: Probing Port 0x%x: already in use\n",
+		       adr);
+		return (0);
+	}
+	save_flags(flags);
+	cli();
+	for (i = 0; i < 16; i++) {
+		in1 = inb(adr + CARD_CONFIG);	/* 'toggelt' bei */
+		in2 = inb(adr + CARD_CONFIG);	/* jedem Zugriff */
+		p16_1 += 0x04 & in1;
+		p16_2 += 0x04 & in2;
+		p8_1 += 0x02 & in1;
+		p8_2 += 0x02 & in2;
+		pc_1 += 0x01 & in1;
+		pc_2 += 0x01 & in2;
+		pfp_1 += 0x40 & in1;
+		pfp_2 += 0x40 & in2;
+	}
+	restore_flags(flags);
+	printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
+	if (65 == ++p16_1 * ++p16_2) {
+		printk(" PCC-16/PCF found\n");
+		return (ELSA_PCC16);
+	} else if (1025 == ++pfp_1 * ++pfp_2) {
+		printk(" PCF-Pro found\n");
+		return (ELSA_PCFPRO);
+	} else if (33 == ++p8_1 * ++p8_2) {
+		printk(" PCC8 found\n");
+		return (ELSA_PCC8);
+	} else if (17 == ++pc_1 * ++pc_2) {
+		printk(" PC found\n");
+		return (ELSA_PC);
+	} else {
+		printk(" failed\n");
+		return (0);
+	}
+}
+
+static unsigned int
+probe_elsa(struct IsdnCardState *sp)
+{
+	int i;
+	unsigned int CARD_portlist[] =
+	{0x160, 0x170, 0x260, 0x360, 0};
+
+	for (i = 0; CARD_portlist[i]; i++) {
+		if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i])))
+			break;
+	}
+	return (CARD_portlist[i]);
+}
+#endif
+
+int
+setup_elsa(struct IsdnCard *card)
+{
+#ifdef CONFIG_HISAX_ELSA_PCC
+	long flags;
+#endif
+	int bytecnt;
+	u_char val, verA, verB;
+	struct IsdnCardState *sp = card->sp;
+	char tmp[64];
+
+	strcpy(tmp, Elsa_revision);
+	printk(KERN_NOTICE "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+#ifdef CONFIG_HISAX_ELSA_PCC
+	if (sp->typ == ISDN_CTYPE_ELSA) {
+		sp->cfg_reg = card->para[0];
+		printk(KERN_INFO "Elsa: Microlink IO probing\n");
+		if (sp->cfg_reg) {
+			if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+				printk(KERN_WARNING
+				     "Elsa: no Elsa Microlink at 0x%x\n",
+				       sp->cfg_reg);
+				return (0);
+			}
+		} else
+			sp->cfg_reg = probe_elsa(sp);
+		if (sp->cfg_reg) {
+			val = bytein(sp->cfg_reg + CARD_CONFIG);
+			if (sp->subtyp == ELSA_PC) {
+				const u_char CARD_IrqTab[8] =
+				{7, 3, 5, 9, 0, 0, 0, 0};
+				sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PC) >> 2];
+			} else if (sp->subtyp == ELSA_PCC8) {
+				const u_char CARD_IrqTab[8] =
+				{7, 3, 5, 9, 0, 0, 0, 0};
+				sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PCC8) >> 4];
+			} else {
+				const u_char CARD_IrqTab[8] =
+				{15, 10, 15, 3, 11, 5, 11, 9};
+				sp->irq = CARD_IrqTab[(val & IRQ_INDEX) >> 3];
+			}
+			val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+			if (val < 3)
+				val |= 8;
+			val += 'A' - 3;
+			if (val == 'B' || val == 'C')
+				val ^= 1;
+			if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G'))
+				val = 'C';
+			printk(KERN_INFO
+			       "Elsa: %s found at 0x%x Rev.:%c IRQ %d\n",
+			       Elsa_Types[sp->subtyp],
+			       sp->cfg_reg,
+			       val, sp->irq);
+			val = bytein(sp->cfg_reg + CARD_ALE) & 0x08;
+			if (val)
+				printk(KERN_WARNING
+				   "Elsa: Microlink S0 bus power bad\n");
+		} else {
+			printk(KERN_WARNING
+			       "No Elsa Microlink found\n");
+			return (0);
+		}
+	} else if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
+		sp->cfg_reg = card->para[1];
+		sp->irq = card->para[0];
+		sp->subtyp = ELSA_QS1000;
+		printk(KERN_INFO
+		       "Elsa: %s found at 0x%x IRQ %d\n",
+		       Elsa_Types[sp->subtyp],
+		       sp->cfg_reg,
+		       sp->irq);
+	} else
+		return (0);
+#endif
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+	if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
+		sp->cfg_reg = card->para[1];
+		sp->irq = card->para[0];
+		sp->subtyp = ELSA_PCMCIA;
+		printk(KERN_INFO
+		       "Elsa: %s found at 0x%x IRQ %d\n",
+		       Elsa_Types[sp->subtyp],
+		       sp->cfg_reg,
+		       sp->irq);
+	} else
+		return (0);
+#endif
+
+	switch (sp->subtyp) {
+		case ELSA_PC:
+			bytecnt = 8;
+			break;
+		case ELSA_PCC8:
+			bytecnt = 8;
+			break;
+		case ELSA_PCFPRO:
+			bytecnt = 16;
+			break;
+		case ELSA_PCC16:
+			bytecnt = 8;
+			break;
+		case ELSA_PCF:
+			bytecnt = 16;
+			break;
+		case ELSA_QS1000:
+			bytecnt = 8;
+			break;
+		case ELSA_PCMCIA:
+			bytecnt = 8;
+			break;
+		default:
+			printk(KERN_WARNING
+			       "Unknown ELSA subtype %d\n", sp->subtyp);
+			return (0);
+	}
+
+	if (check_region((sp->cfg_reg), bytecnt)) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       sp->cfg_reg,
+		       sp->cfg_reg + bytecnt);
+		return (0);
+	} else {
+		request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+	}
+
+	/* Teste Timer */
+#ifdef CONFIG_HISAX_ELSA_PCC
+	byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+	byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+	if (!TimerRun(sp)) {
+		byteout(sp->cfg_reg + CARD_START_TIMER, 0);	/* 2. Versuch */
+		if (!TimerRun(sp)) {
+			printk(KERN_WARNING
+			       "Elsa: timer do not start\n");
+			release_io_elsa(card);
+			return (0);
+		}
+	}
+	save_flags(flags);
+	sti();
+	HZDELAY(1);		/* wait >=10 ms */
+	restore_flags(flags);
+	if (TimerRun(sp)) {
+		printk(KERN_WARNING "Elsa: timer do not run down\n");
+		release_io_elsa(card);
+		return (0);
+	}
+	printk(KERN_INFO "Elsa: timer OK; resetting card\n");
+	reset_elsa(sp);
+#endif
+	verA = readhscx(sp->cfg_reg, 0, HSCX_VSTR) & 0xf;
+	verB = readhscx(sp->cfg_reg, 1, HSCX_VSTR) & 0xf;
+	printk(KERN_INFO "Elsa: HSCX version A: %s  B: %s\n",
+	       HscxVersion(verA), HscxVersion(verB));
+	val = readisac(sp->cfg_reg, ISAC_RBCH);
+	printk(KERN_INFO "Elsa: ISAC %s\n",
+	       ISACVersion(val));
+
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+		printk(KERN_WARNING
+		       "Elsa: wrong HSCX versions check IO address\n");
+		release_io_elsa(card);
+		return (0);
+	}
+#endif
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+	if (sp->subtyp == ELSA_PC) {
+		val = readitac(sp->cfg_reg, ITAC_SYS);
+		printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
+		writeitac(sp->cfg_reg, ITAC_ISEN, 0);
+		writeitac(sp->cfg_reg, ITAC_RFIE, 0);
+		writeitac(sp->cfg_reg, ITAC_XFIE, 0);
+		writeitac(sp->cfg_reg, ITAC_SCIE, 0);
+		writeitac(sp->cfg_reg, ITAC_STIE, 0);
+	}
+#endif
+	sp->modehscx = &modehscx;
+	sp->ph_command = &ph_command;
+	sp->hscx_fill_fifo = &hscx_fill_fifo;
+	sp->isac_fill_fifo = &isac_fill_fifo;
+
+	return (1);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/elsa.h linux-2.0.31-pre3/drivers/isdn/hisax/elsa.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/elsa.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/elsa.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,90 @@
+/* $Id: elsa.h,v 1.6 1997/03/23 21:45:48 keil Exp $
+ *
+ * elsa.h   Header for Elsa ISDN cards
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Elsa GmbH for documents and informations
+ *
+ *
+ * $Log: elsa.h,v $
+ * Revision 1.6  1997/03/23 21:45:48  keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.5  1997/03/04 15:58:13  keil
+ * ELSA PC changes, some stuff for new cards
+ *
+ * Revision 1.4  1997/01/21 22:21:05  keil
+ * Elsa Quickstep support
+ *
+ * Revision 1.3  1996/12/08 19:47:38  keil
+ * ARCOFI support
+ *
+ * Revision 1.2  1996/11/18 15:33:35  keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.1  1996/10/13 20:03:45  keil
+ * Initial revision
+ *
+ *
+*/
+#include <linux/config.h>
+
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+#define CARD_ISAC	1
+#define CARD_HSCX	2
+#define CARD_ALE	4
+#else
+#define CARD_ISAC	0
+#define CARD_ITAC	1
+#define CARD_HSCX	2
+#define CARD_ALE	3
+#define CARD_CONTROL	4
+#define CARD_CONFIG	5
+#define CARD_START_TIMER 6
+#define CARD_TRIG_IRQ	7
+#endif
+
+#define ELSA_PC      1
+#define ELSA_PCC8    2
+#define ELSA_PCC16   3
+#define ELSA_PCF     4
+#define ELSA_PCFPRO  5
+#define ELSA_PCMCIA  6
+#define ELSA_QS1000  7
+#define ELSA_QS3000  8
+
+/* ITAC Registeradressen (only Microlink PC) */
+#define ITAC_SYS	0x34
+#define ITAC_ISEN	0x48
+#define ITAC_RFIE	0x4A
+#define ITAC_XFIE	0x4C
+#define ITAC_SCIE	0x4E
+#define ITAC_STIE	0x46
+
+/***                                                                    ***
+ ***   Makros als Befehle fuer die Kartenregister                       ***
+ ***   (mehrere Befehle werden durch Bit-Oderung kombiniert)            ***
+ ***                                                                    ***/
+
+/* Config-Register (Read) */
+#define TIMER_RUN       0x02    /* Bit 1 des Config-Reg     */
+#define TIMER_RUN_PCC8  0x01    /* Bit 0 des Config-Reg  bei PCC */
+#define IRQ_INDEX       0x38    /* Bit 3,4,5 des Config-Reg */
+#define IRQ_INDEX_PCC8  0x30    /* Bit 4,5 des Config-Reg */
+#define IRQ_INDEX_PC    0x0c    /* Bit 2,3 des Config-Reg */
+
+/* Control-Register (Write) */
+#define LINE_LED        0x02    /* Bit 1 Gelbe LED */
+#define STAT_LED        0x08    /* Bit 3 Gruene LED */
+#define ISDN_RESET      0x20    /* Bit 5 Reset-Leitung */
+#define ENABLE_TIM_INT  0x80    /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define HW_RELEASE      0x07    /* Bit 0-2 Hardwarerkennung */
+#define S0_POWER_BAD    0x08    /* Bit 3 S0-Bus Spannung fehlt */
+
+extern	void elsa_report(struct IsdnCardState *sp);
+extern  void release_io_elsa(struct IsdnCard *card);
+extern	int  setup_elsa(struct IsdnCard *card);
+extern  int  initelsa(struct IsdnCardState *sp);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/fsm.c linux-2.0.31-pre3/drivers/isdn/hisax/fsm.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/fsm.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/fsm.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,183 @@
+/* $Id: fsm.c,v 1.4 1997/04/06 22:56:42 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: fsm.c,v $
+ * Revision 1.4  1997/04/06 22:56:42  keil
+ * Some cosmetic changes
+ *
+ * Revision 1.3  1997/02/16 01:04:08  fritz
+ * Bugfix: Changed timer handling caused hang with 2.1.X
+ *
+ * Revision 1.2  1997/01/09 20:57:27  keil
+ * cleanup & FSM_TIMER_DEBUG
+ *
+ * Revision 1.1  1996/10/13 20:04:52  keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+#define FSM_TIMER_DEBUG 0
+
+void
+FsmNew(struct Fsm *fsm,
+       struct FsmNode *fnlist, int fncount)
+{
+	int i;
+
+	fsm->jumpmatrix = (int *)
+	    kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL);
+	memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
+
+	for (i = 0; i < fncount; i++)
+		fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+			      fnlist[i].state] = (int) fnlist[i].routine;
+}
+
+void
+FsmFree(struct Fsm *fsm)
+{
+	kfree((void *) fsm->jumpmatrix);
+}
+
+int
+FsmEvent(struct FsmInst *fi, int event, void *arg)
+{
+	void (*r) (struct FsmInst *, int, void *);
+	char str[80];
+
+	r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+	if (r) {
+		if (fi->debug) {
+			sprintf(str, "State %s Event %s",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+			fi->printdebug(fi, str);
+		}
+		r(fi, event, arg);
+		return (0);
+	} else {
+		if (fi->debug) {
+			sprintf(str, "State %s Event %s no routine",
+				fi->fsm->strState[fi->state],
+				fi->fsm->strEvent[event]);
+			fi->printdebug(fi, str);
+		}
+		return (!0);
+	}
+}
+
+void
+FsmChangeState(struct FsmInst *fi, int newstate)
+{
+	char str[80];
+
+	fi->state = newstate;
+	if (fi->debug) {
+		sprintf(str, "ChangeState %s",
+			fi->fsm->strState[newstate]);
+		fi->printdebug(fi, str);
+	}
+}
+
+static void
+FsmExpireTimer(struct FsmTimer *ft)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug) {
+		char str[40];
+		sprintf(str, "FsmExpireTimer %lx", (long) ft);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+	FsmEvent(ft->fi, ft->event, ft->arg);
+}
+
+void
+FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+	ft->fi = fi;
+	ft->tl.function = (void *) FsmExpireTimer;
+	ft->tl.data = (long) ft;
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug) {
+		char str[40];
+		sprintf(str, "FsmInitTimer %lx", (long) ft);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+	init_timer(&ft->tl);
+}
+
+void
+FsmDelTimer(struct FsmTimer *ft, int where)
+{
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug) {
+		char str[40];
+		sprintf(str, "FsmDelTimer %lx %d", (long) ft, where);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+	del_timer(&ft->tl);
+}
+
+int
+FsmAddTimer(struct FsmTimer *ft,
+	    int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+	if (ft->fi->debug) {
+		char str[40];
+		sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where);
+		ft->fi->printdebug(ft->fi, str);
+	}
+#endif
+
+	if (ft->tl.next || ft->tl.prev) {
+		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
+		ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
+		return -1;
+	}
+	init_timer(&ft->tl);
+	ft->event = event;
+	ft->arg = arg;
+	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&ft->tl);
+	return 0;
+}
+
+int
+FsmTimerRunning(struct FsmTimer *ft)
+{
+	return (ft->tl.next != NULL);
+}
+
+void
+jiftime(char *s, long mark)
+{
+	s += 8;
+
+	*s-- = '\0';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = '.';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 6 + '0';
+	mark /= 6;
+	*s-- = ':';
+	*s-- = mark % 10 + '0';
+	mark /= 10;
+	*s-- = mark % 10 + '0';
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/hisax.h linux-2.0.31-pre3/drivers/isdn/hisax/hisax.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/hisax.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/hisax.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,540 @@
+/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $
+
+ *   Basic declarations, defines and prototypes
+ *
+ * $Log: hisax.h,v $
+ * Revision 1.13  1997/04/06 22:54:12  keil
+ * Using SKB's
+ *
+ * Revision 1.12  1997/03/23 21:45:45  keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.11  1997/02/11 01:36:02  keil
+ * New Param structure
+ *
+ * Revision 1.10  1997/02/09 00:23:52  keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.9  1997/01/27 23:18:44  keil
+ * prototype for releasestack_isdnl3
+ *
+ * Revision 1.8  1997/01/27 16:02:37  keil
+ * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype
+ *
+ * Revision 1.7  1997/01/21 22:22:14  keil
+ * changes for 2.0; Elsa Quickstep support
+ *
+ * Revision 1.6  1997/01/04 13:48:28  keil
+ * primitiv for MDL_REMOVE added
+ *
+ * Revision 1.5  1996/12/08 19:49:19  keil
+ * Monitor channel support
+ *
+ * Revision 1.4  1996/11/18 15:35:39  keil
+ * some changes for ELSA cards
+ *
+ * Revision 1.3  1996/11/05 19:37:23  keil
+ * using config.h
+ *
+ * Revision 1.2  1996/10/27 22:21:52  keil
+ * CallFlags for broadcast messages
+ *
+ * Revision 1.1  1996/10/13 20:03:46  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/isdnif.h>
+#include <linux/tty.h>
+
+#define PH_ACTIVATE   1
+#define PH_DATA       2
+#define PH_DEACTIVATE 3
+
+#define MDL_ASSIGN       4
+#define DL_UNIT_DATA     5
+#define SC_STARTUP       6
+#define CC_ESTABLISH     7
+#define DL_ESTABLISH     8
+#define DL_DATA          9
+#define CC_S_STATUS_ENQ  10
+
+#define CC_CONNECT       15
+#define CC_CONNECT_ACKNOWLEDGE 16
+#define CO_EOF                 17
+#define SC_DISCONNECT          18
+#define CO_DTMF                19
+#define DL_RELEASE             20
+#define DL_FLUSH               21
+
+#define CO_ALARM               22
+#define CC_REJECT              23
+
+#define CC_SETUP_REQ           24
+#define CC_SETUP_CNF           25
+#define CC_SETUP_IND           26
+#define CC_SETUP_RSP           27
+#define CC_SETUP_COMPLETE_IND  28
+
+#define CC_DISCONNECT_REQ      29
+#define CC_DISCONNECT_IND      30
+
+#define CC_RELEASE_CNF         31
+#define CC_RELEASE_IND         32
+#define CC_RELEASE_REQ         33
+
+#define CC_REJECT_REQ          34
+
+#define CC_PROCEEDING_IND      35
+
+#define CC_DLRL                36
+#define CC_DLEST               37
+
+#define CC_ALERTING_REQ        38
+#define CC_ALERTING_IND        39
+
+#define DL_STOP                40
+#define DL_START               41
+
+#define MDL_NOTEIPROC          46
+
+#define LC_ESTABLISH           47
+#define LC_RELEASE             48
+
+#define PH_REQUEST_PULL        49
+#define PH_PULL_ACK            50
+#define	PH_DATA_PULLED	       51
+#define CC_INFO_CHARGE         52
+
+#define CC_MORE_INFO           53
+#define CC_IGNORE              54
+
+#define MDL_REMOVE             56
+#define MDL_VERIFY             57
+
+#define CC_T303                60
+#define CC_T304                61
+#define CC_T305                62
+#define CC_T308_1              64
+#define CC_T308_2              65
+#define CC_T310                66
+#define CC_T313                67
+#define CC_T318                68
+#define CC_T319                69
+
+#define CC_NOSETUP_RSP_ERR     70
+#define CC_SETUP_ERR           71
+#define CC_CONNECT_ERR         72
+#define CC_RELEASE_ERR         73
+
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING            0x01
+#define MT_CALL_PROCEEDING     0x02
+#define MT_CONNECT             0x07
+#define MT_CONNECT_ACKNOWLEDGE 0x0f
+#define MT_PROGRESS            0x03
+#define MT_SETUP               0x05
+#define MT_SETUP_ACKNOWLEDGE   0x0d
+#define MT_RESUME              0x26
+#define MT_RESUME_ACKNOWLEDGE  0x2e
+#define MT_RESUME_REJECT       0x22
+#define MT_SUSPEND             0x25
+#define MT_SUSPEND_ACKNOWLEDGE 0x2d
+#define MT_SUSPEND_REJECT      0x21
+#define MT_USER_INFORMATION    0x20
+#define MT_DISCONNECT          0x45
+#define MT_RELEASE             0x4d
+#define MT_RELEASE_COMPLETE    0x5a
+#define MT_RESTART             0x46
+#define MT_RESTART_ACKNOWLEDGE 0x4e
+#define MT_SEGMENT             0x60
+#define MT_CONGESTION_CONTROL  0x79
+#define MT_INFORMATION         0x7b
+#define MT_FACILITY            0x62
+#define MT_NOTIFY              0x6e
+#define MT_STATUS              0x7d
+#define MT_STATUS_ENQUIRY      0x75
+
+#define IE_CAUSE               0x08
+
+struct HscxIoctlArg {
+	int channel;
+	int mode;
+	int transbufsize;
+};
+
+#ifdef __KERNEL__
+
+#undef DEBUG_MAGIC
+
+#define MAX_DFRAME_LEN	3072
+#define HSCX_BUFMAX	4096
+#define MAX_DATA_SIZE	(HSCX_BUFMAX - 4)
+#define MAX_DATA_MEM    (HSCX_BUFMAX * 2)
+#define MAX_HEADER_LEN	4
+#define MAX_WINDOW	8
+
+/*
+ * Statemachine
+ */
+struct Fsm {
+	int *jumpmatrix;
+	int state_count, event_count;
+	char **strEvent, **strState;
+};
+
+struct FsmInst {
+	struct Fsm *fsm;
+	int state;
+	int debug;
+	void *userdata;
+	int userint;
+	void (*printdebug) (struct FsmInst *, char *);
+};
+
+struct FsmNode {
+	int state, event;
+	void (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+	struct FsmInst *fi;
+	struct timer_list tl;
+	int event;
+	void *arg;
+};
+
+struct L3Timer {
+	struct PStack *st;
+	struct timer_list tl;
+	int event;
+};
+
+struct Layer1 {
+	void *hardware;
+	int hscx;
+	struct PStack **stlistp;
+	int act_state;
+	void (*l1l2) (struct PStack *, int, void *);
+	void (*l1man) (struct PStack *, int, void *);
+	int hscxmode, hscxchannel, requestpull;
+};
+
+struct Layer2 {
+	int sap, tei, ces;
+	int extended, laptype;
+	int uihsize, ihsize;
+	int vs, va, vr;
+	struct sk_buff_head i_queue;
+	int window, orig;
+	int rejexp;
+	int debug;
+	struct sk_buff *windowar[MAX_WINDOW];
+	int sow;
+	struct FsmInst l2m;
+	void (*l2l1) (struct PStack *, int, void *);
+	void (*l2l1discardq) (struct PStack *, int, void *, int);
+	void (*l2man) (struct PStack *, int, void *);
+	void (*l2l3) (struct PStack *, int, void *);
+	void (*l2tei) (struct PStack *, int, void *);
+	struct FsmTimer t200_timer, t203_timer;
+	int t200, n200, t203;
+	int rc, t200_running;
+	char debug_id[32];
+};
+
+struct Layer3 {
+	void (*l3l4) (struct PStack *, int, void *);
+	void (*l3l2) (struct PStack *, int, void *);
+	int state, callref;
+	struct L3Timer timer;
+	int t303, t304, t305, t308, t310, t313, t318, t319;
+	int n_t303;
+	int debug;
+	int channr;
+};
+
+struct Layer4 {
+	void (*l4l3) (struct PStack *, int, void *);
+	void *userdata;
+	void (*l1writewakeup) (struct PStack *);
+	void (*l2writewakeup) (struct PStack *);
+};
+
+struct Management {
+	void (*manl1) (struct PStack *, int, void *);
+	void (*manl2) (struct PStack *, int, void *);
+	void (*teil2) (struct PStack *, int, void *);
+};
+
+struct Param {
+	int cause;
+	int loc;
+	int bchannel;
+	int callref;		/* Callreferenz Number */
+	setup_parm setup;	/* from isdnif.h numbers and Serviceindicator */
+	int chargeinfo;		/* Charge Info - only for 1tr6 in
+				 * the moment
+				 */
+	int spv;		/* SPV Flag */
+};
+
+struct PStack {
+	struct PStack *next;
+	struct Layer1 l1;
+	struct Layer2 l2;
+	struct Layer3 l3;
+	struct Layer4 l4;
+	struct Management ma;
+	struct Param *pa;
+	int protocol;		/* EDSS1 or 1TR6 */
+};
+
+struct HscxState {
+	int inuse, init, active;
+	struct IsdnCardState *sp;
+	int hscx, mode;
+	u_char *rcvbuf;		/* B-Channel receive Buffer */
+	int rcvidx;		/* B-Channel receive Buffer Index */
+	struct sk_buff *tx_skb;	/* B-Channel transmit Buffer */
+	int tx_cnt;		/* B-Channel transmit counter */
+	int count;		/* Current skb sent count */
+	struct sk_buff_head rqueue;	/* B-Channel receive Queue */
+	struct sk_buff_head squeue;	/* B-Channel receive Queue */
+	struct PStack *st;
+	struct tq_struct tqueue;
+	int event;
+#ifdef DEBUG_MAGIC
+	int magic;		/* 301270 */
+#endif
+};
+
+struct LcFsm {
+	struct FsmInst lcfi;
+	int type;
+	struct Channel *ch;
+	void (*lccall) (struct LcFsm *, int, void *);
+	struct PStack *st;
+	int l2_establish;
+	int l2_start;
+	struct FsmTimer act_timer;
+	char debug_id[32];
+};
+
+struct Channel {
+	struct PStack ds, is;
+	struct IsdnCardState *sp;
+	int hscx;
+	int chan;
+	int incoming;
+	struct FsmInst fi;
+	struct LcFsm lc_d, lc_b;
+	struct Param para;
+	struct FsmTimer drel_timer, dial_timer;
+	int debug;
+#ifdef DEBUG_MAGIC
+	int magic;		/* 301272 */
+#endif
+	int l2_protocol, l2_active_protocol;
+	int l2_primitive, l2_headersize;
+	int data_open;
+	int outcallref;
+	int impair;
+	int Flags;		/* for remembering action done in l4 */
+	int leased;
+};
+
+struct IsdnCardState {
+#ifdef DEBUG_MAGIC
+	int magic;
+#endif
+	unsigned char typ;
+	unsigned char subtyp;
+	int protocol;
+	unsigned int irq;
+	unsigned int cfg_reg;
+	unsigned int membase;
+	unsigned int isac;
+	unsigned int hscx[2];
+	unsigned int counter;
+	int myid;
+	isdn_if iif;
+	u_char *status_buf;
+	u_char *status_read;
+	u_char *status_write;
+	u_char *status_end;
+	void (*ph_command) (struct IsdnCardState *, unsigned int);
+	void (*modehscx) (struct HscxState *, int, int);
+	void (*hscx_fill_fifo) (struct HscxState *);
+	void (*isac_fill_fifo) (struct IsdnCardState *);
+	struct Channel channel[2];
+	struct PStack *stlist;
+	u_char *rcvbuf;
+	int rcvidx;
+	struct sk_buff *tx_skb;
+	int tx_cnt;
+	int event;
+	struct tq_struct tqueue;
+	int ph_active;
+	struct sk_buff_head rq, sq; /* D-channel queues */
+	int cardnr;
+	int ph_state;
+	struct PStack *teistack;
+	struct HscxState hs[2];
+	int dlogflag;
+	char *dlogspace;
+	int debug;
+	unsigned int CallFlags;
+};
+
+#define  MON0_RX	1
+#define  MON1_RX	2
+#define  MON0_TX	4
+#define  MON1_TX	8
+
+#define  ISDN_CTYPE_16_0	1
+#define  ISDN_CTYPE_8_0		2
+#define  ISDN_CTYPE_16_3	3
+#define  ISDN_CTYPE_PNP		4
+#define  ISDN_CTYPE_A1		5
+#define  ISDN_CTYPE_ELSA	6
+#define  ISDN_CTYPE_ELSA_QS1000	7
+#define  ISDN_CTYPE_TELESPCMCIA	8
+#define  ISDN_CTYPE_IX1MICROR2	9
+
+#define  ISDN_CTYPE_COUNT	9
+
+#ifdef	CONFIG_HISAX_16_0
+#define  CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
+#else
+#define  CARD_TELES0  0
+#endif
+
+#ifdef	CONFIG_HISAX_16_3
+#define  CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP) | \
+		     (1<< ISDN_CTYPE_TELESPCMCIA)
+#else
+#define  CARD_TELES3  0
+#endif
+
+#ifdef	CONFIG_HISAX_AVM_A1
+#define  CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#else
+#define  CARD_AVM_A1  0
+#endif
+
+#ifdef	CONFIG_HISAX_ELSA_PCC
+#define  CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_QS1000)
+#else
+#define  CARD_ELSA  0
+#endif
+
+#ifdef	CONFIG_HISAX_ELSA_PCMCIA
+#if CARD_ELSA
+#error "You can't use a ELSA ISA card and a ELSA PCMCIA card with the same driver"
+#else
+#undef CARD_ELSA
+#define CARD_ELSA (1<< ISDN_CTYPE_ELSA_QS1000)
+#endif
+#endif
+
+#ifdef	CONFIG_HISAX_IX1MICROR2
+#define	CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2)
+#else
+#define CARD_IX1MICROR2 0
+#endif
+
+#define  SUPORTED_CARDS  (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
+			 | CARD_IX1MICROR2)
+
+struct IsdnCard {
+	int typ;
+	int protocol;		/* EDSS1 or 1TR6 */
+	unsigned int para[3];
+	struct IsdnCardState *sp;
+};
+
+
+#define LAPD 0
+#define LAPB 1
+
+void l2down(struct PStack *st, u_char pr, struct sk_buff *skb);
+void l2up(struct PStack *st, u_char pr, struct sk_buff *skb);
+void acceptph(struct PStack *st, struct sk_buff *skb);
+void setstack_isdnl2(struct PStack *st, char *debug_id);
+int HiSax_inithardware(void);
+void HiSax_closehardware(void);
+
+void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
+unsigned int randomces(void);
+void setstack_isdnl3(struct PStack *st, struct Channel *chanp);
+void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void releasestack_isdnl2(struct PStack *st);
+void releasestack_isdnl3(struct PStack *st);
+void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
+void newcallref(struct PStack *st);
+
+int setstack_hscx(struct PStack *st, struct HscxState *hs);
+u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
+int getcallref(u_char * p);
+
+void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
+void FsmFree(struct Fsm *fsm);
+int FsmEvent(struct FsmInst *fi, int event, void *arg);
+void FsmChangeState(struct FsmInst *fi, int newstate);
+void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
+int FsmAddTimer(struct FsmTimer *ft, int millisec,
+		int event, void *arg, int where);
+void FsmDelTimer(struct FsmTimer *ft, int where);
+int FsmTimerRunning(struct FsmTimer *ft);
+void jiftime(char *s, long mark);
+
+int HiSax_command(isdn_ctrl * ic);
+int HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb);
+void HiSax_putstatus(struct IsdnCardState *csta, char *buf);
+void HiSax_reportcard(int cardnr);
+int QuickHex(char *txt, u_char * p, int cnt);
+void LogFrame(struct IsdnCardState *sp, u_char * p, int size);
+void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment);
+void iecpy(u_char * dest, u_char * iestart, int ieoffset);
+void setstack_transl2(struct PStack *st);
+void releasestack_transl2(struct PStack *st);
+void close_hscxstate(struct HscxState *);
+void setstack_tei(struct PStack *st);
+
+#endif				/* __KERNEL__ */
+
+#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
+
+int ll_run(struct IsdnCardState *csta);
+void ll_stop(struct IsdnCardState *csta);
+void CallcNew(void);
+void CallcFree(void);
+int CallcNewChan(struct IsdnCardState *csta);
+void CallcFreeChan(struct IsdnCardState *csta);
+void Isdnl2New(void);
+void Isdnl2Free(void);
+void init_tei(struct IsdnCardState *sp, int protocol);
+void release_tei(struct IsdnCardState *sp);
+char *HiSax_getrev(const char *revision);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl1.c linux-2.0.31-pre3/drivers/isdn/hisax/isdnl1.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl1.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl1.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1378 @@
+/* $Id: isdnl1.c,v 1.15 1997/05/27 15:17:55 fritz Exp $
+
+ * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *              Beat Doebeli
+ *
+ *
+ * $Log: isdnl1.c,v $
+ * Revision 1.15  1997/05/27 15:17:55  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.14  1997/04/07 23:00:08  keil
+ * GFP_KERNEL ---> GFP_ATOMIC
+ *
+ * Revision 1.13  1997/04/06 22:55:50  keil
+ * Using SKB's
+ *
+ * Revision 1.12  1997/03/26 13:43:57  keil
+ * small cosmetics
+ *
+ * Revision 1.11  1997/03/25 23:11:23  keil
+ * US NI-1 protocol
+ *
+ * Revision 1.10  1997/03/13 14:45:05  keil
+ * using IRQ proof queue_task
+ *
+ * Revision 1.9  1997/03/12 21:44:21  keil
+ * change Interrupt routine from atomic quick to normal
+ *
+ * Revision 1.8  1997/02/09 00:24:31  keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.7  1997/01/27 15:56:03  keil
+ * PCMCIA Teles card and ITK ix1 micro added
+ *
+ * Revision 1.6  1997/01/21 22:20:00  keil
+ * changes for D-channel log; Elsa Quickstep support
+ *
+ * Revision 1.5  1997/01/10 12:51:19  keil
+ * cleanup; set newversion
+ *
+ * Revision 1.4  1996/12/08 19:44:53  keil
+ * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ *
+ * Revision 1.3  1996/11/18 15:34:47  keil
+ * fix HSCX version code
+ *
+ * Revision 1.2  1996/10/27 22:16:54  keil
+ * ISAC/HSCX version lookup
+ *
+ * Revision 1.1  1996/10/13 20:04:53  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+const char *l1_revision = "$Revision: 1.15 $";
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isdnl1.h"
+
+#if CARD_TELES0
+#include "teles0.h"
+#endif
+
+#if CARD_TELES3
+#include "teles3.h"
+#endif
+
+#if CARD_AVM_A1
+#include "avm_a1.h"
+#endif
+
+#if CARD_ELSA
+#include "elsa.h"
+#endif
+
+#if CARD_IX1MICROR2
+#include "ix1_micro.h"
+#endif
+
+/* #define I4L_IRQ_FLAG SA_INTERRUPT */
+#define I4L_IRQ_FLAG    0
+
+#define HISAX_STATUS_BUFSIZE 4096
+
+#define INCLUDE_INLINE_FUNCS
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+const char *CardType[] =
+{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
+ "Creatix/Teles PnP", "AVM A1", "Elsa ML",
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+ "Elsa PCMCIA",
+#else
+ "Elsa Quickstep",
+#endif
+ "Teles PCMCIA", "ITK ix1-micro Rev.2"};
+
+static char *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+static char *ISACVer[] =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+extern char *HiSax_id;
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*
+hisax_findcard(int driverid)
+{
+	int i;
+
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp)
+			if (cards[i].sp->myid == driverid)
+				return (cards[i].sp);
+	return (struct IsdnCardState *) 0;
+}
+
+int
+HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+	int count;
+	u_char *p;
+	struct IsdnCardState *csta = hisax_findcard(id);
+
+	if (csta) {
+		for (p = buf, count = 0; count < len; p++, count++) {
+			if (user)
+				put_user(*csta->status_read++, p);
+			else
+				*p++ = *csta->status_read++;
+			if (csta->status_read > csta->status_end)
+				csta->status_read = csta->status_buf;
+		}
+		return count;
+	} else {
+		printk(KERN_ERR
+		 "HiSax: if_readstatus called with invalid driverId!\n");
+		return -ENODEV;
+	}
+}
+
+void
+HiSax_putstatus(struct IsdnCardState *csta, char *buf)
+{
+	long flags;
+	int len, count, i;
+	u_char *p;
+	isdn_ctrl ic;
+
+	save_flags(flags);
+	cli();
+	count = 0;
+	len = strlen(buf);
+
+	if (!csta) {
+		printk(KERN_WARNING "HiSax: No CardStatus for message %s", buf);
+		restore_flags(flags);
+		return;
+	}
+	for (p = buf, i = len; i > 0; i--, p++) {
+		*csta->status_write++ = *p;
+		if (csta->status_write > csta->status_end)
+			csta->status_write = csta->status_buf;
+		count++;
+	}
+	restore_flags(flags);
+	if (count) {
+		ic.command = ISDN_STAT_STAVAIL;
+		ic.driver = csta->myid;
+		ic.arg = count;
+		csta->iif.statcallb(&ic);
+	}
+}
+
+int
+ll_run(struct IsdnCardState *csta)
+{
+	long flags;
+	isdn_ctrl ic;
+
+	save_flags(flags);
+	cli();
+	ic.driver = csta->myid;
+	ic.command = ISDN_STAT_RUN;
+	csta->iif.statcallb(&ic);
+	restore_flags(flags);
+	return 0;
+}
+
+void
+ll_stop(struct IsdnCardState *csta)
+{
+	isdn_ctrl ic;
+
+	ic.command = ISDN_STAT_STOP;
+	ic.driver = csta->myid;
+	csta->iif.statcallb(&ic);
+	CallcFreeChan(csta);
+}
+
+static void
+ll_unload(struct IsdnCardState *csta)
+{
+	isdn_ctrl ic;
+
+	ic.command = ISDN_STAT_UNLOAD;
+	ic.driver = csta->myid;
+	csta->iif.statcallb(&ic);
+	if (csta->status_buf)
+		kfree(csta->status_buf);
+	csta->status_read = NULL;
+	csta->status_write = NULL;
+	csta->status_end = NULL;
+	kfree(csta->dlogspace);
+}
+
+void
+debugl1(struct IsdnCardState *sp, char *msg)
+{
+	char tmp[256], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr + 1, msg);
+	HiSax_putstatus(sp, tmp);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+
+char *
+HscxVersion(u_char v)
+{
+	return (HSCXVer[v & 0xf]);
+}
+
+void
+hscx_sched_event(struct HscxState *hsp, int event)
+{
+	hsp->event |= 1 << event;
+	queue_task(&hsp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+char *
+ISACVersion(u_char v)
+{
+	return (ISACVer[(v >> 5) & 3]);
+}
+
+void
+isac_sched_event(struct IsdnCardState *sp, int event)
+{
+	sp->event |= 1 << event;
+	queue_task(&sp->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+int
+act_wanted(struct IsdnCardState *sp)
+{
+	struct PStack *st;
+
+	st = sp->stlist;
+	while (st)
+		if (st->l1.act_state)
+			return (!0);
+		else
+			st = st->next;
+	return (0);
+}
+
+void
+isac_new_ph(struct IsdnCardState *sp)
+{
+	int enq;
+
+	enq = act_wanted(sp);
+
+	switch (sp->ph_state) {
+		case (6):
+			sp->ph_active = 0;
+			sp->ph_command(sp, 15);
+			break;
+		case (15):
+			sp->ph_active = 0;
+			if (enq)
+				sp->ph_command(sp, 0);
+			break;
+		case (0):
+			sp->ph_active = 0;
+			if (enq)
+				sp->ph_command(sp, 0);
+#if 0
+			else
+				sp->ph_command(sp, 15);
+#endif
+			break;
+		case (7):
+			sp->ph_active = 0;
+			if (enq)
+				sp->ph_command(sp, 9);
+			break;
+		case (12):
+			sp->ph_command(sp, 8);
+			sp->ph_active = 5;
+			isac_sched_event(sp, ISAC_PHCHANGE);
+			if (!sp->tx_skb)
+				sp->tx_skb = skb_dequeue(&sp->sq);
+			if (sp->tx_skb) {
+				sp->tx_cnt = 0;
+				sp->isac_fill_fifo(sp);
+			}
+			break;
+		case (13):
+			sp->ph_command(sp, 9);
+			sp->ph_active = 5;
+			isac_sched_event(sp, ISAC_PHCHANGE);
+			if (!sp->tx_skb)
+				sp->tx_skb = skb_dequeue(&sp->sq);
+			if (sp->tx_skb) {
+				sp->tx_cnt = 0;
+				sp->isac_fill_fifo(sp);
+			}
+			break;
+		case (4):
+		case (8):
+			sp->ph_active = 0;
+			break;
+		default:
+			sp->ph_active = 0;
+			break;
+	}
+}
+
+static void
+restart_ph(struct IsdnCardState *sp)
+{
+	if (!sp->ph_active) {
+		if ((sp->ph_state == 6) || (sp->ph_state == 0)) {
+			sp->ph_command(sp, 0);
+			sp->ph_active = 2;
+		} else {
+			sp->ph_command(sp, 1);
+			sp->ph_active = 1;
+		}
+	} else if (sp->ph_active == 2) {
+		sp->ph_command(sp, 1);
+		sp->ph_active = 1;
+	}
+}
+
+
+static void
+act_ivated(struct IsdnCardState *sp)
+{
+	struct PStack *st;
+
+	st = sp->stlist;
+	while (st) {
+		if (st->l1.act_state == 1) {
+			st->l1.act_state = 2;
+			st->l1.l1man(st, PH_ACTIVATE, NULL);
+		}
+		st = st->next;
+	}
+}
+
+static void
+process_new_ph(struct IsdnCardState *sp)
+{
+	if (sp->ph_active == 5)
+		act_ivated(sp);
+}
+
+static void
+process_xmt(struct IsdnCardState *sp)
+{
+	struct PStack *stptr;
+
+	if (sp->tx_skb)
+		return;
+
+	stptr = sp->stlist;
+	while (stptr != NULL)
+		if (stptr->l1.requestpull) {
+			stptr->l1.requestpull = 0;
+			stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
+			break;
+		} else
+			stptr = stptr->next;
+}
+
+static void
+process_rcv(struct IsdnCardState *sp)
+{
+	struct sk_buff *skb, *nskb;
+	struct PStack *stptr;
+	int found, broadc;
+	char tmp[64];
+
+	while ((skb = skb_dequeue(&sp->rq))) {
+#ifdef L2FRAME_DEBUG		/* psa */
+		if (sp->debug & L1_DEB_LAPD)
+			Logl2Frame(sp, skb, "PH_DATA", 1);
+#endif
+		stptr = sp->stlist;
+		broadc = (skb->data[1] >> 1) == 127;
+
+		if (broadc) {
+			if (!(skb->data[0] >> 2)) {	/* sapi 0 */
+				sp->CallFlags = 3;
+				if (sp->dlogflag) {
+					LogFrame(sp, skb->data, skb->len);
+					dlogframe(sp, skb->data + 3, skb->len - 3,
+						  "Q.931 frame network->user broadcast");
+				}
+			}
+			while (stptr != NULL) {
+				if ((skb->data[0] >> 2) == stptr->l2.sap)
+					if ((nskb = skb_clone(skb, GFP_ATOMIC)))
+						stptr->l1.l1l2(stptr, PH_DATA, nskb);
+					else
+						printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
+				stptr = stptr->next;
+			}
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb, FREE_READ);
+		} else {
+			found = 0;
+			while (stptr != NULL)
+				if (((skb->data[0] >> 2) == stptr->l2.sap) &&
+				((skb->data[1] >> 1) == stptr->l2.tei)) {
+					stptr->l1.l1l2(stptr, PH_DATA, skb);
+					found = !0;
+					break;
+				} else
+					stptr = stptr->next;
+			if (!found) {
+				/* BD 10.10.95
+				 * Print out D-Channel msg not processed
+				 * by isdn4linux
+				 */
+
+				if ((!(skb->data[0] >> 2)) && (!(skb->data[2] & 0x01))) {
+					sprintf(tmp,
+						"Q.931 frame network->user with tei %d (not for us)",
+						skb->data[1] >> 1);
+					LogFrame(sp, skb->data, skb->len);
+					dlogframe(sp, skb->data + 4, skb->len - 4, tmp);
+				}
+				SET_SKB_FREE(skb);
+				dev_kfree_skb(skb, FREE_READ);
+			}
+		}
+
+	}
+
+}
+
+static void
+isac_bh(struct IsdnCardState *sp)
+{
+	if (!sp)
+		return;
+
+	if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
+		process_new_ph(sp);
+	if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
+		process_rcv(sp);
+	if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
+		process_xmt(sp);
+}
+
+static void
+l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+	char str[64];
+
+	switch (pr) {
+		case (PH_DATA):
+			if (sp->tx_skb) {
+				skb_queue_tail(&sp->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (sp->debug & L1_DEB_LAPD)
+					Logl2Frame(sp, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				if ((sp->dlogflag) && (!(skb->data[2] & 1))) {	/* I-FRAME */
+					LogFrame(sp, skb->data, skb->len);
+					sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+					dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
+						  str);
+				}
+				sp->tx_skb = skb;
+				sp->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (sp->debug & L1_DEB_LAPD)
+					Logl2Frame(sp, skb, "PH_DATA", 0);
+#endif
+				sp->isac_fill_fifo(sp);
+			}
+			break;
+		case (PH_DATA_PULLED):
+			if (sp->tx_skb) {
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, " l2l1 tx_skb exist this shouldn't happen");
+				break;
+			}
+			if ((sp->dlogflag) && (!(skb->data[2] & 1))) {	/* I-FRAME */
+				LogFrame(sp, skb->data, skb->len);
+				sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+				dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
+					  str);
+			}
+			sp->tx_skb = skb;
+			sp->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (sp->debug & L1_DEB_LAPD)
+				Logl2Frame(sp, skb, "PH_DATA_PULLED", 0);
+#endif
+			sp->isac_fill_fifo(sp);
+			break;
+		case (PH_REQUEST_PULL):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (sp->debug & L1_DEB_LAPD)
+				debugl1(sp, "-> PH_REQUEST_PULL");
+#endif
+			if (!sp->tx_skb) {
+				st->l1.requestpull = 0;
+				st->l1.l1l2(st, PH_PULL_ACK, NULL);
+			} else
+				st->l1.requestpull = !0;
+			break;
+	}
+}
+
+
+static void
+hscx_process_xmt(struct HscxState *hsp)
+{
+	struct PStack *st = hsp->st;
+
+	if (hsp->tx_skb)
+		return;
+
+	if (st->l1.requestpull) {
+		st->l1.requestpull = 0;
+		st->l1.l1l2(st, PH_PULL_ACK, NULL);
+	}
+	if (!hsp->active)
+		if ((!hsp->tx_skb) && (!skb_queue_len(&hsp->squeue)))
+			hsp->sp->modehscx(hsp, 0, 0);
+}
+
+static void
+hscx_process_rcv(struct HscxState *hsp)
+{
+	struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+	if (hsp->magic != 301270) {
+		printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
+		return;
+	}
+#endif
+	while ((skb = skb_dequeue(&hsp->rqueue))) {
+		hsp->st->l1.l1l2(hsp->st, PH_DATA, skb);
+	}
+}
+
+static void
+hscx_bh(struct HscxState *hsp)
+{
+
+	if (!hsp)
+		return;
+
+	if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+		hscx_process_rcv(hsp);
+	if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+		hscx_process_xmt(hsp);
+
+}
+
+/*
+ * interrupt stuff ends here
+ */
+
+void
+HiSax_addlist(struct IsdnCardState *sp,
+	      struct PStack *st)
+{
+	st->next = sp->stlist;
+	sp->stlist = st;
+}
+
+void
+HiSax_rmlist(struct IsdnCardState *sp,
+	     struct PStack *st)
+{
+	struct PStack *p;
+
+	if (sp->stlist == st)
+		sp->stlist = st->next;
+	else {
+		p = sp->stlist;
+		while (p)
+			if (p->next == st) {
+				p->next = st->next;
+				return;
+			} else
+				p = p->next;
+	}
+}
+
+static void
+check_ph_act(struct IsdnCardState *sp)
+{
+	struct PStack *st = sp->stlist;
+
+	while (st) {
+		if (st->l1.act_state)
+			return;
+		st = st->next;
+	}
+	if (sp->ph_active == 5)
+		sp->ph_active = 4;
+}
+
+static void
+HiSax_manl1(struct PStack *st, int pr,
+	    void *arg)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)
+	st->l1.hardware;
+	long flags;
+	char tmp[32];
+
+	switch (pr) {
+		case (PH_ACTIVATE):
+			if (sp->debug) {
+				sprintf(tmp, "PH_ACT ph_active %d", sp->ph_active);
+				debugl1(sp, tmp);
+			}
+			save_flags(flags);
+			cli();
+			if (sp->ph_active & 4) {
+				sp->ph_active = 5;
+				st->l1.act_state = 2;
+				restore_flags(flags);
+				st->l1.l1man(st, PH_ACTIVATE, NULL);
+			} else {
+				st->l1.act_state = 1;
+				if (sp->ph_active == 0)
+					restart_ph(sp);
+				restore_flags(flags);
+			}
+			break;
+		case (PH_DEACTIVATE):
+			st->l1.act_state = 0;
+			if (sp->debug) {
+				sprintf(tmp, "PH_DEACT ph_active %d", sp->ph_active);
+				debugl1(sp, tmp);
+			}
+			check_ph_act(sp);
+			break;
+	}
+}
+
+static void
+HiSax_l2l1discardq(struct PStack *st, int pr,
+		   void *heldby, int releasetoo)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+	if (sp->magic != 301271) {
+		printk(KERN_DEBUG "isac_discardq magic not 301271\n");
+		return;
+	}
+#endif
+
+	while ((skb = skb_dequeue(&sp->sq)))
+		dev_kfree_skb(skb, FREE_WRITE);
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
+{
+	st->l1.hardware = sp;
+	st->protocol = sp->protocol;
+
+	setstack_tei(st);
+
+	st->l1.stlistp = &(sp->stlist);
+	st->l1.act_state = 0;
+	st->l2.l2l1 = l2l1;
+	st->l2.l2l1discardq = HiSax_l2l1discardq;
+	st->ma.manl1 = HiSax_manl1;
+	st->l1.requestpull = 0;
+}
+
+void
+init_hscxstate(struct IsdnCardState *sp,
+	       int hscx)
+{
+	struct HscxState *hsp = sp->hs + hscx;
+
+	hsp->sp = sp;
+	hsp->hscx = hscx;
+
+	hsp->tqueue.next = 0;
+	hsp->tqueue.sync = 0;
+	hsp->tqueue.routine = (void *) (void *) hscx_bh;
+	hsp->tqueue.data = hsp;
+
+	hsp->inuse = 0;
+	hsp->init = 0;
+	hsp->active = 0;
+
+#ifdef DEBUG_MAGIC
+	hsp->magic = 301270;
+#endif
+}
+
+int
+get_irq(int cardnr, void *routine)
+{
+	struct IsdnCard *card = cards + cardnr;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	if (request_irq(card->sp->irq, routine,
+			I4L_IRQ_FLAG, "HiSax", NULL)) {
+		printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+		       card->sp->irq);
+		restore_flags(flags);
+		return (0);
+	}
+	irq2dev_map[card->sp->irq] = (void *) card->sp;
+	restore_flags(flags);
+	return (1);
+}
+
+static void
+release_irq(int cardnr)
+{
+	struct IsdnCard *card = cards + cardnr;
+
+	irq2dev_map[card->sp->irq] = NULL;
+	free_irq(card->sp->irq, NULL);
+}
+
+void
+close_hscxstate(struct HscxState *hs)
+{
+	struct sk_buff *skb;
+
+	hs->sp->modehscx(hs, 0, 0);
+	hs->inuse = 0;
+	if (hs->init) {
+		if (hs->rcvbuf) {
+			kfree(hs->rcvbuf);
+			hs->rcvbuf = NULL;
+		}
+		while ((skb = skb_dequeue(&hs->rqueue))) {
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb, FREE_READ);
+		}
+		while ((skb = skb_dequeue(&hs->squeue)))
+			dev_kfree_skb(skb, FREE_WRITE);
+		if (hs->tx_skb) {
+			dev_kfree_skb(hs->tx_skb, FREE_WRITE);
+			hs->tx_skb = NULL;
+		}
+	}
+	hs->init = 0;
+}
+
+static void
+closecard(int cardnr)
+{
+	struct IsdnCardState *csta = cards[cardnr].sp;
+	struct sk_buff *skb;
+
+	close_hscxstate(csta->hs + 1);
+	close_hscxstate(csta->hs);
+
+	if (csta->rcvbuf) {
+		kfree(csta->rcvbuf);
+		csta->rcvbuf = NULL;
+	}
+	while ((skb = skb_dequeue(&csta->rq))) {
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+	}
+	while ((skb = skb_dequeue(&csta->sq)))
+		dev_kfree_skb(skb, FREE_WRITE);
+	if (csta->tx_skb) {
+		dev_kfree_skb(csta->tx_skb, FREE_WRITE);
+		csta->tx_skb = NULL;
+	}
+	switch (csta->typ) {
+#if CARD_TELES0
+		case ISDN_CTYPE_16_0:
+		case ISDN_CTYPE_8_0:
+			release_io_teles0(cards + cardnr);
+			break;
+#endif
+#if CARD_TELES3
+		case ISDN_CTYPE_PNP:
+		case ISDN_CTYPE_16_3:
+		case ISDN_CTYPE_TELESPCMCIA:
+			release_io_teles3(cards + cardnr);
+			break;
+#endif
+#if CARD_AVM_A1
+		case ISDN_CTYPE_A1:
+			release_io_avm_a1(cards + cardnr);
+			break;
+#endif
+#if CARD_ELSA
+		case ISDN_CTYPE_ELSA:
+		case ISDN_CTYPE_ELSA_QS1000:
+			release_io_elsa(cards + cardnr);
+			break;
+#endif
+#if CARD_IX1MICROR2
+		case ISDN_CTYPE_IX1MICROR2:
+			release_io_ix1micro(cards + cardnr);
+			break;
+#endif
+		default:
+			break;
+	}
+	ll_unload(csta);
+}
+
+static int
+checkcard(int cardnr, char *id)
+{
+	long flags;
+	int ret = 0;
+	struct IsdnCard *card = cards + cardnr;
+	struct IsdnCardState *sp;
+
+	save_flags(flags);
+	cli();
+	if (!(sp = (struct IsdnCardState *)
+	      kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for IsdnCardState(card %d)\n",
+		       cardnr + 1);
+		restore_flags(flags);
+		return (0);
+	}
+	card->sp = sp;
+	sp->cardnr = cardnr;
+	sp->cfg_reg = 0;
+	sp->protocol = card->protocol;
+
+	if ((card->typ > 0) && (card->typ < 31)) {
+		if (!((1 << card->typ) & SUPORTED_CARDS)) {
+			printk(KERN_WARNING
+			     "HiSax: Support for %s Card not selected\n",
+			       CardType[card->typ]);
+			restore_flags(flags);
+			return (0);
+		}
+	} else {
+		printk(KERN_WARNING
+		       "HiSax: Card Type %d out of range\n",
+		       card->typ);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!(sp->dlogspace = kmalloc(4096, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for dlogspace(card %d)\n",
+		       cardnr + 1);
+		restore_flags(flags);
+		return (0);
+	}
+	if (!(sp->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for status_buf(card %d)\n",
+		       cardnr + 1);
+		kfree(sp->dlogspace);
+		restore_flags(flags);
+		return (0);
+	}
+	sp->status_read = sp->status_buf;
+	sp->status_write = sp->status_buf;
+	sp->status_end = sp->status_buf + HISAX_STATUS_BUFSIZE - 1;
+	sp->typ = card->typ;
+	sp->CallFlags = 0;
+	strcpy(sp->iif.id, id);
+	sp->iif.channels = 2;
+	sp->iif.maxbufsize = MAX_DATA_SIZE;
+	sp->iif.hl_hdrlen = MAX_HEADER_LEN;
+	sp->iif.features =
+	    ISDN_FEATURE_L2_X75I |
+	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L2_TRANS |
+	    ISDN_FEATURE_L3_TRANS |
+#ifdef	CONFIG_HISAX_1TR6
+	    ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef	CONFIG_HISAX_EURO
+	    ISDN_FEATURE_P_EURO |
+#endif
+#ifdef        CONFIG_HISAX_NI1
+	    ISDN_FEATURE_P_NI1 |
+#endif
+	    0;
+
+	sp->iif.command = HiSax_command;
+	sp->iif.writebuf = NULL;
+	sp->iif.writecmd = NULL;
+	sp->iif.writebuf_skb = HiSax_writebuf_skb;
+	sp->iif.readstat = HiSax_readstatus;
+	register_isdn(&sp->iif);
+	sp->myid = sp->iif.channels;
+	restore_flags(flags);
+	printk(KERN_NOTICE
+	       "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+	       (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+	       (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+	       (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+	       (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+	       "NONE", sp->iif.id, sp->myid);
+	switch (card->typ) {
+#if CARD_TELES0
+		case ISDN_CTYPE_16_0:
+		case ISDN_CTYPE_8_0:
+			ret = setup_teles0(card);
+			break;
+#endif
+#if CARD_TELES3
+		case ISDN_CTYPE_16_3:
+		case ISDN_CTYPE_PNP:
+		case ISDN_CTYPE_TELESPCMCIA:
+			ret = setup_teles3(card);
+			break;
+#endif
+#if CARD_AVM_A1
+		case ISDN_CTYPE_A1:
+			ret = setup_avm_a1(card);
+			break;
+#endif
+#if CARD_ELSA
+		case ISDN_CTYPE_ELSA:
+		case ISDN_CTYPE_ELSA_QS1000:
+			ret = setup_elsa(card);
+			break;
+#endif
+#if CARD_IX1MICROR2
+		case ISDN_CTYPE_IX1MICROR2:
+			ret = setup_ix1micro(card);
+			break;
+#endif
+		default:
+			printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
+			       card->typ);
+			ll_unload(sp);
+			return (0);
+	}
+	if (!ret) {
+		ll_unload(sp);
+		return (0);
+	}
+	if (!(sp->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) {
+		printk(KERN_WARNING
+		       "HiSax: No memory for isac rcvbuf\n");
+		return (1);
+	}
+	sp->rcvidx = 0;
+	sp->tx_skb = NULL;
+	sp->tx_cnt = 0;
+	sp->event = 0;
+	sp->tqueue.next = 0;
+	sp->tqueue.sync = 0;
+	sp->tqueue.routine = (void *) (void *) isac_bh;
+	sp->tqueue.data = sp;
+
+	skb_queue_head_init(&sp->rq);
+	skb_queue_head_init(&sp->sq);
+
+	sp->stlist = NULL;
+	sp->ph_active = 0;
+	sp->dlogflag = 0;
+	sp->debug = L1_DEB_WARN;
+#ifdef DEBUG_MAGIC
+	sp->magic = 301271;
+#endif
+
+	init_hscxstate(sp, 0);
+	init_hscxstate(sp, 1);
+
+	switch (card->typ) {
+#if CARD_TELES0
+		case ISDN_CTYPE_16_0:
+		case ISDN_CTYPE_8_0:
+			ret = initteles0(sp);
+			break;
+#endif
+#if CARD_TELES3
+		case ISDN_CTYPE_16_3:
+		case ISDN_CTYPE_PNP:
+		case ISDN_CTYPE_TELESPCMCIA:
+			ret = initteles3(sp);
+			break;
+#endif
+#if CARD_AVM_A1
+		case ISDN_CTYPE_A1:
+			ret = initavm_a1(sp);
+			break;
+#endif
+#if CARD_ELSA
+		case ISDN_CTYPE_ELSA:
+		case ISDN_CTYPE_ELSA_QS1000:
+			ret = initelsa(sp);
+			break;
+#endif
+#if CARD_IX1MICROR2
+		case ISDN_CTYPE_IX1MICROR2:
+			ret = initix1micro(sp);
+			break;
+#endif
+		default:
+			ret = 0;
+			break;
+	}
+	if (!ret) {
+		closecard(cardnr);
+		return (0);
+	}
+	init_tei(sp, sp->protocol);
+	CallcNewChan(sp);
+	ll_run(sp);
+	return (1);
+}
+
+void
+HiSax_shiftcards(int idx)
+{
+	int i;
+
+	for (i = idx; i < 15; i++)
+		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
+}
+
+int
+HiSax_inithardware(void)
+{
+	int foundcards = 0;
+	int i = 0;
+	int t = ',';
+	int flg = 0;
+	char *id;
+	char *next_id = HiSax_id;
+	char ids[20];
+
+	if (strchr(HiSax_id, ','))
+		t = ',';
+	else if (strchr(HiSax_id, '%'))
+		t = '%';
+
+	while (i < nrcards) {
+		if (cards[i].typ < 1)
+			break;
+		id = next_id;
+		if ((next_id = strchr(id, t))) {
+			*next_id++ = 0;
+			strcpy(ids, id);
+			flg = i + 1;
+		} else {
+			next_id = id;
+			if (flg >= i)
+				strcpy(ids, id);
+			else
+				sprintf(ids, "%s%d", id, i);
+		}
+		if (checkcard(i, ids)) {
+			foundcards++;
+			i++;
+		} else {
+			printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+			       CardType[cards[i].typ]);
+			if (cards[i].sp)
+				kfree((void *) cards[i].sp);
+			cards[i].sp = NULL;
+			HiSax_shiftcards(i);
+		}
+	}
+	return foundcards;
+}
+
+void
+HiSax_closehardware(void)
+{
+	int i;
+	long flags;
+
+	save_flags(flags);
+	cli();
+	for (i = 0; i < nrcards; i++)
+		if (cards[i].sp) {
+			ll_stop(cards[i].sp);
+			CallcFreeChan(cards[i].sp);
+			release_tei(cards[i].sp);
+			release_irq(i);
+			closecard(i);
+			kfree((void *) cards[i].sp);
+			cards[i].sp = NULL;
+		}
+	Isdnl2Free();
+	CallcFree();
+	restore_flags(flags);
+}
+
+static void
+hscx_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+	long flags;
+
+	switch (pr) {
+		case (PH_DATA):
+			save_flags(flags);
+			cli();
+			if (hsp->tx_skb) {
+				skb_queue_tail(&hsp->squeue, skb);
+				restore_flags(flags);
+			} else {
+				restore_flags(flags);
+				hsp->tx_skb = skb;
+				hsp->count = 0;
+				sp->hscx_fill_fifo(hsp);
+			}
+			break;
+		case (PH_DATA_PULLED):
+			if (hsp->tx_skb) {
+				printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+				break;
+			}
+			hsp->tx_skb = skb;
+			hsp->count = 0;
+			sp->hscx_fill_fifo(hsp);
+			break;
+		case (PH_REQUEST_PULL):
+			if (!hsp->tx_skb) {
+				st->l1.requestpull = 0;
+				st->l1.l1l2(st, PH_PULL_ACK, NULL);
+			} else
+				st->l1.requestpull = !0;
+			break;
+	}
+
+}
+extern struct IsdnBuffers *tracebuf;
+
+static void
+hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
+		  int releasetoo)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *)
+	st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+	struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+	if (hsp->magic != 301270) {
+		printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
+		return;
+	}
+#endif
+
+	while ((skb = skb_dequeue(&hsp->squeue)))
+		dev_kfree_skb(skb, FREE_WRITE);
+}
+
+static int
+open_hscxstate(struct IsdnCardState *sp,
+	       int hscx)
+{
+	struct HscxState *hsp = sp->hs + hscx;
+
+	if (!hsp->init) {
+		if (!(hsp->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+			       "HiSax: No memory for hscx_rcvbuf\n");
+			return (1);
+		}
+		skb_queue_head_init(&hsp->rqueue);
+		skb_queue_head_init(&hsp->squeue);
+	}
+	hsp->init = !0;
+
+	hsp->tx_skb = NULL;
+	hsp->event = 0;
+	hsp->rcvidx = 0;
+	hsp->tx_cnt = 0;
+	return (0);
+}
+
+static void
+hscx_manl1(struct PStack *st, int pr,
+	   void *arg)
+{
+	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+	struct HscxState *hsp = sp->hs + st->l1.hscx;
+
+	switch (pr) {
+		case (PH_ACTIVATE):
+			hsp->active = !0;
+			sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
+			st->l1.l1man(st, PH_ACTIVATE, NULL);
+			break;
+		case (PH_DEACTIVATE):
+			if (!hsp->tx_skb)
+				sp->modehscx(hsp, 0, 0);
+
+			hsp->active = 0;
+			break;
+	}
+}
+
+int
+setstack_hscx(struct PStack *st, struct HscxState *hs)
+{
+	if (open_hscxstate(st->l1.hardware, hs->hscx))
+		return (-1);
+
+	st->l1.hscx = hs->hscx;
+	st->l2.l2l1 = hscx_l2l1;
+	st->ma.manl1 = hscx_manl1;
+	st->l2.l2l1discardq = hscx_l2l1discardq;
+
+	st->l1.act_state = 0;
+	st->l1.requestpull = 0;
+
+	hs->st = st;
+	return (0);
+}
+
+void
+HiSax_reportcard(int cardnr)
+{
+	struct IsdnCardState *sp = cards[cardnr].sp;
+
+	printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
+	printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]);
+	printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug);
+	printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
+	       (ulong) & HiSax_reportcard);
+}
+
+#ifdef L2FRAME_DEBUG		/* psa */
+
+char *
+l2cmd(u_char cmd)
+{
+	switch (cmd & ~0x10) {
+		case 1:
+			return "RR";
+		case 5:
+			return "RNR";
+		case 9:
+			return "REJ";
+		case 0x6f:
+			return "SABME";
+		case 0x0f:
+			return "DM";
+		case 3:
+			return "UI";
+		case 0x43:
+			return "DISC";
+		case 0x63:
+			return "UA";
+		case 0x87:
+			return "FRMR";
+		case 0xaf:
+			return "XID";
+		default:
+			if (!(cmd & 1))
+				return "I";
+			else
+				return "invalid command";
+	}
+}
+
+static char tmp[20];
+
+char *
+l2frames(u_char * ptr)
+{
+	switch (ptr[2] & ~0x10) {
+		case 1:
+		case 5:
+		case 9:
+			sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
+			break;
+		case 0x6f:
+		case 0x0f:
+		case 3:
+		case 0x43:
+		case 0x63:
+		case 0x87:
+		case 0xaf:
+			sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
+			break;
+		default:
+			if (!(ptr[2] & 1)) {
+				sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
+				break;
+			} else
+				return "invalid command";
+	}
+
+
+	return tmp;
+}
+
+void
+Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
+{
+	char tmp[132];
+	u_char *ptr;
+
+	ptr = skb->data;
+
+	if (ptr[0] & 1 || !(ptr[1] & 1))
+		debugl1(sp, "Addres not LAPD");
+	else {
+		sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)",
+			(dir ? "<-" : "->"), buf, l2frames(ptr),
+			((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1);
+		debugl1(sp, tmp);
+	}
+}
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl1.h linux-2.0.31-pre3/drivers/isdn/hisax/isdnl1.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl1.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl1.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,51 @@
+/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $
+ *
+ * $Log: isdnl1.h,v $
+ * Revision 1.4  1997/04/06 22:55:52  keil
+ * Using SKB's
+ *
+ * Revision 1.3  1996/12/08 19:41:55  keil
+ * L2FRAME_DEBUG
+ *
+ * Revision 1.2  1996/10/27 22:26:27  keil
+ * ISAC/HSCX version functions
+ *
+ * Revision 1.1  1996/10/13 20:03:47  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+
+#define L2FRAME_DEBUG
+
+/* DEBUG Level */
+
+#define	L1_DEB_WARN		0x01
+#define	L1_DEB_INTSTAT		0x02
+#define	L1_DEB_ISAC		0x04
+#define	L1_DEB_ISAC_FIFO	0x08
+#define	L1_DEB_HSCX		0x10
+#define	L1_DEB_HSCX_FIFO	0x20
+#define	L1_DEB_LAPD	        0x40
+
+
+#define ISAC_RCVBUFREADY 0
+#define ISAC_XMTBUFREADY 1
+#define ISAC_PHCHANGE    2
+
+#define HSCX_RCVBUFREADY 0
+#define HSCX_XMTBUFREADY 1
+
+extern void debugl1(struct IsdnCardState *sp, char *msg);
+extern char *HscxVersion(u_char v);
+extern char *ISACVersion(u_char v);
+extern void hscx_sched_event(struct HscxState *hsp, int event);
+extern void isac_sched_event(struct IsdnCardState *sp, int event);
+extern void isac_new_ph(struct IsdnCardState *sp);
+extern get_irq(int cardnr, void *routine);
+
+#ifdef L2FRAME_DEBUG
+extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir);
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl2.c linux-2.0.31-pre3/drivers/isdn/hisax/isdnl2.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl2.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl2.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1325 @@
+/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: isdnl2.c,v $
+ * Revision 1.10  1997/05/06 09:38:13  keil
+ * Bugfixes: - clear ack queue entries after resend
+ *           - acknowlege each frame to linklevel
+ *           - UA for SABM is Response, not command
+ *           - only RR was send as supervisor frame (X.75 hangs after a
+ *             sequence error)
+ *
+ * Revision 1.9  1997/04/07 23:02:11  keil
+ * missing braces
+ *
+ * Revision 1.8  1997/04/06 22:59:59  keil
+ * Using SKB's; changing function names; some minor changes
+ *
+ * Revision 1.7  1997/02/09 00:25:44  keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.6  1997/01/21 22:23:42  keil
+ * D-channel log changed
+ *
+ * Revision 1.5  1997/01/04 13:47:06  keil
+ * handling of MDL_REMOVE added (Thanks to Sim Yskes)
+ *
+ * Revision 1.4  1996/12/08 19:51:51  keil
+ * many fixes from Pekka Sarnila
+ *
+ * Revision 1.3  1996/11/05 19:39:12  keil
+ * X.75 bugfixes Thank to Martin Maurer
+ *
+ * Revision 1.2  1996/10/30 10:20:58  keil
+ * X.75 answer of SABMX fixed to response address (AVM X.75 problem)
+ *
+ * Revision 1.1  1996/10/13 20:04:54  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl2.h"
+
+const char *l2_revision = "$Revision: 1.10 $";
+
+static void l2m_debug(struct FsmInst *fi, char *s);
+
+struct Fsm l2fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L2_1,
+	ST_L2_3,
+	ST_L2_4,
+	ST_L2_5,
+	ST_L2_6,
+	ST_L2_7,
+	ST_L2_8,
+};
+
+#define L2_STATE_COUNT (ST_L2_8+1)
+
+static char *strL2State[] =
+{
+	"ST_L2_1",
+	"ST_L2_3",
+	"ST_L2_4",
+	"ST_L2_5",
+	"ST_L2_6",
+	"ST_L2_7",
+	"ST_L2_8",
+};
+
+enum {
+	EV_L2_UI,
+	EV_L2_SABMX,
+	EV_L2_UA,
+	EV_L2_DISC,
+	EV_L2_I,
+	EV_L2_RR,
+	EV_L2_REJ,
+	EV_L2_FRMR,
+	EV_L2_DL_DATA,
+	EV_L2_DL_ESTABLISH,
+	EV_L2_MDL_ASSIGN,
+	EV_L2_MDL_REMOVE,
+	EV_L2_DL_UNIT_DATA,
+	EV_L2_DL_RELEASE,
+	EV_L2_MDL_NOTEIPROC,
+	EV_L2_T200,
+	EV_L2_ACK_PULL,
+	EV_L2_T203,
+	EV_L2_RNR,
+};
+
+#define L2_EVENT_COUNT (EV_L2_RNR+1)
+
+static char *strL2Event[] =
+{
+	"EV_L2_UI",
+	"EV_L2_SABMX",
+	"EV_L2_UA",
+	"EV_L2_DISC",
+	"EV_L2_I",
+	"EV_L2_RR",
+	"EV_L2_REJ",
+	"EV_L2_FRMR",
+	"EV_L2_DL_DATA",
+	"EV_L2_DL_ESTABLISH",
+	"EV_L2_MDL_ASSIGN",
+	"EV_L2_MDL_REMOVE",
+	"EV_L2_DL_UNIT_DATA",
+	"EV_L2_DL_RELEASE",
+	"EV_L2_MDL_NOTEIPROC",
+	"EV_L2_T200",
+	"EV_L2_ACK_PULL",
+	"EV_L2_T203",
+	"EV_L2_RNR",
+};
+
+int errcount = 0;
+
+static int l2addrsize(struct Layer2 *tsp);
+
+static void
+InitWin(struct Layer2 *l2)
+{
+	int i;
+
+	for (i = 0; i < MAX_WINDOW; i++)
+		l2->windowar[i] = NULL;
+}
+
+static void
+ReleaseWin(struct Layer2 *l2)
+{
+	int i, cnt = 0;
+
+
+	for (i = 0; i < MAX_WINDOW; i++) {
+		if (l2->windowar[i]) {
+			cnt++;
+			dev_kfree_skb(l2->windowar[i], FREE_WRITE);
+			l2->windowar[i] = NULL;
+		}
+	}
+	if (cnt)
+		printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
+}
+
+static int
+cansend(struct PStack *st)
+{
+	int p1;
+
+	p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
+	return (st->l2.vs != p1);
+}
+
+static void
+discard_i_queue(struct PStack *st)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&st->l2.i_queue))) {
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+	}
+}
+
+int
+l2headersize(struct Layer2 *tsp, int ui)
+{
+	return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+}
+
+int
+l2addrsize(struct Layer2 *tsp)
+{
+	return (tsp->laptype == LAPD ? 2 : 1);
+}
+
+static int
+sethdraddr(struct Layer2 *tsp,
+	   u_char * header, int rsp)
+{
+	u_char *ptr = header;
+	int crbit;
+
+	if (tsp->laptype == LAPD) {
+		crbit = rsp;
+		if (!tsp->orig)
+			crbit = !crbit;
+		*ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
+		*ptr++ = (tsp->tei << 1) | 1;
+		return (2);
+	} else {
+		crbit = rsp;
+		if (tsp->orig)
+			crbit = !crbit;
+		if (crbit)
+			*ptr++ = 1;
+		else
+			*ptr++ = 3;
+		return (1);
+	}
+}
+
+static void
+enqueue_ui(struct PStack *st,
+	   struct sk_buff *skb)
+{
+	st->l2.l2l1(st, PH_DATA, skb);
+}
+
+static void
+enqueue_super(struct PStack *st,
+	      struct sk_buff *skb)
+{
+	st->l2.l2l1(st, PH_DATA, skb);
+}
+
+static int
+legalnr(struct PStack *st, int nr)
+{
+	struct Layer2 *l2 = &st->l2;
+	int lnr, lvs;
+
+	lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
+	lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
+	return (lnr <= lvs);
+}
+
+static void
+setva(struct PStack *st, int nr)
+{
+	struct Layer2 *l2 = &st->l2;
+
+	if (l2->va != nr) {
+		while (l2->va != nr) {
+			l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
+			dev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE);
+			l2->windowar[l2->sow] = NULL;
+			l2->sow = (l2->sow + 1) % l2->window;
+			if (st->l4.l2writewakeup)
+				st->l4.l2writewakeup(st);
+		}
+	}
+}
+
+static void
+l2s1(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces);
+	FsmChangeState(fi, ST_L2_3);
+}
+
+static void
+l2_send_ui(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	u_char header[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(&(st->l2), header, CMD);
+	header[i++] = UI;
+	memcpy(skb_push(skb, i), header, i);
+	enqueue_ui(st, skb);
+}
+
+static void
+l2_receive_ui(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_pull(skb, l2headersize(&st->l2, 1));
+	st->l2.l2l3(st, DL_UNIT_DATA, skb);
+}
+
+inline void
+send_uframe(struct PStack *st, u_char cmd, u_char cr)
+{
+	struct sk_buff *skb;
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	i = sethdraddr(&st->l2, tmp, cr);
+	tmp[i++] = cmd;
+	if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+		printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n");
+		return;
+	}
+	SET_SKB_FREE(skb);
+	memcpy(skb_put(skb, i), tmp, i);
+	enqueue_super(st, skb);
+}
+
+static void
+establishlink(struct FsmInst *fi)
+{
+	struct PStack *st = fi->userdata;
+	u_char cmd;
+
+	FsmChangeState(fi, ST_L2_5);
+	st->l2.rc = 0;
+
+	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 1");
+
+
+	cmd = (st->l2.extended ? SABME : SABM) | 0x10; 
+	send_uframe(st, cmd, CMD);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+	establishlink(fi);
+}
+
+static void
+l2_send_disconn(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+
+	FsmChangeState(fi, ST_L2_6);
+
+	FsmDelTimer(&st->l2.t203_timer, 1);
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 2);
+		st->l2.t200_running = 0;
+	}
+	st->l2.rc = 0;
+	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 2");
+
+
+	if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
+		send_uframe(st, DISC | 0x10, CMD);
+
+	discard_i_queue(st);
+}
+
+static void
+l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	int est = 1, state;
+	u_char PollFlag;
+
+	state = fi->state;
+
+	skb_pull(skb, l2addrsize(&(st->l2)));
+	PollFlag = *skb->data & 0x10;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if (ST_L2_4 != state)
+		if (st->l2.vs != st->l2.va) {
+			discard_i_queue(st);
+			est = 1;
+		} else
+			est = 0;
+
+	st->l2.vs = 0;
+	st->l2.va = 0;
+	st->l2.vr = 0;
+	st->l2.sow = 0;
+	if (ST_L2_7 != state)
+		FsmChangeState(fi, ST_L2_7);
+
+	send_uframe(st, UA | PollFlag, RSP);
+
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 15);
+		st->l2.t200_running = 0;
+	}
+	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 3");
+
+	if (est)
+		st->l2.l2man(st, DL_ESTABLISH, NULL);
+
+	if (ST_L2_8 == state)
+		if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+			st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+l2_got_disconn(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	struct Channel *chanp = st->l4.userdata;
+	u_char PollFlag;
+
+	skb_pull(skb, l2addrsize(&(st->l2)));
+	PollFlag = *skb->data & 0x10;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	FsmChangeState(fi, ST_L2_4);
+
+	FsmDelTimer(&st->l2.t203_timer, 3);
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 4);
+		st->l2.t200_running = 0;
+	}
+	if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
+		send_uframe(st, UA | PollFlag, RSP);
+
+	st->l2.l2man(st, DL_RELEASE, NULL);
+}
+
+static void
+l2_got_st4_disc(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	struct Channel *chanp = st->l4.userdata;
+	u_char PollFlag;
+
+	skb_pull(skb, l2addrsize(&(st->l2)));
+	PollFlag = *skb->data & 0x10;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
+		send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP);
+
+}
+
+static void
+l2_got_ua_establish(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	u_char f;
+
+	skb_pull(skb, l2addrsize(&(st->l2)));
+	f = *skb->data & 0x10;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	if (f) {
+		st->l2.vs = 0;
+		st->l2.va = 0;
+		st->l2.vr = 0;
+		st->l2.sow = 0;
+		FsmChangeState(fi, ST_L2_7);
+
+		FsmDelTimer(&st->l2.t200_timer, 5);
+		if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 4");
+
+		st->l2.l2man(st, DL_ESTABLISH, NULL);
+	}
+}
+
+static void
+l2_got_ua_disconn(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	u_char f;
+
+	skb_pull(skb, l2addrsize(&(st->l2)));
+	f = *skb->data & 0x10;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	if (f) {
+		FsmDelTimer(&st->l2.t200_timer, 6);
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	}
+}
+
+inline void
+enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
+{
+	struct sk_buff *skb;
+	struct Layer2 *l2;
+	u_char tmp[MAX_HEADER_LEN];
+	int i;
+
+	l2 = &st->l2;
+	i = sethdraddr(l2, tmp, cr);
+	if (l2->extended) {
+		tmp[i++] = typ;
+		tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
+	} else
+		tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
+	if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+		printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n");
+		return;
+	}
+	SET_SKB_FREE(skb);
+	memcpy(skb_put(skb, i), tmp, i);
+	enqueue_super(st, skb);
+}
+
+inline void
+enquiry_response(struct PStack *st, u_char typ, u_char final)
+{
+	enquiry_cr(st, typ, RSP, final);
+}
+
+inline void
+enquiry_command(struct PStack *st, u_char typ, u_char poll)
+{
+	enquiry_cr(st, typ, CMD, poll);
+}
+
+static void
+nrerrorrecovery(struct FsmInst *fi)
+{
+	/* should log error here */
+	establishlink(fi);
+}
+
+static void
+l2_got_st7_RR(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	struct sk_buff *skb = arg;
+	int PollFlag, seq, rsp;
+	struct Layer2 *l2;
+
+	l2 = &st->l2;
+	if (l2->laptype == LAPD)
+		rsp = *skb->data & 0x2;
+	else
+		rsp = *skb->data == 0x3;
+	if (l2->orig)
+		rsp = !rsp;
+
+	skb_pull(skb, l2addrsize(l2));
+	if (l2->extended) {
+		PollFlag = (skb->data[1] & 0x1) == 0x1;
+		seq = skb->data[1] >> 1;
+	} else {
+		PollFlag = (skb->data[0] & 0x10);
+		seq = (skb->data[0] >> 5) & 0x7;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if (!((chanp->impair == 4) && (st->l2.laptype == LAPB)))
+		if ((!rsp) && PollFlag)
+			enquiry_response(st, RR, PollFlag);
+
+	if (legalnr(st, seq)) {
+		if (seq == l2->vs) {
+			setva(st, seq);
+			FsmDelTimer(&l2->t200_timer, 7);
+			l2->t200_running = 0;
+			FsmDelTimer(&l2->t203_timer, 8);
+			if (FsmAddTimer(&l2->t203_timer, l2->t203, EV_L2_T203, NULL, 5))
+				if (l2->l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 5");
+
+			if (skb_queue_len(&st->l2.i_queue))
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		} else if (l2->va != seq) {
+			setva(st, seq);
+			FsmDelTimer(&st->l2.t200_timer, 9);
+			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 6");
+			if (skb_queue_len(&st->l2.i_queue))
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		}
+	} else
+		nrerrorrecovery(fi);
+
+	if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) {
+		fi->userint &= ~LC_FLUSH_WAIT;
+		st->l2.l2man(st, DL_FLUSH, NULL);
+	}
+}
+
+static void
+l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+
+	skb_queue_tail(&st->l2.i_queue, skb);
+	st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static int
+icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr)
+{
+	struct PStack *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+	struct sk_buff *skb = arg;
+	struct IsdnCardState *sp = st->l1.hardware;
+	struct Layer2 *l2 = &(st->l2);
+	int i, p, seq, wasok;
+	char str[64];
+
+	i = l2addrsize(l2);
+	if (l2->extended) {
+		p = (skb->data[i + 1] & 0x1) == 0x1;
+		seq = skb->data[i] >> 1;
+		*nr = (skb->data[i + 1] >> 1) & 0x7f;
+	} else {
+		p = (skb->data[i] & 0x10);
+		seq = (skb->data[i] >> 1) & 0x7;
+		*nr = (skb->data[i] >> 5) & 0x7;
+	}
+
+	if (l2->vr == seq) {
+		wasok = !0;
+
+		l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
+		l2->rejexp = 0;
+
+		if (st->l2.laptype == LAPD)
+			if (sp->dlogflag) {
+				LogFrame(st->l1.hardware, skb->data, skb->len);
+				sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
+				dlogframe(st->l1.hardware, skb->data + l2->ihsize,
+					  skb->len - l2->ihsize, str);
+			}
+		if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
+			if (p || (!skb_queue_len(&st->l2.i_queue)))
+				enquiry_response(st, RR, p);
+		skb_pull(skb, l2headersize(l2, 0));
+	} else {
+		/* n(s)!=v(r) */
+		wasok = 0;
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+		if (st->l2.rejexp) {
+			if (p)
+				if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
+					enquiry_response(st, RR, p);
+		} else {
+			st->l2.rejexp = !0;
+			enquiry_command(st, REJ, 1);
+		}
+	}
+	return wasok;
+}
+
+static void
+l2_got_st7_data(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	int nr, wasok;
+
+	wasok = icommandreceived(fi, event, arg, &nr);
+
+	if (legalnr(st, nr)) {
+		if (nr == st->l2.vs) {
+			setva(st, nr);
+			FsmDelTimer(&st->l2.t200_timer, 10);
+			st->l2.t200_running = 0;
+			FsmDelTimer(&st->l2.t203_timer, 11);
+			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 5");
+
+			if (skb_queue_len(&st->l2.i_queue))
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		} else if (nr != st->l2.va) {
+			setva(st, nr);
+			FsmDelTimer(&st->l2.t200_timer, 12);
+			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 6");
+
+			if (skb_queue_len(&st->l2.i_queue))
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+		}
+	} else
+		nrerrorrecovery(fi);
+
+	if (wasok)
+		st->l2.l2l3(st, DL_DATA, skb);
+}
+
+static void
+l2_got_st8_data(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	int nr, wasok;
+
+	wasok = icommandreceived(fi, event, arg, &nr);
+
+	if (legalnr(st, nr)) {
+		setva(st, nr);
+		if (skb_queue_len(&st->l2.i_queue))
+			st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+	} else
+		nrerrorrecovery(fi);
+
+	if (wasok)
+		st->l2.l2l3(st, DL_DATA, skb);
+}
+
+static void
+l2_got_tei(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	st->l2.tei = (int) arg;
+	establishlink(fi);
+}
+
+static void
+invoke_retransmission(struct PStack *st, int nr)
+{
+	struct Layer2 *l2 = &st->l2;
+	int p1;
+
+	if (l2->vs != nr) {
+		while (l2->vs != nr) {
+
+			l2->vs = l2->vs - 1;
+			if (l2->vs < 0)
+				l2->vs += l2->extended ? 128 : 8;
+
+			p1 = l2->vs - l2->va;
+			if (p1 < 0)
+				p1 += l2->extended ? 128 : 8;
+			p1 = (p1 + l2->sow) % l2->window;
+
+			skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+			l2->windowar[p1] = NULL;
+		}
+		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+	}
+}
+
+static void
+l2_got_st7_rej(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	int PollFlag, seq, rsp;
+	struct Layer2 *l2;
+
+	l2 = &st->l2;
+	if (l2->laptype == LAPD)
+		rsp = *skb->data & 0x2;
+	else
+		rsp = *skb->data == 0x3;
+	if (l2->orig)
+		rsp = !rsp;
+
+	skb_pull(skb, l2addrsize(l2));
+	if (l2->extended) {
+		PollFlag = (skb->data[1] & 0x1) == 0x1;
+		seq = skb->data[1] >> 1;
+	} else {
+		PollFlag = (skb->data[0] & 0x10);
+		seq = (skb->data[0] >> 5) & 0x7;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if ((!rsp) && PollFlag)
+		enquiry_response(st, RR, PollFlag);
+
+	if (!legalnr(st, seq))
+		return;
+
+	setva(st, seq);
+	invoke_retransmission(st, seq);
+}
+
+static void
+l2_no_tei(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	u_char cmd;
+
+	if (st->l2.rc == st->l2.n200) {
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	} else {
+		st->l2.rc++;
+
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 7");
+
+		cmd = (st->l2.extended ? SABME : SABM) | 0x10; 
+		send_uframe(st, cmd, CMD);
+	}
+}
+
+static void
+l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct Channel *chanp = st->l4.userdata;
+
+	if (st->l2.rc == st->l2.n200) {
+		FsmChangeState(fi, ST_L2_4);
+		st->l2.l2man(st, DL_RELEASE, NULL);
+	} else {
+		st->l2.rc++;
+
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 8");
+
+
+		if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
+			send_uframe(st, DISC | 0x10, CMD);
+
+	}
+}
+
+static void
+l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb;
+	struct Layer2 *l2 = &st->l2;
+	u_char header[MAX_HEADER_LEN];
+	int p1, i;
+
+	if (!cansend(st))
+		return;
+
+	skb = skb_dequeue(&l2->i_queue);
+	if (!skb)
+		return;
+
+	p1 = l2->vs - l2->va;
+	if (p1 < 0)
+		p1 += l2->extended ? 128 : 8;
+	p1 = (p1 + l2->sow) % l2->window;
+	if (l2->windowar[p1]) {
+		printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
+		       p1);
+		dev_kfree_skb(l2->windowar[p1], FREE_WRITE);
+	}
+	l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
+
+	i = sethdraddr(&st->l2, header, CMD);
+
+	if (l2->extended) {
+		header[i++] = l2->vs << 1;
+		header[i++] = l2->vr << 1;
+		l2->vs = (l2->vs + 1) % 128;
+	} else {
+		header[i++] = (l2->vr << 5) | (l2->vs << 1);
+		l2->vs = (l2->vs + 1) % 8;
+	}
+
+	memcpy(skb_push(skb, i), header, i);
+	st->l2.l2l1(st, PH_DATA_PULLED, skb);
+	if (!st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t203_timer, 13);
+		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
+			if (st->l2.l2m.debug)
+				l2m_debug(&st->l2.l2m, "FAT 9");
+
+		st->l2.t200_running = !0;
+	}
+	if (skb_queue_len(&l2->i_queue) && cansend(st))
+		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+transmit_enquiry(struct PStack *st)
+{
+
+	enquiry_command(st, RR, 1);
+	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
+		if (st->l2.l2m.debug)
+			l2m_debug(&st->l2.l2m, "FAT 10");
+
+	st->l2.t200_running = !0;
+}
+
+static void
+l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	st->l2.t200_running = 0;
+
+	st->l2.rc = 1;
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(st);
+}
+
+static void
+l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	int PollFlag, seq, rsp;
+	struct Layer2 *l2;
+
+	l2 = &st->l2;
+	if (l2->laptype == LAPD)
+		rsp = *skb->data & 0x2;
+	else
+		rsp = *skb->data == 0x3;
+	if (l2->orig)
+		rsp = !rsp;
+
+	skb_pull(skb, l2addrsize(l2));
+	if (l2->extended) {
+		PollFlag = (skb->data[1] & 0x1) == 0x1;
+		seq = skb->data[1] >> 1;
+	} else {
+		PollFlag = (skb->data[0] & 0x10);
+		seq = (skb->data[0] >> 5) & 0x7;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if (rsp && PollFlag) {
+		if (legalnr(st, seq)) {
+			FsmChangeState(fi, ST_L2_7);
+			setva(st, seq);
+			if (st->l2.t200_running) {
+				FsmDelTimer(&st->l2.t200_timer, 14);
+				st->l2.t200_running = 0;
+			}
+			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
+				if (st->l2.l2m.debug)
+					l2m_debug(&st->l2.l2m, "FAT 11");
+
+			invoke_retransmission(st, seq);
+
+			if (skb_queue_len(&l2->i_queue) && cansend(st))
+				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+			else if (fi->userint & LC_FLUSH_WAIT) {
+				fi->userint &= ~LC_FLUSH_WAIT;
+				st->l2.l2man(st, DL_FLUSH, NULL);
+			}
+		}
+	} else {
+		if (!rsp && PollFlag)
+			enquiry_response(st, RR, PollFlag);
+		if (legalnr(st, seq)) {
+			setva(st, seq);
+		}
+	}
+}
+
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	st->l2.rc = 0;
+	FsmChangeState(fi, ST_L2_8);
+	transmit_enquiry(st);
+}
+
+static void
+l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	if (st->l2.rc == st->l2.n200) {
+		establishlink(fi);
+	} else {
+		st->l2.rc++;
+		transmit_enquiry(st);
+	}
+}
+
+static void
+l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+	struct sk_buff *skb = arg;
+	char tmp[64];
+
+	skb_pull(skb, l2addrsize(&st->l2));
+	if (st->l2.l2m.debug) {
+		if (st->l2.extended)
+			sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
+				skb->data[0], skb->data[1], skb->data[2],
+				skb->data[3], skb->data[4]);
+		else
+			sprintf(tmp, "FRMR information %2x %2x %2x",
+				skb->data[0], skb->data[1], skb->data[2]);
+
+		l2m_debug(&st->l2.l2m, tmp);
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+}
+
+static void
+l2_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+/*TODO
+   if( DL_RELEASE.req outstanding ) {
+   ... issue DL_RELEASE.confirm
+   } else {
+   if( fi->state != ST_L2_4 ) {
+   ... issue DL_RELEASE.indication
+   }
+   }
+   TODO */
+	discard_i_queue(st);	/* There is no UI queue in layer 2 */
+	st->l2.tei = 255;
+	if (st->l2.t200_running) {
+		FsmDelTimer(&st->l2.t200_timer, 18);
+		st->l2.t200_running = 0;
+	}
+	FsmDelTimer(&st->l2.t203_timer, 19);
+	st->l2.l2man(st, DL_RELEASE, NULL);	/* TEMP */
+	FsmChangeState(fi, ST_L2_1);
+}
+
+inline int
+IsUI(u_char * data, int ext)
+{
+	return ((data[0] & 0xef) == UI);
+}
+
+inline int
+IsUA(u_char * data, int ext)
+{
+	return ((data[0] & 0xef) == UA);
+}
+
+inline int
+IsDISC(u_char * data, int ext)
+{
+	return ((data[0] & 0xef) == DISC);
+}
+
+inline int
+IsRR(u_char * data, int ext)
+{
+	if (ext)
+		return (data[0] == RR);
+	else
+		return ((data[0] & 0xf) == 1);
+}
+
+inline int
+IsI(u_char * data, int ext)
+{
+	return ((data[0] & 0x1) == 0x0);
+}
+
+inline int
+IsSABMX(u_char * data, int ext)
+{
+	u_char d = data[0] & ~0x10;
+	
+	return (ext ? d == SABME : d == SABM);
+}
+
+inline int
+IsREJ(u_char * data, int ext)
+{
+	return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9);
+}
+
+inline int
+IsFRMR(u_char * data, int ext)
+{
+	return ((data[0] & 0xef) == FRMR);
+}
+
+inline int
+IsRNR(u_char * data, int ext)
+{
+	if (ext)
+		return (data[0] == RNR);
+	else
+		return ((data[0] & 0xf) == 5);
+}
+
+static struct FsmNode L2FnList[] =
+{
+	{ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
+	{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei},
+	{ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+	{ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
+	{ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish},
+	{ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
+	{ST_L2_7, EV_L2_DL_DATA, l2_feed_iqueue},
+	{ST_L2_7, EV_L2_DL_RELEASE, l2_send_disconn},
+	{ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+	{ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
+	{ST_L2_8, EV_L2_DL_RELEASE, l2_send_disconn},
+
+	{ST_L2_1, EV_L2_UI, l2_receive_ui},
+	{ST_L2_4, EV_L2_UI, l2_receive_ui},
+	{ST_L2_4, EV_L2_SABMX, l2_got_SABMX},
+	{ST_L2_4, EV_L2_DISC, l2_got_st4_disc},
+	{ST_L2_5, EV_L2_UA, l2_got_ua_establish},
+	{ST_L2_6, EV_L2_UA, l2_got_ua_disconn},
+	{ST_L2_7, EV_L2_UI, l2_receive_ui},
+	{ST_L2_7, EV_L2_DISC, l2_got_disconn},
+	{ST_L2_7, EV_L2_I, l2_got_st7_data},
+	{ST_L2_7, EV_L2_RR, l2_got_st7_RR},
+	{ST_L2_7, EV_L2_REJ, l2_got_st7_rej},
+	{ST_L2_7, EV_L2_SABMX, l2_got_SABMX},
+	{ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_8, EV_L2_RR, l2_got_st8_rr_rej},
+	{ST_L2_8, EV_L2_REJ, l2_got_st8_rr_rej},
+	{ST_L2_8, EV_L2_SABMX, l2_got_SABMX},
+	{ST_L2_8, EV_L2_DISC, l2_got_disconn},
+	{ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
+	{ST_L2_8, EV_L2_I, l2_got_st8_data},
+
+	{ST_L2_5, EV_L2_T200, l2_st5_tout_200},
+	{ST_L2_6, EV_L2_T200, l2_st6_tout_200},
+	{ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+	{ST_L2_7, EV_L2_T203, l2_st7_tout_203},
+	{ST_L2_8, EV_L2_T200, l2_st8_tout_200},
+
+	{ST_L2_1, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_3, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
+	{ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
+};
+
+#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
+
+static void
+isdnl2_l1l2(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	u_char *datap;
+	int ret = !0;
+
+	switch (pr) {
+		case (PH_DATA):
+			datap = skb->data;
+			datap += l2addrsize(&st->l2);
+
+			if (IsI(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
+			else if (IsRR(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_RR, skb);
+			else if (IsUI(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
+			else if (IsSABMX(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb);
+			else if (IsUA(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
+			else if (IsDISC(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
+			else if (IsREJ(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, skb);
+			else if (IsFRMR(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
+			else if (IsRNR(datap, st->l2.extended))
+				ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, skb);
+
+			if (ret) {
+				SET_SKB_FREE(skb);
+				dev_kfree_skb(skb, FREE_READ);
+			}
+			break;
+		case (PH_PULL_ACK):
+			FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
+			break;
+	}
+}
+
+static void
+isdnl2_l3l2(struct PStack *st, int pr, void *arg)
+{
+	switch (pr) {
+		case (DL_DATA):
+			if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
+				dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
+			}
+			break;
+		case (DL_UNIT_DATA):
+			if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
+				dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
+			}
+			break;
+	}
+}
+
+static void
+isdnl2_manl2(struct PStack *st, int pr, void *arg)
+{
+	switch (pr) {
+		case (DL_ESTABLISH):
+			FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+			break;
+		case (DL_RELEASE):
+			FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
+			break;
+		case (MDL_NOTEIPROC):
+			FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
+			break;
+		case (DL_FLUSH):
+			(&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
+			break;
+	}
+}
+
+static void
+isdnl2_teil2(struct PStack *st, int pr, void *arg)
+{
+	switch (pr) {
+		case (MDL_ASSIGN):
+			FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
+			break;
+		case (MDL_REMOVE):
+			FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
+			break;
+	}
+}
+
+void
+releasestack_isdnl2(struct PStack *st)
+{
+	FsmDelTimer(&st->l2.t200_timer, 15);
+	FsmDelTimer(&st->l2.t203_timer, 16);
+	discard_i_queue(st);
+	ReleaseWin(&st->l2);
+}
+
+static void
+l2m_debug(struct FsmInst *fi, char *s)
+{
+	struct PStack *st = fi->userdata;
+	char tm[32], str[256];
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
+	HiSax_putstatus(st->l1.hardware, str);
+}
+
+void
+setstack_isdnl2(struct PStack *st, char *debug_id)
+{
+	st->l1.l1l2 = isdnl2_l1l2;
+	st->l3.l3l2 = isdnl2_l3l2;
+	st->ma.manl2 = isdnl2_manl2;
+	st->ma.teil2 = isdnl2_teil2;
+
+	st->l2.uihsize = l2headersize(&st->l2, !0);
+	st->l2.ihsize = l2headersize(&st->l2, 0);
+	skb_queue_head_init(&st->l2.i_queue);
+	InitWin(&st->l2);
+	st->l2.rejexp = 0;
+	st->l2.debug = 0;
+
+	st->l2.l2m.fsm = &l2fsm;
+	st->l2.l2m.state = ST_L2_1;
+	st->l2.l2m.debug = 0;
+	st->l2.l2m.userdata = st;
+	st->l2.l2m.userint = 0;
+	st->l2.l2m.printdebug = l2m_debug;
+	strcpy(st->l2.debug_id, debug_id);
+
+	FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
+	FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
+	st->l2.t200_running = 0;
+}
+
+void
+setstack_transl2(struct PStack *st)
+{
+}
+
+void
+releasestack_transl2(struct PStack *st)
+{
+}
+
+void
+Isdnl2New(void)
+{
+	l2fsm.state_count = L2_STATE_COUNT;
+	l2fsm.event_count = L2_EVENT_COUNT;
+	l2fsm.strEvent = strL2Event;
+	l2fsm.strState = strL2State;
+	FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+}
+
+void
+Isdnl2Free(void)
+{
+	FsmFree(&l2fsm);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl2.h linux-2.0.31-pre3/drivers/isdn/hisax/isdnl2.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl2.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl2.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,18 @@
+/* isdnl2.h */
+
+#define RR     0x01
+#define RNR    0x05
+#define REJ    0x09
+#define SABME  0x6f
+#define SABM   0x2f
+#define DM     0x0f
+#define UI     0x03
+#define DISC   0x43
+#define UA     0x63
+#define FRMR   0x87
+#define XID    0xaf
+
+#define CMD    0
+#define RSP    1
+
+#define LC_FLUSH_WAIT 1
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl3.c linux-2.0.31-pre3/drivers/isdn/hisax/isdnl3.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl3.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl3.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,201 @@
+/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: isdnl3.c,v $
+ * Revision 1.10  1997/04/06 22:54:16  keil
+ * Using SKB's
+ *
+ * Revision 1.9  1997/03/25 23:11:25  keil
+ * US NI-1 protocol
+ *
+ * Revision 1.8  1997/03/21 18:53:44  keil
+ * Report no protocol error to syslog too
+ *
+ * Revision 1.7  1997/03/17 18:34:38  keil
+ * fixed oops if no protocol selected during config
+ *
+ * Revision 1.6  1997/02/16 01:04:08  fritz
+ * Bugfix: Changed timer handling caused hang with 2.1.X
+ *
+ * Revision 1.5  1997/02/09 00:26:27  keil
+ * new interface handling, one interface per card
+ * leased line changes
+ *
+ * Revision 1.4  1997/01/27 23:17:44  keil
+ * delete timers while unloading
+ *
+ * Revision 1.3  1997/01/21 22:31:12  keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.2  1996/11/05 19:42:04  keil
+ * using config.h
+ *
+ * Revision 1.1  1996/10/13 20:04:54  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include <linux/config.h>
+
+const char *l3_revision = "$Revision: 1.10 $";
+
+void
+l3_debug(struct PStack *st, char *s)
+{
+	char str[256], tm[32];
+
+	jiftime(tm, jiffies);
+	sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
+	HiSax_putstatus(st->l1.hardware, str);
+}
+
+
+
+void
+newl3state(struct PStack *st, int state)
+{
+	char tmp[80];
+
+	if (st->l3.debug & L3_DEB_STATE) {
+		sprintf(tmp, "newstate  %d --> %d", st->l3.state, state);
+		l3_debug(st, tmp);
+	}
+	st->l3.state = state;
+}
+
+static void
+L3ExpireTimer(struct L3Timer *t)
+{
+	t->st->l4.l4l3(t->st, t->event, NULL);
+}
+
+void
+L3InitTimer(struct PStack *st, struct L3Timer *t)
+{
+	t->st = st;
+	t->tl.function = (void *) L3ExpireTimer;
+	t->tl.data = (long) t;
+	init_timer(&t->tl);
+}
+
+void
+L3DelTimer(struct L3Timer *t)
+{
+	del_timer(&t->tl);
+}
+
+int
+L3AddTimer(struct L3Timer *t,
+	   int millisec, int event)
+{
+	if (t->tl.next || t->tl.prev) {
+		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
+		return -1;
+	}
+	init_timer(&t->tl);
+	t->event = event;
+	t->tl.expires = jiffies + (millisec * HZ) / 1000;
+	add_timer(&t->tl);
+	return 0;
+}
+
+void
+StopAllL3Timer(struct PStack *st)
+{
+	L3DelTimer(&st->l3.timer);
+}
+
+struct sk_buff *
+l3_alloc_skb(int len)
+{
+	struct sk_buff *skb;
+
+	if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
+		printk(KERN_WARNING "HiSax: No skb for D-channel\n");
+		return (NULL);
+	}
+	SET_SKB_FREE(skb);
+	skb_reserve(skb, MAX_HEADER_LEN);
+	return (skb);
+}
+
+static void
+no_l3_proto(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	l3_debug(st, "no protocol");
+	if (skb)
+		dev_kfree_skb(skb, FREE_READ);
+}
+
+#ifdef	CONFIG_HISAX_EURO
+extern void setstack_dss1(struct PStack *st);
+#endif
+
+#ifdef        CONFIG_HISAX_NI1
+extern void setstack_ni1(struct PStack *st);
+#endif
+
+#ifdef	CONFIG_HISAX_1TR6
+extern void setstack_1tr6(struct PStack *st);
+#endif
+
+void
+setstack_isdnl3(struct PStack *st, struct Channel *chanp)
+{
+	char tmp[64];
+
+	st->l3.debug = L3_DEB_WARN;
+	st->l3.channr = chanp->chan;
+	L3InitTimer(st, &st->l3.timer);
+
+#ifdef	CONFIG_HISAX_EURO
+	if (st->protocol == ISDN_PTYPE_EURO) {
+		setstack_dss1(st);
+	} else
+#endif
+#ifdef        CONFIG_HISAX_NI1
+	if (st->protocol == ISDN_PTYPE_NI1) {
+		setstack_ni1(st);
+	} else
+#endif
+#ifdef	CONFIG_HISAX_1TR6
+	if (st->protocol == ISDN_PTYPE_1TR6) {
+		setstack_1tr6(st);
+	} else
+#endif
+	if (st->protocol == ISDN_PTYPE_LEASED) {
+		st->l4.l4l3 = no_l3_proto;
+		st->l2.l2l3 = no_l3_proto;
+		printk(KERN_NOTICE "HiSax: Leased line mode\n");
+	} else {
+		st->l4.l4l3 = no_l3_proto;
+		st->l2.l2l3 = no_l3_proto;
+		sprintf(tmp, "protocol %s not supported",
+			(st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
+			(st->protocol == ISDN_PTYPE_EURO) ? "euro" :
+			(st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
+			"unknown");
+		printk(KERN_WARNING "HiSax: %s\n", tmp);
+		l3_debug(st, tmp);
+		st->protocol = -1;
+	}
+	st->l3.state = 0;
+	st->l3.callref = 0;
+}
+
+void
+releasestack_isdnl3(struct PStack *st)
+{
+	StopAllL3Timer(st);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/isdnl3.h linux-2.0.31-pre3/drivers/isdn/hisax/isdnl3.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/isdnl3.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/isdnl3.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,38 @@
+/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $
+ *
+ * $Log: isdnl3.h,v $
+ * Revision 1.3  1997/04/06 22:54:17  keil
+ * Using SKB's
+ *
+ * Revision 1.2  1997/01/21 22:31:28  keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.1  1996/10/13 20:03:47  keil
+ * Initial revision
+ *
+ *
+ */
+
+#define SBIT(state) (1<<state)
+#define ALL_STATES  0x00ffffff
+
+#define	PROTO_DIS_EURO	0x08
+
+#define L3_DEB_WARN	0x01
+#define	L3_DEB_PROTERR	0x02
+#define	L3_DEB_STATE	0x04
+#define	L3_DEB_CHARGE	0x08
+
+struct stateentry {
+	int	state;
+	u_char	primitive;
+	void	(*rout) (struct PStack *, u_char, void *);
+};
+
+extern void l3_debug(struct PStack *st, char *s);
+extern void newl3state(struct PStack *st, int state);
+extern void L3InitTimer(struct PStack *st, struct L3Timer *t);
+extern void L3DelTimer(struct L3Timer *t);
+extern int  L3AddTimer(struct L3Timer *t, int millisec, int event);
+extern void StopAllL3Timer(struct PStack *st);
+extern struct sk_buff *l3_alloc_skb(int len);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/ix1_micro.c linux-2.0.31-pre3/drivers/isdn/hisax/ix1_micro.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/ix1_micro.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/ix1_micro.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,937 @@
+/* $Id: ix1_micro.c,v 1.3 1997/04/13 19:54:02 keil Exp $
+
+ * ix1_micro.c  low level stuff for ITK ix1-micro Rev.2 isdn cards
+ *              derived from the original file teles3.c from Karsten Keil
+ *
+ * Copyright (C) 1997 Klaus-Peter Nischke (ITK AG) (for the modifications to
+ *                                                  the original file teles.c)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *              Beat Doebeli
+ *
+ * $Log: ix1_micro.c,v $
+ * Revision 1.3  1997/04/13 19:54:02  keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.2  1997/04/06 22:54:21  keil
+ * Using SKB's
+ *
+ * Revision 1.1  1997/01/27 15:43:10  keil
+ * first version
+ *
+ *
+ */
+
+/*
+   For the modification done by the author the following terms and conditions
+   apply (GNU PUBLIC LICENSE)
+
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   You may contact Klaus-Peter Nischke by email: klaus@nischke.do.eunet.de
+   or by conventional mail:
+
+   Klaus-Peter Nischke
+   Deusener Str. 287
+   44369 Dortmund
+   Germany
+ */
+
+
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles3.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *ix1_revision = "$Revision: 1.3 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+#define SPECIAL_PORT_OFFSET 3
+
+#define ISAC_COMMAND_OFFSET 2
+#define ISAC_DATA_OFFSET 0
+#define HSCX_COMMAND_OFFSET 2
+#define HSCX_DATA_OFFSET 1
+
+#define ISAC_FIFOSIZE 16
+#define HSCX_FIFOSIZE 16
+
+#define TIMEOUT 50
+
+static inline u_char
+IsacReadReg(unsigned int adr, u_char off)
+{
+	byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
+	return bytein(adr + ISAC_DATA_OFFSET);
+}
+
+static inline void
+IsacWriteReg(unsigned int adr, u_char off, u_char data)
+{
+	byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
+	byteout(adr + ISAC_DATA_OFFSET, data);
+}
+
+#define HSCX_OFFSET(WhichHscx,offset) \
+( (WhichHscx) ? (offset+0x60) : (offset+0x20) )
+
+static inline u_char
+HscxReadReg(unsigned int adr, int WhichHscx, u_char off)
+{
+	byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
+	return bytein(adr + HSCX_DATA_OFFSET);
+}
+
+static inline void
+HscxWriteReg(unsigned int adr, int WhichHscx, u_char off, u_char data)
+{
+	byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
+	byteout(adr + HSCX_DATA_OFFSET, data);
+}
+
+
+static inline void
+IsacReadFifo(unsigned int adr, u_char * data, int size)
+{
+	byteout(adr + ISAC_COMMAND_OFFSET, 0);
+	while (size--)
+		*data++ = bytein(adr + ISAC_DATA_OFFSET);
+}
+
+static void
+IsacWriteFifo(unsigned int adr, u_char * data, int size)
+{
+	byteout(adr + ISAC_COMMAND_OFFSET, 0);
+	while (size--) {
+		byteout(adr + ISAC_DATA_OFFSET, *data);
+		data++;
+	}
+}
+
+static inline void
+HscxReadFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
+{
+	byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
+	while (size--)
+		*data++ = bytein(adr + HSCX_DATA_OFFSET);
+}
+
+static void
+HscxWriteFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
+{
+	byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
+	while (size--) {
+		byteout(adr + HSCX_DATA_OFFSET, *data);
+		data++;
+	}
+}
+
+static inline void
+waitforCEC(int adr, int WhichHscx)
+{
+	int to = TIMEOUT;
+
+	while ((HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "ix1-Micro: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int WhichHscx)
+{
+	int to = TIMEOUT;
+
+	while ((!(HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "ix1-Micro: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int WhichHscx, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr, WhichHscx);
+	HscxWriteReg(adr, WhichHscx, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+	printk(KERN_DEBUG "ISTA %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_EXIR));
+}
+
+void
+ix1micro_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", IsacReadReg(sp->isac, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", IsacReadReg(sp->isac, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", IsacReadReg(sp->isac, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *sp = hsp->sp;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvidx + count > HSCX_BUFMAX) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+		hsp->rcvidx = 0;
+		return;
+	}
+	ptr = hsp->rcvbuf + hsp->rcvidx;
+	hsp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	HscxReadFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState *sp = hsp->sp;
+	int more, count;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	if (!hsp->tx_skb)
+		return;
+	if (hsp->tx_skb->len <= 0)
+		return;
+
+	more = (hsp->mode == 1) ? 1 : 0;
+	if (hsp->tx_skb->len > 32) {
+		more = !0;
+		count = 32;
+	} else
+		count = hsp->tx_skb->len;
+
+	waitforXFW(sp->hscx[hsp->hscx], hsp->hscx);
+	save_flags(flags);
+	cli();
+	ptr = hsp->tx_skb->data;
+	skb_pull(hsp->tx_skb, count);
+	hsp->tx_cnt -= count;
+	hsp->count += count;
+	HscxWriteFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+	u_char r;
+	struct HscxState *hsp = sp->hs + hscx;
+	struct sk_buff *skb;
+	int count;
+	char tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode)
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+		} else {
+			count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			hscx_empty_fifo(hsp, count);
+			if ((count = hsp->rcvidx - 1) > 0) {
+				if (sp->debug & L1_DEB_HSCX_FIFO) {
+					sprintf(tmp, "HX Frame %d", count);
+					debugl1(sp, tmp);
+				}
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "IX1: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+					skb_queue_tail(&hsp->rqueue, skb);
+				}
+			}
+		}
+		hsp->rcvidx = 0;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		hscx_empty_fifo(hsp, 32);
+		if (hsp->mode == 1) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(32)))
+				printk(KERN_WARNING "IX1: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+				skb_queue_tail(&hsp->rqueue, skb);
+			}
+			hsp->rcvidx = 0;
+			hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (hsp->tx_skb)
+			if (hsp->tx_skb->len) {
+				hscx_fill_fifo(hsp);
+				return;
+			} else {
+				dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+				hsp->count = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->tx_skb = NULL;
+			}
+		if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+			hsp->count = 0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "isac_empty_fifo");
+
+	if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+		if (sp->debug & L1_DEB_WARN) {
+			char tmp[40];
+			sprintf(tmp, "isac_empty_fifo overrun %d",
+				sp->rcvidx + count);
+			debugl1(sp, tmp);
+		}
+		IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+		sp->rcvidx = 0;
+		return;
+	}
+	ptr = sp->rcvbuf + sp->rcvidx;
+	sp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	IsacReadFifo(sp->isac, ptr, count);
+	IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_fill_fifo");
+
+	if (!sp->tx_skb)
+		return;
+
+	count = sp->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = sp->tx_skb->data;
+	skb_pull(sp->tx_skb, count);
+	sp->tx_cnt += count;
+	IsacWriteFifo(sp->isac, ptr, count);
+	IsacWriteReg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+		debugl1(sp, tmp);
+	}
+	IsacWriteReg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+	u_char exval;
+	struct sk_buff *skb;
+	unsigned int count;
+	char tmp[32];
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+		debugl1(sp, tmp);
+	}
+	if (val & 0x80) {	/* RME */
+		exval = IsacReadReg(sp->isac, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC CRC error");
+			IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+		} else {
+			count = IsacReadReg(sp->isac, ISAC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			isac_empty_fifo(sp, count);
+			if ((count = sp->rcvidx) > 0) {
+				sp->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "IX1: D receive out of memory\n");
+				else {
+					SET_SKB_FREE(skb);
+					memcpy(skb_put(skb, count), sp->rcvbuf, count);
+					skb_queue_tail(&sp->rq, skb);
+				}
+			}
+		}
+		sp->rcvidx = 0;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		isac_empty_fifo(sp, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->tx_skb)
+			if (sp->tx_skb->len) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+				sp->tx_cnt = 0;
+				sp->tx_skb = NULL;
+			}
+		if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+			sp->tx_cnt = 0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (IsacReadReg(sp->isac, ISAC_CIX0) >> 2)
+		    & 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+			sprintf(tmp, "l1state %d", sp->ph_state);
+			debugl1(sp, tmp);
+		}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = IsacReadReg(sp->isac, ISAC_EXIR);
+		if (sp->debug & L1_DEB_WARN) {
+			sprintf(tmp, "ISAC EXIR %02x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+	u_char exval;
+	struct HscxState *hsp;
+	char tmp[32];
+
+
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+		exval = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+		exval = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0x04) {
+		exval = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	u_char val, stat = 0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+	if (!sp) {
+		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+		return;
+	}
+	val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+      Start_HSCX:
+	if (val) {
+		hscx_int_main(sp, val);
+		stat |= 1;
+	}
+	val = IsacReadReg(sp->isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val) {
+		isac_interrupt(sp, val);
+		stat |= 2;
+	}
+	val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX)
+			debugl1(sp, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = IsacReadReg(sp->isac, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	if (stat & 1) {
+		HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0xFF);
+		HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0xFF);
+		HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0x0);
+		HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		IsacWriteReg(sp->isac, ISAC_MASK, 0xFF);
+		IsacWriteReg(sp->isac, ISAC_MASK, 0x0);
+	}
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+	unsigned int adr = sp->isac;
+
+	/* 16.3 IOM 2 Mode */
+	IsacWriteReg(adr, ISAC_MASK, 0xff);
+	IsacWriteReg(adr, ISAC_ADF2, 0x80);
+	IsacWriteReg(adr, ISAC_SQXR, 0x2f);
+	IsacWriteReg(adr, ISAC_SPCR, 0x0);
+	IsacWriteReg(adr, ISAC_ADF1, 0x2);
+	IsacWriteReg(adr, ISAC_STCR, 0x70);
+	IsacWriteReg(adr, ISAC_MODE, 0xc9);
+	IsacWriteReg(adr, ISAC_TIMR, 0x0);
+	IsacWriteReg(adr, ISAC_ADF1, 0x0);
+	IsacWriteReg(adr, ISAC_CMDR, 0x41);
+	IsacWriteReg(adr, ISAC_CIX0, (1 << 2) | 3);
+	IsacWriteReg(adr, ISAC_MASK, 0xff);
+	IsacWriteReg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+			'A' + hscx, mode, ichan);
+		debugl1(sp, tmp);
+	}
+	hs->mode = mode;
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR1, 0x85);
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD1, 0xFF);
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD2, 0xFF);
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RAH2, 0xFF);
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XBCH, 0x0);
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RLCR, 0x0);
+
+	switch (mode) {
+		case 0:
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0xff);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0xff);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x84);
+			break;
+		case 1:
+			if (ichan == 0) {
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+			} else {
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+			}
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0xe4);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
+			break;
+		case 2:
+			if (ichan == 0) {
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+			} else {
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+				HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+			}
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x8c);
+			HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
+			break;
+	}
+	HscxWriteReg(sp->hscx[hscx], hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_ix1micro(struct IsdnCard *card)
+{
+	if (card->sp->cfg_reg)
+		release_region(card->sp->cfg_reg, 4);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int val;
+	char tmp[64];
+
+	val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+	sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x02) {
+		val = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+	}
+	val = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
+	sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+	val = HscxReadReg(sp->hscx[1], 1, HSCX_STAR);
+	sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+	val = HscxReadReg(sp->hscx[0], 0, HSCX_STAR);
+	sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+	val = IsacReadReg(sp->isac, ISAC_STAR);
+	sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+	val = IsacReadReg(sp->isac, ISAC_MODE);
+	sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+	val = IsacReadReg(sp->isac, ISAC_ADF2);
+	sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+	val = IsacReadReg(sp->isac, ISAC_ISTA);
+	sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = IsacReadReg(sp->isac, ISAC_EXIR);
+		sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x04) {
+		val = IsacReadReg(sp->isac, ISAC_CIR0);
+		sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+	}
+	IsacWriteReg(sp->isac, ISAC_MASK, 0);
+	IsacWriteReg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initix1micro(struct IsdnCardState *sp)
+{
+	int ret;
+	int loop = 0;
+	char tmp[40];
+
+	sp->counter = kstat.interrupts[sp->irq];
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr, &ix1micro_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		while (loop++ < 10) {
+			/* At least 1-3 irqs must happen
+			 * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+			 */
+			if (kstat.interrupts[sp->irq] > sp->counter)
+				break;
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 1;
+			schedule();
+		}
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+		debugl1(sp, tmp);
+		if (kstat.interrupts[sp->irq] == sp->counter) {
+			printk(KERN_WARNING
+			       "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
+			       sp->irq);
+			irq2dev_map[sp->irq] = NULL;
+			free_irq(sp->irq, NULL);
+			return (0);
+		}
+	}
+	return (ret);
+}
+
+int
+setup_ix1micro(struct IsdnCard *card)
+{
+	u_char val, verA, verB;
+	struct IsdnCardState *sp = card->sp;
+	long flags;
+	char tmp[64];
+
+	strcpy(tmp, ix1_revision);
+	printk(KERN_NOTICE "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
+	if (sp->typ != ISDN_CTYPE_IX1MICROR2)
+		return (0);
+
+	/* IO-Ports */
+	sp->isac = sp->hscx[0] = sp->hscx[1] = sp->cfg_reg = card->para[1];
+	sp->irq = card->para[0];
+	if (sp->cfg_reg) {
+		if (check_region((sp->cfg_reg), 4)) {
+			printk(KERN_WARNING
+			  "HiSax: %s config port %x-%x already in use\n",
+			       CardType[card->typ],
+			       sp->cfg_reg,
+			       sp->cfg_reg + 4);
+			return (0);
+		} else
+			request_region(sp->cfg_reg, 4, "ix1micro cfg");
+	}
+	/* reset isac */
+	save_flags(flags);
+	val = 3 * (HZ / 10) + 1;
+	sti();
+	while (val--) {
+		byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 1);
+		HZDELAY(1);	/* wait >=10 ms */
+	}
+	byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 0);
+	restore_flags(flags);
+
+	printk(KERN_NOTICE
+	       "HiSax: %s config irq:%d io:0x%x\n",
+	       CardType[sp->typ], sp->irq,
+	       sp->cfg_reg);
+	verA = HscxReadReg(sp->hscx[0], 0, HSCX_VSTR) & 0xf;
+	verB = HscxReadReg(sp->hscx[1], 1, HSCX_VSTR) & 0xf;
+	printk(KERN_INFO "ix1-Micro: HSCX version A: %s  B: %s\n",
+	       HscxVersion(verA), HscxVersion(verB));
+	val = IsacReadReg(sp->isac, ISAC_RBCH);
+	printk(KERN_INFO "ix1-Micro: ISAC %s\n",
+	       ISACVersion(val));
+	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+		printk(KERN_WARNING
+		    "ix1-Micro: wrong HSCX versions check IO address\n");
+		release_io_ix1micro(card);
+		return (0);
+	}
+	sp->modehscx = &modehscx;
+	sp->ph_command = &ph_command;
+	sp->hscx_fill_fifo = &hscx_fill_fifo;
+	sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/ix1_micro.h linux-2.0.31-pre3/drivers/isdn/hisax/ix1_micro.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/ix1_micro.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/ix1_micro.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,50 @@
+/* $Id: ix1_micro.h,v 1.1 1997/01/27 15:42:48 keil Exp $
+
+ * ix1_micro.h  low level stuff for ITK ix1-micro Rev.2 isdn cards
+ *
+ *              derived from teles3.h from Karsten Keil
+ *
+ * Copyright (C) 1997 Klaus-Peter Nischke (ITK AG)   (for the modifications
+ to the original file teles.c)
+ *
+ * $Log: ix1_micro.h,v $
+ * Revision 1.1  1997/01/27 15:42:48  keil
+ * first version
+ *
+ *
+ */
+
+/*
+   For the modification done by the author the following terms and conditions
+   apply (GNU PUBLIC LICENSE)
+
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+   You may contact Klaus-Peter Nischke by email: klaus@nischke.do.eunet.de
+   or by conventional mail:
+
+   Klaus-Peter Nischke
+   Deusener Str. 287
+   44369 Dortmund
+   Germany
+ */
+
+
+extern void ix1micro_report(struct IsdnCardState *sp);
+extern void release_io_ix1micro(struct IsdnCard *card);
+extern int setup_ix1micro(struct IsdnCard *card);
+extern int initix1micro(struct IsdnCardState *sp);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/l3_1tr6.c linux-2.0.31-pre3/drivers/isdn/hisax/l3_1tr6.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/l3_1tr6.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/l3_1tr6.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,796 @@
+/* $Id: l3_1tr6.c,v 1.11 1997/04/06 22:54:18 keil Exp $
+
+ *  German 1TR6 D-channel protocol
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: l3_1tr6.c,v $
+ * Revision 1.11  1997/04/06 22:54:18  keil
+ * Using SKB's
+ *
+ * Revision 1.10  1997/03/13 20:37:58  keil
+ * channel request added
+ *
+ * Revision 1.9  1997/02/11 01:37:40  keil
+ * Changed setup-interface (incoming and outgoing)
+ *
+ * Revision 1.8  1997/01/27 23:20:21  keil
+ * report revision only ones
+ *
+ * Revision 1.7  1997/01/21 22:30:07  keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.6  1996/12/14 21:07:20  keil
+ * additional states for CC_REJECT
+ *
+ * Revision 1.5  1996/12/08 19:55:17  keil
+ * change CC_REJECT_REQ routine
+ *
+ * Revision 1.4  1996/10/30 10:18:01  keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.3  1996/10/27 22:15:37  keil
+ * bugfix reject handling
+ *
+ * Revision 1.2  1996/10/13 23:08:56  keil
+ * added missing state for callback reject
+ *
+ * Revision 1.1  1996/10/13 20:04:55  keil
+ * Initial revision
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+#include "isdnl3.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *l3_1tr6_revision = "$Revision: 1.11 $";
+
+#define MsgHead(ptr, cref, mty, dis) \
+	*ptr++ = dis; \
+	*ptr++ = 0x1; \
+	*ptr++ = cref; \
+	*ptr++ = mty
+
+static void
+l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
+{
+	struct sk_buff *skb;
+	u_char *p;
+
+	if (!(skb = l3_alloc_skb(4)))
+		return;
+	p = skb_put(skb, 4);
+	MsgHead(p, st->l3.callref, mt, pd);
+	st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[128];
+	u_char *p = tmp;
+	u_char *teln;
+	u_char *eaz;
+	u_char channel = 0;
+	int l;
+
+
+	st->l3.callref = st->pa->callref;
+	MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1);
+
+	teln = st->pa->setup.phone;
+	st->pa->spv = 0;
+	if (!isdigit(*teln)) {
+		switch (0x5f & *teln) {
+			case 'S':
+				st->pa->spv = 1;
+				break;
+			case 'C':
+				channel = 0x08;
+			case 'P':
+				channel |= 0x80;
+				teln++;
+				if (*teln == '1')
+					channel |= 0x01;
+				else
+					channel |= 0x02;
+				break;
+			default:
+				if (st->l3.debug & L3_DEB_WARN)
+					l3_debug(st, "Wrong MSN Code");
+				break;
+		}
+		teln++;
+	}
+	if (channel) {
+		*p++ = 0x18;	/* channel indicator */
+		*p++ = 1;
+		*p++ = channel;
+	}
+	if (st->pa->spv) {	/* SPV ? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->setup.si1;	/* 0 for all Services */
+		*p++ = st->pa->setup.si2;	/* 0 for all Services */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV (default) */
+		*p++ = st->pa->setup.si1;	/* 0 for all Services */
+		*p++ = st->pa->setup.si2;	/* 0 for all Services */
+	}
+	eaz = st->pa->setup.eazmsn;
+	if (*eaz) {
+		*p++ = WE0_origAddr;
+		*p++ = strlen(eaz) + 1;
+		/* Classify as AnyPref. */
+		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		while (*eaz)
+			*p++ = *eaz++ & 0x7f;
+	}
+	*p++ = WE0_destAddr;
+	*p++ = strlen(teln) + 1;
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+	while (*teln)
+		*p++ = *teln++ & 0x7f;
+
+	*p++ = WE_Shift_F6;
+	/* Codesatz 6 fuer Service */
+	*p++ = WE6_serviceInd;
+	*p++ = 2;		/* len=2 info,info2 */
+	*p++ = st->pa->setup.si1;
+	*p++ = st->pa->setup.si2;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	L3DelTimer(&st->l3.timer);
+	L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
+	newl3state(st, 1);
+	st->l3.l3l2(st, DL_DATA, skb);
+
+}
+
+static void
+l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	int bcfound = 0;
+	char tmp[80];
+	struct sk_buff *skb = arg;
+
+	p = skb->data;
+	st->pa->callref = getcallref(p);
+	st->l3.callref = 0x80 + st->pa->callref;
+
+	/* Channel Identification */
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		bcfound++;
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup without bchannel");
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
+		st->pa->setup.si1 = p[2];
+		st->pa->setup.si2 = p[3];
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup without service indicator");
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_destAddr, 0)))
+		iecpy(st->pa->setup.eazmsn, p, 1);
+	else
+		st->pa->setup.eazmsn[0] = 0;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
+		iecpy(st->pa->setup.phone, p, 1);
+	} else
+		st->pa->setup.phone[0] = 0;
+
+	p = skb->data;
+	st->pa->spv = 0;
+	if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
+		if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
+			st->pa->spv = 1;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	/* Signal all services, linklevel takes care of Service-Indicator */
+	if (bcfound) {
+		if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+			sprintf(tmp, "non-digital call: %s -> %s",
+				st->pa->setup.phone,
+				st->pa->setup.eazmsn);
+			l3_debug(st, tmp);
+		}
+		newl3state(st, 6);
+		st->l3.l3l4(st, CC_SETUP_IND, NULL);
+	}
+}
+
+static void
+l3_1tr6_setup_ack(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+
+	L3DelTimer(&st->l3.timer);
+	p = skb->data;
+	newl3state(st, 2);
+	if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup answer without bchannel");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
+	st->l3.l3l4(st, CC_MORE_INFO, NULL);
+}
+
+static void
+l3_1tr6_call_sent(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+
+	L3DelTimer(&st->l3.timer);
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup answer without bchannel");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
+	newl3state(st, 3);
+	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3_1tr6_alert(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	L3DelTimer(&st->l3.timer);	/* T304 */
+	newl3state(st, 4);
+	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	int i, tmpcharge = 0;
+	char a_charge[8], tmp[32];
+	struct sk_buff *skb = arg;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
+		iecpy(a_charge, p, 1);
+		for (i = 0; i < strlen(a_charge); i++) {
+			tmpcharge *= 10;
+			tmpcharge += a_charge[i] & 0xf;
+		}
+		if (tmpcharge > st->pa->chargeinfo) {
+			st->pa->chargeinfo = tmpcharge;
+			st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+		}
+		if (st->l3.debug & L3_DEB_CHARGE) {
+			sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+			l3_debug(st, tmp);
+		}
+	} else if (st->l3.debug & L3_DEB_CHARGE)
+		l3_debug(st, "charging info not found");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+}
+
+static void
+l3_1tr6_info_s2(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+}
+
+static void
+l3_1tr6_connect(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	L3DelTimer(&st->l3.timer);	/* T310 */
+	newl3state(st, 10);
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	st->pa->chargeinfo = 0;
+	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+}
+
+static void
+l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	u_char *p;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_cause, 0))) {
+		if (p[1] > 0) {
+			st->pa->cause = p[2];
+			if (p[1] > 1)
+				st->pa->loc = p[3];
+			else
+				st->pa->loc = 0;
+		} else {
+			st->pa->cause = 0;
+			st->pa->loc = 0;
+		}
+	} else
+		st->pa->cause = -1;
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	StopAllL3Timer(st);
+	newl3state(st, 0);
+	l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3_1tr6_rel_ack(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	StopAllL3Timer(st);
+	newl3state(st, 0);
+	st->pa->cause = -1;
+	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	u_char *p;
+	int i, tmpcharge = 0;
+	char a_charge[8], tmp[32];
+
+	StopAllL3Timer(st);
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
+		iecpy(a_charge, p, 1);
+		for (i = 0; i < strlen(a_charge); i++) {
+			tmpcharge *= 10;
+			tmpcharge += a_charge[i] & 0xf;
+		}
+		if (tmpcharge > st->pa->chargeinfo) {
+			st->pa->chargeinfo = tmpcharge;
+			st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+		}
+		if (st->l3.debug & L3_DEB_CHARGE) {
+			sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+			l3_debug(st, tmp);
+		}
+	} else if (st->l3.debug & L3_DEB_CHARGE)
+		l3_debug(st, "charging info not found");
+
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, WE0_cause, 0))) {
+		if (p[1] > 0) {
+			st->pa->cause = p[2];
+			if (p[1] > 1)
+				st->pa->loc = p[3];
+			else
+				st->pa->loc = 0;
+		} else {
+			st->pa->cause = 0;
+			st->pa->loc = 0;
+		}
+	} else {
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "cause not found");
+		st->pa->cause = -1;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 12);
+	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+
+static void
+l3_1tr6_connect_ack(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 10);
+	st->pa->chargeinfo = 0;
+	L3DelTimer(&st->l3.timer);
+	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+}
+
+static void
+l3_1tr6_alert_req(struct PStack *st, u_char pr, void *arg)
+{
+	newl3state(st, 7);
+	l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
+}
+
+static void
+l3_1tr6_setup_rsp(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[24];
+	u_char *p = tmp;
+	int l;
+
+	MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1);
+	if (st->pa->spv) {	/* SPV ? */
+		/* NSF SPV */
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_SPV;	/* SPV */
+		*p++ = st->pa->setup.si1;
+		*p++ = st->pa->setup.si2;
+		*p++ = WE0_netSpecFac;
+		*p++ = 4;	/* Laenge */
+		*p++ = 0;
+		*p++ = FAC_Activate;	/* aktiviere SPV */
+		*p++ = st->pa->setup.si1;
+		*p++ = st->pa->setup.si2;
+	}
+	newl3state(st, 8);
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	st->l3.l3l2(st, DL_DATA, skb);
+	L3DelTimer(&st->l3.timer);
+	L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+}
+
+static void
+l3_1tr6_reset(struct PStack *st, u_char pr, void *arg)
+{
+	newl3state(st, 0);
+}
+
+static void
+l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 0x10;
+	u_char clen = 1;
+
+	if (st->pa->cause > 0)
+		cause = st->pa->cause;
+	/* Map DSS1 causes */
+	switch (cause & 0x7f) {
+		case 0x10:
+			clen = 0;
+			break;
+		case 0x15:
+			cause = CAUSE_CallRejected;
+			break;
+	}
+	StopAllL3Timer(st);
+	MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
+	*p++ = WE0_cause;
+	*p++ = clen;		/* Laenge */
+	if (clen)
+		*p++ = cause | 0x80;
+	newl3state(st, 11);
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	st->l3.l3l2(st, DL_DATA, skb);
+	L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+}
+
+static void
+l3_1tr6_release_req(struct PStack *st, u_char pr, void *arg)
+{
+	StopAllL3Timer(st);
+	newl3state(st, 19);
+	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3_1tr6_t303(struct PStack *st, u_char pr, void *arg)
+{
+	if (st->l3.n_t303 > 0) {
+		st->l3.n_t303--;
+		L3DelTimer(&st->l3.timer);
+		l3_1tr6_setup_req(st, pr, arg);
+	} else {
+		L3DelTimer(&st->l3.timer);
+		st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
+		st->l3.n_t303 = 1;
+		newl3state(st, 0);
+	}
+}
+
+static void
+l3_1tr6_t304(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3_1tr6_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+
+}
+
+static void
+l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 0x90;
+	u_char clen = 1;
+
+	L3DelTimer(&st->l3.timer);
+	if (st->pa->cause > 0)
+		cause = st->pa->cause;
+	/* Map DSS1 causes */
+	switch (cause & 0x7f) {
+		case 0x10:
+			clen = 0;
+			break;
+		case 0x15:
+			cause = CAUSE_CallRejected;
+			break;
+	}
+	MsgHead(p, st->l3.callref, MT_N1_REL, PROTO_DIS_N1);
+	*p++ = WE0_cause;
+	*p++ = clen;		/* Laenge */
+	if (clen)
+		*p++ = cause;
+	newl3state(st, 19);
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	st->l3.l3l2(st, DL_DATA, skb);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3_1tr6_t310(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3_1tr6_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3_1tr6_t313(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3_1tr6_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3_1tr6_t308_1(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
+	newl3state(st, 19);
+}
+
+static void
+l3_1tr6_t308_2(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+	newl3state(st, 0);
+}
+/* *INDENT-OFF* */
+static struct stateentry downstl[] =
+{
+	{SBIT(0),
+	 CC_SETUP_REQ, l3_1tr6_setup_req},
+   	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
+    	 SBIT(10),
+    	 CC_DISCONNECT_REQ, l3_1tr6_disconnect_req},
+	{SBIT(12),
+	 CC_RELEASE_REQ, l3_1tr6_release_req},
+	{ALL_STATES,
+	 CC_DLRL, l3_1tr6_reset},
+	{SBIT(6),
+	 CC_IGNORE, l3_1tr6_reset},
+	{SBIT(6),
+	 CC_REJECT_REQ, l3_1tr6_disconnect_req},
+	{SBIT(6),
+	 CC_ALERTING_REQ, l3_1tr6_alert_req},
+	{SBIT(6) | SBIT(7),
+	 CC_SETUP_RSP, l3_1tr6_setup_rsp},
+	{SBIT(1),
+	 CC_T303, l3_1tr6_t303},
+	{SBIT(2),
+	 CC_T304, l3_1tr6_t304},
+	{SBIT(3),
+	 CC_T310, l3_1tr6_t310},
+	{SBIT(8),
+	 CC_T313, l3_1tr6_t313},
+	{SBIT(11),
+	 CC_T305, l3_1tr6_t305},
+	{SBIT(19),
+	 CC_T308_1, l3_1tr6_t308_1},
+	{SBIT(19),
+	 CC_T308_2, l3_1tr6_t308_2},
+};
+
+static int downstl_len = sizeof(downstl) /
+sizeof(struct stateentry);
+
+static struct stateentry datastln1[] =
+{
+	{SBIT(0),
+	 MT_N1_SETUP, l3_1tr6_setup},
+	{SBIT(1),
+	 MT_N1_SETUP_ACK, l3_1tr6_setup_ack},
+	{SBIT(1) | SBIT(2),
+	 MT_N1_CALL_SENT, l3_1tr6_call_sent},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+	 MT_N1_DISC, l3_1tr6_disc},
+	{SBIT(2) | SBIT(3) | SBIT(4),
+	 MT_N1_ALERT, l3_1tr6_alert},
+	{SBIT(2) | SBIT(3) | SBIT(4),
+	 MT_N1_CONN, l3_1tr6_connect},
+	{SBIT(2),
+	 MT_N1_INFO, l3_1tr6_info_s2},
+	{SBIT(8),
+	 MT_N1_CONN_ACK, l3_1tr6_connect_ack},
+	{SBIT(10),
+	 MT_N1_INFO, l3_1tr6_info},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
+	 SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+	 MT_N1_REL, l3_1tr6_rel},
+	{SBIT(19),
+	 MT_N1_REL_ACK, l3_1tr6_rel_ack}
+};
+/* *INDENT-ON* */
+
+
+
+static int datastln1_len = sizeof(datastln1) /
+sizeof(struct stateentry);
+
+static void
+up1tr6(struct PStack *st, int pr, void *arg)
+{
+	int i, mt;
+	struct sk_buff *skb = arg;
+	char tmp[80];
+
+	if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
+		if (st->l3.debug & L3_DEB_PROTERR) {
+			sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld state %d",
+				(pr == DL_DATA) ? " " : "(broadcast) ",
+				skb->data[0], skb->len, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+		return;
+	}
+	mt = skb->data[skb->data[1] + 2];
+	if (skb->data[0] == PROTO_DIS_N0) {
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled",
+				(pr == DL_DATA) ? " " : "(broadcast) ",
+				st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+	} else if (skb->data[0] == PROTO_DIS_N1) {
+		for (i = 0; i < datastln1_len; i++)
+			if ((mt == datastln1[i].primitive) &&
+			    ((1 << st->l3.state) & datastln1[i].state))
+				break;
+		if (i == datastln1_len) {
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb, FREE_READ);
+			if (st->l3.debug & L3_DEB_STATE) {
+				sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
+				  (pr == DL_DATA) ? " " : "(broadcast) ",
+					st->l3.state, mt);
+				l3_debug(st, tmp);
+			}
+			return;
+		} else {
+			if (st->l3.debug & L3_DEB_STATE) {
+				sprintf(tmp, "up1tr6%sstate %d mt %x",
+				  (pr == DL_DATA) ? " " : "(broadcast) ",
+					st->l3.state, mt);
+				l3_debug(st, tmp);
+			}
+			datastln1[i].rout(st, pr, skb);
+		}
+	}
+}
+
+static void
+down1tr6(struct PStack *st, int pr, void *arg)
+{
+	int i;
+	char tmp[80];
+
+	for (i = 0; i < downstl_len; i++)
+		if ((pr == downstl[i].primitive) &&
+		    ((1 << st->l3.state) & downstl[i].state))
+			break;
+	if (i == downstl_len) {
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "down1tr6 state %d prim %d unhandled",
+				st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "down1tr6 state %d prim %d",
+				st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+		downstl[i].rout(st, pr, arg);
+	}
+}
+
+void
+setstack_1tr6(struct PStack *st)
+{
+	char tmp[64];
+
+	st->l4.l4l3 = down1tr6;
+	st->l2.l2l3 = up1tr6;
+	st->l3.t303 = 4000;
+	st->l3.t304 = 20000;
+	st->l3.t305 = 4000;
+	st->l3.t308 = 4000;
+	st->l3.t310 = 120000;
+	st->l3.t313 = 4000;
+	st->l3.t318 = 4000;
+	st->l3.t319 = 4000;
+	st->l3.n_t303 = 0;
+
+	if (st->l3.channr & 1) {
+		strcpy(tmp, l3_1tr6_revision);
+		printk(KERN_NOTICE "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
+	}
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/l3_1tr6.h linux-2.0.31-pre3/drivers/isdn/hisax/l3_1tr6.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/l3_1tr6.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/l3_1tr6.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,160 @@
+/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+ *
+ *  German 1TR6 D-channel protocol defines
+ *
+ * $Log: l3_1tr6.h,v $
+ * Revision 1.1  1996/10/13 20:03:48  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#ifndef l3_1tr6
+#define l3_1tr6
+
+#define PROTO_DIS_N0 0x40
+#define PROTO_DIS_N1 0x41
+
+/*
+ * MsgType N0
+ */
+#define MT_N0_REG_IND 0x61
+#define MT_N0_CANC_IND 0x62
+#define MT_N0_FAC_STA 0x63
+#define MT_N0_STA_ACK 0x64
+#define MT_N0_STA_REJ 0x65
+#define MT_N0_FAC_INF 0x66
+#define MT_N0_INF_ACK 0x67
+#define MT_N0_INF_REJ 0x68
+#define MT_N0_CLOSE   0x75
+#define MT_N0_CLO_ACK 0x77
+
+
+/*
+ * MsgType N1
+ */
+
+#define MT_N1_ESC 0x00
+#define MT_N1_ALERT 0x01
+#define MT_N1_CALL_SENT 0x02
+#define MT_N1_CONN 0x07
+#define MT_N1_CONN_ACK 0x0F
+#define MT_N1_SETUP 0x05
+#define MT_N1_SETUP_ACK 0x0D
+#define MT_N1_RES 0x26
+#define MT_N1_RES_ACK 0x2E
+#define MT_N1_RES_REJ 0x22
+#define MT_N1_SUSP 0x25
+#define MT_N1_SUSP_ACK 0x2D
+#define MT_N1_SUSP_REJ 0x21
+#define MT_N1_USER_INFO 0x20
+#define MT_N1_DET 0x40
+#define MT_N1_DISC 0x45
+#define MT_N1_REL 0x4D
+#define MT_N1_REL_ACK 0x5A
+#define MT_N1_CANC_ACK 0x6E
+#define MT_N1_CANC_REJ 0x67
+#define MT_N1_CON_CON 0x69
+#define MT_N1_FAC 0x60
+#define MT_N1_FAC_ACK 0x68
+#define MT_N1_FAC_CAN 0x66
+#define MT_N1_FAC_REG 0x64
+#define MT_N1_FAC_REJ 0x65
+#define MT_N1_INFO 0x6D
+#define MT_N1_REG_ACK 0x6C
+#define MT_N1_REG_REJ 0x6F
+#define MT_N1_STAT 0x63
+
+
+
+/*
+ * W Elemente
+ */
+
+#define WE_Shift_F0 0x90
+#define WE_Shift_F6 0x96
+#define WE_Shift_OF0 0x98
+#define WE_Shift_OF6 0x9E
+
+#define WE0_cause 0x08
+#define WE0_connAddr 0x0C
+#define WE0_callID 0x10
+#define WE0_chanID 0x18
+#define WE0_netSpecFac 0x20
+#define WE0_display 0x28
+#define WE0_keypad 0x2C
+#define WE0_origAddr 0x6C
+#define WE0_destAddr 0x70
+#define WE0_userInfo 0x7E
+
+#define WE0_moreData 0xA0
+#define WE0_congestLevel 0xB0
+
+#define WE6_serviceInd 0x01
+#define WE6_chargingInfo 0x02
+#define WE6_date 0x03
+#define WE6_facSelect 0x05
+#define WE6_facStatus 0x06
+#define WE6_statusCalled 0x07
+#define WE6_addTransAttr 0x08
+
+/*
+ * FacCodes
+ */
+#define FAC_Sperre 0x01
+#define FAC_Sperre_All 0x02
+#define FAC_Sperre_Fern 0x03
+#define FAC_Sperre_Intl 0x04
+#define FAC_Sperre_Interk 0x05
+
+#define FAC_Forward1 0x02
+#define FAC_Forward2 0x03
+#define FAC_Konferenz 0x06
+#define FAC_GrabBchan 0x0F
+#define FAC_Reactivate 0x10
+#define FAC_Konferenz3 0x11
+#define FAC_Dienstwechsel1 0x12
+#define FAC_Dienstwechsel2 0x13
+#define FAC_NummernIdent 0x14
+#define FAC_GBG 0x15
+#define FAC_DisplayUebergeben 0x17
+#define FAC_DisplayUmgeleitet 0x1A
+#define FAC_Unterdruecke 0x1B
+#define FAC_Deactivate 0x1E
+#define FAC_Activate 0x1D
+#define FAC_SPV 0x1F
+#define FAC_Rueckwechsel 0x23
+#define FAC_Umleitung 0x24
+
+/*
+ * Cause codes
+ */
+#define CAUSE_InvCRef 0x01
+#define CAUSE_BearerNotImpl 0x03
+#define CAUSE_CIDunknown 0x07
+#define CAUSE_CIDinUse 0x08
+#define CAUSE_NoChans 0x0A
+#define CAUSE_FacNotImpl 0x10
+#define CAUSE_FacNotSubscr 0x11
+#define CAUSE_OutgoingBarred 0x20
+#define CAUSE_UserAccessBusy 0x21
+#define CAUSE_NegativeGBG 0x22
+#define CAUSE_UnknownGBG 0x23
+#define CAUSE_NoSPVknown 0x25
+#define CAUSE_DestNotObtain 0x35
+#define CAUSE_NumberChanged 0x38
+#define CAUSE_OutOfOrder 0x39
+#define CAUSE_NoUserResponse 0x3A
+#define CAUSE_UserBusy 0x3B
+#define CAUSE_IncomingBarred 0x3D
+#define CAUSE_CallRejected 0x3E
+#define CAUSE_NetworkCongestion 0x59
+#define CAUSE_RemoteUser 0x5A
+#define CAUSE_LocalProcErr 0x70
+#define CAUSE_RemoteProcErr 0x71
+#define CAUSE_RemoteUserSuspend 0x72
+#define CAUSE_RemoteUserResumed 0x73
+#define CAUSE_UserInfoDiscarded 0x7F
+
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/l3dss1.c linux-2.0.31-pre3/drivers/isdn/hisax/l3dss1.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/l3dss1.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/l3dss1.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,809 @@
+/* $Id: l3dss1.c,v 1.16 1997/06/03 20:43:46 keil Exp $
+
+ * EURO/DSS1 D-channel protocol
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: l3dss1.c,v $
+ * Revision 1.16  1997/06/03 20:43:46  keil
+ * Display numbers as default
+ *
+ * Revision 1.15  1997/04/17 11:50:48  keil
+ * pa->loc was undefined, if it was not send by the exchange
+ *
+ * Revision 1.14  1997/04/06 22:54:20  keil
+ * Using SKB's
+ *
+ * Revision 1.13  1997/03/13 20:37:28  keil
+ * CLIR and channel request added
+ *
+ * Revision 1.12  1997/02/17 00:34:26  keil
+ * Bugfix: Wrong cause delivered
+ *
+ * Revision 1.11  1997/02/16 12:12:47  fritz
+ * Bugfix: SI2 was nont initialized on incoming calls.
+ *
+ * Revision 1.10  1997/02/11 01:37:24  keil
+ * Changed setup-interface (incoming and outgoing)
+ *
+ * Revision 1.9  1997/01/27 23:20:52  keil
+ * report revision only ones
+ *
+ * Revision 1.8  1997/01/21 22:29:41  keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.7  1996/12/14 21:06:59  keil
+ * additional states for CC_REJECT
+ *
+ * Revision 1.6  1996/12/08 22:59:16  keil
+ * fixed calling party number without octet 3a
+ *
+ * Revision 1.5  1996/12/08 19:53:31  keil
+ * fixes from Pekka Sarnila
+ *
+ * Revision 1.4  1996/11/05 19:44:36  keil
+ * some fixes from Henner Eisen
+ *
+ * Revision 1.3  1996/10/30 10:18:01  keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.2  1996/10/27 22:15:16  keil
+ * bugfix reject handling
+ *
+ * Revision 1.1  1996/10/13 20:04:55  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *dss1_revision = "$Revision: 1.16 $";
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	*ptr++ = 0x1; \
+	*ptr++ = cref; \
+	*ptr++ = mty
+
+static void
+l3dss1_message(struct PStack *st, u_char mt)
+{
+	struct sk_buff *skb;
+	u_char *p;
+
+	if (!(skb = l3_alloc_skb(4)))
+		return;
+	p = skb_put(skb, 4);
+	MsgHead(p, st->l3.callref, mt);
+	st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3dss1_release_req(struct PStack *st, u_char pr, void *arg)
+{
+	StopAllL3Timer(st);
+	newl3state(st, 19);
+	l3dss1_message(st, MT_RELEASE);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3dss1_release_cmpl(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+	int cause = -1;
+
+	p = skb->data;
+	st->pa->loc = 0;
+	if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+		p++;
+		if (*p++ == 2)
+			st->pa->loc = *p++;
+		cause = *p & 0x7f;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	StopAllL3Timer(st);
+	st->pa->cause = cause;
+	newl3state(st, 0);
+	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3dss1_setup_req(struct PStack *st, u_char pr,
+		 void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[128];
+	u_char *p = tmp;
+	u_char channel = 0;
+	u_char screen = 0x80;
+	u_char *teln;
+	u_char *msn;
+	int l;
+
+	st->l3.callref = st->pa->callref;
+	MsgHead(p, st->l3.callref, MT_SETUP);
+
+	/*
+	 * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
+	 */
+	*p++ = 0xa1;		/* complete indicator */
+	switch (st->pa->setup.si1) {
+		case 1:	/* Telephony                               */
+			*p++ = 0x4;	/* BC-IE-code                              */
+			*p++ = 0x3;	/* Length                                  */
+			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps                     */
+			*p++ = 0xa3;	/* A-Law Audio                             */
+			break;
+		case 5:	/* Datatransmission 64k, BTX               */
+		case 7:	/* Datatransmission 64k                    */
+		default:
+			*p++ = 0x4;	/* BC-IE-code                              */
+			*p++ = 0x2;	/* Length                                  */
+			*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
+			break;
+	}
+	/*
+	 * What about info2? Mapping to High-Layer-Compatibility?
+	 */
+	teln = st->pa->setup.phone;
+	if (*teln) {
+		/* parse number for special things */
+		if (!isdigit(*teln)) {
+			switch (0x5f & *teln) {
+				case 'C':
+					channel = 0x08;
+				case 'P':
+					channel |= 0x80;
+					teln++;
+					if (*teln == '1')
+						channel |= 0x01;
+					else
+						channel |= 0x02;
+					break;
+				case 'R':
+					screen = 0xA0;
+					break;
+				case 'D':
+					screen = 0x80;
+					break;
+				default:
+					if (st->l3.debug & L3_DEB_WARN)
+						l3_debug(st, "Wrong MSN Code");
+					break;
+			}
+			teln++;
+		}
+	}
+	if (channel) {
+		*p++ = 0x18;	/* channel indicator */
+		*p++ = 1;
+		*p++ = channel;
+	}
+	msn = st->pa->setup.eazmsn;
+	if (*msn) {
+		*p++ = 0x6c;
+		*p++ = strlen(msn) + (screen ? 2 : 1);
+		/* Classify as AnyPref. */
+		if (screen) {
+			*p++ = 0x01;	/* Ext = '0'B, Type = '000'B, Plan = '0001'B. */
+			*p++ = screen;
+		} else
+			*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		while (*msn)
+			*p++ = *msn++ & 0x7f;
+	}
+	*p++ = 0x70;
+	*p++ = strlen(teln) + 1;
+	/* Classify as AnyPref. */
+	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+
+	while (*teln)
+		*p++ = *teln++ & 0x7f;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	L3DelTimer(&st->l3.timer);
+	L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
+	newl3state(st, 1);
+	st->l3.l3l2(st, DL_DATA, skb);
+
+}
+
+static void
+l3dss1_call_proc(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+
+	L3DelTimer(&st->l3.timer);
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x18, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
+			l3_debug(st, "setup answer without bchannel");
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup answer without bchannel");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 3);
+	L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
+	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3dss1_setup_ack(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+
+	L3DelTimer(&st->l3.timer);
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x18, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
+			l3_debug(st, "setup answer without bchannel");
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup answer without bchannel");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 2);
+	L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
+	st->l3.l3l4(st, CC_MORE_INFO, NULL);
+}
+
+static void
+l3dss1_disconnect(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+	int cause = -1;
+
+	StopAllL3Timer(st);
+	p = skb->data;
+	st->pa->loc = 0;
+	if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+		p++;
+		if (*p++ == 2)
+			st->pa->loc = *p++;
+		cause = *p & 0x7f;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 12);
+	st->pa->cause = cause;
+	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+static void
+l3dss1_connect(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	L3DelTimer(&st->l3.timer);	/* T310 */
+	newl3state(st, 10);
+	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+}
+
+static void
+l3dss1_alerting(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	L3DelTimer(&st->l3.timer);	/* T304 */
+	newl3state(st, 4);
+	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3dss1_setup(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	int bcfound = 0;
+	char tmp[80];
+	struct sk_buff *skb = arg;
+
+	p = skb->data;
+	st->pa->callref = getcallref(p);
+	st->l3.callref = 0x80 + st->pa->callref;
+
+	/*
+	 * Channel Identification
+	 */
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x18, 0))) {
+		st->pa->bchannel = p[2] & 0x3;
+		if (st->pa->bchannel)
+			bcfound++;
+		else if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "setup without bchannel");
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup without bchannel");
+
+	/*
+	   * Bearer Capabilities
+	 */
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x04, 0))) {
+		st->pa->setup.si2 = 0;
+		switch (p[2] & 0x1f) {
+			case 0x00:
+				/* Speech */
+			case 0x10:
+				/* 3.1 Khz audio */
+				st->pa->setup.si1 = 1;
+				break;
+			case 0x08:
+				/* Unrestricted digital information */
+				st->pa->setup.si1 = 7;
+				break;
+			case 0x09:
+				/* Restricted digital information */
+				st->pa->setup.si1 = 2;
+				break;
+			case 0x11:
+				/* Unrestr. digital information  with tones/announcements */
+				st->pa->setup.si1 = 3;
+				break;
+			case 0x18:
+				/* Video */
+				st->pa->setup.si1 = 4;
+				break;
+			default:
+				st->pa->setup.si1 = 0;
+		}
+	} else if (st->l3.debug & L3_DEB_WARN)
+		l3_debug(st, "setup without bearer capabilities");
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x70, 0)))
+		iecpy(st->pa->setup.eazmsn, p, 1);
+	else
+		st->pa->setup.eazmsn[0] = 0;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x6c, 0))) {
+		st->pa->setup.plan = p[2];
+		if (p[2] & 0x80) {
+			iecpy(st->pa->setup.phone, p, 1);
+			st->pa->setup.screen = 0;
+		} else {
+			iecpy(st->pa->setup.phone, p, 2);
+			st->pa->setup.screen = p[3];
+		}
+	} else {
+		st->pa->setup.phone[0] = 0;
+		st->pa->setup.plan = 0;
+		st->pa->setup.screen = 0;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	if (bcfound) {
+		if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+			sprintf(tmp, "non-digital call: %s -> %s",
+				st->pa->setup.phone,
+				st->pa->setup.eazmsn);
+			l3_debug(st, tmp);
+		}
+		newl3state(st, 6);
+		st->l3.l3l4(st, CC_SETUP_IND, NULL);
+	}
+}
+
+static void
+l3dss1_reset(struct PStack *st, u_char pr, void *arg)
+{
+	StopAllL3Timer(st);
+	newl3state(st, 0);
+}
+
+static void
+l3dss1_setup_rsp(struct PStack *st, u_char pr,
+		 void *arg)
+{
+	newl3state(st, 8);
+	l3dss1_message(st, MT_CONNECT);
+	L3DelTimer(&st->l3.timer);
+	L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+}
+
+static void
+l3dss1_connect_ack(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	newl3state(st, 10);
+	L3DelTimer(&st->l3.timer);
+	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+}
+
+static void
+l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 0x10;
+
+	if (st->pa->cause > 0)
+		cause = st->pa->cause;
+
+	StopAllL3Timer(st);
+
+	MsgHead(p, st->l3.callref, MT_DISCONNECT);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause | 0x80;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(st, 11);
+	st->l3.l3l2(st, DL_DATA, skb);
+	L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+}
+
+static void
+l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 0x95;
+
+	if (st->pa->cause > 0)
+		cause = st->pa->cause;
+
+	MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(st, 0);
+	st->l3.l3l2(st, DL_DATA, skb);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3dss1_release(struct PStack *st, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+	int cause = -1;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+		p++;
+		if (*p++ == 2)
+			st->pa->loc = *p++;
+		cause = *p & 0x7f;
+	}
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+	StopAllL3Timer(st);
+	st->pa->cause = cause;
+	newl3state(st, 0);
+	l3dss1_message(st, MT_RELEASE_COMPLETE);
+	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3dss1_alert_req(struct PStack *st, u_char pr,
+		 void *arg)
+{
+	newl3state(st, 7);
+	l3dss1_message(st, MT_ALERTING);
+}
+
+static void
+l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
+{
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	struct sk_buff *skb = arg;
+
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb, FREE_READ);
+
+	MsgHead(p, st->l3.callref, MT_STATUS);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = 0x9E;		/* answer status enquire */
+
+	*p++ = 0x14;		/* CallState */
+	*p++ = 0x1;
+	*p++ = st->l3.state & 0x3f;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3dss1_t303(struct PStack *st, u_char pr, void *arg)
+{
+	if (st->l3.n_t303 > 0) {
+		st->l3.n_t303--;
+		L3DelTimer(&st->l3.timer);
+		l3dss1_setup_req(st, pr, arg);
+	} else {
+		newl3state(st, 0);
+		L3DelTimer(&st->l3.timer);
+		st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
+		st->l3.n_t303 = 1;
+	}
+}
+
+static void
+l3dss1_t304(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3dss1_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+
+}
+
+static void
+l3dss1_t305(struct PStack *st, u_char pr, void *arg)
+{
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	struct sk_buff *skb;
+	u_char cause = 0x90;
+
+	L3DelTimer(&st->l3.timer);
+	if (st->pa->cause > 0)
+		cause = st->pa->cause;
+
+	MsgHead(p, st->l3.callref, MT_RELEASE);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(st, 19);
+	st->l3.l3l2(st, DL_DATA, skb);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3dss1_t310(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3dss1_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3dss1_t313(struct PStack *st, u_char pr, void *arg)
+{
+	L3DelTimer(&st->l3.timer);
+	st->pa->cause = 0xE6;
+	l3dss1_disconnect_req(st, pr, NULL);
+	st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3dss1_t308_1(struct PStack *st, u_char pr, void *arg)
+{
+	newl3state(st, 19);
+	L3DelTimer(&st->l3.timer);
+	l3dss1_message(st, MT_RELEASE);
+	L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
+}
+
+static void
+l3dss1_t308_2(struct PStack *st, u_char pr, void *arg)
+{
+	newl3state(st, 0);
+	L3DelTimer(&st->l3.timer);
+	st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+}
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+	{SBIT(0),
+	 CC_SETUP_REQ, l3dss1_setup_req},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
+	 CC_DISCONNECT_REQ, l3dss1_disconnect_req},
+	{SBIT(12),
+	 CC_RELEASE_REQ, l3dss1_release_req},
+	{ALL_STATES,
+	 CC_DLRL, l3dss1_reset},
+	{SBIT(6),
+	 CC_IGNORE, l3dss1_reset},
+	{SBIT(6),
+	 CC_REJECT_REQ, l3dss1_reject_req},
+	{SBIT(6),
+	 CC_ALERTING_REQ, l3dss1_alert_req},
+	{SBIT(6) | SBIT(7),
+	 CC_SETUP_RSP, l3dss1_setup_rsp},
+	{SBIT(1),
+	 CC_T303, l3dss1_t303},
+	{SBIT(2),
+	 CC_T304, l3dss1_t304},
+	{SBIT(3),
+	 CC_T310, l3dss1_t310},
+	{SBIT(8),
+	 CC_T313, l3dss1_t313},
+	{SBIT(11),
+	 CC_T305, l3dss1_t305},
+	{SBIT(19),
+	 CC_T308_1, l3dss1_t308_1},
+	{SBIT(19),
+	 CC_T308_2, l3dss1_t308_2},
+};
+
+static int downsllen = sizeof(downstatelist) /
+sizeof(struct stateentry);
+
+static struct stateentry datastatelist[] =
+{
+	{ALL_STATES,
+	 MT_STATUS_ENQUIRY, l3dss1_status_enq},
+	{SBIT(0) | SBIT(6),
+	 MT_SETUP, l3dss1_setup},
+	{SBIT(1) | SBIT(2),
+	 MT_CALL_PROCEEDING, l3dss1_call_proc},
+	{SBIT(1),
+	 MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
+	{SBIT(1) | SBIT(2) | SBIT(3),
+	 MT_ALERTING, l3dss1_alerting},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+	 MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+	 MT_RELEASE, l3dss1_release},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+	 MT_DISCONNECT, l3dss1_disconnect},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
+	 MT_CONNECT, l3dss1_connect},
+	{SBIT(8),
+	 MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
+};
+/* *INDENT-ON* */
+
+
+static int datasllen = sizeof(datastatelist) /
+sizeof(struct stateentry);
+
+static void
+dss1up(struct PStack *st, int pr, void *arg)
+{
+	int i, mt;
+	struct sk_buff *skb = arg;
+	char tmp[80];
+
+	if (skb->data[0] != PROTO_DIS_EURO) {
+		if (st->l3.debug & L3_DEB_PROTERR) {
+			sprintf(tmp, "dss1up%sunexpected discriminator %x message len %ld state %d",
+				(pr == DL_DATA) ? " " : "(broadcast) ",
+				skb->data[0], skb->len, st->l3.state);
+			l3_debug(st, tmp);
+		}
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+		return;
+	}
+	mt = skb->data[skb->data[1] + 2];
+	for (i = 0; i < datasllen; i++)
+		if ((mt == datastatelist[i].primitive) &&
+		    ((1 << st->l3.state) & datastatelist[i].state))
+			break;
+	if (i == datasllen) {
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_READ);
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
+				(pr == DL_DATA) ? " " : "(broadcast) ",
+				st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+		return;
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "dss1up%sstate %d mt %x",
+				(pr == DL_DATA) ? " " : "(broadcast) ",
+				st->l3.state, mt);
+			l3_debug(st, tmp);
+		}
+		datastatelist[i].rout(st, pr, skb);
+	}
+}
+
+static void
+dss1down(struct PStack *st, int pr, void *arg)
+{
+	int i;
+	char tmp[80];
+
+	for (i = 0; i < downsllen; i++)
+		if ((pr == downstatelist[i].primitive) &&
+		    ((1 << st->l3.state) & downstatelist[i].state))
+			break;
+	if (i == downsllen) {
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "dss1down state %d prim %d unhandled",
+				st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			sprintf(tmp, "dss1down state %d prim %d",
+				st->l3.state, pr);
+			l3_debug(st, tmp);
+		}
+		downstatelist[i].rout(st, pr, arg);
+	}
+}
+
+void
+setstack_dss1(struct PStack *st)
+{
+	char tmp[64];
+
+	st->l4.l4l3 = dss1down;
+	st->l2.l2l3 = dss1up;
+	st->l3.t303 = 4000;
+	st->l3.t304 = 30000;
+	st->l3.t305 = 30000;
+	st->l3.t308 = 4000;
+	st->l3.t310 = 30000;
+	st->l3.t313 = 4000;
+	st->l3.t318 = 4000;
+	st->l3.t319 = 4000;
+	st->l3.n_t303 = 1;
+
+	if (st->l3.channr & 1) {
+		strcpy(tmp, dss1_revision);
+		printk(KERN_NOTICE "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
+	}
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/Makefile linux-2.0.31-pre3/drivers/isdn/hisax/Makefile
--- linux-2.0.31-pre2/drivers/isdn/hisax/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/Makefile	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,54 @@
+L_OBJS :=
+M_OBJS :=
+O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \
+          q931.o callc.o fsm.o
+
+# EXTRA_CFLAGS += -S
+
+ifeq ($(CONFIG_HISAX_EURO),y)
+	 O_OBJS += l3dss1.o
+endif
+
+ifeq ($(CONFIG_HISAX_NI1),y)
+       O_OBJS += l3ni1.o
+endif
+
+ifeq ($(CONFIG_HISAX_1TR6),y)
+	 O_OBJS += l3_1tr6.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_0),y)
+	 O_OBJS += teles0.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_3),y)
+	 O_OBJS += teles3.o
+endif
+
+ifeq ($(CONFIG_HISAX_AVM_A1),y)
+	 O_OBJS += avm_a1.o
+endif
+
+ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
+	 O_OBJS += elsa.o
+endif
+
+ifeq ($(CONFIG_HISAX_ELSA_PCMCIA),y)
+	 O_OBJS += elsa.o
+endif
+
+ifeq ($(CONFIG_HISAX_IX1MICROR2),y)
+	 O_OBJS += ix1_micro.o
+endif
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+  O_TARGET += hisax.o
+else
+  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+    O_TARGET += hisax.o
+    M_OBJS += hisax.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/q931.c linux-2.0.31-pre3/drivers/isdn/hisax/q931.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/q931.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/q931.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1218 @@
+/* $Id: q931.c,v 1.5 1997/04/06 22:56:43 keil Exp $
+
+ * q931.c       code to decode ITU Q.931 call control messages
+ *
+ * Author       Jan den Ouden
+ *
+ * Changelog
+ *
+ * Pauline Middelink    general improvements
+ *
+ * Beat Doebeli         cause texts, display information element
+ *
+ * Karsten Keil         cause texts, display information element for 1TR6
+ *
+ *
+ * $Log: q931.c,v $
+ * Revision 1.5  1997/04/06 22:56:43  keil
+ * Some cosmetic changes
+ *
+ * Revision 1.4  1997/02/09 00:29:11  keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.3  1997/01/21 22:24:59  keil
+ * cleanups
+ *
+ * Revision 1.2  1996/10/27 22:12:45  keil
+ * reporting unknown level 3 protocol ids
+ *
+ * Revision 1.1  1996/10/13 20:04:56  keil
+ * Initial revision
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+	int l, codeset, maincodeset;
+	u_char *pend = p + size;
+
+	/* skip protocol discriminator, callref and message type */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	p++;
+	codeset = 0;
+	maincodeset = 0;
+	/* while there are bytes left... */
+	while (p < pend) {
+		if ((*p & 0xf0) == 0x90) {
+			codeset = *p & 0x07;
+			if (!(*p & 0x08))
+				maincodeset = codeset;
+		}
+		if (*p & 0x80)
+			p++;
+		else {
+			if (codeset == wanted_set) {
+				if (*p == ie)
+					return (p);
+				if (*p > ie)
+					return (NULL);
+			}
+			p++;
+			l = *p++;
+			p += l;
+			codeset = maincodeset;
+		}
+	}
+	return (NULL);
+}
+
+void
+iecpy(u_char * dest, u_char * iestart, int ieoffset)
+{
+	u_char *p;
+	int l;
+
+	p = iestart + ieoffset + 2;
+	l = iestart[1] - ieoffset;
+	while (l--)
+		*dest++ = *p++;
+	*dest++ = '\0';
+}
+
+int
+getcallref(u_char * p)
+{
+	p++;			/* prot discr */
+	p++;			/* callref length */
+	return (*p);		/* assuming one-byte callref */
+}
+
+/*
+ * According to Table 4-2/Q.931
+ */
+static
+struct MessageType {
+	u_char nr;
+	char *descr;
+} mtlist[] = {
+
+	{
+		0x1, "ALERTING"
+	},
+	{
+		0x2, "CALL PROCEEDING"
+	},
+	{
+		0x7, "CONNECT"
+	},
+	{
+		0xf, "CONNECT ACKNOWLEDGE"
+	},
+	{
+		0x3, "PROGRESS"
+	},
+	{
+		0x5, "SETUP"
+	},
+	{
+		0xd, "SETUP ACKNOWLEDGE"
+	},
+	{
+		0x26, "RESUME"
+	},
+	{
+		0x2e, "RESUME ACKNOWLEDGE"
+	},
+	{
+		0x22, "RESUME REJECT"
+	},
+	{
+		0x25, "SUSPEND"
+	},
+	{
+		0x2d, "SUSPEND ACKNOWLEDGE"
+	},
+	{
+		0x21, "SUSPEND REJECT"
+	},
+	{
+		0x20, "USER INFORMATION"
+	},
+	{
+		0x45, "DISCONNECT"
+	},
+	{
+		0x4d, "RELEASE"
+	},
+	{
+		0x5a, "RELEASE COMPLETE"
+	},
+	{
+		0x46, "RESTART"
+	},
+	{
+		0x4e, "RESTART ACKNOWLEDGE"
+	},
+	{
+		0x60, "SEGMENT"
+	},
+	{
+		0x79, "CONGESTION CONTROL"
+	},
+	{
+		0x7b, "INFORMATION"
+	},
+	{
+		0x62, "FACILITY"
+	},
+	{
+		0x6e, "NOTIFY"
+	},
+	{
+		0x7d, "STATUS"
+	},
+	{
+		0x75, "STATUS ENQUIRY"
+	}
+};
+
+#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
+
+static
+struct MessageType mt_n0[] =
+{
+	{MT_N0_REG_IND, "REGister INDication"},
+	{MT_N0_CANC_IND, "CANCel INDication"},
+	{MT_N0_FAC_STA, "FACility STAtus"},
+	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
+	{MT_N0_STA_REJ, "STAtus REJect"},
+	{MT_N0_FAC_INF, "FACility INFormation"},
+	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
+	{MT_N0_INF_REJ, "INFormation REJect"},
+	{MT_N0_CLOSE, "CLOSE"},
+	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
+};
+
+int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
+
+static
+struct MessageType mt_n1[] =
+{
+	{MT_N1_ESC, "ESCape"},
+	{MT_N1_ALERT, "ALERT"},
+	{MT_N1_CALL_SENT, "CALL SENT"},
+	{MT_N1_CONN, "CONNect"},
+	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
+	{MT_N1_SETUP, "SETUP"},
+	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
+	{MT_N1_RES, "RESume"},
+	{MT_N1_RES_ACK, "RESume ACKnowledge"},
+	{MT_N1_RES_REJ, "RESume REJect"},
+	{MT_N1_SUSP, "SUSPend"},
+	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
+	{MT_N1_SUSP_REJ, "SUSPend REJect"},
+	{MT_N1_USER_INFO, "USER INFO"},
+	{MT_N1_DET, "DETach"},
+	{MT_N1_DISC, "DISConnect"},
+	{MT_N1_REL, "RELease"},
+	{MT_N1_REL_ACK, "RELease ACKnowledge"},
+	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
+	{MT_N1_CANC_REJ, "CANCel REJect"},
+	{MT_N1_CON_CON, "CONgestion CONtrol"},
+	{MT_N1_FAC, "FACility"},
+	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
+	{MT_N1_FAC_CAN, "FACility CANcel"},
+	{MT_N1_FAC_REG, "FACility REGister"},
+	{MT_N1_FAC_REJ, "FACility REJect"},
+	{MT_N1_INFO, "INFOrmation"},
+	{MT_N1_REG_ACK, "REGister ACKnowledge"},
+	{MT_N1_REG_REJ, "REGister REJect"},
+	{MT_N1_STAT, "STATus"}
+};
+
+int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
+
+static struct MessageType fac_1tr6[] =
+{
+	{FAC_Sperre, "Sperre"},
+	{FAC_Forward1, "Forward 1"},
+	{FAC_Forward2, "Forward 2"},
+	{FAC_Konferenz, "Konferenz"},
+	{FAC_GrabBchan, "Grab Bchannel"},
+	{FAC_Reactivate, "Reactivate"},
+	{FAC_Konferenz3, "Dreier Konferenz"},
+	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
+	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
+	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
+	{FAC_GBG, "GBG"},
+	{FAC_DisplayUebergeben, "Display Uebergeben"},
+	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
+	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
+	{FAC_Deactivate, "Deactivate"},
+	{FAC_Activate, "Activate"},
+	{FAC_SPV, "SPV"},
+	{FAC_Rueckwechsel, "Rueckwechsel"},
+	{FAC_Umleitung, "Umleitung"}
+};
+int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
+
+
+
+static int
+prbits(char *dest, u_char b, int start, int len)
+{
+	char *dp = dest;
+
+	b = b << (8 - start);
+	while (len--) {
+		if (b & 0x80)
+			*dp++ = '1';
+		else
+			*dp++ = '0';
+		b = b << 1;
+	}
+	return (dp - dest);
+}
+
+static
+u_char *
+skipext(u_char * p)
+{
+	while (!(*p++ & 0x80));
+	return (p);
+}
+
+/*
+ * Cause Values According to Q.850
+ * edescr: English description
+ * ddescr: German description used by Swissnet II (Swiss Telecom
+ *         not yet written...
+ */
+
+static
+struct CauseValue {
+	u_char nr;
+	char *edescr;
+	char *ddescr;
+} cvlist[] = {
+
+	{
+		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
+	},
+	{
+		0x02, "No route to specified transit network", ""
+	},
+	{
+		0x03, "No route to destination", ""
+	},
+	{
+		0x04, "Send special information tone", ""
+	},
+	{
+		0x05, "Misdialled trunk prefix", ""
+	},
+	{
+		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
+	},
+	{
+		0x07, "Channel awarded and being delivered in an established channel", ""
+	},
+	{
+		0x08, "Preemption", ""
+	},
+	{
+		0x09, "Preemption - circuit reserved for reuse", ""
+	},
+	{
+		0x10, "Normal call clearing", "Normale Ausloesung"
+	},
+	{
+		0x11, "User busy", "TNB besetzt"
+	},
+	{
+		0x12, "No user responding", ""
+	},
+	{
+		0x13, "No answer from user (user alerted)", ""
+	},
+	{
+		0x14, "Subscriber absent", ""
+	},
+	{
+		0x15, "Call rejected", ""
+	},
+	{
+		0x16, "Number changed", ""
+	},
+	{
+		0x1a, "non-selected user clearing", ""
+	},
+	{
+		0x1b, "Destination out of order", ""
+	},
+	{
+		0x1c, "Invalid number format (address incomplete)", ""
+	},
+	{
+		0x1d, "Facility rejected", ""
+	},
+	{
+		0x1e, "Response to Status enquiry", ""
+	},
+	{
+		0x1f, "Normal, unspecified", ""
+	},
+	{
+		0x22, "No circuit/channel available", ""
+	},
+	{
+		0x26, "Network out of order", ""
+	},
+	{
+		0x27, "Permanent frame mode connection out-of-service", ""
+	},
+	{
+		0x28, "Permanent frame mode connection operational", ""
+	},
+	{
+		0x29, "Temporary failure", ""
+	},
+	{
+		0x2a, "Switching equipment congestion", ""
+	},
+	{
+		0x2b, "Access information discarded", ""
+	},
+	{
+		0x2c, "Requested circuit/channel not available", ""
+	},
+	{
+		0x2e, "Precedence call blocked", ""
+	},
+	{
+		0x2f, "Resource unavailable, unspecified", ""
+	},
+	{
+		0x31, "Quality of service unavailable", ""
+	},
+	{
+		0x32, "Requested facility not subscribed", ""
+	},
+	{
+		0x35, "Outgoing calls barred within CUG", ""
+	},
+	{
+		0x37, "Incoming calls barred within CUG", ""
+	},
+	{
+		0x39, "Bearer capability not authorized", ""
+	},
+	{
+		0x3a, "Bearer capability not presently available", ""
+	},
+	{
+		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
+	},
+	{
+		0x3f, "Service or option not available, unspecified", ""
+	},
+	{
+		0x41, "Bearer capability not implemented", ""
+	},
+	{
+		0x42, "Channel type not implemented", ""
+	},
+	{
+		0x43, "Requested facility not implemented", ""
+	},
+	{
+		0x44, "Only restricted digital information bearer capability is available", ""
+	},
+	{
+		0x4f, "Service or option not implemented", ""
+	},
+	{
+		0x51, "Invalid call reference value", ""
+	},
+	{
+		0x52, "Identified channel does not exist", ""
+	},
+	{
+		0x53, "A suspended call exists, but this call identity does not", ""
+	},
+	{
+		0x54, "Call identity in use", ""
+	},
+	{
+		0x55, "No call suspended", ""
+	},
+	{
+		0x56, "Call having the requested call identity has been cleared", ""
+	},
+	{
+		0x57, "User not member of CUG", ""
+	},
+	{
+		0x58, "Incompatible destination", ""
+	},
+	{
+		0x5a, "Non-existent CUG", ""
+	},
+	{
+		0x5b, "Invalid transit network selection", ""
+	},
+	{
+		0x5f, "Invalid message, unspecified", ""
+	},
+	{
+		0x60, "Mandatory information element is missing", ""
+	},
+	{
+		0x61, "Message type non-existent or not implemented", ""
+	},
+	{
+		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
+	},
+	{
+		0x63, "Information element/parameter non-existent or not implemented", ""
+	},
+	{
+		0x64, "Invalid information element contents", ""
+	},
+	{
+		0x65, "Message not compatible with call state", ""
+	},
+	{
+		0x66, "Recovery on timer expiry", ""
+	},
+	{
+		0x67, "Parameter non-existent or not implemented - passed on", ""
+	},
+	{
+		0x6e, "Message with unrecognized parameter discarded", ""
+	},
+	{
+		0x6f, "Protocol error, unspecified", ""
+	},
+	{
+		0x7f, "Interworking, unspecified", ""
+	},
+};
+
+#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
+
+static
+int
+prcause(char *dest, u_char * p)
+{
+	u_char *end;
+	char *dp = dest;
+	int i, cause;
+
+	end = p + p[1] + 1;
+	p += 2;
+	dp += sprintf(dp, "    coding ");
+	dp += prbits(dp, *p, 7, 2);
+	dp += sprintf(dp, " location ");
+	dp += prbits(dp, *p, 4, 4);
+	*dp++ = '\n';
+	p = skipext(p);
+
+	cause = 0x7f & *p++;
+
+	/* locate cause value */
+	for (i = 0; i < CVSIZE; i++)
+		if (cvlist[i].nr == cause)
+			break;
+
+	/* display cause value if it exists */
+	if (i == CVSIZE)
+		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+	else
+		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
+
+	while (!0) {
+		if (p > end)
+			break;
+		dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
+		dp += sprintf(dp, " rej %d ", *p & 0x7f);
+		if (*p & 0x80) {
+			*dp++ = '\n';
+			break;
+		} else
+			dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
+	}
+	return (dp - dest);
+
+}
+
+static
+struct MessageType cause_1tr6[] =
+{
+	{CAUSE_InvCRef, "Invalid Call Reference"},
+	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
+	{CAUSE_CIDunknown, "Caller Identity unknown"},
+	{CAUSE_CIDinUse, "Caller Identity in Use"},
+	{CAUSE_NoChans, "No Channels available"},
+	{CAUSE_FacNotImpl, "Facility Not Implemented"},
+	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
+	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
+	{CAUSE_UserAccessBusy, "User Access Busy"},
+	{CAUSE_NegativeGBG, "Negative GBG"},
+	{CAUSE_UnknownGBG, "Unknown  GBG"},
+	{CAUSE_NoSPVknown, "No SPV known"},
+	{CAUSE_DestNotObtain, "Destination not obtainable"},
+	{CAUSE_NumberChanged, "Number changed"},
+	{CAUSE_OutOfOrder, "Out Of Order"},
+	{CAUSE_NoUserResponse, "No User Response"},
+	{CAUSE_UserBusy, "User Busy"},
+	{CAUSE_IncomingBarred, "Incoming Barred"},
+	{CAUSE_CallRejected, "Call Rejected"},
+	{CAUSE_NetworkCongestion, "Network Congestion"},
+	{CAUSE_RemoteUser, "Remote User initiated"},
+	{CAUSE_LocalProcErr, "Local Procedure Error"},
+	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
+	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
+	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
+	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
+};
+
+int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+
+static int
+prcause_1tr6(char *dest, u_char * p)
+{
+	char *dp = dest;
+	int i, cause;
+
+	p++;
+	if (0 == *p) {
+		dp += sprintf(dp, "   OK (cause length=0)\n");
+		return (dp - dest);
+	} else if (*p > 1) {
+		dp += sprintf(dp, "    coding ");
+		dp += prbits(dp, p[2], 7, 2);
+		dp += sprintf(dp, " location ");
+		dp += prbits(dp, p[2], 4, 4);
+		*dp++ = '\n';
+	}
+	p++;
+	cause = 0x7f & *p;
+
+	/* locate cause value */
+	for (i = 0; i < cause_1tr6_len; i++)
+		if (cause_1tr6[i].nr == cause)
+			break;
+
+	/* display cause value if it exists */
+	if (i == cause_1tr6_len)
+		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+	else
+		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
+
+	return (dp - dest);
+
+}
+
+static int
+prchident(char *dest, u_char * p)
+{
+	char *dp = dest;
+
+	p += 2;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+static int
+prcalled(char *dest, u_char * p)
+{
+	int l;
+	char *dp = dest;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p++, 8, 8);
+	*dp++ = '\n';
+	dp += sprintf(dp, "    number digits ");
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+prcalling(char *dest, u_char * p)
+{
+	int l;
+	char *dp = dest;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	if (!(*p & 0x80)) {
+		dp += sprintf(dp, "    octet 3a ");
+		dp += prbits(dp, *++p, 8, 8);
+		*dp++ = '\n';
+		l--;
+	};
+	p++;
+
+	dp += sprintf(dp, "    number digits ");
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+static
+int
+prbearer(char *dest, u_char * p)
+{
+	char *dp = dest, ch;
+
+	p += 2;
+	dp += sprintf(dp, "    octet 3  ");
+	dp += prbits(dp, *p++, 8, 8);
+	*dp++ = '\n';
+	dp += sprintf(dp, "    octet 4  ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	if ((*p++ & 0x1f) == 0x18) {
+		dp += sprintf(dp, "    octet 4.1 ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	/* check for user information layer 1 */
+	if ((*p & 0x60) == 0x20) {
+		ch = ' ';
+		do {
+			dp += sprintf(dp, "    octet 5%c ", ch);
+			dp += prbits(dp, *p, 8, 8);
+			*dp++ = '\n';
+			if (ch == ' ')
+				ch = 'a';
+			else
+				ch++;
+		}
+		while (!(*p++ & 0x80));
+	}
+	/* check for user information layer 2 */
+	if ((*p & 0x60) == 0x40) {
+		dp += sprintf(dp, "    octet 6  ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	/* check for user information layer 3 */
+	if ((*p & 0x60) == 0x60) {
+		dp += sprintf(dp, "    octet 7  ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	return (dp - dest);
+}
+
+static int
+general(char *dest, u_char * p)
+{
+	char *dp = dest;
+	char ch = ' ';
+	int l, octet = 3;
+
+	p++;
+	l = *p++;
+	/* Iterate over all octets in the information element */
+	while (l--) {
+		dp += sprintf(dp, "    octet %d%c ", octet, ch);
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+
+		/* last octet in group? */
+		if (*p & 0x80) {
+			octet++;
+			ch = ' ';
+		} else if (ch == ' ')
+			ch = 'a';
+		else
+			ch++;
+	}
+	return (dp - dest);
+}
+
+static int
+prcharge(char *dest, u_char * p)
+{
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++ - 1;
+	dp += sprintf(dp, "    GEA ");
+	dp += prbits(dp, *p++, 8, 8);
+	dp += sprintf(dp, "  Anzahl: ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+prtext(char *dest, u_char * p)
+{
+	char *dp = dest;
+	int l;
+
+	p++;
+	l = *p++;
+	dp += sprintf(dp, "    ");
+	/* Iterate over all octets in the * information element */
+	while (l--)
+		*dp++ = *p++;
+	*dp++ = '\n';
+	return (dp - dest);
+}
+static int
+display(char *dest, u_char * p)
+{
+	char *dp = dest;
+	char ch = ' ';
+	int l, octet = 3;
+
+	p++;
+	l = *p++;
+	/* Iterate over all octets in the * display-information element */
+	dp += sprintf(dp, "   \"");
+	while (l--) {
+		dp += sprintf(dp, "%c", *p++);
+
+		/* last octet in group? */
+		if (*p & 0x80) {
+			octet++;
+			ch = ' ';
+		} else if (ch == ' ')
+			ch = 'a';
+
+		else
+			ch++;
+	}
+	*dp++ = '\"';
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+int
+prfacility(char *dest, u_char * p)
+{
+	char *dp = dest;
+	int l, l2;
+
+	p++;
+	l = *p++;
+	dp += sprintf(dp, "    octet 3 ");
+	dp += prbits(dp, *p++, 8, 8);
+	dp += sprintf(dp, "\n");
+	l -= 1;
+
+	while (l > 0) {
+		dp += sprintf(dp, "   octet 4 ");
+		dp += prbits(dp, *p++, 8, 8);
+		dp += sprintf(dp, "\n");
+		dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
+		l -= 2;
+		dp += sprintf(dp, "   contents ");
+		while (l2--) {
+			dp += sprintf(dp, "%2x ", *p++);
+			l--;
+		}
+		dp += sprintf(dp, "\n");
+	}
+
+	return (dp - dest);
+}
+
+static
+struct InformationElement {
+	u_char nr;
+	char *descr;
+	int (*f) (char *, u_char *);
+} ielist[] = {
+
+	{
+		0x00, "Segmented message", general
+	},
+	{
+		0x04, "Bearer capability", prbearer
+	},
+	{
+		0x08, "Cause", prcause
+	},
+	{
+		0x10, "Call identity", general
+	},
+	{
+		0x14, "Call state", general
+	},
+	{
+		0x18, "Channel identification", prchident
+	},
+	{
+		0x1c, "Facility", prfacility
+	},
+	{
+		0x1e, "Progress indicator", general
+	},
+	{
+		0x20, "Network-specific facilities", general
+	},
+	{
+		0x27, "Notification indicator", general
+	},
+	{
+		0x28, "Display", display
+	},
+	{
+		0x29, "Date/Time", general
+	},
+	{
+		0x2c, "Keypad facility", general
+	},
+	{
+		0x34, "Signal", general
+	},
+	{
+		0x40, "Information rate", general
+	},
+	{
+		0x42, "End-to-end delay", general
+	},
+	{
+		0x43, "Transit delay selection and indication", general
+	},
+	{
+		0x44, "Packet layer binary parameters", general
+	},
+	{
+		0x45, "Packet layer window size", general
+	},
+	{
+		0x46, "Packet size", general
+	},
+	{
+		0x47, "Closed user group", general
+	},
+	{
+		0x4a, "Reverse charge indication", general
+	},
+	{
+		0x6c, "Calling party number", prcalling
+	},
+	{
+		0x6d, "Calling party subaddress", general
+	},
+	{
+		0x70, "Called party number", prcalled
+	},
+	{
+		0x71, "Called party subaddress", general
+	},
+	{
+		0x74, "Redirecting number", general
+	},
+	{
+		0x78, "Transit network selection", general
+	},
+	{
+		0x79, "Restart indicator", general
+	},
+	{
+		0x7c, "Low layer compatibility", general
+	},
+	{
+		0x7d, "High layer compatibility", general
+	},
+	{
+		0x7e, "User-user", general
+	},
+	{
+		0x7f, "Escape for extension", general
+	},
+};
+
+
+#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+
+static struct InformationElement we_0[] =
+{
+	{WE0_cause, "Cause", prcause_1tr6},
+	{WE0_connAddr, "Connecting Address", prcalled},
+	{WE0_callID, "Call IDentity", general},
+	{WE0_chanID, "Channel IDentity", general},
+	{WE0_netSpecFac, "Network Specific Facility", general},
+	{WE0_display, "Display", general},
+	{WE0_keypad, "Keypad", general},
+	{WE0_origAddr, "Origination Address", prcalled},
+	{WE0_destAddr, "Destination Address", prcalled},
+	{WE0_userInfo, "User Info", general}
+};
+
+static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
+
+static struct InformationElement we_6[] =
+{
+	{WE6_serviceInd, "Service Indicator", general},
+	{WE6_chargingInfo, "Charging Information", prcharge},
+	{WE6_date, "Date", prtext},
+	{WE6_facSelect, "Facility Select", general},
+	{WE6_facStatus, "Facility Status", general},
+	{WE6_statusCalled, "Status Called", general},
+	{WE6_addTransAttr, "Additional Transmission Attributes", general}
+};
+static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
+
+int
+QuickHex(char *txt, u_char * p, int cnt)
+{
+	register int i;
+	register char *t = txt;
+	register u_char w;
+
+	for (i = 0; i < cnt; i++) {
+		*t++ = ' ';
+		w = (p[i] >> 4) & 0x0f;
+		if (w < 10)
+			*t++ = '0' + w;
+		else
+			*t++ = 'A' - 10 + w;
+		w = p[i] & 0x0f;
+		if (w < 10)
+			*t++ = '0' + w;
+		else
+			*t++ = 'A' - 10 + w;
+	}
+	*t++ = 0;
+	return (t - txt);
+}
+
+void
+LogFrame(struct IsdnCardState *sp, u_char * buf, int size)
+{
+	char *dp;
+
+	if (size < 1)
+		return;
+	dp = sp->dlogspace;
+	if (size < 4096 / 3 - 10) {
+		dp += sprintf(dp, "HEX:");
+		dp += QuickHex(dp, buf, size);
+		dp--;
+		*dp++ = '\n';
+		*dp = 0;
+	} else
+		sprintf(dp, "LogFrame: warning Frame too big (%d)\n",
+			size);
+	HiSax_putstatus(sp, sp->dlogspace);
+}
+
+void
+dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
+{
+	u_char *bend = buf + size;
+	char *dp;
+	unsigned char pd, cr_l, cr, mt;
+	int i, cs = 0, cs_old = 0, cs_fest = 0;
+
+	if (size < 1)
+		return;
+	/* display header */
+	dp = sp->dlogspace;
+	dp += sprintf(dp, "%s\n", comment);
+
+	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
+		/* locate message type */
+		pd = *buf++;
+		cr_l = *buf++;
+		if (cr_l)
+			cr = *buf++;
+		else
+			cr = 0;
+		mt = *buf++;
+		if (pd == PROTO_DIS_N0) {	/* N0 */
+			for (i = 0; i < mt_n0_len; i++)
+				if (mt_n0[i].nr == mt)
+					break;
+			/* display message type if it exists */
+			if (i == mt_n0_len)
+				dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
+					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+					      size, mt);
+			else
+				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+					      size, mt_n0[i].descr);
+		} else {	/* N1 */
+			for (i = 0; i < mt_n1_len; i++)
+				if (mt_n1[i].nr == mt)
+					break;
+			/* display message type if it exists */
+			if (i == mt_n1_len)
+				dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
+					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+					      size, mt);
+			else
+				dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+					      cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+					      size, mt_n1[i].descr);
+		}
+
+		/* display each information element */
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+					case 1:
+						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+						cs_old = cs;
+						cs = *buf & 7;
+						cs_fest = *buf & 8;
+						break;
+					case 3:
+						dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+						break;
+					case 2:
+						if (*buf == 0xa0) {
+							dp += sprintf(dp, "  More data\n");
+							break;
+						}
+						if (*buf == 0xa1) {
+							dp += sprintf(dp, "  Sending complete\n");
+						}
+						break;
+						/* fall through */
+					default:
+						dp += sprintf(dp, "  Reserved %x\n", *buf);
+						break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			if (cs == 0) {
+				for (i = 0; i < we_0_len; i++)
+					if (*buf == we_0[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_0_len) {
+					dp += sprintf(dp, "  %s\n", we_0[i].descr);
+					dp += we_0[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else if (cs == 6) {
+				for (i = 0; i < we_6_len; i++)
+					if (*buf == we_6[i].nr)
+						break;
+
+				/* When found, give appropriate msg */
+				if (i != we_6_len) {
+					dp += sprintf(dp, "  %s\n", we_6[i].descr);
+					dp += we_6[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			} else
+				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+			/* Skip to next element */
+			if (cs_fest == 8) {
+				cs = cs_old;
+				cs_old = 0;
+				cs_fest = 0;
+			}
+			buf += buf[1] + 2;
+		}
+	} else if (buf[0] == 8) {	/* EURO */
+		/* locate message type */
+		buf++;
+		cr_l = *buf++;
+		if (cr_l)
+			cr = *buf++;
+		else
+			cr = 0;
+		mt = *buf++;
+		for (i = 0; i < MTSIZE; i++)
+			if (mtlist[i].nr == mt)
+				break;
+
+		/* display message type if it exists */
+		if (i == MTSIZE)
+			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
+			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+				      size, mt);
+		else
+			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+				      size, mtlist[i].descr);
+
+		/* display each information element */
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+					case 1:
+						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+						break;
+					case 3:
+						dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
+						break;
+					case 5:
+						dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
+						break;
+					case 2:
+						if (*buf == 0xa0) {
+							dp += sprintf(dp, "  More data\n");
+							break;
+						}
+						if (*buf == 0xa1) {
+							dp += sprintf(dp, "  Sending complete\n");
+						}
+						break;
+						/* fall through */
+					default:
+						dp += sprintf(dp, "  Reserved %x\n", *buf);
+						break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			for (i = 0; i < IESIZE; i++)
+				if (*buf == ielist[i].nr)
+					break;
+
+			/* When not found, give appropriate msg */
+			if (i != IESIZE) {
+				dp += sprintf(dp, "  %s\n", ielist[i].descr);
+				dp += ielist[i].f(dp, buf);
+			} else
+				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+
+			/* Skip to next element */
+			buf += buf[1] + 2;
+		}
+	} else {
+		dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
+	}
+	dp += sprintf(dp, "\n");
+	HiSax_putstatus(sp, sp->dlogspace);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/siemens.h linux-2.0.31-pre3/drivers/isdn/hisax/siemens.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/siemens.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/siemens.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,71 @@
+/* $Id: siemens.h,v 1.4 1997/01/21 22:24:33 keil Exp $
+ *
+ * siemens.h   ISAC and HSCX spezific Macros
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: siemens.h,v $
+ * Revision 1.4  1997/01/21 22:24:33  keil
+ * cleanups
+ *
+ * Revision 1.3  1996/12/08 19:48:34  keil
+ * adding Monitor channel registers
+ *
+ * Revision 1.2  1996/10/27 22:24:00  keil
+ * HSCX version code removed
+ *
+ * Revision 1.1  1996/10/12 21:39:39  keil
+ * Initial revision
+ *
+ *
+*/
+
+
+/* All Registers without FIFOs (original Siemens Spec - 20 hex) */
+
+#define ISAC_MASK 0x0
+#define ISAC_ISTA 0x0
+#define ISAC_STAR 0x1
+#define ISAC_CMDR 0x1
+#define ISAC_EXIR 0x4
+#define ISAC_RBCH 0xa
+#define ISAC_ADF2 0x19
+#define ISAC_SPCR 0x10
+#define ISAC_ADF1 0x18
+#define ISAC_CIR0 0x11
+#define ISAC_CIX0 0x11
+#define ISAC_STCR 0x17
+#define ISAC_MODE 0x2
+#define ISAC_RSTA 0x7
+#define ISAC_RBCL 0x5
+#define ISAC_TIMR 0x3
+#define ISAC_SQXR 0x1b
+#define ISAC_MOSR 0x1a
+#define ISAC_MOCR 0x1a
+#define ISAC_MOR0 0x12
+#define ISAC_MOX0 0x12
+#define ISAC_MOR1 0x14
+#define ISAC_MOX1 0x14
+
+#define HSCX_ISTA 0x0
+#define HSCX_CCR1 0xf
+#define HSCX_CCR2 0xc
+#define HSCX_TSAR 0x11
+#define HSCX_TSAX 0x10
+#define HSCX_XCCR 0x12
+#define HSCX_RCCR 0x13
+#define HSCX_MODE 0x2
+#define HSCX_CMDR 0x1
+#define HSCX_EXIR 0x4
+#define HSCX_XAD1 0x4
+#define HSCX_XAD2 0x5
+#define HSCX_RAH2 0x7
+#define HSCX_RSTA 0x7
+#define HSCX_TIMR 0x3
+#define HSCX_STAR 0x1
+#define HSCX_RBCL 0x5
+#define HSCX_XBCH 0xd
+#define HSCX_VSTR 0xe
+#define HSCX_RLCR 0xe
+#define HSCX_MASK 0x0
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/tei.c linux-2.0.31-pre3/drivers/isdn/hisax/tei.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/tei.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/tei.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,317 @@
+/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *
+ * $Log: tei.c,v $
+ * Revision 1.8  1997/04/07 22:59:08  keil
+ * GFP_KERNEL --> GFP_ATOMIC
+ *
+ * Revision 1.7  1997/04/06 22:54:03  keil
+ * Using SKB's
+ *
+ * Revision 1.6  1997/02/09 00:25:12  keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.5  1997/01/27 15:57:51  keil
+ * cosmetics
+ *
+ * Revision 1.4  1997/01/21 22:32:44  keil
+ * Tei verify request
+ *
+ * Revision 1.3  1997/01/04 13:45:02  keil
+ * cleanup,adding remove tei request (thanks to Sim Yskes)
+ *
+ * Revision 1.2  1996/12/08 19:52:39  keil
+ * minor debug fix
+ *
+ * Revision 1.1  1996/10/13 20:04:57  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+
+const char *tei_revision = "$Revision: 1.8 $";
+
+static struct PStack *
+findces(struct PStack *st, int ces)
+{
+	struct PStack *ptr = *(st->l1.stlistp);
+
+	while (ptr)
+		if (ptr->l2.ces == ces)
+			return (ptr);
+		else
+			ptr = ptr->next;
+	return (NULL);
+}
+
+static struct PStack *
+findtei(struct PStack *st, int tei)
+{
+	struct PStack *ptr = *(st->l1.stlistp);
+
+	if (tei == 127)
+		return (NULL);
+
+	while (ptr)
+		if (ptr->l2.tei == tei)
+			return (ptr);
+		else
+			ptr = ptr->next;
+	return (NULL);
+}
+
+static void
+mdl_unit_data_res(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+{
+	struct sk_buff *skb;
+	u_char *bp;
+
+	if (!(skb = alloc_skb(6 + MAX_HEADER_LEN, GFP_ATOMIC))) {
+		printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
+		return;
+	}
+	SET_SKB_FREE(skb);
+	skb_reserve(skb, MAX_HEADER_LEN);
+	bp = skb_put(skb, 5);
+	bp[0] = 0xf;
+	bp[1] = ri >> 8;
+	bp[2] = ri & 0xff;
+	bp[3] = mt;
+	bp[4] = (ai << 1) | 1;
+	st->l3.l3l2(st, DL_UNIT_DATA, skb);
+}
+
+static void
+mdl_unit_data_ind(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+{
+	unsigned int tces;
+	struct PStack *otsp, *ptr;
+	char tmp[64];
+
+	switch (mt) {
+		case (2):
+			tces = ri;
+			if (st->l3.debug) {
+				sprintf(tmp, "identity assign ces %d ai %d", tces, ai);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			if ((otsp = findces(st, tces))) {
+				if (st->l3.debug) {
+					sprintf(tmp, "ces %d --> tei %d", tces, ai);
+					st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+				}
+				otsp->ma.teil2(otsp, MDL_ASSIGN, (void *) (int) ai);
+			}
+			break;
+		case (3):
+			tces = ri;
+			if (st->l3.debug) {
+				sprintf(tmp, "identity denied for ces %d ai %d", tces, ai);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			if ((otsp = findces(st, tces))) {
+				if (st->l3.debug) {
+					sprintf(tmp, "ces %d denied tei %d", tces, ai);
+					st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+				}
+				otsp->l2.tei = 255;
+				otsp->l2.ces = randomces();
+				otsp->ma.teil2(otsp, MDL_REMOVE, 0);
+			}
+			break;
+		case (4):
+			if (st->l3.debug) {
+				sprintf(tmp, "checking identity for %d", ai);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			if (ai == 0x7f) {
+				ptr = *(st->l1.stlistp);
+				while (ptr) {
+					if ((ptr->l2.tei & 0x7f) != 0x7f) {
+						if (st->l3.debug) {
+							sprintf(tmp, "check response for ces %d with tei %d",
+								ptr->l2.ces, ptr->l2.tei);
+							st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+						}
+						/* send identity check response (user->network) */
+						mdl_unit_data_res(st, ptr->l2.ces, 5, ptr->l2.tei);
+					}
+					ptr = ptr->next;
+				}
+			} else {
+				otsp = findtei(st, ai);
+				if (!otsp)
+					break;
+				if (st->l3.debug) {
+					sprintf(tmp, "check response for ces %d with tei %d",
+					     otsp->l2.ces, otsp->l2.tei);
+					st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+				}
+				/* send identity check response (user->network) */
+				mdl_unit_data_res(st, otsp->l2.ces, 5, otsp->l2.tei);
+			}
+			break;
+		case (6):
+			if (st->l3.debug) {
+				sprintf(tmp, "removal for %d", ai);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			if (ai == 0x7f) {
+				ptr = *(st->l1.stlistp);
+				while (ptr) {
+					if ((ptr->l2.tei & 0x7f) != 0x7f) {
+						if (st->l3.debug) {
+							sprintf(tmp, "rem ces %d with tei %d",
+								ptr->l2.ces, ptr->l2.tei);
+							st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+						}
+						ptr->ma.teil2(ptr, MDL_REMOVE, 0);
+					}
+					ptr = ptr->next;
+				}
+			} else {
+				otsp = findtei(st, ai);
+				if (!otsp)
+					break;
+				if (st->l3.debug) {
+					sprintf(tmp, "rem ces %d with tei %d",
+					     otsp->l2.ces, otsp->l2.tei);
+					st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+				}
+				otsp->ma.teil2(otsp, MDL_REMOVE, 0);
+			}
+			break;
+		default:
+			if (st->l3.debug) {
+				sprintf(tmp, "message unknown %d ai %d", mt, ai);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+	}
+}
+
+void
+tei_handler(struct PStack *st,
+	    u_char pr, struct sk_buff *skb)
+{
+	u_char *bp;
+	unsigned int data;
+	char tmp[32];
+
+	switch (pr) {
+		case (MDL_ASSIGN):
+			data = (unsigned int) skb;
+			if (st->l3.debug) {
+				sprintf(tmp, "ces %d assign request", data);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			mdl_unit_data_res(st, data, 1, 127);
+			break;
+		case (MDL_VERIFY):
+			data = (unsigned int) skb;
+			if (st->l3.debug) {
+				sprintf(tmp, "%d id verify request", data);
+				st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+			}
+			mdl_unit_data_res(st, 0, 7, data);
+			break;
+		case (DL_UNIT_DATA):
+			bp = skb->data;
+			if (bp[0] != 0xf) {
+				/* wrong management entity identifier, ignore */
+				/* shouldn't ibh be released??? */
+				printk(KERN_WARNING "tei handler wrong entity id %x\n", bp[0]);
+			} else
+				mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1);
+			dev_kfree_skb(skb, FREE_READ);
+			break;
+		default:
+			break;
+	}
+}
+
+unsigned int
+randomces(void)
+{
+	int x = jiffies & 0xffff;
+
+	return (x);
+}
+
+static void
+tei_man(struct PStack *sp, int i, void *v)
+{
+
+	printk(KERN_DEBUG "tei_man\n");
+}
+
+static void
+tei_l2tei(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *sp = st->l1.hardware;
+
+	tei_handler(sp->teistack, pr, arg);
+}
+
+void
+setstack_tei(struct PStack *st)
+{
+	st->l2.l2tei = tei_l2tei;
+}
+
+void
+init_tei(struct IsdnCardState *sp, int protocol)
+{
+	struct PStack *st;
+	char tmp[128];
+
+	st = (struct PStack *) kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+	setstack_HiSax(st, sp);
+	st->l2.extended = !0;
+	st->l2.laptype = LAPD;
+	st->l2.window = 1;
+	st->l2.orig = !0;
+	st->protocol = protocol;
+/*
+ * the following is not necessary for tei mng. (broadcast only)
+ */
+	st->l2.t200 = 500;	/* 500 milliseconds */
+	st->l2.n200 = 4;	/* try 4 times */
+
+	st->l2.sap = 63;
+	st->l2.tei = 127;
+
+	sprintf(tmp, "Card %d tei", sp->cardnr + 1);
+	setstack_isdnl2(st, tmp);
+	st->l2.debug = 0;
+	st->l3.debug = 0;
+
+	st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+
+	st->l2.l2l3 = (void *) tei_handler;
+	st->l1.l1man = tei_man;
+	st->l2.l2man = tei_man;
+	st->l4.l2writewakeup = NULL;
+
+	HiSax_addlist(sp, st);
+	sp->teistack = st;
+}
+
+void
+release_tei(struct IsdnCardState *sp)
+{
+	struct PStack *st = sp->teistack;
+
+	HiSax_rmlist(sp, st);
+	kfree((void *) st);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/teles0.c linux-2.0.31-pre3/drivers/isdn/hisax/teles0.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/teles0.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/teles0.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,968 @@
+/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $
+
+ * teles0.c     low level stuff for Teles Memory IO isdn cards
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *              Beat Doebeli
+ *
+ * $Log: teles0.c,v $
+ * Revision 1.8  1997/04/13 19:54:04  keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.7  1997/04/06 22:54:04  keil
+ * Using SKB's
+ *
+ * Revision 1.6  1997/01/27 15:52:18  keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.5  1997/01/21 22:25:59  keil
+ * cleanups
+ *
+ * Revision 1.4  1996/11/05 19:41:27  keil
+ * more changes for 2.1
+ *
+ * Revision 1.3  1996/10/30 10:22:58  keil
+ * Changes for 2.1 kernels
+ *
+ * Revision 1.2  1996/10/27 22:08:34  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:58  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles0.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+
+const char *teles0_revision = "$Revision: 1.8 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readisac(unsigned int adr, u_char off)
+{
+	return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writeisac(unsigned int adr, u_char off, u_char data)
+{
+	writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+
+static inline u_char
+readhscx(unsigned int adr, int hscx, u_char off)
+{
+	return readb(adr + (hscx ? 0x1e0 : 0x1a0) +
+		     ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+{
+	writeb(data, adr + (hscx ? 0x1e0 : 0x1a0) +
+	       ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *) (adr + 0x100);
+	for (i = 0; i < size; i++)
+		data[i] = readb(ad);
+}
+
+static void
+write_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *) (adr + 0x100);
+	for (i = 0; i < size; i++)
+		writeb(data[i], ad);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+	register int i;
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+	for (i = 0; i < size; i++)
+		data[i] = readb(ad);
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+	int i;
+	register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+	for (i = 0; i < size; i++)
+		writeb(data[i], ad);
+}
+static inline void
+waitforCEC(int adr, int hscx)
+{
+	int to = 50;
+
+	while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int hscx)
+{
+	int to = 50;
+
+	while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr, hscx);
+	writehscx(adr, hscx, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+	printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR));
+}
+
+void
+teles0_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *sp = hsp->sp;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvidx + count > HSCX_BUFMAX) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+		hsp->rcvidx = 0;
+		return;
+	}
+	ptr = hsp->rcvbuf + hsp->rcvidx;
+	hsp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+	writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState *sp = hsp->sp;
+	int more, count;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	if (!hsp->tx_skb)
+		return;
+	if (hsp->tx_skb->len <= 0)
+		return;
+
+	more = (hsp->mode == 1) ? 1 : 0;
+	if (hsp->tx_skb->len > 32) {
+		more = !0;
+		count = 32;
+	} else
+		count = hsp->tx_skb->len;
+
+	waitforXFW(sp->membase, hsp->hscx);
+	save_flags(flags);
+	cli();
+	ptr = hsp->tx_skb->data;
+	skb_pull(hsp->tx_skb, count);
+	hsp->tx_cnt -= count;
+	hsp->count += count;
+	write_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+	writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+	u_char r;
+	struct HscxState *hsp = sp->hs + hscx;
+	struct sk_buff *skb;
+	int count;
+	char tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode)
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+		} else {
+			count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			hscx_empty_fifo(hsp, count);
+			if ((count = hsp->rcvidx - 1) > 0) {
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "teles0: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+					skb_queue_tail(&hsp->rqueue, skb);
+				}
+			}
+		}
+		hsp->rcvidx = 0;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		hscx_empty_fifo(hsp, 32);
+		if (hsp->mode == 1) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(32)))
+				printk(KERN_WARNING "teles0: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+				skb_queue_tail(&hsp->rqueue, skb);
+			}
+			hsp->rcvidx = 0;
+			hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (hsp->tx_skb)
+			if (hsp->tx_skb->len) {
+				hscx_fill_fifo(hsp);
+				return;
+			} else {
+				dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+				hsp->count = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->tx_skb = NULL;
+			}
+		if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+			hsp->count = 0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_empty_fifo");
+
+	if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+		if (sp->debug & L1_DEB_WARN) {
+			char tmp[40];
+			sprintf(tmp, "isac_empty_fifo overrun %d",
+				sp->rcvidx + count);
+			debugl1(sp, tmp);
+		}
+		writeisac(sp->membase, ISAC_CMDR, 0x80);
+		sp->rcvidx = 0;
+		return;
+	}
+	ptr = sp->rcvbuf + sp->rcvidx;
+	sp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo_isac(sp->membase, ptr, count);
+	writeisac(sp->membase, ISAC_CMDR, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_fill_fifo");
+
+	if (!sp->tx_skb)
+		return;
+
+	count = sp->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = sp->tx_skb->data;
+	skb_pull(sp->tx_skb, count);
+	sp->tx_cnt += count;
+	write_fifo_isac(sp->membase, ptr, count);
+	writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+		debugl1(sp, tmp);
+	}
+	writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+	u_char exval;
+	struct sk_buff *skb;
+	unsigned int count;
+	char tmp[32];
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+		debugl1(sp, tmp);
+	}
+	if (val & 0x80) {	/* RME */
+		exval = readisac(sp->membase, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC CRC error");
+			writeisac(sp->membase, ISAC_CMDR, 0x80);
+		} else {
+			count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			isac_empty_fifo(sp, count);
+			if ((count = sp->rcvidx) > 0) {
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "teles0: D receive out of memory\n");
+				else {
+					SET_SKB_FREE(skb);
+					memcpy(skb_put(skb, count), sp->rcvbuf, count);
+					skb_queue_tail(&sp->rq, skb);
+				}
+			}
+		}
+		sp->rcvidx = 0;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		isac_empty_fifo(sp, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->tx_skb)
+			if (sp->tx_skb->len) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+				sp->tx_cnt = 0;
+				sp->tx_skb = NULL;
+			}
+		if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+			sp->tx_cnt = 0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2)
+		    & 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+			sprintf(tmp, "l1state %d", sp->ph_state);
+			debugl1(sp, tmp);
+		}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readisac(sp->membase, ISAC_EXIR);
+		if (sp->debug & L1_DEB_WARN) {
+			sprintf(tmp, "ISAC EXIR %02x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+	u_char exval;
+	struct HscxState *hsp;
+	char tmp[32];
+
+
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+		exval = readhscx(sp->membase, 1, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->membase, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+		exval = readhscx(sp->membase, 0, HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->membase, hsp->hscx, 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0x04) {
+		exval = readhscx(sp->membase, 0, HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *sp;
+	u_char val, stat = 0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+	if (!sp) {
+		printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
+		return;
+	}
+	val = readhscx(sp->membase, 1, HSCX_ISTA);
+      Start_HSCX:
+	if (val) {
+		hscx_int_main(sp, val);
+		stat |= 1;
+	}
+	val = readisac(sp->membase, ISAC_ISTA);
+      Start_ISAC:
+	if (val) {
+		isac_interrupt(sp, val);
+		stat |= 2;
+	}
+	val = readhscx(sp->membase, 1, HSCX_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_HSCX)
+			debugl1(sp, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readisac(sp->membase, ISAC_ISTA);
+	if (val) {
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	if (stat & 1) {
+		writehscx(sp->membase, 0, HSCX_MASK, 0xFF);
+		writehscx(sp->membase, 1, HSCX_MASK, 0xFF);
+		writehscx(sp->membase, 0, HSCX_MASK, 0x0);
+		writehscx(sp->membase, 1, HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writeisac(sp->membase, ISAC_MASK, 0xFF);
+		writeisac(sp->membase, ISAC_MASK, 0x0);
+	}
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+	unsigned int adr = sp->membase;
+
+	/* 16.0 IOM 1 Mode */
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_ADF2, 0x0);
+	writeisac(adr, ISAC_SPCR, 0xa);
+	writeisac(adr, ISAC_ADF1, 0x2);
+	writeisac(adr, ISAC_STCR, 0x70);
+	writeisac(adr, ISAC_MODE, 0xc9);
+	writeisac(adr, ISAC_CMDR, 0x41);
+	writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+	writeisac(adr, ISAC_MASK, 0xff);
+	writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+			'A' + hscx, mode, ichan);
+		debugl1(sp, tmp);
+	}
+	hs->mode = mode;
+	writehscx(sp->membase, hscx, HSCX_CCR1, 0x85);
+	writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF);
+	writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF);
+	writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF);
+	writehscx(sp->membase, hscx, HSCX_XBCH, 0x0);
+
+	/* Switch IOM 1 SSI */
+	if (hscx == 0)
+		ichan = 1 - ichan;
+
+	switch (mode) {
+		case (0):
+			writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+			writehscx(sp->membase, hscx, HSCX_TSAX, 0xff);
+			writehscx(sp->membase, hscx, HSCX_TSAR, 0xff);
+			writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+			writehscx(sp->membase, hscx, HSCX_MODE, 0x84);
+			break;
+		case (1):
+			if (ichan == 0) {
+				writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+				writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+				writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+				writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+				writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+			} else {
+				writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+				writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+				writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+				writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+				writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+			}
+			writehscx(sp->membase, hscx, HSCX_MODE, 0xe4);
+			writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+			break;
+		case (2):
+			if (ichan == 0) {
+				writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+				writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+				writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+				writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+				writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+			} else {
+				writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+				writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+				writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+				writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+				writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+			}
+			writehscx(sp->membase, hscx, HSCX_MODE, 0x8c);
+			writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+			break;
+	}
+	writehscx(sp->membase, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_teles0(struct IsdnCard *card)
+{
+	if (card->sp->cfg_reg)
+		release_region(card->sp->cfg_reg, 8);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int val;
+	char tmp[64];
+
+	val = readhscx(sp->membase, 1, HSCX_ISTA);
+	sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readhscx(sp->membase, 1, HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x02) {
+		val = readhscx(sp->membase, 0, HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+	}
+	val = readhscx(sp->membase, 0, HSCX_ISTA);
+	sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+	val = readhscx(sp->membase, 1, HSCX_STAR);
+	sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+	val = readhscx(sp->membase, 0, HSCX_STAR);
+	sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->membase, ISAC_STAR);
+	sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->membase, ISAC_MODE);
+	sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->membase, ISAC_ADF2);
+	sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+	val = readisac(sp->membase, ISAC_ISTA);
+	sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readisac(sp->membase, ISAC_EXIR);
+		sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x04) {
+		val = readisac(sp->membase, ISAC_CIR0);
+		sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+	}
+	writeisac(sp->membase, ISAC_MASK, 0);
+	writeisac(sp->membase, ISAC_CMDR, 0x41);
+}
+
+int
+initteles0(struct IsdnCardState *sp)
+{
+	int ret;
+	int loop = 0;
+	char tmp[40];
+
+	sp->counter = kstat.interrupts[sp->irq];
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr, &telesS0_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		while (loop++ < 10) {
+			/* At least 1-3 irqs must happen
+			 * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+			 */
+			if (kstat.interrupts[sp->irq] > sp->counter)
+				break;
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 1;
+			schedule();
+		}
+		sprintf(tmp, "IRQ %d count %d", sp->irq,
+			kstat.interrupts[sp->irq]);
+		debugl1(sp, tmp);
+		if (kstat.interrupts[sp->irq] == sp->counter) {
+			printk(KERN_WARNING
+			       "Teles0: IRQ(%d) getting no interrupts during init\n",
+			       sp->irq);
+			irq2dev_map[sp->irq] = NULL;
+			free_irq(sp->irq, NULL);
+			return (0);
+		}
+	}
+	return (ret);
+}
+
+int
+setup_teles0(struct IsdnCard *card)
+{
+	u_char cfval, val, verA, verB;
+	struct IsdnCardState *sp = card->sp;
+	long flags;
+	char tmp[64];
+
+	strcpy(tmp, teles0_revision);
+	printk(KERN_NOTICE "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
+	if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0))
+		return (0);
+
+	if (sp->typ == ISDN_CTYPE_16_0)
+		sp->cfg_reg = card->para[2];
+	else			/* 8.0 */
+		sp->cfg_reg = 0;
+
+	if (card->para[1] < 0x10000) {
+		card->para[1] <<= 4;
+		printk(KERN_INFO
+		   "Teles0: membase configured DOSish, assuming 0x%lx\n",
+		       (unsigned long) card->para[1]);
+	}
+	sp->membase = card->para[1];
+	sp->irq = card->para[0];
+	if (sp->cfg_reg) {
+		if (check_region((sp->cfg_reg), 8)) {
+			printk(KERN_WARNING
+			  "HiSax: %s config port %x-%x already in use\n",
+			       CardType[card->typ],
+			       sp->cfg_reg,
+			       sp->cfg_reg + 8);
+			return (0);
+		} else {
+			request_region(sp->cfg_reg, 8, "teles cfg");
+		}
+	}
+	switch (sp->irq) {
+		case 2:
+			cfval = 0x00;
+			break;
+		case 3:
+			cfval = 0x02;
+			break;
+		case 4:
+			cfval = 0x04;
+			break;
+		case 5:
+			cfval = 0x06;
+			break;
+		case 10:
+			cfval = 0x08;
+			break;
+		case 11:
+			cfval = 0x0A;
+			break;
+		case 12:
+			cfval = 0x0C;
+			break;
+		case 15:
+			cfval = 0x0E;
+			break;
+		default:
+			cfval = 0x00;
+			break;
+	}
+	cfval |= ((card->para[1] >> 9) & 0xF0);
+	if (sp->cfg_reg) {
+		if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       sp->cfg_reg + 0, val);
+			release_region(sp->cfg_reg, 8);
+			return (0);
+		}
+		if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       sp->cfg_reg + 1, val);
+			release_region(sp->cfg_reg, 8);
+			return (0);
+		}
+		val = bytein(sp->cfg_reg + 2);	/* 0x1e=without AB
+						   * 0x1f=with AB
+						   * 0x1c 16.3 ???
+						 */
+		if (val != 0x1e && val != 0x1f) {
+			printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+			       sp->cfg_reg + 2, val);
+			release_region(sp->cfg_reg, 8);
+			return (0);
+		}
+		save_flags(flags);
+		byteout(sp->cfg_reg + 4, cfval);
+		sti();
+		HZDELAY(HZ / 10 + 1);
+		byteout(sp->cfg_reg + 4, cfval | 1);
+		HZDELAY(HZ / 10 + 1);
+		restore_flags(flags);
+	}
+	printk(KERN_NOTICE
+	       "HiSax: %s config irq:%d mem:%x cfg:%x\n",
+	       CardType[sp->typ], sp->irq,
+	       sp->membase, sp->cfg_reg);
+	verA = readhscx(sp->membase, 0, HSCX_VSTR) & 0xf;
+	verB = readhscx(sp->membase, 1, HSCX_VSTR) & 0xf;
+	printk(KERN_INFO "Teles0: HSCX version A: %s  B: %s\n",
+	       HscxVersion(verA), HscxVersion(verB));
+	val = readisac(sp->membase, ISAC_RBCH);
+	printk(KERN_INFO "Teles0: ISAC %s\n",
+	       ISACVersion(val));
+
+	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+		printk(KERN_WARNING
+		 "Teles0: wrong HSCX versions check IO/MEM addresses\n");
+		release_io_teles0(card);
+		return (0);
+	}
+	save_flags(flags);
+	writeb(0, sp->membase + 0x80);
+	sti();
+	HZDELAY(HZ / 5 + 1);
+	writeb(1, sp->membase + 0x80);
+	HZDELAY(HZ / 5 + 1);
+	restore_flags(flags);
+
+	sp->modehscx = &modehscx;
+	sp->ph_command = &ph_command;
+	sp->hscx_fill_fifo = &hscx_fill_fifo;
+	sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/teles0.h linux-2.0.31-pre3/drivers/isdn/hisax/teles0.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/teles0.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/teles0.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,21 @@
+/* $Id: teles0.h,v 1.2 1997/01/21 22:26:52 keil Exp $
+ *
+ * teles0.h   Header for Teles 16.0 8.0 & compatible
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles0.h,v $
+ * Revision 1.2  1997/01/21 22:26:52  keil
+ * cleanups
+ *
+ * Revision 1.1  1996/10/13 20:03:48  keil
+ * Initial revision
+ *
+ *
+*/
+
+extern	void teles0_report(struct IsdnCardState *sp);
+extern  void release_io_teles0(struct IsdnCard *card);
+extern	int  setup_teles0(struct IsdnCard *card);
+extern  int  initteles0(struct IsdnCardState *sp);
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/teles3.c linux-2.0.31-pre3/drivers/isdn/hisax/teles3.c
--- linux-2.0.31-pre2/drivers/isdn/hisax/teles3.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/teles3.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,1034 @@
+/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $
+
+ * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
+ *
+ *              based on the teles driver from Jan den Ouden
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to    Jan den Ouden
+ *              Fritz Elfert
+ *              Beat Doebeli
+ *
+ * $Log: teles3.c,v $
+ * Revision 1.11  1997/04/13 19:54:05  keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.10  1997/04/06 22:54:05  keil
+ * Using SKB's
+ *
+ * Revision 1.9  1997/03/22 02:01:07  fritz
+ * -Reworked toplevel Makefile. From now on, no different Makefiles
+ *  for standalone- and in-kernel-compilation are needed any more.
+ * -Added local Rules.make for above reason.
+ * -Experimental changes in teles3.c for enhanced IRQ-checking with
+ *  2.1.X and SMP kernels.
+ * -Removed diffstd-script, same functionality is in stddiff -r.
+ * -Enhanced scripts std2kern and stddiff.
+ *
+ * Revision 1.8  1997/02/23 18:43:55  fritz
+ * Added support for Teles-Vision.
+ *
+ * Revision 1.7  1997/01/28 22:48:33  keil
+ * fixes for Teles PCMCIA (Christof Petig)
+ *
+ * Revision 1.6  1997/01/27 15:52:55  keil
+ * SMP proof,cosmetics, PCMCIA added
+ *
+ * Revision 1.5  1997/01/21 22:28:32  keil
+ * cleanups
+ *
+ * Revision 1.4  1996/12/14 21:05:41  keil
+ * Reset for 16.3 PnP
+ *
+ * Revision 1.3  1996/11/05 19:56:54  keil
+ * debug output fixed
+ *
+ * Revision 1.2  1996/10/27 22:09:15  keil
+ * cosmetic changes
+ *
+ * Revision 1.1  1996/10/13 20:04:59  keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles3.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *teles3_revision = "$Revision: 1.11 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readreg(unsigned int adr, u_char off)
+{
+	return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, u_char off, u_char data)
+{
+	byteout(adr + off, data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+	insb(adr + 0x1e, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+	outsb(adr + 0x1e, data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+	int to = 50;
+
+	while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles3: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr)
+{
+	int to = 50;
+
+	while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
+		udelay(1);
+		to--;
+	}
+	if (!to)
+		printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
+}
+static inline void
+writehscxCMDR(int adr, u_char data)
+{
+	long flags;
+
+	save_flags(flags);
+	cli();
+	waitforCEC(adr);
+	writereg(adr, HSCX_CMDR, data);
+	restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+	printk(KERN_DEBUG "HSCX %d\n", hscx);
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+teles3_report(struct IsdnCardState *sp)
+{
+	printk(KERN_DEBUG "ISAC\n");
+	printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+	printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+	printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+	hscxreport(sp, 0);
+	hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+	u_char *ptr;
+	struct IsdnCardState *sp = hsp->sp;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_empty_fifo");
+
+	if (hsp->rcvidx + count > HSCX_BUFMAX) {
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+		writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		hsp->rcvidx = 0;
+		return;
+	}
+	ptr = hsp->rcvbuf + hsp->rcvidx;
+	hsp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo(sp->hscx[hsp->hscx], ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+	struct IsdnCardState *sp = hsp->sp;
+	int more, count;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+		debugl1(sp, "hscx_fill_fifo");
+
+	if (!hsp->tx_skb)
+		return;
+	if (hsp->tx_skb->len <= 0)
+		return;
+
+	more = (hsp->mode == 1) ? 1 : 0;
+	if (hsp->tx_skb->len > 32) {
+		more = !0;
+		count = 32;
+	} else
+		count = hsp->tx_skb->len;
+
+	waitforXFW(sp->hscx[hsp->hscx]);
+	save_flags(flags);
+	cli();
+	ptr = hsp->tx_skb->data;
+	skb_pull(hsp->tx_skb, count);
+	hsp->tx_cnt -= count;
+	hsp->count += count;
+	write_fifo(sp->hscx[hsp->hscx], ptr, count);
+	writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_HSCX_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+			     hsp->hscx ? 'B' : 'A', count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+	u_char r;
+	struct HscxState *hsp = sp->hs + hscx;
+	struct sk_buff *skb;
+	int count;
+	char tmp[32];
+
+	if (!hsp->init)
+		return;
+
+	if (val & 0x80) {	/* RME */
+
+		r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+		if ((r & 0xf0) != 0xa0) {
+			if (!r & 0x80)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX invalid frame");
+			if ((r & 0x40) && hsp->mode)
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX RDO mode=%d",
+						hsp->mode);
+					debugl1(sp, tmp);
+				}
+			if (!r & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "HSCX CRC error");
+			writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+		} else {
+			count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			hscx_empty_fifo(hsp, count);
+			if ((count = hsp->rcvidx - 1) > 0) {
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "teles3: receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+					skb_queue_tail(&hsp->rqueue, skb);
+				}
+			}
+		}
+		hsp->rcvidx = 0;
+		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		hscx_empty_fifo(hsp, 32);
+		if (hsp->mode == 1) {
+			/* receive audio data */
+			if (!(skb = dev_alloc_skb(32)))
+				printk(KERN_WARNING "teles3: receive out of memory\n");
+			else {
+				memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+				skb_queue_tail(&hsp->rqueue, skb);
+			}
+			hsp->rcvidx = 0;
+			hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+		}
+	}
+	if (val & 0x10) {	/* XPR */
+		if (hsp->tx_skb)
+			if (hsp->tx_skb->len) {
+				hscx_fill_fifo(hsp);
+				return;
+			} else {
+				dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+				hsp->count = 0;
+				if (hsp->st->l4.l1writewakeup)
+					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->tx_skb = NULL;
+			}
+		if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+			hsp->count = 0;
+			hscx_fill_fifo(hsp);
+		} else
+			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+	}
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "isac_empty_fifo");
+
+	if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+		if (sp->debug & L1_DEB_WARN) {
+			char tmp[40];
+			sprintf(tmp, "isac_empty_fifo overrun %d",
+				sp->rcvidx + count);
+			debugl1(sp, tmp);
+		}
+		writereg(sp->isac, ISAC_CMDR, 0x80);
+		sp->rcvidx = 0;
+		return;
+	}
+	ptr = sp->rcvbuf + sp->rcvidx;
+	sp->rcvidx += count;
+	save_flags(flags);
+	cli();
+	read_fifo(sp->isac, ptr, count);
+	writereg(sp->isac, ISAC_CMDR, 0x80);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+		debugl1(sp, "isac_fill_fifo");
+
+	if (!sp->tx_skb)
+		return;
+
+	count = sp->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = sp->tx_skb->data;
+	skb_pull(sp->tx_skb, count);
+	sp->tx_cnt += count;
+	write_fifo(sp->isac, ptr, count);
+	writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+	restore_flags(flags);
+	if (sp->debug & L1_DEB_ISAC_FIFO) {
+		char tmp[128];
+		char *t = tmp;
+
+		t += sprintf(t, "isac_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(sp, tmp);
+	}
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+	if (sp->debug & L1_DEB_ISAC) {
+		char tmp[32];
+		sprintf(tmp, "ph_command %d", command);
+		debugl1(sp, tmp);
+	}
+	writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+	u_char exval;
+	struct sk_buff *skb;
+	unsigned int count;
+	char tmp[32];
+
+	if (sp->debug & L1_DEB_ISAC) {
+		sprintf(tmp, "ISAC interrupt %x", val);
+		debugl1(sp, tmp);
+	}
+	if (val & 0x80) {	/* RME */
+		exval = readreg(sp->isac, ISAC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC RDO");
+			if (!exval & 0x20)
+				if (sp->debug & L1_DEB_WARN)
+					debugl1(sp, "ISAC CRC error");
+			writereg(sp->isac, ISAC_CMDR, 0x80);
+		} else {
+			count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			isac_empty_fifo(sp, count);
+			if ((count = sp->rcvidx) > 0) {
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "AVM: D receive out of memory\n");
+				else {
+					SET_SKB_FREE(skb);
+					memcpy(skb_put(skb, count), sp->rcvbuf, count);
+					skb_queue_tail(&sp->rq, skb);
+				}
+			}
+		}
+		sp->rcvidx = 0;
+		isac_sched_event(sp, ISAC_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		isac_empty_fifo(sp, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (sp->tx_skb)
+			if (sp->tx_skb->len) {
+				isac_fill_fifo(sp);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+				sp->tx_cnt = 0;
+				sp->tx_skb = NULL;
+			}
+		if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+			sp->tx_cnt = 0;
+			isac_fill_fifo(sp);
+		} else
+			isac_sched_event(sp, ISAC_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
+		    & 0xf;
+		if (sp->debug & L1_DEB_ISAC) {
+			sprintf(tmp, "l1state %d", sp->ph_state);
+			debugl1(sp, tmp);
+		}
+		isac_new_ph(sp);
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (sp->debug & L1_DEB_WARN)
+			debugl1(sp, "ISAC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = readreg(sp->isac, ISAC_EXIR);
+		if (sp->debug & L1_DEB_WARN) {
+			sprintf(tmp, "ISAC EXIR %02x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+	u_char exval;
+	struct HscxState *hsp;
+	char tmp[32];
+
+
+	if (val & 0x01) {
+		hsp = sp->hs + 1;
+		exval = readreg(sp->hscx[1], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0xf8) {
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX B interrupt %x", val);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, val, 1);
+	}
+	if (val & 0x02) {
+		hsp = sp->hs;
+		exval = readreg(sp->hscx[0], HSCX_EXIR);
+		if (exval == 0x40) {
+			if (hsp->mode == 1)
+				hscx_fill_fifo(hsp);
+			else {
+				/* Here we lost an TX interrupt, so
+				   * restart transmitting the whole frame.
+				 */
+				if (hsp->tx_skb) {
+					skb_push(hsp->tx_skb, hsp->count);
+					hsp->tx_cnt += hsp->count;
+					hsp->count = 0;
+				}
+				writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+				if (sp->debug & L1_DEB_WARN) {
+					sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+					debugl1(sp, tmp);
+				}
+			}
+		} else if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A EXIR %x", exval);
+			debugl1(sp, tmp);
+		}
+	}
+	if (val & 0x04) {
+		exval = readreg(sp->hscx[0], HSCX_ISTA);
+		if (sp->debug & L1_DEB_HSCX) {
+			sprintf(tmp, "HSCX A interrupt %x", exval);
+			debugl1(sp, tmp);
+		}
+		hscx_interrupt(sp, exval, 0);
+	}
+}
+
+static void
+teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 20
+	struct IsdnCardState *sp;
+	u_char val, stat = 0;
+	int count = 0;
+
+	sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+	if (!sp) {
+		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+		return;
+	}
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+      Start_HSCX:
+	if (val) {
+		hscx_int_main(sp, val);
+		stat |= 1;
+	}
+	val = readreg(sp->isac, ISAC_ISTA);
+      Start_ISAC:
+	if (val) {
+		isac_interrupt(sp, val);
+		stat |= 2;
+	}
+	count++;
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (sp->debug & L1_DEB_HSCX)
+			debugl1(sp, "HSCX IntStat after IntRoutine");
+		goto Start_HSCX;
+	}
+	val = readreg(sp->isac, ISAC_ISTA);
+	if (val && count < MAXCOUNT) {
+		if (sp->debug & L1_DEB_ISAC)
+			debugl1(sp, "ISAC IntStat after IntRoutine");
+		goto Start_ISAC;
+	}
+	if (count >= MAXCOUNT)
+		printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
+	if (stat & 1) {
+		writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+		writereg(sp->hscx[0], HSCX_MASK, 0x0);
+		writereg(sp->hscx[1], HSCX_MASK, 0x0);
+	}
+	if (stat & 2) {
+		writereg(sp->isac, ISAC_MASK, 0xFF);
+		writereg(sp->isac, ISAC_MASK, 0x0);
+	}
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+	unsigned int adr = sp->isac;
+
+	/* 16.3 IOM 2 Mode */
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_ADF2, 0x80);
+	writereg(adr, ISAC_SQXR, 0x2f);
+	writereg(adr, ISAC_SPCR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x2);
+	writereg(adr, ISAC_STCR, 0x70);
+	writereg(adr, ISAC_MODE, 0xc9);
+	writereg(adr, ISAC_TIMR, 0x0);
+	writereg(adr, ISAC_ADF1, 0x0);
+	writereg(adr, ISAC_CMDR, 0x41);
+	writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+	writereg(adr, ISAC_MASK, 0xff);
+	writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+	struct IsdnCardState *sp = hs->sp;
+	int hscx = hs->hscx;
+
+	if (sp->debug & L1_DEB_HSCX) {
+		char tmp[40];
+		sprintf(tmp, "hscx %c mode %d ichan %d",
+			'A' + hscx, mode, ichan);
+		debugl1(sp, tmp);
+	}
+	hs->mode = mode;
+	writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+	writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+	writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+	writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+	switch (mode) {
+		case (0):
+			writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+			writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+			writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+			writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+			break;
+		case (1):
+			if (ichan == 0) {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			} else {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			}
+			writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+			writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+			break;
+		case (2):
+			if (ichan == 0) {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			} else {
+				writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+				writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+				writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+				writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+				writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+			}
+			writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+			writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+			break;
+	}
+	writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask)
+{
+	if (mask & 1)
+		release_region(card->sp->isac, 32);
+	if (mask & 2)
+		release_region(card->sp->hscx[0], 32);
+	if (mask & 4)
+		release_region(card->sp->hscx[1], 32);
+}
+
+void
+release_io_teles3(struct IsdnCard *card)
+{
+	if (card->sp->typ == ISDN_CTYPE_TELESPCMCIA)
+		release_region(card->sp->hscx[0], 97);
+	else {
+		if (card->sp->cfg_reg)
+			release_region(card->sp->cfg_reg, 8);
+		release_ioregs(card, 0x7);
+	}
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+	int val;
+	char tmp[64];
+
+	val = readreg(sp->hscx[1], HSCX_ISTA);
+	sprintf(tmp, "HSCX B ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readreg(sp->hscx[1], HSCX_EXIR);
+		sprintf(tmp, "HSCX B EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x02) {
+		val = readreg(sp->hscx[0], HSCX_EXIR);
+		sprintf(tmp, "HSCX A EXIR %x", val);
+		debugl1(sp, tmp);
+	}
+	val = readreg(sp->hscx[0], HSCX_ISTA);
+	sprintf(tmp, "HSCX A ISTA %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->hscx[1], HSCX_STAR);
+	sprintf(tmp, "HSCX B STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->hscx[0], HSCX_STAR);
+	sprintf(tmp, "HSCX A STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_STAR);
+	sprintf(tmp, "ISAC STAR %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_MODE);
+	sprintf(tmp, "ISAC MODE %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_ADF2);
+	sprintf(tmp, "ISAC ADF2 %x", val);
+	debugl1(sp, tmp);
+	val = readreg(sp->isac, ISAC_ISTA);
+	sprintf(tmp, "ISAC ISTA %x", val);
+	debugl1(sp, tmp);
+	if (val & 0x01) {
+		val = readreg(sp->isac, ISAC_EXIR);
+		sprintf(tmp, "ISAC EXIR %x", val);
+		debugl1(sp, tmp);
+	} else if (val & 0x04) {
+		val = readreg(sp->isac, ISAC_CIR0);
+		sprintf(tmp, "ISAC CIR0 %x", val);
+		debugl1(sp, tmp);
+	}
+	writereg(sp->isac, ISAC_MASK, 0);
+	writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initteles3(struct IsdnCardState *sp)
+{
+	int ret;
+	int loop = 0;
+	char tmp[40];
+
+	sp->counter = kstat.interrupts[sp->irq];
+	sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+	debugl1(sp, tmp);
+	clear_pending_ints(sp);
+	ret = get_irq(sp->cardnr, &teles3_interrupt);
+	if (ret) {
+		initisac(sp);
+		sp->modehscx(sp->hs, 0, 0);
+		writereg(sp->hscx[sp->hs->hscx], HSCX_CMDR, 0x01);
+		sp->modehscx(sp->hs + 1, 0, 0);
+		writereg(sp->hscx[(sp->hs + 1)->hscx], HSCX_CMDR, 0x01);
+		while (loop++ < 10) {
+			/* At least 1-3 irqs must happen
+			 * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+			 */
+			if (kstat.interrupts[sp->irq] > sp->counter)
+				break;
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 1;
+			schedule();
+		}
+		sprintf(tmp, "IRQ %d count %d loop %d", sp->irq,
+			kstat.interrupts[sp->irq], loop);
+		debugl1(sp, tmp);
+		if (kstat.interrupts[sp->irq] <= sp->counter) {
+			printk(KERN_WARNING
+			       "Teles3: IRQ(%d) getting no interrupts during init\n",
+			       sp->irq);
+			irq2dev_map[sp->irq] = NULL;
+			free_irq(sp->irq, NULL);
+			return (0);
+		}
+	}
+	return (ret);
+}
+
+int
+setup_teles3(struct IsdnCard *card)
+{
+	u_char cfval = 0, val, verA, verB;
+	struct IsdnCardState *sp = card->sp;
+	long flags;
+	char tmp[64];
+
+	strcpy(tmp, teles3_revision);
+	printk(KERN_NOTICE "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
+	if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP)
+	    && (sp->typ != ISDN_CTYPE_TELESPCMCIA))
+		return (0);
+
+	if (sp->typ == ISDN_CTYPE_16_3) {
+		sp->cfg_reg = card->para[1];
+		switch (sp->cfg_reg) {
+			case 0x180:
+			case 0x280:
+			case 0x380:
+				sp->cfg_reg |= 0xc00;
+				break;
+		}
+		sp->isac = sp->cfg_reg - 0x400;
+		sp->hscx[0] = sp->cfg_reg - 0xc00;
+		sp->hscx[1] = sp->cfg_reg - 0x800;
+	} else if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
+		sp->cfg_reg = 0;
+		sp->hscx[0] = card->para[1];
+		sp->hscx[1] = card->para[1] + 0x20;
+		sp->isac = card->para[1] + 0x40;
+	} else {		/* PNP */
+		sp->cfg_reg = 0;
+		sp->isac = card->para[1];
+		sp->hscx[0] = card->para[2];
+		sp->hscx[1] = card->para[2] + 0x20;
+	}
+	sp->irq = card->para[0];
+	if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
+		if (check_region((sp->hscx[0]), 97)) {
+			printk(KERN_WARNING
+			       "HiSax: %s ports %x-%x already in use\n",
+			       CardType[sp->typ],
+			       sp->hscx[0],
+			       sp->hscx[0] + 96);
+			return (0);
+		} else
+			request_region(sp->hscx[0], 97, "HiSax Teles PCMCIA");
+	} else {
+		if (sp->cfg_reg) {
+			if (check_region((sp->cfg_reg), 8)) {
+				printk(KERN_WARNING
+				       "HiSax: %s config port %x-%x already in use\n",
+				       CardType[card->typ],
+				       sp->cfg_reg,
+				       sp->cfg_reg + 8);
+				return (0);
+			} else {
+				request_region(sp->cfg_reg, 8, "teles3 cfg");
+			}
+		}
+		if (check_region((sp->isac), 32)) {
+			printk(KERN_WARNING
+			   "HiSax: %s isac ports %x-%x already in use\n",
+			       CardType[sp->typ],
+			       sp->isac,
+			       sp->isac + 32);
+			if (sp->cfg_reg) {
+				release_region(sp->cfg_reg, 8);
+			}
+			return (0);
+		} else {
+			request_region(sp->isac, 32, "HiSax isac");
+		}
+		if (check_region((sp->hscx[0]), 32)) {
+			printk(KERN_WARNING
+			 "HiSax: %s hscx A ports %x-%x already in use\n",
+			       CardType[sp->typ],
+			       sp->hscx[0],
+			       sp->hscx[0] + 32);
+			if (sp->cfg_reg) {
+				release_region(sp->cfg_reg, 8);
+			}
+			release_ioregs(card, 1);
+			return (0);
+		} else {
+			request_region(sp->hscx[0], 32, "HiSax hscx A");
+		}
+		if (check_region((sp->hscx[1]), 32)) {
+			printk(KERN_WARNING
+			 "HiSax: %s hscx B ports %x-%x already in use\n",
+			       CardType[sp->typ],
+			       sp->hscx[1],
+			       sp->hscx[1] + 32);
+			if (sp->cfg_reg) {
+				release_region(sp->cfg_reg, 8);
+			}
+			release_ioregs(card, 3);
+			return (0);
+		} else {
+			request_region(sp->hscx[1], 32, "HiSax hscx B");
+		}
+		switch (sp->irq) {
+			case 2:
+				cfval = 0x00;
+				break;
+			case 3:
+				cfval = 0x02;
+				break;
+			case 4:
+				cfval = 0x04;
+				break;
+			case 5:
+				cfval = 0x06;
+				break;
+			case 10:
+				cfval = 0x08;
+				break;
+			case 11:
+				cfval = 0x0A;
+				break;
+			case 12:
+				cfval = 0x0C;
+				break;
+			case 15:
+				cfval = 0x0E;
+				break;
+			default:
+				cfval = 0x00;
+				break;
+		}
+	}
+	if (sp->cfg_reg) {
+		if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       sp->cfg_reg + 0, val);
+			release_io_teles3(card);
+			return (0);
+		}
+		if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       sp->cfg_reg + 1, val);
+			release_io_teles3(card);
+			return (0);
+		}
+		val = bytein(sp->cfg_reg + 2);	/* 0x1e=without AB
+						   * 0x1f=with AB
+						   * 0x1c 16.3 ???
+						   * 0x46 16.3 with AB + Video (Teles-Vision)
+						 */
+		if (val != 0x46 && val != 0x1c && val != 0x1e && val != 0x1f) {
+			printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+			       sp->cfg_reg + 2, val);
+			release_io_teles3(card);
+			return (0);
+		}
+		save_flags(flags);
+		byteout(sp->cfg_reg + 4, cfval);
+		sti();
+		HZDELAY(HZ / 10 + 1);
+		byteout(sp->cfg_reg + 4, cfval | 1);
+		HZDELAY(HZ / 10 + 1);
+		restore_flags(flags);
+	} else {
+		/* Reset off for 16.3 PnP , thanks to Georg Acher */
+		save_flags(flags);
+		byteout(sp->isac + 0x1c, 1);
+		HZDELAY(2);
+		restore_flags(flags);
+	}
+	printk(KERN_NOTICE
+	       "HiSax: %s config irq:%d isac:%x  cfg:%x\n",
+	       CardType[sp->typ], sp->irq,
+	       sp->isac, sp->cfg_reg);
+	printk(KERN_NOTICE
+	       "HiSax: hscx A:%x  hscx B:%x\n",
+	       sp->hscx[0], sp->hscx[1]);
+	verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
+	verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
+	printk(KERN_INFO "Teles3: HSCX version A: %s  B: %s\n",
+	       HscxVersion(verA), HscxVersion(verB));
+	val = readreg(sp->isac, ISAC_RBCH);
+	printk(KERN_INFO "Teles3: ISAC %s\n",
+	       ISACVersion(val));
+	if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+		printk(KERN_WARNING
+		       "Teles3: wrong HSCX versions check IO address\n");
+		release_io_teles3(card);
+		return (0);
+	}
+	sp->modehscx = &modehscx;
+	sp->ph_command = &ph_command;
+	sp->hscx_fill_fifo = &hscx_fill_fifo;
+	sp->isac_fill_fifo = &isac_fill_fifo;
+	return (1);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/hisax/teles3.h linux-2.0.31-pre3/drivers/isdn/hisax/teles3.h
--- linux-2.0.31-pre2/drivers/isdn/hisax/teles3.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/hisax/teles3.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,21 @@
+/* $Id: teles3.h,v 1.2 1997/01/21 22:27:14 keil Exp $
+ *
+ * teles3.h   Header for Teles 16.3 PNP & compatible
+ *
+ * Author	Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles3.h,v $
+ * Revision 1.2  1997/01/21 22:27:14  keil
+ * cleanups
+ *
+ * Revision 1.1  1996/10/13 20:03:49  keil
+ * Initial revision
+ *
+ *
+*/
+
+extern	void teles3_report(struct IsdnCardState *sp);
+extern  void release_io_teles3(struct IsdnCard *card);
+extern	int  setup_teles3(struct IsdnCard *card);
+extern  int  initteles3(struct IsdnCardState *sp);
diff -urN linux-2.0.31-pre2/drivers/isdn/icn/icn.c linux-2.0.31-pre3/drivers/isdn/icn/icn.c
--- linux-2.0.31-pre2/drivers/isdn/icn/icn.c	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/icn/icn.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,5 +1,5 @@
-/* $Id: icn.c,v 1.31 1996/11/13 02:36:25 fritz Exp $
- *
+/* $Id: icn.c,v 1.45 1997/06/21 10:42:06 fritz Exp $
+
  * ISDN low-level module for the ICN active ISDN-Card.
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
@@ -16,9 +16,54 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: icn.c,v $
+ * Revision 1.45  1997/06/21 10:42:06  fritz
+ * Added availability to select leased mode on only one channel.
+ *
+ * Revision 1.44  1997/03/30 16:51:26  calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.43  1997/03/21 18:27:04  fritz
+ * Corrected parsing of incoming setup.
+ *
+ * Revision 1.42  1997/03/05 21:13:18  fritz
+ * Bugfix: sndcount was not reset on hangup.
+ *
+ * Revision 1.41  1997/02/24 23:34:29  fritz
+ * Bugfix in Layer1 error-recovery.
+ *
+ * Revision 1.40  1997/02/23 23:34:45  fritz
+ * Minor bugfixes in debugging code.
+ *
+ * Revision 1.39  1997/02/23 16:21:56  fritz
+ * Bugfix: Check for NULL pointer in icn_parse_status().
+ *
+ * Revision 1.38  1997/02/11 18:29:31  fritz
+ * Bugfix in D64S initialization.
+ *
+ * Revision 1.37  1997/02/10 22:43:20  fritz
+ * Added plan and screen elements on ISDN_STAT_ICALL
+ *
+ * Revision 1.36  1997/02/10 21:31:20  fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.35  1997/02/10 10:10:28  fritz
+ * Changes for Kernel 2.1.X compatibility.
+ * Enhanced initialization, can recover from
+ * misconfiguration by other autoprobing drivers.
+ *
+ * Revision 1.34  1997/01/29 22:34:44  fritz
+ * Cleanup, Corrected D64S setup of 2nd channel.
+ *
+ * Revision 1.33  1996/12/05 20:31:48  tsbogend
+ * added handling of L2: DATA LINK LOST messages
+ *
+ * Revision 1.32  1996/11/14 23:49:18  fritz
+ * Bugfix: copy_to_user/copy_from_user mismatch in debugging-ioctl.
+ *
  * Revision 1.31  1996/11/13 02:36:25  fritz
  * Fixed a race condition in writecmd.
  * Some optimizations and cleanup.
@@ -148,21 +193,25 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.31 $";
+*revision = "$Revision: 1.45 $";
 
 static int icn_addcard(int, char *, char *);
 
 /*
- * Free queue completely.
+ * Free send-queue completely.
  * Parameter:
- *   queue = pointer to queue-head
+ *   card   = pointer to card struct
+ *   channel = channel number
  */
-static void icn_free_queue(struct sk_buff_head *queue)
+static void
+icn_free_queue(icn_card * card, int channel)
 {
-        struct sk_buff *skb;
+	struct sk_buff_head *queue = &card->spqueue[channel];
+	struct sk_buff *skb;
 
-        while ((skb = skb_dequeue(queue)))
-                dev_kfree_skb(skb, FREE_WRITE);
+	while ((skb = skb_dequeue(queue)))
+		dev_kfree_skb(skb, FREE_WRITE);
+	card->sndcount[channel] = 0;
 }
 
 /* Put a value into a shift-register, highest bit first.
@@ -172,53 +221,57 @@
  *            firstbit = Bit-Number of highest bit
  *            bitcount = Number of bits to output
  */
-static inline void icn_shiftout(unsigned short port,
-                     unsigned long val,
-                     int firstbit,
-                     int bitcount)
+static inline void
+icn_shiftout(unsigned short port,
+	     unsigned long val,
+	     int firstbit,
+	     int bitcount)
 {
 
-        register u_char s;
-        register u_char c;
+	register u_char s;
+	register u_char c;
 
-        for (s = firstbit, c = bitcount; c > 0; s--, c--)
-                OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
+	for (s = firstbit, c = bitcount; c > 0; s--, c--)
+		OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
 }
 
 /*
  * disable a cards shared memory
  */
-static inline void icn_disable_ram(icn_card *card)
+static inline void
+icn_disable_ram(icn_card * card)
 {
-        OUTB_P(0, ICN_MAPRAM);
+	OUTB_P(0, ICN_MAPRAM);
 }
 
 /*
  * enable a cards shared memory
  */
-static inline void icn_enable_ram(icn_card *card)
+static inline void
+icn_enable_ram(icn_card * card)
 {
-        OUTB_P(0xff, ICN_MAPRAM);
+	OUTB_P(0xff, ICN_MAPRAM);
 }
 
 /*
  * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
  */
-static inline void icn_map_channel(icn_card *card, int channel)
+static inline void
+icn_map_channel(icn_card * card, int channel)
 {
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
+	printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
 #endif
-        if ((channel == dev.channel) && (card == dev.mcard))
-                return;
-        if (dev.mcard)
-                icn_disable_ram(dev.mcard);
-        icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);        /* Select Bank          */
-        icn_enable_ram(card);
-        dev.mcard = card;
-        dev.channel = channel;
+	if ((channel == dev.channel) && (card == dev.mcard))
+		return;
+	if (dev.mcard)
+		icn_disable_ram(dev.mcard);
+	icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);	/* Select Bank          */
+	icn_enable_ram(card);
+	dev.mcard = card;
+	dev.channel = channel;
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "icn_map_channel done\n");
+	printk(KERN_DEBUG "icn_map_channel done\n");
 #endif
 }
 
@@ -227,98 +280,102 @@
  * Return 0 if requested card/channel is unmapped (failure).
  * Return 1 on success.
  */
-static inline int icn_lock_channel(icn_card *card, int channel)
+static inline int
+icn_lock_channel(icn_card * card, int channel)
 {
-        register int retval;
-        ulong flags;
+	register int retval;
+	ulong flags;
 
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
+	printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
 #endif
-        save_flags(flags);
-        cli();
-        if ((dev.channel == channel) && (card == dev.mcard)) {
-                dev.chanlock++;
-                retval = 1;
+	save_flags(flags);
+	cli();
+	if ((dev.channel == channel) && (card == dev.mcard)) {
+		dev.chanlock++;
+		retval = 1;
 #ifdef MAP_DEBUG
-                printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
+		printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
 #endif
-        } else {
-                retval = 0;
+	} else {
+		retval = 0;
 #ifdef MAP_DEBUG
-                printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel);
+		printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
 #endif
-        }
-        restore_flags(flags);
-        return retval;
+	}
+	restore_flags(flags);
+	return retval;
 }
 
 /*
  * Release current card/channel lock
  */
-static inline void icn_release_channel(void)
+static inline void
+icn_release_channel(void)
 {
-        ulong flags;
+	ulong flags;
 
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock);
+	printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
 #endif
-        save_flags(flags);
-        cli();
-        if (dev.chanlock > 0)
-                dev.chanlock--;
-        restore_flags(flags);
+	save_flags(flags);
+	cli();
+	if (dev.chanlock > 0)
+		dev.chanlock--;
+	restore_flags(flags);
 }
 
 /*
  * Try to map and lock a cards channel.
  * Return 1 on success, 0 on failure.
  */
-static inline int icn_trymaplock_channel(icn_card *card, int channel)
+static inline int
+icn_trymaplock_channel(icn_card * card, int channel)
 {
-        ulong flags;
+	ulong flags;
 
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
-               dev.chanlock);
+	printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
+	       dev.chanlock);
 #endif
-        save_flags(flags);
-        cli();
-        if ((!dev.chanlock) ||
-            ((dev.channel == channel) && (dev.mcard == card))) {
-                dev.chanlock++;
-                icn_map_channel(card,channel);
-                restore_flags(flags);
+	save_flags(flags);
+	cli();
+	if ((!dev.chanlock) ||
+	    ((dev.channel == channel) && (dev.mcard == card))) {
+		dev.chanlock++;
+		icn_map_channel(card, channel);
+		restore_flags(flags);
 #ifdef MAP_DEBUG
-                printk(KERN_DEBUG "trymaplock %d OK\n", channel);
+		printk(KERN_DEBUG "trymaplock %d OK\n", channel);
 #endif
-                return 1;
-        }
-        restore_flags(flags);
+		return 1;
+	}
+	restore_flags(flags);
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
+	printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
 #endif
-        return 0;
+	return 0;
 }
 
 /*
  * Release current card/channel lock,
  * then map same or other channel without locking.
  */
-static inline void icn_maprelease_channel(icn_card *card, int channel)
+static inline void
+icn_maprelease_channel(icn_card * card, int channel)
 {
-        ulong flags;
+	ulong flags;
 
 #ifdef MAP_DEBUG
-        printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
+	printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
 #endif
-        save_flags(flags);
-        cli();
-        if (dev.chanlock > 0)
-                dev.chanlock--;
-        if (!dev.chanlock)
-                icn_map_channel(card,channel);
-        restore_flags(flags);
+	save_flags(flags);
+	cli();
+	if (dev.chanlock > 0)
+		dev.chanlock--;
+	if (!dev.chanlock)
+		icn_map_channel(card, channel);
+	restore_flags(flags);
 }
 
 /* Get Data from the B-Channel, assemble fragmented packets and put them
@@ -326,47 +383,48 @@
  * This routine is called via timer-callback from icn_pollbchan().
  */
 
-static void icn_pollbchan_receive(int channel, icn_card *card)
+static void
+icn_pollbchan_receive(int channel, icn_card * card)
 {
-        int mch = channel + ((card->secondhalf) ? 2 : 0);
-        int eflag;
-        int cnt;
+	int mch = channel + ((card->secondhalf) ? 2 : 0);
+	int eflag;
+	int cnt;
 	struct sk_buff *skb;
 
-        if (icn_trymaplock_channel(card,mch)) {
-                while (rbavl) {
-                        cnt = readb(&rbuf_l);
-                        if ((card->rcvidx[channel] + cnt) > 4000) {
-                                printk(KERN_WARNING 
-                                       "icn: (%s) bogus packet on ch%d, dropping.\n",
-                                       CID,
-                                       channel + 1);
-                                card->rcvidx[channel] = 0;
-                                eflag = 0;
-                        } else {
-                                memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
-                                              &rbuf_d, cnt);
-                                card->rcvidx[channel] += cnt;
-                                eflag = readb(&rbuf_f);
-                        }
-                        rbnext;
-                        icn_maprelease_channel(card, mch & 2);
-                        if (!eflag) {
-                                if ((cnt = card->rcvidx[channel])) {
-                                        if (!(skb = dev_alloc_skb(cnt))) {
-                                                printk(KERN_WARNING "ïcn: receive out of memory\n");
-                                                break;
-                                        }
-                                        memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt); 
-                                        card->rcvidx[channel] = 0;
-                                        card->interface.rcvcallb_skb(card->myid, channel, skb);
-                                }
-                        }
-                        if (!icn_trymaplock_channel(card, mch))
-                                break;
-                }
-                icn_maprelease_channel(card, mch & 2);
-        }
+	if (icn_trymaplock_channel(card, mch)) {
+		while (rbavl) {
+			cnt = readb(&rbuf_l);
+			if ((card->rcvidx[channel] + cnt) > 4000) {
+				printk(KERN_WARNING
+				       "icn: (%s) bogus packet on ch%d, dropping.\n",
+				       CID,
+				       channel + 1);
+				card->rcvidx[channel] = 0;
+				eflag = 0;
+			} else {
+				memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
+					      &rbuf_d, cnt);
+				card->rcvidx[channel] += cnt;
+				eflag = readb(&rbuf_f);
+			}
+			rbnext;
+			icn_maprelease_channel(card, mch & 2);
+			if (!eflag) {
+				if ((cnt = card->rcvidx[channel])) {
+					if (!(skb = dev_alloc_skb(cnt))) {
+						printk(KERN_WARNING "ïcn: receive out of memory\n");
+						break;
+					}
+					memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
+					card->rcvidx[channel] = 0;
+					card->interface.rcvcallb_skb(card->myid, channel, skb);
+				}
+			}
+			if (!icn_trymaplock_channel(card, mch))
+				break;
+		}
+		icn_maprelease_channel(card, mch & 2);
+	}
 }
 
 /* Send data-packet to B-Channel, split it up into fragments of
@@ -376,58 +434,59 @@
  * directly from icn_sendbuf().
  */
 
-static void icn_pollbchan_send(int channel, icn_card *card)
+static void
+icn_pollbchan_send(int channel, icn_card * card)
 {
-        int mch = channel + ((card->secondhalf) ? 2 : 0);
-        int cnt;
+	int mch = channel + ((card->secondhalf) ? 2 : 0);
+	int cnt;
 	unsigned long flags;
-        struct sk_buff *skb;
-        isdn_ctrl cmd;
+	struct sk_buff *skb;
+	isdn_ctrl cmd;
 
-        if (!(card->sndcount[channel] ||
-             skb_queue_len(&card->spqueue[channel])))
-                return;
-        if (icn_trymaplock_channel(card,mch)) {
-                while (sbfree && (card->sndcount[channel] ||
-                                  skb_queue_len(&card->spqueue[channel]))) {
-                        save_flags(flags);
-                        cli();
-                        if (card->xmit_lock[channel]) {
-                                restore_flags(flags);
-                                break;
-                        }
-                        card->xmit_lock[channel]++;
-                        restore_flags(flags);
-                        skb = skb_dequeue(&card->spqueue[channel]);
-                        if (!skb)
-                                break;
-		        if (skb->len > ICN_FRAGSIZE) {
-			    writeb (0xff, &sbuf_f);
-			    cnt = ICN_FRAGSIZE;
+	if (!(card->sndcount[channel] ||
+	      skb_queue_len(&card->spqueue[channel])))
+		return;
+	if (icn_trymaplock_channel(card, mch)) {
+		while (sbfree && (card->sndcount[channel] ||
+			       skb_queue_len(&card->spqueue[channel]))) {
+			save_flags(flags);
+			cli();
+			if (card->xmit_lock[channel]) {
+				restore_flags(flags);
+				break;
+			}
+			card->xmit_lock[channel]++;
+			restore_flags(flags);
+			skb = skb_dequeue(&card->spqueue[channel]);
+			if (!skb)
+				break;
+			if (skb->len > ICN_FRAGSIZE) {
+				writeb(0xff, &sbuf_f);
+				cnt = ICN_FRAGSIZE;
 			} else {
-			    writeb (0x0, &sbuf_f);
-			    cnt = skb->len;
+				writeb(0x0, &sbuf_f);
+				cnt = skb->len;
 			}
-		        writeb (cnt, &sbuf_l);		    
-                        memcpy_toio(&sbuf_d, skb->data, cnt);
-                        skb_pull(skb, cnt);
-                        card->sndcount[channel] -= cnt;
-                        sbnext;        /* switch to next buffer        */
-                        icn_maprelease_channel(card, mch & 2);
-                        if (!skb->len) {
-                                dev_kfree_skb(skb, FREE_WRITE);
-                                cmd.command = ISDN_STAT_BSENT;
-                                cmd.driver = card->myid;
-                                cmd.arg = channel;
-                                card->interface.statcallb(&cmd);
-                        } else
-                                skb_queue_head(&card->spqueue[channel], skb);
-                        card->xmit_lock[channel] = 0;
-                        if (!icn_trymaplock_channel(card, mch))
-                                break;
-                }
-                icn_maprelease_channel(card, mch & 2);
-        }
+			writeb(cnt, &sbuf_l);
+			memcpy_toio(&sbuf_d, skb->data, cnt);
+			skb_pull(skb, cnt);
+			card->sndcount[channel] -= cnt;
+			sbnext; /* switch to next buffer        */
+			icn_maprelease_channel(card, mch & 2);
+			if (!skb->len) {
+				dev_kfree_skb(skb, FREE_WRITE);
+				cmd.command = ISDN_STAT_BSENT;
+				cmd.driver = card->myid;
+				cmd.arg = channel;
+				card->interface.statcallb(&cmd);
+			} else
+				skb_queue_head(&card->spqueue[channel], skb);
+			card->xmit_lock[channel] = 0;
+			if (!icn_trymaplock_channel(card, mch))
+				break;
+		}
+		icn_maprelease_channel(card, mch & 2);
+	}
 }
 
 /* Send/Receive Data to/from the B-Channel.
@@ -435,54 +494,61 @@
  * It schedules itself while any B-Channel is open.
  */
 
-static void icn_pollbchan(unsigned long data)
+static void
+icn_pollbchan(unsigned long data)
 {
-        icn_card *card = (icn_card *)data;
-        unsigned long flags;
+	icn_card *card = (icn_card *) data;
+	unsigned long flags;
 
-                if (card->flags & ICN_FLAGS_B1ACTIVE) {
-                        icn_pollbchan_receive(0, card);
-                        icn_pollbchan_send(0, card);
-                }
-                if (card->flags & ICN_FLAGS_B2ACTIVE) {
-                        icn_pollbchan_receive(1, card);
-                        icn_pollbchan_send(1, card);
-                }
-                if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
-                        /* schedule b-channel polling again */
-                        save_flags(flags);
-                        cli();
-                        del_timer(&card->rb_timer);
-                        card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-                        add_timer(&card->rb_timer);
-                        card->flags |= ICN_FLAGS_RBTIMER;
-                        restore_flags(flags);
-                } else
-                        card->flags &= ~ICN_FLAGS_RBTIMER;
+	if (card->flags & ICN_FLAGS_B1ACTIVE) {
+		icn_pollbchan_receive(0, card);
+		icn_pollbchan_send(0, card);
+	}
+	if (card->flags & ICN_FLAGS_B2ACTIVE) {
+		icn_pollbchan_receive(1, card);
+		icn_pollbchan_send(1, card);
+	}
+	if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
+		/* schedule b-channel polling again */
+		save_flags(flags);
+		cli();
+		del_timer(&card->rb_timer);
+		card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+		add_timer(&card->rb_timer);
+		card->flags |= ICN_FLAGS_RBTIMER;
+		restore_flags(flags);
+	} else
+		card->flags &= ~ICN_FLAGS_RBTIMER;
 }
 
 typedef struct icn_stat {
-        char *statstr;
-        int  command;
-        int  action;
+	char *statstr;
+	int command;
+	int action;
 } icn_stat;
-
-static icn_stat icn_stat_table[] = {
-        {"BCON_",          ISDN_STAT_BCONN, 1}, /* B-Channel connected        */
-        {"BDIS_",          ISDN_STAT_BHUP,  2}, /* B-Channel disconnected     */
-        {"DCON_",          ISDN_STAT_DCONN, 0}, /* D-Channel connected        */
-        {"DDIS_",          ISDN_STAT_DHUP,  0}, /* D-Channel disconnected     */
-        {"DCAL_I",         ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line  */
-        {"DSCA_I",         ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV     */
-        {"FCALL",          ISDN_STAT_ICALL, 4}, /* Leased line connection up  */
-        {"CIF",            ISDN_STAT_CINF,  5}, /* Charge-info, 1TR6-type     */
-        {"AOC",            ISDN_STAT_CINF,  6}, /* Charge-info, DSS1-type     */
-        {"CAU",            ISDN_STAT_CAUSE, 7}, /* Cause code                 */
-        {"TEI OK",         ISDN_STAT_RUN,   0}, /* Card connected to wallplug */
-        {"NO D-CHAN",      ISDN_STAT_NODCH, 0}, /* No D-channel available     */
-        {"E_L1: ACT FAIL", ISDN_STAT_BHUP,  8}, /* Layer-1 activation failed  */
-        {NULL,             0             , -1}
+/* *INDENT-OFF* */
+static icn_stat icn_stat_table[] =
+{
+	{"BCON_",          ISDN_STAT_BCONN, 1},	/* B-Channel connected        */
+	{"BDIS_",          ISDN_STAT_BHUP,  2},	/* B-Channel disconnected     */
+	{"DCON_",          ISDN_STAT_DCONN, 0},	/* D-Channel connected        */
+	{"DDIS_",          ISDN_STAT_DHUP,  0},	/* D-Channel disconnected     */
+	{"DCAL_I",         ISDN_STAT_ICALL, 3},	/* Incoming call dialup-line  */
+	{"DSCA_I",         ISDN_STAT_ICALL, 3},	/* Incoming call 1TR6-SPV     */
+	{"FCALL",          ISDN_STAT_ICALL, 4},	/* Leased line connection up  */
+	{"CIF",            ISDN_STAT_CINF,  5},	/* Charge-info, 1TR6-type     */
+	{"AOC",            ISDN_STAT_CINF,  6},	/* Charge-info, DSS1-type     */
+	{"CAU",            ISDN_STAT_CAUSE, 7},	/* Cause code                 */
+	{"TEI OK",         ISDN_STAT_RUN,   0},	/* Card connected to wallplug */
+	{"NO D-CHAN",      ISDN_STAT_NODCH, 0},	/* No D-channel available     */
+	{"E_L1: ACT FAIL", ISDN_STAT_BHUP,  8},	/* Layer-1 activation failed  */
+	{"E_L2: DATA LIN", ISDN_STAT_BHUP,  8},	/* Layer-2 data link lost     */
+	{"E_L1: ACTIVATION FAILED",
+					   ISDN_STAT_BHUP,  8},	/* Layer-1 activation failed  */
+	{NULL, 0, -1}
 };
+/* *INDENT-ON* */
+
 
 /*
  * Check Statusqueue-Pointer from isdn-cards.
@@ -494,199 +560,244 @@
  * This routine is called periodically via timer.
  */
 
-static int icn_parse_status(u_char *status, int channel, icn_card *card)
+static int
+icn_parse_status(u_char * status, int channel, icn_card * card)
+{
+	icn_stat *s = icn_stat_table;
+	int action = -1;
+	int dflag = 0;
+	unsigned long flags;
+	isdn_ctrl cmd;
+
+	while (s->statstr) {
+		if (!strncmp(status, s->statstr, strlen(s->statstr))) {
+			cmd.command = s->command;
+			action = s->action;
+			break;
+		}
+		s++;
+	}
+	if (action == -1)
+		return 0;
+	cmd.driver = card->myid;
+	cmd.arg = channel;
+	switch (action) {
+		case 1:
+			card->flags |= (channel) ?
+			    ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
+			break;
+		case 2:
+			card->flags &= ~((channel) ?
+				ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
+			icn_free_queue(card, channel);
+			save_flags(flags);
+			cli();
+			card->rcvidx[channel] = 0;
+			restore_flags(flags);
+			dflag |= (channel + 1);
+			break;
+		case 3:
+			{
+				char *t = status + 6;
+				char *s = strpbrk(t, ",");
+
+				*s++ = '\0';
+				strncpy(cmd.parm.setup.phone, t,
+					sizeof(cmd.parm.setup.phone));
+				s = strpbrk(t = s, ",");
+				*s++ = '\0';
+				if (!strlen(t))
+					cmd.parm.setup.si1 = 0;
+				else
+					cmd.parm.setup.si1 =
+					    simple_strtoul(t, NULL, 10);
+				s = strpbrk(t = s, ",");
+				*s++ = '\0';
+				if (!strlen(t))
+					cmd.parm.setup.si2 = 0;
+				else
+					cmd.parm.setup.si2 =
+					    simple_strtoul(t, NULL, 10);
+				strncpy(cmd.parm.setup.eazmsn, s,
+					sizeof(cmd.parm.setup.eazmsn));
+			}
+			cmd.parm.setup.plan = 0;
+			cmd.parm.setup.screen = 0;
+			break;
+		case 4:
+			sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
+			sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
+			cmd.parm.setup.si1 = 7;
+			cmd.parm.setup.si2 = 0;
+			cmd.parm.setup.plan = 0;
+			cmd.parm.setup.screen = 0;
+			break;
+		case 5:
+			strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1);
+			break;
+		case 6:
+			sprintf(cmd.parm.num, "%d",
+			     (int) simple_strtoul(status + 7, NULL, 16));
+			break;
+		case 7:
+			status += 3;
+			if (strlen(status) == 4)
+				sprintf(cmd.parm.num, "%s%c%c",
+				     status + 2, *status, *(status + 1));
+			else
+				strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1);
+			break;
+		case 8:
+			dflag = 3;
+			card->flags &= ~ICN_FLAGS_B1ACTIVE;
+			icn_free_queue(card, 0);
+			save_flags(flags);
+			cli();
+			card->rcvidx[0] = 0;
+			restore_flags(flags);
+			cmd.arg = 0;
+			cmd.driver = card->myid;
+			card->interface.statcallb(&cmd);
+			cmd.command = ISDN_STAT_DHUP;
+			cmd.arg = 0;
+			cmd.driver = card->myid;
+			card->interface.statcallb(&cmd);
+			cmd.command = ISDN_STAT_BHUP;
+			card->flags &= ~ICN_FLAGS_B2ACTIVE;
+			icn_free_queue(card, 1);
+			save_flags(flags);
+			cli();
+			card->rcvidx[1] = 0;
+			restore_flags(flags);
+			cmd.arg = 1;
+			cmd.driver = card->myid;
+			card->interface.statcallb(&cmd);
+			cmd.command = ISDN_STAT_DHUP;
+			cmd.arg = 1;
+			cmd.driver = card->myid;
+			break;
+	}
+	card->interface.statcallb(&cmd);
+	return dflag;
+}
+
+static void
+icn_putmsg(icn_card * card, unsigned char c)
+{
+	ulong flags;
+
+	save_flags(flags);
+	cli();
+	*card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+	if (card->msg_buf_write == card->msg_buf_read) {
+		if (++card->msg_buf_read > card->msg_buf_end)
+			card->msg_buf_read = card->msg_buf;
+	}
+	if (card->msg_buf_write > card->msg_buf_end)
+		card->msg_buf_write = card->msg_buf;
+	restore_flags(flags);
+}
+
+static void
+icn_polldchan(unsigned long data)
 {
-        icn_stat  *s = icn_stat_table;
-        int       action = -1;
-        int       dflag  = 0;
-        unsigned long flags;
-        isdn_ctrl cmd;
-
-        while (s->statstr) {
-                if (!strncmp(status,s->statstr,strlen(s->statstr))) {
-                        cmd.command = s->command;
-                        action = s->action;
-                        break;
-                }
-                s++;
-        }
-        if (action==-1)
-                return 0;
-        cmd.driver = card->myid;
-        cmd.arg = channel;
-        switch (action) {
-                case 1:
-                        card->flags |= (channel)?
-                                ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE;
-                        break;
-                case 2:
-                        card->flags &= ~((channel)?
-                                ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
-                        icn_free_queue(&card->spqueue[channel]);
-                        save_flags(flags);
-                        cli();
-                        card->rcvidx[channel] = 0;
-                        restore_flags(flags);
-                        dflag |= (channel+1);
-                        break;
-                case 3:
-                        strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1);
-                        break;
-                case 4:
-                        sprintf(cmd.num,"LEASED%d,07,00,%d",
-                                 card->myid,channel+1);
-                        break;
-                case 5:
-                        strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1);
-                        break;
-                case 6:
-                        sprintf(cmd.num,"%d",
-                                (int)simple_strtoul(status + 7,NULL,16));
-                        break;
-                case 7:
-                        status += 3;
-                        if (strlen(status)==4)
-                                sprintf(cmd.num,"%s%c%c",
-                                        status+2,*status,*(status+1));
-                        else
-                                strncpy(cmd.num, status+1, sizeof(cmd.num) - 1);
-                        break;
-                case 8:
-                        cmd.arg = 0;
-                        cmd.driver = card->myid;
-                        card->interface.statcallb(&cmd);
-                        cmd.command = ISDN_STAT_DHUP;
-                        cmd.arg = 0;
-                        cmd.driver = card->myid;
-                        card->interface.statcallb(&cmd);
-                        cmd.command = ISDN_STAT_BHUP;
-                        cmd.arg = 1;
-                        cmd.driver = card->myid;
-                        card->interface.statcallb(&cmd);
-                        cmd.command = ISDN_STAT_DHUP;
-                        cmd.arg = 1;
-                        cmd.driver = card->myid;
-                        break;
-        }
-        card->interface.statcallb(&cmd);
-        return dflag;
-}
-
-static void icn_putmsg(icn_card *card, unsigned char c)
-{
-        ulong flags;
-
-        save_flags(flags);
-        cli();
-        *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
-        if (card->msg_buf_write == card->msg_buf_read) {
-                if (++card->msg_buf_read > card->msg_buf_end)
-                card->msg_buf_read = card->msg_buf;
-        }
-        if (card->msg_buf_write > card->msg_buf_end)
-                card->msg_buf_write = card->msg_buf;
-        restore_flags(flags);
-}
-
-static void icn_polldchan(unsigned long data)
-{
-        icn_card *card = (icn_card *)data;
-        int mch = card->secondhalf ? 2 : 0;
-        int avail = 0;
-        int dflag = 0;
-        int left;
-        u_char c;
-        int ch;
-        int flags;
-        int i;
-        u_char *p;
-        isdn_ctrl cmd;
-
-        if (icn_trymaplock_channel(card,mch)) {
-                avail = msg_avail;
-                for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
-                        c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
-                        icn_putmsg(card, c);
-                        if (c == 0xff) {
-                                card->imsg[card->iptr] = 0;
-                                card->iptr = 0;
-                                if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
-                                    card->imsg[1] <= '2' && card->imsg[2] == ';') {
-                                        ch = (card->imsg[1] - '0') - 1;
-                                        p = &card->imsg[3];
-                                        dflag |= icn_parse_status(p, ch, card);
-                                } else {
-                                        p = card->imsg;
-                                        if (!strncmp(p, "DRV1.", 5)) {
-                                                u_char vstr[10];
-                                                u_char *q = vstr;
-
-                                                printk(KERN_INFO "icn: (%s) %s\n",CID,p);
-                                                if (!strncmp(p + 7, "TC", 2)) {
-                                                        card->ptype = ISDN_PTYPE_1TR6;
-                                                        card->interface.features |= ISDN_FEATURE_P_1TR6;
-                                                        printk(KERN_INFO
-                                                               "icn: (%s) 1TR6-Protocol loaded and running\n",CID);
-                                                }
-                                                if (!strncmp(p + 7, "EC", 2)) {
-                                                        card->ptype = ISDN_PTYPE_EURO;
-                                                        card->interface.features |= ISDN_FEATURE_P_EURO;
-                                                        printk(KERN_INFO
-                                                               "icn: (%s) Euro-Protocol loaded and running\n",CID);
-                                                }
-                                                p = strstr(card->imsg,"BRV") + 3;
-                                                while (*p) {
-                                                        if (*p>='0' && *p<='9')
-                                                                *q++ = *p;
-                                                        p++;
-                                                }
-                                                *q = '\0';
-                                                strcat(vstr,"000");
-                                                vstr[3] = '\0';
-                                                card->fw_rev = (int)simple_strtoul(vstr,NULL,10);
-                                                continue;
-                                                
-                                        }
-                                }
-                        } else {
-                                card->imsg[card->iptr] = c;
-                                if (card->iptr < 59)
-                                        card->iptr++;
-                        }
-                }
-                writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
-                icn_release_channel();
-        }
-        if (avail) {
-                cmd.command = ISDN_STAT_STAVAIL;
-                cmd.driver = card->myid;
-                cmd.arg = avail;
-                card->interface.statcallb(&cmd);
-        }
-        if (dflag & 1)
-                card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
-        if (dflag & 2)
-                card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
-        if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
-                if (!(card->flags & ICN_FLAGS_RBTIMER)) {
-                        /* schedule b-channel polling */
-                        card->flags |= ICN_FLAGS_RBTIMER;
-                        save_flags(flags);
-                        cli();
-                        del_timer(&card->rb_timer);
-                        card->rb_timer.function = icn_pollbchan;
-                        card->rb_timer.data = (unsigned long)card;
-                        card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-                        add_timer(&card->rb_timer);
-                        restore_flags(flags);
-                }
-        /* schedule again */
-        save_flags(flags);
-        cli();
-        del_timer(&card->st_timer);
-        card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-        add_timer(&card->st_timer);
-        restore_flags(flags);
+	icn_card *card = (icn_card *) data;
+	int mch = card->secondhalf ? 2 : 0;
+	int avail = 0;
+	int dflag = 0;
+	int left;
+	u_char c;
+	int ch;
+	int flags;
+	int i;
+	u_char *p;
+	isdn_ctrl cmd;
+
+	if (icn_trymaplock_channel(card, mch)) {
+		avail = msg_avail;
+		for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
+			c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
+			icn_putmsg(card, c);
+			if (c == 0xff) {
+				card->imsg[card->iptr] = 0;
+				card->iptr = 0;
+				if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+				    card->imsg[1] <= '2' && card->imsg[2] == ';') {
+					ch = (card->imsg[1] - '0') - 1;
+					p = &card->imsg[3];
+					dflag |= icn_parse_status(p, ch, card);
+				} else {
+					p = card->imsg;
+					if (!strncmp(p, "DRV1.", 5)) {
+						u_char vstr[10];
+						u_char *q = vstr;
+
+						printk(KERN_INFO "icn: (%s) %s\n", CID, p);
+						if (!strncmp(p + 7, "TC", 2)) {
+							card->ptype = ISDN_PTYPE_1TR6;
+							card->interface.features |= ISDN_FEATURE_P_1TR6;
+							printk(KERN_INFO
+							       "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
+						}
+						if (!strncmp(p + 7, "EC", 2)) {
+							card->ptype = ISDN_PTYPE_EURO;
+							card->interface.features |= ISDN_FEATURE_P_EURO;
+							printk(KERN_INFO
+							       "icn: (%s) Euro-Protocol loaded and running\n", CID);
+						}
+						p = strstr(card->imsg, "BRV") + 3;
+						while (*p) {
+							if (*p >= '0' && *p <= '9')
+								*q++ = *p;
+							p++;
+						}
+						*q = '\0';
+						strcat(vstr, "000");
+						vstr[3] = '\0';
+						card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
+						continue;
+
+					}
+				}
+			} else {
+				card->imsg[card->iptr] = c;
+				if (card->iptr < 59)
+					card->iptr++;
+			}
+		}
+		writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
+		icn_release_channel();
+	}
+	if (avail) {
+		cmd.command = ISDN_STAT_STAVAIL;
+		cmd.driver = card->myid;
+		cmd.arg = avail;
+		card->interface.statcallb(&cmd);
+	}
+	if (dflag & 1)
+		card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
+	if (dflag & 2)
+		card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
+	if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
+		if (!(card->flags & ICN_FLAGS_RBTIMER)) {
+			/* schedule b-channel polling */
+			card->flags |= ICN_FLAGS_RBTIMER;
+			save_flags(flags);
+			cli();
+			del_timer(&card->rb_timer);
+			card->rb_timer.function = icn_pollbchan;
+			card->rb_timer.data = (unsigned long) card;
+			card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+			add_timer(&card->rb_timer);
+			restore_flags(flags);
+		}
+	/* schedule again */
+	save_flags(flags);
+	cli();
+	del_timer(&card->st_timer);
+	card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+	add_timer(&card->st_timer);
+	restore_flags(flags);
 }
 
 /* Append a packet to the transmit buffer-queue.
@@ -698,34 +809,35 @@
  *   Number of bytes transferred, -E??? on error
  */
 
-static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
+static int
+icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
 {
-        int len = skb->len;
-        unsigned long flags;
-        struct sk_buff *nskb;
-
-        if (len > 4000) {
-                printk(KERN_WARNING
-                       "icn: Send packet too large\n");
-                return -EINVAL;
-        }
-        if (len) {
-                if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE))
-                        return 0;
-                if (card->sndcount[channel] > ICN_MAX_SQUEUE)
-                        return 0;
-                save_flags(flags);
-                cli();
-                nskb = skb_clone(skb, GFP_ATOMIC);
-                if (nskb) {
-                        skb_queue_tail(&card->spqueue[channel], nskb);
-                        dev_kfree_skb(skb, FREE_WRITE);
-                } else
-                        len = 0;
-                card->sndcount[channel] += len;
-                restore_flags(flags);
-        }
-        return len;
+	int len = skb->len;
+	unsigned long flags;
+	struct sk_buff *nskb;
+
+	if (len > 4000) {
+		printk(KERN_WARNING
+		       "icn: Send packet too large\n");
+		return -EINVAL;
+	}
+	if (len) {
+		if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
+			return 0;
+		if (card->sndcount[channel] > ICN_MAX_SQUEUE)
+			return 0;
+		save_flags(flags);
+		cli();
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (nskb) {
+			skb_queue_tail(&card->spqueue[channel], nskb);
+			dev_kfree_skb(skb, FREE_WRITE);
+		} else
+			len = 0;
+		card->sndcount[channel] += len;
+		restore_flags(flags);
+	}
+	return len;
 }
 
 /*
@@ -735,42 +847,43 @@
  *   0 on success (Boot loader ready)
  *   -EIO on failure (timeout)
  */
-static int icn_check_loader(int cardnumber)
+static int
+icn_check_loader(int cardnumber)
 {
-        int timer = 0;
+	int timer = 0;
 
-        while (1) {
+	while (1) {
 #ifdef BOOT_DEBUG
-                printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
+		printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
 #endif
-                if (readb(&dev.shmem->data_control.scns) ||
-                    readb(&dev.shmem->data_control.scnr)) {
-                        if (timer++ > 5) {
-                                printk(KERN_WARNING
-                                       "icn: Boot-Loader %d timed out.\n",
-                                       cardnumber);
-                                icn_release_channel();
-                                return -EIO;
-                        }
+		if (readb(&dev.shmem->data_control.scns) ||
+		    readb(&dev.shmem->data_control.scnr)) {
+			if (timer++ > 5) {
+				printk(KERN_WARNING
+				       "icn: Boot-Loader %d timed out.\n",
+				       cardnumber);
+				icn_release_channel();
+				return -EIO;
+			}
 #ifdef BOOT_DEBUG
-                        printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
+			printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
 #endif
-                        current->state = TASK_INTERRUPTIBLE;
-                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-                        schedule();
-                } else {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+			schedule();
+		} else {
 #ifdef BOOT_DEBUG
-                        printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
+			printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
 #endif
-                        icn_release_channel();
-                        return 0;
-                }
-        }
+			icn_release_channel();
+			return 0;
+		}
+	}
 }
 
 /* Load the boot-code into the interface-card's memory and start it.
  * Always called from user-process.
- * 
+ *
  * Parameters:
  *            buffer = pointer to packet
  * Return:
@@ -792,891 +905,937 @@
 #define SLEEP(sec)
 #endif
 
-static int icn_loadboot(u_char * buffer, icn_card * card)
+static int
+icn_loadboot(u_char * buffer, icn_card * card)
 {
-        int ret;
-        ulong flags;
+	int ret;
+	ulong flags;
 	u_char *codebuf;
 
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
+	printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
 #endif
-        if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
-                return ret;
-        if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) {
-                printk(KERN_WARNING "icn: Could not allocate code buffer\n");
-                return -ENOMEM;
-        }
-        save_flags(flags);
-        cli();
-        if (!card->rvalid) {
-                if (check_region(card->port, ICN_PORTLEN)) {
-                        printk(KERN_WARNING
-                               "icn: (%s) ports 0x%03x-0x%03x in use.\n",
-                               CID,
-                               card->port,
-                               card->port + ICN_PORTLEN);
-                        restore_flags(flags);
-                        kfree(codebuf);
-                        return -EBUSY;
-                }
-                request_region(card->port, ICN_PORTLEN, card->regname);
-                card->rvalid = 1;
-                if (card->doubleS0)
-                        card->other->rvalid = 1;
-        }
-        if (!dev.mvalid) {
-                if (check_shmem((ulong) dev.shmem, 0x4000)) {
-                        printk(KERN_WARNING
-                               "icn: memory at 0x%08lx in use.\n",
-                               (ulong) dev.shmem);
-                        restore_flags(flags);
-                        return -EBUSY;
-                }
-                request_shmem((ulong) dev.shmem, 0x4000, "icn");
-                dev.mvalid = 1;
-        }
-        restore_flags(flags);
-        OUTB_P(0, ICN_RUN);                                       /* Reset Controller */
-        OUTB_P(0, ICN_MAPRAM);                                    /* Disable RAM      */
-        icn_shiftout(ICN_CFG, 0x0f, 3, 4);                        /* Windowsize= 16k  */
-        icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr.    */
+	if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
+		printk(KERN_WARNING "icn: Could not allocate code buffer\n");
+		return -ENOMEM;
+	}
+	if ((ret = copy_from_user(codebuf, buffer, ICN_CODE_STAGE1))) {
+		kfree(codebuf);
+		return ret;
+	}
+	save_flags(flags);
+	cli();
+	if (!card->rvalid) {
+		if (check_region(card->port, ICN_PORTLEN)) {
+			printk(KERN_WARNING
+			       "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+			       CID,
+			       card->port,
+			       card->port + ICN_PORTLEN);
+			restore_flags(flags);
+			kfree(codebuf);
+			return -EBUSY;
+		}
+		request_region(card->port, ICN_PORTLEN, card->regname);
+		card->rvalid = 1;
+		if (card->doubleS0)
+			card->other->rvalid = 1;
+	}
+	if (!dev.mvalid) {
+		if (check_shmem((ulong) dev.shmem, 0x4000)) {
+			printk(KERN_WARNING
+			       "icn: memory at 0x%08lx in use.\n",
+			       (ulong) dev.shmem);
+			restore_flags(flags);
+			return -EBUSY;
+		}
+		request_shmem((ulong) dev.shmem, 0x4000, "icn");
+		dev.mvalid = 1;
+	}
+	restore_flags(flags);
+	OUTB_P(0, ICN_RUN);     /* Reset Controller */
+	OUTB_P(0, ICN_MAPRAM);  /* Disable RAM      */
+	icn_shiftout(ICN_CFG, 0x0f, 3, 4);	/* Windowsize= 16k  */
+	icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10);	/* Set RAM-Addr.    */
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
+	printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
 #endif
-        SLEEP(1);
+	SLEEP(1);
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "Map Bank 0\n");
+	printk(KERN_DEBUG "Map Bank 0\n");
 #endif
-        save_flags(flags);
-        cli();
-        icn_map_channel(card,0);                                   /* Select Bank 0    */
-        icn_lock_channel(card,0);                                  /* Lock Bank 0      */
-        restore_flags(flags);
-        SLEEP(1);
-        copy_from_user(codebuf, buffer, ICN_CODE_STAGE1);
-        memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);           /* Copy code        */
+	save_flags(flags);
+	cli();
+	icn_map_channel(card, 0);	/* Select Bank 0    */
+	icn_lock_channel(card, 0);	/* Lock Bank 0      */
+	restore_flags(flags);
+	SLEEP(1);
+	memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);	/* Copy code        */
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "Bootloader transfered\n");
+	printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
-        if (card->doubleS0) {
-                SLEEP(1);
+	if (card->doubleS0) {
+		SLEEP(1);
 #ifdef BOOT_DEBUG
-                printk(KERN_DEBUG "Map Bank 8\n");
+		printk(KERN_DEBUG "Map Bank 8\n");
 #endif
-                save_flags(flags);
-                cli();
-                icn_release_channel();
-                icn_map_channel(card,2);                           /* Select Bank 8   */
-                icn_lock_channel(card,2);                          /* Lock Bank 8     */
-                restore_flags(flags);
-                SLEEP(1);
-                memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);           /* Copy code        */
+		save_flags(flags);
+		cli();
+		icn_release_channel();
+		icn_map_channel(card, 2);	/* Select Bank 8   */
+		icn_lock_channel(card, 2);	/* Lock Bank 8     */
+		restore_flags(flags);
+		SLEEP(1);
+		memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);	/* Copy code        */
 #ifdef BOOT_DEBUG
-                printk(KERN_DEBUG "Bootloader transfered\n");
+		printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
-        }
-        kfree(codebuf);
-        SLEEP(1);
-        OUTB_P(0xff, ICN_RUN);                                     /* Start Boot-Code */
-        if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
-                return ret;
-        if (!card->doubleS0)
-                return 0;
-        /* reached only, if we have a Double-S0-Card */
+	}
+	kfree(codebuf);
+	SLEEP(1);
+	OUTB_P(0xff, ICN_RUN);  /* Start Boot-Code */
+	if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
+		return ret;
+	if (!card->doubleS0)
+		return 0;
+	/* reached only, if we have a Double-S0-Card */
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "Map Bank 0\n");
+	printk(KERN_DEBUG "Map Bank 0\n");
 #endif
-        save_flags(flags);
-        cli();
-        icn_map_channel(card,0);                                   /* Select Bank 0   */
-        icn_lock_channel(card,0);                                  /* Lock Bank 0     */
-        restore_flags(flags);
-        SLEEP(1);
-        return (icn_check_loader(1));
-}
-
-static int icn_loadproto(u_char * buffer, icn_card * card)
-{
-        register u_char *p = buffer;
-        u_char codebuf[256];
-        uint left = ICN_CODE_STAGE2;
-        uint cnt;
-        int timer;
-        int ret;
-        unsigned long flags;
+	save_flags(flags);
+	cli();
+	icn_map_channel(card, 0);	/* Select Bank 0   */
+	icn_lock_channel(card, 0);	/* Lock Bank 0     */
+	restore_flags(flags);
+	SLEEP(1);
+	return (icn_check_loader(1));
+}
+
+static int
+icn_loadproto(u_char * buffer, icn_card * card)
+{
+	register u_char *p = buffer;
+	u_char codebuf[256];
+	uint left = ICN_CODE_STAGE2;
+	uint cnt;
+	int timer;
+	int ret;
+	unsigned long flags;
 
 #ifdef BOOT_DEBUG
-        printk(KERN_DEBUG "icn_loadproto called\n");
+	printk(KERN_DEBUG "icn_loadproto called\n");
 #endif
-        if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
-                return ret;
-        timer = 0;
-        save_flags(flags);
-        cli();
-        if (card->secondhalf) {
-                icn_map_channel(card, 2);
-                icn_lock_channel(card, 2);
-        } else {
-                icn_map_channel(card, 0);
-                icn_lock_channel(card, 0);
-        }
-        restore_flags(flags);
-        while (left) {
-                if (sbfree) {                           /* If there is a free buffer...  */
-                        cnt = MIN(256, left);
-                        copy_from_user(codebuf, p, cnt);
-                        memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data                     */ 
-                        sbnext;                         /* switch to next buffer         */
-                        p += cnt;
-                        left -= cnt;
-                        timer = 0;
-                } else {
+	if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
+		return ret;
+	timer = 0;
+	save_flags(flags);
+	cli();
+	if (card->secondhalf) {
+		icn_map_channel(card, 2);
+		icn_lock_channel(card, 2);
+	} else {
+		icn_map_channel(card, 0);
+		icn_lock_channel(card, 0);
+	}
+	restore_flags(flags);
+	while (left) {
+		if (sbfree) {   /* If there is a free buffer...  */
+			cnt = MIN(256, left);
+			if (copy_from_user(codebuf, p, cnt)) {
+				icn_maprelease_channel(card, 0);
+				return -EFAULT;
+			}
+			memcpy_toio(&sbuf_l, codebuf, cnt);	/* copy data                     */
+			sbnext; /* switch to next buffer         */
+			p += cnt;
+			left -= cnt;
+			timer = 0;
+		} else {
 #ifdef BOOT_DEBUG
-                        printk(KERN_DEBUG "boot 2 !sbfree\n");
+			printk(KERN_DEBUG "boot 2 !sbfree\n");
 #endif
-                        if (timer++ > 5) {
-                                icn_maprelease_channel(card, 0);
-                                return -EIO;
-                        }
-                        current->state = TASK_INTERRUPTIBLE;
-                        current->timeout = jiffies + 10;
-                        schedule();
-                }
-        }
-        writeb (0x20, &sbuf_n);
-        timer = 0;
-        while (1) {
-                if (readb(&cmd_o) || readb(&cmd_i)) {
+			if (timer++ > 5) {
+				icn_maprelease_channel(card, 0);
+				return -EIO;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 10;
+			schedule();
+		}
+	}
+	writeb(0x20, &sbuf_n);
+	timer = 0;
+	while (1) {
+		if (readb(&cmd_o) || readb(&cmd_i)) {
 #ifdef BOOT_DEBUG
-                        printk(KERN_DEBUG "Proto?\n");
+			printk(KERN_DEBUG "Proto?\n");
 #endif
-                        if (timer++ > 5) {
-                                printk(KERN_WARNING
-                                       "icn: (%s) Protocol timed out.\n",
-                                       CID);
+			if (timer++ > 5) {
+				printk(KERN_WARNING
+				       "icn: (%s) Protocol timed out.\n",
+				       CID);
 #ifdef BOOT_DEBUG
-                                printk(KERN_DEBUG "Proto TO!\n");
+				printk(KERN_DEBUG "Proto TO!\n");
 #endif
-                                icn_maprelease_channel(card, 0);
-                                return -EIO;
-                        }
+				icn_maprelease_channel(card, 0);
+				return -EIO;
+			}
 #ifdef BOOT_DEBUG
-                        printk(KERN_DEBUG "Proto TO?\n");
+			printk(KERN_DEBUG "Proto TO?\n");
 #endif
-                        current->state = TASK_INTERRUPTIBLE;
-                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-                        schedule();
-                } else {
-                        if ((card->secondhalf) || (!card->doubleS0)) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+			schedule();
+		} else {
+			if ((card->secondhalf) || (!card->doubleS0)) {
 #ifdef BOOT_DEBUG
-                                printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
-                                       card->secondhalf);
+				printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
+				       card->secondhalf);
 #endif
-                                save_flags(flags);
-                                cli();
-                                init_timer(&card->st_timer);
-                                card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-                                card->st_timer.function = icn_polldchan;
-                                card->st_timer.data = (unsigned long)card;
-                                add_timer(&card->st_timer);
-                                card->flags |= ICN_FLAGS_RUNNING;
-                                if (card->doubleS0) {
-                                        init_timer(&card->other->st_timer);
-                                        card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-                                        card->other->st_timer.function = icn_polldchan;
-                                        card->other->st_timer.data = (unsigned long)card->other;
-                                        add_timer(&card->other->st_timer);
-                                        card->other->flags |= ICN_FLAGS_RUNNING;
-                                }
-                                restore_flags(flags);
-                        }
-                        icn_maprelease_channel(card, 0);
-                        return 0;
-                }
-        }
+				save_flags(flags);
+				cli();
+				init_timer(&card->st_timer);
+				card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+				card->st_timer.function = icn_polldchan;
+				card->st_timer.data = (unsigned long) card;
+				add_timer(&card->st_timer);
+				card->flags |= ICN_FLAGS_RUNNING;
+				if (card->doubleS0) {
+					init_timer(&card->other->st_timer);
+					card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+					card->other->st_timer.function = icn_polldchan;
+					card->other->st_timer.data = (unsigned long) card->other;
+					add_timer(&card->other->st_timer);
+					card->other->flags |= ICN_FLAGS_RUNNING;
+				}
+				restore_flags(flags);
+			}
+			icn_maprelease_channel(card, 0);
+			return 0;
+		}
+	}
 }
 
 /* Read the Status-replies from the Interface */
-static int icn_readstatus(u_char * buf, int len, int user, icn_card * card)
+static int
+icn_readstatus(u_char * buf, int len, int user, icn_card * card)
 {
-        int count;
-        u_char *p;
+	int count;
+	u_char *p;
 
-        for (p = buf, count = 0; count < len; p++, count++) {
-                if (card->msg_buf_read == card->msg_buf_write)
-                        return count;
-                if (user)
-                        put_user(*card->msg_buf_read++, p);
-                else
-                        *p = *card->msg_buf_read++;
-                if (card->msg_buf_read > card->msg_buf_end)
-                        card->msg_buf_read = card->msg_buf;
-        }
-        return count;
+	for (p = buf, count = 0; count < len; p++, count++) {
+		if (card->msg_buf_read == card->msg_buf_write)
+			return count;
+		if (user)
+			put_user(*card->msg_buf_read++, p);
+		else
+			*p = *card->msg_buf_read++;
+		if (card->msg_buf_read > card->msg_buf_end)
+			card->msg_buf_read = card->msg_buf;
+	}
+	return count;
 }
 
 /* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
+static int
+icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
 {
 	int mch = card->secondhalf ? 2 : 0;
-        int avail;
-        int pp;
-        int i;
-        int count;
-        int xcount;
-        int ocount;
-        int loop;
-        unsigned long flags;
-        int lastmap_channel;
-        struct icn_card *lastmap_card;
-        u_char *p;
-        isdn_ctrl cmd;
-        u_char msg[0x100];
-
-        ocount = 1;
-        xcount = loop = 0;
-        while (len) {
-                save_flags(flags);
-                cli();
-                lastmap_card = dev.mcard;
-                lastmap_channel = dev.channel;
-                icn_map_channel(card, mch);
-		
-                avail = cmd_free;
-                count = MIN(avail, len);
-                if (user)
-                        copy_from_user(msg, buf, count);
-                else
-                        memcpy(msg, buf, count);
-                icn_putmsg(card, '>');
-                for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
-			     ++) {
-                        writeb((*p == '\n') ? 0xff : *p,
-                               &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
-                        len--;
-                        xcount++;
-                        icn_putmsg(card, *p);
-                        if ((*p == '\n') && (i > 1)) {
-                                icn_putmsg(card, '>');
-                                ocount++;
-                        }
-                        ocount++;
-                }
-                writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
-                if (lastmap_card)
-                        icn_map_channel(lastmap_card, lastmap_channel);
-                restore_flags(flags);
-                if (len) {
-                        udelay(1000);
-                        if (loop++ > 20)
-                                break;
-                } else
-                        break;
-        }
-        if (len && (!user))
-                printk(KERN_WARNING "icn: writemsg incomplete!\n");
-        cmd.command = ISDN_STAT_STAVAIL;
-        cmd.driver = card->myid;
-        cmd.arg = ocount;
-        card->interface.statcallb(&cmd);
-        return xcount;
+	int avail;
+	int pp;
+	int i;
+	int count;
+	int xcount;
+	int ocount;
+	int loop;
+	unsigned long flags;
+	int lastmap_channel;
+	struct icn_card *lastmap_card;
+	u_char *p;
+	isdn_ctrl cmd;
+	u_char msg[0x100];
+
+	ocount = 1;
+	xcount = loop = 0;
+	while (len) {
+		save_flags(flags);
+		cli();
+		lastmap_card = dev.mcard;
+		lastmap_channel = dev.channel;
+		icn_map_channel(card, mch);
+
+		avail = cmd_free;
+		count = MIN(avail, len);
+		if (user)
+			copy_from_user(msg, buf, count);
+		else
+			memcpy(msg, buf, count);
+		icn_putmsg(card, '>');
+		for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
+		     ++) {
+			writeb((*p == '\n') ? 0xff : *p,
+			   &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
+			len--;
+			xcount++;
+			icn_putmsg(card, *p);
+			if ((*p == '\n') && (i > 1)) {
+				icn_putmsg(card, '>');
+				ocount++;
+			}
+			ocount++;
+		}
+		writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
+		if (lastmap_card)
+			icn_map_channel(lastmap_card, lastmap_channel);
+		restore_flags(flags);
+		if (len) {
+			udelay(1000);
+			if (loop++ > 20)
+				break;
+		} else
+			break;
+	}
+	if (len && (!user))
+		printk(KERN_WARNING "icn: writemsg incomplete!\n");
+	cmd.command = ISDN_STAT_STAVAIL;
+	cmd.driver = card->myid;
+	cmd.arg = ocount;
+	card->interface.statcallb(&cmd);
+	return xcount;
 }
 
 /*
  * Delete card's pending timers, send STOP to linklevel
  */
-static void icn_stopcard(icn_card * card)
+static void
+icn_stopcard(icn_card * card)
 {
-        unsigned long flags;
-        isdn_ctrl cmd;
+	unsigned long flags;
+	isdn_ctrl cmd;
 
-        save_flags(flags);
-        cli();
-        if (card->flags & ICN_FLAGS_RUNNING) {
-                card->flags &= ~ICN_FLAGS_RUNNING;
-                del_timer(&card->st_timer);
-                del_timer(&card->rb_timer);
-                cmd.command = ISDN_STAT_STOP;
-                cmd.driver  = card->myid;
-                card->interface.statcallb(&cmd);
-                if (card->doubleS0)
-                        icn_stopcard(card->other);
-        }
-        restore_flags(flags);
-}
-
-static void icn_stopallcards(void)
-{
-        icn_card *p = cards;
-
-        while (p) {
-                icn_stopcard(p);
-                p = p->next;
-        }
-}
-
-static int icn_command(isdn_ctrl * c, icn_card * card)
-{
-        ulong a;
-        ulong flags;
-        int i;
-        char cbuf[60];
-        isdn_ctrl cmd;
-        icn_cdef cdef;
-
-        switch (c->command) {
-        case ISDN_CMD_IOCTL:
-                memcpy(&a, c->num, sizeof(ulong));
-                switch (c->arg) {
-                        case ICN_IOCTL_SETMMIO:
-                                if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
-                                        if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
-                                                printk(KERN_WARNING
-                                                       "icn: memory at 0x%08lx in use.\n",
-                                                       (ulong) (a & 0x0ffc000));
-                                                return -EINVAL;
-                                        }
-                                        icn_stopallcards();
-                                        save_flags(flags);
-                                        cli();
-                                        if (dev.mvalid)
-                                                release_shmem((ulong) dev.shmem, 0x4000);
-                                        dev.mvalid = 0;
-                                        dev.shmem = (icn_shmem *) (a & 0x0ffc000);
-                                        restore_flags(flags);
-                                        printk(KERN_INFO
-                                               "icn: (%s) mmio set to 0x%08lx\n",
-                                               CID,
-                                               (unsigned long) dev.shmem);
-                                }
-                                break;
-                        case ICN_IOCTL_GETMMIO:
-                                return (long) dev.shmem;
-                        case ICN_IOCTL_SETPORT:
-                                if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
-                                    || a == 0x340 || a == 0x350 || a == 0x360 ||
-                                    a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
-                                    || a == 0x348 || a == 0x358 || a == 0x368) {
-                                        if (card->port != (unsigned short) a) {
-                                                if (check_region((unsigned short) a, ICN_PORTLEN)) {
-                                                        printk(KERN_WARNING
-                                                               "icn: (%s) ports 0x%03x-0x%03x in use.\n",
-                                                               CID, (int) a, (int) a + ICN_PORTLEN);
-                                                        return -EINVAL;
-                                                }
-                                                icn_stopcard(card);
-                                                save_flags(flags);
-                                                cli();
-                                                if (card->rvalid)
-                                                        release_region(card->port, ICN_PORTLEN);
-                                                card->port = (unsigned short) a;
-                                                card->rvalid = 0;
-                                                if (card->doubleS0) {
-                                                        card->other->port = (unsigned short) a;
-                                                        card->other->rvalid = 0;
-                                                }
-                                                restore_flags(flags);
-                                                printk(KERN_INFO
-                                                       "icn: (%s) port set to 0x%03x\n",
-                                                       CID, card->port);
-                                        }
-                                } else
-                                        return -EINVAL;
-                                break;
-                        case ICN_IOCTL_GETPORT:
-                                return (int) card->port;
-                        case ICN_IOCTL_GETDOUBLE:
-                                return (int) card->doubleS0;
-                        case ICN_IOCTL_DEBUGVAR:
-				if ((i = verify_area(VERIFY_WRITE,
-                                                    (void *) a,
-                                                    sizeof(ulong) * 2)))
-                                        return i;
-                                copy_from_user((char *)a,
-                                            (char *)&card, sizeof(ulong));
-				a += sizeof(ulong);
-				{
-                                        ulong l = (ulong)&dev;
-                                        copy_from_user((char *)a,
-                                                    (char *)&l, sizeof(ulong));
-                                }
-                                return 0;
-                        case ICN_IOCTL_LOADBOOT:
-                                icn_stopcard(card);
-                                return (icn_loadboot((u_char *) a, card));
-                        case ICN_IOCTL_LOADPROTO:
-                                icn_stopcard(card);
-                                if ((i = (icn_loadproto((u_char *) a, card))))
-                                        return i;
-                                if (card->doubleS0)
-                                        i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
-                                return i;
-                                break;
-                        case ICN_IOCTL_ADDCARD:
-                                if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
-                                        return i;
-                                copy_from_user((char *)&cdef, (char *)a, sizeof(cdef));
-                                return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
-                                break;
-                        case ICN_IOCTL_LEASEDCFG:
-                                if (a) {
-                                        if (!card->leased) {
-                                                card->leased = 1;
-                                                while (card->ptype == ISDN_PTYPE_UNKNOWN) {
-                                                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-                                                        schedule();
-                                                }
-                                                current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
-                                                schedule();
-                                                sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
-                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                                printk(KERN_INFO
-                                                       "icn: (%s) Leased-line mode enabled\n",
-                                                       CID);
-                                                cmd.command = ISDN_STAT_RUN;
-                                                cmd.driver = card->myid;
-                                                cmd.arg = 0;
-                                                card->interface.statcallb(&cmd);
-                                        }
-                                } else {
-                                        if (card->leased) {
-                                                card->leased = 0;
-                                                sprintf(cbuf, "00;FV2OFF\n");
-                                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                                printk(KERN_INFO
-                                                       "icn: (%s) Leased-line mode disabled\n",
-                                                       CID);
-                                                cmd.command = ISDN_STAT_RUN;
-                                                cmd.driver = card->myid;
-                                                cmd.arg = 0;
-                                                card->interface.statcallb(&cmd);
-                                        }
-                                }
-                                return 0;
-                        default:
-                                return -EINVAL;
-                }
-                break;
-                case ISDN_CMD_DIAL:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (card->leased)
-                                break;
-                        if ((c->arg & 255) < ICN_BCH) {
-                                char *p;
-                                char *p2;
-                                char dial[50];
-                                char sis[50];
-                                char dcode[4];
-                                int si1, si2;
-                                
-                                a = c->arg;
-                                strcpy(sis, c->num);
-                                p = strrchr(sis, ',');
-                                *p++ = '\0';
-                                si2 = simple_strtoul(p,NULL,10);
-                                p = strrchr(sis, ',') + 1;
-                                si1 = simple_strtoul(p,NULL,10);
-                                p = c->num;
-                                if (*p == 's' || *p == 'S') {
-                                        /* Dial for SPV */
-                                        p++;
-                                        strcpy(dcode, "SCA");
-                                } else
-                                        /* Normal Dial */
-                                        strcpy(dcode, "CAL");
-                                strcpy(dial, p);
-                                p = strchr(dial, ',');
-                                *p++ = '\0';
-                                p2 = strchr(p, ',');
-                                *p2 = '\0';
-                                sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
-                                        si2, p);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_ACCEPTD:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (c->arg < ICN_BCH) {
-                                a = c->arg + 1;
-                                if (card->fw_rev >= 300) {
-                                        switch (card->l2_proto[a-1]) {
-                                                case ISDN_PROTO_L2_X75I:
-                                                        sprintf(cbuf, "%02d;BX75\n", (int) a);
-                                                        break;
-                                                case ISDN_PROTO_L2_HDLC:
-                                                        sprintf(cbuf, "%02d;BTRA\n", (int) a);
-                                                        break;
-                                        }
-                                        i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                }
-                                sprintf(cbuf, "%02d;DCON_R\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_ACCEPTB:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (c->arg < ICN_BCH) {
-                                a = c->arg + 1;
-                                if (card->fw_rev >= 300)
-                                        switch (card->l2_proto[a-1]) {
-                                                case ISDN_PROTO_L2_X75I:
-                                                        sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
-                                                        break;
-                                                case ISDN_PROTO_L2_HDLC:
-                                                        sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
-                                                        break;
-                                        }
-                                else
-                                        sprintf(cbuf, "%02d;BCON_R\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_HANGUP:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (c->arg < ICN_BCH) {
-                                a = c->arg + 1;
-                                sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_SETEAZ:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (card->leased)
-                                break;
-                        if (c->arg < ICN_BCH) {
-                                a = c->arg + 1;
-                                if (card->ptype == ISDN_PTYPE_EURO) {
-                                        sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
-                                                c->num[0] ? "N" : "ALL", c->num);
-                                } else
-                                        sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
-                                                c->num[0] ? c->num : "0123456789");
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_CLREAZ:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if (card->leased)
-                                break;
-                        if (c->arg < ICN_BCH) {
-                                a = c->arg + 1;
-                                if (card->ptype == ISDN_PTYPE_EURO)
-                                        sprintf(cbuf, "%02d;MSNC\n", (int) a);
-                                else
-                                        sprintf(cbuf, "%02d;EAZC\n", (int) a);
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                        }
-                        break;
-                case ISDN_CMD_SETL2:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if ((c->arg & 255) < ICN_BCH) {
-                                a = c->arg;
-                                switch (a >> 8) {
-                                        case ISDN_PROTO_L2_X75I:
-                                                sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
-                                                break;
-                                        case ISDN_PROTO_L2_HDLC:
-                                                sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
-                                                break;
-                                        default:
-                                                return -EINVAL;
-                                }
-                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                card->l2_proto[a & 255] = (a >> 8);
-                        }
-                        break;
-                case ISDN_CMD_GETL2:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if ((c->arg & 255) < ICN_BCH)
-                                return card->l2_proto[c->arg & 255];
-                        else
-                                return -ENODEV;
-                case ISDN_CMD_SETL3:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        return 0;
-                case ISDN_CMD_GETL3:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        if ((c->arg & 255) < ICN_BCH)
-                                return ISDN_PROTO_L3_TRANS;
-                        else
-                                return -ENODEV;
-                case ISDN_CMD_GETEAZ:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        break;
-                case ISDN_CMD_SETSIL:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        break;
-                case ISDN_CMD_GETSIL:
-                        if (!card->flags & ICN_FLAGS_RUNNING)
-                                return -ENODEV;
-                        break;
-                case ISDN_CMD_LOCK:
-                        MOD_INC_USE_COUNT;
-                        break;
-                case ISDN_CMD_UNLOCK:
-                        MOD_DEC_USE_COUNT;
-                        break;
-                default:
-                        return -EINVAL;
-        }
-        return 0;
+	save_flags(flags);
+	cli();
+	if (card->flags & ICN_FLAGS_RUNNING) {
+		card->flags &= ~ICN_FLAGS_RUNNING;
+		del_timer(&card->st_timer);
+		del_timer(&card->rb_timer);
+		cmd.command = ISDN_STAT_STOP;
+		cmd.driver = card->myid;
+		card->interface.statcallb(&cmd);
+		if (card->doubleS0)
+			icn_stopcard(card->other);
+	}
+	restore_flags(flags);
+}
+
+static void
+icn_stopallcards(void)
+{
+	icn_card *p = cards;
+
+	while (p) {
+		icn_stopcard(p);
+		p = p->next;
+	}
 }
 
 /*
- * Find card with given driverId
+ * Unmap all cards, because some of them may be mapped accidetly during
+ * autoprobing of some network drivers (SMC-driver?)
  */
-static inline icn_card *
-  icn_findcard(int driverid)
+static void
+icn_disable_cards(void)
 {
-        icn_card *p = cards;
+	icn_card *card = cards;
+	unsigned long flags;
 
-        while (p) {
-                if (p->myid == driverid)
-                        return p;
-                p = p->next;
-        }
-        return (icn_card *)0;
+	save_flags(flags);
+	cli();
+	while (card) {
+		if (check_region(card->port, ICN_PORTLEN)) {
+			printk(KERN_WARNING
+			       "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+			       CID,
+			       card->port,
+			       card->port + ICN_PORTLEN);
+			cli();
+		} else {
+			OUTB_P(0, ICN_RUN);	/* Reset Controller     */
+			OUTB_P(0, ICN_MAPRAM);	/* Disable RAM          */
+		}
+		card = card->next;
+	}
+	restore_flags(flags);
+}
+
+static int
+icn_command(isdn_ctrl * c, icn_card * card)
+{
+	ulong a;
+	ulong flags;
+	int i;
+	char cbuf[60];
+	isdn_ctrl cmd;
+	icn_cdef cdef;
+
+	switch (c->command) {
+		case ISDN_CMD_IOCTL:
+			memcpy(&a, c->parm.num, sizeof(ulong));
+			switch (c->arg) {
+				case ICN_IOCTL_SETMMIO:
+					if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
+						if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+							printk(KERN_WARNING
+							       "icn: memory at 0x%08lx in use.\n",
+							       (ulong) (a & 0x0ffc000));
+							return -EINVAL;
+						}
+						icn_stopallcards();
+						save_flags(flags);
+						cli();
+						if (dev.mvalid)
+							release_shmem((ulong) dev.shmem, 0x4000);
+						dev.mvalid = 0;
+						dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+						restore_flags(flags);
+						printk(KERN_INFO
+						       "icn: (%s) mmio set to 0x%08lx\n",
+						       CID,
+						       (unsigned long) dev.shmem);
+					}
+					break;
+				case ICN_IOCTL_GETMMIO:
+					return (long) dev.shmem;
+				case ICN_IOCTL_SETPORT:
+					if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
+					    || a == 0x340 || a == 0x350 || a == 0x360 ||
+					    a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
+					    || a == 0x348 || a == 0x358 || a == 0x368) {
+						if (card->port != (unsigned short) a) {
+							if (check_region((unsigned short) a, ICN_PORTLEN)) {
+								printk(KERN_WARNING
+								       "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+								       CID, (int) a, (int) a + ICN_PORTLEN);
+								return -EINVAL;
+							}
+							icn_stopcard(card);
+							save_flags(flags);
+							cli();
+							if (card->rvalid)
+								release_region(card->port, ICN_PORTLEN);
+							card->port = (unsigned short) a;
+							card->rvalid = 0;
+							if (card->doubleS0) {
+								card->other->port = (unsigned short) a;
+								card->other->rvalid = 0;
+							}
+							restore_flags(flags);
+							printk(KERN_INFO
+							       "icn: (%s) port set to 0x%03x\n",
+							CID, card->port);
+						}
+					} else
+						return -EINVAL;
+					break;
+				case ICN_IOCTL_GETPORT:
+					return (int) card->port;
+				case ICN_IOCTL_GETDOUBLE:
+					return (int) card->doubleS0;
+				case ICN_IOCTL_DEBUGVAR:
+					if ((i = copy_to_user((char *) a,
+					  (char *) &card, sizeof(ulong))))
+						return i;
+					a += sizeof(ulong);
+					{
+						ulong l = (ulong) & dev;
+						if ((i = copy_to_user((char *) a,
+							     (char *) &l, sizeof(ulong))))
+							return i;
+					}
+					return 0;
+				case ICN_IOCTL_LOADBOOT:
+					if (dev.firstload) {
+						icn_disable_cards();
+						dev.firstload = 0;
+					}
+					icn_stopcard(card);
+					return (icn_loadboot((u_char *) a, card));
+				case ICN_IOCTL_LOADPROTO:
+					icn_stopcard(card);
+					if ((i = (icn_loadproto((u_char *) a, card))))
+						return i;
+					if (card->doubleS0)
+						i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
+					return i;
+					break;
+				case ICN_IOCTL_ADDCARD:
+					if (!dev.firstload)
+						return -EBUSY;
+					if ((i = copy_from_user((char *) &cdef, (char *) a, sizeof(cdef))))
+						return i;
+					return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
+					break;
+				case ICN_IOCTL_LEASEDCFG:
+					if (a) {
+						if (!card->leased) {
+							card->leased = 1;
+							while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+								current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+								schedule();
+							}
+							current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+							schedule();
+							sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n)02;EAZ%c\n",
+								(a & 1)?'1':'C', (a & 2)?'2':'C');
+							i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+							printk(KERN_INFO
+							       "icn: (%s) Leased-line mode enabled\n",
+							       CID);
+							cmd.command = ISDN_STAT_RUN;
+							cmd.driver = card->myid;
+							cmd.arg = 0;
+							card->interface.statcallb(&cmd);
+						}
+					} else {
+						if (card->leased) {
+							card->leased = 0;
+							sprintf(cbuf, "00;FV2OFF\n");
+							i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+							printk(KERN_INFO
+							       "icn: (%s) Leased-line mode disabled\n",
+							       CID);
+							cmd.command = ISDN_STAT_RUN;
+							cmd.driver = card->myid;
+							cmd.arg = 0;
+							card->interface.statcallb(&cmd);
+						}
+					}
+					return 0;
+				default:
+					return -EINVAL;
+			}
+			break;
+		case ISDN_CMD_DIAL:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (card->leased)
+				break;
+			if ((c->arg & 255) < ICN_BCH) {
+				char *p;
+				char dial[50];
+				char dcode[4];
+
+				a = c->arg;
+				p = c->parm.setup.phone;
+				if (*p == 's' || *p == 'S') {
+					/* Dial for SPV */
+					p++;
+					strcpy(dcode, "SCA");
+				} else
+					/* Normal Dial */
+					strcpy(dcode, "CAL");
+				strcpy(dial, p);
+				sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
+					dcode, dial, c->parm.setup.si1,
+				c->parm.setup.si2, c->parm.setup.eazmsn);
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_ACCEPTD:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (c->arg < ICN_BCH) {
+				a = c->arg + 1;
+				if (card->fw_rev >= 300) {
+					switch (card->l2_proto[a - 1]) {
+						case ISDN_PROTO_L2_X75I:
+							sprintf(cbuf, "%02d;BX75\n", (int) a);
+							break;
+						case ISDN_PROTO_L2_HDLC:
+							sprintf(cbuf, "%02d;BTRA\n", (int) a);
+							break;
+					}
+					i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+				}
+				sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_ACCEPTB:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (c->arg < ICN_BCH) {
+				a = c->arg + 1;
+				if (card->fw_rev >= 300)
+					switch (card->l2_proto[a - 1]) {
+						case ISDN_PROTO_L2_X75I:
+							sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+							break;
+						case ISDN_PROTO_L2_HDLC:
+							sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+							break;
+				} else
+					sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_HANGUP:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (c->arg < ICN_BCH) {
+				a = c->arg + 1;
+				sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_SETEAZ:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (card->leased)
+				break;
+			if (c->arg < ICN_BCH) {
+				a = c->arg + 1;
+				if (card->ptype == ISDN_PTYPE_EURO) {
+					sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+						c->parm.num[0] ? "N" : "ALL", c->parm.num);
+				} else
+					sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+						c->parm.num[0] ? c->parm.num : "0123456789");
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_CLREAZ:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if (card->leased)
+				break;
+			if (c->arg < ICN_BCH) {
+				a = c->arg + 1;
+				if (card->ptype == ISDN_PTYPE_EURO)
+					sprintf(cbuf, "%02d;MSNC\n", (int) a);
+				else
+					sprintf(cbuf, "%02d;EAZC\n", (int) a);
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+			}
+			break;
+		case ISDN_CMD_SETL2:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if ((c->arg & 255) < ICN_BCH) {
+				a = c->arg;
+				switch (a >> 8) {
+					case ISDN_PROTO_L2_X75I:
+						sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+						break;
+					case ISDN_PROTO_L2_HDLC:
+						sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+						break;
+					default:
+						return -EINVAL;
+				}
+				i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+				card->l2_proto[a & 255] = (a >> 8);
+			}
+			break;
+		case ISDN_CMD_GETL2:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if ((c->arg & 255) < ICN_BCH)
+				return card->l2_proto[c->arg & 255];
+			else
+				return -ENODEV;
+		case ISDN_CMD_SETL3:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			return 0;
+		case ISDN_CMD_GETL3:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			if ((c->arg & 255) < ICN_BCH)
+				return ISDN_PROTO_L3_TRANS;
+			else
+				return -ENODEV;
+		case ISDN_CMD_GETEAZ:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			break;
+		case ISDN_CMD_SETSIL:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			break;
+		case ISDN_CMD_GETSIL:
+			if (!card->flags & ICN_FLAGS_RUNNING)
+				return -ENODEV;
+			break;
+		case ISDN_CMD_LOCK:
+			MOD_INC_USE_COUNT;
+			break;
+		case ISDN_CMD_UNLOCK:
+			MOD_DEC_USE_COUNT;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
 }
 
 /*
- * Wrapper functions for interface to linklevel
+ * Find card with given driverId
  */
-static int if_command(isdn_ctrl * c)
-{
-        icn_card *card = icn_findcard(c->driver);
-
-        if (card)
-                return (icn_command(c, card));
-        printk(KERN_ERR
-               "icn: if_command %d called with invalid driverId %d!\n",
-		c->command, c->driver);
-        return -ENODEV;
-}
-
-static int if_writecmd(const u_char * buf, int len, int user, int id, int channel)
-{
-        icn_card *card = icn_findcard(id);
-
-        if (card) {
-                if (!card->flags & ICN_FLAGS_RUNNING)
-                        return -ENODEV;
-                return (icn_writecmd(buf, len, user, card));
-        }
-        printk(KERN_ERR
-               "icn: if_writecmd called with invalid driverId!\n");
-        return -ENODEV;
-}
-
-static int if_readstatus(u_char * buf, int len, int user, int id, int channel)
+static inline icn_card *
+icn_findcard(int driverid)
 {
-        icn_card *card = icn_findcard(id);
+	icn_card *p = cards;
 
-        if (card) {
-                if (!card->flags & ICN_FLAGS_RUNNING)
-                        return -ENODEV;
-                return (icn_readstatus(buf, len, user, card));
-        }
-        printk(KERN_ERR
-               "icn: if_readstatus called with invalid driverId!\n");
-        return -ENODEV;
+	while (p) {
+		if (p->myid == driverid)
+			return p;
+		p = p->next;
+	}
+	return (icn_card *) 0;
 }
 
-static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
 {
-        icn_card *card = icn_findcard(id);
+	icn_card *card = icn_findcard(c->driver);
 
-        if (card) {
-                if (!card->flags & ICN_FLAGS_RUNNING)
-                        return -ENODEV;
-                return (icn_sendbuf(channel, skb, card));
-        }
-        printk(KERN_ERR
-               "icn: if_sendbuf called with invalid driverId!\n");
-        return -ENODEV;
+	if (card)
+		return (icn_command(c, card));
+	printk(KERN_ERR
+	       "icn: if_command %d called with invalid driverId %d!\n",
+	       c->command, c->driver);
+	return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+	icn_card *card = icn_findcard(id);
+
+	if (card) {
+		if (!card->flags & ICN_FLAGS_RUNNING)
+			return -ENODEV;
+		return (icn_writecmd(buf, len, user, card));
+	}
+	printk(KERN_ERR
+	       "icn: if_writecmd called with invalid driverId!\n");
+	return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+	icn_card *card = icn_findcard(id);
+
+	if (card) {
+		if (!card->flags & ICN_FLAGS_RUNNING)
+			return -ENODEV;
+		return (icn_readstatus(buf, len, user, card));
+	}
+	printk(KERN_ERR
+	       "icn: if_readstatus called with invalid driverId!\n");
+	return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, struct sk_buff *skb)
+{
+	icn_card *card = icn_findcard(id);
+
+	if (card) {
+		if (!card->flags & ICN_FLAGS_RUNNING)
+			return -ENODEV;
+		return (icn_sendbuf(channel, skb, card));
+	}
+	printk(KERN_ERR
+	       "icn: if_sendbuf called with invalid driverId!\n");
+	return -ENODEV;
 }
 
 /*
  * Allocate a new card-struct, initialize it
  * link it into cards-list and register it at linklevel.
  */
-static icn_card *icn_initcard(int port, char *id) {
-        icn_card *card;
-        int i;
-
-        if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
-                printk(KERN_WARNING
-                       "icn: (%s) Could not allocate card-struct.\n", id);
-                return (icn_card *)0;
-        }
-        memset((char *) card, 0, sizeof(icn_card));
-        card->port = port;
-        card->interface.channels = ICN_BCH;
-        card->interface.maxbufsize = 4000;
-        card->interface.command = if_command;
+static icn_card *
+icn_initcard(int port, char *id)
+{
+	icn_card *card;
+	int i;
+
+	if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+		printk(KERN_WARNING
+		       "icn: (%s) Could not allocate card-struct.\n", id);
+		return (icn_card *) 0;
+	}
+	memset((char *) card, 0, sizeof(icn_card));
+	card->port = port;
+	card->interface.channels = ICN_BCH;
+	card->interface.maxbufsize = 4000;
+	card->interface.command = if_command;
 	card->interface.writebuf_skb = if_sendbuf;
-        card->interface.writecmd = if_writecmd;
-        card->interface.readstat = if_readstatus;
-        card->interface.features = ISDN_FEATURE_L2_X75I |
-                ISDN_FEATURE_L2_HDLC |
-                ISDN_FEATURE_L3_TRANS |
-                ISDN_FEATURE_P_UNKNOWN;
-        card->ptype = ISDN_PTYPE_UNKNOWN;
-        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
-        card->msg_buf_write = card->msg_buf;
-        card->msg_buf_read = card->msg_buf;
-        card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
-        for (i=0;i<ICN_BCH;i++) {
-                card->l2_proto[i] = ISDN_PROTO_L2_X75I;
-                skb_queue_head_init(&card->spqueue[i]);
-        }
-        card->next = cards;
-        cards = card;
-        if (!register_isdn(&card->interface)) {
-                cards = cards->next;
-                printk(KERN_WARNING
-                       "icn: Unable to register %s\n", id);
-                kfree(card);
-                return (icn_card*)0;
-        }
-        card->myid = card->interface.channels;
-        sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
-        return card;
-}
-
-static int icn_addcard(int port, char *id1, char *id2)
-{
-        ulong flags;
-        icn_card *card;
-        icn_card *card2;
-
-        save_flags(flags);
-        cli();
-        if (!(card = icn_initcard(port,id1))) {
-                restore_flags(flags);
-                return -EIO;
-        }
-        if (!strlen(id2)) {
-                restore_flags(flags);
-                printk(KERN_INFO
-                       "icn: (%s) ICN-2B, port 0x%x added\n",
-                       card->interface.id, port);
-                return 0;
-        }
-        if (!(card2 = icn_initcard(port,id2))) {
-                restore_flags(flags);
-                printk(KERN_INFO
-                       "icn: (%s) half ICN-4B, port 0x%x added\n",
-                       card2->interface.id, port);
-                return 0;
-        }
-        card->doubleS0 = 1;
-        card->secondhalf = 0;
-        card->other = card2;
-        card2->doubleS0 = 1;
-        card2->secondhalf = 1;
-        card2->other = card;
-        restore_flags(flags);
-        printk(KERN_INFO
-               "icn: (%s and %s) ICN-4B, port 0x%x added\n",
-               card->interface.id, card2->interface.id, port);
-        return 0;
+	card->interface.writecmd = if_writecmd;
+	card->interface.readstat = if_readstatus;
+	card->interface.features = ISDN_FEATURE_L2_X75I |
+	    ISDN_FEATURE_L2_HDLC |
+	    ISDN_FEATURE_L3_TRANS |
+	    ISDN_FEATURE_P_UNKNOWN;
+	card->ptype = ISDN_PTYPE_UNKNOWN;
+	strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+	card->msg_buf_write = card->msg_buf;
+	card->msg_buf_read = card->msg_buf;
+	card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+	for (i = 0; i < ICN_BCH; i++) {
+		card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+		skb_queue_head_init(&card->spqueue[i]);
+	}
+	card->next = cards;
+	cards = card;
+	if (!register_isdn(&card->interface)) {
+		cards = cards->next;
+		printk(KERN_WARNING
+		       "icn: Unable to register %s\n", id);
+		kfree(card);
+		return (icn_card *) 0;
+	}
+	card->myid = card->interface.channels;
+	sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
+	return card;
+}
+
+static int
+icn_addcard(int port, char *id1, char *id2)
+{
+	ulong flags;
+	icn_card *card;
+	icn_card *card2;
+
+	save_flags(flags);
+	cli();
+	if (!(card = icn_initcard(port, id1))) {
+		restore_flags(flags);
+		return -EIO;
+	}
+	if (!strlen(id2)) {
+		restore_flags(flags);
+		printk(KERN_INFO
+		       "icn: (%s) ICN-2B, port 0x%x added\n",
+		       card->interface.id, port);
+		return 0;
+	}
+	if (!(card2 = icn_initcard(port, id2))) {
+		restore_flags(flags);
+		printk(KERN_INFO
+		       "icn: (%s) half ICN-4B, port 0x%x added\n",
+		       card2->interface.id, port);
+		return 0;
+	}
+	card->doubleS0 = 1;
+	card->secondhalf = 0;
+	card->other = card2;
+	card2->doubleS0 = 1;
+	card2->secondhalf = 1;
+	card2->other = card;
+	restore_flags(flags);
+	printk(KERN_INFO
+	       "icn: (%s and %s) ICN-4B, port 0x%x added\n",
+	       card->interface.id, card2->interface.id, port);
+	return 0;
 }
 
 #ifdef MODULE
 #define icn_init init_module
 #else
-void icn_setup(char *str, int *ints)
+void
+icn_setup(char *str, int *ints)
 {
-        char *p;
-        static char sid[20];
-        static char sid2[20];
-
-        if (ints[0])
-                portbase = ints[1];
-        if (ints[0]>1)
-                membase = ints[2];
-        if (strlen(str)) {
-                strcpy(sid,str);
-                icn_id = sid;
-                if ((p = strchr(sid,','))) {
-                        *p++ = 0;
-                        strcpy(sid2,p);
-                        icn_id2 = sid2;
-                }
-        }
+	char *p;
+	static char sid[20];
+	static char sid2[20];
+
+	if (ints[0])
+		portbase = ints[1];
+	if (ints[0] > 1)
+		membase = ints[2];
+	if (strlen(str)) {
+		strcpy(sid, str);
+		icn_id = sid;
+		if ((p = strchr(sid, ','))) {
+			*p++ = 0;
+			strcpy(sid2, p);
+			icn_id2 = sid2;
+		}
+	}
 }
 #endif
 
-int icn_init(void)
-{
-        char *p;
-        char rev[10];
-
-        memset(&dev, 0, sizeof(icn_dev));
-        dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000);
-        dev.channel = -1;
-        dev.mcard   = NULL;
-
-        /* No symbols to export, hide all symbols */
-        register_symtab(NULL);
-
-        if ((p = strchr(revision, ':'))) {
-                strcpy(rev, p + 1);
-                p = strchr(rev, '$');
-                *p = 0;
-        } else
-                strcpy(rev, " ??? ");
-        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
-               (ulong) dev.shmem);
-        return (icn_addcard(portbase,icn_id,icn_id2));
+int
+icn_init(void)
+{
+	char *p;
+	char rev[10];
+
+	memset(&dev, 0, sizeof(icn_dev));
+	dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000);
+	dev.channel = -1;
+	dev.mcard = NULL;
+	dev.firstload = 1;
+
+	/* No symbols to export, hide all symbols */
+#if (LINUX_VERSION_CODE < 0x020111)
+	register_symtab(NULL);
+#else
+	EXPORT_NO_SYMBOLS;
+#endif
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else
+		strcpy(rev, " ??? ");
+	printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
+	       (ulong) dev.shmem);
+	return (icn_addcard(portbase, icn_id, icn_id2));
 }
 
 #ifdef MODULE
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
-        isdn_ctrl cmd;
-        icn_card *card = cards;
-        icn_card *last;
-        int i;
-
-        icn_stopallcards();
-        while (card) {
-                cmd.command = ISDN_STAT_UNLOAD;
-                cmd.driver = card->myid;
-                card->interface.statcallb(&cmd);
-                if (card->rvalid) {
-                        OUTB_P(0, ICN_RUN);    /* Reset Controller     */
-                        OUTB_P(0, ICN_MAPRAM); /* Disable RAM          */
-                        if (card->secondhalf || (!card->doubleS0)) {
-                                release_region(card->port, ICN_PORTLEN);
-                                card->rvalid = 0;
-                        }
-                        for (i = 0; i < ICN_BCH; i++)
-                                icn_free_queue(&card->spqueue[i]);
-                }
-                card = card->next;
-        }
-        card = cards;
-        while (card) {
-                last = card;
-                card = card->next;
-                kfree(last);
-        }
-        if (dev.mvalid)
-                release_shmem((ulong) dev.shmem, 0x4000);
-        printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
+	isdn_ctrl cmd;
+	icn_card *card = cards;
+	icn_card *last;
+	int i;
+
+	icn_stopallcards();
+	while (card) {
+		cmd.command = ISDN_STAT_UNLOAD;
+		cmd.driver = card->myid;
+		card->interface.statcallb(&cmd);
+		if (card->rvalid) {
+			OUTB_P(0, ICN_RUN);	/* Reset Controller     */
+			OUTB_P(0, ICN_MAPRAM);	/* Disable RAM          */
+			if (card->secondhalf || (!card->doubleS0)) {
+				release_region(card->port, ICN_PORTLEN);
+				card->rvalid = 0;
+			}
+			for (i = 0; i < ICN_BCH; i++)
+				icn_free_queue(card, i);
+		}
+		card = card->next;
+	}
+	card = cards;
+	while (card) {
+		last = card;
+		card = card->next;
+		kfree(last);
+	}
+	if (dev.mvalid)
+		release_shmem((ulong) dev.shmem, 0x4000);
+	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
 #endif
diff -urN linux-2.0.31-pre2/drivers/isdn/icn/icn.h linux-2.0.31-pre3/drivers/isdn/icn/icn.h
--- linux-2.0.31-pre2/drivers/isdn/icn/icn.h	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/icn/icn.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,5 +1,5 @@
-/* $Id: icn.h,v 1.22 1996/11/13 02:37:33 fritz Exp $
- *
+/* $Id: icn.h,v 1.26 1997/02/14 12:23:16 fritz Exp $
+
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
  * Copyright 1994 by Fritz Elfert (fritz@wuemaus.franken.de)
@@ -16,9 +16,23 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: icn.h,v $
+ * Revision 1.26  1997/02/14 12:23:16  fritz
+ * Added support for new insmod parameter handling.
+ *
+ * Revision 1.25  1997/02/10 10:10:31  fritz
+ * Changes for Kernel 2.1.X compatibility.
+ * Enhanced initialization, can recover from
+ * misconfiguration by other autoprobing drivers.
+ *
+ * Revision 1.24  1997/01/29 22:34:46  fritz
+ * Cleanup, Corrected D64S setup of 2nd channel.
+ *
+ * Revision 1.23  1996/12/17 18:47:55  tsbogend
+ * changed timeouts from absolute numbers to HZ based values
+ *
  * Revision 1.22  1996/11/13 02:37:33  fritz
  * Added delay include.
  *
@@ -113,9 +127,9 @@
 
 /* Struct for adding new cards */
 typedef struct icn_cdef {
-        int port;
-        char id1[10];
-        char id2[10];
+	int port;
+	char id1[10];
+	char id2[10];
 } icn_cdef;
 
 #if defined(__KERNEL__) || defined(__DEBUGVAR__)
@@ -141,7 +155,7 @@
 #include <linux/delay.h>
 #include <linux/isdnif.h>
 
-#endif /* __KERNEL__ */
+#endif                          /* __KERNEL__ */
 
 /* some useful macros for debugging */
 #ifdef ICN_DEBUG_PORT
@@ -155,138 +169,154 @@
 #define ICN_PORTLEN (0x04)
 #define ICN_MEMADDR 0x0d0000
 
-#define ICN_FLAGS_B1ACTIVE 1     /* B-Channel-1 is open                     */
-#define ICN_FLAGS_B2ACTIVE 2     /* B-Channel-2 is open                     */
-#define ICN_FLAGS_RUNNING  4     /* Cards driver activated                  */
-#define ICN_FLAGS_RBTIMER  8     /* cyclic scheduling of B-Channel-poll     */
-
-#define ICN_BOOT_TIMEOUT1  100   /* Delay for Boot-download (jiffies)       */
-#define ICN_CHANLOCK_DELAY  10   /* Delay for Channel-mapping (jiffies)     */
-
-#define ICN_TIMER_BCREAD 1       /* B-Channel poll-cycle                    */
-#define ICN_TIMER_DCREAD 50      /* D-Channel poll-cycle                    */
-
-#define ICN_CODE_STAGE1 4096     /* Size of bootcode                        */
-#define ICN_CODE_STAGE2 65536    /* Size of protocol-code                   */
-
-#define ICN_MAX_SQUEUE 8000      /* Max. outstanding send-data (2* hw-buf.) */
-#define ICN_FRAGSIZE (250)       /* Max. size of send-fragments             */
-#define ICN_BCH 2                /* Number of supported channels per card   */
+#define ICN_FLAGS_B1ACTIVE 1    /* B-Channel-1 is open                     */
+#define ICN_FLAGS_B2ACTIVE 2    /* B-Channel-2 is open                     */
+#define ICN_FLAGS_RUNNING  4    /* Cards driver activated                  */
+#define ICN_FLAGS_RBTIMER  8    /* cyclic scheduling of B-Channel-poll     */
+
+#define ICN_BOOT_TIMEOUT1  (HZ) /* Delay for Boot-download (jiffies)       */
+#define ICN_CHANLOCK_DELAY (HZ/10)	/* Delay for Channel-mapping (jiffies)     */
+
+#define ICN_TIMER_BCREAD (HZ/100)	/* B-Channel poll-cycle                    */
+#define ICN_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle                    */
+
+#define ICN_CODE_STAGE1 4096    /* Size of bootcode                        */
+#define ICN_CODE_STAGE2 65536   /* Size of protocol-code                   */
+
+#define ICN_MAX_SQUEUE 8000     /* Max. outstanding send-data (2* hw-buf.) */
+#define ICN_FRAGSIZE (250)      /* Max. size of send-fragments             */
+#define ICN_BCH 2               /* Number of supported channels per card   */
 
 /* type-definitions for accessing the mmap-io-areas */
 
-#define SHM_DCTL_OFFSET (0)      /* Offset to data-controlstructures in shm */
-#define SHM_CCTL_OFFSET (0x1d2)  /* Offset to comm-controlstructures in shm */
-#define SHM_CBUF_OFFSET (0x200)  /* Offset to comm-buffers in shm           */
-#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm           */
+#define SHM_DCTL_OFFSET (0)     /* Offset to data-controlstructures in shm */
+#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */
+#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm           */
+#define SHM_DBUF_OFFSET (0x2000)	/* Offset to data-buffers in shm           */
 
 /*
  * Layout of card's data buffers
  */
 typedef struct {
-        unsigned char length;             /* Bytecount of fragment (max 250)    */
-        unsigned char endflag;            /* 0=last frag., 0xff=frag. continued */
-        unsigned char data[ICN_FRAGSIZE]; /* The data                           */
-        /* Fill to 256 bytes */
-        char unused[0x100 - ICN_FRAGSIZE - 2];
+	unsigned char length;   /* Bytecount of fragment (max 250)    */
+	unsigned char endflag;  /* 0=last frag., 0xff=frag. continued */
+	unsigned char data[ICN_FRAGSIZE];	/* The data                           */
+	/* Fill to 256 bytes */
+	char unused[0x100 - ICN_FRAGSIZE - 2];
 } frag_buf;
 
 /*
  * Layout of card's shared memory
  */
 typedef union {
-        struct {
-                unsigned char scns;            /* Index to free SendFrag.             */
-                unsigned char scnr;            /* Index to active SendFrag   READONLY */
-                unsigned char ecns;            /* Index to free RcvFrag.     READONLY */
-                unsigned char ecnr;            /* Index to valid RcvFrag              */
-                char unused[6];
-                unsigned short fuell1;         /* Internal Buf Bytecount              */
-        } data_control;
-        struct {
-                char unused[SHM_CCTL_OFFSET];
-                unsigned char iopc_i;          /* Read-Ptr Status-Queue      READONLY */
-                unsigned char iopc_o;          /* Write-Ptr Status-Queue              */
-                unsigned char pcio_i;          /* Write-Ptr Command-Queue             */
-                unsigned char pcio_o;          /* Read-Ptr Command Queue     READONLY */
-        } comm_control;
-        struct {
-                char unused[SHM_CBUF_OFFSET];
-                unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue           */
-                unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue            */
-        } comm_buffers;
-        struct {
-                char unused[SHM_DBUF_OFFSET];
-                frag_buf receive_buf[0x10];
-                frag_buf send_buf[0x10];
-        } data_buffers;
+	struct {
+		unsigned char scns;	/* Index to free SendFrag.             */
+		unsigned char scnr;	/* Index to active SendFrag   READONLY */
+		unsigned char ecns;	/* Index to free RcvFrag.     READONLY */
+		unsigned char ecnr;	/* Index to valid RcvFrag              */
+		char unused[6];
+		unsigned short fuell1;	/* Internal Buf Bytecount              */
+	} data_control;
+	struct {
+		char unused[SHM_CCTL_OFFSET];
+		unsigned char iopc_i;	/* Read-Ptr Status-Queue      READONLY */
+		unsigned char iopc_o;	/* Write-Ptr Status-Queue              */
+		unsigned char pcio_i;	/* Write-Ptr Command-Queue             */
+		unsigned char pcio_o;	/* Read-Ptr Command Queue     READONLY */
+	} comm_control;
+	struct {
+		char unused[SHM_CBUF_OFFSET];
+		unsigned char pcio_buf[0x100];	/* Ring-Buffer Command-Queue           */
+		unsigned char iopc_buf[0x100];	/* Ring-Buffer Status-Queue            */
+	} comm_buffers;
+	struct {
+		char unused[SHM_DBUF_OFFSET];
+		frag_buf receive_buf[0x10];
+		frag_buf send_buf[0x10];
+	} data_buffers;
 } icn_shmem;
 
 /*
  * Per card driver data
  */
 typedef struct icn_card {
-        struct icn_card *next;        /* Pointer to next device struct    */
-        struct icn_card *other;       /* Pointer to other card for ICN4B  */
-        unsigned short port;          /* Base-port-address                */
-        int myid;                     /* Driver-Nr. assigned by linklevel */
-        int rvalid;                   /* IO-portregion has been requested */
-        int leased;                   /* Flag: This Adapter is connected  */
-                                      /*       to a leased line           */
-        unsigned short flags;         /* Statusflags                      */
-        int doubleS0;                 /* Flag: ICN4B                      */
-        int secondhalf;               /* Flag: Second half of a doubleS0  */
-        int fw_rev;                   /* Firmware revision loaded         */
-        int ptype;                    /* Protocol type (1TR6 or Euro)     */
-        struct timer_list st_timer;   /* Timer for Status-Polls           */
-        struct timer_list rb_timer;   /* Timer for B-Channel-Polls        */
-        u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers        */
-        int rcvidx[ICN_BCH];          /* Index for above buffers          */
-        int l2_proto[ICN_BCH];        /* Current layer-2-protocol         */
-        isdn_if interface;            /* Interface to upper layer         */
-        int iptr;                     /* Index to imsg-buffer             */
-        char imsg[60];                /* Internal buf for status-parsing  */
-        char msg_buf[2048];           /* Buffer for status-messages       */
-        char *msg_buf_write;          /* Writepointer for statusbuffer    */
-        char *msg_buf_read;           /* Readpointer for statusbuffer     */
-        char *msg_buf_end;            /* Pointer to end of statusbuffer   */
-        int sndcount[ICN_BCH];        /* Byte-counters for B-Ch.-send     */
-        struct sk_buff_head
-                spqueue[ICN_BCH];     /* Sendqueue                        */
-        char regname[35];             /* Name used for request_region     */
-        u_char xmit_lock[ICN_BCH];    /* Semaphore for pollbchan_send()   */
+	struct icn_card *next;  /* Pointer to next device struct    */
+	struct icn_card *other; /* Pointer to other card for ICN4B  */
+	unsigned short port;    /* Base-port-address                */
+	int myid;               /* Driver-Nr. assigned by linklevel */
+	int rvalid;             /* IO-portregion has been requested */
+	int leased;             /* Flag: This Adapter is connected  */
+	/*       to a leased line           */
+	unsigned short flags;   /* Statusflags                      */
+	int doubleS0;           /* Flag: ICN4B                      */
+	int secondhalf;         /* Flag: Second half of a doubleS0  */
+	int fw_rev;             /* Firmware revision loaded         */
+	int ptype;              /* Protocol type (1TR6 or Euro)     */
+	struct timer_list st_timer;	/* Timer for Status-Polls           */
+	struct timer_list rb_timer;	/* Timer for B-Channel-Polls        */
+	u_char rcvbuf[ICN_BCH][4096];	/* B-Channel-Receive-Buffers        */
+	int rcvidx[ICN_BCH];    /* Index for above buffers          */
+	int l2_proto[ICN_BCH];  /* Current layer-2-protocol         */
+	isdn_if interface;      /* Interface to upper layer         */
+	int iptr;               /* Index to imsg-buffer             */
+	char imsg[60];          /* Internal buf for status-parsing  */
+	char msg_buf[2048];     /* Buffer for status-messages       */
+	char *msg_buf_write;    /* Writepointer for statusbuffer    */
+	char *msg_buf_read;     /* Readpointer for statusbuffer     */
+	char *msg_buf_end;      /* Pointer to end of statusbuffer   */
+	int sndcount[ICN_BCH];  /* Byte-counters for B-Ch.-send     */
+	struct sk_buff_head
+	 spqueue[ICN_BCH];      /* Sendqueue                        */
+	char regname[35];       /* Name used for request_region     */
+	u_char xmit_lock[ICN_BCH];	/* Semaphore for pollbchan_send()   */
 } icn_card;
 
 /*
  * Main driver data
  */
 typedef struct icn_dev {
-        icn_shmem *shmem;             /* Pointer to memory-mapped-buffers */
-        int mvalid;                   /* IO-shmem has been requested      */
-        int channel;                  /* Currently mapped channel         */
-        struct icn_card *mcard;       /* Currently mapped card            */
-        int chanlock;                 /* Semaphore for channel-mapping    */
+	icn_shmem *shmem;       /* Pointer to memory-mapped-buffers */
+	int mvalid;             /* IO-shmem has been requested      */
+	int channel;            /* Currently mapped channel         */
+	struct icn_card *mcard; /* Currently mapped card            */
+	int chanlock;           /* Semaphore for channel-mapping    */
+	int firstload;          /* Flag: firmware never loaded      */
 } icn_dev;
 
 typedef icn_dev *icn_devptr;
 
 #ifdef __KERNEL__
 
-static icn_card *cards  = (icn_card *) 0;
-static u_char   chan2bank[] = { 0, 4, 8, 12 }; /* for icn_map_channel() */ 
+static icn_card *cards = (icn_card *) 0;
+static u_char chan2bank[] =
+{0, 4, 8, 12};                  /* for icn_map_channel() */
 
-static icn_dev  dev;
+static icn_dev dev;
 
 /* With modutils >= 1.1.67 Integers can be changed while loading a
  * module. For this reason define the Port-Base an Shmem-Base as
  * integers.
  */
-int portbase  = ICN_BASEADDR;
-int membase   = ICN_MEMADDR;
-char *icn_id  = "\0";
-char *icn_id2 = "\0";
+static int portbase = ICN_BASEADDR;
+static int membase = ICN_MEMADDR;
+static char *icn_id = "\0";
+static char *icn_id2 = "\0";
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_PARM(portbase, "i");
+MODULE_PARM_DESC(portbase, "Port adress of first card");
+MODULE_PARM(membase, "i");
+MODULE_PARM_DESC(membase, "Shared memory adress of all cards");
+MODULE_PARM(icn_id, "s");
+MODULE_PARM_DESC(icn_id, "ID-String of first card");
+MODULE_PARM(icn_id2, "s");
+MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
+#endif
+#endif
 
-#endif                                /* __KERNEL__ */
+#endif                          /* __KERNEL__ */
 
 /* Utility-Macros */
 
@@ -298,11 +328,11 @@
 
 /* Return true, if there is a free transmit-buffer */
 #define sbfree (((readb(&dev.shmem->data_control.scns)+1) & 0xf) != \
-                readb(&dev.shmem->data_control.scnr))
+		readb(&dev.shmem->data_control.scnr))
 
 /* Switch to next transmit-buffer */
 #define sbnext (writeb((readb(&dev.shmem->data_control.scns)+1) & 0xf, \
-                       &dev.shmem->data_control.scns))
+		       &dev.shmem->data_control.scns))
 
 /* Shortcuts for transmit-buffer-access */
 #define sbuf_n dev.shmem->data_control.scns
@@ -312,11 +342,11 @@
 
 /* Return true, if there is receive-data is available */
 #define rbavl  (readb(&dev.shmem->data_control.ecnr) != \
-                readb(&dev.shmem->data_control.ecns))
+		readb(&dev.shmem->data_control.ecns))
 
 /* Switch to next receive-buffer */
 #define rbnext (writeb((readb(&dev.shmem->data_control.ecnr)+1) & 0xf, \
-                       &dev.shmem->data_control.ecnr))
+		       &dev.shmem->data_control.ecnr))
 
 /* Shortcuts for receive-buffer-access */
 #define rbuf_n dev.shmem->data_control.ecnr
@@ -330,8 +360,8 @@
 
 /* Return free space in command-buffer */
 #define cmd_free ((readb(&cmd_i)>=readb(&cmd_o))? \
-                  0x100-readb(&cmd_i)+readb(&cmd_o): \
-                  readb(&cmd_o)-readb(&cmd_i))
+		  0x100-readb(&cmd_i)+readb(&cmd_o): \
+		  readb(&cmd_o)-readb(&cmd_i))
 
 /* Shortcuts for message-buffer-access */
 #define msg_o (dev.shmem->comm_control.iopc_o)
@@ -339,8 +369,8 @@
 
 /* Return length of Message, if avail. */
 #define msg_avail ((readb(&msg_o)>readb(&msg_i))? \
-                   0x100-readb(&msg_o)+readb(&msg_i): \
-                   readb(&msg_i)-readb(&msg_o))
+		   0x100-readb(&msg_o)+readb(&msg_i): \
+		   readb(&msg_i)-readb(&msg_o))
 
 #define CID (card->interface.id)
 
@@ -355,5 +385,5 @@
 #define release_shmem release_region
 #define request_shmem request_region
 
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* icn_h */
+#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif                          /* icn_h */
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_audio.c linux-2.0.31-pre3/drivers/isdn/isdn_audio.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_audio.c	1996-06-07 06:02:40.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_audio.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,10 +1,10 @@
-/* $Id: isdn_audio.c,v 1.6 1996/06/06 14:43:31 fritz Exp $
- *
+/* $Id: isdn_audio.c,v 1.8 1997/03/02 14:29:16 fritz Exp $
+
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
- * 
+ *
  * 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)
@@ -17,9 +17,15 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_audio.c,v $
+ * Revision 1.8  1997/03/02 14:29:16  fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.7  1997/02/03 22:44:11  fritz
+ * Reformatted according CodingStyle
+ *
  * Revision 1.6  1996/06/06 14:43:31  fritz
  * Changed to support DTMF decoding on audio playback also.
  *
@@ -47,154 +53,158 @@
 #include "isdn_audio.h"
 #include "isdn_common.h"
 
-char *isdn_audio_revision        = "$Revision: 1.6 $";
+char *isdn_audio_revision = "$Revision: 1.8 $";
 
 /*
  * Misc. lookup-tables.
  */
 
 /* ulaw -> signed 16-bit */
-static short isdn_audio_ulaw_to_s16[] = {
-        0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
-        0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
-        0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
-        0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
-        0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
-        0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
-        0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
-        0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
-        0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
-        0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
-        0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
-        0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
-        0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
-        0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
-        0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
-        0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
-        0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
-        0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
-        0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
-        0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
-        0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
-        0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
-        0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
-        0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
-        0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
-        0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
-        0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
-        0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
-        0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
-        0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
-        0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
-        0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
+static short isdn_audio_ulaw_to_s16[] =
+{
+	0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
+	0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
+	0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
+	0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
+	0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
+	0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
+	0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
+	0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
+	0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
+	0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
+	0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
+	0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
+	0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
+	0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
+	0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
+	0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
+	0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
+	0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
+	0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
+	0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
+	0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
+	0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
+	0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
+	0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
+	0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
+	0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
+	0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
+	0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
+	0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
+	0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
+	0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
+	0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
 };
 
 /* alaw -> signed 16-bit */
-static short isdn_audio_alaw_to_s16[] = {
-        0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
-        0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
-        0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
-        0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
-        0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
-        0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
-        0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
-        0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
-        0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
-        0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
-        0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
-        0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
-        0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
-        0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
-        0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
-        0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
-        0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
-        0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
-        0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
-        0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
-        0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
-        0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
-        0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
-        0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
-        0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
-        0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
-        0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
-        0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
-        0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
-        0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
-        0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
-        0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
+static short isdn_audio_alaw_to_s16[] =
+{
+	0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
+	0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
+	0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
+	0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
+	0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
+	0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
+	0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
+	0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
+	0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
+	0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
+	0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
+	0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
+	0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
+	0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
+	0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
+	0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
+	0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
+	0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
+	0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
+	0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
+	0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
+	0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
+	0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
+	0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
+	0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
+	0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
+	0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
+	0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
+	0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
+	0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
+	0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
+	0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
 };
 
 /* alaw -> ulaw */
-static char isdn_audio_alaw_to_ulaw[] = {
-        0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
-        0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
-        0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
-        0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
-        0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
-        0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
-        0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
-        0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
-        0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
-        0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
-        0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
-        0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
-        0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
-        0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
-        0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
-        0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
-        0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
-        0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
-        0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
-        0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
-        0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
-        0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
-        0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
-        0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
-        0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
-        0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
-        0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
-        0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
-        0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
-        0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
-        0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
-        0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
+static char isdn_audio_alaw_to_ulaw[] =
+{
+	0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
+	0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
+	0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
+	0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
+	0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
+	0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
+	0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
+	0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
+	0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
+	0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
+	0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
+	0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
+	0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
+	0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
+	0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
+	0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
+	0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
+	0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
+	0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
+	0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
+	0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
+	0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
+	0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
+	0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
+	0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
+	0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
+	0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
+	0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
+	0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
+	0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
+	0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
+	0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
 };
 
 /* ulaw -> alaw */
-static char isdn_audio_ulaw_to_alaw[] = {
-        0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
-        0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
-        0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
-        0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
-        0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
-        0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
-        0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
-        0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
-        0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
-        0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
-        0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
-        0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
-        0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
-        0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
-        0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
-        0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
-        0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
-        0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
-        0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
-        0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
-        0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
-        0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
-        0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
-        0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
-        0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
-        0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
-        0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
-        0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
-        0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
-        0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
-        0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
-        0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
+static char isdn_audio_ulaw_to_alaw[] =
+{
+	0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
+	0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
+	0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
+	0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
+	0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
+	0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
+	0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
+	0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
+	0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
+	0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
+	0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
+	0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
+	0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
+	0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
+	0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
+	0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
+	0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
+	0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
+	0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
+	0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
+	0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
+	0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
+	0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
+	0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
+	0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
+	0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
+	0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
+	0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
+	0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
+	0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
+	0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
+	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
 };
 
 #define NCOEFF           16     /* number of frequencies to be analyzed       */
@@ -206,68 +216,72 @@
 #define HIGRP             1
 
 typedef struct {
-        int grp;        /* low/high group     */
-        int k;          /* k                  */
-        int k2;         /* k fuer 2. harmonic */
+	int grp;                /* low/high group     */
+	int k;                  /* k                  */
+	int k2;                 /* k fuer 2. harmonic */
 } dtmf_t;
 
 /* For DTMF recognition:
  * 2 * cos(2 * PI * k / N) precalculated for all k
  */
-static int cos2pik[NCOEFF] = {
-        55812,  29528, 53603,  24032, 51193,  14443, 48590,   6517,
-        38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
+static int cos2pik[NCOEFF] =
+{
+	55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
+	38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
 };
 
-static dtmf_t dtmf_tones[8] = {
-        { LOGRP,  0,  1 }, /*  697 Hz */
-        { LOGRP,  2,  3 }, /*  770 Hz */
-        { LOGRP,  4,  5 }, /*  852 Hz */
-        { LOGRP,  6,  7 }, /*  941 Hz */
-        { HIGRP,  8,  9 }, /* 1209 Hz */
-        { HIGRP, 10, 11 }, /* 1336 Hz */
-        { HIGRP, 12, 13 }, /* 1477 Hz */
-        { HIGRP, 14, 15 }  /* 1633 Hz */
+static dtmf_t dtmf_tones[8] =
+{
+	{LOGRP, 0, 1},          /*  697 Hz */
+	{LOGRP, 2, 3},          /*  770 Hz */
+	{LOGRP, 4, 5},          /*  852 Hz */
+	{LOGRP, 6, 7},          /*  941 Hz */
+	{HIGRP, 8, 9},          /* 1209 Hz */
+	{HIGRP, 10, 11},        /* 1336 Hz */
+	{HIGRP, 12, 13},        /* 1477 Hz */
+	{HIGRP, 14, 15}         /* 1633 Hz */
 };
 
-static char dtmf_matrix[4][4] = {
-        {'1', '2', '3', 'A'},
-        {'4', '5', '6', 'B'},
-        {'7', '8', '9', 'C'},
-        {'*', '0', '#', 'D'}
+static char dtmf_matrix[4][4] =
+{
+	{'1', '2', '3', 'A'},
+	{'4', '5', '6', 'B'},
+	{'7', '8', '9', 'C'},
+	{'*', '0', '#', 'D'}
 };
 
 #if ((CPU == 386) || (CPU == 486) || (CPU == 586))
 static inline void
 isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
 {
-        __asm__("cld\n"
-                "1:\tlodsb\n\t"
-                "xlatb\n\t"
-                "stosb\n\t"
-                "loop 1b\n\t"
-                ::"b" ((long)table), "c" (n), "D" ((long)buff), "S" ((long)buff)
-                :"bx","cx","di","si","ax");
+	__asm__("cld\n"
+		"1:\tlodsb\n\t"
+		"xlatb\n\t"
+		"stosb\n\t"
+		"loop 1b\n\t"
+      : :  "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
+      :        "bx", "cx", "di", "si", "ax");
 }
+
 #else
 static inline void
 isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
 {
-        while (n--) 
-                *buff++ = table[*buff];
+	while (n--)
+		*buff++ = table[*buff];
 }
 #endif
 
 void
 isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
 {
-        isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
+	isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
 }
 
 void
 isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
 {
-        isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
+	isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
 }
 
 /*
@@ -278,207 +292,218 @@
  */
 
 
-#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
+#define ZEROTRAP                /* turn on the trap as per the MIL-STD */
 #undef ZEROTRAP
-#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
+#define BIAS 0x84               /* define the add-in bias for 16 bit samples */
 #define CLIP 32635
 
 static unsigned char
-isdn_audio_linear2ulaw(int sample) {
-        static int exp_lut[256] = {
-                0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
-                4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-                5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-                5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-                6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-                7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
-        };
-        int sign, exponent, mantissa;
-        unsigned char ulawbyte;
-
-        /* Get the sample into sign-magnitude. */
-        sign = (sample >> 8) & 0x80;      /* set aside the sign  */
-        if(sign != 0) sample = -sample;   /* get magnitude       */
-        if(sample > CLIP) sample = CLIP;  /* clip the magnitude  */
-
-        /* Convert from 16 bit linear to ulaw. */
-        sample = sample + BIAS;
-        exponent = exp_lut[( sample >> 7 ) & 0xFF];
-        mantissa = (sample >> (exponent + 3)) & 0x0F;
-        ulawbyte = ~(sign | (exponent << 4) | mantissa);
+isdn_audio_linear2ulaw(int sample)
+{
+	static int exp_lut[256] =
+	{
+		0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+	};
+	int sign,
+	 exponent,
+	 mantissa;
+	unsigned char ulawbyte;
+
+	/* Get the sample into sign-magnitude. */
+	sign = (sample >> 8) & 0x80;	/* set aside the sign  */
+	if (sign != 0)
+		sample = -sample;	/* get magnitude       */
+	if (sample > CLIP)
+		sample = CLIP;  /* clip the magnitude  */
+
+	/* Convert from 16 bit linear to ulaw. */
+	sample = sample + BIAS;
+	exponent = exp_lut[(sample >> 7) & 0xFF];
+	mantissa = (sample >> (exponent + 3)) & 0x0F;
+	ulawbyte = ~(sign | (exponent << 4) | mantissa);
 #ifdef ZEROTRAP
-        /* optional CCITT trap */
-        if (ulawbyte == 0) ulawbyte = 0x02;
+	/* optional CCITT trap */
+	if (ulawbyte == 0)
+		ulawbyte = 0x02;
 #endif
-        return(ulawbyte);
+	return (ulawbyte);
 }
 
 
-static int Mx[3][8] = {
-        { 0x3800, 0x5600, 0,0,0,0,0,0 },
-        { 0x399a, 0x3a9f, 0x4d14, 0x6607, 0,0,0,0 },
-        { 0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607 },
+static int Mx[3][8] =
+{
+	{0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
+	{0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
+	{0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
 };
 
-static int bitmask[9] = {
-        0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
-}; 
+static int bitmask[9] =
+{
+	0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
+};
 
 static int
-isdn_audio_get_bits (adpcm_state *s, unsigned char **in, int *len)
+isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len)
 {
-        while( s->nleft < s->nbits) {
-                int d = *((*in)++);
-                (*len)--;
-                s->word = (s->word << 8) | d;
-                s->nleft += 8;
-        }
-        s->nleft -= s->nbits;
-        return (s->word >> s->nleft) & bitmask[s->nbits];
+	while (s->nleft < s->nbits) {
+		int d = *((*in)++);
+		(*len)--;
+		s->word = (s->word << 8) | d;
+		s->nleft += 8;
+	}
+	s->nleft -= s->nbits;
+	return (s->word >> s->nleft) & bitmask[s->nbits];
 }
 
 static void
-isdn_audio_put_bits (int data, int nbits, adpcm_state *s,
-                     unsigned char **out, int *len)
+isdn_audio_put_bits(int data, int nbits, adpcm_state * s,
+		    unsigned char **out, int *len)
 {
-        s->word = (s->word << nbits) | (data & bitmask[nbits]);
-        s->nleft += nbits;
-        while(s->nleft >= 8) {
-                int d = (s->word >> (s->nleft-8));
-                *(out[0]++) = d & 255;
-                (*len)++;
-                s->nleft -= 8;
-        }
+	s->word = (s->word << nbits) | (data & bitmask[nbits]);
+	s->nleft += nbits;
+	while (s->nleft >= 8) {
+		int d = (s->word >> (s->nleft - 8));
+		*(out[0]++) = d & 255;
+		(*len)++;
+		s->nleft -= 8;
+	}
 }
 
 adpcm_state *
-isdn_audio_adpcm_init(adpcm_state *s, int nbits)
+isdn_audio_adpcm_init(adpcm_state * s, int nbits)
 {
-        if (!s)
-                s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
-        if (s) {
-                s->a     = 0;
-                s->d     = 5;
-                s->word  = 0;
-                s->nleft = 0;
-                s->nbits = nbits;
-        }
-        return s;
+	if (!s)
+		s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
+	if (s) {
+		s->a = 0;
+		s->d = 5;
+		s->word = 0;
+		s->nleft = 0;
+		s->nbits = nbits;
+	}
+	return s;
 }
 
 dtmf_state *
-isdn_audio_dtmf_init(dtmf_state *s)
+isdn_audio_dtmf_init(dtmf_state * s)
 {
-        if (!s)
-                s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
-        if (s) {
-                s->idx   = 0;
-                s->last  = ' ';
-        }
-        return s;
+	if (!s)
+		s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
+	if (s) {
+		s->idx = 0;
+		s->last = ' ';
+	}
+	return s;
 }
 
 /*
  * Decompression of adpcm data to a/u-law
  *
  */
- 
+
 int
-isdn_audio_adpcm2xlaw (adpcm_state *s, int fmt, unsigned char *in,
-                      unsigned char *out, int len)
+isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
+		      unsigned char *out, int len)
 {
-        int a = s->a;
-        int d = s->d;
-        int nbits = s->nbits;
-        int olen = 0;
-        
-        while (len) {
-                int e = isdn_audio_get_bits(s, &in, &len);
-                int sign;
-
-                if (nbits == 4 && e == 0)
-                        d = 4;
-                sign = (e >> (nbits-1))?-1:1;
-                e &= bitmask[nbits-1];
-                a += sign * ((e << 1) + 1) * d >> 1;
-                if (d & 1)
-                        a++;
-                if (fmt)
-                        *out++ = isdn_audio_ulaw_to_alaw[
-                                 isdn_audio_linear2ulaw(a << 2)];
-                else
-                        *out++ = isdn_audio_linear2ulaw(a << 2);
-                olen++;
-                d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14;
-                if ( d < 5 )
-                        d = 5;     
-        }
-        s->a = a;
-        s->d = d;
-        return olen;
+	int a = s->a;
+	int d = s->d;
+	int nbits = s->nbits;
+	int olen = 0;
+
+	while (len) {
+		int e = isdn_audio_get_bits(s, &in, &len);
+		int sign;
+
+		if (nbits == 4 && e == 0)
+			d = 4;
+		sign = (e >> (nbits - 1)) ? -1 : 1;
+		e &= bitmask[nbits - 1];
+		a += sign * ((e << 1) + 1) * d >> 1;
+		if (d & 1)
+			a++;
+		if (fmt)
+			*out++ = isdn_audio_ulaw_to_alaw[
+					 isdn_audio_linear2ulaw(a << 2)];
+		else
+			*out++ = isdn_audio_linear2ulaw(a << 2);
+		olen++;
+		d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
+		if (d < 5)
+			d = 5;
+	}
+	s->a = a;
+	s->d = d;
+	return olen;
 }
 
 int
-isdn_audio_2adpcm_flush (adpcm_state *s, unsigned char *out)
+isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
 {
 	int olen = 0;
 
-        if (s->nleft)
-                isdn_audio_put_bits(0, 8-s->nleft, s, &out, &olen);
-        return olen;
+	if (s->nleft)
+		isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
+	return olen;
 }
 
 int
-isdn_audio_xlaw2adpcm (adpcm_state *s, int fmt, unsigned char *in,
-                      unsigned char *out, int len)
+isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
+		      unsigned char *out, int len)
 {
-        int a = s->a;
-        int d = s->d;
-        int nbits = s->nbits;
-        int olen = 0;
-
-        while (len--) {
-                int e = 0, nmax = 1 << (nbits - 1);
-                int sign, delta;
-              
-                if (fmt)
-                        delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
-                else
-                        delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
-                if (delta < 0) {
-                        e = nmax;
-                        delta = -delta;
-                }
-                while( --nmax && delta > d ) {
-                        delta -= d;
-                        e++;
-                }
-                if (nbits == 4 && ((e & 0x0f) == 0))
-                        e = 8;
-                isdn_audio_put_bits(e, nbits, s, &out, &olen);
-                sign = (e >> (nbits-1))?-1:1 ;
-                e &= bitmask[nbits-1];
-                
-                a += sign * ((e << 1) + 1) * d >> 1;
-                if (d & 1)
-                        a++;
-                d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14;
-                if (d < 5)
-                        d=5;
-        }
+	int a = s->a;
+	int d = s->d;
+	int nbits = s->nbits;
+	int olen = 0;
+
+	while (len--) {
+		int e = 0,
+		 nmax = 1 << (nbits - 1);
+		int sign,
+		 delta;
+
+		if (fmt)
+			delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
+		else
+			delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
+		if (delta < 0) {
+			e = nmax;
+			delta = -delta;
+		}
+		while (--nmax && delta > d) {
+			delta -= d;
+			e++;
+		}
+		if (nbits == 4 && ((e & 0x0f) == 0))
+			e = 8;
+		isdn_audio_put_bits(e, nbits, s, &out, &olen);
+		sign = (e >> (nbits - 1)) ? -1 : 1;
+		e &= bitmask[nbits - 1];
+
+		a += sign * ((e << 1) + 1) * d >> 1;
+		if (d & 1)
+			a++;
+		d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
+		if (d < 5)
+			d = 5;
+	}
 	s->a = a;
 	s->d = d;
-        return olen;
+	return olen;
 }
 
 /*
@@ -488,99 +513,109 @@
  * Result is stored into an sk_buff and queued up for later
  * evaluation.
  */
-void
-isdn_audio_goertzel(int *sample, modem_info *info) {
-        int sk, sk1, sk2;
-        int k, n;
-        struct sk_buff *skb;
-        int *result;
-
-        skb = dev_alloc_skb(sizeof(int) * NCOEFF);
-        if (!skb) {
-                printk(KERN_WARNING
-                       "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
-                       info->line);
-                return;
-        }
-        result = (int *)skb_put(skb, sizeof(int) * NCOEFF);
-        skb->free = 1;
-        skb->users = 0;
-        for (k = 0; k < NCOEFF; k++) {
-                sk = sk1 = sk2 = 0;
-                for (n = 0; n < DTMF_NPOINTS; n++) {
-                        sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
-                        sk2 = sk1;
-                        sk1 = sk;
-                }
-                result[k] =
-                        ((sk * sk) >> AMP_BITS) - 
-                        ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
-                        ((sk2 * sk2) >> AMP_BITS);
-        }
-        skb_queue_tail(&info->dtmf_queue, skb);
-        isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+static void
+isdn_audio_goertzel(int *sample, modem_info * info)
+{
+	int sk,
+	 sk1,
+	 sk2;
+	int k,
+	 n;
+	struct sk_buff *skb;
+	int *result;
+
+	skb = dev_alloc_skb(sizeof(int) * NCOEFF);
+	if (!skb) {
+		printk(KERN_WARNING
+		  "isdn_audio: Could not alloc DTMF result for ttyI%d\n",
+		       info->line);
+		return;
+	}
+	SET_SKB_FREE(skb);
+	result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
+	for (k = 0; k < NCOEFF; k++) {
+		sk = sk1 = sk2 = 0;
+		for (n = 0; n < DTMF_NPOINTS; n++) {
+			sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
+			sk2 = sk1;
+			sk1 = sk;
+		}
+		result[k] =
+		    ((sk * sk) >> AMP_BITS) -
+		    ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
+		    ((sk2 * sk2) >> AMP_BITS);
+	}
+	skb_queue_tail(&info->dtmf_queue, skb);
+	isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
 }
 
 void
-isdn_audio_eval_dtmf(modem_info *info)
+isdn_audio_eval_dtmf(modem_info * info)
 {
-        struct sk_buff *skb;
-        int *result;
-        dtmf_state *s;
-        int silence;
-        int i;
-        int di;
-        int ch;
-        unsigned long flags;
-        int grp[2];
-        char what;
-        char *p;
-
-        while ((skb = skb_dequeue(&info->dtmf_queue))) {
-                result = (int *)skb->data;
-                s = info->dtmf_state;
-                grp[LOGRP] = grp[HIGRP] = -2;
-                silence = 0;
-                for(i = 0; i < 8; i++) {
-                        if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
-                            (result[dtmf_tones[i].k2] < H2_TRESH)    )
-                                grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2)?i:-1;
-                        else
-                                if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
-                                    (result[dtmf_tones[i].k2] < SILENCE_TRESH)  )
-                                        silence++;
-                }
-                if(silence == 8)
-                        what = ' ';
-                else {
-                        if((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
-                                what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
-                                if(s->last != ' ' && s->last != '.')
-                                        s->last = what;  /* min. 1 non-DTMF between DTMF */
-                        } else
-                                what = '.';
-                }
-                if ((what != s->last) && (what != ' ') && (what != '.')) {
-                        printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
-                        p = skb->data;
-                        *p++ = 0x10;
-                        *p = what;
-                        skb_trim(skb, 2);
-                        save_flags(flags);
-                        cli();
-                        di = info->isdn_driver;
-                        ch = info->isdn_channel;
-                        __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
-                        dev->drv[di]->rcvcount[ch] += 2;
-                        restore_flags(flags);
-                        /* Schedule dequeuing */
-                        if ((dev->modempoll) && (info->rcvsched))
-                                isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-                        wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
-                } else
-                        kfree_skb(skb, FREE_READ);
-                s->last = what;
-        }
+	struct sk_buff *skb;
+	int *result;
+	dtmf_state *s;
+	int silence;
+	int i;
+	int di;
+	int ch;
+	unsigned long flags;
+	int grp[2];
+	char what;
+	char *p;
+
+	while ((skb = skb_dequeue(&info->dtmf_queue))) {
+		result = (int *) skb->data;
+		s = info->dtmf_state;
+		grp[LOGRP] = grp[HIGRP] = -2;
+		silence = 0;
+		for (i = 0; i < 8; i++) {
+			if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
+			    (result[dtmf_tones[i].k2] < H2_TRESH))
+				grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
+			else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
+			      (result[dtmf_tones[i].k2] < SILENCE_TRESH))
+				silence++;
+		}
+		if (silence == 8)
+			what = ' ';
+		else {
+			if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
+				what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
+				if (s->last != ' ' && s->last != '.')
+					s->last = what;	/* min. 1 non-DTMF between DTMF */
+			} else
+				what = '.';
+		}
+		if ((what != s->last) && (what != ' ') && (what != '.')) {
+			printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
+			p = skb->data;
+			*p++ = 0x10;
+			*p = what;
+			skb_trim(skb, 2);
+			if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+				printk(KERN_WARNING
+				       "isdn_audio: insufficient skb_headroom, dropping\n");
+				kfree_skb(skb, FREE_READ);
+				return;
+			}
+			ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+			ISDN_AUDIO_SKB_LOCK(skb) = 0;
+			save_flags(flags);
+			cli();
+			di = info->isdn_driver;
+			ch = info->isdn_channel;
+			__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
+			dev->drv[di]->rcvcount[ch] += 2;
+			restore_flags(flags);
+			/* Schedule dequeuing */
+			if ((dev->modempoll) && (info->rcvsched))
+				isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+			wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+		} else
+			kfree_skb(skb, FREE_READ);
+		s->last = what;
+	}
 }
 
 /*
@@ -593,30 +628,28 @@
  *   fmt  = audio data format (0 = ulaw, 1 = alaw)
  */
 void
-isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
+isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
 {
-        dtmf_state *s = info->dtmf_state;
-        int i;
-        int c;
-
-        while (len) {
-                c = MIN(len, (DTMF_NPOINTS - s->idx));
-                if (c <= 0)
-                        break;
-                for (i = 0; i < c; i++) {
-                        if (fmt)
-                                s->buf[s->idx++] =
-                                        isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
-                        else
-                                s->buf[s->idx++] =
-                                        isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
-                }
-                if (s->idx == DTMF_NPOINTS) {
-                        isdn_audio_goertzel(s->buf, info);
-                        s->idx = 0;
-                }
-                len -= c;
-        }
+	dtmf_state *s = info->dtmf_state;
+	int i;
+	int c;
+
+	while (len) {
+		c = MIN(len, (DTMF_NPOINTS - s->idx));
+		if (c <= 0)
+			break;
+		for (i = 0; i < c; i++) {
+			if (fmt)
+				s->buf[s->idx++] =
+				    isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
+			else
+				s->buf[s->idx++] =
+				    isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
+		}
+		if (s->idx == DTMF_NPOINTS) {
+			isdn_audio_goertzel(s->buf, info);
+			s->idx = 0;
+		}
+		len -= c;
+	}
 }
-
-
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_audio.h linux-2.0.31-pre3/drivers/isdn/isdn_audio.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_audio.h	1996-06-07 06:02:40.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_audio.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-/* $Id: isdn_audio.h,v 1.4 1996/06/06 14:43:32 fritz Exp $
- *
+/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $
+
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
@@ -16,9 +16,12 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_audio.h,v $
+ * Revision 1.5  1997/02/03 22:45:21  fritz
+ * Reformatted according CodingStyle
+ *
  * Revision 1.4  1996/06/06 14:43:32  fritz
  * Changed to support DTMF decoding on audio playback also.
  *
@@ -33,27 +36,27 @@
  *
  */
 
-#define DTMF_NPOINTS 205       /* Number of samples for DTMF recognition */
+#define DTMF_NPOINTS 205        /* Number of samples for DTMF recognition */
 typedef struct adpcm_state {
-        int  a;
-        int  d;
-        int  word;
-        int  nleft;
-        int  nbits;
+	int a;
+	int d;
+	int word;
+	int nleft;
+	int nbits;
 } adpcm_state;
 
 typedef struct dtmf_state {
-        char last;
-        int  idx;
-        int  buf[DTMF_NPOINTS];
+	char last;
+	int idx;
+	int buf[DTMF_NPOINTS];
 } dtmf_state;
 
 extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
 extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
 extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
-extern int  isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int  isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int  isdn_audio_2adpcm_flush(adpcm_state *s, unsigned char *out);
+extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
+extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
+extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
 extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
 extern void isdn_audio_eval_dtmf(modem_info *);
 dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_cards.c linux-2.0.31-pre3/drivers/isdn/isdn_cards.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_cards.c	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_cards.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-/* $Id: isdn_cards.c,v 1.2 1996/10/13 19:52:17 keil Exp $
- *
+/* $Id: isdn_cards.c,v 1.6 1997/04/23 18:56:03 fritz Exp $
+
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
@@ -16,9 +16,21 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_cards.c,v $
+ * Revision 1.6  1997/04/23 18:56:03  fritz
+ * Old Teles driver removed, Changed doc and scripts accordingly.
+ *
+ * Revision 1.5  1997/03/30 17:10:36  calle
+ * added support for AVM-B1-PCI card.
+ *
+ * Revision 1.4  1997/03/04 21:59:44  calle
+ * Added AVM-B1-CAPI2.0 driver
+ *
+ * Revision 1.3  1997/02/03 23:31:14  fritz
+ * Reformatted according CodingStyle
+ *
  * Revision 1.2  1996/10/13 19:52:17  keil
  * HiSax support
  *
@@ -33,10 +45,6 @@
 extern void icn_init(void);
 #endif
 
-#ifdef CONFIG_ISDN_DRV_TELES
-extern void teles_init(void);
-#endif
-
 #ifdef CONFIG_ISDN_DRV_HISAX
 extern void HiSax_init(void);
 #endif
@@ -45,19 +53,33 @@
 extern void pcbit_init(void);
 #endif
 
-void isdn_cards_init(void)
+#ifdef CONFIG_ISDN_DRV_AVMB1
+extern void avmb1_init(void);
+extern void capi_init(void);
+extern void capidrv_init(void);
+#ifdef CONFIG_PCI
+extern int b1pci_init(void);
+#endif
+#endif
+
+void
+isdn_cards_init(void)
 {
 #if CONFIG_ISDN_DRV_ICN
-        icn_init();
-#endif
-#if CONFIG_ISDN_DRV_TELES
-        teles_init();
+	icn_init();
 #endif
 #ifdef CONFIG_ISDN_DRV_HISAX
 	HiSax_init();
 #endif
 #if CONFIG_ISDN_DRV_PCBIT
-        pcbit_init();
+	pcbit_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1
+	avmb1_init();
+#ifdef CONFIG_PCI
+	b1pci_init();
+#endif
+	capi_init();
+	capidrv_init();
 #endif
 }
-
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_cards.h linux-2.0.31-pre3/drivers/isdn/isdn_cards.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_cards.h	1996-04-21 01:56:14.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_cards.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-/* $Id: isdn_cards.h,v 1.1 1996/04/20 16:04:03 fritz Exp $
- *
+/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $
+
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
@@ -16,13 +16,15 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_cards.h,v $
+ * Revision 1.2  1997/02/03 23:31:55  fritz
+ * Reformatted according CodingStyle
+ *
  * Revision 1.1  1996/04/20 16:04:03  fritz
  * Initial revision
  *
  */
 
 extern void isdn_cards_init(void);
-
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_common.c linux-2.0.31-pre3/drivers/isdn/isdn_common.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_common.c	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_common.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,11 +1,11 @@
-/* $Id: isdn_common.c,v 1.28 1996/11/13 02:33:19 fritz Exp $
- *
+/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+
  * Linux ISDN subsystem, common used functions (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -18,9 +18,72 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.44  1997/05/27 15:17:23  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.43  1997/03/31 14:09:43  fritz
+ * Fixed memory leak in isdn_close().
+ *
+ * Revision 1.42  1997/03/30 16:51:08  calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.41  1997/03/24 22:54:41  fritz
+ * Some small fixes in debug code.
+ *
+ * Revision 1.40  1997/03/08 08:13:51  fritz
+ * Bugfix: IIOCSETMAP (Set mapping) was broken.
+ *
+ * Revision 1.39  1997/03/07 01:32:54  fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.38  1997/03/05 21:15:02  fritz
+ * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg()
+ *
+ * Revision 1.37  1997/03/02 14:29:18  fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.36  1997/02/28 02:32:40  fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ *          to isdn_tty.c
+ * Bugfix:  Bisync protocol did not behave like documented.
+ *
+ * Revision 1.35  1997/02/21 13:01:19  fritz
+ * Changes CAUSE message output in kernel log.
+ *
+ * Revision 1.34  1997/02/10 20:12:43  fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.33  1997/02/10 10:05:42  fritz
+ * More changes for Kernel 2.1.X
+ * Symbol information moved to isdn_syms.c
+ *
+ * Revision 1.32  1997/02/03 22:55:26  fritz
+ * Reformatted according CodingStyle.
+ * Changed isdn_writebuf_stub static.
+ * Slow down tty-RING counter.
+ * skb->free stuff replaced by macro.
+ * Bugfix in audio-skb locking.
+ * Bugfix in HL-driver locking.
+ *
+ * Revision 1.31  1997/01/17 01:19:18  fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.30  1997/01/14 01:27:47  fritz
+ * Changed audio receive not to rely on skb->users and skb->lock.
+ * Added ATI2 and related variables.
+ * Started adding full-duplex audio capability.
+ *
+ * Revision 1.29  1997/01/12 23:33:03  fritz
+ * Made isdn_all_eaz foolproof.
+ *
  * Revision 1.28  1996/11/13 02:33:19  fritz
  * Fixed a race condition.
  *
@@ -134,11 +197,13 @@
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/version.h>
-#ifndef __GENKSYMS__      /* Don't want genksyms report unneeded structs */
-#include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
 #endif
+#include <linux/isdn.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #include "isdn_net.h"
@@ -149,13 +214,11 @@
 #include "isdn_cards.h"
 
 /* Debugflags */
-#undef  ISDN_DEBUG_STATCALLB
-#define NEW_ISDN_TIMER_CTRL
+#undef ISDN_DEBUG_STATCALLB
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static int  has_exported = 0;
-static char *isdn_revision      = "$Revision: 1.28 $";
+static char *isdn_revision = "$Revision: 1.44 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -170,18 +233,23 @@
 static char *isdn_audio_revision = ": none $";
 #endif
 
-void isdn_MOD_INC_USE_COUNT(void)
+static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+
+void
+isdn_MOD_INC_USE_COUNT(void)
 {
 	MOD_INC_USE_COUNT;
 }
 
-void isdn_MOD_DEC_USE_COUNT(void)
+void
+isdn_MOD_DEC_USE_COUNT(void)
 {
 	MOD_DEC_USE_COUNT;
 }
 
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
+void
+isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 {
 	int dumpc;
 
@@ -192,26 +260,29 @@
 }
 #endif
 
-static __inline void isdn_trash_skb(struct sk_buff *skb, int rw)
+static __inline void
+isdn_trash_skb(struct sk_buff *skb, int rw)
 {
-        skb->free = 1;
-        kfree_skb(skb, rw);
+	SET_SKB_FREE(skb);
+	kfree_skb(skb, rw);
 }
 
-static void isdn_free_queue(struct sk_buff_head *queue)
+static void
+isdn_free_queue(struct sk_buff_head *queue)
 {
-        struct sk_buff *skb;
-        unsigned long flags;
+	struct sk_buff *skb;
+	unsigned long flags;
 
-        save_flags(flags);
-        cli();
-        if (skb_queue_len(queue))
-                while ((skb = skb_dequeue(queue)))
-                        isdn_trash_skb(skb, FREE_READ);
-        restore_flags(flags);
+	save_flags(flags);
+	cli();
+	if (skb_queue_len(queue))
+		while ((skb = skb_dequeue(queue)))
+			isdn_trash_skb(skb, FREE_READ);
+	restore_flags(flags);
 }
 
-int isdn_dc2minor(int di, int ch)
+int
+isdn_dc2minor(int di, int ch)
 {
 	int i;
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
@@ -222,8 +293,10 @@
 
 static int isdn_timer_cnt1 = 0;
 static int isdn_timer_cnt2 = 0;
+static int isdn_timer_cnt3 = 0;
 
-static void isdn_timer_funct(ulong dummy)
+static void
+isdn_timer_funct(ulong dummy)
 {
 	int tf = dev->tflags;
 
@@ -241,34 +314,35 @@
 			if (tf & ISDN_TIMER_NETDIAL)
 				isdn_net_dial();
 		}
-                if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
-                        isdn_timer_cnt2 = 0;
-                        if (tf & ISDN_TIMER_NETHANGUP)
-                                isdn_net_autohup();
-                        if (tf & ISDN_TIMER_MODEMRING)
-                                isdn_tty_modem_ring();
+		if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
+			isdn_timer_cnt2 = 0;
+			if (tf & ISDN_TIMER_NETHANGUP)
+				isdn_net_autohup();
+			if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) {
+				isdn_timer_cnt3 = 0;
+				if (tf & ISDN_TIMER_MODEMRING)
+					isdn_tty_modem_ring();
+			}
 #if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
-                        if (tf & ISDN_TIMER_IPPP)
-                                isdn_ppp_timer_timeout();
+			if (tf & ISDN_TIMER_IPPP)
+				isdn_ppp_timer_timeout();
 #endif
-                }
+		}
 	}
 	if (tf) {
-                int flags;
+		int flags;
 
 		save_flags(flags);
 		cli();
-                del_timer(&dev->timer);
-#ifndef NEW_ISDN_TIMER_CTRL
-                dev->timer.function = isdn_timer_funct;
-#endif
+		del_timer(&dev->timer);
 		dev->timer.expires = jiffies + ISDN_TIMER_RES;
 		add_timer(&dev->timer);
 		restore_flags(flags);
 	}
 }
 
-void isdn_timer_ctrl(int tf, int onoff)
+void
+isdn_timer_ctrl(int tf, int onoff)
 {
 	int flags;
 
@@ -283,447 +357,287 @@
 		dev->tflags |= tf;
 	else
 		dev->tflags &= ~tf;
-#ifdef NEW_ISDN_TIMER_CTRL
 	if (dev->tflags) {
-                if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
-                        dev->timer.expires = jiffies + ISDN_TIMER_RES;
+		if (!del_timer(&dev->timer))	/* del_timer is 1, when active */
+			dev->timer.expires = jiffies + ISDN_TIMER_RES;
 		add_timer(&dev->timer);
 	}
-#else
-	if (dev->tflags) {
-                del_timer(&dev->timer);
-                dev->timer.function = isdn_timer_funct;
-		dev->timer.expires = jiffies + ISDN_TIMER_RES;
-		add_timer(&dev->timer);
-	}
-#endif
 	restore_flags(flags);
 }
 
 /*
  * Receive a packet from B-Channel. (Called from low-level-module)
  */
-static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
+static void
+isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
 {
-	ulong flags;
 	int i;
-        int midx;
-#ifdef CONFIG_ISDN_AUDIO
-        int ifmt;
-#endif
-	modem_info *info;
-        
-        if ((i = isdn_dc2minor(di,channel))==-1) {
-                isdn_trash_skb(skb, FREE_READ);
-                return;
-        }
+
+	if ((i = isdn_dc2minor(di, channel)) == -1) {
+		isdn_trash_skb(skb, FREE_READ);
+		return;
+	}
 	/* Update statistics */
-        dev->ibytes[i] += skb->len;
+	dev->ibytes[i] += skb->len;
 	/* First, try to deliver data to network-device */
 	if (isdn_net_rcv_skb(i, skb))
 		return;
 	/* No network-device found, deliver to tty or raw-channel */
-        skb->free = 1;
+	SET_SKB_FREE(skb);
 	if (skb->len) {
-                if ((midx = dev->m_idx[i])<0) {
-                        /* if midx is invalid, drop packet */
-                        isdn_trash_skb(skb, FREE_READ);
-                        return;
-                }
-                info  = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
-                ifmt = 1;
-
-                if (info->vonline)
-                        isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
-#endif
-                if ((info->online < 2) &&
-                    (!(info->vonline & 1))) {
-                        /* If Modem not listening, drop data */
-                        isdn_trash_skb(skb, FREE_READ);
-                        return;
-                }
-                if (info->emu.mdmreg[13] & 2)
-                        /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
-                        if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
-                                skb_pull(skb,4);
-                /* The users field of an sk_buff is used in a special way
-                 * with tty's incoming data:
-                 *   users is set to the number of DLE codes when in audio mode.
-                 */
-                skb->users = 0;
-#ifdef CONFIG_ISDN_AUDIO
-                if (info->vonline & 1) {
-                        /* voice conversion/compression */
-                        switch (info->emu.vpar[3]) {
-                                case 2:
-                                case 3:
-                                case 4:
-                                        /* adpcm
-                                         * Since compressed data takes less
-                                         * space, we can overwrite the buffer.
-                                         */
-                                        skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr,
-                                                                           ifmt,
-                                                                           skb->data,
-                                                                           skb->data,
-                                                                           skb->len));
-                                        break;
-                                case 5:
-                                        /* a-law */
-                                        if (!ifmt)
-                                                isdn_audio_ulaw2alaw(skb->data,skb->len);
-                                        break;
-                                case 6:
-                                        /* u-law */
-                                        if (ifmt)
-                                                isdn_audio_alaw2ulaw(skb->data,skb->len);
-                                        break;
-                        }
-                        skb->users = isdn_tty_countDLE(skb->data,skb->len);
-                }
-#endif
-                /* Try to deliver directly via tty-flip-buf if queue is empty */
-                save_flags(flags);
-                cli();
-                if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
-                        if (isdn_tty_try_read(info, skb)) {
-                                restore_flags(flags);
-                                return;
-                        }
-                /* Direct deliver failed or queue wasn't empty.
-                 * Queue up for later dequeueing via timer-irq.
-                 */
-                __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
-                dev->drv[di]->rcvcount[channel] += (skb->len + skb->users);
-                restore_flags(flags);
-                /* Schedule dequeuing */
-                if ((dev->modempoll) && (info->rcvsched))
-                        isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-                wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
+		if (isdn_tty_rcv_skb(i, di, channel, skb))
+			return;
+		wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
 	} else
-                isdn_trash_skb(skb, FREE_READ);
+		isdn_trash_skb(skb, FREE_READ);
 }
 
-void isdn_all_eaz(int di, int ch)
+void
+isdn_all_eaz(int di, int ch)
 {
 	isdn_ctrl cmd;
 
+	if (di < 0)
+		return;
 	cmd.driver = di;
 	cmd.arg = ch;
 	cmd.command = ISDN_CMD_SETEAZ;
-	cmd.num[0] = '\0';
+	cmd.parm.num[0] = '\0';
 	(void) dev->drv[di]->interface->command(&cmd);
 }
 
-static int isdn_status_callback(isdn_ctrl * c)
+static int
+isdn_status_callback(isdn_ctrl * c)
 {
 	int di;
-	int mi;
 	ulong flags;
 	int i;
 	int r;
-	int retval=0;
-        modem_info *info;
+	int retval = 0;
 	isdn_ctrl cmd;
 
 	di = c->driver;
-        i = isdn_dc2minor(di, c->arg);
+	i = isdn_dc2minor(di, c->arg);
 	switch (c->command) {
-                case ISDN_STAT_BSENT:
-			if (i<0)
+		case ISDN_STAT_BSENT:
+			if (i < 0)
 				return -1;
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        if (isdn_net_stat_callback(i, c->command))
-                                return 0;
-                        isdn_tty_bsent(di, c->arg);
-                        wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
-                        break;
-                case ISDN_STAT_STAVAIL:
-                        save_flags(flags);
-                        cli();
-                        dev->drv[di]->stavail += c->arg;
-                        restore_flags(flags);
-                        wake_up_interruptible(&dev->drv[di]->st_waitq);
-                        break;
-                case ISDN_STAT_RUN:
-                        dev->drv[di]->running = 1;
-                        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-                                if (dev->drvmap[i] == di)
-                                        isdn_all_eaz(di, dev->chanmap[i]);
-                        break;
-                case ISDN_STAT_STOP:
-                        dev->drv[di]->running = 0;
-                        break;
-                case ISDN_STAT_ICALL:
-			if (i<0)
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (isdn_net_stat_callback(i, c->command))
+				return 0;
+			if (isdn_tty_stat_callback(i, c))
+				return 0;
+			wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
+			break;
+		case ISDN_STAT_STAVAIL:
+			save_flags(flags);
+			cli();
+			dev->drv[di]->stavail += c->arg;
+			restore_flags(flags);
+			wake_up_interruptible(&dev->drv[di]->st_waitq);
+			break;
+		case ISDN_STAT_RUN:
+			dev->drv[di]->running = 1;
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+				if (dev->drvmap[i] == di)
+					isdn_all_eaz(di, dev->chanmap[i]);
+			break;
+		case ISDN_STAT_STOP:
+			dev->drv[di]->running = 0;
+			break;
+		case ISDN_STAT_ICALL:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num);
+			printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
 #endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
-                                cmd.driver = di;
-                                cmd.arg = c->arg;
-                                cmd.command = ISDN_CMD_HANGUP;
-                                dev->drv[di]->interface->command(&cmd);
-                                return 0;
-                        }
-
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
+				cmd.driver = di;
+				cmd.arg = c->arg;
+				cmd.command = ISDN_CMD_HANGUP;
+				dev->drv[di]->interface->command(&cmd);
+				return 0;
+			}
 			/* Try to find a network-interface which will accept incoming call */
-                        cmd.driver = di;
-                        cmd.arg = c->arg;
-                        cmd.command = ISDN_CMD_LOCK;
-                        dev->drv[di]->interface->command(&cmd);
-			r = isdn_net_find_icall(di, c->arg, i, c->num);
+			cmd.driver = di;
+			cmd.arg = c->arg;
+			cmd.command = ISDN_CMD_LOCK;
+			dev->drv[di]->interface->command(&cmd);
+			r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
 			switch (r) {
-                                case 0:
-                                        /* No network-device replies. Schedule RING-message to
-                                         * tty and set RI-bit of modem-status.
-                                         */
-                                        if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) {
-                                                info = &dev->mdm.info[mi];
-                                                info->msr |= UART_MSR_RI;
-                                                isdn_tty_modem_result(2, info);
-                                                isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
-                                                return 1;
-                                        } else if (dev->drv[di]->reject_bus) {
-                                                cmd.driver = di;
-                                                cmd.arg = c->arg;
-                                                cmd.command = ISDN_CMD_HANGUP;
-                                                dev->drv[di]->interface->command(&cmd);
-                                                retval=2;
-                                        }
-                                        break;
-                                case 1:
-                                        /* Schedule connection-setup */
-                                        isdn_net_dial();
-                                        cmd.driver = di;
-                                        cmd.arg = c->arg;
-                                        cmd.command = ISDN_CMD_ACCEPTD;
-                                        dev->drv[di]->interface->command(&cmd);
-                                        return 1;
-                                        break;
-                                case 2:	/* For calling back, first reject incoming call ... */
-                                case 3:	/* Interface found, but down, reject call actively  */
-                                	retval=2;
-                                        printk(KERN_INFO "isdn: Rejecting Call\n");
-                                        cmd.driver = di;
-                                        cmd.arg = c->arg;
-                                        cmd.command = ISDN_CMD_HANGUP;
-                                        dev->drv[di]->interface->command(&cmd);
-                                        if (r == 3)
-                                                break;
-                                        /* Fall through */
-                                case 4:
-                                        /* ... then start callback. */
-                                        isdn_net_dial();
-                                        return 2;
+				case 0:
+					/* No network-device replies.
+					 * Try ttyI's
+					 */
+					if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0)
+						retval = 1;
+					else if (dev->drv[di]->reject_bus) {
+						cmd.driver = di;
+						cmd.arg = c->arg;
+						cmd.command = ISDN_CMD_HANGUP;
+						dev->drv[di]->interface->command(&cmd);
+						retval = 2;
+					}
+					break;
+				case 1:
+					/* Schedule connection-setup */
+					isdn_net_dial();
+					cmd.driver = di;
+					cmd.arg = c->arg;
+					cmd.command = ISDN_CMD_ACCEPTD;
+					dev->drv[di]->interface->command(&cmd);
+					retval = 1;
+					break;
+				case 2:	/* For calling back, first reject incoming call ... */
+				case 3:	/* Interface found, but down, reject call actively  */
+					retval = 2;
+					printk(KERN_INFO "isdn: Rejecting Call\n");
+					cmd.driver = di;
+					cmd.arg = c->arg;
+					cmd.command = ISDN_CMD_HANGUP;
+					dev->drv[di]->interface->command(&cmd);
+					if (r == 3)
+						break;
+					/* Fall through */
+				case 4:
+					/* ... then start callback. */
+					isdn_net_dial();
+					break;
+			}
+			if (retval != 1) {
+				cmd.driver = di;
+				cmd.arg = c->arg;
+				cmd.command = ISDN_CMD_UNLOCK;
+				dev->drv[di]->interface->command(&cmd);
 			}
-                        cmd.driver = di;
-                        cmd.arg = c->arg;
-                        cmd.command = ISDN_CMD_UNLOCK;
-                        dev->drv[di]->interface->command(&cmd);
-                        return retval;
-                        break;
-                case ISDN_STAT_CINF:
-			if (i<0)
+			return retval;
+			break;
+		case ISDN_STAT_CINF:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num);
+			printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
 #endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        if (strcmp(c->num, "0"))
-                                isdn_net_stat_callback(i, c->command);
-                        break;
-                case ISDN_STAT_CAUSE:
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (strcmp(c->parm.num, "0"))
+				isdn_net_stat_callback(i, c->command);
+			break;
+		case ISDN_STAT_CAUSE:
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num);
+			printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
 #endif
-                        printk(KERN_INFO "isdn: cause: %s\n", c->num);
-                        break;
-                case ISDN_STAT_DCONN:
-			if (i<0)
+			printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
+			       dev->drvid[di], c->arg, c->parm.num);
+			isdn_tty_stat_callback(i, c);
+			break;
+		case ISDN_STAT_DCONN:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
+			printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
 #endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        /* Find any network-device, waiting for D-channel setup */
-                        if (isdn_net_stat_callback(i, c->command))
-                                break;
-
-			if ((mi = dev->m_idx[i]) >= 0) {
-				/* If any tty has just dialed-out, setup B-Channel */
-                                info = &dev->mdm.info[mi];
-				if (info->flags &
-				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (info->dialing == 1) {
-						info->dialing = 2;
-						cmd.driver = di;
-						cmd.arg = c->arg;
-						cmd.command = ISDN_CMD_ACCEPTB;
-						dev->drv[di]->interface->command(&cmd);
-						return 0;
-					}
-				}
-                        }
-                        break;
-                case ISDN_STAT_DHUP:
-			if (i<0)
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			/* Find any net-device, waiting for D-channel setup */
+			if (isdn_net_stat_callback(i, c->command))
+				break;
+			/* Find any ttyI, waiting for D-channel setup */
+			if (isdn_tty_stat_callback(i, c)) {
+				cmd.driver = di;
+				cmd.arg = c->arg;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				dev->drv[di]->interface->command(&cmd);
+				break;
+			}
+			break;
+		case ISDN_STAT_DHUP:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        dev->drv[di]->flags &= ~(1 << (c->arg));
-                        isdn_info_update();
-                        /* Signal hangup to network-devices */
-                        if (isdn_net_stat_callback(i, c->command))
-                                break;
-			if ((mi = dev->m_idx[i]) >= 0) {
-				/* Signal hangup to tty-device */
-                                info = &dev->mdm.info[mi];
-				if (info->flags &
-				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (info->dialing == 1) {
-						info->dialing = 0;
-						isdn_tty_modem_result(7, info);
-					}
-					if (info->online)
-						isdn_tty_modem_result(3, info);
-#ifdef ISDN_DEBUG_MODEM_HUP
-					printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+			printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
 #endif
-					isdn_tty_modem_hup(info);
-					return 0;
-				}
-			}
-                        break;
-                case ISDN_STAT_BCONN:
-			if (i<0)
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->flags &= ~(1 << (c->arg));
+			isdn_info_update();
+			/* Signal hangup to network-devices */
+			if (isdn_net_stat_callback(i, c->command))
+				break;
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_BCONN:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
+			printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
 #endif
-                        /* Signal B-channel-connect to network-devices */
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        dev->drv[di]->flags |= (1 << (c->arg));
-                        isdn_info_update();
-                        if (isdn_net_stat_callback(i, c->command))
-                                break;
-			if ((mi = dev->m_idx[i]) >= 0) {
-				/* Schedule CONNECT-Message to any tty, waiting for it and
-				 * set DCD-bit of its modem-status.
-				 */
-                                info = &dev->mdm.info[mi];
-				if (info->flags &
-				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					info->msr |= UART_MSR_DCD;
-					if (info->dialing)
-						info->dialing = 0;
-					info->rcvsched = 1;
-                                        if (USG_MODEM(dev->usage[i]))
-                                          isdn_tty_modem_result(5, info);
-                                        if (USG_VOICE(dev->usage[i]))
-                                          isdn_tty_modem_result(11, info);
-				}
-			}
-                        break;
-                case ISDN_STAT_BHUP:
-			if (i<0)
+			/* Signal B-channel-connect to network-devices */
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->flags |= (1 << (c->arg));
+			isdn_info_update();
+			if (isdn_net_stat_callback(i, c->command))
+				break;
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_BHUP:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
+			printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
 #endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        dev->drv[di]->flags &= ~(1 << (c->arg));
-                        isdn_info_update();
-			if ((mi = dev->m_idx[i]) >= 0) {
-				/* Signal hangup to tty-device, schedule NO CARRIER-message */
-                                info = &dev->mdm.info[mi];
-				if (info->flags &
-				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (info->msr & UART_MSR_DCD)
-						isdn_tty_modem_result(3, info);
-					info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
-#ifdef ISDN_DEBUG_MODEM_HUP
-					printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
-#endif
-					isdn_tty_modem_hup(info);
-				}
-			}
-                        break;
-                case ISDN_STAT_NODCH:
-			if (i<0)
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			dev->drv[di]->flags &= ~(1 << (c->arg));
+			isdn_info_update();
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_NODCH:
+			if (i < 0)
 				return -1;
 #ifdef ISDN_DEBUG_STATCALLB
-                        printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
+			printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
 #endif
-                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
-                                return 0;
-                        if (isdn_net_stat_callback(i, c->command))
-                                break;
-			if ((mi = dev->m_idx[i]) >= 0) {
-                                info = &dev->mdm.info[mi];
-				if (info->flags &
-				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					if (info->dialing) {
-						info->dialing = 0;
-						isdn_tty_modem_result(6, info);
-					}
-					info->msr &= ~UART_MSR_DCD;
-					if (info->online) {
-						isdn_tty_modem_result(3, info);
-						info->online = 0;
-					}
+			if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+				return 0;
+			if (isdn_net_stat_callback(i, c->command))
+				break;
+			if (isdn_tty_stat_callback(i, c))
+				break;
+			break;
+		case ISDN_STAT_ADDCH:
+			break;
+		case ISDN_STAT_UNLOAD:
+			save_flags(flags);
+			cli();
+			isdn_tty_stat_callback(i, c);
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+				if (dev->drvmap[i] == di) {
+					dev->drvmap[i] = -1;
+					dev->chanmap[i] = -1;
 				}
-			}
-                        break;
-                case ISDN_STAT_ADDCH:
-                        break;
-                case ISDN_STAT_UNLOAD:
-                        save_flags(flags);
-                        cli();
-                        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-                                if (dev->drvmap[i] == di) {
-                                        dev->drvmap[i] = -1;
-                                        dev->chanmap[i] = -1;
-                                }
-                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                modem_info *info = &dev->mdm.info[i];
-                                
-                                if (info->isdn_driver == di) {
-                                        info->isdn_driver = -1;
-                                        info->isdn_channel = -1;
-                                        if (info->online) {
-                                                isdn_tty_modem_result(3, info);
-                                                isdn_tty_modem_hup(info);
-                                        }
-                                }
-                        }
-                        dev->drivers--;
-                        dev->channels -= dev->drv[di]->channels;
-                        kfree(dev->drv[di]->rcverr);
-                        kfree(dev->drv[di]->rcvcount);
-                        for (i = 0; i < dev->drv[di]->channels; i++)
-                                isdn_free_queue(&dev->drv[di]->rpqueue[i]);
-                        kfree(dev->drv[di]->rpqueue);
-                        kfree(dev->drv[di]->rcv_waitq);
-                        kfree(dev->drv[di]->snd_waitq);
-                        kfree(dev->drv[di]);
-                        dev->drv[di] = NULL;
-                        dev->drvid[di][0] = '\0';
-                        isdn_info_update();
-                        restore_flags(flags);
-                        return 0;
-                default:
-                        return -1;
+			dev->drivers--;
+			dev->channels -= dev->drv[di]->channels;
+			kfree(dev->drv[di]->rcverr);
+			kfree(dev->drv[di]->rcvcount);
+			for (i = 0; i < dev->drv[di]->channels; i++)
+				isdn_free_queue(&dev->drv[di]->rpqueue[i]);
+			kfree(dev->drv[di]->rpqueue);
+			kfree(dev->drv[di]->rcv_waitq);
+			kfree(dev->drv[di]->snd_waitq);
+			kfree(dev->drv[di]);
+			dev->drv[di] = NULL;
+			dev->drvid[di][0] = '\0';
+			isdn_info_update();
+			restore_flags(flags);
+			return 0;
+		default:
+			return -1;
 	}
 	return 0;
 }
@@ -731,7 +645,8 @@
 /*
  * Get integer from char-pointer, set pointer to end of number
  */
-int isdn_getnum(char **p)
+int
+isdn_getnum(char **p)
 {
 	int v = -1;
 
@@ -746,14 +661,15 @@
  * isdn_readbchan() tries to get data from the read-queue.
  * It MUST be called with interrupts off.
  */
-int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
+int
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
 {
 	int left;
 	int count;
 	int count_pull;
-        int count_put;
+	int count_put;
 	int dflag;
-        struct sk_buff *skb;
+	struct sk_buff *skb;
 	u_char *cp;
 
 	if (!dev->drv[di])
@@ -768,99 +684,106 @@
 	cp = buf;
 	count = 0;
 	while (left) {
-                if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
-                        break;
-                if (skb->lock)
-                        break;
-                skb->lock = 1;
-                if (skb->users) {
-                        /* users is the count of DLE's in
-                         * this buff when in voice mode.
-                         */
-                        char *p = skb->data;
-                        unsigned long DLEmask = (1 << channel);
-
-                        dflag = 0;
-                        count_pull = count_put = 0;
-                        while ((count_pull < skb->len) && (left-- > 0)) {
-                                if (dev->drv[di]->DLEflag & DLEmask) {
-                                        if (user)
-                                                put_user(DLE,cp++);
-                                        else
-                                                *cp++ = DLE;
-                                        dev->drv[di]->DLEflag &= ~DLEmask;
-                                } else {
-                                        if (user)
-                                                put_user(*p,cp++);
-                                        else
-                                                *cp++ = *p;
-                                        if (*p == DLE) {
-                                                dev->drv[di]->DLEflag |= DLEmask;
-                                                skb->users--;
-                                        }
-                                        p++;
-                                        count_pull++;
-                                }
-                                count_put++;
-                        }
-                        if (count_pull >= skb->len)
-                                dflag = 1;
-                } else {
-                        /* No DLE's in buff, so simply copy it */
-                        dflag = 1;
-                        if ((count_pull = skb->len) > left) {
-                                count_pull = left;
-                                dflag = 0;
-                        }
-                        count_put = count_pull;
-                        if (user)
-                                copy_to_user(cp, skb->data, count_put);
-                        else
-                                memcpy(cp, skb->data, count_put);
-                        cp += count_put;
-                        left -= count_put;
-                }
-                count += count_put;
-                if (fp) {
-                        memset(fp, 0, count_put);
-                        fp += count_put;
-                }
-                if (dflag) {
-                        /* We got all the data in this buff.
-                         * Now we can dequeue it.
-                         */
+		if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+			break;
+#ifdef CONFIG_ISDN_AUDIO
+		if (ISDN_AUDIO_SKB_LOCK(skb))
+			break;
+		ISDN_AUDIO_SKB_LOCK(skb) = 1;
+		if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+			char *p = skb->data;
+			unsigned long DLEmask = (1 << channel);
+
+			dflag = 0;
+			count_pull = count_put = 0;
+			while ((count_pull < skb->len) && (left-- > 0)) {
+				if (dev->drv[di]->DLEflag & DLEmask) {
+					if (user)
+						put_user(DLE, cp++);
+					else
+						*cp++ = DLE;
+					dev->drv[di]->DLEflag &= ~DLEmask;
+				} else {
+					if (user)
+						put_user(*p, cp++);
+					else
+						*cp++ = *p;
+					if (*p == DLE) {
+						dev->drv[di]->DLEflag |= DLEmask;
+						(ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+					}
+					p++;
+					count_pull++;
+				}
+				count_put++;
+			}
+			if (count_pull >= skb->len)
+				dflag = 1;
+		} else {
+#endif
+			/* No DLE's in buff, so simply copy it */
+			dflag = 1;
+			if ((count_pull = skb->len) > left) {
+				count_pull = left;
+				dflag = 0;
+			}
+			count_put = count_pull;
+			if (user)
+				copy_to_user(cp, skb->data, count_put);
+			else
+				memcpy(cp, skb->data, count_put);
+			cp += count_put;
+			left -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
+		}
+#endif
+		count += count_put;
+		if (fp) {
+			memset(fp, 0, count_put);
+			fp += count_put;
+		}
+		if (dflag) {
+			/* We got all the data in this buff.
+			 * Now we can dequeue it.
+			 */
 			if (fp)
 				*(fp - 1) = 0xff;
-                        skb->lock = 0;
-                        skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
-                        isdn_trash_skb(skb, FREE_READ);
+#ifdef CONFIG_ISDN_AUDIO
+			ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+			skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+			isdn_trash_skb(skb, FREE_READ);
 		} else {
-                        /* Not yet emptied this buff, so it
-                         * must stay in the queue, for further calls
-                         * but we pull off the data we got until now.
-                         */
-			skb_pull(skb,count_pull);
-                        skb->lock = 0;
-                }
+			/* Not yet emptied this buff, so it
+			 * must stay in the queue, for further calls
+			 * but we pull off the data we got until now.
+			 */
+			skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+			ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+		}
 		dev->drv[di]->rcvcount[channel] -= count_put;
 	}
 	return count;
 }
 
-static __inline int isdn_minor2drv(int minor)
+static __inline int
+isdn_minor2drv(int minor)
 {
 	return (dev->drvmap[minor]);
 }
 
-static __inline int isdn_minor2chan(int minor)
+static __inline int
+isdn_minor2chan(int minor)
 {
 	return (dev->chanmap[minor]);
 }
 
-#define INF_DV 0x01 /* Data version for /dev/isdninfo */
+#define INF_DV 0x01             /* Data version for /dev/isdninfo */
 
 static char *
- isdn_statstr(void)
+isdn_statstr(void)
 {
 	static char istatbuf[2048];
 	char *p;
@@ -913,7 +836,8 @@
 
 /* Module interface-code */
 
-void isdn_info_update(void)
+void
+isdn_info_update(void)
 {
 	infostruct *p = dev->infochain;
 
@@ -924,7 +848,8 @@
 	wake_up_interruptible(&(dev->info_waitq));
 }
 
-static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+static RWTYPE
+isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
 {
 	uint minor = MINOR(inode->i_rdev);
 	int len = 0;
@@ -935,14 +860,15 @@
 	if (minor == ISDN_MINOR_STATUS) {
 		char *p;
 		if (!file->private_data) {
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
 			interruptible_sleep_on(&(dev->info_waitq));
-                }
+		}
 		p = isdn_statstr();
 		file->private_data = 0;
 		if ((len = strlen(p)) <= count) {
-			copy_to_user(buf, p, len);
+			if (copy_to_user(buf, p, len))
+				return -EFAULT;
 			file->f_pos += len;
 			return len;
 		}
@@ -957,11 +883,11 @@
 		if (!dev->drv[drvidx]->running)
 			return -ENODEV;
 		chidx = isdn_minor2chan(minor);
-                save_flags(flags);
-                cli();
+		save_flags(flags);
+		cli();
 		len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
 		file->f_pos += len;
-                restore_flags(flags);
+		restore_flags(flags);
 		return len;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -969,10 +895,10 @@
 		if (drvidx < 0)
 			return -ENODEV;
 		if (!dev->drv[drvidx]->stavail) {
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
 			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
-                }
+		}
 		if (dev->drv[drvidx]->interface->readstat)
 			len = dev->drv[drvidx]->interface->
 			    readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
@@ -981,10 +907,10 @@
 			len = 0;
 		save_flags(flags);
 		cli();
-                if (len)
-                        dev->drv[drvidx]->stavail -= len;
-                else
-                        dev->drv[drvidx]->stavail = 0;
+		if (len)
+			dev->drv[drvidx]->stavail -= len;
+		else
+			dev->drv[drvidx]->stavail = 0;
 		restore_flags(flags);
 		file->f_pos += len;
 		return len;
@@ -996,12 +922,14 @@
 	return -ENODEV;
 }
 
-static LSTYPE isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
+static LSTYPE
+isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
 {
 	return -ESPIPE;
 }
 
-static RWTYPE isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+static RWTYPE
+isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
 {
 	uint minor = MINOR(inode->i_rdev);
 	int drvidx;
@@ -1045,10 +973,12 @@
 	return -ENODEV;
 }
 
-static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
+#if (LINUX_VERSION_CODE < 0x020117)
+static int
+isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
 {
 	uint minor = MINOR(inode->i_rdev);
-        int drvidx  = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
 	if (minor == ISDN_MINOR_STATUS) {
 		if (file->private_data)
@@ -1063,49 +993,81 @@
 		if (drvidx < 0)
 			return -ENODEV;
 		if (dev->drv[drvidx]->stavail)
-                        return 1;
-                else {
-                        if (st)
-                                select_wait(&(dev->drv[drvidx]->st_waitq), st);
-                        return 0;
-                }
+			return 1;
+		else {
+			if (st)
+				select_wait(&(dev->drv[drvidx]->st_waitq), st);
+			return 0;
+		}
 		return 1;
-	 }
+	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
 		return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
 #endif
 	return -ENODEV;
 }
+#else
+static unsigned int
+isdn_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask = 0;
+	unsigned int minor = MINOR(file->f_inode->i_rdev);
+	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+
+	if (minor == ISDN_MINOR_STATUS) {
+		poll_wait(&(dev->info_waitq), wait);
+		/* mask = POLLOUT | POLLWRNORM; */
+		if (file->private_data) {
+			mask |= POLLIN | POLLRDNORM;
+		}
+		return mask;
+	}
+	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+		poll_wait(&(dev->drv[drvidx]->st_waitq), wait);
+		if (drvidx < 0) {
+			printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n");
+			return POLLERR;
+		}
+		mask = POLLOUT | POLLWRNORM;
+		if (dev->drv[drvidx]->stavail) {
+			mask |= POLLIN | POLLRDNORM;
+		}
+		return mask;
+	}
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return (isdn_ppp_poll(file, wait));
+#endif
+	printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
+	return POLLERR;
+}
+#endif
 
-static int isdn_set_allcfg(char *src)
+static int
+isdn_set_allcfg(char *src)
 {
 	int ret;
 	int i;
 	ulong flags;
-	char buf[1024];
 	isdn_net_ioctl_cfg cfg;
 	isdn_net_ioctl_phone phone;
 
 	if ((ret = isdn_net_rmall()))
 		return ret;
+	if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
+		return ret;
 	save_flags(flags);
 	cli();
-	if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) {
-		restore_flags(flags);
-		return ret;
-	}
-	copy_from_user((char *) &i, src, sizeof(int));
-        src += sizeof(int);
+	src += sizeof(int);
 	while (i) {
-		char *c;
-		char *c2;
+		int phone_len;
+		int out_flag;
 
-		if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) {
+		if ((ret = copy_from_user((char *) &cfg, src, sizeof(cfg)))) {
 			restore_flags(flags);
 			return ret;
 		}
-		copy_from_user((char *) &cfg, src, sizeof(cfg));
 		src += sizeof(cfg);
 		if (!isdn_net_new(cfg.name, NULL)) {
 			restore_flags(flags);
@@ -1115,49 +1077,31 @@
 			restore_flags(flags);
 			return ret;
 		}
-		if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
-			restore_flags(flags);
-			return ret;
-		}
-		copy_from_user(buf, src, sizeof(buf));
-		src += sizeof(buf);
-		c = buf;
-		while (*c) {
-			if ((c2 = strchr(c, ' ')))
-				*c2++ = '\0';
-			strcpy(phone.phone, c);
-			strcpy(phone.name, cfg.name);
-			phone.outgoing = 0;
-			if ((ret = isdn_net_addphone(&phone))) {
+		phone_len = out_flag = 0;
+		while (out_flag < 2) {
+			if ((ret = verify_area(VERIFY_READ, src, 1))) {
 				restore_flags(flags);
 				return ret;
 			}
-			if (c2)
-				c = c2;
-			else
-				c += strlen(c);
-		}
-		if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
-			restore_flags(flags);
-			return ret;
-		}
-		copy_from_user(buf, src, sizeof(buf));
-		src += sizeof(buf);
-		c = buf;
-		while (*c) {
-			if ((c2 = strchr(c, ' ')))
-				*c2++ = '\0';
-			strcpy(phone.phone, c);
-			strcpy(phone.name, cfg.name);
-			phone.outgoing = 1;
-			if ((ret = isdn_net_addphone(&phone))) {
-				restore_flags(flags);
-				return ret;
+			GET_USER(phone.phone[phone_len], src++);
+			if ((phone.phone[phone_len] == ' ') ||
+			    (phone.phone[phone_len] == '\0')) {
+				if (phone_len) {
+					phone.phone[phone_len] = '\0';
+					strcpy(phone.name, cfg.name);
+					phone.outgoing = out_flag;
+					if ((ret = isdn_net_addphone(&phone))) {
+						restore_flags(flags);
+						return ret;
+					}
+				} else
+					out_flag++;
+				phone_len = 0;
 			}
-			if (c2)
-				c = c2;
-			else
-				c += strlen(c);
+			if (++phone_len >= sizeof(phone.phone))
+				printk(KERN_WARNING
+				       "%s: IIOCSETSET phone number too long, ignored\n",
+				       cfg.name);
 		}
 		i--;
 	}
@@ -1165,7 +1109,8 @@
 	return 0;
 }
 
-static int isdn_get_allcfg(char *dest)
+static int
+isdn_get_allcfg(char *dest)
 {
 	isdn_net_ioctl_cfg cfg;
 	isdn_net_ioctl_phone phone;
@@ -1178,7 +1123,7 @@
 	cli();
 	p = dev->netdev;
 	while (p) {
-		if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 10))) {
+		if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
 			restore_flags(flags);
 			return ret;
 		}
@@ -1196,11 +1141,18 @@
 		cfg.p_encap = p->local.p_encap;
 		cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
 		cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
-		cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0;
-		cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
-		copy_to_user(dest, p->local.name, 10);
+		cfg.chargehup = (p->local.hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+		cfg.ihup = (p->local.hupflags & ISDN_INHUP) ? 1 : 0;
+		cfg.chargeint = p->local.chargeint;
+		if (copy_to_user(dest, p->local.name, 10)) {
+			restore_flags(flags);
+			return -EFAULT;
+		}
 		dest += 10;
-		copy_to_user(dest, (char *) &cfg, sizeof(cfg));
+		if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) {
+			restore_flags(flags);
+			return -EFAULT;
+		}
 		dest += sizeof(cfg);
 		strcpy(phone.name, p->local.name);
 		phone.outgoing = 0;
@@ -1216,51 +1168,63 @@
 			return ret;
 		} else
 			dest += ret;
+		put_user(0, dest);
 		p = p->next;
 	}
 	restore_flags(flags);
 	return 0;
 }
 
-static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
 	uint minor = MINOR(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
 	int chidx;
 	int ret;
+	int i;
+	char *p;
 	char *s;
-	char name[10];
-	char bname[21];
-	isdn_ioctl_struct iocts;
-	isdn_net_ioctl_phone phone;
-	isdn_net_ioctl_cfg cfg;
+	union iocpar {
+		char name[10];
+		char bname[22];
+		isdn_ioctl_struct iocts;
+		isdn_net_ioctl_phone phone;
+		isdn_net_ioctl_cfg cfg;
+	} iocpar;
+
+#define name  iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
 
 	if (minor == ISDN_MINOR_STATUS) {
-                switch (cmd) {
-                        case IIOCGETDVR:
-                                return(TTY_DV +
-                                       (NET_DV << 8) +
-                                       (INF_DV << 16));
-                        case IIOCGETCPS:
-                                if (arg) {
-                                        ulong *p = (ulong *)arg;
-                                        int i;
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                                               sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
-                                                return ret;
-                                        for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
-                                                put_user(dev->ibytes[i],p++);
-                                                put_user(dev->obytes[i],p++);
-                                        }
-                                        return 0;
-                                } else
-                                        return -EINVAL;
-                                break;
-                        default:
-		                return -EINVAL;
-                }
-        }
+		switch (cmd) {
+			case IIOCGETDVR:
+				return (TTY_DV +
+					(NET_DV << 8) +
+					(INF_DV << 16));
+			case IIOCGETCPS:
+				if (arg) {
+					ulong *p = (ulong *) arg;
+					int i;
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+						return ret;
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						put_user(dev->ibytes[i], p++);
+						put_user(dev->obytes[i], p++);
+					}
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				return -EINVAL;
+		}
+	}
 	if (!dev->drivers)
 		return -ENODEV;
 	if (minor < ISDN_MINOR_CTRL) {
@@ -1275,336 +1239,329 @@
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		switch (cmd) {
 #ifdef CONFIG_NETDEVICES
-                        case IIOCNETAIF:
-                                /* Add a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
-                                                return ret;
-                                        copy_from_user(name, (char *) arg, sizeof(name));
-                                        s = name;
-                                } else
-                                        s = NULL;
-                                if ((s = isdn_net_new(s, NULL))) {
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
-                                                return ret;
-                                        copy_to_user((char *) arg, s, strlen(s) + 1);
-                                        return 0;
-                                } else
-                                        return -ENODEV;
-                        case IIOCNETASL:
-                                /* Add a slave to a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
-                                                return ret;
-                                        copy_from_user(bname, (char *) arg, sizeof(bname));
-                                } else
-                                        return -EINVAL;
-                                if ((s = isdn_net_newslave(bname))) {
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
-                                                return ret;
-                                        copy_to_user((char *) arg, s, strlen(s) + 1);
-                                        return 0;
-                                } else
-                                        return -ENODEV;
-                        case IIOCNETDIF:
-                                /* Delete a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
-                                                return ret;
-                                        copy_from_user(name, (char *) arg, sizeof(name));
-                                        return isdn_net_rm(name);
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETSCF:
-                                /* Set configurable parameters of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
-                                                return ret;
-                                        copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
-                                        return isdn_net_setcfg(&cfg);
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETGCF:
-                                /* Get configurable parameters of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
-                                                return ret;
-                                        copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
-                                        if (!(ret = isdn_net_getcfg(&cfg))) {
-                                                if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
-                                                        return ret;
-                                                copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg));
-                                        }
-                                        return ret;
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETANM:
-                                /* Add a phone-number to a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
-                                                return ret;
-                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
-                                        return isdn_net_addphone(&phone);
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETGNM:
-                                /* Get list of phone-numbers of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
-                                                return ret;
-                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
-                                        return isdn_net_getphones(&phone, (char *) arg);
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETDNM:
-                                /* Delete a phone-number of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
-                                                return ret;
-                                        copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
-                                        return isdn_net_delphone(&phone);
-                                } else
-                                        return -EINVAL;
-                        case IIOCNETDIL:
-                                /* Force dialing of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
-                                                return ret;
-                                        copy_from_user(name, (char *) arg, sizeof(name));
-                                        return isdn_net_force_dial(name);
-                                } else
-                                        return -EINVAL;
+			case IIOCNETAIF:
+				/* Add a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+						return ret;
+					s = name;
+				} else
+					s = NULL;
+				if ((s = isdn_net_new(s, NULL))) {
+					if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+						return ret;
+					return 0;
+				} else
+					return -ENODEV;
+			case IIOCNETASL:
+				/* Add a slave to a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user(bname, (char *) arg, sizeof(bname) - 1)))
+						return ret;
+				} else
+					return -EINVAL;
+				if ((s = isdn_net_newslave(bname))) {
+					if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+						return ret;
+					return 0;
+				} else
+					return -ENODEV;
+			case IIOCNETDIF:
+				/* Delete a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+						return ret;
+					return isdn_net_rm(name);
+				} else
+					return -EINVAL;
+			case IIOCNETSCF:
+				/* Set configurable parameters of a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+						return ret;
+					return isdn_net_setcfg(&cfg);
+				} else
+					return -EINVAL;
+			case IIOCNETGCF:
+				/* Get configurable parameters of a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+						return ret;
+					if (!(ret = isdn_net_getcfg(&cfg))) {
+						if ((ret = copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))))
+							return ret;
+					}
+					return ret;
+				} else
+					return -EINVAL;
+			case IIOCNETANM:
+				/* Add a phone-number to a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+						return ret;
+					return isdn_net_addphone(&phone);
+				} else
+					return -EINVAL;
+			case IIOCNETGNM:
+				/* Get list of phone-numbers of a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+						return ret;
+					return isdn_net_getphones(&phone, (char *) arg);
+				} else
+					return -EINVAL;
+			case IIOCNETDNM:
+				/* Delete a phone-number of a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+						return ret;
+					return isdn_net_delphone(&phone);
+				} else
+					return -EINVAL;
+			case IIOCNETDIL:
+				/* Force dialing of a network-interface */
+				if (arg) {
+					if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+						return ret;
+					return isdn_net_force_dial(name);
+				} else
+					return -EINVAL;
 #ifdef CONFIG_ISDN_PPP
-                        case IIOCNETALN:
-                                if(arg) {
-                                        if ((ret = verify_area(VERIFY_READ,
-                                                               (void*)arg,
-                                                               sizeof(name))))
-                                                return ret;
-                                } else
-                                        return -EINVAL;
-                                copy_from_user(name,(char*)arg,sizeof(name));
-                                return isdn_ppp_dial_slave(name);
-                        case IIOCNETDLN:
-                                if(arg) {
-                                        if ((ret = verify_area(VERIFY_READ,
-                                                               (void*)arg,
-                                                               sizeof(name))))
-                                                return ret;
-                                } else
-                                        return -EINVAL;
-                                copy_from_user(name,(char*)arg,sizeof(name));
-                                return isdn_ppp_hangup_slave(name);
-#endif
-                        case IIOCNETHUP:
-                                /* Force hangup of a network-interface */
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
-                                                return ret;
-                                        copy_from_user(name, (char *) arg, sizeof(name));
-                                        return isdn_net_force_hangup(name);
-                                } else
-                                        return -EINVAL;
-                                break;
-#endif				/* CONFIG_NETDEVICES */
-                        case IIOCSETVER:
-                                dev->net_verbose = arg;
-                                printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
-                                return 0;
-                        case IIOCSETGST:
-                                if (arg)
-                                        dev->global_flags |= ISDN_GLOBAL_STOPPED;
-                                else
-                                        dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-                                printk(KERN_INFO "isdn: Global Mode %s\n",
-                                       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
-                                return 0;
-                        case IIOCSETBRJ:
-                                drvidx = -1;
-                                if (arg) {
-                                        int i;
-                                        char *p;
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg,
-                                                               sizeof(isdn_ioctl_struct))))
-                                                return ret;
-                                        copy_from_user((char *) &iocts, (char *) arg,
-                                                      sizeof(isdn_ioctl_struct));
-                                        if (strlen(iocts.drvid)) {
-                                                if ((p = strchr(iocts.drvid, ',')))
-                                                        *p = 0;
-                                                drvidx = -1;
-                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                                drvidx = i;
-                                                                break;
-                                                        }
-                                        }
-                                }
-                                if (drvidx == -1)
-                                        return -ENODEV;
-                                dev->drv[drvidx]->reject_bus = iocts.arg;
-                                return 0;
-                        case IIOCGETSET:
-                                /* Get complete setup (all network-interfaces and profile-
-                                   settings of all tty-devices */
-                                if (arg)
-                                        return (isdn_get_allcfg((char *) arg));
-                                else
-                                        return -EINVAL;
-                                break;
-                        case IIOCSETSET:
-                                /* Set complete setup (all network-interfaces and profile-
-                                   settings of all tty-devices */
-                                if (arg)
-                                        return (isdn_set_allcfg((char *) arg));
-                                else
-                                        return -EINVAL;
-                                break;
-                        case IIOCSIGPRF:
-                                dev->profd = current;
-                                return 0;
-                                break;
-                        case IIOCGETPRF:
-                                /* Get all Modem-Profiles */
-                                if (arg) {
-                                        char *p = (char *) arg;
-                                        int i;
-                                        
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                                               (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
-                                                               * ISDN_MAX_CHANNELS)))
-                                                return ret;
-                                        
-                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                copy_to_user(p, dev->mdm.info[i].emu.profile,
-                                                            ISDN_MODEM_ANZREG);
-                                                p += ISDN_MODEM_ANZREG;
-                                                copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
-                                                p += ISDN_MSNLEN;
-                                        }
-                                        return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
-                                } else
-                                        return -EINVAL;
-                                break;
-                        case IIOCSETPRF:
-                                /* Set all Modem-Profiles */
-                                if (arg) {
-                                        char *p = (char *) arg;
-                                        int i;
-                                        
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg,
-                                                               (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
-                                                               * ISDN_MAX_CHANNELS)))
-                                                return ret;
-                                        
-                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                                copy_from_user(dev->mdm.info[i].emu.profile, p,
-                                                              ISDN_MODEM_ANZREG);
-                                                p += ISDN_MODEM_ANZREG;
-                                                copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
-                                                p += ISDN_MSNLEN;
-                                        }
-                                        return 0;
-                                } else
-                                        return -EINVAL;
-                                break;
-                        case IIOCSETMAP:
-                        case IIOCGETMAP:
-                                /* Set/Get MSN->EAZ-Mapping for a driver */
-                                if (arg) {
-                                        int i;
-                                        char *p;
-                                        char nstring[255];
-                                        
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg,
-                                                               sizeof(isdn_ioctl_struct))))
-                                                return ret;
-                                        copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
-                                        if (strlen(iocts.drvid)) {
-                                                drvidx = -1;
-                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                                drvidx = i;
-                                                                break;
-                                                        }
-                                        } else
-                                                drvidx = 0;
-                                        if (drvidx == -1)
-                                                return -ENODEV;
-                                        if (cmd == IIOCSETMAP) {
-                                                if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
-                                                        return ret;
-                                                copy_from_user(nstring, (char *) iocts.arg, 255);
-                                                memset(dev->drv[drvidx]->msn2eaz, 0,
-                                                       sizeof(dev->drv[drvidx]->msn2eaz));
-                                                p = strtok(nstring, ",");
-                                                i = 0;
-                                                while ((p) && (i < 10)) {
-                                                        strcpy(dev->drv[drvidx]->msn2eaz[i++], p);
-                                                        p = strtok(NULL, ",");
-                                                }
-                                        } else {
-                                                p = nstring;
-                                                for (i = 0; i < 10; i++)
-                                                        p += sprintf(p, "%s%s",
-                                                                     strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-                                                                     dev->drv[drvidx]->msn2eaz[i] : "-",
-                                                                     (i < 9) ? "," : "\0");
-                                                if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
-                                                                       strlen(nstring) + 1)))
-                                                        return ret;
-                                                copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1);
-                                        }
-                                        return 0;
-                                } else
-                                        return -EINVAL;
-                        case IIOCDBGVAR:
-                                if (arg) {
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
-                                                return ret;
-                                        copy_to_user((char *) arg, (char *) &dev, sizeof(ulong));
-                                        return 0;
-                                } else
-                                        return -EINVAL;
-                                break;
-                        default:
-                                if ((cmd&IIOCDRVCTL)==IIOCDRVCTL)
-                                        cmd = ((cmd>>_IOC_NRSHIFT)&_IOC_NRMASK)& ISDN_DRVIOCTL_MASK;
+			case IIOCNETALN:
+				if (!arg)
+					return -EINVAL;
+				if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+					return ret;
+				return isdn_ppp_dial_slave(name);
+			case IIOCNETDLN:
+				if (!arg)
+					return -EINVAL;
+				if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+					return ret;
+				return isdn_ppp_hangup_slave(name);
+#endif
+			case IIOCNETHUP:
+				/* Force hangup of a network-interface */
+				if (!arg)
+					return -EINVAL;
+			        if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+			        	return ret;
+			        return isdn_net_force_hangup(name);
+				break;
+#endif                          /* CONFIG_NETDEVICES */
+			case IIOCSETVER:
+				dev->net_verbose = arg;
+				printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+				return 0;
+			case IIOCSETGST:
+				if (arg)
+					dev->global_flags |= ISDN_GLOBAL_STOPPED;
+				else
+					dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+				printk(KERN_INFO "isdn: Global Mode %s\n",
+				       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+				return 0;
+			case IIOCSETBRJ:
+				drvidx = -1;
+				if (arg) {
+					int i;
+					char *p;
+					if ((ret = copy_from_user((char *) &iocts, (char *) arg,
+					      sizeof(isdn_ioctl_struct))))
+						return ret;
+					if (strlen(iocts.drvid)) {
+						if ((p = strchr(iocts.drvid, ',')))
+							*p = 0;
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
+					}
+				}
+				if (drvidx == -1)
+					return -ENODEV;
+				dev->drv[drvidx]->reject_bus = iocts.arg;
+				return 0;
+			case IIOCGETSET:
+				/* Get complete setup (all network-interfaces and profile-
+				   settings of all tty-devices */
+				if (arg)
+					return (isdn_get_allcfg((char *) arg));
+				else
+					return -EINVAL;
+				break;
+			case IIOCSETSET:
+				/* Set complete setup (all network-interfaces and profile-
+				   settings of all tty-devices */
+				if (arg)
+					return (isdn_set_allcfg((char *) arg));
 				else
 					return -EINVAL;
-                                if (arg) {
-                                        int i;
-                                        char *p;
-                                        if ((ret = verify_area(VERIFY_READ, (void *) arg,
-                                                               sizeof(isdn_ioctl_struct))))
-                                                return ret;
-                                        copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
-                                        if (strlen(iocts.drvid)) {
-                                                if ((p = strchr(iocts.drvid, ',')))
-                                                        *p = 0;
-                                                drvidx = -1;
-                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                                drvidx = i;
-                                                                break;
-                                                        }
-                                        } else
-                                                drvidx = 0;
-                                        if (drvidx == -1)
-                                                return -ENODEV;
-                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                                               sizeof(isdn_ioctl_struct))))
-                                                return ret;
-                                        c.driver = drvidx;
-                                        c.command = ISDN_CMD_IOCTL;
-                                        c.arg = cmd;
-                                        memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
-                                        ret = dev->drv[drvidx]->interface->command(&c);
-                                        memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
-                                        copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
-                                        return ret;
-                                } else
-                                        return -EINVAL;
+				break;
+			case IIOCSIGPRF:
+				dev->profd = current;
+				return 0;
+				break;
+			case IIOCGETPRF:
+				/* Get all Modem-Profiles */
+				if (arg) {
+					char *p = (char *) arg;
+					int i;
+
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					(ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+						   * ISDN_MAX_CHANNELS)))
+						return ret;
+
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+						      ISDN_MODEM_ANZREG))
+							return -EFAULT;
+						p += ISDN_MODEM_ANZREG;
+						if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+							return -EFAULT;
+						p += ISDN_MSNLEN;
+					}
+					return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
+				} else
+					return -EINVAL;
+				break;
+			case IIOCSETPRF:
+				/* Set all Modem-Profiles */
+				if (arg) {
+					char *p = (char *) arg;
+					int i;
+
+					if ((ret = verify_area(VERIFY_READ, (void *) arg,
+					(ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+						   * ISDN_MAX_CHANNELS)))
+						return ret;
+
+					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+						if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
+						      ISDN_MODEM_ANZREG)))
+							return ret;
+						p += ISDN_MODEM_ANZREG;
+						if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
+							return ret;
+						p += ISDN_MSNLEN;
+					}
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			case IIOCSETMAP:
+			case IIOCGETMAP:
+				/* Set/Get MSN->EAZ-Mapping for a driver */
+				if (arg) {
+
+					if ((ret = copy_from_user((char *) &iocts,
+							    (char *) arg,
+					     sizeof(isdn_ioctl_struct))))
+						return ret;
+					if (strlen(iocts.drvid)) {
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
+					} else
+						drvidx = 0;
+					if (drvidx == -1)
+						return -ENODEV;
+					if (cmd == IIOCSETMAP) {
+						int loop = 1;
+
+						p = (char *) iocts.arg;
+						i = 0;
+						while (loop) {
+							int j = 0;
+
+							while (1) {
+								if ((ret = verify_area(VERIFY_READ, p, 1)))
+									return ret;
+								GET_USER(bname[j], p++);
+								switch (bname[j]) {
+									case '\0':
+										loop = 0;
+										/* Fall through */
+									case ',':
+										bname[j] = '\0';
+										strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+										j = ISDN_MSNLEN;
+										break;
+									default:
+										j++;
+								}
+								if (j >= ISDN_MSNLEN)
+									break;
+							}
+							if (++i > 9)
+								break;
+						}
+					} else {
+						p = (char *) iocts.arg;
+						for (i = 0; i < 10; i++) {
+							sprintf(bname, "%s%s",
+								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+								dev->drv[drvidx]->msn2eaz[i] : "-",
+								(i < 9) ? "," : "\0");
+							if ((ret = copy_to_user(p, bname, strlen(bname) + 1)))
+								return ret;
+							p += strlen(bname);
+						}
+					}
+					return 0;
+				} else
+					return -EINVAL;
+			case IIOCDBGVAR:
+				if (arg) {
+					if ((ret = copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))))
+						return ret;
+					return 0;
+				} else
+					return -EINVAL;
+				break;
+			default:
+				if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+					cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+				else
+					return -EINVAL;
+				if (arg) {
+					int i;
+					char *p;
+					if ((ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))))
+						return ret;
+					if (strlen(iocts.drvid)) {
+						if ((p = strchr(iocts.drvid, ',')))
+							*p = 0;
+						drvidx = -1;
+						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+								drvidx = i;
+								break;
+							}
+					} else
+						drvidx = 0;
+					if (drvidx == -1)
+						return -ENODEV;
+					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					     sizeof(isdn_ioctl_struct))))
+						return ret;
+					c.driver = drvidx;
+					c.command = ISDN_CMD_IOCTL;
+					c.arg = cmd;
+					memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+					ret = dev->drv[drvidx]->interface->command(&c);
+					memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+					if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
+						return -EFAULT;
+					return ret;
+				} else
+					return -EINVAL;
 		}
 	}
 #ifdef CONFIG_ISDN_PPP
@@ -1612,6 +1569,12 @@
 		return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
 #endif
 	return -ENODEV;
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
 }
 
 /*
@@ -1619,7 +1582,8 @@
  * MOD_INC_USE_COUNT make sure that the driver memory is not freed
  * while the device is in use.
  */
-static int isdn_open(struct inode *ino, struct file *filep)
+static int
+isdn_open(struct inode *ino, struct file *filep)
 {
 	uint minor = MINOR(ino->i_rdev);
 	int drvidx;
@@ -1671,20 +1635,21 @@
 	if (minor <= ISDN_MINOR_PPPMAX) {
 		int ret;
 		if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
-		        MOD_INC_USE_COUNT;
+			MOD_INC_USE_COUNT;
 		return ret;
 	}
 #endif
 	return -ENODEV;
 }
 
-static void isdn_close(struct inode *ino, struct file *filep)
+static CLOSETYPE
+isdn_close(struct inode *ino, struct file *filep)
 {
 	uint minor = MINOR(ino->i_rdev);
 	int drvidx;
 	isdn_ctrl c;
 
-        MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p = dev->infochain;
 		infostruct *q = NULL;
@@ -1695,37 +1660,39 @@
 				else
 					dev->infochain = (infostruct *) (p->next);
 				kfree(p);
-				return;
+				return CLOSEVAL;
+				kfree(p);
 			}
 			q = p;
 			p = (infostruct *) (p->next);
 		}
+		return CLOSEVAL;
 		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-                return;
 	}
 	if (minor < ISDN_MINOR_CTRL) {
 		drvidx = isdn_minor2drv(minor);
+			return CLOSEVAL;
 		if (drvidx < 0)
-			return;
 		c.command = ISDN_CMD_UNLOCK;
 		c.driver = drvidx;
+		return CLOSEVAL;
 		(void) dev->drv[drvidx]->interface->command(&c);
-		return;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+			return CLOSEVAL;
 		if (drvidx < 0)
-			return;
 		if (dev->profd == current)
 			dev->profd = NULL;
 		c.command = ISDN_CMD_UNLOCK;
 		c.driver = drvidx;
+		return CLOSEVAL;
 		(void) dev->drv[drvidx]->interface->command(&c);
-		return;
 	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
 		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+	return CLOSEVAL;
 #endif
 }
 
@@ -1734,17 +1701,21 @@
 	isdn_lseek,
 	isdn_read,
 	isdn_write,
-	NULL,			/* isdn_readdir */
-	isdn_select,		/* isdn_select */
-	isdn_ioctl,		/* isdn_ioctl */
-	NULL,			/* isdn_mmap */
+	NULL,                   /* isdn_readdir */
+#if (LINUX_VERSION_CODE < 0x020117)
+	isdn_select,            /* isdn_select */
+#else
+	isdn_poll,              /* isdn_poll */
+#endif
+	isdn_ioctl,             /* isdn_ioctl */
+	NULL,                   /* isdn_mmap */
 	isdn_open,
 	isdn_close,
-	NULL			/* fsync */
+	NULL                    /* fsync */
 };
 
 char *
- isdn_map_eaz2msn(char *msn, int di)
+isdn_map_eaz2msn(char *msn, int di)
 {
 	driver *this = dev->drv[di];
 	int i;
@@ -1762,13 +1733,14 @@
  * Find an unused ISDN-channel, whose feature-flags match the
  * given L2- and L3-protocols.
  */
-int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
-		     ,int pre_chan)
+int
+isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
+		      ,int pre_chan)
 {
 	int i;
 	ulong flags;
 	ulong features;
-        isdn_ctrl cmd;
+	isdn_ctrl cmd;
 
 	save_flags(flags);
 	cli();
@@ -1786,10 +1758,10 @@
 						dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
 						dev->usage[i] |= usage;
 						isdn_info_update();
-                                                cmd.driver = d;
-                                                cmd.arg = 0;
-                                                cmd.command = ISDN_CMD_LOCK;
-                                                (void) dev->drv[d]->interface->command(&cmd);
+						cmd.driver = d;
+						cmd.arg = 0;
+						cmd.command = ISDN_CMD_LOCK;
+						(void) dev->drv[d]->interface->command(&cmd);
 						restore_flags(flags);
 						return i;
 					} else {
@@ -1797,10 +1769,10 @@
 							dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
 							dev->usage[i] |= usage;
 							isdn_info_update();
-                                                        cmd.driver = d;
-                                                        cmd.arg = 0;
-                                                        cmd.command = ISDN_CMD_LOCK;
-                                                        (void) dev->drv[d]->interface->command(&cmd);
+							cmd.driver = d;
+							cmd.arg = 0;
+							cmd.command = ISDN_CMD_LOCK;
+							(void) dev->drv[d]->interface->command(&cmd);
 							restore_flags(flags);
 							return i;
 						}
@@ -1815,7 +1787,8 @@
 /*
  * Set state of ISDN-channel to 'unused'
  */
-void isdn_free_channel(int di, int ch, int usage)
+void
+isdn_free_channel(int di, int ch, int usage)
 {
 	int i;
 	ulong flags;
@@ -1829,15 +1802,15 @@
 		    (dev->chanmap[i] == ch)) {
 			dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
 			strcpy(dev->num[i], "???");
-                        dev->ibytes[i] = 0;
-                        dev->obytes[i] = 0;
+			dev->ibytes[i] = 0;
+			dev->obytes[i] = 0;
 			isdn_info_update();
-                        isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
-                        cmd.driver = di;
-                        cmd.arg = ch;
-                        cmd.command = ISDN_CMD_UNLOCK;
-                        restore_flags(flags);
-                        (void) dev->drv[di]->interface->command(&cmd);
+			isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
+			cmd.driver = di;
+			cmd.arg = ch;
+			cmd.command = ISDN_CMD_UNLOCK;
+			restore_flags(flags);
+			(void) dev->drv[di]->interface->command(&cmd);
 			return;
 		}
 	restore_flags(flags);
@@ -1846,7 +1819,8 @@
 /*
  * Cancel Exclusive-Flag for ISDN-channel
  */
-void isdn_unexclusive_channel(int di, int ch)
+void
+isdn_unexclusive_channel(int di, int ch)
 {
 	int i;
 	ulong flags;
@@ -1874,55 +1848,57 @@
  * len     = Length of packet-data
  *
  */
-void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len) 
+static void
+isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
 {
-        struct sk_buff *skb;
+	struct sk_buff *skb;
 
 	if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 		return;
-        skb = dev_alloc_skb(len);
-        if (skb) {
-                memcpy(skb_put(skb, len), buf, len);
-                isdn_receive_skb_callback(drvidx, chan, skb);
-        } else
-                printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
+	skb = dev_alloc_skb(len);
+	if (skb) {
+		memcpy(skb_put(skb, len), buf, len);
+		isdn_receive_skb_callback(drvidx, chan, skb);
+	} else
+		printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
 }
 
 /*
  *  writebuf replacement for SKB_ABLE drivers
  */
-int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, 
-		       int user)
+static int
+isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
+		   int user)
 {
 	int ret;
 
-        if (dev->drv[drvidx]->interface->writebuf)
-                ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
-                                                            len, user);
-        else {
-                struct sk_buff * skb;
-
-                skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
-                                GFP_ATOMIC);
-                if (skb == NULL)
-                        return 0;
-
-                skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
-                skb->free = 1;
-
-                if (user)
-                        copy_from_user(skb_put(skb, len), buf, len);
-                else
-                        memcpy(skb_put(skb, len), buf, len);
-
-                ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
-                                                                chan, skb);
-                if (ret <= 0)
-                        kfree_skb(skb, FREE_WRITE);
-        }
-        if (ret > 0)
-                dev->obytes[isdn_dc2minor(drvidx,chan)] += ret;
-        return ret;
+	if (dev->drv[drvidx]->interface->writebuf)
+		ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
+							    len, user);
+	else {
+		struct sk_buff *skb;
+
+		skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
+				GFP_ATOMIC);
+		if (skb == NULL)
+			return 0;
+
+		skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
+		SET_SKB_FREE(skb);
+
+		if (user)
+			copy_from_user(skb_put(skb, len), buf, len);
+		else
+			memcpy(skb_put(skb, len), buf, len);
+
+		ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
+							      chan, skb);
+		if (ret <= 0)
+			kfree_skb(skb, FREE_WRITE);
+	}
+	if (ret > 0)
+		dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
+	return ret;
 }
 
 /*
@@ -1933,32 +1909,36 @@
  * Return: length of data on success, -ERRcode on failure.
  */
 
-int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
+int
+isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
 {
-        int ret;
-	int len = skb->len;	/* skb pointer no longer valid after free */
+	int ret;
+	int len = skb->len;     /* skb pointer no longer valid after free */
 
-        if (dev->drv[drvidx]->interface->writebuf_skb) 
+	if (dev->drv[drvidx]->interface->writebuf_skb)
 		ret = dev->drv[drvidx]->interface->
-			writebuf_skb(drvidx, chan, skb);
+		    writebuf_skb(drvidx, chan, skb);
 	else {
 		if ((ret = dev->drv[drvidx]->interface->
-                     writebuf(drvidx,chan,skb->data,skb->len,0)) == len)
-		        dev_kfree_skb(skb, FREE_WRITE);
-        }
-        if (ret > 0)
-                dev->obytes[isdn_dc2minor(drvidx,chan)] += len;
-        return ret;
+		  writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+			dev_kfree_skb(skb, FREE_WRITE);
+	}
+	if (ret > 0)
+		dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+	return ret;
 }
 
 /*
  * Low-level-driver registration
  */
 
-int register_isdn(isdn_if * i)
+int
+register_isdn(isdn_if * i)
 {
 	driver *d;
-	int n, j, k;
+	int n,
+	 j,
+	 k;
 	ulong flags;
 	int drvidx;
 
@@ -1974,9 +1954,9 @@
 		return 0;
 	}
 	if ((!i->writebuf_skb) && (!i->writebuf)) {
-                printk(KERN_WARNING "register_isdn: No write routine given.\n");
-                return 0;
-        }
+		printk(KERN_WARNING "register_isdn: No write routine given.\n");
+		return 0;
+	}
 	if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
 		printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
 		return 0;
@@ -1995,17 +1975,17 @@
 		return 0;
 	}
 	memset((char *) d->rcvcount, 0, sizeof(int) * n);
-        if (!(d->rpqueue =
-              (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
-                printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
-                kfree(d->rcvcount);
-                kfree(d->rcverr);
-                kfree(d);
-                return 0;
-        }
-        for (j = 0; j < n; j++) {
-                skb_queue_head_init(&d->rpqueue[j]);
-        }
+	if (!(d->rpqueue =
+	      (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
+		printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+		kfree(d->rcvcount);
+		kfree(d->rcverr);
+		kfree(d);
+		return 0;
+	}
+	for (j = 0; j < n; j++) {
+		skb_queue_head_init(&d->rpqueue[j]);
+	}
 	if (!(d->rcv_waitq = (struct wait_queue **)
 	      kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
 		printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
@@ -2039,17 +2019,17 @@
 		if (!dev->drv[drvidx])
 			break;
 	i->channels = drvidx;
- 
+
 	i->rcvcallb_skb = isdn_receive_skb_callback;
-	i->rcvcallb     = isdn_receive_callback;
-	i->statcallb    = isdn_status_callback;
+	i->rcvcallb = isdn_receive_callback;
+	i->statcallb = isdn_status_callback;
 	if (!strlen(i->id))
 		sprintf(i->id, "line%d", drvidx);
 	save_flags(flags);
 	cli();
-        for (j = 0; j < drvidx; j++)
-                if (!strcmp(i->id,dev->drvid[j]))
-                    sprintf(i->id, "line%d", drvidx);                    
+	for (j = 0; j < drvidx; j++)
+		if (!strcmp(i->id, dev->drvid[j]))
+			sprintf(i->id, "line%d", drvidx);
 	for (j = 0; j < n; j++)
 		for (k = 0; k < ISDN_MAX_CHANNELS; k++)
 			if (dev->chanmap[k] < 0) {
@@ -2078,7 +2058,8 @@
 #define isdn_init init_module
 #endif
 
-static char *isdn_getrev(const char *revision)
+static char *
+isdn_getrev(const char *revision)
 {
 	char *rev;
 	char *p;
@@ -2092,29 +2073,18 @@
 	return rev;
 }
 
-static struct symbol_table isdn_syms = {
-#include <linux/symtab_begin.h>
-        X(register_isdn),
-#include <linux/symtab_end.h>
-};
-
-static void isdn_export_syms(void)
-{
-        register_symtab(&isdn_syms);
-        has_exported = 1;
-}
-
 /*
  * Allocate and initialize all data, register modem-devices
  */
-int isdn_init(void)
+int
+isdn_init(void)
 {
 	int i;
-        char irev[50];
-        char trev[50];
-        char nrev[50];
-        char prev[50];
-        char arev[50];
+	char irev[50];
+	char trev[50];
+	char nrev[50];
+	char prev[50];
+	char arev[50];
 
 	sti();
 	if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
@@ -2122,10 +2092,8 @@
 		return -EIO;
 	}
 	memset((char *) dev, 0, sizeof(isdn_dev));
-#ifdef NEW_ISDN_TIMER_CTRL
-        init_timer(&dev->timer);
-        dev->timer.function = isdn_timer_funct;
-#endif
+	init_timer(&dev->timer);
+	dev->timer.function = isdn_timer_funct;
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		dev->drvmap[i] = -1;
 		dev->chanmap[i] = -1;
@@ -2158,21 +2126,20 @@
 		kfree(dev);
 		return -EIO;
 	}
-#endif				/* CONFIG_ISDN_PPP */
+#endif                          /* CONFIG_ISDN_PPP */
 
-        if (!has_exported)
-                isdn_export_syms();
+	isdn_export_syms();
 
-        strcpy(irev,isdn_revision);
-        strcpy(trev,isdn_tty_revision);
-        strcpy(nrev,isdn_net_revision);
-        strcpy(prev,isdn_ppp_revision);
-        strcpy(arev,isdn_audio_revision);
+	strcpy(irev, isdn_revision);
+	strcpy(trev, isdn_tty_revision);
+	strcpy(nrev, isdn_net_revision);
+	strcpy(prev, isdn_ppp_revision);
+	strcpy(arev, isdn_audio_revision);
 	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
-        printk("%s/", isdn_getrev(trev));
-        printk("%s/", isdn_getrev(nrev));
-        printk("%s/", isdn_getrev(prev));
-        printk("%s", isdn_getrev(arev));
+	printk("%s/", isdn_getrev(trev));
+	printk("%s/", isdn_getrev(nrev));
+	printk("%s/", isdn_getrev(prev));
+	printk("%s", isdn_getrev(arev));
 
 #ifdef MODULE
 	printk(" loaded\n");
@@ -2188,7 +2155,8 @@
 /*
  * Unload module
  */
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
 	int flags;
 	int i;
@@ -2214,9 +2182,9 @@
 		return;
 	}
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
-                kfree(dev->mdm.info[i].xmit_buf - 4);
-        }
+		isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
+		kfree(dev->mdm.info[i].xmit_buf - 4);
+	}
 	if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
 		printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
 	} else {
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_common.h linux-2.0.31-pre3/drivers/isdn/isdn_common.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_common.h	1996-06-01 01:56:51.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_common.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,11 +1,11 @@
-/* $Id: isdn_common.h,v 1.3 1996/05/19 00:13:05 fritz Exp $
- *
+/* $Id: isdn_common.h,v 1.6 1997/02/28 02:32:44 fritz Exp $
+
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -18,9 +18,21 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.6  1997/02/28 02:32:44  fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ *          to isdn_tty.c
+ * Bugfix:  Bisync protocol did not behave like documented.
+ *
+ * Revision 1.5  1997/02/10 10:05:45  fritz
+ * More changes for Kernel 2.1.X
+ * Symbol information moved to isdn_syms.c
+ *
+ * Revision 1.4  1997/02/03 22:56:50  fritz
+ * Removed isdn_writebuf_stub prototype.
+ *
  * Revision 1.3  1996/05/19 00:13:05  fritz
  * Removed debug flag.
  *
@@ -38,26 +50,32 @@
 #undef  ISDN_DEBUG_MODEM_HUP
 #undef  ISDN_DEBUG_MODEM_ICALL
 #undef  ISDN_DEBUG_MODEM_DUMP
+#undef  ISDN_DEBUG_MODEM_VOICE
 #undef  ISDN_DEBUG_AT
 #undef  ISDN_DEBUG_NET_DUMP
 #undef  ISDN_DEBUG_NET_DIAL
 #undef  ISDN_DEBUG_NET_ICALL
 
 /* Prototypes */
-extern void  isdn_MOD_INC_USE_COUNT(void);
-extern void  isdn_MOD_DEC_USE_COUNT(void);
-extern void  isdn_free_channel(int di, int ch, int usage);
-extern void  isdn_all_eaz(int di, int ch);
-extern int   isdn_dc2minor(int di, int ch);
-extern void  isdn_info_update(void);
-extern char* isdn_map_eaz2msn(char *msn, int di);
-extern void  isdn_timer_ctrl(int tf, int onoff);
-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, int);
-extern int   isdn_get_free_channel(int, int, int, int, int);
-extern int   isdn_writebuf_stub(int, int, const u_char *, int, int);
-extern int   isdn_writebuf_skb_stub(int, int, struct sk_buff *);
+extern void isdn_MOD_INC_USE_COUNT(void);
+extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_free_channel(int di, int ch, int usage);
+extern void isdn_all_eaz(int di, int ch);
+extern int isdn_dc2minor(int di, int ch);
+extern void isdn_info_update(void);
+extern char *isdn_map_eaz2msn(char *msn, int di);
+extern void isdn_timer_ctrl(int tf, int onoff);
+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, int);
+extern int isdn_get_free_channel(int, int, int, int, int);
+extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *);
+extern int register_isdn(isdn_if * i);
+#if (LINUX_VERSION_CODE < 0x020111)
+extern void isdn_export_syms(void);
+#else
+#define isdn_export_syms()
+#endif
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-extern void  isdn_dumppkt(char *, u_char *, int, int);
+extern void isdn_dumppkt(char *, u_char *, int, int);
 #endif
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_net.c linux-2.0.31-pre3/drivers/isdn/isdn_net.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_net.c	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_net.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,11 +1,11 @@
-/* $Id: isdn_net.c,v 1.29 1996/11/13 02:31:38 fritz Exp $
- *
+/* $Id: isdn_net.c,v 1.47 1997/06/21 10:52:05 fritz Exp $
+
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -18,9 +18,73 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.47  1997/06/21 10:52:05  fritz
+ * Removed wrong SET_SKB_FREE in isdn_net_send_skb()
+ *
+ * Revision 1.46  1997/06/17 13:05:24  hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ *
+ * Revision 1.45  1997/06/10 16:24:22  hipp
+ * hard_header changes for syncPPP (now behaves like RAWIP)
+ *
+ * Revision 1.44  1997/05/27 15:17:26  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.43  1997/03/30 16:51:13  calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.42  1997/03/11 08:43:51  fritz
+ * Perform a hangup if number is deleted while dialing.
+ *
+ * Revision 1.41  1997/03/08 08:16:31  fritz
+ * Bugfix: Deleting a phone number during dial gave unpredictable results.
+ *
+ * Revision 1.40  1997/03/05 21:16:08  fritz
+ * Fix: did not compile with 2.1.27
+ *
+ * Revision 1.39  1997/03/04 21:36:52  fritz
+ * Added sending ICMP messages when no connetion is possible.
+ *
+ * Revision 1.38  1997/02/23 23:41:14  fritz
+ * Bugfix: Slave interfaces have to be hung up before master.
+ *
+ * Revision 1.37  1997/02/11 18:32:51  fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.36  1997/02/10 21:31:11  fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.35  1997/02/10 20:12:45  fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.34  1997/02/03 23:15:07  fritz
+ * Reformatted according CodingStyle.
+ * replaced arp_find prototype by proper include.
+ * made dev_purge_queues static.
+ * Bugfix in bogocps calculation.
+ * removed isdn_net_receive_callback - was never used ;-)
+ * Misc. fixes for Kernel 2.1.X comaptibility.
+ *
+ * Revision 1.33  1997/01/17 01:19:25  fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.32  1997/01/14 01:29:31  fritz
+ * Bugfix: isdn_net_hangup() did not reset ISDN_NET_CONNECTED.
+ *
+ * Revision 1.31  1997/01/11 23:30:42  fritz
+ * Speed up dial statemachine.
+ *
+ * Revision 1.30  1996/11/25 17:20:50  hipp
+ * fixed pppbind bug in isdn_net_find_icall()
+ *
  * Revision 1.29  1996/11/13 02:31:38  fritz
  * Minor cleanup.
  *
@@ -140,38 +204,47 @@
 #include <linux/module.h>
 #include <linux/isdn.h>
 #include <linux/if_arp.h>
+#include <net/arp.h>
+#include <net/icmp.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
 #ifdef CONFIG_ISDN_PPP
 #include "isdn_ppp.h"
 #endif
 
-/* In ksyms.c, but why not in some .h ??? */
-extern int arp_find(unsigned char *, u32, struct device *, u32,
-                    struct sk_buff *);
-
 /* Prototypes */
 
 int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_wildmat(char *s, char *p);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
- 
-extern void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
+static void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
 
-char *isdn_net_revision = "$Revision: 1.29 $";
+char *isdn_net_revision = "$Revision: 1.47 $";
 
  /*
   * Code for raw-networking over ISDN
   */
 
 static void
+isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
+{
+	printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP\n",
+	       dev->name, reason);
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0
+#if (LINUX_VERSION_CODE < 0x02010f)	/* 2.1.15 */
+		  ,dev
+#endif
+	    );
+}
+
+static void
 isdn_net_reset(struct device *dev)
 {
 	ulong flags;
 
 	save_flags(flags);
-	cli();			/* Avoid glitch on writes to CMD regs */
+	cli();                  /* Avoid glitch on writes to CMD regs */
 	dev->interrupt = 0;
 	dev->tbusy = 0;
 	restore_flags(flags);
@@ -191,7 +264,7 @@
 		dev->dev_addr[i] = 0xfc;
 	memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32));
 
-        /* If this interface has slaves, start them also */
+	/* If this interface has slaves, start them also */
 
 	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
 		while (p) {
@@ -200,7 +273,6 @@
 			p = (((isdn_net_local *) p->priv)->slave);
 		}
 	}
-
 	isdn_MOD_INC_USE_COUNT();
 	return 0;
 }
@@ -211,15 +283,15 @@
 static void
 isdn_net_bind_channel(isdn_net_local * lp, int idx)
 {
-        ulong flags;
+	ulong flags;
 
-        save_flags(flags);
-        cli();
+	save_flags(flags);
+	cli();
 	lp->isdn_device = dev->drvmap[idx];
 	lp->isdn_channel = dev->chanmap[idx];
-        dev->rx_netdev[idx] = lp->netdev;
-        dev->st_netdev[idx] = lp->netdev;
-        restore_flags(flags);
+	dev->rx_netdev[idx] = lp->netdev;
+	dev->st_netdev[idx] = lp->netdev;
+	restore_flags(flags);
 }
 
 /*
@@ -232,25 +304,25 @@
 
 	save_flags(flags);
 	cli();
-        if (lp->first_skb) {
-                dev_kfree_skb(lp->first_skb,FREE_WRITE);
-                lp->first_skb = NULL;
-        }
-	if(lp->sav_skb) {
-                dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+	if (lp->first_skb) {
+		dev_kfree_skb(lp->first_skb, FREE_WRITE);
+		lp->first_skb = NULL;
+	}
+	if (lp->sav_skb) {
+		dev_kfree_skb(lp->sav_skb, FREE_WRITE);
 		lp->sav_skb = NULL;
 	}
-	if(!lp->master) /* purge only for master device */
+	if (!lp->master)        /* purge only for master device */
 		dev_purge_queues(&lp->netdev->dev);
 	lp->dialstate = 0;
-	dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
-	dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
+	dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
+	dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
 	isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
 	lp->flags &= ~ISDN_NET_CONNECTED;
 	lp->isdn_device = -1;
 	lp->isdn_channel = -1;
 
-        restore_flags(flags);
+	restore_flags(flags);
 }
 
 /*
@@ -272,37 +344,50 @@
 isdn_net_autohup()
 {
 	isdn_net_dev *p = dev->netdev;
-        int anymore;
+	int anymore;
 
-        anymore = 0;
+	anymore = 0;
 	while (p) {
 		isdn_net_local *l = (isdn_net_local *) & (p->local);
 		if ((jiffies - last_jiffies) == 0)
-			l->cps = 0;
+			l->cps = l->transcount;
 		else
-			l->cps = l->transcount / (jiffies - last_jiffies);
+			l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
 		l->transcount = 0;
 		if (dev->net_verbose > 3)
 			printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
 		if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
-                        anymore = 1;
+			anymore = 1;
 			l->huptimer++;
 			if ((l->onhtime) && (l->huptimer > l->onhtime))
-				if (l->outgoing) {
-					if (l->hupflags & 4) {
-						if (l->hupflags & 1)
+				if (l->hupflags & ISDN_MANCHARGE &&
+				    l->hupflags & ISDN_CHARGEHUP) {
+					while (jiffies - l->chargetime > l->chargeint)
+						l->chargetime += l->chargeint;
+					if (jiffies - l->chargetime >= l->chargeint - 2 * HZ)
+						if (l->outgoing || l->hupflags & ISDN_INHUP)
 							isdn_net_hangup(&p->dev);
-						else if (jiffies - l->chargetime > l->chargeint)
+				} else if (l->outgoing) {
+					if (l->hupflags & ISDN_CHARGEHUP) {
+						if (l->hupflags & ISDN_WAITCHARGE) {
+							printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
+							       l->name, l->hupflags);
 							isdn_net_hangup(&p->dev);
+						} else if (jiffies - l->chargetime > l->chargeint) {
+							printk(KERN_DEBUG
+							       "isdn_net: %s: chtime = %d, chint = %d\n",
+							       l->name, l->chargetime, l->chargeint);
+							isdn_net_hangup(&p->dev);
+						}
 					} else
 						isdn_net_hangup(&p->dev);
-				} else if (l->hupflags & 8)
+				} else if (l->hupflags & ISDN_INHUP)
 					isdn_net_hangup(&p->dev);
 		}
 		p = (isdn_net_dev *) p->next;
 	}
 	last_jiffies = jiffies;
-        isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,anymore);
+	isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
 }
 
 /*
@@ -318,57 +403,56 @@
 
 	if (p) {
 		isdn_net_local *lp = &(p->local);
-                switch (cmd) {
+		switch (cmd) {
 			case ISDN_STAT_BSENT:
 				/* A packet has successfully been sent out */
 				if ((lp->flags & ISDN_NET_CONNECTED) &&
 				    (!lp->dialstate)) {
 					lp->stats.tx_packets++;
-					if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
+					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
 						struct device *mdev;
-						if(lp->master)
+						if (lp->master)
 							mdev = lp->master;
 						else
 							mdev = &lp->netdev->dev;
-						if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) {
+						if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
 							lp->sav_skb = NULL;
 							mark_bh(NET_BH);
-						}
-						else {
+						} else {
 							return 1;
 						}
 					}
-                                        if (clear_bit(0,(void*)&(p->dev.tbusy)))
-                                                mark_bh(NET_BH);
+					if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
+						mark_bh(NET_BH);
 				}
 				return 1;
 			case ISDN_STAT_DCONN:
 				/* D-Channel is up */
-                                switch (lp->dialstate) {
-                                        case 4:
-                                        case 7:
-                                        case 8:
-                                                lp->dialstate++;
-                                                return 1;
-                                        case 12:
-                                                lp->dialstate = 5;
-                                                return 1;
-                                }
+				switch (lp->dialstate) {
+					case 4:
+					case 7:
+					case 8:
+						lp->dialstate++;
+						return 1;
+					case 12:
+						lp->dialstate = 5;
+						return 1;
+				}
 				break;
 			case ISDN_STAT_DHUP:
 				/* Either D-Channel-hangup or error during dialout */
 				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
 					lp->flags &= ~ISDN_NET_CONNECTED;
-					if(lp->first_skb) {
-						dev_kfree_skb(lp->first_skb,FREE_WRITE);
+					if (lp->first_skb) {
+						dev_kfree_skb(lp->first_skb, FREE_WRITE);
 						lp->first_skb = NULL;
 					}
-					if(lp->sav_skb) {
-						dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+					if (lp->sav_skb) {
+						dev_kfree_skb(lp->sav_skb, FREE_WRITE);
 						lp->sav_skb = NULL;
 					}
 					isdn_free_channel(lp->isdn_device, lp->isdn_channel,
-                                                          ISDN_USAGE_NET);
+							  ISDN_USAGE_NET);
 #ifdef CONFIG_ISDN_PPP
 					isdn_ppp_free(lp);
 #endif
@@ -380,49 +464,51 @@
 					lp->isdn_channel = -1;
 					dev->st_netdev[idx] = NULL;
 					dev->rx_netdev[idx] = NULL;
-                                        return 1;
+					return 1;
 				}
-                                break;
+				break;
 			case ISDN_STAT_BCONN:
 				/* B-Channel is up */
-                                switch (lp->dialstate) {
-                                        case 5:
-                                        case 6:
-                                        case 7:
-                                        case 8:
-                                        case 9:
-                                        case 10:
-                                        case 12:
-                                                if (lp->dialstate <= 6) {
-                                                        dev->usage[idx] |= ISDN_USAGE_OUTGOING;
-                                                        isdn_info_update();
-                                                } else
-                                                        dev->rx_netdev[idx] = p;
-                                                lp->dialstate = 0;
-                                                isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,1);
-                                                printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
-                                                /* If first Chargeinfo comes before B-Channel connect,
-                                                 * we correct the timestamp here.
-                                                 */
-                                                lp->chargetime = jiffies;
-                                                /* Immediately send first skb to speed up arp */
+				switch (lp->dialstate) {
+					case 5:
+					case 6:
+					case 7:
+					case 8:
+					case 9:
+					case 10:
+					case 12:
+						if (lp->dialstate <= 6) {
+							dev->usage[idx] |= ISDN_USAGE_OUTGOING;
+							isdn_info_update();
+						} else
+							dev->rx_netdev[idx] = p;
+						lp->dialstate = 0;
+						isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
+						printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+						/* If first Chargeinfo comes before B-Channel connect,
+						 * we correct the timestamp here.
+						 */
+						lp->chargetime = jiffies;
+						printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n",
+						lp->name, lp->chargetime);
+						/* Immediately send first skb to speed up arp */
 #ifdef CONFIG_ISDN_PPP
-						if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 							isdn_ppp_wakeup_daemon(lp);
 #endif
-                                                if (lp->first_skb) {
-                                                        if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb)))
-                                                                lp->first_skb = NULL;
-                                                }
-                                                return 1;
+						if (lp->first_skb) {
+							if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
+								lp->first_skb = NULL;
+						}
+						return 1;
 				}
 				break;
 			case ISDN_STAT_NODCH:
 				/* No D-Channel avail. */
 				if (lp->dialstate == 4) {
 					lp->dialstate--;
-                                        return 1;
-                                }
+					return 1;
+				}
 				break;
 			case ISDN_STAT_CINF:
 				/* Charge-info from TelCo. Calculate interval between
@@ -430,17 +516,19 @@
 				 * usage by isdn_net_autohup()
 				 */
 				lp->charge++;
-				if (lp->hupflags & 2) {
-					lp->hupflags &= ~1;
+				if (lp->hupflags & ISDN_HAVECHARGE) {
+					lp->hupflags &= ~ISDN_WAITCHARGE;
 					lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
 				}
-				if (lp->hupflags & 1)
-					lp->hupflags |= 2;
+				if (lp->hupflags & ISDN_WAITCHARGE)
+					lp->hupflags |= ISDN_HAVECHARGE;
 				lp->chargetime = jiffies;
+				printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n",
+				       lp->name, lp->chargetime);
 				return 1;
-                }
+		}
 	}
-        return 0;
+	return 0;
 }
 
 /*
@@ -473,191 +561,220 @@
 	isdn_net_dev *p = dev->netdev;
 	int anymore = 0;
 	int i;
+	int flags;
 	isdn_ctrl cmd;
 
 	while (p) {
 #ifdef ISDN_DEBUG_NET_DIAL
-                if (p->local.dialstate)
-                        printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name,p->local.dialstate);
+		if (p->local.dialstate)
+			printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name, p->local.dialstate);
 #endif
 		switch (p->local.dialstate) {
-		case 0:
-			/* Nothing to do for this interface */
-			break;
-		case 1:
-			/* Initiate dialout. Set phone-number-pointer to first number
-			 * of interface.
-			 */
-			p->local.dial = p->local.phone[1];
-			anymore = 1;
-			p->local.dialstate++;
-			break;
-			/* Prepare dialing. Clear EAZ, then set EAZ. */
-		case 2:
-			cmd.driver = p->local.isdn_device;
-			cmd.arg = p->local.isdn_channel;
-			cmd.command = ISDN_CMD_CLREAZ;
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			sprintf(cmd.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver));
-			cmd.command = ISDN_CMD_SETEAZ;
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			p->local.dialretry = 0;
-			anymore = 1;
-			p->local.dialstate++;
-			break;
-		case 3:
-			/* Setup interface, dial current phone-number, switch to next number.
-			 * If list of phone-numbers is exhausted, increment
-			 * retry-counter.
-			 */
-			cmd.driver = p->local.isdn_device;
-			cmd.command = ISDN_CMD_SETL2;
-			cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			cmd.driver = p->local.isdn_device;
-			cmd.command = ISDN_CMD_SETL3;
-			cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			cmd.driver = p->local.isdn_device;
-			cmd.arg = p->local.isdn_channel;
-			p->local.huptimer = 0;
-			p->local.outgoing = 1;
-			p->local.hupflags |= 1;
-                        p->local.hupflags &= ~2;
-			if (!strcmp(p->local.dial->num, "LEASED")) {
-				p->local.dialstate = 4;
-				printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
-			} else {
-				cmd.command = ISDN_CMD_DIAL;
-				sprintf(cmd.num, "%s,%s,7,0", p->local.dial->num,
-				  isdn_map_eaz2msn(p->local.msn, cmd.driver));
-				i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel);
-				if (i >= 0) {
-					strcpy(dev->num[i], p->local.dial->num);
-					isdn_info_update();
+			case 0:
+				/* Nothing to do for this interface */
+				break;
+			case 1:
+				/* Initiate dialout. Set phone-number-pointer to first number
+				 * of interface.
+				 */
+				save_flags(flags);
+				cli();
+				p->local.dial = p->local.phone[1];
+				restore_flags(flags);
+				if (!p->local.dial) {
+					printk(KERN_WARNING "%s: phone number deleted?\n",
+					       p->local.name);
+					isdn_net_hangup(&p->dev);
+					break;
 				}
-				printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name,
-				 p->local.dialretry, p->local.dial->num);
-				/*
-				 * Switch to next number or back to start if at end of list.
+				anymore = 1;
+				p->local.dialstate++;
+				/* Fall through */
+			case 2:
+				/* Prepare dialing. Clear EAZ, then set EAZ. */
+				cmd.driver = p->local.isdn_device;
+				cmd.arg = p->local.isdn_channel;
+				cmd.command = ISDN_CMD_CLREAZ;
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver));
+				cmd.command = ISDN_CMD_SETEAZ;
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				p->local.dialretry = 0;
+				anymore = 1;
+				p->local.dialstate++;
+				/* Falls through */
+			case 3:
+				/* Setup interface, dial current phone-number, switch to next number.
+				 * If list of phone-numbers is exhausted, increment
+				 * retry-counter.
 				 */
-				if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) {
-					p->local.dial = p->local.phone[1];
-					p->local.dialretry++;
+				cmd.driver = p->local.isdn_device;
+				cmd.command = ISDN_CMD_SETL2;
+				cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				cmd.driver = p->local.isdn_device;
+				cmd.command = ISDN_CMD_SETL3;
+				cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				cmd.driver = p->local.isdn_device;
+				cmd.arg = p->local.isdn_channel;
+				save_flags(flags);
+				cli();
+				if (!p->local.dial) {
+					restore_flags(flags);
+					printk(KERN_WARNING "%s: phone number deleted?\n",
+					       p->local.name);
+					isdn_net_hangup(&p->dev);
+					break;
 				}
-				p->local.dtimer = 0;
+				if (!strcmp(p->local.dial->num, "LEASED")) {
+					restore_flags(flags);
+					p->local.dialstate = 4;
+					printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
+				} else {
+					sprintf(cmd.parm.setup.phone, "%s", p->local.dial->num);
+					/*
+					 * Switch to next number or back to start if at end of list.
+					 */
+					if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) {
+						p->local.dial = p->local.phone[1];
+						p->local.dialretry++;
+					}
+					restore_flags(flags);
+					cmd.command = ISDN_CMD_DIAL;
+					cmd.parm.setup.si1 = 7;
+					cmd.parm.setup.si2 = 0;
+					sprintf(cmd.parm.setup.eazmsn, "%s",
+						isdn_map_eaz2msn(p->local.msn, cmd.driver));
+					i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel);
+					if (i >= 0) {
+						strcpy(dev->num[i], cmd.parm.setup.phone);
+						isdn_info_update();
+					}
+					printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name,
+					       p->local.dialretry - 1, cmd.parm.setup.phone);
+					p->local.dtimer = 0;
 #ifdef ISDN_DEBUG_NET_DIAL
-				printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device,
-				       p->local.isdn_channel);
+					printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device,
+					       p->local.isdn_channel);
 #endif
+					dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				}
+				p->local.huptimer = 0;
+				p->local.outgoing = 1;
+				if (p->local.chargeint) {
+					p->local.hupflags |= ISDN_HAVECHARGE;
+					p->local.hupflags &= ~ISDN_WAITCHARGE;
+				} else {
+					p->local.hupflags |= ISDN_WAITCHARGE;
+					p->local.hupflags &= ~ISDN_HAVECHARGE;
+				}
+				anymore = 1;
+				p->local.dialstate =
+				    (p->local.cbdelay &&
+				     (p->local.flags & ISDN_NET_CBOUT)) ? 12 : 4;
+				break;
+			case 4:
+				/* Wait for D-Channel-connect.
+				 * If timeout and max retries not
+				 * reached, switch back to state 3.
+				 */
+				if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					if (p->local.dialretry < p->local.dialmax) {
+						p->local.dialstate = 3;
+					} else
+						isdn_net_hangup(&p->dev);
+				anymore = 1;
+				break;
+			case 5:
+				/* Got D-Channel-Connect, send B-Channel-request */
+				cmd.driver = p->local.isdn_device;
+				cmd.arg = p->local.isdn_channel;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				anymore = 1;
+				p->local.dtimer = 0;
+				p->local.dialstate++;
 				dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			}
-			anymore = 1;
-			p->local.dialstate =
-                                (p->local.cbdelay &&
-                                 (p->local.flags & ISDN_NET_CBOUT))?12:4;
-			break;
-		case 4:
-			/* Wait for D-Channel-connect.
-                         * If timeout and max retries not
-			 * reached, switch back to state 3.
-			 */
-			if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
-				if (p->local.dialretry < p->local.dialmax) {
-					p->local.dialstate = 3;
-				} else
-                                        isdn_net_hangup(&p->dev);
-			anymore = 1;
-			break;
-		case 5:
-			/* Got D-Channel-Connect, send B-Channel-request */
-			cmd.driver = p->local.isdn_device;
-			cmd.arg = p->local.isdn_channel;
-			cmd.command = ISDN_CMD_ACCEPTB;
-			anymore = 1;
-			p->local.dtimer = 0;
-			p->local.dialstate++;
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			break;
-		case 6:
-			/* Wait for B- or D-Channel-connect. If timeout,
-                         * switch back to state 3.
-			 */
+				break;
+			case 6:
+				/* Wait for B- or D-Channel-connect. If timeout,
+				 * switch back to state 3.
+				 */
 #ifdef ISDN_DEBUG_NET_DIAL
-			printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer);
+				printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer);
 #endif
-			if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
-				p->local.dialstate = 3;
-			anymore = 1;
-			break;
-		case 7:
-			/* Got incoming Call, setup L2 and L3 protocols,
-                         * then wait for D-Channel-connect
-                         */
+				if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					p->local.dialstate = 3;
+				anymore = 1;
+				break;
+			case 7:
+				/* Got incoming Call, setup L2 and L3 protocols,
+				 * then wait for D-Channel-connect
+				 */
 #ifdef ISDN_DEBUG_NET_DIAL
-			printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+				printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
 #endif
-			cmd.driver = p->local.isdn_device;
-			cmd.command = ISDN_CMD_SETL2;
-			cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			cmd.driver = p->local.isdn_device;
-			cmd.command = ISDN_CMD_SETL3;
-			cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15)
-				isdn_net_hangup(&p->dev);
-			else {
+				cmd.driver = p->local.isdn_device;
+				cmd.command = ISDN_CMD_SETL2;
+				cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				cmd.driver = p->local.isdn_device;
+				cmd.command = ISDN_CMD_SETL3;
+				cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
+				if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15)
+					isdn_net_hangup(&p->dev);
+				else {
+					anymore = 1;
+					p->local.dialstate++;
+				}
+				break;
+			case 9:
+				/* Got incoming D-Channel-Connect, send B-Channel-request */
+				cmd.driver = p->local.isdn_device;
+				cmd.arg = p->local.isdn_channel;
+				cmd.command = ISDN_CMD_ACCEPTB;
+				dev->drv[p->local.isdn_device]->interface->command(&cmd);
 				anymore = 1;
-                                p->local.dialstate++;
-                        }
-			break;
-		case 9:
-			/* Got incoming D-Channel-Connect, send B-Channel-request */
-			cmd.driver = p->local.isdn_device;
-			cmd.arg = p->local.isdn_channel;
-			cmd.command = ISDN_CMD_ACCEPTB;
-			dev->drv[p->local.isdn_device]->interface->command(&cmd);
-			anymore = 1;
-			p->local.dtimer = 0;
-			p->local.dialstate++;
-			break;
-		case 8:
-                case 10:
-			/*  Wait for B- or D-channel-connect */
+				p->local.dtimer = 0;
+				p->local.dialstate++;
+				break;
+			case 8:
+			case 10:
+				/*  Wait for B- or D-channel-connect */
 #ifdef ISDN_DEBUG_NET_DIAL
-			printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+				printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
 #endif
-			if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
-				isdn_net_hangup(&p->dev);
-			else
+				if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+					isdn_net_hangup(&p->dev);
+				else
+					anymore = 1;
+				break;
+			case 11:
+				/* Callback Delay */
+				if (p->local.dtimer++ > p->local.cbdelay)
+					p->local.dialstate = 1;
 				anymore = 1;
-			break;
-                case 11:
-                        /* Callback Delay */
-                        if (p->local.dtimer++ > p->local.cbdelay)
-                                p->local.dialstate = 1;
-                        anymore = 1;
-                        break;
-		case 12:
-			/* Remote does callback. Hangup after cbdelay, then wait for incoming
-                         * call (in state 4).
-			 */
-                        if (p->local.dtimer++ > p->local.cbdelay) {
-                                printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
-                                p->local.dtimer = 0;
-                                p->local.dialstate = 4;
-                                cmd.driver = p->local.isdn_device;
-                                cmd.command = ISDN_CMD_HANGUP;
-                                cmd.arg = p->local.isdn_channel;
-                                (void) dev->drv[cmd.driver]->interface->command(&cmd);
-                                isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
-                        }
-                        anymore = 1;
-			break;
-		default:
-			printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
-			       p->local.dialstate, p->local.name);
+				break;
+			case 12:
+				/* Remote does callback. Hangup after cbdelay, then wait for incoming
+				 * call (in state 4).
+				 */
+				if (p->local.dtimer++ > p->local.cbdelay) {
+					printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
+					p->local.dtimer = 0;
+					p->local.dialstate = 4;
+					cmd.driver = p->local.isdn_device;
+					cmd.command = ISDN_CMD_HANGUP;
+					cmd.arg = p->local.isdn_channel;
+					(void) dev->drv[cmd.driver]->interface->command(&cmd);
+					isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
+				}
+				anymore = 1;
+				break;
+			default:
+				printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
+				       p->local.dialstate, p->local.name);
 		}
 		p = (isdn_net_dev *) p->next;
 	}
@@ -674,6 +791,7 @@
 	isdn_ctrl cmd;
 
 	if (lp->flags & ISDN_NET_CONNECTED) {
+		lp->flags &= ~ISDN_NET_CONNECTED;
 		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
 #ifdef CONFIG_ISDN_PPP
 		isdn_ppp_free(lp);
@@ -685,7 +803,7 @@
 		printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
 		isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
 	}
-        isdn_net_unbind_channel(lp);
+	isdn_net_unbind_channel(lp);
 }
 
 typedef struct {
@@ -696,59 +814,59 @@
 static void
 isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
 {
-        u_char *p = buf;
+	u_char *p = buf;
 	unsigned short proto = ETH_P_IP;
-        int data_ofs;
+	int data_ofs;
 	ip_ports *ipp;
 	char addinfo[100];
 
-        addinfo[0] = '\0';
-        switch (lp->p_encap) {
-                case ISDN_NET_ENCAP_IPTYP:
-                        proto = ntohs(*(unsigned short *)&buf[0]);
-                        p = &buf[2];
-                        break;
-                case ISDN_NET_ENCAP_ETHER:
-                        proto = ntohs(*(unsigned short *)&buf[12]);
-                        p = &buf[14];
-                        break;
-                case ISDN_NET_ENCAP_CISCOHDLC:
-                        proto = ntohs(*(unsigned short *)&buf[2]);
-                        p = &buf[4];
-                        break;
-        }
+	addinfo[0] = '\0';
+	switch (lp->p_encap) {
+		case ISDN_NET_ENCAP_IPTYP:
+			proto = ntohs(*(unsigned short *) &buf[0]);
+			p = &buf[2];
+			break;
+		case ISDN_NET_ENCAP_ETHER:
+			proto = ntohs(*(unsigned short *) &buf[12]);
+			p = &buf[14];
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLC:
+			proto = ntohs(*(unsigned short *) &buf[2]);
+			p = &buf[4];
+			break;
+	}
 	data_ofs = ((p[0] & 15) * 4);
-        switch (proto) {
+	switch (proto) {
 		case ETH_P_IP:
 			switch (p[9]) {
-                                case 1:
-                                        strcpy(addinfo, " ICMP");
-                                        break;
-                                case 2:
-                                        strcpy(addinfo, " IGMP");
-                                        break;
-                                case 4:
-                                        strcpy(addinfo, " IPIP");
-                                        break;
-                                case 6:
-                                        ipp = (ip_ports *) (&p[data_ofs]);
-                                        sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
-                                                ntohs(ipp->dest));
-                                        break;
-                                case 8:
-                                        strcpy(addinfo, " EGP");
-                                        break;
-                                case 12:
-                                        strcpy(addinfo, " PUP");
-                                        break;
-                                case 17:
-                                        ipp = (ip_ports *) (&p[data_ofs]);
-                                        sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
-                                                ntohs(ipp->dest));
-                                        break;
-                                case 22:
-                                        strcpy(addinfo, " IDP");
-                                        break;
+				case 1:
+					strcpy(addinfo, " ICMP");
+					break;
+				case 2:
+					strcpy(addinfo, " IGMP");
+					break;
+				case 4:
+					strcpy(addinfo, " IPIP");
+					break;
+				case 6:
+					ipp = (ip_ports *) (&p[data_ofs]);
+					sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
+						ntohs(ipp->dest));
+					break;
+				case 8:
+					strcpy(addinfo, " EGP");
+					break;
+				case 12:
+					strcpy(addinfo, " PUP");
+					break;
+				case 17:
+					ipp = (ip_ports *) (&p[data_ofs]);
+					sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
+						ntohs(ipp->dest));
+					break;
+				case 22:
+					strcpy(addinfo, " IDP");
+					break;
 			}
 			printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
 			       p[12], p[13], p[14], p[15],
@@ -760,7 +878,7 @@
 			       p[14], p[15], p[16], p[17],
 			       p[24], p[25], p[26], p[27]);
 			break;
-        }
+	}
 }
 
 /*
@@ -772,28 +890,27 @@
  * Side-effects: ndev->tbusy is cleared on success.
  */
 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 */
-	
-        ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
+	int len = skb->len;     /* save len */
+
+	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
 	if (ret == len) {
 		lp->transcount += len;
-		clear_bit(0, (void *)&(ndev->tbusy));
+		clear_bit(0, (void *) &(ndev->tbusy));
+		return 0;
+	}
+	if (ret < 0) {
+		dev_kfree_skb(skb, FREE_WRITE);
+		lp->stats.tx_errors++;
+		clear_bit(0, (void *) &(ndev->tbusy));
 		return 0;
 	}
-        if (ret < 0) {
-                skb->free = 1;
-                dev_kfree_skb(skb, FREE_WRITE);
-                lp->stats.tx_errors++;
-                clear_bit(0, (void *)&(ndev->tbusy));
-                return 0;
-        }
 	return 1;
-}                                      
-	
+}
+
 
 /*
  *  Helper function for isdn_net_start_xmit.
@@ -807,23 +924,23 @@
  */
 
 static int
-isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb) 
+isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
 {
-        int ret;
+	int ret;
 
 	/* For the other encaps the header has already been built */
 #ifdef CONFIG_ISDN_PPP
 	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
 		return isdn_ppp_xmit(skb, ndev);
 	}
-#endif		
+#endif
 	/* Reset hangup-timeout */
 	lp->huptimer = 0;
-	if (lp->cps > 7000) {
+	if (lp->cps > lp->triggercps) {
 		/* Device overloaded */
 
-		/* 
-		 * Packet-delivery via round-robin over master 
+		/*
+		 * Packet-delivery via round-robin over master
 		 * and all connected slaves.
 		 */
 		if (lp->master)
@@ -847,18 +964,16 @@
 				/* First time overload: set timestamp only */
 				lp->sqfull = 1;
 				lp->sqfull_stamp = jiffies;
-			} 
-			else {
+			} else {
 				/* subsequent overload: if slavedelay exceeded, start dialing */
 				if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
 					isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
 			}
 		}
-	} 
-	else {
+	} else {
 		/* Not overloaded, deliver locally */
 		ret = isdn_net_send_skb(ndev, lp, skb);
-		if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10*HZ) )))
+		if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
 			lp->sqfull = 0;
 	}
 	return ret;
@@ -877,8 +992,8 @@
 	if (ndev->tbusy) {
 		if (jiffies - ndev->trans_start < (2 * HZ))
 			return 1;
-                if (!lp->dialstate)
-                        lp->stats.tx_errors++;
+		if (!lp->dialstate)
+			lp->stats.tx_errors++;
 		ndev->tbusy = 0;
 		ndev->trans_start = jiffies;
 	}
@@ -887,10 +1002,10 @@
 		return 0;
 	}
 	/* Avoid timer-based retransmission conflicts. */
-	if (set_bit(0, (void *) &ndev->tbusy) != 0)
+	if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
 		printk(KERN_WARNING
-                       "%s: Transmitter access conflict.\n",
-                       ndev->name);
+		       "%s: Transmitter access conflict.\n",
+		       ndev->name);
 	else {
 		u_char *buf = skb->data;
 #ifdef ISDN_DEBUG_NET_DUMP
@@ -903,23 +1018,31 @@
 				save_flags(flags);
 				cli();
 				/* Grab a free ISDN-Channel */
-				if ((chi = 
-                                     isdn_get_free_channel(ISDN_USAGE_NET,
-                                                           lp->l2_proto,
-                                                           lp->l3_proto,
-                                                           lp->pre_device,
-                                                           lp->pre_channel)) < 0) {
-                                        printk(KERN_WARNING
-                                               "isdn_net_start_xmit: No channel for %s\n",
-                                               ndev->name);
+				if ((chi =
+				     isdn_get_free_channel(ISDN_USAGE_NET,
+							   lp->l2_proto,
+							   lp->l3_proto,
+							   lp->pre_device,
+						 lp->pre_channel)) < 0) {
 					restore_flags(flags);
-		/* we probably should drop the skb here and return 0 to omit
-		   'socket destroy delayed' messages */
+#if 0
+					printk(KERN_WARNING
+					       "isdn_net_start_xmit: No channel for %s\n",
+					       ndev->name);
+					/* we probably should drop the skb here and return 0 to omit
+					   'socket destroy delayed' messages */
 					return 1;
+#else
+					isdn_net_unreachable(ndev, skb,
+							   "No channel");
+					dev_kfree_skb(skb, FREE_WRITE);
+					ndev->tbusy = 0;
+					return 0;
+#endif
 				}
-                                /* Log packet, which triggered dialing */
+				/* Log packet, which triggered dialing */
 				if (dev->net_verbose)
-                                        isdn_net_log_packet(buf, lp);
+					isdn_net_log_packet(buf, lp);
 				lp->dialstate = 1;
 				lp->flags |= ISDN_NET_CONNECTED;
 				/* Connect interface with channel */
@@ -928,59 +1051,47 @@
 				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
 					/* no 'first_skb' handling for syncPPP */
 					if (isdn_ppp_bind(lp) < 0) {
-                                        	dev_kfree_skb(skb,FREE_WRITE);
+						dev_kfree_skb(skb, FREE_WRITE);
 						isdn_net_unbind_channel(lp);
-                                                restore_flags(flags);
+						restore_flags(flags);
 						return 0;	/* STN (skb to nirvana) ;) */
 					}
 					restore_flags(flags);
-	                                isdn_net_dial();	/* Initiate dialing */
+					isdn_net_dial();	/* Initiate dialing */
 					return 1;	/* let upper layer requeue skb packet */
 				}
 #endif
-                                /* remember first skb to speed up arp
-                                 * when using encap ETHER
-                                 */
-                                if (lp->first_skb) {
-                                        printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
-                                        dev_kfree_skb(lp->first_skb,FREE_WRITE);
-                                        lp->first_skb = NULL;
-                                }
-                                lp->first_skb = skb;
+				/* remember first skb to speed up arp
+				 * when using encap ETHER
+				 */
+				if (lp->first_skb) {
+					printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
+					dev_kfree_skb(lp->first_skb, FREE_WRITE);
+					lp->first_skb = NULL;
+				}
+				lp->first_skb = skb;
 				/* Initiate dialing */
-                                ndev->tbusy = 0;
+				ndev->tbusy = 0;
 				restore_flags(flags);
 				isdn_net_dial();
-                                return 0;
+				return 0;
 			} else {
-                                /*
-                                 * Having no phone-number is a permanent
-                                 * failure or misconfiguration.
-                                 * Instead of just dropping, we should also
-                                 * have the upper layers to respond
-                                 * with an ICMP No route to host in the
-                                 * future, however at the moment, i don't
-                                 * know a simple way to do that.
-                                 * The same applies, when the telecom replies
-                                 * "no destination" to our dialing-attempt.
-                                 */
-                                printk(KERN_WARNING
-                                       "isdn_net: No phone number for %s, packet dropped\n",
-                                       ndev->name);
+				isdn_net_unreachable(ndev, skb,
+						     "No phone number");
 				dev_kfree_skb(skb, FREE_WRITE);
 				ndev->tbusy = 0;
-                                return 0;
+				return 0;
 			}
 		} else {
-                        /* Connection is established, try sending */
+			/* Connection is established, try sending */
 			ndev->trans_start = jiffies;
 			if (!lp->dialstate) {
-                                if (lp->first_skb) {
-                                        if (isdn_net_xmit(ndev,lp,lp->first_skb))
-                                                return 1;
-                                        lp->first_skb = NULL;
-                                }
-				return(isdn_net_xmit(ndev, lp, skb));
+				if (lp->first_skb) {
+					if (isdn_net_xmit(ndev, lp, lp->first_skb))
+						return 1;
+					lp->first_skb = NULL;
+				}
+				return (isdn_net_xmit(ndev, lp, skb));
 			} else
 				ndev->tbusy = 1;
 		}
@@ -998,7 +1109,6 @@
 
 	dev->tbusy = 1;
 	dev->start = 0;
-	isdn_net_hangup(dev);
 	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
 		/* If this interface has slaves, stop them also */
 		while (p) {
@@ -1008,6 +1118,7 @@
 			p = (((isdn_net_local *) p->priv)->slave);
 		}
 	}
+	isdn_net_hangup(dev);
 	isdn_MOD_DEC_USE_COUNT();
 	return 0;
 }
@@ -1016,7 +1127,7 @@
  * Get statistics
  */
 static struct enet_statistics *
- isdn_net_get_stats(struct device *dev)
+isdn_net_get_stats(struct device *dev)
 {
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
 	return &lp->stats;
@@ -1031,51 +1142,50 @@
  *      This is normal practice and works for any 'now in use' protocol.
  */
 
-unsigned short isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
+static unsigned short
+isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
 {
-        struct ethhdr *eth;
-        unsigned char *rawp;
-        
-        skb_pull(skb,ETH_HLEN);
-        eth= skb->mac.ethernet;
-        
-        if(*eth->h_dest&1) {
-                if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
-                        skb->pkt_type=PACKET_BROADCAST;
-                else
-                        skb->pkt_type=PACKET_MULTICAST;
-        }
-        
-        /*
-         *      This ALLMULTI check should be redundant by 1.4
-         *      so don't forget to remove it.
-         */
-        
-        else if (dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) {
-                if (memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
-                        skb->pkt_type=PACKET_OTHERHOST;
-        }
-
-        if (ntohs(eth->h_proto) >= 1536)
-                return eth->h_proto;
-
-        rawp = skb->data;
-
-        /*
-         *      This is a magic hack to spot IPX packets. Older Novell breaks
-         *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
-         *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-         *      won't work for fault tolerant netware but does for the rest.
-         */
-        if (*(unsigned short *)rawp == 0xFFFF)
-                return htons(ETH_P_802_3);
-        /*
-         *      Real 802.2 LLC
-         */
-        return htons(ETH_P_802_2);
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb_pull(skb, ETH_HLEN);
+	eth = skb->mac.ethernet;
+
+	if (*eth->h_dest & 1) {
+		if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	}
+	/*
+	 *      This ALLMULTI check should be redundant by 1.4
+	 *      so don't forget to remove it.
+	 */
+
+	else if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+		if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	if (ntohs(eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+	/*
+	 *      This is a magic hack to spot IPX packets. Older Novell breaks
+	 *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
+	 *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+	 *      won't work for fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *) rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+	/*
+	 *      Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
 }
 
-/* 
+/*
  * Got a packet from ISDN-Channel.
  */
 static void
@@ -1083,21 +1193,21 @@
 {
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
 #ifdef CONFIG_ISDN_PPP
-        isdn_net_local *olp = lp;  /* original 'lp' */
-        int proto = PPP_PROTOCOL(skb->data);
+	isdn_net_local *olp = lp;	/* original 'lp' */
+	int proto = PPP_PROTOCOL(skb->data);
 #endif
 
 	lp->transcount += skb->len;
 	lp->stats.rx_packets++;
 #ifdef CONFIG_ISDN_PPP
-        /*
-         * If encapsulation is syncppp, don't reset
-         * huptimer on LCP packets.
-         */
-        if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
-            (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+	/*
+	 * If encapsulation is syncppp, don't reset
+	 * huptimer on LCP packets.
+	 */
+	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+	    (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
 #endif
-	        lp->huptimer = 0;
+		lp->huptimer = 0;
 
 	if (lp->master) {
 		/* Bundling: If device is a slave-device, deliver to master, also
@@ -1107,56 +1217,55 @@
 		lp = (isdn_net_local *) ndev->priv;
 		lp->stats.rx_packets++;
 #ifdef CONFIG_ISDN_PPP
-                /*
-                 * If encapsulation is syncppp, don't reset
-                 * huptimer on LCP packets.
-                 */
-                if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
-                    (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+		/*
+		 * If encapsulation is syncppp, don't reset
+		 * huptimer on LCP packets.
+		 */
+		if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+		    (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
 #endif
-                        lp->huptimer = 0;
+			lp->huptimer = 0;
 	}
-
 	skb->dev = ndev;
 	skb->pkt_type = PACKET_HOST;
-        skb->mac.raw = skb->data;
+	skb->mac.raw = skb->data;
 #ifdef ISDN_DEBUG_NET_DUMP
-        isdn_dumppkt("R:", skb->data, skb->len, 40);
+	isdn_dumppkt("R:", skb->data, skb->len, 40);
 #endif
 	switch (lp->p_encap) {
-                case ISDN_NET_ENCAP_ETHER:
-                        /* Ethernet over ISDN */
-                        skb->protocol = isdn_net_type_trans(skb,ndev);
-                        break;
-                case ISDN_NET_ENCAP_UIHDLC:
-                        /* HDLC with UI-frame (for ispa with -h1 option) */
-                        skb_pull(skb,2);
-                        /* Fall through */
-                case ISDN_NET_ENCAP_RAWIP:
-                        /* RAW-IP without MAC-Header */
-                        skb->protocol = htons(ETH_P_IP);
-                        break;
-                case ISDN_NET_ENCAP_CISCOHDLC:
-                        /* CISCO-HDLC IP with type field and  fake I-frame-header */
-                        skb_pull(skb, 2);
-                        /* Fall through */
-                case ISDN_NET_ENCAP_IPTYP:
-                        /* IP with type field */
-                        skb->protocol = *(unsigned short *)&(skb->data[0]);
-                        skb_pull(skb, 2);
-                        if (*(unsigned short *)skb->data == 0xFFFF)
-                                skb->protocol = htons(ETH_P_802_3);
-                        break;
+		case ISDN_NET_ENCAP_ETHER:
+			/* Ethernet over ISDN */
+			skb->protocol = isdn_net_type_trans(skb, ndev);
+			break;
+		case ISDN_NET_ENCAP_UIHDLC:
+			/* HDLC with UI-frame (for ispa with -h1 option) */
+			skb_pull(skb, 2);
+			/* Fall through */
+		case ISDN_NET_ENCAP_RAWIP:
+			/* RAW-IP without MAC-Header */
+			skb->protocol = htons(ETH_P_IP);
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLC:
+			/* CISCO-HDLC IP with type field and  fake I-frame-header */
+			skb_pull(skb, 2);
+			/* Fall through */
+		case ISDN_NET_ENCAP_IPTYP:
+			/* IP with type field */
+			skb->protocol = *(unsigned short *) &(skb->data[0]);
+			skb_pull(skb, 2);
+			if (*(unsigned short *) skb->data == 0xFFFF)
+				skb->protocol = htons(ETH_P_802_3);
+			break;
 #ifdef CONFIG_ISDN_PPP
-                case ISDN_NET_ENCAP_SYNCPPP:
-                        isdn_ppp_receive(lp->netdev, olp, skb);
-                        return;
-#endif
-                default:
-                        printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
-                               lp->name);
-                        kfree_skb(skb,FREE_READ);
-                        return;
+		case ISDN_NET_ENCAP_SYNCPPP:
+			isdn_ppp_receive(lp->netdev, olp, skb);
+			return;
+#endif
+		default:
+			printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
+			       lp->name);
+			kfree_skb(skb, FREE_READ);
+			return;
 	}
 	netif_rx(skb);
 	return;
@@ -1168,34 +1277,7 @@
  * else return 0.
  */
 int
-isdn_net_receive_callback(int idx, u_char * buf, int len)
-{
-	isdn_net_dev *p = dev->rx_netdev[idx];
-	struct sk_buff *skb;
-
-	if (p) {
-		isdn_net_local *lp = &p->local;
-		if ((lp->flags & ISDN_NET_CONNECTED) &&
-		    (!lp->dialstate)) {
-			skb = dev_alloc_skb(len);
-			if (skb == NULL) {
-				printk(KERN_WARNING "out of memory\n");
-				return 0;
-			}
-			memcpy(skb_put(skb, len), buf, len);
-			isdn_net_receive(&p->dev, skb);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- *  receive callback for lowlevel drivers, which support skb's
- */
-
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb) 
+isdn_net_rcv_skb(int idx, struct sk_buff *skb)
 {
 	isdn_net_dev *p = dev->rx_netdev[idx];
 
@@ -1212,43 +1294,41 @@
 
 static int
 my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
-              void *daddr, void *saddr, unsigned len)
+	      void *daddr, void *saddr, unsigned len)
 {
-	struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
+	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
 
-	/* 
+	/*
 	 * Set the protocol type. For a packet of type ETH_P_802_3 we
-         * put the length here instead. It is up to the 802.2 layer to
-         * carry protocol information.
+	 * put the length here instead. It is up to the 802.2 layer to
+	 * carry protocol information.
 	 */
-	
-	if(type!=ETH_P_802_3) 
+
+	if (type != ETH_P_802_3)
 		eth->h_proto = htons(type);
 	else
 		eth->h_proto = htons(len);
 
 	/*
-	 *	Set the source hardware address. 
+	 * Set the source hardware address.
 	 */
-	if(saddr)
-		memcpy(eth->h_source,saddr,dev->addr_len);
+	if (saddr)
+		memcpy(eth->h_source, saddr, dev->addr_len);
 	else
-		memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
+		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
 
 	/*
-	 *	Anyway, the loopback-device should never use this function... 
+	 * Anyway, the loopback-device should never use this function...
 	 */
 
 	if (dev->flags & IFF_LOOPBACK) {
 		memset(eth->h_dest, 0, dev->addr_len);
-		return(dev->hard_header_len);
+		return (dev->hard_header_len);
 	}
-	
-	if(daddr) {
-		memcpy(eth->h_dest,daddr,dev->addr_len);
+	if (daddr) {
+		memcpy(eth->h_dest, daddr, dev->addr_len);
 		return dev->hard_header_len;
 	}
-	
 	return -dev->hard_header_len;
 }
 
@@ -1256,76 +1336,114 @@
  *  build an header
  *  depends on encaps that is being used.
  */
- 
+
 static int
 isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
-                void *daddr, void *saddr, unsigned plen)
+		void *daddr, void *saddr, unsigned plen)
 {
 	isdn_net_local *lp = dev->priv;
 	ushort len = 0;
-	
+
 	switch (lp->p_encap) {
-                case ISDN_NET_ENCAP_ETHER:
-                        len = my_eth_header(skb, dev, type, daddr, saddr, plen);
-                        break;
-                case ISDN_NET_ENCAP_RAWIP:
-                        printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
+		case ISDN_NET_ENCAP_ETHER:
+			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+			break;
+#ifdef CONFIG_ISDN_PPP
+		case ISDN_NET_ENCAP_SYNCPPP:
+			/* stick on a fake header to keep fragmentation code happy. */
+			len = IPPP_MAX_HEADER;
+			skb_push(skb,len);
+			break;
+#endif
+		case ISDN_NET_ENCAP_RAWIP:
+			printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
 			len = 0;
-                        break;
-                case ISDN_NET_ENCAP_IPTYP:
-                        /* ethernet type field */
-                        *((ushort*) skb_push(skb, 2)) = htons(type);
-                        len = 2;
-                        break;
-                case ISDN_NET_ENCAP_UIHDLC:
-                        /* HDLC with UI-Frames (for ispa with -h1 option) */
-                        *((ushort*) skb_push(skb, 2)) = htons(0x0103);
-                        len = 2;
-                        break;
-                case ISDN_NET_ENCAP_CISCOHDLC:
+			break;
+		case ISDN_NET_ENCAP_IPTYP:
+			/* ethernet type field */
+			*((ushort *) skb_push(skb, 2)) = htons(type);
+			len = 2;
+			break;
+		case ISDN_NET_ENCAP_UIHDLC:
+			/* HDLC with UI-Frames (for ispa with -h1 option) */
+			*((ushort *) skb_push(skb, 2)) = htons(0x0103);
+			len = 2;
+			break;
+		case ISDN_NET_ENCAP_CISCOHDLC:
 			skb_push(skb, 4);
-                        skb->data[0] = 0x0f;
-                        skb->data[1] = 0x00;
-                        *((ushort*)&skb->data[2]) = htons(type);
-                        len = 4;
-                        break;
+			skb->data[0] = 0x0f;
+			skb->data[1] = 0x00;
+			*((ushort *) & skb->data[2]) = htons(type);
+			len = 4;
+			break;
 	}
 	return len;
 }
 
 /* We don't need to send arp, because we have point-to-point connections. */
-
+#if (LINUX_VERSION_CODE < 0x02010F)
 static int
 isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst,
-                        struct sk_buff *skb)
+			struct sk_buff *skb)
 {
 	isdn_net_local *lp = dev->priv;
-        int ret = 0;
+	int ret = 0;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+		struct ethhdr *eth = (struct ethhdr *) buff;
+
+		/*
+		 *      Only ARP/IP is currently supported
+		 */
 
-        if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
-                struct ethhdr *eth = (struct ethhdr *)buff;
-                
-                /*
-                 *      Only ARP/IP is currently supported
-                 */
-                
-                if(eth->h_proto != htons(ETH_P_IP)) {
-                        printk(KERN_WARNING
-                               "isdn_net: %s don't know how to resolve type %d addresses?\n",
-                               dev->name, (int)eth->h_proto);
-                        memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-                        return 0;
-                }
-                /*
-                 *      Try to get ARP to resolve the header.
-                 */
-#ifdef CONFIG_INET       
-                ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
-#endif  
-        }
+		if (eth->h_proto != htons(ETH_P_IP)) {
+			printk(KERN_WARNING
+			       "isdn_net: %s don't know how to resolve type %d addresses?\n",
+			       dev->name, (int) eth->h_proto);
+			memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+			return 0;
+		}
+		/*
+		 *      Try to get ARP to resolve the header.
+		 */
+#ifdef CONFIG_INET
+		ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb) ? 1 : 0;
+#endif
+	}
 	return ret;
 }
+#else
+static int
+isdn_net_rebuild_header(struct sk_buff *skb)
+{
+	struct device *dev = skb->dev;
+	isdn_net_local *lp = dev->priv;
+	int ret = 0;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+		struct ethhdr *eth = (struct ethhdr *) skb->data;
 
+		/*
+		 *      Only ARP/IP is currently supported
+		 */
+
+		if (eth->h_proto != htons(ETH_P_IP)) {
+			printk(KERN_WARNING
+			       "isdn_net: %s don't know how to resolve type %d addresses?\n",
+			       dev->name, (int) eth->h_proto);
+			memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+			return 0;
+		}
+		/*
+		 *      Try to get ARP to resolve the header.
+		 */
+#ifdef CONFIG_INET
+		ret = arp_find(eth->h_dest, skb) ? 1 : 0;
+#endif
+	}
+	return ret;
+}
+#endif
 /*
  * Interface-setup. (called just after registering a new interface)
  */
@@ -1333,8 +1451,9 @@
 isdn_net_init(struct device *ndev)
 {
 	ushort max_hlhdr_len = 0;
-        isdn_net_local *lp = (isdn_net_local *)ndev->priv;
-	int drvidx, i;
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	int drvidx,
+	 i;
 
 	if (ndev == NULL) {
 		printk(KERN_WARNING "isdn_net_init: dev = NULL!\n");
@@ -1344,54 +1463,61 @@
 		printk(KERN_WARNING "isdn_net_init: dev->priv = NULL!\n");
 		return -ENODEV;
 	}
-
-        ether_setup(ndev);
-        lp->org_hcb               = ndev->header_cache_bind;
-        lp->org_hcu               = ndev->header_cache_update;
+	ether_setup(ndev);
+#if (LINUX_VERSION_CODE < 0x02010F)
+	lp->org_hcb = ndev->header_cache_bind;
+#else
+	lp->org_hhc = ndev->hard_header_cache;
+#endif
+	lp->org_hcu = ndev->header_cache_update;
 
 	/* Setup the generic properties */
 
-        ndev->hard_header         = NULL;
-        ndev->header_cache_bind   = NULL;
-        ndev->header_cache_update = NULL;
-        ndev->mtu                 = 1500;
-        ndev->flags               = IFF_NOARP;
-        ndev->family              = AF_INET;
-        ndev->type                = ARPHRD_ETHER;  
-        ndev->addr_len            = ETH_ALEN;
-        ndev->pa_addr             = 0;
-        ndev->pa_brdaddr          = 0;
-        ndev->pa_mask             = 0;
-        ndev->pa_alen             = 4;
+	ndev->hard_header = NULL;
+#if (LINUX_VERSION_CODE < 0x02010F)
+	ndev->header_cache_bind = NULL;
+#else
+	ndev->hard_header_cache = NULL;
+#endif
+	ndev->header_cache_update = NULL;
+	ndev->mtu = 1500;
+	ndev->flags = IFF_NOARP;
+	ndev->family = AF_INET;
+	ndev->type = ARPHRD_ETHER;
+	ndev->addr_len = ETH_ALEN;
+	ndev->pa_addr = 0;
+	ndev->pa_brdaddr = 0;
+	ndev->pa_mask = 0;
+	ndev->pa_alen = 4;
 
-        for (i = 0; i < ETH_ALEN; i++)
-                ndev->broadcast[i]=0xff;
+	for (i = 0; i < ETH_ALEN; i++)
+		ndev->broadcast[i] = 0xff;
 
 	for (i = 0; i < DEV_NUMBUFFS; i++)
-                skb_queue_head_init(&ndev->buffs[i]);
-	
+		skb_queue_head_init(&ndev->buffs[i]);
+
 	/* The ISDN-specific entries in the device structure. */
-	ndev->open                = &isdn_net_open;
-	ndev->hard_start_xmit     = &isdn_net_start_xmit;
+	ndev->open = &isdn_net_open;
+	ndev->hard_start_xmit = &isdn_net_start_xmit;
 
-	/* 
+	/*
 	 *  up till binding we ask the protocol layer to reserve as much
 	 *  as we might need for HL layer
-         */
-	
+	 */
+
 	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
 		if (dev->drv[drvidx])
 			if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
 				max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
 
-	ndev->hard_header_len     = ETH_HLEN + max_hlhdr_len;
+	ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
 
-	ndev->stop                = &isdn_net_close;
-	ndev->get_stats           = &isdn_net_get_stats;
-	ndev->rebuild_header      = &isdn_net_rebuild_header;
+	ndev->stop = &isdn_net_close;
+	ndev->get_stats = &isdn_net_get_stats;
+	ndev->rebuild_header = &isdn_net_rebuild_header;
 
 #ifdef CONFIG_ISDN_PPP
-	ndev->do_ioctl            = isdn_ppp_dev_ioctl;
+	ndev->do_ioctl = isdn_ppp_dev_ioctl;
 #endif
 	return 0;
 }
@@ -1432,35 +1558,35 @@
 
 	for (; *p; s++, p++)
 		switch (*p) {
-                        case '\\':
-                                /*
-                                 * Literal match with following character,
-                                 * fall through.
-                                 */
-                                p++;
-                        default:
-                                if (*s != *p)
-                                        return (0);
-                                continue;
-                        case '?':
-                                /* Match anything. */
-                                if (*s == '\0')
-                                        return (0);
-                                continue;
-                        case '*':
-                                /* Trailing star matches everything. */
-                                return (*++p ? isdn_net_Star(s, p) : 1);
-                        case '[':
-                                /* [^....] means inverse character class. */
-                                if ((reverse = (p[1] == '^')))
-                                        p++;
-                                for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
-                                        /* This next line requires a good C compiler. */
-                                        if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
-                                                matched = 1;
-                                if (matched == reverse)
-                                        return (0);
-                                continue;
+			case '\\':
+				/*
+				 * Literal match with following character,
+				 * fall through.
+				 */
+				p++;
+			default:
+				if (*s != *p)
+					return (0);
+				continue;
+			case '?':
+				/* Match anything. */
+				if (*s == '\0')
+					return (0);
+				continue;
+			case '*':
+				/* Trailing star matches everything. */
+				return (*++p ? isdn_net_Star(s, p) : 1);
+			case '[':
+				/* [^....] means inverse character class. */
+				if ((reverse = (p[1] == '^')))
+					p++;
+				for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
+					/* This next line requires a good C compiler. */
+					if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
+						matched = 1;
+				if (matched == reverse)
+					return (0);
+				continue;
 		}
 	return (*s == '\0');
 }
@@ -1477,12 +1603,12 @@
 	while (p) {
 		if (p->local.pre_device == drvidx)
 			switch (p->local.pre_channel) {
-			case 0:
-				p->local.pre_channel = 1;
-				break;
-			case 1:
-				p->local.pre_channel = 0;
-				break;
+				case 0:
+					p->local.pre_channel = 1;
+					break;
+				case 1:
+					p->local.pre_channel = 0;
+					break;
 			}
 		p = (isdn_net_dev *) p->next;
 	}
@@ -1519,7 +1645,7 @@
  *               4 = Wait cbdelay, then call back
  */
 int
-isdn_net_find_icall(int di, int ch, int idx, char *num)
+isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 {
 	char *eaz;
 	int si1;
@@ -1530,40 +1656,24 @@
 	isdn_net_dev *p;
 	isdn_net_phone *n;
 	ulong flags;
-	char nr[31];
-	char *s;
+	char nr[32];
 
 	/* Search name in netdev-chain */
 	save_flags(flags);
 	cli();
-	if (num[0] == ',') {
+	if (!setup.phone[0]) {
 		nr[0] = '0';
-		strncpy(&nr[1], num, 30);
+		nr[1] = '\0';
 		printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
 	} else
-		strncpy(nr, num, 30);
-	s = strtok(nr, ",");
-	s = strtok(NULL, ",");
-	if (!s) {
-		printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n",
-		       num);
-		restore_flags(flags);
-		return 0;
-	}
-	si1 = (int)simple_strtoul(s,NULL,10);
-	s = strtok(NULL, ",");
-	if (!s) {
-		printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n",
-		       num);
-		restore_flags(flags);
-		return 0;
-	}
-	si2 = (int)simple_strtoul(s,NULL,10);
-	eaz = strtok(NULL, ",");
-	if (!eaz) {
+		strcpy(nr, setup.phone);
+	si1 = (int) setup.si1;
+	si2 = (int) setup.si2;
+	if (!setup.eazmsn[0]) {
 		printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
 		eaz = "0";
-	}
+	} else
+		eaz = setup.eazmsn;
 	if (dev->net_verbose > 1)
 		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
 	/* Accept only calls with Si1 = 7 (Data-Transmission) */
@@ -1583,12 +1693,12 @@
 	while (p) {
 		/* If last check has triggered as binding-swap, revert it */
 		switch (swapped) {
-		case 2:
-			isdn_net_swap_usage(idx, sidx);
-			/* fall through */
-		case 1:
-			isdn_net_swapbind(di);
-			break;
+			case 2:
+				isdn_net_swap_usage(idx, sidx);
+				/* fall through */
+			case 1:
+				isdn_net_swapbind(di);
+				break;
 		}
 		swapped = 0;
 		if (!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz))
@@ -1597,11 +1707,11 @@
 		printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
 		       p->local.name, p->local.msn, p->local.flags, p->local.dialstate);
 #endif
-		if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) &&	    /* EAZ is matching   */
-		    (((!(p->local.flags & ISDN_NET_CONNECTED)) &&	            /* but not connected */
-		      (USG_NONE(dev->usage[idx]))) ||	                            /* and ch. unused or */
-		     ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing        */
-		       (!(p->local.flags & ISDN_NET_CALLBACK)))		            /* but no callback   */
+		if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) &&	/* EAZ is matching   */
+		    (((!(p->local.flags & ISDN_NET_CONNECTED)) &&	/* but not connected */
+		      (USG_NONE(dev->usage[idx]))) ||	/* and ch. unused or */
+		     ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) &&	/* if dialing        */
+		       (!(p->local.flags & ISDN_NET_CALLBACK)))	/* but no callback   */
 		     ))) {
 #ifdef ISDN_DEBUG_NET_ICALL
 			printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
@@ -1611,13 +1721,13 @@
 				if ((p->local.pre_channel != ch) ||
 				    (p->local.pre_device != di)) {
 					/* Here we got a problem:
-					   If using an ICN-Card, an incoming call is always signaled on
-					   on the first channel of the card, if both channels are
-					   down. However this channel may be bound exclusive. If the
-					   second channel is free, this call should be accepted.
-					   The solution is horribly but it runs, so what:
-					   We exchange the exclusive bindings of the two channels, the
-					   corresponding variables in the interface-structs.
+					 * If using an ICN-Card, an incoming call is always signaled on
+					 * on the first channel of the card, if both channels are
+					 * down. However this channel may be bound exclusive. If the
+					 * second channel is free, this call should be accepted.
+					 * The solution is horribly but it runs, so what:
+					 * We exchange the exclusive bindings of the two channels, the
+					 * corresponding variables in the interface-structs.
 					 */
 					if (ch == 0) {
 						sidx = isdn_dc2minor(di, 1);
@@ -1626,13 +1736,13 @@
 #endif
 						if (USG_NONE(dev->usage[sidx])) {
 							/* Second Channel is free, now see if it is bound
-							   exclusive too. */
+							 * exclusive too. */
 							if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
 #ifdef ISDN_DEBUG_NET_ICALL
 								printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
 #endif
 								/* Yes, swap bindings only, if the original
-								   binding is bound to channel 1 of this driver */
+								 * binding is bound to channel 1 of this driver */
 								if ((p->local.pre_device == di) &&
 								    (p->local.pre_channel == 1)) {
 									isdn_net_swapbind(di);
@@ -1674,7 +1784,7 @@
 						continue;
 					}
 				}
-			} /* if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) */
+			}
 #ifdef ISDN_DEBUG_NET_ICALL
 			printk(KERN_DEBUG "n_fi: match2\n");
 #endif
@@ -1739,7 +1849,7 @@
 							return 0;
 						}
 						/* Setup dialstate. */
-                                                lp->dtimer = 0;
+						lp->dtimer = 0;
 						lp->dialstate = 11;
 						lp->flags |= ISDN_NET_CONNECTED;
 						/* Connect interface with channel */
@@ -1754,7 +1864,7 @@
 #endif
 						/* Initiate dialing by returning 2 or 4 */
 						restore_flags(flags);
-						return (lp->flags & ISDN_NET_CBHUP)?2:4;
+						return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
 					} else
 						printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
 					restore_flags(flags);
@@ -1766,28 +1876,27 @@
 					   device, so free this device */
 					if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) {
 #ifdef CONFIG_ISDN_PPP
-                                                if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-                                                        isdn_ppp_free(lp);
+						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+							isdn_ppp_free(lp);
 #endif
 						isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
 							 ISDN_USAGE_NET);
-                                        }
+					}
 					dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
 					dev->usage[idx] |= ISDN_USAGE_NET;
 					strcpy(dev->num[idx], nr);
 					isdn_info_update();
-                                        dev->st_netdev[idx] = lp->netdev;
+					dev->st_netdev[idx] = lp->netdev;
 					p->local.isdn_device = di;
 					p->local.isdn_channel = ch;
 					p->local.ppp_slot = -1;
-					p->local.pppbind = -1;
 					p->local.flags |= ISDN_NET_CONNECTED;
 					p->local.dialstate = 7;
 					p->local.dtimer = 0;
 					p->local.outgoing = 0;
 					p->local.huptimer = 0;
-					p->local.hupflags |= 1;
-                                        p->local.hupflags &= ~2;
+					p->local.hupflags |= ISDN_WAITCHARGE;
+					p->local.hupflags &= ~ISDN_HAVECHARGE;
 #ifdef CONFIG_ISDN_PPP
 					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 						if (isdn_ppp_bind(lp) < 0) {
@@ -1814,7 +1923,7 @@
  * Search list of net-interfaces for an interface with given name.
  */
 isdn_net_dev *
- isdn_net_findif(char *name)
+isdn_net_findif(char *name)
 {
 	isdn_net_dev *p = dev->netdev;
 
@@ -1831,7 +1940,8 @@
  * This is called from the userlevel-routine below or
  * from isdn_net_start_xmit().
  */
-int isdn_net_force_dial_lp(isdn_net_local * lp)
+int
+isdn_net_force_dial_lp(isdn_net_local * lp)
 {
 	if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
 		int chi;
@@ -1841,8 +1951,8 @@
 			cli();
 			/* Grab a free ISDN-Channel */
 			if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
-						    lp->l3_proto,
-						    lp->pre_device,
+							 lp->l3_proto,
+							 lp->pre_device,
 						 lp->pre_channel)) < 0) {
 				printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
 				restore_flags(flags);
@@ -1874,7 +1984,7 @@
  * Force a net-interface to dial out.
  * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
  */
-int 
+int
 isdn_net_force_dial(char *name)
 {
 	isdn_net_dev *p = isdn_net_findif(name);
@@ -1906,9 +2016,9 @@
 		strcpy(netdev->local.name, "         ");
 	else
 		strcpy(netdev->local.name, name);
-	netdev->dev.name      = netdev->local.name;
-	netdev->dev.priv      = &netdev->local;
-	netdev->dev.init      = isdn_net_init;
+	netdev->dev.name = netdev->local.name;
+	netdev->dev.priv = &netdev->local;
+	netdev->dev.init = isdn_net_init;
 	netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP;
 	if (master) {
 		/* Device shall be a slave */
@@ -1936,7 +2046,7 @@
 	netdev->local.magic = ISDN_NET_MAGIC;
 
 #ifdef CONFIG_ISDN_PPP
-	netdev->mp_last = NULL;	/* mpqueue is empty */
+	netdev->mp_last = NULL; /* mpqueue is empty */
 	netdev->ib.next_num = 0;
 	netdev->ib.last = NULL;
 #endif
@@ -1952,18 +2062,19 @@
 	netdev->local.exclusive = -1;
 	netdev->local.ppp_slot = -1;
 	netdev->local.pppbind = -1;
-        netdev->local.sav_skb = NULL;
-        netdev->local.first_skb = NULL;
+	netdev->local.sav_skb = NULL;
+	netdev->local.first_skb = NULL;
 	netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
 	netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
+	netdev->local.triggercps = 6000;
 	netdev->local.slavedelay = 10 * HZ;
 	netdev->local.srobin = &netdev->dev;
-	netdev->local.hupflags = 8;	/* Do hangup even on incoming calls */
+	netdev->local.hupflags = ISDN_INHUP;	/* Do hangup even on incoming calls */
 	netdev->local.onhtime = 10;	/* Default hangup-time for saving costs
-					   of those who forget configuring this */
+	   of those who forget configuring this */
 	netdev->local.dialmax = 1;
-        netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */
-        netdev->local.cbdelay = 25;      /* Wait 5 secs before Callback */
+	netdev->local.flags = ISDN_NET_CBHUP;	/* Hangup before Callback */
+	netdev->local.cbdelay = 25;	/* Wait 5 secs before Callback */
 	/* Put into to netdev-chain */
 	netdev->next = (void *) dev->netdev;
 	dev->netdev = netdev;
@@ -1989,6 +2100,9 @@
 		/* Master must be a real interface, not a slave */
 		if (n->local.master)
 			return NULL;
+		/* Master must not be started yet */
+		if (n->dev.start)
+			return NULL;
 		return (isdn_net_new(newname, &(n->dev)));
 	}
 	return NULL;
@@ -2000,7 +2114,8 @@
  * for not overwriting existing setups. It has to get the current
  * setup first, if only selected parameters are to be changed.
  */
-int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
+int
+isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
 {
 	isdn_net_dev *p = isdn_net_findif(cfg->name);
 	ulong features;
@@ -2020,33 +2135,34 @@
 			printk(KERN_WARNING "isdn_net: No driver with selected features\n");
 			return -ENODEV;
 		}
-                if (p->local.p_encap != cfg->p_encap)
-                        if (p->dev.start) {
-                                printk(KERN_WARNING
-                                       "%s: cannot change encap when if is up\n",
-                                       p->local.name);
-                                return -EBUSY;
-                        }
-                if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+		if (p->local.p_encap != cfg->p_encap)
+			if (p->dev.start) {
+				printk(KERN_WARNING
+				"%s: cannot change encap when if is up\n",
+				       p->local.name);
+				return -EBUSY;
+			}
+		if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
 #ifndef CONFIG_ISDN_PPP
-                        printk(KERN_WARNING "%s: SyncPPP support not configured\n",
-                               p->local.name);
-                        return -EINVAL;
+			printk(KERN_WARNING "%s: SyncPPP support not configured\n",
+			       p->local.name);
+			return -EINVAL;
 #else
-                        p->dev.type = ARPHRD_PPP; /* change ARP type */
-                        p->dev.addr_len = 0;
+			p->dev.type = ARPHRD_PPP;	/* change ARP type */
+			p->dev.addr_len = 0;
 #endif
-                }
+		}
 		if (strlen(cfg->drvid)) {
 			/* A bind has been requested ... */
-			char *c,*e;
+			char *c,
+			*e;
 
 			drvidx = -1;
 			chidx = -1;
 			strcpy(drvid, cfg->drvid);
 			if ((c = strchr(drvid, ','))) {
 				/* The channel-number is appended to the driver-Id with a comma */
-				chidx = (int)simple_strtoul(c + 1,&e,10);
+				chidx = (int) simple_strtoul(c + 1, &e, 10);
 				if (e == c)
 					chidx = -1;
 				*c = '\0';
@@ -2071,9 +2187,9 @@
 			/* If binding is exclusive, try to grab the channel */
 			save_flags(flags);
 			if ((i = isdn_get_free_channel(ISDN_USAGE_NET, p->local.l2_proto,
-						  p->local.l3_proto,
-						  drvidx,
-						  chidx)) < 0) {
+						       p->local.l3_proto,
+						       drvidx,
+						       chidx)) < 0) {
 				/* Grab failed, because desired channel is in use */
 				p->local.exclusive = -1;
 				restore_flags(flags);
@@ -2089,22 +2205,23 @@
 			p->local.exclusive = -1;
 			if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) {
 				isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
-                                isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET);
+				isdn_free_channel(p->local.pre_device, p->local.pre_channel, ISDN_USAGE_NET);
 				drvidx = -1;
 				chidx = -1;
 			}
 		}
 		strcpy(p->local.msn, cfg->eaz);
-		p->local.pre_device  = drvidx;
+		p->local.pre_device = drvidx;
 		p->local.pre_channel = chidx;
-		p->local.onhtime     = cfg->onhtime;
-		p->local.charge      = cfg->charge;
-		p->local.l2_proto    = cfg->l2_proto;
-		p->local.l3_proto    = cfg->l3_proto;
-                p->local.cbdelay     = cfg->cbdelay;
-                p->local.dialmax     = cfg->dialmax;
-		p->local.slavedelay  = cfg->slavedelay * HZ;
-		p->local.pppbind     = cfg->pppbind;
+		p->local.onhtime = cfg->onhtime;
+		p->local.charge = cfg->charge;
+		p->local.l2_proto = cfg->l2_proto;
+		p->local.l3_proto = cfg->l3_proto;
+		p->local.cbdelay = cfg->cbdelay;
+		p->local.dialmax = cfg->dialmax;
+		p->local.triggercps = cfg->triggercps;
+		p->local.slavedelay = cfg->slavedelay * HZ;
+		p->local.pppbind = cfg->pppbind;
 		if (cfg->secure)
 			p->local.flags |= ISDN_NET_SECURE;
 		else
@@ -2114,47 +2231,63 @@
 		else
 			p->local.flags &= ~ISDN_NET_CBHUP;
 		switch (cfg->callback) {
-                        case 0:
-                                p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT);
-                                break;
-                        case 1:
-                                p->local.flags |= ISDN_NET_CALLBACK;
-                                p->local.flags &= ~ISDN_NET_CBOUT;
-                                break;
-                        case 2:
-                                p->local.flags |= ISDN_NET_CBOUT;
-                                p->local.flags &= ~ISDN_NET_CALLBACK;
-                                break;
-                }
+			case 0:
+				p->local.flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+				break;
+			case 1:
+				p->local.flags |= ISDN_NET_CALLBACK;
+				p->local.flags &= ~ISDN_NET_CBOUT;
+				break;
+			case 2:
+				p->local.flags |= ISDN_NET_CBOUT;
+				p->local.flags &= ~ISDN_NET_CALLBACK;
+				break;
+		}
 		if (cfg->chargehup)
-			p->local.hupflags |= 4;
+			p->local.hupflags |= ISDN_CHARGEHUP;
 		else
-			p->local.hupflags &= ~4;
+			p->local.hupflags &= ~ISDN_CHARGEHUP;
 		if (cfg->ihup)
-			p->local.hupflags |= 8;
+			p->local.hupflags |= ISDN_INHUP;
 		else
-			p->local.hupflags &= ~8;
+			p->local.hupflags &= ~ISDN_INHUP;
+		if (cfg->chargeint > 10) {
+			p->local.hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+			p->local.chargeint = cfg->chargeint * HZ;
+		}
 		if (cfg->p_encap != p->local.p_encap) {
-                        if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
-                                p->dev.hard_header         = NULL;
-                                p->dev.header_cache_bind   = NULL;
-                                p->dev.header_cache_update = NULL;
-                                p->dev.flags               = IFF_NOARP;
-                        } else {
-                                p->dev.hard_header = isdn_net_header;
-                                if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
-                                        p->dev.header_cache_bind   = p->local.org_hcb;
-                                        p->dev.header_cache_update = p->local.org_hcu;
-                                        p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
-                                } else {
-                                        p->dev.header_cache_bind   = NULL;
-                                        p->dev.header_cache_update = NULL;
-                                        p->dev.flags               = IFF_NOARP;
-                                }
-                        }
-                }
-		p->local.p_encap     = cfg->p_encap;
-                return 0;
+			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
+				p->dev.hard_header = NULL;
+#if (LINUX_VERSION_CODE < 0x02010F)
+				p->dev.header_cache_bind = NULL;
+#else
+				p->dev.hard_header_cache = NULL;
+#endif
+				p->dev.header_cache_update = NULL;
+				p->dev.flags = IFF_NOARP;
+			} else {
+				p->dev.hard_header = isdn_net_header;
+				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
+#if (LINUX_VERSION_CODE < 0x02010F)
+					p->dev.header_cache_bind = p->local.org_hcb;
+#else
+					p->dev.hard_header_cache = p->local.org_hhc;
+#endif
+					p->dev.header_cache_update = p->local.org_hcu;
+					p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
+				} else {
+#if (LINUX_VERSION_CODE < 0x02010F)
+					p->dev.header_cache_bind = NULL;
+#else
+					p->dev.hard_header_cache = NULL;
+#endif
+					p->dev.header_cache_update = NULL;
+					p->dev.flags = IFF_NOARP;
+				}
+			}
+		}
+		p->local.p_encap = cfg->p_encap;
+		return 0;
 	}
 	return -ENODEV;
 }
@@ -2162,7 +2295,8 @@
 /*
  * Perform get-interface-parameters.ioctl
  */
-int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
+int
+isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
 {
 	isdn_net_dev *p = isdn_net_findif(cfg->name);
 
@@ -2181,16 +2315,19 @@
 		cfg->p_encap = p->local.p_encap;
 		cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
 		cfg->callback = 0;
-                if (p->local.flags & ISDN_NET_CALLBACK)
-                        cfg->callback = 1;
-                if (p->local.flags & ISDN_NET_CBOUT)
-                        cfg->callback = 2;
+		if (p->local.flags & ISDN_NET_CALLBACK)
+			cfg->callback = 1;
+		if (p->local.flags & ISDN_NET_CBOUT)
+			cfg->callback = 2;
 		cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
 		cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
 		cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
-                cfg->cbdelay = p->local.cbdelay;
-                cfg->dialmax = p->local.dialmax;
+		cfg->cbdelay = p->local.cbdelay;
+		cfg->dialmax = p->local.dialmax;
+		cfg->triggercps = p->local.triggercps;
 		cfg->slavedelay = p->local.slavedelay / HZ;
+		cfg->chargeint = (p->local.hupflags & ISDN_CHARGEHUP) ?
+		    (p->local.chargeint / HZ) : 0;
 		cfg->pppbind = p->local.pppbind;
 		if (p->local.slave)
 			strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name);
@@ -2208,7 +2345,8 @@
 /*
  * Add a phone-number to an interface.
  */
-int isdn_net_addphone(isdn_net_ioctl_phone * phone)
+int
+isdn_net_addphone(isdn_net_ioctl_phone * phone)
 {
 	isdn_net_dev *p = isdn_net_findif(phone->name);
 	isdn_net_phone *n;
@@ -2229,7 +2367,8 @@
 /*
  * Return a string of all phone-numbers of an interface.
  */
-int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
+int
+isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
 {
 	isdn_net_dev *p = isdn_net_findif(phone->name);
 	int inout = phone->outgoing & 1;
@@ -2244,22 +2383,21 @@
 	save_flags(flags);
 	cli();
 	inout &= 1;
-        for (n = p->local.phone[inout]; n; n = n->next) {
+	for (n = p->local.phone[inout]; n; n = n->next) {
 		if (more) {
 			put_user(' ', phones++);
 			count++;
 		}
-		if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) {
+		if ((ret = copy_to_user(phones, n->num, strlen(n->num) + 1))) {
 			restore_flags(flags);
 			return ret;
 		}
-		copy_to_user(phones, n->num, strlen(n->num) + 1);
 		phones += strlen(n->num);
 		count += strlen(n->num);
 		more = 1;
 	}
-        put_user(0,phones);
-        count++;
+	put_user(0, phones);
+	count++;
 	restore_flags(flags);
 	return count;
 }
@@ -2268,18 +2406,24 @@
  * Delete a phone-number from an interface.
  */
 
-int isdn_net_delphone(isdn_net_ioctl_phone * phone)
+int
+isdn_net_delphone(isdn_net_ioctl_phone * phone)
 {
 	isdn_net_dev *p = isdn_net_findif(phone->name);
 	int inout = phone->outgoing & 1;
 	isdn_net_phone *n;
 	isdn_net_phone *m;
+	int flags;
 
 	if (p) {
+		save_flags(flags);
+		cli();
 		n = p->local.phone[inout];
 		m = NULL;
 		while (n) {
 			if (!strcmp(n->num, phone->phone)) {
+				if (p->local.dial == n)
+					p->local.dial = n->next;
 				if (m)
 					m->next = n->next;
 				else
@@ -2290,6 +2434,7 @@
 			m = n;
 			n = (isdn_net_phone *) n->next;
 		}
+		restore_flags(flags);
 		return -EINVAL;
 	}
 	return -ENODEV;
@@ -2298,7 +2443,8 @@
 /*
  * Delete all phone-numbers of an interface.
  */
-static int isdn_net_rmallphone(isdn_net_dev * p)
+static int
+isdn_net_rmallphone(isdn_net_dev * p)
 {
 	isdn_net_phone *n;
 	isdn_net_phone *m;
@@ -2316,6 +2462,7 @@
 		}
 		p->local.phone[i] = NULL;
 	}
+	p->local.dial = NULL;
 	restore_flags(flags);
 	return 0;
 }
@@ -2323,7 +2470,8 @@
 /*
  * Force a hangup of a network-interface.
  */
-int isdn_net_force_hangup(char *name)
+int
+isdn_net_force_hangup(char *name)
 {
 	isdn_net_dev *p = isdn_net_findif(name);
 	struct device *q;
@@ -2331,13 +2479,13 @@
 	if (p) {
 		if (p->local.isdn_device < 0)
 			return 1;
-		isdn_net_hangup(&p->dev);
 		q = p->local.slave;
 		/* If this interface has slaves, do a hangup for them also. */
 		while (q) {
 			isdn_net_hangup(q);
 			q = (((isdn_net_local *) q->priv)->slave);
 		}
+		isdn_net_hangup(&p->dev);
 		return 0;
 	}
 	return -ENODEV;
@@ -2346,7 +2494,8 @@
 /*
  * Helper-function for isdn_net_rm: Do the real work.
  */
-static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
+static int
+isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
 {
 	int flags;
 
@@ -2399,9 +2548,6 @@
 		isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
 	restore_flags(flags);
 
-#ifdef CONFIG_ISDN_MPP
-	isdn_ppp_free_mpqueue(p);	/* still necessary? */
-#endif
 	kfree(p);
 
 	return 0;
@@ -2410,7 +2556,8 @@
 /*
  * Remove a single network-interface.
  */
-int isdn_net_rm(char *name)
+int
+isdn_net_rm(char *name)
 {
 	isdn_net_dev *p;
 	isdn_net_dev *q;
@@ -2433,7 +2580,8 @@
 /*
  * Remove all network-interfaces
  */
-int isdn_net_rmall(void)
+int
+isdn_net_rmall(void)
 {
 	int flags;
 	int ret;
@@ -2446,7 +2594,7 @@
 			/* Remove master-devices only, slaves get removed with their master */
 			if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
 				restore_flags(flags);
-			        return ret;
+				return ret;
 			}
 		}
 	}
@@ -2455,17 +2603,18 @@
 	return 0;
 }
 
-/* 
+/*
  * helper function to flush device queues
  * the better place would be net/core/dev.c
  */
-void dev_purge_queues(struct device *dev)
+static void
+dev_purge_queues(struct device *dev)
 {
 	int i;
-	for(i=0;i<DEV_NUMBUFFS;i++) {
+	for (i = 0; i < DEV_NUMBUFFS; i++) {
 		struct sk_buff *skb;
-		while((skb=skb_dequeue(&dev->buffs[i])))
-				dev_kfree_skb(skb,FREE_WRITE);
-        }
-	
+		while ((skb = skb_dequeue(&dev->buffs[i])))
+			dev_kfree_skb(skb, FREE_WRITE);
+	}
+
 }
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_net.h linux-2.0.31-pre3/drivers/isdn/isdn_net.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_net.h	1996-04-21 01:56:14.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_net.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,11 +1,11 @@
-/* $Id: isdn_net.h,v 1.2 1996/04/20 16:29:43 fritz Exp $
- *
+/* $Id: isdn_net.h,v 1.5 1997/02/10 20:12:47 fritz Exp $
+
  * header for Linux ISDN subsystem, network related functions (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -18,9 +18,18 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.h,v $
+ * Revision 1.5  1997/02/10 20:12:47  fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.4  1997/02/03 23:16:48  fritz
+ * Removed isdn_net_receive_callback prototype.
+ *
+ * Revision 1.3  1997/01/17 01:19:30  fritz
+ * Applied chargeint patch.
+ *
  * Revision 1.2  1996/04/20 16:29:43  fritz
  * Misc. typos
  *
@@ -29,24 +38,30 @@
  *
  */
 
-extern char*         isdn_net_new(char *, struct device *);
-extern char*         isdn_net_newslave(char *);
-extern int           isdn_net_rm(char *);
-extern int           isdn_net_rmall(void);
-extern int           isdn_net_stat_callback(int, int);
-extern int           isdn_net_receive_callback(int, u_char *, int);
-extern int           isdn_net_setcfg(isdn_net_ioctl_cfg *);
-extern int           isdn_net_getcfg(isdn_net_ioctl_cfg *);
-extern int           isdn_net_addphone(isdn_net_ioctl_phone *);
-extern int           isdn_net_getphones(isdn_net_ioctl_phone *, char *);
-extern int           isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int           isdn_net_find_icall(int, int, int, char *);
-extern void          isdn_net_hangup(struct device *);
-extern void          isdn_net_dial(void);
-extern void          isdn_net_autohup(void);
-extern int           isdn_net_force_hangup(char *);
-extern int           isdn_net_force_dial(char *);
-extern isdn_net_dev* isdn_net_findif(char *);
-extern int           isdn_net_send_skb(struct device *, isdn_net_local *, 
-				      struct sk_buff *);
-extern int           isdn_net_rcv_skb(int, struct sk_buff *); 
+			      /* Definitions for hupflags:                */
+#define ISDN_WAITCHARGE  1      /* did not get a charge info yet            */
+#define ISDN_HAVECHARGE  2      /* We know a charge info                    */
+#define ISDN_CHARGEHUP   4      /* We want to use the charge mechanism      */
+#define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
+#define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
+
+extern char *isdn_net_new(char *, struct device *);
+extern char *isdn_net_newslave(char *);
+extern int isdn_net_rm(char *);
+extern int isdn_net_rmall(void);
+extern int isdn_net_stat_callback(int, int);
+extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_addphone(isdn_net_ioctl_phone *);
+extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
+extern int isdn_net_delphone(isdn_net_ioctl_phone *);
+extern int isdn_net_find_icall(int, int, int, setup_parm);
+extern void isdn_net_hangup(struct device *);
+extern void isdn_net_dial(void);
+extern void isdn_net_autohup(void);
+extern int isdn_net_force_hangup(char *);
+extern int isdn_net_force_dial(char *);
+extern isdn_net_dev *isdn_net_findif(char *);
+extern int isdn_net_send_skb(struct device *, isdn_net_local *,
+			     struct sk_buff *);
+extern int isdn_net_rcv_skb(int, struct sk_buff *);
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_ppp.c linux-2.0.31-pre3/drivers/isdn/isdn_ppp.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_ppp.c	1996-11-12 22:36:19.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_ppp.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-/* $Id: isdn_ppp.c,v 1.20 1996/10/30 12:21:58 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.28 1997/06/17 13:05:57 hipp Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -16,9 +16,42 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.28  1997/06/17 13:05:57  hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
+ * Revision 1.27  1997/03/30 16:51:17  calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.26  1997/02/23 16:53:44  hipp
+ * minor cleanup
+ * some initial changes for future PPP compresion
+ * added AC,PC compression for outgoing frames
+ *
+ * Revision 1.25  1997/02/12 20:37:35  hipp
+ * New ioctl() PPPIOCGCALLINFO, minor cleanup
+ *
+ * Revision 1.24  1997/02/11 18:32:56  fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.23  1997/02/10 11:12:19  fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.22  1997/02/06 15:03:51  hipp
+ * changed GFP_KERNEL kmalloc to GFP_ATOMIC in isdn_ppp_fill_mpqueue()
+ *
+ * Revision 1.21  1997/02/03 23:29:38  fritz
+ * Reformatted according CodingStyle
+ * Bugfix: removed isdn_ppp_skb_destructor, used by upper layers.
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
  * Revision 1.20  1996/10/30 12:21:58  fritz
  * Cosmetic fix: Compiler warning when compiling without MPP.
  *
@@ -92,70 +125,91 @@
 
 /* TODO: right tbusy handling when using MP */
 
+/*
+ * experimental for dynamic addressing: readdress IP frames
+ */
 #undef ISDN_SYNCPPP_READDRESS
 
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
+#endif
 #include "isdn_common.h"
 #include "isdn_ppp.h"
 #include "isdn_net.h"
 
 #ifndef PPP_IPX
-#define PPP_IPX 0x002b 
+#define PPP_IPX 0x002b
 #endif
 
 /* set this if you use dynamic addressing */
- 
+
 /* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot);
+static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
 static int isdn_ppp_closewait(int slot);
 static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
-			struct sk_buff *skb, int proto);
+				 struct sk_buff *skb, int proto);
 static int isdn_ppp_if_get_unit(char *namebuf);
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+				struct ippp_struct *,struct ippp_struct *);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+				struct sk_buff *skb);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type);
 
 #ifdef CONFIG_ISDN_MPP
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
 static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min);
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev,isdn_net_local *, long min);
+static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min);
+static void isdn_ppp_free_sqqueue(isdn_net_dev *);
 static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
-		int BEbyte, long *sqno, int min_sqno);
+				 int BEbyte, long *sqno, int min_sqno);
+static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision              = "$Revision: 1.20 $";
+char *isdn_ppp_revision = "$Revision: 1.28 $";
 
-struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct isdn_ppp_compressor *ipc_head = NULL;
 
 extern int isdn_net_force_dial_lp(isdn_net_local *);
 
 /*
  * frame log (debug)
  */
-static void isdn_ppp_frame_log(char *info,char *data,int len,int maxlen)
+static void
+isdn_ppp_frame_log(char *info, char *data, int len, int maxlen)
 {
-	int cnt,j,i;
+	int cnt,
+	 j,
+	 i;
 	char buf[80];
 
-	if(len < maxlen)
+	if (len < maxlen)
 		maxlen = len;
-	
-	for(i=0,cnt=0;cnt<maxlen;i++) {
-		for(j=0;j<16 && cnt<maxlen;j++,cnt++)
-			sprintf(buf+j*3,"%02x ",(unsigned char) data[cnt]);
-		printk(KERN_DEBUG "%s[%d]: %s\n",info,i,buf);
+
+	for (i = 0, cnt = 0; cnt < maxlen; i++) {
+		for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
+			sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
+		printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf);
 	}
 }
 
 /*
- * unbind isdn_net_local <=> ippp-device 
+ * unbind isdn_net_local <=> ippp-device
  * note: it can happen, that we hangup/free the master before the slaves
  */
-int isdn_ppp_free(isdn_net_local *lp)
+int
+isdn_ppp_free(isdn_net_local * lp)
 {
 #ifdef CONFIG_ISDN_MPP
-	isdn_net_local *master_lp=lp;
+	isdn_net_local *master_lp = lp;
 #endif
 	unsigned long flags;
 	struct ippp_struct *is;
@@ -168,14 +222,14 @@
 	save_flags(flags);
 	cli();
 #ifdef CONFIG_ISDN_MPP
-	if(lp->master)
+	if (lp->master)
 		master_lp = (isdn_net_local *) lp->master->priv;
 
 	lp->last->next = lp->next;
 	lp->next->last = lp->last;
-	if(master_lp->netdev->queue == lp) {
+	if (master_lp->netdev->queue == lp) {
 		master_lp->netdev->queue = lp->next;
-		if(lp->next == lp) {	/* last link in queue? */
+		if (lp->next == lp) {	/* last link in queue? */
 			master_lp->netdev->ib.bundled = 0;
 			isdn_ppp_free_mpqueue(master_lp->netdev);
 			isdn_ppp_free_sqqueue(master_lp->netdev);
@@ -184,21 +238,21 @@
 	lp->next = lp->last = lp;	/* (re)set own pointers */
 #endif
 
-	if( (is->state & IPPP_CONNECT) )
+	if ((is->state & IPPP_CONNECT))
 		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
-	else if(is->state & IPPP_ASSIGNED)
+	else if (is->state & IPPP_ASSIGNED)
 		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGEND' staet */
-		
 
-	if(is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp);
 
-	is->lp = NULL;	/* link is down .. set lp to NULL */
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
+
+	is->lp = NULL;          /* link is down .. set lp to NULL */
 #ifdef ISDN_SYNCPPP_READDRESS
 	is->old_pa_addr = 0x0;
 	is->old_pa_dstaddr = 0x0;
 #endif
-	lp->ppp_slot = -1;			/* is this OK ?? */
+	lp->ppp_slot = -1;      /* is this OK ?? */
 	restore_flags(flags);
 
 	return 0;
@@ -207,7 +261,8 @@
 /*
  * bind isdn_net_local <=> ippp-device
  */
-int isdn_ppp_bind(isdn_net_local * lp)
+int
+isdn_ppp_bind(isdn_net_local * lp)
 {
 	int i;
 	int unit = 0;
@@ -220,14 +275,13 @@
 	save_flags(flags);
 	cli();
 
-	if(lp->pppbind < 0)	/* device bounded to ippp device ? */
-	{
- 		isdn_net_dev *net_dev = dev->netdev;
+	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */
+		isdn_net_dev *net_dev = dev->netdev;
 		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
-		memset(exclusive,0,ISDN_MAX_CHANNELS);
+		memset(exclusive, 0, ISDN_MAX_CHANNELS);
 		while (net_dev) {	/* step through net devices to find exclusive minors */
 			isdn_net_local *lp = &net_dev->local;
-			if(lp->pppbind >= 0)
+			if (lp->pppbind >= 0)
 				exclusive[lp->pppbind] = 1;
 			net_dev = net_dev->next;
 		}
@@ -235,14 +289,13 @@
 		 * search a free device / slot
 		 */
 		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
+			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) {	/* OPEN, but not connected! */
 				break;
 			}
 		}
-	}
-	else {
-		for(i=0;i<ISDN_MAX_CHANNELS;i++)
-			if(ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
+	} else {
+		for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+			if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
 				break;
 	}
 
@@ -251,13 +304,11 @@
 		printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n");
 		return -1;
 	}
-
-	unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
-	if(unit < 0) {
-		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",lp->name);
+	unit = isdn_ppp_if_get_unit(lp->name);	/* get unit number from interface name .. ugly! */
+	if (unit < 0) {
+		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
 		return -1;
 	}
-
 	lp->ppp_slot = i;
 	is = ippp_table[i];
 	is->lp = lp;
@@ -274,9 +325,10 @@
  * (wakes up daemon after B-channel connect)
  */
 
-void isdn_ppp_wakeup_daemon(isdn_net_local *lp)
+void
+isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 {
-	if(lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
 		return;
 
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
@@ -287,10 +339,11 @@
 
 /*
  * there was a hangup on the netdevice
- * force wakeup of the ippp device 
+ * force wakeup of the ippp device
  * go into 'device waits for release' state
  */
-static int isdn_ppp_closewait(int slot)
+static int
+isdn_ppp_closewait(int slot)
 {
 	struct ippp_struct *is;
 
@@ -309,56 +362,64 @@
  * isdn_ppp_find_slot / isdn_ppp_free_slot
  */
 
-static int isdn_ppp_get_slot(void)
+static int
+isdn_ppp_get_slot(void)
 {
 	int i;
-	for(i=0;i<ISDN_MAX_CHANNELS;i++) {
-		if(!ippp_table[i]->state)
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+		if (!ippp_table[i]->state)
 			return i;
 	}
 	return -1;
 }
 
 /*
- * isdn_ppp_open 
+ * isdn_ppp_open
  */
 
-int isdn_ppp_open(int min, struct file *file)
+int
+isdn_ppp_open(int min, struct file *file)
 {
 	int slot;
 	struct ippp_struct *is;
 
-	if(min < 0 || min > ISDN_MAX_CHANNELS)
+	if (min < 0 || min > ISDN_MAX_CHANNELS)
 		return -ENODEV;
 
 	slot = isdn_ppp_get_slot();
-	if(slot < 0) {
+	if (slot < 0) {
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
 
-	if(is->debug & 0x1)
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",slot, min,is->state);
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
 
-	is->lp = 0;
-	is->mp_seqno = 0;  /* MP sequence number */
-	is->pppcfg = 0;    /* ppp configuration */
-	is->mpppcfg = 0;   /* mppp configuration */
-	is->range = 0x1000000;	/* MP: 24 bit range */
+	/* compression stuff */
+	is->compressor = NULL;
+	is->decomp_stat = is->comp_stat = NULL;
+	is->link_compressor = NULL;
+	is->link_decomp_stat = is->link_comp_stat = NULL;
+
+	is->lp = NULL;
+	is->mp_seqno = 0;       /* MP sequence number */
+	is->pppcfg = 0;         /* ppp configuration */
+	is->mpppcfg = 0;        /* mppp configuration */
+	is->range = 0x1000000;  /* MP: 24 bit range */
 	is->last_link_seqno = -1;	/* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
-	is->unit = -1;	/* set, when we have our interface */
-	is->mru = 1524;	/* MRU, default 1524 */
-	is->maxcid = 16;	/* VJ: maxcid */
+	is->unit = -1;          /* set, when we have our interface */
+	is->mru = 1524;         /* MRU, default 1524 */
+	is->maxcid = 16;        /* VJ: maxcid */
 	is->tk = current;
-	is->wq = NULL;    /* read() wait queue */
-	is->wq1 = NULL;   /* select() wait queue */
-	is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+	is->wq = NULL;          /* read() wait queue */
+	is->wq1 = NULL;         /* select() wait queue */
+	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
 	is->minor = min;
 #ifdef CONFIG_ISDN_PPP_VJ
-        /*
-         * VJ header compression init
-         */
+	/*
+	 * VJ header compression init
+	 */
 	is->slcomp = slhc_init(16, 16);	/* not necessary for 2. link in bundle */
 #endif
 
@@ -370,7 +431,8 @@
 /*
  * release ippp device
  */
-void isdn_ppp_release(int min, struct file *file)
+void
+isdn_ppp_release(int min, struct file *file)
 {
 	int i;
 	struct ippp_struct *is;
@@ -379,14 +441,14 @@
 		return;
 	is = file->private_data;
 
-	if(is->debug & 0x1)
+	if (is->debug & 0x1)
 		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
 
-	if (is->lp) {	/* a lp address says: this link is still up */
+	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
-		
-		is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
-		/* 
+
+		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
+		/*
 		 * isdn_net_hangup() calls isdn_ppp_free()
 		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
 		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
@@ -399,8 +461,8 @@
 			is->rq[i].buf = NULL;
 		}
 	}
-        is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
-        is->last = is->rq;
+	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
+	is->last = is->rq;
 
 #ifdef CONFIG_ISDN_PPP_VJ
 	slhc_free(is->slcomp);
@@ -413,216 +475,286 @@
 /*
  * get_arg .. ioctl helper
  */
-static int get_arg(void *b,void *val,int len)
+static int
+get_arg(void *b, void *val, int len)
 {
 	int r;
-	if(len <= 0)
-		len = sizeof(unsigned long); 
-	if ((r = verify_area(VERIFY_READ, (void *) b, len )))
-		 return r;
-	copy_from_user((void *) val, b, len );
+	if (len <= 0)
+		len = sizeof(unsigned long);
+	if ((r = copy_from_user((void *) val, b, len)))
+		return r;
 	return 0;
 }
 
 /*
  * set arg .. ioctl helper
  */
-static int set_arg(void *b, unsigned long val,void *str)
+static int
+set_arg(void *b, unsigned long val, void *str)
 {
 	int r;
-	if(!str) {
-		if ((r = verify_area(VERIFY_WRITE, b, 4 )))
-			 return r;
-		copy_to_user(b, (void *) &val, 4 );
-	}
-	else {
-		if ((r = verify_area(VERIFY_WRITE, b,val)))
+	if (!str) {
+		if ((r = copy_to_user(b, (void *) &val, 4)))
+			return r;
+	} else {
+		if ((r = copy_to_user(b, str, val)))
 			return r;
-		copy_to_user(b,str,val);
 	}
 	return 0;
 }
 
 /*
- * ippp device ioctl 
+ * ippp device ioctl
  */
-int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+int
+isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long val;
-	int r;
+	int num,r;
 	struct ippp_struct *is;
+	isdn_net_local *lp;
 
-	is = file->private_data;
+	is = (struct ippp_struct *) file->private_data;
+	lp = is->lp;
 
-	if(is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",min,cmd,is->state);
+	if (is->debug & 0x1)
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
 
 	if (!(is->state & IPPP_OPEN))
 		return -EINVAL;
 
 	switch (cmd) {
-	case PPPIOCBUNDLE:
+		case PPPIOCBUNDLE:
 #ifdef CONFIG_ISDN_MPP
-		if( !(is->state & IPPP_CONNECT) )
-			return -EINVAL;
-		if ((r = get_arg((void *) arg, &val,0)))
-			return r;
-		printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
-                        (int) min, (int) is->unit, (int) val);
-		return isdn_ppp_bundle(is, val);
+			if (!(is->state & IPPP_CONNECT))
+				return -EINVAL;
+			if ((r = get_arg((void *) arg, &val, 0)))
+				return r;
+			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
+			       (int) min, (int) is->unit, (int) val);
+			return isdn_ppp_bundle(is, val);
 #else
-		return -1;
+			return -1;
 #endif
-		break;
-	case PPPIOCGUNIT:	/* get ppp/isdn unit number */
-		if ((r = set_arg((void *) arg, is->unit,NULL)))
-			return r;
-		break;
-	case PPPIOCGMPFLAGS:	/* get configuration flags */
-		if ((r = set_arg((void *) arg, is->mpppcfg,NULL)))
-			return r;
-		break;
-	case PPPIOCSMPFLAGS:	/* set configuration flags */
-		if ((r = get_arg((void *) arg, &val,0)))
-			return r;
-		is->mpppcfg = val;
-		break;
-	case PPPIOCGFLAGS:	/* get configuration flags */
-		if ((r = set_arg((void *) arg, is->pppcfg,NULL)))
-			return r;
-		break;
-	case PPPIOCSFLAGS:	/* set configuration flags */
-		if ((r = get_arg((void *) arg, &val,0))) {
-			return r;
-		}
-		if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT) ) {
-			isdn_net_local *lp = is->lp;
-			if(lp) {
-				lp->netdev->dev.tbusy = 0;
-				mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+			break;
+		case PPPIOCGUNIT:	/* get ppp/isdn unit number */
+			if ((r = set_arg((void *) arg, is->unit, NULL)))
+				return r;
+			break;
+		case PPPIOCGMPFLAGS:	/* get configuration flags */
+			if ((r = set_arg((void *) arg, is->mpppcfg, NULL)))
+				return r;
+			break;
+		case PPPIOCSMPFLAGS:	/* set configuration flags */
+			if ((r = get_arg((void *) arg, &val, 0)))
+				return r;
+			is->mpppcfg = val;
+			break;
+		case PPPIOCGFLAGS:	/* get configuration flags */
+			if ((r = set_arg((void *) arg, is->pppcfg, NULL)))
+				return r;
+			break;
+		case PPPIOCSFLAGS:	/* set configuration flags */
+			if ((r = get_arg((void *) arg, &val, 0))) {
+				return r;
 			}
-		}
-		is->pppcfg = val;
-		break;
+			if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
+				if (lp) {
+					lp->netdev->dev.tbusy = 0;
+					mark_bh(NET_BH);	/* OK .. we are ready to send buffers */
+				}
+			}
+			is->pppcfg = val;
+			break;
 #if 0
-	case PPPIOCGSTAT:	/* read PPP statistic information */
-		break;
+		case PPPIOCGSTAT:	/* read PPP statistic information */
+			break;
 #endif
-	case PPPIOCGIDLE:	/* get idle time information */
-		if(is->lp)
-		{
-			struct ppp_idle pidle;
-			pidle.xmit_idle = pidle.recv_idle = is->lp->huptimer;
-			if((r = set_arg((void *) arg,sizeof(struct ppp_idle),&pidle)))
-				return r;	
-		}
-		break;
-	case PPPIOCSMRU:	/* set receive unit size for PPP */
-		if ((r = get_arg((void *) arg, &val,0)))
-			return r;
-		is->mru = val;
-		break;
-	case PPPIOCSMPMRU:
-		break;
-	case PPPIOCSMPMTU:
-		break;
-	case PPPIOCSMAXCID:	/* set the maximum compression slot id */
-		if ((r = get_arg((void *) arg, &val,0)))
-			return r;
-		val++;
-		if(is->maxcid != val) {
+		case PPPIOCGIDLE:	/* get idle time information */
+			if (lp) {
+				struct ppp_idle pidle;
+				pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
+				if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle)))
+					 return r;
+			}
+			break;
+		case PPPIOCSMRU:	/* set receive unit size for PPP */
+			if ((r = get_arg((void *) arg, &val, 0)))
+				return r;
+			is->mru = val;
+			break;
+		case PPPIOCSMPMRU:
+			break;
+		case PPPIOCSMPMTU:
+			break;
+		case PPPIOCSMAXCID:	/* set the maximum compression slot id */
+			if ((r = get_arg((void *) arg, &val, 0)))
+				return r;
+			val++;
+			if (is->maxcid != val) {
 #ifdef CONFIG_ISDN_PPP_VJ
-			struct slcompress *sltmp;
+				struct slcompress *sltmp;
 #endif
-			if(is->debug & 0x1)
-				printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val);
-			is->maxcid = val;
+				if (is->debug & 0x1)
+					printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
+				is->maxcid = val;
 #ifdef CONFIG_ISDN_PPP_VJ
-			sltmp = slhc_init(16,val);
-			if(!sltmp) {
-				printk(KERN_ERR "ippp, can't realloc slhc struct\n");
-				return -ENOMEM;
-			}	
-			if(is->slcomp)
-				slhc_free(is->slcomp);
-			is->slcomp = sltmp;
+				sltmp = slhc_init(16, val);
+				if (!sltmp) {
+					printk(KERN_ERR "ippp, can't realloc slhc struct\n");
+					return -ENOMEM;
+				}
+				if (is->slcomp)
+					slhc_free(is->slcomp);
+				is->slcomp = sltmp;
 #endif
-		}
-		break;
-	case PPPIOCGDEBUG:
-		if ((r = set_arg((void *) arg, is->debug,0)))
-			return r;
-		break;
-	case PPPIOCSDEBUG:
-		if ((r = get_arg((void *) arg, &val,0)))
-			return r;
-		is->debug = val;
-		break;
-	case PPPIOCSCOMPRESS:
-#if 0
-		{
-			struct ppp_option_data pod;
-			r = get_arg((void *) arg,&pod,sizeof(struct ppp_option_data));
-			if(r)
+			}
+			break;
+		case PPPIOCGDEBUG:
+			if ((r = set_arg((void *) arg, is->debug, 0)))
 				return r;
-			ippp_set_compression(is,&pod);
-		}
-#endif
-		break;
-	default:
-		break;
+			break;
+		case PPPIOCSDEBUG:
+			if ((r = get_arg((void *) arg, &val, 0)))
+				return r;
+			is->debug = val;
+			break;
+		case PPPIOCGCOMPRESSORS:
+			{
+				unsigned long protos = 0;
+				struct isdn_ppp_compressor *ipc = ipc_head;
+				while(ipc) {
+					protos |= (0x1<<ipc->num);
+					ipc = ipc->next;
+				}
+				if ((r = set_arg((void *) arg, protos, 0)))
+					return r;
+			}
+			break;
+		case PPPIOCSCOMPRESSOR:
+			if ((r = get_arg((void *) arg, &num, sizeof(int))))
+				return r;
+			return isdn_ppp_set_compressor(is, num);
+			break;
+		case PPPIOCGCALLINFO:
+			{
+				struct pppcallinfo pci;
+				memset((char *) &pci,0,sizeof(struct pppcallinfo));
+				if(lp)
+				{
+					strncpy(pci.local_num,lp->msn,63);
+					if(lp->dial) {
+						strncpy(pci.remote_num,lp->dial->num,63);
+					}
+					pci.charge_units = lp->charge;
+					if(lp->outgoing)
+						pci.calltype = CALLTYPE_OUTGOING;
+					else
+						pci.calltype = CALLTYPE_INCOMING;
+					if(lp->flags & ISDN_NET_CALLBACK)
+						pci.calltype |= CALLTYPE_CALLBACK;
+				}
+				return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci);
+			}
+		default:
+			break;
 	}
 	return 0;
 }
 
-int isdn_ppp_select(int min, struct file *file, int type, select_table * st)
+#if (LINUX_VERSION_CODE < 0x020117)
+int
+isdn_ppp_select(int min, struct file *file, int type, select_table * st)
 {
-	struct ippp_buf_queue *bf, *bl;
+	struct ippp_buf_queue *bf,
+	*bl;
 	unsigned long flags;
 	struct ippp_struct *is;
 
 	is = file->private_data;
 
-	if(is->debug & 0x2)
-		printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",min,type);
+	if (is->debug & 0x2)
+		printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type);
 
 	if (!(is->state & IPPP_OPEN))
 		return -EINVAL;
 
 	switch (type) {
-	case SEL_IN:
-		save_flags(flags);
-		cli();
-		bl = is->last;
-		bf = is->first;
-		/* 
-		 * if IPPP_NOBLOCK is set we return even if we have nothing to read 
-		 */
-		if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
-			select_wait(&is->wq, st);
+		case SEL_IN:
+			save_flags(flags);
+			cli();
+			bl = is->last;
+			bf = is->first;
+			/*
+			 * if IPPP_NOBLOCK is set we return even if we have nothing to read
+			 */
+			if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
+				select_wait(&is->wq, st);
+				restore_flags(flags);
+				return 0;
+			}
+			is->state &= ~IPPP_NOBLOCK;
 			restore_flags(flags);
+			return 1;
+		case SEL_OUT:
+			/* we're always ready to send .. */
+			return 1;
+		case SEL_EX:
+			select_wait(&is->wq1, st);
 			return 0;
-		}
-		is->state &= ~IPPP_NOBLOCK;
-		restore_flags(flags);
-		return 1;
-	case SEL_OUT:
-                /* we're always ready to send .. */
-		return 1;
-	case SEL_EX:
-		select_wait(&is->wq1, st);
-		return 0;
 	}
 	return 1;
 }
+#else
+unsigned int
+isdn_ppp_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask;
+	struct ippp_buf_queue *bf;
+	struct ippp_buf_queue *bl;
+	unsigned long flags;
+	struct ippp_struct *is;
+
+	is = file->private_data;
+
+	if (is->debug & 0x2)
+		printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_inode->i_rdev));
+
+	poll_wait(&is->wq, wait);
+
+	if (!(is->state & IPPP_OPEN)) {
+		printk(KERN_DEBUG "isdn_ppp: device not open\n");
+		return POLLERR;
+	}
+	/* we're always ready to send .. */
+	mask = POLLOUT | POLLWRNORM;
+
+	save_flags(flags);
+	cli();
+	bl = is->last;
+	bf = is->first;
+	/*
+	 * if IPPP_NOBLOCK is set we return even if we have nothing to read
+	 */
+	if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
+		is->state &= ~IPPP_NOBLOCK;
+		mask |= POLLIN | POLLRDNORM;
+	}
+	restore_flags(flags);
+	return mask;
+}
+#endif
+
 
 /*
  *  fill up isdn_ppp_read() queue ..
  */
 
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
+static int
+isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
 {
-	struct ippp_buf_queue *bf, *bl;
+	struct ippp_buf_queue *bf,
+	*bl;
 	unsigned long flags;
 	unsigned char *nbuf;
 	struct ippp_struct *is;
@@ -637,9 +769,8 @@
 		printk(KERN_DEBUG "ippp: device not activated.\n");
 		return 0;
 	}
-
-	nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC);
-	if(!nbuf) {
+	nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
+	if (!nbuf) {
 		printk(KERN_WARNING "ippp: Can't alloc buf\n");
 		return 0;
 	}
@@ -647,7 +778,7 @@
 	nbuf[1] = PPP_UI;
 	nbuf[2] = proto >> 8;
 	nbuf[3] = proto & 0xff;
-	memcpy(nbuf+4, buf, len);
+	memcpy(nbuf + 4, buf, len);
 
 	save_flags(flags);
 	cli();
@@ -662,7 +793,7 @@
 		is->first = bf;
 	}
 	bl->buf = (char *) nbuf;
-	bl->len = len+4;
+	bl->len = len + 4;
 
 	is->last = bl->next;
 	restore_flags(flags);
@@ -678,12 +809,14 @@
  *           reports, that there is data
  */
 
-int isdn_ppp_read(int min, struct file *file, char *buf, int count)
+int
+isdn_ppp_read(int min, struct file *file, char *buf, int count)
 {
 	struct ippp_struct *is;
 	struct ippp_buf_queue *b;
 	int r;
 	unsigned long flags;
+	unsigned char *save_buf;
 
 	is = file->private_data;
 
@@ -697,26 +830,30 @@
 	cli();
 
 	b = is->first->next;
-	if (!b->buf) {
+	save_buf = b->buf;
+	if (!save_buf) {
 		restore_flags(flags);
 		return -EAGAIN;
 	}
 	if (b->len < count)
 		count = b->len;
-	copy_to_user(buf, b->buf, count);
-	kfree(b->buf);
 	b->buf = NULL;
 	is->first = b;
+
 	restore_flags(flags);
 
+	copy_to_user(buf, save_buf, count);
+	kfree(save_buf);
+
 	return count;
 }
 
 /*
  * ipppd wanna write a packet to the card .. non-blocking
  */
- 
-int isdn_ppp_write(int min, struct file *file,  const char *buf, int count)
+
+int
+isdn_ppp_write(int min, struct file *file, const char *buf, int count)
 {
 	isdn_net_local *lp;
 	struct ippp_struct *is;
@@ -735,15 +872,16 @@
 	if (!lp)
 		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
 	else {
-                /*
-                 * Don't reset huptimer for
-                 * LCP packets. (Echo requests).
-                 */
-                copy_from_user(protobuf, buf, 4);
-                proto = PPP_PROTOCOL(protobuf);
-                if (proto != PPP_LCP)
+		/*
+		 * Don't reset huptimer for
+		 * LCP packets. (Echo requests).
+		 */
+		if (copy_from_user(protobuf, buf, 4))
+			return -EFAULT;
+		proto = PPP_PROTOCOL(protobuf);
+		if (proto != PPP_LCP)
 			lp->huptimer = 0;
-		
+
 		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
 			return 0;
 
@@ -752,23 +890,23 @@
 			int cnt;
 			struct sk_buff *skb;
 			skb = dev_alloc_skb(count);
-			if(!skb) {
+			if (!skb) {
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
 				return count;
 			}
-			skb->free = 1;
-			copy_from_user(skb_put(skb, count), buf, count);
-			if(is->debug & 0x40) {
-				printk(KERN_DEBUG "ppp xmit: len %ld\n",skb->len);
-				isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
-			}
-			if( (cnt=isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb)) != count) {
-				if(lp->sav_skb) {
-					dev_kfree_skb(lp->sav_skb,FREE_WRITE);
-					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",cnt,count);
-				}
-				else
-					printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",cnt,count);
+			SET_SKB_FREE(skb);
+			if (copy_from_user(skb_put(skb, count), buf, count))
+				return -EFAULT;
+			if (is->debug & 0x40) {
+				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
+				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+			}
+			if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+				if (lp->sav_skb) {
+					dev_kfree_skb(lp->sav_skb, FREE_WRITE);
+					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
+				} else
+					printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
 				lp->sav_skb = skb;
 			}
 		}
@@ -777,21 +915,23 @@
 }
 
 /*
- * init memory, structures etc. 
+ * init memory, structures etc.
  */
 
-int isdn_ppp_init(void)
+int
+isdn_ppp_init(void)
 {
-	int i, j;
+	int i,
+	 j;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-	        if (!(ippp_table[i] = (struct ippp_struct *)
-	                kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
-		        printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
+		if (!(ippp_table[i] = (struct ippp_struct *)
+		      kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+			printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
 			for (j = 0; j < i; j++)
 				kfree(ippp_table[i]);
-		        return -1;
-	        }
+			return -1;
+		}
 		memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
 		ippp_table[i]->state = 0;
 		ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
@@ -807,78 +947,109 @@
 	return 0;
 }
 
-void isdn_ppp_cleanup(void)
+void
+isdn_ppp_cleanup(void)
 {
-        int i;
+	int i;
 
-        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-                kfree(ippp_table[i]);
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		kfree(ippp_table[i]);
 }
 
 /*
+ * get the PPP protocol header and pull skb
+ */
+static int isdn_ppp_strip_proto(struct sk_buff *skb) 
+{
+	int proto;
+	if (skb->data[0] & 0x1) {
+		proto = skb->data[0];
+		skb_pull(skb, 1);   /* protocol ID is only 8 bit */
+	} else {
+		proto = ((int) skb->data[0] << 8) + skb->data[1];
+		skb_pull(skb, 2);
+	}
+	return proto;
+}
+
+
+/*
  * handler for incoming packets on a syncPPP interface
  */
 void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
 {
 	struct ippp_struct *is;
+	int proto;
+
 	is = ippp_table[lp->ppp_slot];
 
-	if(is->debug & 0x4) {
-		printk(KERN_DEBUG "ippp_receive: len: %ld\n",skb->len);
-		isdn_ppp_frame_log("receive",skb->data,skb->len,32);
+	if (is->debug & 0x4) {
+		printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
+		isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
 	}
-
-	if(net_dev->local.master) {
+	if (net_dev->local.master) {
 		printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
-		net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev;
+		net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev;
 	}
-
-	if(skb->data[0] == 0xff && skb->data[1] == 0x03)
-		skb_pull(skb,2);
+	if (skb->data[0] == 0xff && skb->data[1] == 0x03)
+		skb_pull(skb, 2);
 	else if (is->pppcfg & SC_REJ_COMP_AC) {
-		skb->free = 1;
-		dev_kfree_skb(skb,0 /* FREE_READ */ );
-		return;		/* discard it silently */
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, 0 /* FREE_READ */ );
+		return;         /* discard it silently */
 	}
 
+	proto = isdn_ppp_strip_proto(skb);
+
 #ifdef CONFIG_ISDN_MPP
 	if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
-		int proto;
 		int sqno_end;
-		if (skb->data[0] & 0x1) {
-			proto = skb->data[0];
-			skb_pull(skb,1);	/* protocol ID is only 8 bit */
-		} else {
-			proto = ((int) skb->data[0] << 8) + skb->data[1];
-			skb_pull(skb,2);
+		
+		if(proto == PPP_LINK_COMP) {
+			printk(KERN_DEBUG "received single link compressed frame\n");
+			skb = isdn_ppp_decompress(skb,is,NULL);
+			if(!skb)
+				return;
+			proto = isdn_ppp_strip_proto(skb);
 		}
+
 		if (proto == PPP_MP) {
 			isdn_net_local *lpq;
 			long sqno, min_sqno, tseq;
+
 			u_char BEbyte = skb->data[0];
-			if(is->debug & 0x8)
-	 			printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto ,
-					(int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], 
-					(int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
+			if (is->debug & 0x8)
+				printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
+				       (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
+				       (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
 			if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) {
 				sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
-				skb_pull(skb,4);
+				skb_pull(skb, 4);
 			} else {
 				sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1];
-				skb_pull(skb,2);
+				skb_pull(skb, 2);
 			}
 
+			/*
+			 * new sequence number lower than last number? (this is only allowed
+			 * for overflow case)
+			 */
 			if ((tseq = is->last_link_seqno) >= sqno) {
 				int range = is->range;
-				if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
+				if (tseq + 1024 < range + sqno)	/* redundancy check .. not MP conform */
 					printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq);
 				else {
 					sqno += range;
 					is->last_link_seqno = sqno;
 				}
-			} else
+			} else {
+				/* here, we should also add an redundancy check */
 				is->last_link_seqno = sqno;
+			}
 
+			/* 
+			 * step over all links to find lowest link number
+			 */
 			for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
 				long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
 				if (lls >= 0 && lls < min_sqno)
@@ -887,11 +1058,14 @@
 				if (lpq == net_dev->queue)
 					break;
 			}
-			if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {	/* OK, every link overflowed */
-				int mask = ippp_table[lpq->ppp_slot]->range - 1;	/* range is a power of 2 */
-#if 0
-				isdn_ppp_cleanup_queue(net_dev, min_sqno);
-#endif
+
+			/*
+			 * for the case, that the last frame numbers of all 
+			 * links are overflowed: mask/reduce the sequenece number to
+			 * 'normal' numbering.
+			 */
+			if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
+				int mask = ippp_table[lpq->ppp_slot]->range-1;	/* range is power of two, so a mask will do the job */
 				isdn_ppp_mask_queue(net_dev, mask);
 				net_dev->ib.next_num &= mask;
 				{
@@ -910,18 +1084,22 @@
 				}
 			}
 			if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
-				printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
-				if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) {
+				static int dmes = 0;
+				if( !dmes ) {
+					printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
+					dmes = 1;
+				}
+				if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) {
 					net_dev->ib.modify = 1;	/* block timeout-timer */
-					isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno); 
+					isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
 					net_dev->ib.modify = 0;
-					return;		/* no packet complete */
+					return;	/* no packet complete */
 				}
 			} else
 				sqno_end = sqno;
 
-			if(is->debug & 0x40)
-				printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n",min_sqno,sqno_end,net_dev->ib.next_num );
+			if (is->debug & 0x40)
+				printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num);
 
 			/*
 			 * MP buffer management .. reorders incoming packets ..
@@ -930,7 +1108,7 @@
 			 * first check whether there is more than one link in the bundle
 			 * then check whether the number is in order
 			 */
-			net_dev->ib.modify = 1;		/* block timeout-timer */
+			net_dev->ib.modify = 1;	/* block timeout-timer */
 			if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) {
 				/*
 				 * packet is not 'in order'
@@ -941,9 +1119,9 @@
 				if (!q) {
 					net_dev->ib.modify = 0;
 					printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
-					skb->free = 1;
+					SET_SKB_FREE(skb);
 					dev_kfree_skb(skb, 0 /* FREE_READ */ );
-					return;		/* discard */
+					return;	/* discard */
 				}
 				q->skb = skb;
 				q->sqno_end = sqno_end;
@@ -966,123 +1144,128 @@
 					}
 				}
 			} else {
-				/* 
-			 	 * packet was 'in order' .. push it higher
+				/*
+				 * packet was 'in order' .. push it higher
 				 */
 				net_dev->ib.next_num = sqno_end + 1;
-				isdn_ppp_push_higher(net_dev, lp, skb, -1);
+				proto = isdn_ppp_strip_proto(skb);
+				isdn_ppp_push_higher(net_dev, lp, skb, proto);
 			}
-			isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
+			isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
 			net_dev->ib.modify = 0;
 
 		} else
-			isdn_ppp_push_higher(net_dev, lp, skb , proto);
+			isdn_ppp_push_higher(net_dev, lp, skb, proto);
 	} else
 #endif
-		isdn_ppp_push_higher(net_dev, lp, skb , -1);
+		isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
 /*
  * push frame to higher layers
  * note: net_dev has to be master net_dev
  */
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto)
+static void
+isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
 {
 	struct device *dev = &net_dev->dev;
 	struct ippp_struct *is = ippp_table[lp->ppp_slot];
 
-	if (proto < 0) {	/* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
-		if (skb->data[0] & 0x01) {	/* is it odd? */
-			proto = (unsigned char) skb->data[0];
-			skb_pull(skb,1);	/* protocol ID is only 8 bit */
-		} else {
-			proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
-			skb_pull(skb,2);
-		}
+	if (is->debug & 0x10) {
+		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
+		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
 	}
 
-	if(is->debug & 0x10) {
-		printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto);
-		isdn_ppp_frame_log("rpush",skb->data,skb->len,32);
+	if(proto == PPP_COMP) {
+		if(!lp->master)
+			skb = isdn_ppp_decompress(skb,is,is);
+		else
+			skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
+		if(!skb)
+			return;
+		proto = isdn_ppp_strip_proto(skb);
 	}
 
 	switch (proto) {
-	case PPP_IPX: /* untested */
-		if(is->debug & 0x20)
-			printk(KERN_DEBUG "isdn_ppp: IPX\n");
-		skb->dev = dev;
-		skb->mac.raw = skb->data;
-		skb->protocol = htons(ETH_P_IPX);
-		break;
-#ifdef CONFIG_ISDN_PPP_VJ
-	case PPP_VJC_UNCOMP:
-		if(is->debug & 0x20)
-			printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
-		if(slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
-			printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
-			net_dev->local.stats.rx_dropped++;
-			skb->free = 1;
-			dev_kfree_skb(skb,0 /* FREE_READ */ );
-			return;
-		}
-#endif
-	case PPP_IP:
-		if(is->debug & 0x20)
-			printk(KERN_DEBUG "isdn_ppp: IP\n");
-		skb->dev = dev;
-		skb->mac.raw = skb->data;
-		skb->protocol = htons(ETH_P_IP);
-		break;
-	case PPP_VJC_COMP:
-                if(is->debug & 0x20)
-                        printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+		case PPP_IPX:  /* untested */
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: IPX\n");
+			skb->dev = dev;
+			skb->mac.raw = skb->data;
+			skb->protocol = htons(ETH_P_IPX);
+			break;
 #ifdef CONFIG_ISDN_PPP_VJ
-		{
-			struct sk_buff *skb_old = skb;
-			int pkt_len;
-			skb = dev_alloc_skb(skb_old->len + 40);
-
-			skb_old->free = 1;
-
-			if (!skb) {
-				printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+		case PPP_VJC_UNCOMP:
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+			if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
 				net_dev->local.stats.rx_dropped++;
-				dev_kfree_skb(skb_old,0 /* FREE_READ */ );
+				SET_SKB_FREE(skb);
+				dev_kfree_skb(skb, 0 /* FREE_READ */ );
 				return;
 			}
+#endif
+		case PPP_IP:
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: IP\n");
 			skb->dev = dev;
-			skb_put(skb,skb_old->len + 40);
-			memcpy(skb->data, skb_old->data, skb_old->len);
 			skb->mac.raw = skb->data;
-			pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
-						  skb->data, skb_old->len);
-			dev_kfree_skb(skb_old,0 /* FREE_READ */ );
-			if(pkt_len < 0) {
-				skb->free = 1;
-				dev_kfree_skb(skb, 0 /* FREE_READ */ );
-				lp->stats.rx_dropped++;
-				return;
-			}
-			skb_trim(skb, pkt_len);
 			skb->protocol = htons(ETH_P_IP);
-		}
+			break;
+		case PPP_VJC_COMP:
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+#ifdef CONFIG_ISDN_PPP_VJ
+			{
+				struct sk_buff *skb_old = skb;
+				int pkt_len;
+				skb = dev_alloc_skb(skb_old->len + 40);
+
+				SET_SKB_FREE(skb_old);
+
+				if (!skb) {
+					printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+					net_dev->local.stats.rx_dropped++;
+					dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+					return;
+				}
+				skb->dev = dev;
+				skb_put(skb, skb_old->len + 40);
+				memcpy(skb->data, skb_old->data, skb_old->len);
+				skb->mac.raw = skb->data;
+				pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+						skb->data, skb_old->len);
+				dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+				if (pkt_len < 0) {
+					SET_SKB_FREE(skb);
+					dev_kfree_skb(skb, 0 /* FREE_READ */ );
+					lp->stats.rx_dropped++;
+					return;
+				}
+				skb_trim(skb, pkt_len);
+				skb->protocol = htons(ETH_P_IP);
+			}
 #else
-		printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
-		lp->stats.rx_dropped++;
-		skb->free = 1;
-		dev_kfree_skb(skb,0 /* FREE_READ */ );
-		return;
+			printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
+			lp->stats.rx_dropped++;
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb, 0 /* FREE_READ */ );
+			return;
 #endif
-		break;
-	default:
-		isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_slot);	/* push data to pppd device */
-		skb->free = 1;
-		dev_kfree_skb(skb,0 /* FREE_READ */ );
-		return;
+			break;
+		case PPP_CCP:
+			isdn_ppp_receive_ccp(net_dev,lp,skb);
+			/* fall through */
+		default:
+			isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb, 0 /* FREE_READ */ );
+			return;
 	}
 
 	netif_rx(skb);
-/* net_dev->local.stats.rx_packets++; */ /* done in isdn_net.c */
+	/* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
 	/* Reset hangup-timer */
 	lp->huptimer = 0;
 
@@ -1090,89 +1273,95 @@
 }
 
 /*
- * send ppp frame .. we expect a PIDCOMPressable proto -- 
- *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!! 
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
  */
-
-static void isdn_ppp_skb_destructor(struct sk_buff *skb)	/* debug function */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
 {
-	char outstr[80],*outpnt=outstr;
-	int i;
+	struct sk_buff *skb = *skb_p;
 
-	*outpnt = 0;
-	for(i=0;i<24 && i<skb->len;i++) {
-		sprintf(outpnt,"%02x ",skb->data[i]);
-		outpnt += 3;
+	if(skb_headroom(skb) < len) {
+		printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+		dev_kfree_skb(skb,FREE_WRITE);
+		return NULL;
 	}
-	printk(KERN_DEBUG "ippp_dstrct: %s\n",outstr);
+	return skb_push(skb,len);
 }
 
-int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
+
+/*
+ * send ppp frame .. we expect a PIDCOMPressable proto --
+ *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
+ *
+ * VJ compression may change skb pointer!!! .. requeue with old
+ * skb isn't allowed!!
+ */
+
+int
+isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct device *mdev = ((isdn_net_local *) (dev->priv) )->master;	/* get master (for redundancy) */
+	struct device *mdev = ((isdn_net_local *) (dev->priv))->master;	/* get master (for redundancy) */
 	isdn_net_local *lp,*mlp;
 	isdn_net_dev *nd;
-	int proto = PPP_IP;	/* 0x21 */
+	unsigned int proto = PPP_IP;     /* 0x21 */
 	struct ippp_struct *ipt,*ipts;
 
-	if(mdev)
-		mlp = (isdn_net_local *) (mdev->priv); 
+	if (mdev)
+		mlp = (isdn_net_local *) (mdev->priv);
 	else {
 		mdev = dev;
 		mlp = (isdn_net_local *) (dev->priv);
 	}
-	nd = mlp->netdev;	/* get master lp */
+	nd = mlp->netdev;       /* get master lp */
 	ipts = ippp_table[mlp->ppp_slot];
 
-	if (!(ipts->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
+	if (!(ipts->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
 #ifdef ISDN_SYNCPPP_READDRESS
-		if(!ipts->old_pa_addr)
+		if (!ipts->old_pa_addr)
 			ipts->old_pa_addr = mdev->pa_addr;
-		if(!ipts->old_pa_dstaddr)
+		if (!ipts->old_pa_dstaddr)
 			ipts->old_pa_dstaddr = mdev->pa_dstaddr;
 #endif
-		if(ipts->debug & 0x1) {
-			printk(KERN_INFO "%s: IP frame delayed.\n",dev->name);
-			skb->destructor = isdn_ppp_skb_destructor;
-		}
- 		return 1;
+		if (ipts->debug & 0x1)
+			printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
+		return 1;
 	}
 
-	skb->destructor = NULL;
-
-	switch(ntohs(skb->protocol)) {
+	switch (ntohs(skb->protocol)) {
 		case ETH_P_IP:
 			proto = PPP_IP;
 #ifdef ISDN_SYNCPPP_READDRESS
-			if(ipts->old_pa_addr != mdev->pa_addr)
-			{
+			if (ipts->old_pa_addr != mdev->pa_addr) {
 				struct iphdr *ipfr;
 				ipfr = (struct iphdr *) skb->data;
-printk(KERN_DEBUG "IF-address changed from %lx to %lx\n",ipts->old_pa_addr,mdev->pa_addr);
-				if(ipfr->version == 4) {
-					if(ipfr->saddr == ipts->old_pa_addr) {
-printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
+				if(ipts->debug & 0x4)
+					printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr);
+				if (ipfr->version == 4) {
+					if (ipfr->saddr == ipts->old_pa_addr) {
+						printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr);
 						ipfr->saddr = mdev->pa_addr;
 					}
 				}
 			}
-			/* dstaddr change not so improtant */
+			/* dstaddr change not so important */
 #endif
 			break;
 		case ETH_P_IPX:
 			proto = PPP_IPX;	/* untested */
 			break;
+		default:
+			dev_kfree_skb(skb, FREE_WRITE);
+			printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol);
+			return 0;
 	}
 
-	lp = nd->queue;		/* get lp on top of queue */
+	lp = nd->queue;         /* get lp on top of queue */
 
-	if(lp->sav_skb) {	/* find a non-busy device */
+	if (lp->sav_skb) {      /* find a non-busy device */
 		isdn_net_local *nlp = lp->next;
-		while(lp->sav_skb) {
-			if(lp == nlp)
+		while (lp->sav_skb) {
+			if (lp == nlp)
 				return 1;
 			nlp = nd->queue = nd->queue->next;
 		}
@@ -1180,43 +1369,49 @@
 	}
 	ipt = ippp_table[lp->ppp_slot];
 
-        lp->huptimer = 0;
+	lp->huptimer = 0;
 
 	/*
-	 * after this line .. requeueing in the device queue is no longer allowed!!! 
+	 * after this line .. requeueing in the device queue is no longer allowed!!!
 	 */
 
-	if(ipt->debug & 0x4)
-		printk(KERN_DEBUG  "xmit skb, len %ld\n",skb->len);
+	/* Pull off the fake header we stuck on earlier to keep
+     * the fragemntation code happy.
+     * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
+     * above. So, enabling this is no longer allowed
+     */
+	skb_pull(skb,IPPP_MAX_HEADER);
+
+	if (ipt->debug & 0x4)
+		printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
 
 #ifdef CONFIG_ISDN_PPP_VJ
-	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but this check again */
+	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes, but check this again */
 		struct sk_buff *new_skb;
 
 		new_skb = dev_alloc_skb(skb->len);
-		if(new_skb) {
+		if (new_skb) {
 			u_char *buf;
 			int pktlen;
 
 			new_skb->dev = skb->dev;
-			new_skb->free = 1;
-			skb_put(new_skb,skb->len);
+			SET_SKB_FREE(new_skb);
+			skb_put(new_skb, skb->len);
 			buf = skb->data;
 
 			pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
-					&buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
+				 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
 
-			if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
-				if(new_skb->data != buf)
+			if (buf != skb->data) {	
+				if (new_skb->data != buf)
 					printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
-				dev_kfree_skb(skb,FREE_WRITE);
+				dev_kfree_skb(skb, FREE_WRITE);
 				skb = new_skb;
-			}
-			else {
-				dev_kfree_skb(new_skb,0 /* FREE_WRITE */ );
+			} else {
+				dev_kfree_skb(new_skb, 0 /* FREE_WRITE */ );
 			}
 
-			skb_trim(skb,pktlen);
+			skb_trim(skb, pktlen);
 			if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) {	/* cslip? style -> PPP */
 				proto = PPP_VJC_COMP;
 				skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
@@ -1229,8 +1424,13 @@
 	}
 #endif
 
-        if(ipt->debug & 0x24)
- 		printk(KERN_DEBUG  "xmit2 skb, len %ld, proto %04x\n",skb->len,proto);
+    /*
+     * normal or bundle compression
+     */
+	skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+
+	if (ipt->debug & 0x24)
+		printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
 
 #ifdef CONFIG_ISDN_MPP
 	if (ipt->mpppcfg & SC_MP_PROT) {
@@ -1239,41 +1439,64 @@
 		ipts->mp_seqno++;
 		nd->queue = nd->queue->next;
 		if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
-			skb_push(skb, 3);
+			unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+			if(!data)
+				return 0;
 			mp_seqno &= 0xfff;
-			skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8);	/* (B)egin & (E)ndbit .. */
-			skb->data[1] = mp_seqno & 0xff;
-			skb->data[2] = proto;	/* PID compression */
+			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf);	/* (B)egin & (E)ndbit .. */
+			data[1] = mp_seqno & 0xff;
+			data[2] = proto;	/* PID compression */
 		} else {
-			skb_push(skb, 5);
-			skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
-			skb->data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
-			skb->data[2] = (mp_seqno >> 8) & 0xff;
-			skb->data[3] = (mp_seqno >> 0) & 0xff;
-			skb->data[4] = proto;	/* PID compression */
+			unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+			if(!data)
+				return 0;
+			data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
+			data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
+			data[2] = (mp_seqno >> 8) & 0xff;
+			data[3] = (mp_seqno >> 0) & 0xff;
+			data[4] = proto;	/* PID compression */
 		}
 		proto = PPP_MP; /* MP Protocol, 0x003d */
 	}
 #endif
-	skb_push(skb,4);
-	skb->data[0] = 0xff;        /* All Stations */
-	skb->data[1] = 0x03;        /* Unnumbered information */
-	skb->data[2] = proto >> 8;
-	skb->data[3] = proto & 0xff;
-
-        /* tx-stats are now updated via BSENT-callback */
-
-	if(ipts->debug & 0x40) {
-		printk(KERN_DEBUG "skb xmit: len: %ld\n",skb->len);
-		isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
-	}
-
-	if(isdn_net_send_skb(dev , lp , skb)) {	
-		if(lp->sav_skb) {	/* whole sav_skb processing with disabled IRQs ?? */
-			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name);
-			dev_kfree_skb(skb,FREE_WRITE);
-		}
-		else
+
+	/*
+	 * 'link' compression 
+	 */
+	skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
+	if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
+		unsigned char *data = isdn_ppp_skb_push(&skb,1);
+		if(!data)
+			return 0;
+		data[0] = proto & 0xff;
+	}
+	else {
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			return 0;
+		data[0] = (proto >> 8) & 0xff;
+		data[1] = proto & 0xff;
+	}
+	if(!(ipt->pppcfg & SC_COMP_AC)) {
+		unsigned char *data = isdn_ppp_skb_push(&skb,2);
+		if(!data)
+			return 0;
+		data[0] = 0xff;    /* All Stations */
+		data[1] = 0x03;    /* Unnumbered information */
+	}
+
+	/* tx-stats are now updated via BSENT-callback */
+
+	if (ipts->debug & 0x40) {
+		printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
+		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+	}
+	if (isdn_net_send_skb(dev, lp, skb)) {
+		if (lp->sav_skb) {	/* whole sav_skb processing with disabled IRQs ?? */
+			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name);
+			dev_kfree_skb(skb, FREE_WRITE);
+		} else
 			lp->sav_skb = skb;
 	}
 	return 0;
@@ -1281,16 +1504,17 @@
 
 #ifdef CONFIG_ISDN_MPP
 
-void isdn_ppp_free_sqqueue(isdn_net_dev * p) 
+static void
+isdn_ppp_free_sqqueue(isdn_net_dev * p)
 {
 	struct sqqueue *q = p->ib.sq;
 
 	p->ib.sq = NULL;
-	while(q) {
+	while (q) {
 		struct sqqueue *qn = q->next;
-		if(q->skb) {
-			q->skb->free = 1;
-			dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+		if (q->skb) {
+			SET_SKB_FREE(q->skb);
+			dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
 		}
 		kfree(q);
 		q = qn;
@@ -1298,24 +1522,29 @@
 
 }
 
-void isdn_ppp_free_mpqueue(isdn_net_dev * p)
+static void 
+isdn_ppp_free_mpqueue(isdn_net_dev * p)
 {
-	struct mpqueue *ql, *q = p->mp_last;
+	struct mpqueue *q = p->mp_last;
+	p->mp_last = NULL;
+
 	while (q) {
-		ql = q->next;
-		q->skb->free = 1;
- 		dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+		struct mpqueue *ql = q->next;
+		SET_SKB_FREE(q->skb);
+		dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
 		kfree(q);
 		q = ql;
 	}
 }
 
-static int isdn_ppp_bundle(struct ippp_struct *is, int unit)
+static int
+isdn_ppp_bundle(struct ippp_struct *is, int unit)
 {
 	char ifn[IFNAMSIZ + 1];
 	long flags;
 	isdn_net_dev *p;
-	isdn_net_local *lp,*nlp;
+	isdn_net_local *lp,
+	*nlp;
 
 	sprintf(ifn, "ippp%d", unit);
 	p = isdn_net_findif(ifn);
@@ -1356,7 +1585,8 @@
 }
 
 
-static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
+static void
+isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
 {
 	struct mpqueue *q = dev->mp_last;
 	while (q) {
@@ -1365,14 +1595,19 @@
 	}
 }
 
-static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, long *sqnop, int min_sqno)
+static int
+isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno)
 {
-	struct mpqueue *qe, *q1, *q;
-	long cnt, flags;
-	int pktlen, sqno_end;
+	struct mpqueue *qe,
+	*q1,
+	*q;
+	long cnt,
+	 flags;
+	int pktlen,
+	 sqno_end;
 	int sqno = *sqnop;
 
-	q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL);
+	q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC);
 	if (!q1) {
 		printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
 		save_flags(flags);
@@ -1395,9 +1630,9 @@
 		q1->last = NULL;
 		isdn_ppp_cleanup_mpqueue(dev, min_sqno);	/* not necessary */
 		restore_flags(flags);
-		return -1;
+		return -1;	/* -1 is not an error. Just says, that this fragment hasn't complete a full frame */
 	}
-	for (;;) {		/* the faster way would be to step from the queue-end to the start */
+	for (;;) {              /* the faster way would be to step from the queue-end to the start */
 		if (sqno > q->sqno) {
 			if (q->next) {
 				q = q->next;
@@ -1465,26 +1700,26 @@
 	isdn_ppp_cleanup_mpqueue(dev, min_sqno);
 	restore_flags(flags);
 
-	*skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
+	*skb = dev_alloc_skb(pktlen + 40);	/* not needed: +40 for VJ compression .. */
 
 	if (!(*skb)) {
 		while (q) {
 			struct mpqueue *ql = q->next;
-			q->skb->free = 1;
-			dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+			SET_SKB_FREE(q->skb);
+			dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
 			kfree(q);
 			q = ql;
 		}
 		return -2;
 	}
 	cnt = 0;
-	skb_put(*skb,pktlen);
+	skb_put(*skb, pktlen);
 	while (q) {
 		struct mpqueue *ql = q->next;
 		memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
 		cnt += q->skb->len;
-		q->skb->free = 1;
-		dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+		SET_SKB_FREE(q->skb);
+		dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
 		kfree(q);
 		q = ql;
 	}
@@ -1497,28 +1732,32 @@
  * or packets with a sqno less or equal to min_sqno
  * net_dev: master netdevice , lp: 'real' local connection
  */
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev *net_dev, isdn_net_local *lp,long min_sqno)
+static void
+isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno)
 {
 	struct sqqueue *q;
 
-	while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno) ) {
-		if(q->sqno_start != net_dev->ib.next_num) {
-			printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n",net_dev->ib.next_num);
+	while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
+		int proto;
+		if (q->sqno_start != net_dev->ib.next_num) {
+			printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
 #ifdef CONFIG_ISDN_PPP_VJ
 			slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
 #endif
 		}
-		isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+		proto = isdn_ppp_strip_proto(q->skb);
+		isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
 		net_dev->ib.sq = q->next;
 		net_dev->ib.next_num = q->sqno_end + 1;
 		kfree(q);
-    }
+	}
 }
 
 /*
  * remove stale packets from list
  */
-static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
+static void
+isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
 {
 #ifdef CONFIG_ISDN_PPP_VJ
 	int toss = 0;
@@ -1526,36 +1765,36 @@
 /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
    eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
    wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
-   bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete 
+   bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
    groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
    ja ein Paket mit B und eins mit E dazwischenpassen */
 
-	struct mpqueue *ql, *q = dev->mp_last;
-	while (q) {
-		if (q->sqno < min_sqno) {
-			if (q->BEbyte & MP_END_FRAG) {
-				printk(KERN_DEBUG "ippp: freeing stale packet!\n");
-				if ((dev->mp_last = q->next))
-					q->next->last = NULL;
-				while (q) {
-					ql = q->last;
-					q->skb->free = 1;
-					dev_kfree_skb(q->skb,0 /* FREE_READ */ );
-					kfree(q);
+	struct mpqueue *ql,
+	*q = dev->mp_last;
+	while(q && (q->sqno < min_sqno) ) {
+		if ( (q->BEbyte & MP_END_FRAG) || 
+			 (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
+			printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
+			if ((dev->mp_last = q->next))
+				q->next->last = NULL;
+			while (q) {
+				ql = q->last;
+				SET_SKB_FREE(q->skb);
+				printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+				dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
+				kfree(q);
 #ifdef CONFIG_ISDN_PPP_VJ
-					toss = 1;
+				toss = 1;
 #endif
-					q = ql;
-				}
-				q = dev->mp_last;
-			} else
-				q = q->next;
+				q = ql;
+			}
+			q = dev->mp_last;
 		} else
-			break;
+			q = q->next;
 	}
 #ifdef CONFIG_ISDN_PPP_VJ
 	/* did we free a stale frame ? */
-	if(toss)
+	if (toss)
 		slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
 #endif
 }
@@ -1566,26 +1805,28 @@
 
 #endif
 
-void isdn_ppp_timer_timeout(void)
+void
+isdn_ppp_timer_timeout(void)
 {
 #ifdef CONFIG_ISDN_MPP
 	isdn_net_dev *net_dev = dev->netdev;
-	struct sqqueue *q, *ql = NULL, *qn;
+	struct sqqueue *q,
+	*ql = NULL,
+	*qn;
 
 	while (net_dev) {
 		isdn_net_local *lp = &net_dev->local;
-		if (net_dev->ib.modify || lp->master)	{	/* interface locked or slave?*/
+		if (net_dev->ib.modify || lp->master) {	/* interface locked or slave? */
 			net_dev = net_dev->next;
 			continue;
 		}
-
 		q = net_dev->ib.sq;
 		while (q) {
 			if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
 
 #ifdef CONFIG_ISDN_PPP_VJ
 				/* did we step over a missing frame ? */
-				if(q->sqno_start != net_dev->ib.next_num)
+				if (q->sqno_start != net_dev->ib.next_num)
 					slhc_toss(ippp_table[lp->ppp_slot]->slcomp);
 #endif
 
@@ -1594,7 +1835,8 @@
 				net_dev->ib.next_num = q->sqno_end + 1;
 				q->next = NULL;
 				for (; ql;) {
-					isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
+					int proto = isdn_ppp_strip_proto(ql->skb);
+					isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
 					qn = ql->next;
 					kfree(ql);
 					ql = qn;
@@ -1612,46 +1854,47 @@
  * network device ioctl handlers
  */
 
-static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *dev)
+static int
+isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev)
 {
-	struct ppp_stats *res, t;
+	struct ppp_stats *res,
+	 t;
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
 	int err;
 
-        res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
-        err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats));
+	res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+	err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));
 
-	if(err)
+	if (err)
 		return err;
 
 	/* build a temporary stat struct and copy it to user space */
 
-	memset (&t, 0, sizeof(struct ppp_stats));
-	if(dev->flags & IFF_UP) {
+	memset(&t, 0, sizeof(struct ppp_stats));
+	if (dev->flags & IFF_UP) {
 		t.p.ppp_ipackets = lp->stats.rx_packets;
 		t.p.ppp_ierrors = lp->stats.rx_errors;
 		t.p.ppp_opackets = lp->stats.tx_packets;
 		t.p.ppp_oerrors = lp->stats.tx_errors;
 #ifdef CONFIG_ISDN_PPP_VJ
-		if(slot >= 0 && ippp_table[slot]->slcomp) {
+		if (slot >= 0 && ippp_table[slot]->slcomp) {
 			struct slcompress *slcomp = ippp_table[slot]->slcomp;
-			t.vj.vjs_packets  = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed;
+			t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
 			t.vj.vjs_compressed = slcomp->sls_o_compressed;
 			t.vj.vjs_searches = slcomp->sls_o_searches;
-			t.vj.vjs_misses   = slcomp->sls_o_misses;
-			t.vj.vjs_errorin  = slcomp->sls_i_error;
-			t.vj.vjs_tossed   = slcomp->sls_i_tossed;
+			t.vj.vjs_misses = slcomp->sls_o_misses;
+			t.vj.vjs_errorin = slcomp->sls_i_error;
+			t.vj.vjs_tossed = slcomp->sls_i_tossed;
 			t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
 			t.vj.vjs_compressedin = slcomp->sls_i_compressed;
 		}
 #endif
 	}
-	copy_to_user (res, &t, sizeof (struct ppp_stats));
-	return 0;
-
+	return copy_to_user(res, &t, sizeof(struct ppp_stats));
 }
 
-int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+int
+isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
 	int error;
 	char *r;
@@ -1659,7 +1902,7 @@
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
 
 #if 0
-	printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_slot);
+	printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n", cmd, lp->ppp_slot);
 #endif
 
 	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
@@ -1669,12 +1912,10 @@
 		case SIOCGPPPVER:
 			r = (char *) ifr->ifr_ifru.ifru_data;
 			len = strlen(PPP_VERSION) + 1;
-			error = verify_area(VERIFY_WRITE, r, len);
-			if (!error)
-				copy_to_user(r, PPP_VERSION, len);
+			error = copy_to_user(r, PPP_VERSION, len);
 			break;
 		case SIOCGPPPSTATS:
-			error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev);
+			error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
 			break;
 		default:
 			error = -EINVAL;
@@ -1683,51 +1924,55 @@
 	return error;
 }
 
-static int isdn_ppp_if_get_unit(char *name)
+static int
+isdn_ppp_if_get_unit(char *name)
 {
-	int len, i, unit = 0, deci;
+	int len,
+	 i,
+	 unit = 0,
+	 deci;
 
 	len = strlen(name);
 
-	if(strncmp("ippp",name,4) || len > 8)
+	if (strncmp("ippp", name, 4) || len > 8)
 		return -1;
 
 	for (i = 0, deci = 1; i < len; i++, deci *= 10) {
-		char a = name[len-i-1];
+		char a = name[len - i - 1];
 		if (a >= '0' && a <= '9')
 			unit += (a - '0') * deci;
 		else
 			break;
 	}
-	if (!i || len-i != 4)
+	if (!i || len - i != 4)
 		unit = -1;
 
 	return unit;
 }
 
 
-int isdn_ppp_dial_slave(char *name)
+int
+isdn_ppp_dial_slave(char *name)
 {
 #ifdef CONFIG_ISDN_MPP
 	isdn_net_dev *ndev;
 	isdn_net_local *lp;
 	struct device *sdev;
 
-	if(!(ndev = isdn_net_findif(name)))
+	if (!(ndev = isdn_net_findif(name)))
 		return 1;
 	lp = &ndev->local;
-	if(!(lp->flags & ISDN_NET_CONNECTED))
+	if (!(lp->flags & ISDN_NET_CONNECTED))
 		return 5;
 
 	sdev = lp->slave;
-	while(sdev)
-	{
+	while (sdev) {
 		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
-		if(!(mlp->flags & ISDN_NET_CONNECTED))
+		if (!(mlp->flags & ISDN_NET_CONNECTED))
 			break;
 		sdev = mlp->slave;
 	}
-	if(!sdev)
+	if (!sdev)
 		return 2;
 
 	isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
@@ -1737,28 +1982,28 @@
 #endif
 }
 
-int isdn_ppp_hangup_slave(char *name)
+int
+isdn_ppp_hangup_slave(char *name)
 {
 #ifdef CONFIG_ISDN_MPP
-        isdn_net_dev *ndev;
-        isdn_net_local *lp;
-        struct device *sdev;
+	isdn_net_dev *ndev;
+	isdn_net_local *lp;
+	struct device *sdev;
 
-	if(!(ndev = isdn_net_findif(name)))
+	if (!(ndev = isdn_net_findif(name)))
 		return 1;
 	lp = &ndev->local;
-	if(!(lp->flags & ISDN_NET_CONNECTED))
+	if (!(lp->flags & ISDN_NET_CONNECTED))
 		return 5;
 
 	sdev = lp->slave;
-	while(sdev)
-	{
+	while (sdev) {
 		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
-		if((mlp->flags & ISDN_NET_CONNECTED))
+		if ((mlp->flags & ISDN_NET_CONNECTED))
 			break;
 		sdev = mlp->slave;
 	}
-	if(!sdev)
+	if (!sdev)
 		return 2;
 
 	isdn_net_hangup(sdev);
@@ -1768,13 +2013,182 @@
 #endif
 }
 
+/*
+ * PPP compression stuff
+ */
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+{
+#if 1
+	printk(KERN_ERR "compression not included!\n");
+	SET_SKB_FREE(skb);
+	dev_kfree_skb(skb,FREE_WRITE);
+	return NULL;
+#else
+	if(!master) {
+		/* 
+		 * single link compression 
+		 */
+		if(!is->link_compressor) {
+			printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb,FREE_WRITE);
+			return NULL;
+		}
+		if(!is->link_decomp_stat) {
+			printk(KERN_DEBUG "ippp: initialize link compressor\n");
+		}
+/*
+		-> decompress link
+*/
+    }
+	else {
+		/*
+		 * 'normal' or bundle-compression 
+		 */
+		if(!master->compressor) {
+			printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+			SET_SKB_FREE(skb);
+			dev_kfree_skb(skb,FREE_WRITE);
+			return NULL;
+		}
+		if(!master->decomp_stat) {
+#if 0
+			master->decomp_stat = (master->compressor->decomp_alloc)( .. );
+#endif
+			printk(KERN_DEBUG "ippp: initialize compressor\n");
+		}
+	}
+	
+	return skb;
+#endif
+}
+
+/*
+ * compress a frame 
+ *   type=0: normal/bundle compression
+ *       =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+	struct ippp_struct *is,struct ippp_struct *master,int type)
+{
+#if 1	
+	return skb_in;
+#else
+    int ret;
+    int new_proto;
+    struct isdn_ppp_compressor *compressor;
+    void *stat;
+    struct sk_buff *skb_out;
+
+	if(type) { /* type=1 => Link compression */
+		compressor = is->link_compressor;
+		stat = is->link_comp_stat;
+		new_proto = PPP_LINK_COMP;
+	}
+	else {
+		if(!master) {
+			compressor = is->compressor;
+			stat = is->comp_stat;
+		}
+		else {
+			compressor = master->compressor;
+			stat = master->comp_stat;
+		}
+		new_proto = PPP_COMP;
+	}
+
+	if(!compressor) {
+		printk(KERN_ERR "No compressor set!\n");
+		return skb_in;
+	}
+	if(!stat) {
+		/* init here ? */
+		return skb_in;
+	}
+
+	skb_out = dev_alloc_skb(skb_in->len);
+	if(!skb_out)
+		return skb_in;
+
+	ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+	if(!ret) {
+		SET_SKB_FREE(skb_out);
+		dev_kfree_skb(skb_out,0);
+		return skb_in;
+	}
+	
+	dev_kfree_skb(skb_in,FREE_WRITE);
+	*proto = new_proto;
+	return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame .. 
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+	 struct sk_buff *skb)
+{
+#if 0
+	printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+		skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
+
+int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
+{
+	ipc->next = ipc_head;
+	ipc->prev = NULL;
+	if(ipc_head) {
+		ipc_head->prev = ipc;
+	}
+	ipc_head = ipc;
+	return 0;
+}
+
+int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
+{
+	if(ipc->prev)
+		ipc->prev->next = ipc->next;
+	else
+		ipc_head = ipc->next;
+	if(ipc->next)
+		ipc->next->prev = ipc->prev;
+	ipc->prev = ipc->next = NULL;
+	return 0;
+}
+
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
+{
+	struct isdn_ppp_compressor *ipc = ipc_head;
+
+	while(ipc) {
+		if(ipc->num == num) {
+			return 0;	
+			is->compressor = ipc;
+			is->link_compressor = ipc;
+		}
+		ipc = ipc->next;
+	}
+	return -EINVAL;
+}
+
+
 #if 0
-static struct symbol_table isdn_ppp_syms = {
+static struct symbol_table isdn_ppp_syms =
+{
 #include <linux/symtab_begin.h>
-    X(isdn_ppp_register_compressor),
-    X(isdn_ppp_unregister_compressor),
+	X(isdn_ppp_register_compressor),
+	X(isdn_ppp_unregister_compressor),
 #include <linux/symtab_end.h>
 };
 #endif
 
 
+
+
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_ppp.h linux-2.0.31-pre3/drivers/isdn/isdn_ppp.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_ppp.h	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_ppp.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,9 +1,9 @@
-/* $Id: isdn_ppp.h,v 1.6 1996/09/23 01:58:11 fritz Exp $
- *
+/* $Id: isdn_ppp.h,v 1.10 1997/06/17 13:06:00 hipp Exp $
+
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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)
@@ -16,9 +16,26 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.h,v $
+ * Revision 1.10  1997/06/17 13:06:00  hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
+ * Revision 1.9  1997/02/11 18:32:59  fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.8  1997/02/10 10:11:33  fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.7  1997/02/03 23:18:57  fritz
+ * Removed isdn_ppp_free_sqqueue prototype
+ *         and ippp_table (both static in isdn_ppp.c).
+ *
  * Revision 1.6  1996/09/23 01:58:11  fritz
  * Fix: With syncPPP encapsulation, discard LCP packets
  *      when calculating hangup timeout.
@@ -41,31 +58,34 @@
  *
  */
 
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
+#include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
 extern void isdn_ppp_timer_timeout(void);
-extern int  isdn_ppp_read(int , struct file *, char *, int);
-extern int  isdn_ppp_write(int , struct file *, const char *, int);
-extern int  isdn_ppp_open(int , struct file *);
-extern int  isdn_ppp_init(void);
+extern int isdn_ppp_read(int, struct file *, char *, int);
+extern int isdn_ppp_write(int, struct file *, const char *, int);
+extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
-extern int  isdn_ppp_free(isdn_net_local *);
-extern int  isdn_ppp_bind(isdn_net_local *);
-extern int  isdn_ppp_xmit(struct sk_buff *, struct device *);
+extern int isdn_ppp_free(isdn_net_local *);
+extern int isdn_ppp_bind(isdn_net_local *);
+extern int isdn_ppp_xmit(struct sk_buff *, struct device *);
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int  isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
-extern void isdn_ppp_free_mpqueue(isdn_net_dev *);
-extern void isdn_ppp_free_sqqueue(isdn_net_dev *);
-extern int  isdn_ppp_select(int, struct file *, int, select_table *);
-extern int  isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
+extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
+#if (LINUX_VERSION_CODE < 0x020117)
+extern int isdn_ppp_select(int, struct file *, int, select_table *);
+#else
+extern unsigned int isdn_ppp_poll(struct file *, poll_table *);
+#endif
+extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
 extern void isdn_ppp_release(int, struct file *);
-extern int  isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
-extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
-
 #define IPPP_OPEN	0x01
 #define IPPP_CONNECT	0x02
 #define IPPP_CLOSEWAIT	0x04
 #define IPPP_NOBLOCK	0x08
 #define IPPP_ASSIGNED	0x10
 
+#define IPPP_MAX_HEADER 10
+
+
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_syms.c linux-2.0.31-pre3/drivers/isdn/isdn_syms.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_syms.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_syms.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,55 @@
+/* $Id: isdn_syms.c,v 1.3 1997/02/16 01:02:47 fritz Exp $
+
+ * Linux ISDN subsystem, exported symbols (linklevel).
+ *
+ * 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: isdn_syms.c,v $
+ * Revision 1.3  1997/02/16 01:02:47  fritz
+ * Added GPL-Header, Id and Log
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#ifndef __GENKSYMS__      /* Don't want genksyms report unneeded structs */
+#include <linux/isdn.h>
+#endif
+#include "isdn_common.h"
+
+#if (LINUX_VERSION_CODE < 0x020111)
+static int has_exported;
+
+static struct symbol_table isdn_syms = {
+#include <linux/symtab_begin.h>
+        X(register_isdn),
+#include <linux/symtab_end.h>
+};
+
+void
+isdn_export_syms(void)
+{
+	if (has_exported)
+		return;
+        register_symtab(&isdn_syms);
+        has_exported = 1;
+}
+
+#else
+
+EXPORT_SYMBOL(register_isdn);
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_tty.c linux-2.0.31-pre3/drivers/isdn/isdn_tty.c
--- linux-2.0.31-pre2/drivers/isdn/isdn_tty.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/isdn_tty.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,10 +1,10 @@
-/* $Id: isdn_tty.c,v 1.23 1996/10/22 23:14:02 fritz Exp $
- *
+/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $
+
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
- * 
+ *
  * 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)
@@ -17,9 +17,80 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.41  1997/05/27 15:17:31  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.40  1997/03/24 22:55:27  fritz
+ * Added debug code for status callbacks.
+ *
+ * Revision 1.39  1997/03/21 18:25:56  fritz
+ * Corrected CTS handling.
+ *
+ * Revision 1.38  1997/03/07 12:13:35  fritz
+ * Bugfix: Send audio in adpcm format was broken.
+ * Bugfix: CTS handling was wrong.
+ *
+ * Revision 1.37  1997/03/07 01:37:34  fritz
+ * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled.
+ * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly.
+ * Bugfix: conversion was wrong when sending ulaw audio.
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.36  1997/03/04 21:41:55  fritz
+ * Fix: Excessive stack usage of isdn_tty_senddown()
+ *      and isdn_tty_end_vrx() could lead to problems.
+ *
+ * Revision 1.35  1997/03/02 19:05:52  fritz
+ * Bugfix: Avoid recursion.
+ *
+ * Revision 1.34  1997/03/02 14:29:22  fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.33  1997/02/28 02:32:45  fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ *          to isdn_tty.c
+ * Bugfix:  Bisync protocol did not behave like documented.
+ *
+ * Revision 1.32  1997/02/23 15:43:03  fritz
+ * Small change in handling of incoming calls
+ * documented in newest version of ttyI.4
+ *
+ * Revision 1.31  1997/02/21 13:05:57  fritz
+ * Bugfix: Remote hangup did not set location-info on ttyI's
+ *
+ * Revision 1.30  1997/02/18 09:41:05  fritz
+ * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?).
+ * Beautified output of AT&V.
+ *
+ * Revision 1.29  1997/02/16 12:11:51  fritz
+ * Added S13,Bit4 option.
+ *
+ * Revision 1.28  1997/02/10 22:07:08  fritz
+ * Added 2 modem registers for numbering plan and screening info.
+ *
+ * Revision 1.27  1997/02/10 21:31:14  fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.26  1997/02/10 20:12:48  fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.25  1997/02/03 23:04:30  fritz
+ * Reformatted according CodingStyle.
+ * skb->free stuff replaced by macro.
+ * Finished full-duplex audio.
+ *
+ * Revision 1.24  1997/01/14 01:32:42  fritz
+ * Changed audio receive not to rely on skb->users and skb->lock.
+ * Added ATI2 and related variables.
+ * Started adding full-duplex audio capability.
+ *
  * Revision 1.23  1996/10/22 23:14:02  fritz
  * Changes for compatibility to 2.0.X and 2.1.X kernels.
  *
@@ -114,6 +185,7 @@
  * Initial revision
  *
  */
+#undef ISDN_TTY_STAT_DEBUG
 
 #define __NO_VERSION__
 #include <linux/config.h>
@@ -129,29 +201,35 @@
 
 /* Prototypes */
 
-static int  isdn_tty_edit_at(const char *, int, modem_info *, int);
+static int isdn_tty_edit_at(const char *, int, modem_info *, int);
 static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
 static void isdn_tty_modem_reset_regs(modem_info *, int);
 static void isdn_tty_cmd_ATA(modem_info *);
 static void isdn_tty_at_cout(char *, modem_info *);
 static void isdn_tty_flush_buffer(struct tty_struct *);
+static void isdn_tty_modem_result(int, modem_info *);
+#ifdef CONFIG_ISDN_AUDIO
+static int isdn_tty_countDLE(unsigned char *, int);
+#endif
 
 /* Leave this unchanged unless you know what you do! */
 #define MODEM_PARANOIA_CHECK
 #define MODEM_DO_RESTART
 
 static char *isdn_ttyname_ttyI = "ttyI";
-static char *isdn_ttyname_cui  = "cui";
-static int bit2si[8] = {1,5,7,7,7,7,7,7};
-static int si2bit[8] = {4,1,4,4,4,4,4,4};
-                                
-char *isdn_tty_revision        = "$Revision: 1.23 $";
+static char *isdn_ttyname_cui = "cui";
+static int bit2si[8] =
+{1, 5, 7, 7, 7, 7, 7, 7};
+static int si2bit[8] =
+{4, 1, 4, 4, 4, 4, 4, 4};
+
+char *isdn_tty_revision = "$Revision: 1.41 $";
 
 #define DLE 0x10
 #define ETX 0x03
 #define DC4 0x14
 
-/* isdn_tty_try_read() is called from within isdn_receive_callback()
+/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. This
  * is done to speed up tty-receiving if the receive-queue is empty.
  * This routine MUST be called with interrupts off.
@@ -160,37 +238,45 @@
  *  0 = Failure, data has to be buffered and later processed by
  *      isdn_tty_readmodem().
  */
-int isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
+static int
+isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
 {
-        int c;
-        int len;
-        struct tty_struct *tty;
+	int c;
+	int len;
+	struct tty_struct *tty;
 
 	if (info->online) {
 		if ((tty = info->tty)) {
 			if (info->mcr & UART_MCR_RTS) {
 				c = TTY_FLIPBUF_SIZE - tty->flip.count;
-                                len = skb->len + skb->users;
+				len = skb->len
+#ifdef CONFIG_ISDN_AUDIO
+					+ ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+					;
 				if (c >= len) {
-                                        if (skb->users)
-                                                while (skb->len--) {
-                                                        if (*skb->data == DLE)
-                                                                tty_insert_flip_char(tty, DLE, 0);
-                                                        tty_insert_flip_char(tty, *skb->data++, 0);
-                                                }
-                                        else {
-                                                memcpy(tty->flip.char_buf_ptr,
-                                                       skb->data, len);
-                                                tty->flip.count += len;
-                                                tty->flip.char_buf_ptr += len;
-                                                memset(tty->flip.flag_buf_ptr, 0, len);
-                                                tty->flip.flag_buf_ptr += len;
-                                        }
-                                        if (info->emu.mdmreg[12] & 128)
-                                                tty->flip.flag_buf_ptr[len - 1] = 0xff;
-					queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-                                        skb->free = 1;
-                                        kfree_skb(skb, FREE_READ);
+#ifdef CONFIG_ISDN_AUDIO
+					if (ISDN_AUDIO_SKB_DLECOUNT(skb))
+						while (skb->len--) {
+							if (*skb->data == DLE)
+								tty_insert_flip_char(tty, DLE, 0);
+							tty_insert_flip_char(tty, *skb->data++, 0);
+					} else {
+#endif
+						memcpy(tty->flip.char_buf_ptr,
+						       skb->data, len);
+						tty->flip.count += len;
+						tty->flip.char_buf_ptr += len;
+						memset(tty->flip.flag_buf_ptr, 0, len);
+						tty->flip.flag_buf_ptr += len;
+#ifdef CONFIG_ISDN_AUDIO
+					}
+#endif
+					if (info->emu.mdmreg[12] & 128)
+						tty->flip.flag_buf_ptr[len - 1] = 0xff;
+					queue_task(&tty->flip.tqueue, &tq_timer);
+					SET_SKB_FREE(skb);
+					kfree_skb(skb, FREE_READ);
 					return 1;
 				}
 			}
@@ -203,7 +289,8 @@
  * It tries getting received data from the receive queue an stuff it into
  * the tty's flip-buffer.
  */
-void isdn_tty_readmodem(void)
+void
+isdn_tty_readmodem(void)
 {
 	int resched = 0;
 	int midx;
@@ -216,7 +303,7 @@
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		if ((midx = dev->m_idx[i]) >= 0) {
-                        info = &dev->mdm.info[midx];
+			info = &dev->mdm.info[midx];
 			if (info->online) {
 				r = 0;
 #ifdef CONFIG_ISDN_AUDIO
@@ -226,20 +313,20 @@
 					if (info->mcr & UART_MCR_RTS) {
 						c = TTY_FLIPBUF_SIZE - tty->flip.count;
 						if (c > 0) {
-                                                        save_flags(flags);
-                                                        cli();
+							save_flags(flags);
+							cli();
 							r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
-								      tty->flip.char_buf_ptr,
-								      tty->flip.flag_buf_ptr, c, 0);
-                                                        /* CISCO AsyncPPP Hack */
+									   tty->flip.char_buf_ptr,
+									   tty->flip.flag_buf_ptr, c, 0);
+							/* CISCO AsyncPPP Hack */
 							if (!(info->emu.mdmreg[12] & 128))
 								memset(tty->flip.flag_buf_ptr, 0, r);
 							tty->flip.count += r;
 							tty->flip.flag_buf_ptr += r;
 							tty->flip.char_buf_ptr += r;
 							if (r)
-								queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-                                                        restore_flags(flags);
+								queue_task(&tty->flip.tqueue, &tq_timer);
+							restore_flags(flags);
 						}
 					} else
 						r = 1;
@@ -251,257 +338,383 @@
 				} else
 					info->rcvsched = 1;
 			}
-                }
+		}
 	}
 	if (!resched)
 		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 }
 
-void isdn_tty_cleanup_xmit(modem_info *info)
+int
+isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
 {
-        struct sk_buff *skb;
-        unsigned long flags;
+	ulong flags;
+	int midx;
+#ifdef CONFIG_ISDN_AUDIO
+	int ifmt;
+#endif
+	modem_info *info;
 
-        save_flags(flags);
-        cli();
-        if (skb_queue_len(&info->xmit_queue))
-                while ((skb = skb_dequeue(&info->xmit_queue))) {
-                        skb->free = 1;
-                        kfree_skb(skb, FREE_WRITE);
-                }
-        if (skb_queue_len(&info->dtmf_queue))
-                while ((skb = skb_dequeue(&info->dtmf_queue))) {
-                        skb->free = 1;
-                        kfree_skb(skb, FREE_WRITE);
-                }
-        restore_flags(flags);
-}
-
-static void isdn_tty_tint(modem_info *info)
-{
-        struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
-        int len, slen;
-
-        if (!skb)
-                return;
-        len = skb->len;
-        if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
-                                         info->isdn_channel, skb)) == len) {
-                struct tty_struct *tty = info->tty;
-                info->send_outstanding++;
-                info->msr |= UART_MSR_CTS;
-                info->lsr |= UART_LSR_TEMT;
-                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                    tty->ldisc.write_wakeup)
-                        (tty->ldisc.write_wakeup) (tty);
-                wake_up_interruptible(&tty->write_wait);
-                return;
-        }
-        if (slen > 0)
-                skb_pull(skb,slen);
-        skb_queue_head(&info->xmit_queue, skb);
+	if ((midx = dev->m_idx[i]) < 0) {
+		/* if midx is invalid, packet is not for tty */
+		return 0;
+	}
+	info = &dev->mdm.info[midx];
+#ifdef CONFIG_ISDN_AUDIO
+	ifmt = 1;
+	
+	if (info->vonline)
+		isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
+#endif
+	if ((info->online < 2)
+#ifdef CONFIG_ISDN_AUDIO
+	    && (!(info->vonline & 1))
+#endif
+		) {
+		/* If Modem not listening, drop data */
+		SET_SKB_FREE(skb);
+		kfree_skb(skb, FREE_READ);
+		return 1;
+	}
+	if (info->emu.mdmreg[13] & 2)
+		/* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
+		if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
+			skb_pull(skb, 4);
+#ifdef CONFIG_ISDN_AUDIO
+	if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+		printk(KERN_WARNING
+		       "isdn_audio: insufficient skb_headroom, dropping\n");
+		SET_SKB_FREE(skb);
+		kfree_skb(skb, FREE_READ);
+		return 1;
+	}
+	ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+	ISDN_AUDIO_SKB_LOCK(skb) = 0;
+	if (info->vonline & 1) {
+		/* voice conversion/compression */
+		switch (info->emu.vpar[3]) {
+			case 2:
+			case 3:
+			case 4:
+				/* adpcm
+				 * Since compressed data takes less
+				 * space, we can overwrite the buffer.
+				 */
+				skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
+								    ifmt,
+								    skb->data,
+								    skb->data,
+								    skb->len));
+				break;
+			case 5:
+				/* a-law */
+				if (!ifmt)
+					isdn_audio_ulaw2alaw(skb->data, skb->len);
+				break;
+			case 6:
+				/* u-law */
+				if (ifmt)
+					isdn_audio_alaw2ulaw(skb->data, skb->len);
+				break;
+		}
+		ISDN_AUDIO_SKB_DLECOUNT(skb) =
+			isdn_tty_countDLE(skb->data, skb->len);
+	}
+#endif
+	/* Try to deliver directly via tty-flip-buf if queue is empty */
+	save_flags(flags);
+	cli();
+	if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+		if (isdn_tty_try_read(info, skb)) {
+			restore_flags(flags);
+			return 1;
+		}
+	/* Direct deliver failed or queue wasn't empty.
+	 * Queue up for later dequeueing via timer-irq.
+	 */
+	__skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
+	dev->drv[di]->rcvcount[channel] +=
+		(skb->len
+#ifdef CONFIG_ISDN_AUDIO
+		 + ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+			);
+	restore_flags(flags);
+	/* Schedule dequeuing */
+	if ((dev->modempoll) && (info->rcvsched))
+		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+	return 1;
 }
 
+void
+isdn_tty_cleanup_xmit(modem_info * info)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (skb_queue_len(&info->xmit_queue))
+		while ((skb = skb_dequeue(&info->xmit_queue))) {
+			SET_SKB_FREE(skb);
+			kfree_skb(skb, FREE_WRITE);
+		}
 #ifdef CONFIG_ISDN_AUDIO
-int isdn_tty_countDLE(unsigned char *buf, int len)
-{
-        int count = 0;
-
-        while (len--)
-                if (*buf++ == DLE)
-                        count++;
-        return count;
+	if (skb_queue_len(&info->dtmf_queue))
+		while ((skb = skb_dequeue(&info->dtmf_queue))) {
+			SET_SKB_FREE(skb);
+			kfree_skb(skb, FREE_WRITE);
+		}
+#endif
+	restore_flags(flags);
+}
+
+static void
+isdn_tty_tint(modem_info * info)
+{
+	struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
+	int len,
+	 slen;
+
+	if (!skb)
+		return;
+	len = skb->len;
+	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
+					   info->isdn_channel, skb)) == len) {
+		struct tty_struct *tty = info->tty;
+		info->send_outstanding++;
+		info->msr |= UART_MSR_CTS;
+		info->lsr |= UART_LSR_TEMT;
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup) (tty);
+		wake_up_interruptible(&tty->write_wait);
+		return;
+	}
+	if (slen < 0) {
+		/* Error: no channel, already shutdown, or wrong parameter */
+		SET_SKB_FREE(skb);
+		dev_kfree_skb(skb, FREE_WRITE);
+		return;
+	}
+	if (slen)
+		skb_pull(skb, slen);
+	skb_queue_head(&info->xmit_queue, skb);
+}
+
+#ifdef CONFIG_ISDN_AUDIO
+static int
+isdn_tty_countDLE(unsigned char *buf, int len)
+{
+	int count = 0;
+
+	while (len--)
+		if (*buf++ == DLE)
+			count++;
+	return count;
 }
 
 /* This routine is called from within isdn_tty_write() to perform
  * DLE-decoding when sending audio-data.
  */
-static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
+static int
+isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len)
 {
-        unsigned char *p = &info->xmit_buf[info->xmit_count];
-        int count = 0;
+	unsigned char *p = &info->xmit_buf[info->xmit_count];
+	int count = 0;
 
-        while (len>0) {
-                if (m->lastDLE) {
-                        m->lastDLE = 0;
-                        switch (*p) {
-                                case DLE:
-                                        /* Escape code */
-                                        if (len>1)
-                                                memmove(p,p+1,len-1);
-                                        p--;
-                                        count++;
-                                        break;
-                                case ETX:
-                                        /* End of data */
-                                        info->vonline |= 4;
-                                        return count;
-                                case DC4:
-                                        /* Abort RX */
-                                        info->vonline &= ~1;
-                                        isdn_tty_at_cout("\020\003", info);
-                                        if (!info->vonline)
-                                                isdn_tty_at_cout("\r\nVCON\r\n", info);
-                                        /* Fall through */
-                                case 'q':
-                                case 's':
-                                        /* Silence */
-                                        if (len>1)
-                                                memmove(p,p+1,len-1);
-                                        p--;
-                                        break;
-                        }
-                } else {
-                        if (*p == DLE)
-                                m->lastDLE = 1;
-                        else
-                                count++;
-                }
-                p++;
-                len--;
-        }
-        if (len<0) {
-                printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
-                return 0;
-        }
-        return count;
+	while (len > 0) {
+		if (m->lastDLE) {
+			m->lastDLE = 0;
+			switch (*p) {
+				case DLE:
+					/* Escape code */
+					if (len > 1)
+						memmove(p, p + 1, len - 1);
+					p--;
+					count++;
+					break;
+				case ETX:
+					/* End of data */
+					info->vonline |= 4;
+					return count;
+				case DC4:
+					/* Abort RX */
+					info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+					printk(KERN_DEBUG
+					       "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
+					       info->line);
+#endif
+					isdn_tty_at_cout("\020\003", info);
+					if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+						printk(KERN_DEBUG
+						       "DLEdown: send VCON on ttyI%d\n",
+						       info->line);
+#endif
+						isdn_tty_at_cout("\r\nVCON\r\n", info);
+					}
+					/* Fall through */
+				case 'q':
+				case 's':
+					/* Silence */
+					if (len > 1)
+						memmove(p, p + 1, len - 1);
+					p--;
+					break;
+			}
+		} else {
+			if (*p == DLE)
+				m->lastDLE = 1;
+			else
+				count++;
+		}
+		p++;
+		len--;
+	}
+	if (len < 0) {
+		printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
+		return 0;
+	}
+	return count;
 }
 
 /* This routine is called from within isdn_tty_write() when receiving
  * audio-data. It interrupts receiving, if an character other than
  * ^S or ^Q is sent.
  */
-static int isdn_tty_end_vrx(const char *buf, int c, int from_user)
+static int
+isdn_tty_end_vrx(const char *buf, int c, int from_user)
 {
-	char tmpbuf[VBUF];
-        char *p;
+	char ch;
 
-        if (c > VBUF) {
-                printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
-                return 1;
-        }
-	if (from_user) {
-		copy_from_user(tmpbuf, buf, c);
-                p = tmpbuf;
-        } else
-                p = (char *)buf;
-        while (c--) {
-                if ((*p != 0x11) && (*p != 0x13))
-                        return 1;
-                p++;
-        }
-        return 0;
+	while (c--) {
+		if (from_user)
+			GET_USER(ch, buf);
+		else
+			ch = *buf;
+		if ((ch != 0x11) && (ch != 0x13))
+			return 1;
+		buf++;
+	}
+	return 0;
 }
 
-static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 };
+static int voice_cf[7] =
+{0, 0, 4, 3, 2, 0, 0};
 
-#endif        /* CONFIG_ISDN_AUDIO */
+#endif                          /* CONFIG_ISDN_AUDIO */
 
 /* isdn_tty_senddown() is called either directly from within isdn_tty_write()
  * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
  * outgoing data from the tty's xmit-buffer, handles voice-decompression or
  * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
  */
-static void isdn_tty_senddown(modem_info * info)
+static void
+isdn_tty_senddown(modem_info * info)
 {
-        unsigned char *buf = info->xmit_buf;
-        int buflen;
-        int skb_res;
-        struct sk_buff *skb;
-        unsigned long flags;
-
-        save_flags(flags);
-        cli();
-        if (!(buflen = info->xmit_count)) {
-                restore_flags(flags);
-                return;
-        }
-        if (info->isdn_driver < 0) {
-                info->xmit_count = 0;
-                restore_flags(flags);
-                return;
-        }
-        skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
-#ifdef CONFIG_ISDN_AUDIO
-        if (info->vonline & 2) {
-                /* For now, ifmt is fixed to 1 (alaw), since this
-                 * is used with ISDN everywhere in the world, except
-                 * US, Canada and Japan.
-                 * Later, when US-ISDN protocols are implemented,
-                 * this setting will depend on the D-channel protocol.
-                 */
-                int ifmt = 1;
-                int skb_len;
-                unsigned char hbuf[VBUF];
-
-                memcpy(hbuf,info->xmit_buf,buflen);
-                info->xmit_count = 0;
-                restore_flags(flags);
-                /* voice conversion/decompression */
-                skb_len = buflen * voice_cf[info->emu.vpar[3]];
-                skb = dev_alloc_skb(skb_len + skb_res);
-                if (!skb) {
-                        printk(KERN_WARNING
-                               "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
-                        return;
-                }
-                skb_reserve(skb, skb_res);
-                switch (info->emu.vpar[3]) {
-                        case 2:
-                        case 3:
-                        case 4:
-                                /* adpcm, compatible to ZyXel 1496 modem
-                                 * with ROM revision 6.01
-                                 */
-                                buflen = isdn_audio_adpcm2xlaw(info->adpcms,
-                                                               ifmt,
-                                                               hbuf,
-                                                               skb_put(skb,skb_len),
-                                                               buflen);
-                                skb_trim(skb, buflen);
-                                break;
-                        case 5:
-                                /* a-law */
-                                if (!ifmt)
-                                        isdn_audio_alaw2ulaw(hbuf,buflen);
-                                memcpy(skb_put(skb,buflen),hbuf,buflen);
-                                break;
-                        case 6:
-                                /* u-law */
-                                if (ifmt)
-                                        isdn_audio_ulaw2alaw(hbuf,buflen);
-                                memcpy(skb_put(skb,buflen),hbuf,buflen);
-                                break;
-                }
-                if (info->vonline & 4) {
-                        info->vonline &= ~6;
-                        if (!info->vonline)
-                                isdn_tty_at_cout("\r\nVCON\r\n",info);
-                }
-        } else {
-#endif        /* CONFIG_ISDN_AUDIO */
-                skb = dev_alloc_skb(buflen + skb_res);
-                if (!skb) {
-                        printk(KERN_WARNING
-                               "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
-                        restore_flags(flags);
-                        return;
-                }
-                skb_reserve(skb, skb_res);
-                memcpy(skb_put(skb,buflen),buf,buflen);
-                info->xmit_count = 0;
-                restore_flags(flags);
-#ifdef CONFIG_ISDN_AUDIO
-        }
-#endif
-        skb->free = 1;
-        if (info->emu.mdmreg[13] & 2)
-                /* Add T.70 simplified header */
-                memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
-        skb_queue_tail(&info->xmit_queue, skb);
-        if ((info->emu.mdmreg[12] & 0x10) != 0)
-                info->msr &= UART_MSR_CTS;
-        info->lsr &= UART_LSR_TEMT;
+	int buflen;
+	int skb_res;
+#ifdef CONFIG_ISDN_AUDIO
+	int audio_len;
+#endif
+	struct sk_buff *skb;
+	unsigned long flags;
+
+#ifdef CONFIG_ISDN_AUDIO
+	if (info->vonline & 4) {
+		info->vonline &= ~6;
+		if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+			printk(KERN_DEBUG
+			       "senddown: send VCON on ttyI%d\n",
+			       info->line);
+#endif
+			isdn_tty_at_cout("\r\nVCON\r\n", info);
+		}
+	}
+#endif
+	save_flags(flags);
+	cli();
+	if (!(buflen = info->xmit_count)) {
+		restore_flags(flags);
+		return;
+	}
+	if ((info->emu.mdmreg[12] & 0x10) != 0)
+		info->msr &= ~UART_MSR_CTS;
+	info->lsr &= ~UART_LSR_TEMT;
+	if (info->isdn_driver < 0) {
+		info->xmit_count = 0;
+		restore_flags(flags);
+		return;
+	}
+	skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
+#ifdef CONFIG_ISDN_AUDIO
+	if (info->vonline & 2)
+		audio_len = buflen * voice_cf[info->emu.vpar[3]];
+	else
+		audio_len = 0;
+	skb = dev_alloc_skb(skb_res + buflen + audio_len);
+#else
+	skb = dev_alloc_skb(skb_res + buflen);
+#endif
+	if (!skb) {
+		restore_flags(flags);
+		printk(KERN_WARNING
+		       "isdn_tty: Out of memory in ttyI%d senddown\n",
+		       info->line);
+		return;
+	}
+	skb_reserve(skb, skb_res);
+	memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+	info->xmit_count = 0;
+	restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
+	if (info->vonline & 2) {
+		/* For now, ifmt is fixed to 1 (alaw), since this
+		 * is used with ISDN everywhere in the world, except
+		 * US, Canada and Japan.
+		 * Later, when US-ISDN protocols are implemented,
+		 * this setting will depend on the D-channel protocol.
+		 */
+		int ifmt = 1;
+
+		/* voice conversion/decompression */
+		switch (info->emu.vpar[3]) {
+			case 2:
+			case 3:
+			case 4:
+				/* adpcm, compatible to ZyXel 1496 modem
+				 * with ROM revision 6.01
+				 */
+				audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
+								  ifmt,
+								  skb->data,
+						    skb_put(skb, audio_len),
+								  buflen);
+				skb_pull(skb, buflen);
+				skb_trim(skb, audio_len);
+				break;
+			case 5:
+				/* a-law */
+				if (!ifmt)
+					isdn_audio_alaw2ulaw(skb->data,
+							     buflen);
+				break;
+			case 6:
+				/* u-law */
+				if (ifmt)
+					isdn_audio_ulaw2alaw(skb->data,
+							     buflen);
+				break;
+		}
+	}
+#endif                          /* CONFIG_ISDN_AUDIO */
+	SET_SKB_FREE(skb);
+	if (info->emu.mdmreg[13] & 2)
+		/* Add T.70 simplified header */
+		memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+	skb_queue_tail(&info->xmit_queue, skb);
 }
 
 /************************************************************
@@ -517,53 +730,55 @@
  * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
  * into the tty's flip-buffer.
  */
-static void isdn_tty_modem_do_ncarrier(unsigned long data)
+static void
+isdn_tty_modem_do_ncarrier(unsigned long data)
 {
-        modem_info * info = (modem_info *)data;
-        isdn_tty_modem_result(3, info);
+	modem_info *info = (modem_info *) data;
+	isdn_tty_modem_result(3, info);
 }
 
 /* Next routine is called, whenever the DTR-signal is raised.
  * It checks the ncarrier-flag, and triggers the above routine
  * when necessary. The ncarrier-flag is set, whenever DTR goes
  * low.
- */      
-static void isdn_tty_modem_ncarrier(modem_info * info)
+ */
+static void
+isdn_tty_modem_ncarrier(modem_info * info)
 {
-        if (info->ncarrier) {
-                info->ncarrier = 0;
-                info->nc_timer.expires = jiffies + HZ;
-                info->nc_timer.function = isdn_tty_modem_do_ncarrier;
-                info->nc_timer.data = (unsigned long)info;
-                add_timer(&info->nc_timer);
-        }
+	if (info->ncarrier) {
+		info->nc_timer.expires = jiffies + HZ;
+		info->nc_timer.function = isdn_tty_modem_do_ncarrier;
+		info->nc_timer.data = (unsigned long) info;
+		add_timer(&info->nc_timer);
+	}
 }
 
 /* isdn_tty_dial() performs dialing of a tty an the necessary
  * setup of the lower levels before that.
  */
-static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
+static void
+isdn_tty_dial(char *n, modem_info * info, atemu * m)
 {
-        int usg = ISDN_USAGE_MODEM;
-        int si = 7;
-        int l2 = m->mdmreg[14];
+	int usg = ISDN_USAGE_MODEM;
+	int si = 7;
+	int l2 = m->mdmreg[14];
 	isdn_ctrl cmd;
 	ulong flags;
 	int i;
-        int j;
+	int j;
 
-        for (j=7;j>=0;j--)
-                if (m->mdmreg[18] & (1<<j)) {
-                        si = bit2si[j];
-                        break;
-                }
-#ifdef CONFIG_ISDN_AUDIO
-                if (si == 1) {
-                        l2 = 4;
-                        usg = ISDN_USAGE_VOICE;
-                }
+	for (j = 7; j >= 0; j--)
+		if (m->mdmreg[18] & (1 << j)) {
+			si = bit2si[j];
+			break;
+		}
+#ifdef CONFIG_ISDN_AUDIO
+	if (si == 1) {
+		l2 = 4;
+		usg = ISDN_USAGE_VOICE;
+	}
 #endif
-        m->mdmreg[20] = si2bit[si];
+	m->mdmreg[20] = si2bit[si];
 	save_flags(flags);
 	cli();
 	i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1);
@@ -571,38 +786,44 @@
 		restore_flags(flags);
 		isdn_tty_modem_result(6, info);
 	} else {
-                info->isdn_driver = dev->drvmap[i];
-                info->isdn_channel = dev->chanmap[i];
-                info->drv_index = i;
-                dev->m_idx[i] = info->line;
-                dev->usage[i] |= ISDN_USAGE_OUTGOING;
-                isdn_info_update();
-                restore_flags(flags);
-                cmd.driver = info->isdn_driver;
-                cmd.arg = info->isdn_channel;
-                cmd.command = ISDN_CMD_CLREAZ;
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
-                cmd.driver = info->isdn_driver;
-                cmd.command = ISDN_CMD_SETEAZ;
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                cmd.driver = info->isdn_driver;
-                cmd.command = ISDN_CMD_SETL2;
-                cmd.arg = info->isdn_channel + (l2 << 8);
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                cmd.driver = info->isdn_driver;
-                cmd.command = ISDN_CMD_SETL3;
-                cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                cmd.driver = info->isdn_driver;
-                cmd.arg = info->isdn_channel;
-                sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver),
-                        si, m->mdmreg[19]);
-                cmd.command = ISDN_CMD_DIAL;
-                info->dialing = 1;
-                strcpy(dev->num[i], n);
-                isdn_info_update();
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
+		info->isdn_driver = dev->drvmap[i];
+		info->isdn_channel = dev->chanmap[i];
+		info->drv_index = i;
+		dev->m_idx[i] = info->line;
+		dev->usage[i] |= ISDN_USAGE_OUTGOING;
+		info->last_dir = 1;
+		strcpy(info->last_num, n);
+		isdn_info_update();
+		restore_flags(flags);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_CLREAZ;
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETEAZ;
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
+		info->last_l2 = l2;
+		cmd.arg = info->isdn_channel + (l2 << 8);
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		sprintf(cmd.parm.setup.phone, "%s", n);
+		sprintf(cmd.parm.setup.eazmsn, "%s",
+			isdn_map_eaz2msn(m->msn, info->isdn_driver));
+		cmd.parm.setup.si1 = si;
+		cmd.parm.setup.si2 = m->mdmreg[19];
+		cmd.command = ISDN_CMD_DIAL;
+		info->dialing = 1;
+		strcpy(dev->num[i], n);
+		isdn_info_update();
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
 	}
 }
 
@@ -610,64 +831,66 @@
  * ISDN-line (hangup). The usage-status is cleared
  * and some cleanup is done also.
  */
-void isdn_tty_modem_hup(modem_info * info)
+static void
+isdn_tty_modem_hup(modem_info * info, int local)
 {
 	isdn_ctrl cmd;
-        int usage;
+	int usage;
 
-        if (!info)
-                return;
+	if (!info)
+		return;
 #ifdef ISDN_DEBUG_MODEM_HUP
-        printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
+	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 #endif
-        info->rcvsched = 0;
-        info->online = 0;
-        isdn_tty_flush_buffer(info->tty);
-        if (info->vonline & 1) {
-                /* voice-recording, add DLE-ETX */
-                isdn_tty_at_cout("\020\003", info);
-        }
-        if (info->vonline & 2) {
-                /* voice-playing, add DLE-DC4 */
-                isdn_tty_at_cout("\020\024", info);
-        }
-        info->vonline = 0;
-#ifdef CONFIG_ISDN_AUDIO
-        if (info->dtmf_state) {
-                kfree(info->dtmf_state);
-                info->dtmf_state = NULL;
-        }
-        if (info->adpcms) {
-                kfree(info->adpcms);
-                info->adpcms = NULL;
-        }
-        if (info->adpcmr) {
-                kfree(info->adpcmr);
-                info->adpcmr = NULL;
-        }
+	info->rcvsched = 0;
+	isdn_tty_flush_buffer(info->tty);
+	if (info->online) {
+		info->last_lhup = local;
+		info->online = 0;
+		/* NO CARRIER message */
+		isdn_tty_modem_result(3, info);
+	}
+#ifdef CONFIG_ISDN_AUDIO
+	info->vonline = 0;
+	if (info->dtmf_state) {
+		kfree(info->dtmf_state);
+		info->dtmf_state = NULL;
+	}
+	if (info->adpcms) {
+		kfree(info->adpcms);
+		info->adpcms = NULL;
+	}
+	if (info->adpcmr) {
+		kfree(info->adpcmr);
+		info->adpcmr = NULL;
+	}
 #endif
-        info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
-        info->lsr |= UART_LSR_TEMT;
+	info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
+	info->lsr |= UART_LSR_TEMT;
 	if (info->isdn_driver >= 0) {
-		cmd.driver = info->isdn_driver;
-		cmd.command = ISDN_CMD_HANGUP;
-		cmd.arg = info->isdn_channel;
-		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		if (local) {
+			cmd.driver = info->isdn_driver;
+			cmd.command = ISDN_CMD_HANGUP;
+			cmd.arg = info->isdn_channel;
+			dev->drv[info->isdn_driver]->interface->command(&cmd);
+		}
 		isdn_all_eaz(info->isdn_driver, info->isdn_channel);
-                usage = (info->emu.mdmreg[20] == 1)?
-                        ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
+		info->emu.mdmreg[1] = 0;
+		usage = (info->emu.mdmreg[20] == 1) ?
+		    ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
 		isdn_free_channel(info->isdn_driver, info->isdn_channel,
-                                  usage);
+				  usage);
 	}
 	info->isdn_driver = -1;
 	info->isdn_channel = -1;
-        if (info->drv_index >= 0) {
-                dev->m_idx[info->drv_index] = -1;
-                info->drv_index = -1;
-        }
+	if (info->drv_index >= 0) {
+		dev->m_idx[info->drv_index] = -1;
+		info->drv_index = -1;
+	}
 }
 
-static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
+static inline int
+isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
 {
 #ifdef MODEM_PARANOIA_CHECK
 	if (!info) {
@@ -688,9 +911,13 @@
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static void isdn_tty_change_speed(modem_info * info)
+static void
+isdn_tty_change_speed(modem_info * info)
 {
-	uint cflag, cval, fcr, quot;
+	uint cflag,
+	 cval,
+	 fcr,
+	 quot;
 	int i;
 
 	if (!info->tty || !info->tty->termios)
@@ -707,19 +934,19 @@
 	}
 	if (quot) {
 		info->mcr |= UART_MCR_DTR;
-                isdn_tty_modem_ncarrier(info);                
+		isdn_tty_modem_ncarrier(info);
 	} else {
 		info->mcr &= ~UART_MCR_DTR;
-                if (info->emu.mdmreg[13] & 4) {
+		if (info->emu.mdmreg[13] & 4) {
 #ifdef ISDN_DEBUG_MODEM_HUP
-                        printk(KERN_DEBUG "Mhup in changespeed\n");
+			printk(KERN_DEBUG "Mhup in changespeed\n");
 #endif
-                        if (info->online)
-                                info->ncarrier = 1;
-                        isdn_tty_modem_reset_regs(info, 0);
-                        isdn_tty_modem_hup(info);
-                }
-                return;
+			if (info->online)
+				info->ncarrier = 1;
+			isdn_tty_modem_reset_regs(info, 0);
+			isdn_tty_modem_hup(info, 1);
+		}
+		return;
 	}
 	/* byte size and parity */
 	cval = cflag & (CSIZE | CSTOPB);
@@ -742,7 +969,8 @@
 	}
 }
 
-static int isdn_tty_startup(modem_info * info)
+static int
+isdn_tty_startup(modem_info * info)
 {
 	ulong flags;
 
@@ -750,12 +978,12 @@
 		return 0;
 	save_flags(flags);
 	cli();
-        isdn_MOD_INC_USE_COUNT();
+	isdn_MOD_INC_USE_COUNT();
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
 #endif
 	/*
-	 * Now, initialize the UART 
+	 * Now, initialize the UART
 	 */
 	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
 	if (info->tty)
@@ -776,7 +1004,8 @@
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void isdn_tty_shutdown(modem_info * info)
+static void
+isdn_tty_shutdown(modem_info * info)
 {
 	ulong flags;
 
@@ -786,17 +1015,18 @@
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 #endif
 	save_flags(flags);
-	cli();			/* Disable interrupts */
-        isdn_MOD_DEC_USE_COUNT();
+	cli();                  /* Disable interrupts */
+	isdn_MOD_DEC_USE_COUNT();
+	info->msr &= ~UART_MSR_RI;
 	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
-                if (info->emu.mdmreg[13] & 4) {
-                        isdn_tty_modem_reset_regs(info, 0);
+		if (info->emu.mdmreg[13] & 4) {
+			isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                        printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
+			printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
 #endif
-                        isdn_tty_modem_hup(info);
-                }
+			isdn_tty_modem_hup(info, 1);
+		}
 	}
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -814,9 +1044,11 @@
  *  - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
  *  - If dialing, abort dial.
  */
-static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
+static int
+isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
 {
-	int c, total = 0;
+	int c,
+	 total = 0;
 	ulong flags;
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -824,70 +1056,82 @@
 		return 0;
 	if (!tty)
 		return 0;
-        save_flags(flags);
-        cli();
+	save_flags(flags);
+	cli();
 	while (1) {
 		c = MIN(count, info->xmit_size - info->xmit_count);
 		if (info->isdn_driver >= 0)
 			c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
 		if (c <= 0)
 			break;
-                if ((info->online > 1) ||
-                    (info->vonline & 2)) {
-                        atemu *m = &info->emu;
-
-                        if (!(info->vonline & 2))
-                                isdn_tty_check_esc(buf, m->mdmreg[2], c,
-                                                   &(m->pluscount),
-                                                   &(m->lastplus),
-                                                   from_user);
-                        if (from_user)
-                                copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
-                        else
-                                memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
-#ifdef CONFIG_ISDN_AUDIO
-                        if (info->vonline & 2) {
-                                int cc;
-
-                                if (!(cc = isdn_tty_handleDLEdown(info,m,c))) {
-                                        /* If DLE decoding results in zero-transmit, but
-                                         * c originally was non-zero, do a wakeup.
-                                         */
-                                        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                                            tty->ldisc.write_wakeup)
-                                                (tty->ldisc.write_wakeup) (tty);
-                                        wake_up_interruptible(&tty->write_wait);
-                                        info->msr |= UART_MSR_CTS;
-                                        info->lsr |= UART_LSR_TEMT;
-                                }
-                                info->xmit_count += cc;
-                        } else
+		if ((info->online > 1)
+#ifdef CONFIG_ISDN_AUDIO
+		    || (info->vonline & 3)
 #endif
-                                info->xmit_count += c;
-			if (m->mdmreg[13] & 1) {
-                                isdn_tty_senddown(info);
-                                isdn_tty_tint(info);
-                        }
-		} else {
-                        info->msr |= UART_MSR_CTS;
-                        info->lsr |= UART_LSR_TEMT;
+			) {
+			atemu *m = &info->emu;
+
 #ifdef CONFIG_ISDN_AUDIO
-                        if (info->vonline & 1) {
-                                if (isdn_tty_end_vrx(buf, c, from_user)) {
-                                        info->vonline &= ~1;
-                                        isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
-                                }
-                        } else
+			if (!info->vonline)
+#endif
+				isdn_tty_check_esc(buf, m->mdmreg[2], c,
+						   &(m->pluscount),
+						   &(m->lastplus),
+						   from_user);
+			if (from_user)
+				copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
+			else
+				memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+#ifdef CONFIG_ISDN_AUDIO
+			if (info->vonline) {
+				int cc = isdn_tty_handleDLEdown(info, m, c);
+				if (info->vonline & 2) {
+					if (!cc) {
+						/* If DLE decoding results in zero-transmit, but
+						 * c originally was non-zero, do a wakeup.
+						 */
+						if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+						 tty->ldisc.write_wakeup)
+							(tty->ldisc.write_wakeup) (tty);
+						wake_up_interruptible(&tty->write_wait);
+						info->msr |= UART_MSR_CTS;
+						info->lsr |= UART_LSR_TEMT;
+					}
+					info->xmit_count += cc;
+				}
+				if ((info->vonline & 3) == 1) {
+					/* Do NOT handle Ctrl-Q or Ctrl-S
+					 * when in full-duplex audio mode.
+					 */
+					if (isdn_tty_end_vrx(buf, c, from_user)) {
+						info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+						printk(KERN_DEBUG
+						       "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
+						       info->line);
+#endif
+						isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
+					}
+				}
+			} else
 #endif
-                                if (info->dialing) {
-                                        info->dialing = 0;
+				info->xmit_count += c;
+			if (m->mdmreg[13] & 1) {
+				isdn_tty_senddown(info);
+				isdn_tty_tint(info);
+			}
+		} else {
+			info->msr |= UART_MSR_CTS;
+			info->lsr |= UART_LSR_TEMT;
+			if (info->dialing) {
+				info->dialing = 0;
 #ifdef ISDN_DEBUG_MODEM_HUP
-                                        printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
+				printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
 #endif
-                                        isdn_tty_modem_result(3, info);
-                                        isdn_tty_modem_hup(info);
-                                } else
-                                        c = isdn_tty_edit_at(buf, c, info, from_user);
+				isdn_tty_modem_result(3, info);
+				isdn_tty_modem_hup(info, 1);
+			} else
+				c = isdn_tty_edit_at(buf, c, info, from_user);
 		}
 		buf += c;
 		count -= c;
@@ -895,11 +1139,12 @@
 	}
 	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
 		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
-        restore_flags(flags);
+	restore_flags(flags);
 	return total;
 }
 
-static int isdn_tty_write_room(struct tty_struct *tty)
+static int
+isdn_tty_write_room(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 	int ret;
@@ -912,7 +1157,8 @@
 	return (ret < 0) ? 0 : ret;
 }
 
-static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
+static int
+isdn_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -923,32 +1169,34 @@
 	return (info->xmit_count);
 }
 
-static void isdn_tty_flush_buffer(struct tty_struct *tty)
+static void
+isdn_tty_flush_buffer(struct tty_struct *tty)
 {
 	modem_info *info;
-        unsigned long flags;
+	unsigned long flags;
 
-        save_flags(flags);
-        cli();
-        if (!tty) {
-                restore_flags(flags);
-                return;
-        }
-        info =  (modem_info *) tty->driver_data;
+	save_flags(flags);
+	cli();
+	if (!tty) {
+		restore_flags(flags);
+		return;
+	}
+	info = (modem_info *) tty->driver_data;
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) {
-                restore_flags(flags);
+		restore_flags(flags);
 		return;
-        }
-        isdn_tty_cleanup_xmit(info);
-        info->xmit_count = 0;
-        restore_flags(flags);
+	}
+	isdn_tty_cleanup_xmit(info);
+	info->xmit_count = 0;
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup) (tty);
 }
 
-static void isdn_tty_flush_chars(struct tty_struct *tty)
+static void
+isdn_tty_flush_chars(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -961,12 +1209,13 @@
 /*
  * ------------------------------------------------------------
  * isdn_tty_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
  */
-static void isdn_tty_throttle(struct tty_struct *tty)
+static void
+isdn_tty_throttle(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -977,7 +1226,8 @@
 	info->mcr &= ~UART_MCR_RTS;
 }
 
-static void isdn_tty_unthrottle(struct tty_struct *tty)
+static void
+isdn_tty_unthrottle(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -1006,9 +1256,10 @@
  *          release the bus after transmitting. This must be done when
  *          the transmit shift register is empty, not be done when the
  *          transmit holding register is empty.  This functionality
- *          allows RS485 driver to be written in user space. 
+ *          allows RS485 driver to be written in user space.
  */
-static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
+static int
+isdn_tty_get_lsr_info(modem_info * info, uint * value)
 {
 	u_char status;
 	uint result;
@@ -1024,9 +1275,11 @@
 }
 
 
-static int isdn_tty_get_modem_info(modem_info * info, uint * value)
+static int
+isdn_tty_get_modem_info(modem_info * info, uint * value)
 {
-	u_char control, status;
+	u_char control,
+	 status;
 	uint result;
 	ulong flags;
 
@@ -1045,76 +1298,78 @@
 	return 0;
 }
 
-static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
+static int
+isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
 {
 	uint arg;
-        int pre_dtr;
+	int pre_dtr;
 
-    GET_USER(arg, (uint *)value);
+	GET_USER(arg, (uint *) value);
 	switch (cmd) {
-                case TIOCMBIS:
+		case TIOCMBIS:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
 #endif
-                        if (arg & TIOCM_RTS) {
-                                info->mcr |= UART_MCR_RTS;
-                        }
-                        if (arg & TIOCM_DTR) {
-                                info->mcr |= UART_MCR_DTR;
-                                isdn_tty_modem_ncarrier(info);
-                        }
-                        break;
-                case TIOCMBIC:
+			if (arg & TIOCM_RTS) {
+				info->mcr |= UART_MCR_RTS;
+			}
+			if (arg & TIOCM_DTR) {
+				info->mcr |= UART_MCR_DTR;
+				isdn_tty_modem_ncarrier(info);
+			}
+			break;
+		case TIOCMBIC:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
 #endif
-                        if (arg & TIOCM_RTS) {
-                                info->mcr &= ~UART_MCR_RTS;
-                        }
-                        if (arg & TIOCM_DTR) {
-                                info->mcr &= ~UART_MCR_DTR;
-                                if (info->emu.mdmreg[13] & 4) {
-                                        isdn_tty_modem_reset_regs(info, 0);
+			if (arg & TIOCM_RTS) {
+				info->mcr &= ~UART_MCR_RTS;
+			}
+			if (arg & TIOCM_DTR) {
+				info->mcr &= ~UART_MCR_DTR;
+				if (info->emu.mdmreg[13] & 4) {
+					isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                                        printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
+					printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
 #endif
-                                        if (info->online)
-                                                info->ncarrier = 1;
-                                        isdn_tty_modem_hup(info);
-                                }
-                        }
-                        break;
-                case TIOCMSET:
+					if (info->online)
+						info->ncarrier = 1;
+					isdn_tty_modem_hup(info, 1);
+				}
+			}
+			break;
+		case TIOCMSET:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
 #endif
-                        pre_dtr = (info->mcr & UART_MCR_DTR);
-                        info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
-                                     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-                                     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-                        if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
-                                if (!(info->mcr & UART_MCR_DTR)) {
-                                        if (info->emu.mdmreg[13] & 4) {
-                                                isdn_tty_modem_reset_regs(info, 0);
+			pre_dtr = (info->mcr & UART_MCR_DTR);
+			info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
+				 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+			       | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+			if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
+				if (!(info->mcr & UART_MCR_DTR)) {
+					if (info->emu.mdmreg[13] & 4) {
+						isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                                                printk(KERN_DEBUG "Mhup in TIOCMSET\n");
+						printk(KERN_DEBUG "Mhup in TIOCMSET\n");
 #endif
-                                                if (info->online)
-                                                        info->ncarrier = 1;
-                                                isdn_tty_modem_hup(info);
-                                        }
-                                } else
-                                        isdn_tty_modem_ncarrier(info);
-                        }
-                        break;
-                default:
-                        return -EINVAL;
+						if (info->online)
+							info->ncarrier = 1;
+						isdn_tty_modem_hup(info, 1);
+					}
+				} else
+					isdn_tty_modem_ncarrier(info);
+			}
+			break;
+		default:
+			return -EINVAL;
 	}
 	return 0;
 }
 
-static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
-		       uint cmd, ulong arg)
+static int
+isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
+	       uint cmd, ulong arg)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 	int error;
@@ -1122,97 +1377,98 @@
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
 		return -ENODEV;
-        if (tty->flags & (1 << TTY_IO_ERROR))
-                return -EIO;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 	switch (cmd) {
-                case TCSBRK:		/* SVID version: non-zero arg --> no break */
+		case TCSBRK:   /* SVID version: non-zero arg --> no break */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
 #endif
-                        retval = tty_check_change(tty);
-                        if (retval)
-                                return retval;
-                        tty_wait_until_sent(tty, 0);
-                        return 0;
-                case TCSBRKP:		/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			return 0;
+		case TCSBRKP:  /* support for POSIX tcsendbreak() */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
 #endif
-                        retval = tty_check_change(tty);
-                        if (retval)
-                                return retval;
-                        tty_wait_until_sent(tty, 0);
-                        return 0;
-                case TIOCGSOFTCAR:
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			return 0;
+		case TIOCGSOFTCAR:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
 #endif
-                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-                        if (error)
-                                return error;
-                        put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
-                        return 0;
-                case TIOCSSOFTCAR:
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+			if (error)
+				return error;
+			put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
 #endif
-                        error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
-                        if (error)
-                                return error;
-                        GET_USER(arg, (ulong *) arg);
-                        tty->termios->c_cflag =
-                                ((tty->termios->c_cflag & ~CLOCAL) |
-                                 (arg ? CLOCAL : 0));
-                        return 0;
-                case TIOCMGET:
+			error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+			if (error)
+				return error;
+			GET_USER(arg, (ulong *) arg);
+			tty->termios->c_cflag =
+			    ((tty->termios->c_cflag & ~CLOCAL) |
+			     (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCMGET:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
 #endif
-                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-                        if (error)
-                                return error;
-                        return isdn_tty_get_modem_info(info, (uint *) arg);
-                case TIOCMBIS:
-                case TIOCMBIC:
-                case TIOCMSET:
-                        error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
-                        if (error)
-                                return error;
-                        return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
-                case TIOCSERGETLSR:	/* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			return isdn_tty_get_modem_info(info, (uint *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
+		case TIOCSERGETLSR:	/* Get line status register */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
+			printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
 #endif
-                        error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-                        if (error)
-                                return error;
-                        else
-                                return isdn_tty_get_lsr_info(info, (uint *) arg);
-                        
-                default:
+			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+			if (error)
+				return error;
+			else
+				return isdn_tty_get_lsr_info(info, (uint *) arg);
+
+		default:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
+			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
 #endif
-                        return -ENOIOCTLCMD;
+			return -ENOIOCTLCMD;
 	}
 	return 0;
 }
 
-static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void
+isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
-        if (!old_termios)
-                isdn_tty_change_speed(info);
-        else {
-                if (tty->termios->c_cflag == old_termios->c_cflag)
-                        return;
-                isdn_tty_change_speed(info);
-                if ((old_termios->c_cflag & CRTSCTS) &&
-                    !(tty->termios->c_cflag & CRTSCTS)) {
-                        tty->hw_stopped = 0;
-                }
-        }
+	if (!old_termios)
+		isdn_tty_change_speed(info);
+	else {
+		if (tty->termios->c_cflag == old_termios->c_cflag)
+			return;
+		isdn_tty_change_speed(info);
+		if ((old_termios->c_cflag & CRTSCTS) &&
+		    !(tty->termios->c_cflag & CRTSCTS)) {
+			tty->hw_stopped = 0;
+		}
+	}
 }
 
 /*
@@ -1220,9 +1476,11 @@
  * isdn_tty_open() and friends
  * ------------------------------------------------------------
  */
-static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
+static int
+isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
 {
-	struct wait_queue wait = {current, NULL};
+	struct wait_queue wait =
+	{current, NULL};
 	int do_clocal = 0;
 	unsigned long flags;
 	int retval;
@@ -1233,8 +1491,8 @@
 	 */
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ISDN_ASYNC_CLOSING)) {
-                if (info->flags & ISDN_ASYNC_CLOSING)
-                        interruptible_sleep_on(&info->close_wait);
+		if (info->flags & ISDN_ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
 #ifdef MODEM_DO_RESTART
 		if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
@@ -1267,7 +1525,7 @@
 	 * and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
-            (tty->flags & (1 << TTY_IO_ERROR))) {
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
 		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
 			return -EBUSY;
 		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
@@ -1293,11 +1551,11 @@
 	printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
 	       info->line, info->count);
 #endif
-        save_flags(flags);
-        cli();
-        if (!(tty_hung_up_p(filp)))
-                info->count--;
-        restore_flags(flags);
+	save_flags(flags);
+	cli();
+	if (!(tty_hung_up_p(filp)))
+		info->count--;
+	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
@@ -1349,10 +1607,12 @@
  * the IRQ chain.   It also performs the serial-specific
  * initialization for the tty structure.
  */
-static int isdn_tty_open(struct tty_struct *tty, struct file *filp)
+static int
+isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info;
-	int retval, line;
+	int retval,
+	 line;
 
 	line = MINOR(tty->device) - tty->driver.minor_start;
 	if (line < 0 || line > ISDN_MAX_CHANNELS)
@@ -1403,7 +1663,8 @@
 	return 0;
 }
 
-static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
+static void
+isdn_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 	ulong flags;
@@ -1454,7 +1715,7 @@
 	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
 
-        tty->closing = 1;
+	tty->closing = 1;
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
@@ -1462,7 +1723,7 @@
 	 * line status register.
 	 */
 	if (info->flags & ISDN_ASYNC_INITIALIZED) {
-		tty_wait_until_sent(tty, 3000);		/* 30 seconds timeout */
+		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -1484,12 +1745,12 @@
 	if (tty->ldisc.flush_buffer)
 		tty->ldisc.flush_buffer(tty);
 	info->tty = 0;
-        info->ncarrier = 0;
+	info->ncarrier = 0;
 	tty->closing = 0;
 	if (info->blocked_open) {
-                current->state = TASK_INTERRUPTIBLE;
-                current->timeout = jiffies + 50;
-                schedule();
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 50;
+		schedule();
 		wake_up_interruptible(&info->open_wait);
 	}
 	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
@@ -1504,7 +1765,8 @@
 /*
  * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
-static void isdn_tty_hangup(struct tty_struct *tty)
+static void
+isdn_tty_hangup(struct tty_struct *tty)
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 
@@ -1519,7 +1781,8 @@
 
 /* This routine initializes all emulator-data.
  */
-static void isdn_tty_reset_profile(atemu * m)
+static void
+isdn_tty_reset_profile(atemu * m)
 {
 	m->profile[0] = 0;
 	m->profile[1] = 0;
@@ -1545,27 +1808,34 @@
 	m->pmsn[0] = '\0';
 }
 
-static void isdn_tty_modem_reset_vpar(atemu *m)
+#ifdef CONFIG_ISDN_AUDIO
+static void
+isdn_tty_modem_reset_vpar(atemu * m)
 {
-        m->vpar[0] = 2;  /* Voice-device            (2 = phone line) */
-        m->vpar[1] = 0;  /* Silence detection level (0 = none      ) */
-        m->vpar[2] = 70; /* Silence interval        (7 sec.        ) */
-        m->vpar[3] = 2;  /* Compression type        (1 = ADPCM-2   ) */
+	m->vpar[0] = 2;         /* Voice-device            (2 = phone line) */
+	m->vpar[1] = 0;         /* Silence detection level (0 = none      ) */
+	m->vpar[2] = 70;        /* Silence interval        (7 sec.        ) */
+	m->vpar[3] = 2;         /* Compression type        (1 = ADPCM-2   ) */
 }
+#endif
 
-static void isdn_tty_modem_reset_regs(modem_info *info, int force)
+static void
+isdn_tty_modem_reset_regs(modem_info * info, int force)
 {
-        atemu *m = &info->emu;
+	atemu *m = &info->emu;
 	if ((m->mdmreg[12] & 32) || force) {
 		memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
 		memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
-                info->xmit_size = m->mdmreg[16] * 16;
+		info->xmit_size = m->mdmreg[16] * 16;
 	}
-        isdn_tty_modem_reset_vpar(m);
+#ifdef CONFIG_ISDN_AUDIO
+	isdn_tty_modem_reset_vpar(m);
+#endif
 	m->mdmcmdl = 0;
 }
 
-static void modem_write_profile(atemu * m)
+static void
+modem_write_profile(atemu * m)
 {
 	memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
 	memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
@@ -1573,7 +1843,8 @@
 		send_sig(SIGIO, dev->profd, 1);
 }
 
-int isdn_tty_modem_init(void)
+int
+isdn_tty_modem_init(void)
 {
 	modem *m;
 	int i;
@@ -1630,6 +1901,12 @@
 	}
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		info = &m->info[i];
+		sprintf(info->last_cause, "0000");
+		sprintf(info->last_num, "none");
+		info->last_dir = 0;
+		info->last_lhup = 1;
+		info->last_l2 = 0;
+		info->last_si = 0;
 		isdn_tty_reset_profile(&info->emu);
 		isdn_tty_modem_reset_regs(info, 1);
 		info->magic = ISDN_ASYNC_MAGIC;
@@ -1646,14 +1923,16 @@
 		info->isdn_channel = -1;
 		info->drv_index = -1;
 		info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
-                skb_queue_head_init(&info->xmit_queue);
-                skb_queue_head_init(&info->dtmf_queue);
-                if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
-                        printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
-                        return -3;
-                }
-                /* Make room for T.70 header */
-                info->xmit_buf += 4;
+		skb_queue_head_init(&info->xmit_queue);
+#ifdef CONFIG_ISDN_AUDIO
+		skb_queue_head_init(&info->dtmf_queue);
+#endif
+		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
+			return -3;
+		}
+		/* Make room for T.70 header */
+		info->xmit_buf += 4;
 	}
 	return 0;
 }
@@ -1664,61 +1943,46 @@
  * it to the ISDN-Channel.
  * Return Index to dev->mdm or -1 if none found.
  */
-int isdn_tty_find_icall(int di, int ch, char *num)
+int
+isdn_tty_find_icall(int di, int ch, setup_parm setup)
 {
 	char *eaz;
 	int i;
 	int idx;
 	int si1;
 	int si2;
-	char *s;
-	char nr[31];
+	char nr[32];
 	ulong flags;
 
 	save_flags(flags);
 	cli();
-	if (num[0] == ',') {
+	if (!setup.phone[0]) {
 		nr[0] = '0';
-		strncpy(&nr[1], num, 29);
+		nr[1] = '\0';
 		printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
 	} else
-		strncpy(nr, num, 30);
-	s = strtok(nr, ",");
-	s = strtok(NULL, ",");
-	if (!s) {
-		printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
-		       num);
-		restore_flags(flags);
-		return -1;
-	}
-	si1 = (int)simple_strtoul(s,NULL,10);
-	s = strtok(NULL, ",");
-	if (!s) {
-		printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
-		       num);
-		restore_flags(flags);
-		return -1;
-	}
-	si2 = (int)simple_strtoul(s,NULL,10);
-	eaz = strtok(NULL, ",");
-	if (!eaz) {
+		strcpy(nr, setup.phone);
+	si1 = (int) setup.si1;
+	si2 = (int) setup.si2;
+	if (!setup.eazmsn[0]) {
 		printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
 		eaz = "0";
-	}
+	} else
+		eaz = setup.eazmsn;
 #ifdef ISDN_DEBUG_MODEM_ICALL
 	printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
 #endif
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                modem_info *info = &dev->mdm.info[i];
+		modem_info *info = &dev->mdm.info[i];
 #ifdef ISDN_DEBUG_MODEM_ICALL
 		printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
 		       info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
 		       info->emu.mdmreg[18], info->emu.mdmreg[19]);
 #endif
 		if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
-                             eaz)) &&                             /* EAZ is matching      */
-		    (info->emu.mdmreg[18] & si2bit[si1]) &&       /* SI1 is matching      */
-		    ((info->emu.mdmreg[19] == si2) || !si2)) {    /* SI2 is matching or 0 */
+			     eaz)) &&	/* EAZ is matching      */
+		    (info->emu.mdmreg[18] & si2bit[si1]) &&	/* SI1 is matching      */
+		    ((info->emu.mdmreg[19] == si2) || !si2)) {	/* SI2 is matching or 0 */
 			idx = isdn_dc2minor(di, ch);
 #ifdef ISDN_DEBUG_MODEM_ICALL
 			printk(KERN_DEBUG "m_fi: match1\n");
@@ -1735,13 +1999,18 @@
 				info->drv_index = idx;
 				dev->m_idx[idx] = info->line;
 				dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
-				dev->usage[idx] |= (si1==1)?ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
+				dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
 				strcpy(dev->num[idx], nr);
-                                info->emu.mdmreg[20] = si2bit[si1];
+				info->emu.mdmreg[20] = si2bit[si1];
+				info->emu.mdmreg[21] = setup.plan;
+				info->emu.mdmreg[22] = setup.screen;
 				isdn_info_update();
 				restore_flags(flags);
 				printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
 				       info->line);
+				info->msr |= UART_MSR_RI;
+				isdn_tty_modem_result(2, info);
+				isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
 				return info->line;
 			}
 		}
@@ -1752,6 +2021,140 @@
 	return -1;
 }
 
+#define TTY_IS_ACTIVE(info) \
+	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+
+int
+isdn_tty_stat_callback(int i, isdn_ctrl * c)
+{
+	int mi;
+	modem_info *info;
+
+	if (i < 0)
+		return 0;
+	if ((mi = dev->m_idx[i]) >= 0) {
+		info = &dev->mdm.info[mi];
+		switch (c->command) {
+			case ISDN_STAT_BSENT:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
+#endif
+				if ((info->isdn_driver == c->driver) &&
+				    (info->isdn_channel == c->arg)) {
+					info->msr |= UART_MSR_CTS;
+					if (info->send_outstanding)
+						if (!(--info->send_outstanding))
+							info->lsr |= UART_LSR_TEMT;
+					isdn_tty_tint(info);
+					return 1;
+				}
+				break;
+			case ISDN_STAT_CAUSE:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
+#endif
+				/* Signal cause to tty-device */
+				strncpy(info->last_cause, c->parm.num, 5);
+				return 1;
+			case ISDN_STAT_DCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
+#endif
+				if (TTY_IS_ACTIVE(info)) {
+					if (info->dialing == 1) {
+						info->dialing = 2;
+						return 1;
+					}
+				}
+				break;
+			case ISDN_STAT_DHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
+#endif
+				if (TTY_IS_ACTIVE(info)) {
+					if (info->dialing == 1) {
+						info->dialing = 0;
+						isdn_tty_modem_result(7, info);
+					}
+#ifdef ISDN_DEBUG_MODEM_HUP
+					printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+#endif
+					isdn_tty_modem_hup(info, 0);
+					return 1;
+				}
+				break;
+			case ISDN_STAT_BCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
+#endif
+				/* Schedule CONNECT-Message to any tty
+				 * waiting for it and
+				 * set DCD-bit of its modem-status.
+				 */
+				if (TTY_IS_ACTIVE(info)) {
+					info->msr |= UART_MSR_DCD;
+					if (info->dialing) {
+						info->dialing = 0;
+						info->last_dir = 1;
+					} else
+						info->last_dir = 0;
+					info->rcvsched = 1;
+					if (USG_MODEM(dev->usage[i]))
+						isdn_tty_modem_result(5, info);
+					if (USG_VOICE(dev->usage[i]))
+						isdn_tty_modem_result(11, info);
+					return 1;
+				}
+				break;
+			case ISDN_STAT_BHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
+#endif
+				if (TTY_IS_ACTIVE(info)) {
+#ifdef ISDN_DEBUG_MODEM_HUP
+					printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
+#endif
+					isdn_tty_modem_hup(info, 0);
+					return 1;
+				}
+				break;
+			case ISDN_STAT_NODCH:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
+#endif
+				if (TTY_IS_ACTIVE(info)) {
+					if (info->dialing) {
+						info->dialing = 0;
+						info->last_l2 = -1;
+						info->last_si = 0;
+						sprintf(info->last_cause, "0000");
+						isdn_tty_modem_result(6, info);
+					}
+					info->msr &= ~UART_MSR_DCD;
+					if (info->online) {
+						isdn_tty_modem_result(3, info);
+						info->online = 0;
+					}
+					return 1;
+				}
+				break;
+			case ISDN_STAT_UNLOAD:
+#ifdef ISDN_TTY_STAT_DEBUG
+				printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
+#endif
+				for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+					info = &dev->mdm.info[i];
+					if (info->isdn_driver == c->driver) {
+						if (info->online)
+							isdn_tty_modem_hup(info, 1);
+					}
+				}
+				return 1;
+		}
+	}
+	return 0;
+}
+
 /*********************************************************************
  Modem-Emulator-Routines
  *********************************************************************/
@@ -1762,7 +2165,8 @@
  * Put a message from the AT-emulator into receive-buffer of tty,
  * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
  */
-static void isdn_tty_at_cout(char *msg, modem_info * info)
+static void
+isdn_tty_at_cout(char *msg, modem_info * info)
 {
 	struct tty_struct *tty;
 	atemu *m = &info->emu;
@@ -1779,17 +2183,17 @@
 	tty = info->tty;
 	for (p = msg; *p; p++) {
 		switch (*p) {
-                        case '\r':
-                                c = m->mdmreg[3];
-                                break;
-                        case '\n':
-                                c = m->mdmreg[4];
-                                break;
-                        case '\b':
-                                c = m->mdmreg[5];
-                                break;
-                        default:
-                                c = *p;
+			case '\r':
+				c = m->mdmreg[3];
+				break;
+			case '\n':
+				c = m->mdmreg[4];
+				break;
+			case '\b':
+				c = m->mdmreg[5];
+				break;
+			default:
+				c = *p;
 		}
 		if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
 			restore_flags(flags);
@@ -1806,24 +2210,25 @@
 /*
  * Perform ATH Hangup
  */
-static void isdn_tty_on_hook(modem_info * info)
+static void
+isdn_tty_on_hook(modem_info * info)
 {
 	if (info->isdn_channel >= 0) {
 #ifdef ISDN_DEBUG_MODEM_HUP
 		printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
 #endif
-		isdn_tty_modem_result(3, info);
-		isdn_tty_modem_hup(info);
+		isdn_tty_modem_hup(info, 1);
 	}
 }
 
-static void isdn_tty_off_hook(void)
+static void
+isdn_tty_off_hook(void)
 {
 	printk(KERN_DEBUG "isdn_tty_off_hook\n");
 }
 
-#define PLUSWAIT1 (HZ/2)	/* 0.5 sec. */
-#define PLUSWAIT2 (HZ*3/2)	/* 1.5 sec */
+#define PLUSWAIT1 (HZ/2)        /* 0.5 sec. */
+#define PLUSWAIT2 (HZ*3/2)      /* 1.5 sec */
 
 /*
  * Check Buffer for Modem-escape-sequence, activate timer-callback to
@@ -1836,8 +2241,9 @@
  *   pluscount  count of valid escape-characters so far
  *   lastplus   timestamp of last character
  */
-static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
-			   int *lastplus, int from_user)
+static void
+isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
+		   int *lastplus, int from_user)
 {
 	char cbuf[3];
 
@@ -1880,7 +2286,8 @@
  * For CONNECT-messages also switch to online-mode.
  * For RING-message handle auto-ATA if register 0 != 0
  */
-void isdn_tty_modem_result(int code, modem_info * info)
+static void
+isdn_tty_modem_result(int code, modem_info * info)
 {
 	atemu *m = &info->emu;
 	static char *msg[] =
@@ -1888,47 +2295,66 @@
 	 "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
 	 "RINGING", "NO MSN/EAZ", "VCON"};
 	ulong flags;
-	char s[4];
+	char s[10];
 
 	switch (code) {
-                case 2:
-                        m->mdmreg[1]++;	/* RING */
-                        if (m->mdmreg[1] == m->mdmreg[0])
-                                /* Automatically accept incoming call */
-                                isdn_tty_cmd_ATA(info);
-                        break;
-                case 3:
-                        /* NO CARRIER */
-                        save_flags(flags);
-                        cli();
+		case 2:
+			m->mdmreg[1]++;	/* RING */
+			if (m->mdmreg[1] == m->mdmreg[0])
+				/* Automatically accept incoming call */
+				isdn_tty_cmd_ATA(info);
+			break;
+		case 3:
+			/* NO CARRIER */
 #ifdef ISDN_DEBUG_MODEM_HUP
-                        printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
-                               (info->flags & ISDN_ASYNC_CLOSING),
-                               (!info->tty));
-#endif
-                        if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
-                                restore_flags(flags);
-                                return;
-                        }
-                        restore_flags(flags);
-                        if (info->vonline & 1) {
-                                /* voice-recording, add DLE-ETX */
-                                isdn_tty_at_cout("\020\003", info);
-                        }
-                        if (info->vonline & 2) {
-                                /* voice-playing, add DLE-DC4 */
-                                isdn_tty_at_cout("\020\024", info);
-                        }
-                        break;
-                case 1:
-                case 5:
-                        if (!info->online)
-                                info->online = 2;
-                        break;
-                case 11:
-                        if (!info->online)
-                                info->online = 1;
-                        break;
+			printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
+			       (info->flags & ISDN_ASYNC_CLOSING),
+			       (!info->tty));
+#endif
+			save_flags(flags);
+			cli();
+			m->mdmreg[1] = 0;
+			del_timer(&info->nc_timer);
+			info->ncarrier = 0;
+			if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+				restore_flags(flags);
+				return;
+			}
+			restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
+			if (info->vonline & 1) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+				printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
+				       info->line);
+#endif
+				/* voice-recording, add DLE-ETX */
+				isdn_tty_at_cout("\020\003", info);
+			}
+			if (info->vonline & 2) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+				printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
+				       info->line);
+#endif
+				/* voice-playing, add DLE-DC4 */
+				isdn_tty_at_cout("\020\024", info);
+			}
+#endif
+			break;
+		case 1:
+		case 5:
+			sprintf(info->last_cause, "0000");
+			if (!info->online)
+				info->online = 2;
+			break;
+		case 11:
+#ifdef ISDN_DEBUG_MODEM_VOICE
+			printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
+			       info->line);
+#endif
+			sprintf(info->last_cause, "0000");
+			if (!info->online)
+				info->online = 1;
+			break;
 	}
 	if (m->mdmreg[12] & 1) {
 		/* Show results */
@@ -1938,17 +2364,38 @@
 			sprintf(s, "%d", code);
 			isdn_tty_at_cout(s, info);
 		} else {
-			if (code == 2) {
+			if ((code == 2) && (!(m->mdmreg[13] & 16))) {
 				isdn_tty_at_cout("CALLER NUMBER: ", info);
 				isdn_tty_at_cout(dev->num[info->drv_index], info);
 				isdn_tty_at_cout("\r\n", info);
 			}
 			isdn_tty_at_cout(msg[code], info);
-			if (code == 5) {
-				/* Append Protocol to CONNECT message */
-				isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
-				if (m->mdmreg[13] & 2)
-					isdn_tty_at_cout("/T.70", info);
+			switch (code) {
+				case 2:
+					/* Print CID only once, _after_ 1.st RING */
+					if ((m->mdmreg[13] & 16) && (m->mdmreg[1] == 1)) {
+						isdn_tty_at_cout("\r\n", info);
+						isdn_tty_at_cout("CALLER NUMBER: ", info);
+						isdn_tty_at_cout(dev->num[info->drv_index], info);
+					}
+					break;
+				case 3:
+				case 6:
+				case 7:
+				case 8:
+					m->mdmreg[1] = 0;
+					/* Append Cause-Message if enabled */
+					if (m->mdmreg[13] & 8) {
+						sprintf(s, "/%s", info->last_cause);
+						isdn_tty_at_cout(s, info);
+					}
+					break;
+				case 5:
+					/* Append Protocol to CONNECT message */
+					isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
+					if (m->mdmreg[13] & 2)
+						isdn_tty_at_cout("/T.70", info);
+					break;
 			}
 		}
 		isdn_tty_at_cout("\r\n", info);
@@ -1960,13 +2407,13 @@
 			restore_flags(flags);
 			return;
 		}
-                if (info->tty->ldisc.flush_buffer)
-                        info->tty->ldisc.flush_buffer(info->tty);
+		if (info->tty->ldisc.flush_buffer)
+			info->tty->ldisc.flush_buffer(info->tty);
 		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
 		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
 			tty_hangup(info->tty);
-                }
+		}
 		restore_flags(flags);
 	}
 }
@@ -1974,7 +2421,8 @@
 /*
  * Display a modem-register-value.
  */
-static void isdn_tty_show_profile(int ridx, modem_info * info)
+static void
+isdn_tty_show_profile(int ridx, modem_info * info)
 {
 	char v[6];
 
@@ -1985,7 +2433,8 @@
 /*
  * Get MSN-string from char-pointer, set pointer to end of number
  */
-static void isdn_tty_get_msnstr(char *n, char **p)
+static void
+isdn_tty_get_msnstr(char *n, char **p)
 {
 	while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ','))
 		*n++ = *p[0]++;
@@ -1995,7 +2444,8 @@
 /*
  * Get phone-number from modem-commandbuffer
  */
-static void isdn_tty_getdial(char *p, char *q)
+static void
+isdn_tty_getdial(char *p, char *q)
 {
 	int first = 1;
 
@@ -2011,648 +2461,775 @@
 #define PARSE_ERROR { isdn_tty_modem_result(4, info); return; }
 #define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; }
 
+static void
+isdn_tty_report(modem_info * info)
+{
+	atemu *m = &info->emu;
+	char s[80];
+
+	isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
+	sprintf(s, "    Remote Number:    %s\r\n", info->last_num);
+	isdn_tty_at_cout(s, info);
+	sprintf(s, "    Direction:        %s\r\n", info->last_dir ? "outgoing" : "incoming");
+	isdn_tty_at_cout(s, info);
+	isdn_tty_at_cout("    Layer-2 Protocol: ", info);
+	switch (info->last_l2) {
+		case ISDN_PROTO_L2_X75I:
+			isdn_tty_at_cout("x75i", info);
+			break;
+		case ISDN_PROTO_L2_X75UI:
+			isdn_tty_at_cout("x75ui", info);
+			break;
+		case ISDN_PROTO_L2_X75BUI:
+			isdn_tty_at_cout("x75bui", info);
+			break;
+		case ISDN_PROTO_L2_HDLC:
+			isdn_tty_at_cout("hdlc", info);
+			break;
+		case ISDN_PROTO_L2_TRANS:
+			isdn_tty_at_cout("transparent", info);
+			break;
+		default:
+			isdn_tty_at_cout("unknown", info);
+			break;
+	}
+	isdn_tty_at_cout((m->mdmreg[13] & 2) ? "/t.70\r\n" : "\r\n", info);
+	isdn_tty_at_cout("    Service:          ", info);
+	switch (info->last_si) {
+		case 1:
+			isdn_tty_at_cout("audio\r\n", info);
+			break;
+		case 5:
+			isdn_tty_at_cout("btx\r\n", info);
+			break;
+		case 7:
+			isdn_tty_at_cout("data\r\n", info);
+			break;
+		default:
+			sprintf(s, "%d\r\n", info->last_si);
+			isdn_tty_at_cout(s, info);
+			break;
+	}
+	sprintf(s, "    Hangup location:  %s\r\n", info->last_lhup ? "local" : "remote");
+	isdn_tty_at_cout(s, info);
+	sprintf(s, "    Last cause:       %s\r\n", info->last_cause);
+	isdn_tty_at_cout(s, info);
+}
+
 /*
  * Parse AT&.. commands.
  */
-static int isdn_tty_cmd_ATand(char **p, modem_info * info)
+static int
+isdn_tty_cmd_ATand(char **p, modem_info * info)
 {
-        atemu *m = &info->emu;
-        int i;
-        char rb[100];
-
-        switch (*p[0]) {
-                case 'B':
-                        /* &B - Set Buffersize */
-                        p[0]++;
-                        i = isdn_getnum(p);
-                        if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
-                                PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
-                        if ((m->mdmreg[18] & 1) && (i > VBUF))
-                                PARSE_ERROR1;
-#endif
-                        m->mdmreg[16] = i / 16;
-                        info->xmit_size = m->mdmreg[16] * 16;
-                        break;
-                case 'D':
-                        /* &D - Set DCD-Low-behavior */
-                        p[0]++;
-                        switch (isdn_getnum(p)) {
-                                case 0:
-                                        m->mdmreg[13] &= ~4;
-                                        m->mdmreg[12] &= ~32;
-                                        break;
-                                case 2:
-                                        m->mdmreg[13] |= 4;
-                                        m->mdmreg[12] &= ~32;
-                                        break;
-                                case 3:
-                                        m->mdmreg[13] |= 4;
-                                        m->mdmreg[12] |= 32;
-                                        break;
-                                default:
-                                        PARSE_ERROR1
-                        }
-                        break;
-                case 'E':
-                        /* &E -Set EAZ/MSN */
-                        p[0]++;
-                        isdn_tty_get_msnstr(m->msn, p);
-                        break;
-                case 'F':
-                        /* &F -Set Factory-Defaults */
-                        p[0]++;
-                        isdn_tty_reset_profile(m);
-                        isdn_tty_modem_reset_regs(info, 1);
-                        break;
-                case 'S':
-                        /* &S - Set Windowsize */
-                        p[0]++;
-                        i = isdn_getnum(p);
-                        if ((i > 0) && (i < 9))
-                                m->mdmreg[17] = i;
-                        else
-                                PARSE_ERROR1;
-                        break;
-                case 'V':
-                        /* &V - Show registers */
-                        p[0]++;
-                        for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
-                                sprintf(rb, "S%d=%d%s", i, 
-                                        m->mdmreg[i], (i == 6) ? "\r\n" : " ");
-                                isdn_tty_at_cout(rb, info);
-                        }
-                        sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
-                                strlen(m->msn) ? m->msn : "None");
-                        isdn_tty_at_cout(rb, info);
-                        break;
-                case 'W':
-                        /* &W - Write Profile */
-                        p[0]++;
-                        switch (*p[0]) {
-                                case '0':
-                                        p[0]++;
-                                        modem_write_profile(m);
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                case 'X':
-                        /* &X - Switch to BTX-Mode */
-                        p[0]++;
-                        switch (isdn_getnum(p)) {
-                                case 0:
-                                        m->mdmreg[13] &= ~2;
-                                        info->xmit_size = m->mdmreg[16] * 16;
-                                        break;
-                                case 1:
-                                        m->mdmreg[13] |= 2;
-                                        m->mdmreg[14] = 0;
-                                        info->xmit_size = 112;
-                                        m->mdmreg[18] = 4;
-                                        m->mdmreg[19] = 0;
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                default:
-                        PARSE_ERROR1;
-        }
-        return 0;
+	atemu *m = &info->emu;
+	int i;
+	char rb[100];
+
+	switch (*p[0]) {
+		case 'B':
+			/* &B - Set Buffersize */
+			p[0]++;
+			i = isdn_getnum(p);
+			if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
+				PARSE_ERROR1;
+#ifdef CONFIG_ISDN_AUDIO
+			if ((m->mdmreg[18] & 1) && (i > VBUF))
+				PARSE_ERROR1;
+#endif
+			m->mdmreg[16] = i / 16;
+			info->xmit_size = m->mdmreg[16] * 16;
+			break;
+		case 'D':
+			/* &D - Set DCD-Low-behavior */
+			p[0]++;
+			switch (isdn_getnum(p)) {
+				case 0:
+					m->mdmreg[13] &= ~4;
+					m->mdmreg[12] &= ~32;
+					break;
+				case 2:
+					m->mdmreg[13] |= 4;
+					m->mdmreg[12] &= ~32;
+					break;
+				case 3:
+					m->mdmreg[13] |= 4;
+					m->mdmreg[12] |= 32;
+					break;
+				default:
+					PARSE_ERROR1
+			}
+			break;
+		case 'E':
+			/* &E -Set EAZ/MSN */
+			p[0]++;
+			isdn_tty_get_msnstr(m->msn, p);
+			break;
+		case 'F':
+			/* &F -Set Factory-Defaults */
+			p[0]++;
+			isdn_tty_reset_profile(m);
+			isdn_tty_modem_reset_regs(info, 1);
+			break;
+		case 'S':
+			/* &S - Set Windowsize */
+			p[0]++;
+			i = isdn_getnum(p);
+			if ((i > 0) && (i < 9))
+				m->mdmreg[17] = i;
+			else
+				PARSE_ERROR1;
+			break;
+		case 'V':
+			/* &V - Show registers */
+			p[0]++;
+			isdn_tty_at_cout("\r\n", info);
+			for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
+				sprintf(rb, "S%02d=%03d%s", i,
+					m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
+				isdn_tty_at_cout(rb, info);
+			}
+			sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
+				strlen(m->msn) ? m->msn : "None");
+			isdn_tty_at_cout(rb, info);
+			break;
+		case 'W':
+			/* &W - Write Profile */
+			p[0]++;
+			switch (*p[0]) {
+				case '0':
+					p[0]++;
+					modem_write_profile(m);
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case 'X':
+			/* &X - Switch to BTX-Mode */
+			p[0]++;
+			switch (isdn_getnum(p)) {
+				case 0:
+					m->mdmreg[13] &= ~2;
+					info->xmit_size = m->mdmreg[16] * 16;
+					break;
+				case 1:
+					m->mdmreg[13] |= 2;
+					m->mdmreg[14] = 0;
+					info->xmit_size = 112;
+					m->mdmreg[18] = 4;
+					m->mdmreg[19] = 0;
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		default:
+			PARSE_ERROR1;
+	}
+	return 0;
+}
+
+static int
+isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
+{
+	/* Some plausibility checks */
+	switch (mreg) {
+		case 14:
+			if (mval > ISDN_PROTO_L2_TRANS)
+				return 1;
+			break;
+		case 16:
+			if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+				return 1;
+#ifdef CONFIG_ISDN_AUDIO
+			if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+				return 1;
+#endif
+			info->xmit_size = mval * 16;
+			break;
+		case 20:
+		case 21:
+		case 22:
+			/* readonly registers */
+			return 1;
+	}
+	return 0;
 }
 
 /*
  * Perform ATS command
  */
-static int isdn_tty_cmd_ATS(char **p, modem_info * info)
+static int
+isdn_tty_cmd_ATS(char **p, modem_info * info)
 {
-        atemu *m = &info->emu;
-        int mreg;
-        int mval;
-
-        mreg = isdn_getnum(p);
-        if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
-                PARSE_ERROR1;
-        switch (*p[0]) {
-                case '=':
-                        p[0]++;
-                        mval = isdn_getnum(p);
-                        if (mval < 0 || mval > 255)
-                                PARSE_ERROR1;
-                        switch (mreg) {
-                                /* Some plausibility checks */
-                                case 14:
-                                        if (mval > ISDN_PROTO_L2_TRANS)
-                                                PARSE_ERROR1;
-                                        break;
-                                case 16:
-                                        if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
-                                                PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
-                                        if ((m->mdmreg[18] & 1) && (mval > VBUFX))
-                                                PARSE_ERROR1;
-#endif
-                                        info->xmit_size = mval * 16;
-                                        break;
-                                case 20:
-                                        PARSE_ERROR1;
-                        }
-                        m->mdmreg[mreg] = mval;
-                        break;
-                case '?':
-                        p[0]++;
-                        isdn_tty_show_profile(mreg, info);
-                        break;
-                default:
-                        PARSE_ERROR1;
-                        break;
-        }
-        return 0;
+	atemu *m = &info->emu;
+	int bitpos;
+	int mreg;
+	int mval;
+	int bval;
+
+	mreg = isdn_getnum(p);
+	if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
+		PARSE_ERROR1;
+	switch (*p[0]) {
+		case '=':
+			p[0]++;
+			mval = isdn_getnum(p);
+			if (mval < 0 || mval > 255)
+				PARSE_ERROR1;
+			if (isdn_tty_check_ats(mreg, mval, info, m))
+				PARSE_ERROR1;
+			m->mdmreg[mreg] = mval;
+			break;
+		case '.':
+			/* Set/Clear a single bit */
+			p[0]++;
+			bitpos = isdn_getnum(p);
+			if ((bitpos < 0) || (bitpos > 7))
+				PARSE_ERROR1;
+			switch (*p[0]) {
+				case '=':
+					p[0]++;
+					bval = isdn_getnum(p);
+					if (bval < 0 || bval > 1)
+						PARSE_ERROR1;
+					if (bval)
+						mval = m->mdmreg[mreg] | (1 << bitpos);
+					else
+						mval = m->mdmreg[mreg] & ~(1 << bitpos);
+					if (isdn_tty_check_ats(mreg, mval, info, m))
+						PARSE_ERROR1;
+					m->mdmreg[mreg] = mval;
+					break;
+				case '?':
+					p[0]++;
+					isdn_tty_at_cout("\r\n", info);
+					isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
+							 info);
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case '?':
+			p[0]++;
+			isdn_tty_show_profile(mreg, info);
+			break;
+		default:
+			PARSE_ERROR1;
+			break;
+	}
+	return 0;
 }
 
 /*
  * Perform ATA command
  */
-static void isdn_tty_cmd_ATA(modem_info * info)
+static void
+isdn_tty_cmd_ATA(modem_info * info)
 {
-        atemu *m = &info->emu;
-        isdn_ctrl cmd;
-        int l2;
-
-        if (info->msr & UART_MSR_RI) {
-                /* Accept incoming call */
-                m->mdmreg[1] = 0;
-                info->msr &= ~UART_MSR_RI;
-                l2 = m->mdmreg[14];
-#ifdef CONFIG_ISDN_AUDIO
-                /* If more than one bit set in reg18, autoselect Layer2 */
-                if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18])
-                        if (m->mdmreg[20] == 1) l2 = 4;
-#endif
-                cmd.driver = info->isdn_driver;
-                cmd.command = ISDN_CMD_SETL2;
-                cmd.arg = info->isdn_channel + (l2 << 8);
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                cmd.driver = info->isdn_driver;
-                cmd.command = ISDN_CMD_SETL3;
-                cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-                cmd.driver = info->isdn_driver;
-                cmd.arg = info->isdn_channel;
-                cmd.command = ISDN_CMD_ACCEPTD;
-                dev->drv[info->isdn_driver]->interface->command(&cmd);
-        } else
-                isdn_tty_modem_result(8, info);
+	atemu *m = &info->emu;
+	isdn_ctrl cmd;
+	int l2;
+
+	if (info->msr & UART_MSR_RI) {
+		/* Accept incoming call */
+		info->last_dir = 0;
+		strcpy(info->last_num, dev->num[info->drv_index]);
+		m->mdmreg[1] = 0;
+		info->msr &= ~UART_MSR_RI;
+		l2 = m->mdmreg[14];
+#ifdef CONFIG_ISDN_AUDIO
+		/* If more than one bit set in reg18, autoselect Layer2 */
+		if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) {
+			if (m->mdmreg[20] == 1)
+				l2 = 4;
+			else
+				l2 = 0;
+		}
+#endif
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL2;
+		cmd.arg = info->isdn_channel + (l2 << 8);
+		info->last_l2 = l2;
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.command = ISDN_CMD_SETL3;
+		cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+		cmd.driver = info->isdn_driver;
+		cmd.arg = info->isdn_channel;
+		cmd.command = ISDN_CMD_ACCEPTD;
+		dev->drv[info->isdn_driver]->interface->command(&cmd);
+	} else
+		isdn_tty_modem_result(8, info);
 }
 
 #ifdef CONFIG_ISDN_AUDIO
 /*
  * Parse AT+F.. commands
  */
-static int isdn_tty_cmd_PLUSF(char **p, modem_info * info)
+static int
+isdn_tty_cmd_PLUSF(char **p, modem_info * info)
 {
-        atemu *m = &info->emu;
-        int par;
+	atemu *m = &info->emu;
+	int par;
 	char rs[20];
 
-        if (!strncmp(p[0],"CLASS",5)) {
-                p[0] += 5;
-                switch (*p[0]) {
-                        case '?':
-                                p[0]++;
-                                sprintf(rs,"\r\n%d",
-                                        (m->mdmreg[18]&1)?8:0);
-                                isdn_tty_at_cout(rs, info);
-                                break;
-                        case '=':
-                                p[0]++;
-                                switch (*p[0]) {
-                                        case '0':
-                                                p[0]++;
-                                                m->mdmreg[18] = 4;
-                                                info->xmit_size =
-                                                        m->mdmreg[16] * 16;
-                                                break;
-                                        case '8':
-                                                p[0]++;
-                                                m->mdmreg[18] = 5;
-                                                info->xmit_size = VBUF;
-                                                break;
-                                        case '?':
-                                                p[0]++;
-                                                isdn_tty_at_cout("\r\n0,8",
-                                                                 info);
-                                                break;
-                                        default:
-                                                PARSE_ERROR1;
-                                }
-                                break;
-                        default:
-                                PARSE_ERROR1;
-                }
-                return 0;
-        }        
-        if (!strncmp(p[0],"AA",2)) {
-                p[0] += 2;
-                switch (*p[0]) {
-                        case '?':
-                                p[0]++;
-                                sprintf(rs,"\r\n%d",
-                                        m->mdmreg[0]);
-                                isdn_tty_at_cout(rs, info);
-                                break;
-                        case '=':
-                                p[0]++;
-                                par = isdn_getnum(p);
-                                if ((par < 0) || (par > 255))
-                                        PARSE_ERROR1;
-                                m->mdmreg[0]=par;
-                                break;
-                        default:
-                                PARSE_ERROR1;                                
-                }
-                return 0;
-        }
-        PARSE_ERROR1;
+	if (!strncmp(p[0], "CLASS", 5)) {
+		p[0] += 5;
+		switch (*p[0]) {
+			case '?':
+				p[0]++;
+				sprintf(rs, "\r\n%d",
+					(m->mdmreg[18] & 1) ? 8 : 0);
+				isdn_tty_at_cout(rs, info);
+				break;
+			case '=':
+				p[0]++;
+				switch (*p[0]) {
+					case '0':
+						p[0]++;
+						m->mdmreg[18] = 4;
+						info->xmit_size =
+						    m->mdmreg[16] * 16;
+						break;
+					case '8':
+						p[0]++;
+						m->mdmreg[18] = 5;
+						info->xmit_size = VBUF;
+						break;
+					case '?':
+						p[0]++;
+						isdn_tty_at_cout("\r\n0,8",
+								 info);
+						break;
+					default:
+						PARSE_ERROR1;
+				}
+				break;
+			default:
+				PARSE_ERROR1;
+		}
+		return 0;
+	}
+	if (!strncmp(p[0], "AA", 2)) {
+		p[0] += 2;
+		switch (*p[0]) {
+			case '?':
+				p[0]++;
+				sprintf(rs, "\r\n%d",
+					m->mdmreg[0]);
+				isdn_tty_at_cout(rs, info);
+				break;
+			case '=':
+				p[0]++;
+				par = isdn_getnum(p);
+				if ((par < 0) || (par > 255))
+					PARSE_ERROR1;
+				m->mdmreg[0] = par;
+				break;
+			default:
+				PARSE_ERROR1;
+		}
+		return 0;
+	}
+	PARSE_ERROR1;
 }
 
 /*
  * Parse AT+V.. commands
  */
-static int isdn_tty_cmd_PLUSV(char **p, modem_info * info)
+static int
+isdn_tty_cmd_PLUSV(char **p, modem_info * info)
 {
-        atemu *m = &info->emu;
-        static char *vcmd[] = {"NH","IP","LS","RX","SD","SM","TX",NULL};
-        int i;
+	atemu *m = &info->emu;
+	static char *vcmd[] =
+	{"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL};
+	int i;
 	int par1;
 	int par2;
 	char rs[20];
 
-        i = 0;
-        while (vcmd[i]) {
-                if (!strncmp(vcmd[i],p[0],2)) {
-                        p[0] += 2;
-                        break;
-                }
-                i++;
-        }
-        switch (i) {
-                case 0:
-                        /* AT+VNH - Auto hangup feature */
-                        switch (*p[0]) {
-                                case '?':
-                                        p[0]++;
-                                        isdn_tty_at_cout("\r\n1", info);
-                                        break;
-                                case '=':
-                                        p[0]++;
-                                        switch (*p[0]) {
-                                                case '1':
-                                                        p[0]++;
-                                                        break;
-                                                case '?':
-                                                        p[0]++;
-                                                        isdn_tty_at_cout("\r\n1", info);
-                                                        break;
-                                                default:
-                                                        PARSE_ERROR1;
-                                        }
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                case 1:
-                        /* AT+VIP - Reset all voice parameters */
-                        isdn_tty_modem_reset_vpar(m);
-                        break;
-                case 2:
-                        /* AT+VLS - Select device, accept incoming call */
-                        switch (*p[0]) {
-                                case '?':
-                                        p[0]++;
-                                        sprintf(rs,"\r\n%d",m->vpar[0]);
-                                        isdn_tty_at_cout(rs, info);
-                                        break;
-                                case '=':
-                                        p[0]++;
-                                        switch (*p[0]) {
-                                                case '0':
-                                                        p[0]++;
-                                                        m->vpar[0] = 0;
-                                                        break;
-                                                case '2':
-                                                        p[0]++;
-                                                        m->vpar[0] = 2;
-                                                        break;
-                                                case '?':
-                                                        p[0]++;
-                                                        isdn_tty_at_cout("\r\n0,2", info);
-                                                        break;
-                                                default:
-                                                        PARSE_ERROR1;
-                                        }
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                case 3:
-                        /* AT+VRX - Start recording */
-                        if (!m->vpar[0])
-                                PARSE_ERROR1;
-                        if (info->online != 1) {
-                                isdn_tty_modem_result(8, info);
-                                return 1;
-                        }
-                        info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
-                        if (!info->dtmf_state) {
-                                printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
-                                PARSE_ERROR1;
-                        }
-                        if (m->vpar[3] < 5) {
-                                info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
-                                if (!info->adpcmr) {
-                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
-                                        PARSE_ERROR1;
-                                }
-                        }
-                        info->vonline = 1;
-                        isdn_tty_modem_result(1, info);
-                        return 1;
-                        break;
-                case 4:
-                        /* AT+VSD - Silence detection */
-                        switch (*p[0]) {
-                                case '?':
-                                        p[0]++;
-                                        sprintf(rs,"\r\n<%d>,<%d>",
-                                                m->vpar[1],
-                                                m->vpar[2]);
-                                        isdn_tty_at_cout(rs, info);
-                                        break;
-                                case '=':
-                                        p[0]++;
-                                        switch (*p[0]) {
-                                                case '0':
-                                                case '1':
-                                                case '2':
-                                                case '3':
-                                                        par1 = isdn_getnum(p);
-                                                        if ((par1 < 0) || (par1 > 31))
-                                                                PARSE_ERROR1;
-                                                        if (*p[0] != ',')
-                                                                PARSE_ERROR1;
-                                                        p[0]++;
-                                                        par2 = isdn_getnum(p);
-                                                        if ((par2 < 0) || (par2 > 255))
-                                                                PARSE_ERROR1;
-                                                        m->vpar[1] = par1;
-                                                        m->vpar[2] = par2;
-                                                        break;
-                                                case '?':
-                                                        p[0]++;
-                                                        isdn_tty_at_cout("\r\n<0-31>,<0-255>",
-                                                                         info);
-                                                        break;
-                                                default:
-                                                        PARSE_ERROR1;
-                                        }
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                case 5:
-                        /* AT+VSM - Select compression */
-                        switch (*p[0]) {
-                                case '?':
-                                        p[0]++;
-                                        sprintf(rs,"\r\n<%d>,<%d><8000>",
-                                                m->vpar[3],
-                                                m->vpar[1]);
-                                        isdn_tty_at_cout(rs, info);
-                                        break;
-                                case '=':
-                                        p[0]++;
-                                        switch (*p[0]) {
-                                                case '2':
-                                                case '3':
-                                                case '4':
-                                                case '5':
-                                                case '6':
-                                                        par1 = isdn_getnum(p);
-                                                        if ((par1 < 2) || (par1 > 6))
-                                                                PARSE_ERROR1;
-                                                        m->vpar[3] = par1;
-                                                        break;
-                                                case '?':
-                                                        p[0]++;
-                                                        isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
-                                                                         info);
-                                                        isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
-                                                                         info);
-                                                        isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
-                                                                         info);
-                                                        isdn_tty_at_cout("5;ALAW;8;0;(8000)",
-                                                                         info);
-                                                        isdn_tty_at_cout("6;ULAW;8;0;(8000)",
-                                                                         info);
-                                                        break;
-                                                default:
-                                                        PARSE_ERROR1;
-                                        }
-                                        break;
-                                default:
-                                        PARSE_ERROR1;
-                        }
-                        break;
-                case 6:
-                        /* AT+VTX - Start sending */
-                        if (!m->vpar[0])
-                                PARSE_ERROR1;
-                        if (info->online != 1) {
-                                isdn_tty_modem_result(8, info);
-                                return 1;
-                        }
-                        info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
-                        if (!info->dtmf_state) {
-                                printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
-                                PARSE_ERROR1;
-                        }
-                        if (m->vpar[3] < 5) {
-                                info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
-                                if (!info->adpcms) {
-                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
-                                        PARSE_ERROR1;
-                                }
-                        }
-                        m->lastDLE = 0;
-                        info->vonline = 2;
-                        isdn_tty_modem_result(1, info);
-                        return 1;
-                        break;
-                default:
-                        PARSE_ERROR1;
-        }
-        return 0;
+	i = 0;
+	while (vcmd[i]) {
+		if (!strncmp(vcmd[i], p[0], 2)) {
+			p[0] += 2;
+			break;
+		}
+		i++;
+	}
+	switch (i) {
+		case 0:
+			/* AT+VNH - Auto hangup feature */
+			switch (*p[0]) {
+				case '?':
+					p[0]++;
+					isdn_tty_at_cout("\r\n1", info);
+					break;
+				case '=':
+					p[0]++;
+					switch (*p[0]) {
+						case '1':
+							p[0]++;
+							break;
+						case '?':
+							p[0]++;
+							isdn_tty_at_cout("\r\n1", info);
+							break;
+						default:
+							PARSE_ERROR1;
+					}
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case 1:
+			/* AT+VIP - Reset all voice parameters */
+			isdn_tty_modem_reset_vpar(m);
+			break;
+		case 2:
+			/* AT+VLS - Select device, accept incoming call */
+			switch (*p[0]) {
+				case '?':
+					p[0]++;
+					sprintf(rs, "\r\n%d", m->vpar[0]);
+					isdn_tty_at_cout(rs, info);
+					break;
+				case '=':
+					p[0]++;
+					switch (*p[0]) {
+						case '0':
+							p[0]++;
+							m->vpar[0] = 0;
+							break;
+						case '2':
+							p[0]++;
+							m->vpar[0] = 2;
+							break;
+						case '?':
+							p[0]++;
+							isdn_tty_at_cout("\r\n0,2", info);
+							break;
+						default:
+							PARSE_ERROR1;
+					}
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case 3:
+			/* AT+VRX - Start recording */
+			if (!m->vpar[0])
+				PARSE_ERROR1;
+			if (info->online != 1) {
+				isdn_tty_modem_result(8, info);
+				return 1;
+			}
+			info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
+			if (!info->dtmf_state) {
+				printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
+				PARSE_ERROR1;
+			}
+			if (m->vpar[3] < 5) {
+				info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
+				if (!info->adpcmr) {
+					printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+					PARSE_ERROR1;
+				}
+			}
+#ifdef ISDN_DEBUG_AT
+			printk(KERN_DEBUG "AT: +VRX\n");
+#endif
+			info->vonline |= 1;
+			isdn_tty_modem_result(1, info);
+			return 0;
+			break;
+		case 4:
+			/* AT+VSD - Silence detection */
+			switch (*p[0]) {
+				case '?':
+					p[0]++;
+					sprintf(rs, "\r\n<%d>,<%d>",
+						m->vpar[1],
+						m->vpar[2]);
+					isdn_tty_at_cout(rs, info);
+					break;
+				case '=':
+					p[0]++;
+					switch (*p[0]) {
+						case '0':
+						case '1':
+						case '2':
+						case '3':
+							par1 = isdn_getnum(p);
+							if ((par1 < 0) || (par1 > 31))
+								PARSE_ERROR1;
+							if (*p[0] != ',')
+								PARSE_ERROR1;
+							p[0]++;
+							par2 = isdn_getnum(p);
+							if ((par2 < 0) || (par2 > 255))
+								PARSE_ERROR1;
+							m->vpar[1] = par1;
+							m->vpar[2] = par2;
+							break;
+						case '?':
+							p[0]++;
+							isdn_tty_at_cout("\r\n<0-31>,<0-255>",
+								   info);
+							break;
+						default:
+							PARSE_ERROR1;
+					}
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case 5:
+			/* AT+VSM - Select compression */
+			switch (*p[0]) {
+				case '?':
+					p[0]++;
+					sprintf(rs, "\r\n<%d>,<%d><8000>",
+						m->vpar[3],
+						m->vpar[1]);
+					isdn_tty_at_cout(rs, info);
+					break;
+				case '=':
+					p[0]++;
+					switch (*p[0]) {
+						case '2':
+						case '3':
+						case '4':
+						case '5':
+						case '6':
+							par1 = isdn_getnum(p);
+							if ((par1 < 2) || (par1 > 6))
+								PARSE_ERROR1;
+							m->vpar[3] = par1;
+							break;
+						case '?':
+							p[0]++;
+							isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
+								   info);
+							isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
+								   info);
+							isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
+								   info);
+							isdn_tty_at_cout("5;ALAW;8;0;(8000)",
+								   info);
+							isdn_tty_at_cout("6;ULAW;8;0;(8000)",
+								   info);
+							break;
+						default:
+							PARSE_ERROR1;
+					}
+					break;
+				default:
+					PARSE_ERROR1;
+			}
+			break;
+		case 6:
+			/* AT+VTX - Start sending */
+			if (!m->vpar[0])
+				PARSE_ERROR1;
+			if (info->online != 1) {
+				isdn_tty_modem_result(8, info);
+				return 1;
+			}
+			info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
+			if (!info->dtmf_state) {
+				printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
+				PARSE_ERROR1;
+			}
+			if (m->vpar[3] < 5) {
+				info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
+				if (!info->adpcms) {
+					printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+					PARSE_ERROR1;
+				}
+			}
+#ifdef ISDN_DEBUG_AT
+			printk(KERN_DEBUG "AT: +VTX\n");
+#endif
+			m->lastDLE = 0;
+			info->vonline |= 2;
+			isdn_tty_modem_result(1, info);
+			return 0;
+			break;
+		default:
+			PARSE_ERROR1;
+	}
+	return 0;
 }
-#endif        /* CONFIG_ISDN_AUDIO */
+#endif                          /* CONFIG_ISDN_AUDIO */
 
 /*
  * Parse and perform an AT-command-line.
  */
-static void isdn_tty_parse_at(modem_info * info)
+static void
+isdn_tty_parse_at(modem_info * info)
 {
-        atemu *m = &info->emu;
-        char *p;
-        char ds[40];
+	atemu *m = &info->emu;
+	char *p;
+	char ds[40];
 
 #ifdef ISDN_DEBUG_AT
-        printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
+	printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
+#endif
+	for (p = &m->mdmcmd[2]; *p;) {
+		switch (*p) {
+			case 'A':
+				/* A - Accept incoming call */
+				p++;
+				isdn_tty_cmd_ATA(info);
+				return;
+				break;
+			case 'D':
+				/* D - Dial */
+				isdn_tty_getdial(++p, ds);
+				p += strlen(p);
+				if (!strlen(m->msn))
+					isdn_tty_modem_result(10, info);
+				else if (strlen(ds))
+					isdn_tty_dial(ds, info, m);
+				else
+					PARSE_ERROR;
+				return;
+			case 'E':
+				/* E - Turn Echo on/off */
+				p++;
+				switch (isdn_getnum(&p)) {
+					case 0:
+						m->mdmreg[12] &= ~4;
+						break;
+					case 1:
+						m->mdmreg[12] |= 4;
+						break;
+					default:
+						PARSE_ERROR;
+				}
+				break;
+			case 'H':
+				/* H - On/Off-hook */
+				p++;
+				switch (*p) {
+					case '0':
+						p++;
+						isdn_tty_on_hook(info);
+						break;
+					case '1':
+						p++;
+						isdn_tty_off_hook();
+						break;
+					default:
+						isdn_tty_on_hook(info);
+						break;
+				}
+				break;
+			case 'I':
+				/* I - Information */
+				p++;
+				isdn_tty_at_cout("\r\nLinux ISDN", info);
+				switch (*p) {
+					case '0':
+					case '1':
+						p++;
+						break;
+					case '2':
+						p++;
+						isdn_tty_report(info);
+						break;
+					default:
+				}
+				break;
+			case 'O':
+				/* O - Go online */
+				p++;
+				if (info->msr & UART_MSR_DCD)
+					/* if B-Channel is up */
+					isdn_tty_modem_result(5, info);
+				else
+					isdn_tty_modem_result(3, info);
+				return;
+			case 'Q':
+				/* Q - Turn Emulator messages on/off */
+				p++;
+				switch (isdn_getnum(&p)) {
+					case 0:
+						m->mdmreg[12] |= 1;
+						break;
+					case 1:
+						m->mdmreg[12] &= ~1;
+						break;
+					default:
+						PARSE_ERROR;
+				}
+				break;
+			case 'S':
+				/* S - Set/Get Register */
+				p++;
+				if (isdn_tty_cmd_ATS(&p, info))
+					return;
+				break;
+			case 'V':
+				/* V - Numeric or ASCII Emulator-messages */
+				p++;
+				switch (isdn_getnum(&p)) {
+					case 0:
+						m->mdmreg[12] |= 2;
+						break;
+					case 1:
+						m->mdmreg[12] &= ~2;
+						break;
+					default:
+						PARSE_ERROR;
+				}
+				break;
+			case 'Z':
+				/* Z - Load Registers from Profile */
+				p++;
+				isdn_tty_modem_reset_regs(info, 1);
+				break;
+#ifdef CONFIG_ISDN_AUDIO
+			case '+':
+				p++;
+				switch (*p) {
+					case 'F':
+						p++;
+						if (isdn_tty_cmd_PLUSF(&p, info))
+							return;
+						break;
+					case 'V':
+						if (!(m->mdmreg[18] & 1))
+							PARSE_ERROR;
+						p++;
+						if (isdn_tty_cmd_PLUSV(&p, info))
+							return;
+						break;
+					default:
+						PARSE_ERROR;
+				}
+				break;
+#endif                          /* CONFIG_ISDN_AUDIO */
+			case '&':
+				p++;
+				if (isdn_tty_cmd_ATand(&p, info))
+					return;
+				break;
+			default:
+				PARSE_ERROR;
+		}
+	}
+#ifdef CONFIG_ISDN_AUDIO
+	if (!info->vonline)
 #endif
-        for (p = &m->mdmcmd[2]; *p;) {
-                switch (*p) {
-                        case 'A':
-                                /* A - Accept incoming call */
-                                p++;
-                                isdn_tty_cmd_ATA(info);
-                                return;
-                                break;
-                        case 'D':
-                                /* D - Dial */
-                                isdn_tty_getdial(++p, ds);
-                                p += strlen(p);
-                                if (!strlen(m->msn))
-                                        isdn_tty_modem_result(10, info);
-                                else if (strlen(ds))
-                                        isdn_tty_dial(ds, info, m);
-                                else
-                                        isdn_tty_modem_result(4, info);
-                                return;
-                        case 'E':
-                                /* E - Turn Echo on/off */
-                                p++;
-                                switch (isdn_getnum(&p)) {
-                                        case 0:
-                                                m->mdmreg[12] &= ~4;
-                                                break;
-                                        case 1:
-                                                m->mdmreg[12] |= 4;
-                                                break;
-                                        default:
-                                                PARSE_ERROR;
-                                }
-                                break;
-                        case 'H':
-                                /* H - On/Off-hook */
-                                p++;
-                                switch (*p) {
-                                        case '0':
-                                                p++;
-                                                isdn_tty_on_hook(info);
-                                                break;
-                                        case '1':
-                                                p++;
-                                                isdn_tty_off_hook();
-                                                break;
-                                        default:
-                                                isdn_tty_on_hook(info);
-                                                break;
-                                }
-                                break;
-                        case 'I':
-                                /* I - Information */
-                                p++;
-                                isdn_tty_at_cout("\r\nLinux ISDN", info);
-                                switch (*p) {
-                                        case '0':
-                                        case '1':
-                                                p++;
-                                                break;
-                                        default:
-                                }
-                                break;
-                        case 'O':
-                                /* O - Go online */
-                                p++;
-                                if (info->msr & UART_MSR_DCD)
-                                        /* if B-Channel is up */
-                                        isdn_tty_modem_result(5, info);
-                                else
-                                        isdn_tty_modem_result(3, info);
-                                return;
-                        case 'Q':
-                                /* Q - Turn Emulator messages on/off */
-                                p++;
-                                switch (isdn_getnum(&p)) {
-                                        case 0:
-                                                m->mdmreg[12] |= 1;
-                                                break;
-                                        case 1:
-                                                m->mdmreg[12] &= ~1;
-                                                break;
-                                        default:
-                                                PARSE_ERROR;
-                                }
-                                break;
-                        case 'S':
-                                /* S - Set/Get Register */
-                                p++;
-                                if (isdn_tty_cmd_ATS(&p, info))
-                                        return;
-                                break;
-                        case 'V':
-                                /* V - Numeric or ASCII Emulator-messages */
-                                p++;
-                                switch (isdn_getnum(&p)) {
-                                        case 0:
-                                                m->mdmreg[12] |= 2;
-                                                break;
-                                        case 1:
-                                                m->mdmreg[12] &= ~2;
-                                                break;
-                                        default:
-                                                PARSE_ERROR;
-                                }
-                                break;
-                        case 'Z':
-                                /* Z - Load Registers from Profile */
-                                p++;
-                                isdn_tty_modem_reset_regs(info, 1);
-                                break;
-#ifdef CONFIG_ISDN_AUDIO
-                        case '+':
-                                p++;
-                                switch (*p) {
-                                        case 'F':
-                                                p++;
-                                                if (isdn_tty_cmd_PLUSF(&p, info))
-                                                        return;
-                                                break;
-                                        case 'V':
-                                                if (!(m->mdmreg[18] & 1))
-                                                        PARSE_ERROR;
-                                                p++;
-                                                if (isdn_tty_cmd_PLUSV(&p, info))
-                                                        return;
-                                                break;
-                                }
-                                break;
-#endif        /* CONFIG_ISDN_AUDIO */
-                        case '&':
-                                p++;
-                                if (isdn_tty_cmd_ATand(&p, info))
-                                        return;
-                                break;
-                        default:
-                                isdn_tty_modem_result(4, info);
-                                return;
-                }
-        }
-        isdn_tty_modem_result(0, info);
+		isdn_tty_modem_result(0, info);
 }
 
 /* Need own toupper() because standard-toupper is not available
@@ -2669,7 +3246,8 @@
  *   channel  index to line (minor-device)
  *   user     flag: buffer is in userspace
  */
-static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
+static int
+isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
 {
 	atemu *m = &info->emu;
 	int total = 0;
@@ -2715,16 +3293,16 @@
 			if (m->mdmcmdl < 255) {
 				c = my_toupper(c);
 				switch (m->mdmcmdl) {
-                                        case 0:
-                                                if (c == 'A')
-                                                        m->mdmcmd[m->mdmcmdl++] = c;
-                                                break;
-                                        case 1:
-                                                if (c == 'T')
-                                                        m->mdmcmd[m->mdmcmdl++] = c;
-                                                break;
-                                        default:
-                                                m->mdmcmd[m->mdmcmdl++] = c;
+					case 0:
+						if (c == 'A')
+							m->mdmcmd[m->mdmcmdl++] = c;
+						break;
+					case 1:
+						if (c == 'T')
+							m->mdmcmd[m->mdmcmdl++] = c;
+						break;
+					default:
+						m->mdmcmd[m->mdmcmdl++] = c;
 				}
 			}
 		}
@@ -2735,10 +3313,11 @@
 /*
  * Switch all modem-channels who are online and got a valid
  * escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within 
+ * This function is called every second via timer-interrupt from within
  * timer-dispatcher isdn_timer_function()
  */
-void isdn_tty_modem_escape(void)
+void
+isdn_tty_modem_escape(void)
 {
 	int ton = 0;
 	int i;
@@ -2747,7 +3326,7 @@
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 		if (USG_MODEM(dev->usage[i]))
 			if ((midx = dev->m_idx[i]) >= 0) {
-                                modem_info *info = &dev->mdm.info[midx];
+				modem_info *info = &dev->mdm.info[midx];
 				if (info->online) {
 					ton = 1;
 					if ((info->emu.pluscount == 3) &&
@@ -2757,27 +3336,28 @@
 						isdn_tty_modem_result(0, info);
 					}
 				}
-                        }
+			}
 	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 }
 
 /*
  * Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within 
+ * This function is called every second via timer-interrupt from within
  * timer-dispatcher isdn_timer_function()
  */
-void isdn_tty_modem_ring(void)
+void
+isdn_tty_modem_ring(void)
 {
 	int ton = 0;
 	int i;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                modem_info *info = &dev->mdm.info[i];
-                if (info->msr & UART_MSR_RI) {
-                        ton = 1;
-                        isdn_tty_modem_result(2, info);
-                }
-        }
+		modem_info *info = &dev->mdm.info[i];
+		if (info->msr & UART_MSR_RI) {
+			ton = 1;
+			isdn_tty_modem_result(2, info);
+		}
+	}
 	isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
 }
 
@@ -2785,41 +3365,19 @@
  * For all online tty's, try sending data to
  * the lower levels.
  */
-void isdn_tty_modem_xmit(void)
+void
+isdn_tty_modem_xmit(void)
 {
 	int ton = 1;
 	int i;
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                modem_info *info = &dev->mdm.info[i];
-                if (info->online) {
-                        ton = 1;
-                        isdn_tty_senddown(info);
-                        isdn_tty_tint(info);
-                }
-        }
+		modem_info *info = &dev->mdm.info[i];
+		if (info->online) {
+			ton = 1;
+			isdn_tty_senddown(info);
+			isdn_tty_tint(info);
+		}
+	}
 	isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
 }
-
-/*
- * A packet has been output successfully.
- * Search the tty-devices for an appropriate device, decrement its
- * counter for outstanding packets, and set CTS.
- */
-void isdn_tty_bsent(int drv, int chan)
-{
-	int i;
-
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                modem_info *info = &dev->mdm.info[i];
-                if ((info->isdn_driver == drv) &&
-                    (info->isdn_channel == chan) ) {
-                        info->msr |= UART_MSR_CTS;
-                        if (info->send_outstanding)
-                                if (!(--info->send_outstanding))
-                                        info->lsr |= UART_LSR_TEMT;
-                        isdn_tty_tint(info);
-                }
-        }
-	return;
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/isdn_tty.h linux-2.0.31-pre3/drivers/isdn/isdn_tty.h
--- linux-2.0.31-pre2/drivers/isdn/isdn_tty.h	1996-05-19 05:29:29.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/isdn_tty.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,10 +1,10 @@
-/* $Id: isdn_tty.h,v 1.5 1996/05/17 03:52:31 fritz Exp $
- *
+/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $
+
  * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
- * 
+ *
  * 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)
@@ -17,9 +17,26 @@
  *
  * 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. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.h,v $
+ * Revision 1.10  1997/03/02 14:29:26  fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.9  1997/02/28 02:32:49  fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ *          to isdn_tty.c
+ * Bugfix:  Bisync protocol did not behave like documented.
+ *
+ * Revision 1.8  1997/02/10 20:12:50  fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.7  1997/02/03 23:06:10  fritz
+ * Reformatted according CodingStyle
+ *
+ * Revision 1.6  1997/01/14 01:35:19  fritz
+ * Changed prototype of isdn_tty_modem_hup.
+ *
  * Revision 1.5  1996/05/17 03:52:31  fritz
  * Changed DLE handling for audio receive.
  *
@@ -37,15 +54,12 @@
  *
  */
 
-extern void  isdn_tty_modem_result(int, modem_info *);
-extern void  isdn_tty_modem_escape(void);
-extern void  isdn_tty_modem_ring(void);
-extern void  isdn_tty_modem_xmit(void);
-extern void  isdn_tty_modem_hup(modem_info *);
-extern int   isdn_tty_modem_init(void);
-extern void  isdn_tty_readmodem(void);
-extern int   isdn_tty_try_read(modem_info *, struct sk_buff *);
-extern int   isdn_tty_find_icall(int, int, char *);
-extern int   isdn_tty_countDLE(unsigned char *, int);
-extern void  isdn_tty_bsent(int, int);
-extern void  isdn_tty_cleanup_xmit(modem_info *);
+extern void isdn_tty_modem_escape(void);
+extern void isdn_tty_modem_ring(void);
+extern void isdn_tty_modem_xmit(void);
+extern int isdn_tty_modem_init(void);
+extern void isdn_tty_readmodem(void);
+extern int isdn_tty_find_icall(int, int, setup_parm);
+extern void isdn_tty_cleanup_xmit(modem_info *);
+extern int isdn_tty_stat_callback(int, isdn_ctrl *);
+extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
diff -urN linux-2.0.31-pre2/drivers/isdn/Makefile linux-2.0.31-pre3/drivers/isdn/Makefile
--- linux-2.0.31-pre2/drivers/isdn/Makefile	1996-05-19 05:29:29.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/Makefile	2003-08-15 15:03:53.000000000 -0700
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit
+ALL_SUB_DIRS := icn pcbit hisax avmb1
 
 L_OBJS :=
 LX_OBJS :=
@@ -13,8 +13,8 @@
 
 ifeq ($(CONFIG_ISDN),y)
   L_TARGET := isdn.a
-  L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o
-  LX_OBJS += isdn_common.o
+  L_OBJS += isdn_common.o isdn_net.o isdn_tty.o isdn_cards.o
+  LX_OBJS += isdn_syms.o
   ifdef CONFIG_ISDN_PPP
     L_OBJS += isdn_ppp.o
   endif
@@ -25,8 +25,8 @@
   ifeq ($(CONFIG_ISDN),m)
     M_OBJS += isdn.o
     O_TARGET += isdn.o
-    O_OBJS += isdn_net.o isdn_tty.o
-    OX_OBJS += isdn_common.o
+    O_OBJS += isdn_common.o isdn_net.o isdn_tty.o
+    OX_OBJS += isdn_syms.o
     ifdef CONFIG_ISDN_PPP
       O_OBJS += isdn_ppp.o
     endif
@@ -36,13 +36,13 @@
   endif
 endif
 
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
-  L_OBJS += teles/teles.o
-  SUB_DIRS += teles
-  MOD_SUB_DIRS += teles
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+  L_OBJS += hisax/hisax.o
+  SUB_DIRS += hisax
+  MOD_SUB_DIRS += hisax
 else
-  ifeq ($(CONFIG_ISDN_DRV_TELES),m)
-    MOD_SUB_DIRS += teles
+  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+    MOD_SUB_DIRS += hisax
   endif
 endif
 
@@ -66,5 +66,35 @@
   endif
 endif
 
+ifeq ($(CONFIG_ISDN_DRV_SC),y)
+  L_OBJS += sc/sc.o
+  SUB_DIRS += sc
+  MOD_SUB_DIRS += sc
+else
+  ifeq ($(CONFIG_ISDN_DRV_SC),m)
+    MOD_SUB_DIRS += sc
+  endif
+endif
+
+ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+  L_OBJS += avmb1/avmb1.o
+  SUB_DIRS += avmb1
+  MOD_SUB_DIRS += avmb1
+else
+  ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
+    MOD_SUB_DIRS += avmb1
+  endif
+endif
+
+ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
+  L_OBJS += isdnloop/isdnloop.o
+  SUB_DIRS += isdnloop
+  MOD_SUB_DIRS += isdnloop
+else
+  ifeq ($(CONFIG_ISDN_DRV_LOOP),m)
+    MOD_SUB_DIRS += isdnloop
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.0.31-pre2/drivers/isdn/pcbit/callbacks.c linux-2.0.31-pre3/drivers/isdn/pcbit/callbacks.c
--- linux-2.0.31-pre2/drivers/isdn/pcbit/callbacks.c	1996-06-29 10:36:22.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/pcbit/callbacks.c	2003-08-15 15:03:53.000000000 -0700
@@ -164,18 +164,12 @@
          *  ictl.num >= strlen() + strlen() + 5
          */
 
-        if (cbdata->data.setup.CalledPN) 
-		sprintf(ictl.num, "%s,%d,%d,%s", 
-			cbdata->data.setup.CallingPN, 
-			7, 0, 
-			cbdata->data.setup.CalledPN);
-	
-	else
-		sprintf(ictl.num, "%s,%d,%d,%s", 
-			cbdata->data.setup.CallingPN,
-			7, 0, 
-			"0");
-
+		strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
+		strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
+		ictl.parm.setup.si1 = 7;
+		ictl.parm.setup.si2 = 0;
+		ictl.parm.setup.plan = 0;
+		ictl.parm.setup.screen = 0;
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "statstr: %s\n", ictl.num);
diff -urN linux-2.0.31-pre2/drivers/isdn/pcbit/capi.c linux-2.0.31-pre3/drivers/isdn/pcbit/capi.c
--- linux-2.0.31-pre2/drivers/isdn/pcbit/capi.c	1996-06-29 10:36:22.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/pcbit/capi.c	2003-08-15 15:03:53.000000000 -0700
@@ -147,7 +147,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
@@ -170,7 +170,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -200,7 +200,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -222,7 +222,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
   
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -285,7 +285,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -338,7 +338,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -357,7 +357,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = callref;  
 
@@ -382,7 +382,7 @@
 		return -1;
 	}
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2)) = chan->callref;  
 
diff -urN linux-2.0.31-pre2/drivers/isdn/pcbit/drv.c linux-2.0.31-pre3/drivers/isdn/pcbit/drv.c
--- linux-2.0.31-pre2/drivers/isdn/pcbit/drv.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/pcbit/drv.c	2003-08-15 15:03:53.000000000 -0700
@@ -226,7 +226,6 @@
 	struct pcbit_dev  *dev;
 	struct pcbit_chan *chan;
 	struct callb_data info;
-	char *cp;
 
 	dev = finddev(ctl->driver);
 
@@ -245,14 +244,7 @@
 		break;
 	case ISDN_CMD_DIAL:
 		info.type = EV_USR_SETUP_REQ;
-		info.data.setup.CalledPN = (char *) &ctl->num;
-		cp = strchr(info.data.setup.CalledPN, ',');
-		if (cp)
-			*cp = 0;
-		else {
-			printk(KERN_DEBUG "DIAL: error in CalledPN\n");
-			return -1;
-		}		
+		info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
 		pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
 		break;
 	case ISDN_CMD_ACCEPTD:
@@ -280,7 +272,7 @@
 		pcbit_clear_msn(dev);
 		break;
 	case ISDN_CMD_SETEAZ:
-		pcbit_set_msn(dev, ctl->num);
+		pcbit_set_msn(dev, ctl->parm.num);
 		break;
 	case ISDN_CMD_SETL3:
 		if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
@@ -457,15 +449,9 @@
 		for (i=0; i < len; i++)
 		{
 			for(j=0; j < LOAD_RETRY; j++)
-			{
-				__volatile__ unsigned char * ptr;
-
-				ptr = dev->sh_mem + dev->loadptr;
-				if (*ptr == 0)
+				if (!(readb(dev->sh_mem + dev->loadptr)))
 					break;
 
-			}
-
 			if (j == LOAD_RETRY)
 			{
 				errstat = -ETIME;
@@ -745,7 +731,7 @@
 #endif
 	}
 
-	skb->free = 1;
+	SET_SKB_FREE(skb);
 
 	kfree_skb(skb, FREE_READ);
 
@@ -944,7 +930,7 @@
 		return -ENODEV;
 	}
 
-	cmd = (struct pcbit_ioctl *) ctl->num;
+	cmd = (struct pcbit_ioctl *) ctl->parm.num;
 
 	switch(ctl->arg) {
 	case PCBIT_IOCTL_GETSTAT:
diff -urN linux-2.0.31-pre2/drivers/isdn/pcbit/layer2.c linux-2.0.31-pre3/drivers/isdn/pcbit/layer2.c
--- linux-2.0.31-pre2/drivers/isdn/pcbit/layer2.c	1996-06-29 10:36:22.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/pcbit/layer2.c	2003-08-15 15:03:53.000000000 -0700
@@ -1,13 +1,13 @@
 /*
  * Copyright (C) 1996 Universidade de Lisboa
- * 
+ *
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
- * This software may be used and distributed according to the terms of 
+ * This software may be used and distributed according to the terms of
  * the GNU Public License, incorporated herein by reference.
  */
 
-/*        
+/*
  *        PCBIT-D low-layer interface
  */
 
@@ -19,7 +19,7 @@
 /*
  *        TODO: better handling of errors
  *              re-write/remove debug printks
- */ 
+ */
 
 #define __NO_VERSION__
 
@@ -57,7 +57,7 @@
 
 /*
  *  task queue struct
- */ 
+ */
 
 
 
@@ -66,16 +66,16 @@
  *  drv.c
  */
 
-extern void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, 
-			     struct sk_buff * skb,
+extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
+			     struct sk_buff *skb,
 			     ushort hdr_len, ushort refnum);
 
 /*
  *  Prototypes
  */
 
-void pcbit_deliver(void * data);
-static void pcbit_transmit(struct pcbit_dev * dev);
+void pcbit_deliver(void *data);
+static void pcbit_transmit(struct pcbit_dev *dev);
 
 static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
 
@@ -83,9 +83,10 @@
 static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
 static void pcbit_l2_err_recover(unsigned long data);
 
-static void pcbit_firmware_bug(struct pcbit_dev * dev);
+static void pcbit_firmware_bug(struct pcbit_dev *dev);
 
-static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev)
+static __inline__ void
+pcbit_sched_delivery(struct pcbit_dev *dev)
 {
 	queue_task(&dev->qdelivery, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
@@ -96,71 +97,67 @@
  *  Called from layer3
  */
 
-int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, 
-		   struct sk_buff *skb, unsigned short hdr_len)
-        
-{
-        struct frame_buf * frame, * ptr;
-        unsigned long flags;
-
-        if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
-                dev_kfree_skb(skb, FREE_WRITE);
-                return -1;
-        }
-
-        if ( (frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), 
-						   GFP_ATOMIC)) == NULL ) {
-                printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
+int
+pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+	       struct sk_buff *skb, unsigned short hdr_len)
+{
+	struct frame_buf *frame,
+	*ptr;
+	unsigned long flags;
+
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+		dev_kfree_skb(skb, FREE_WRITE);
+		return -1;
+	}
+	if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
+						  GFP_ATOMIC)) == NULL) {
+		printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
 		dev_kfree_skb(skb, FREE_WRITE);
-                return -1;
-        }
+		return -1;
+	}
+	frame->msg = msg;
+	frame->refnum = refnum;
+	frame->copied = 0;
+	frame->hdr_len = hdr_len;
+
+	if (skb)
+		frame->dt_len = skb->len - hdr_len;
+	else
+		frame->dt_len = 0;
 
-        frame->msg = msg;
-        frame->refnum = refnum;
-        frame->copied = 0;        
-        frame->hdr_len = hdr_len;
-
-        if (skb) {
-                frame->dt_len = skb->len - hdr_len;
-		if (frame->dt_len == 0)
-                        skb->lock++;
-        }
-        else
-                frame->dt_len = 0;
-
-        frame->skb = skb;
+	frame->skb = skb;
 
-        frame->next = NULL;
+	frame->next = NULL;
 
-        save_flags(flags);
-        cli();
+	save_flags(flags);
+	cli();
+
+	if (dev->write_queue == NULL) {
+		dev->write_queue = frame;
+		restore_flags(flags);
+		pcbit_transmit(dev);
+	} else {
+		for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
+		ptr->next = frame;
 
-        if (dev->write_queue == NULL) {
-                dev->write_queue = frame;
 		restore_flags(flags);
-                pcbit_transmit(dev);
-        }
-        else {        
-                for(ptr=dev->write_queue; ptr->next; ptr=ptr->next);
-                ptr->next = frame;
-                
-                restore_flags(flags);
-        }
-        return 0;
+	}
+	return 0;
 }
 
-static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len)
+static __inline__ void
+pcbit_tx_update(struct pcbit_dev *dev, ushort len)
 {
-        u_char info;
+	u_char info;
 
-        dev->send_seq = (dev->send_seq + 1) % 8;
+	dev->send_seq = (dev->send_seq + 1) % 8;
 
-        dev->fsize[dev->send_seq] = len;
-        info = 0;
-        info |= dev->rcv_seq  << 3;
-        info |= dev->send_seq;
+	dev->fsize[dev->send_seq] = len;
+	info = 0;
+	info |= dev->rcv_seq << 3;
+	info |= dev->send_seq;
 
-        writeb(info, dev->sh_mem + BANK4);
+	writeb(info, dev->sh_mem + BANK4);
 
 }
 
@@ -168,46 +165,47 @@
  * called by interrupt service routine or by write_2
  */
 
-static void pcbit_transmit(struct pcbit_dev * dev)
+static void
+pcbit_transmit(struct pcbit_dev *dev)
 {
-        struct frame_buf * frame = NULL;
-        unsigned char unacked;
-        int flen;           /* fragment frame length including all headers */
-	int totlen;         /* non-fragmented frame length */
-        int free;
-	int count, cp_len;
-        unsigned long flags;
+	struct frame_buf *frame = NULL;
+	unsigned char unacked;
+	int flen;               /* fragment frame length including all headers */
+	int totlen;             /* non-fragmented frame length */
+	int free;
+	int count,
+	 cp_len;
+	unsigned long flags;
 	unsigned short tt;
 
-        if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
-                return;
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+		return;
 
-        unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
+	unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
 
 	save_flags(flags);
 	cli();
 
-        if (dev->free > 16 && dev->write_queue && unacked < 7) {
+	if (dev->free > 16 && dev->write_queue && unacked < 7) {
 
-                if (!dev->w_busy)
-                        dev->w_busy = 1;
-                else
-                {
-                        restore_flags(flags);
-                        return;
-                }
+		if (!dev->w_busy)
+			dev->w_busy = 1;
+		else {
+			restore_flags(flags);
+			return;
+		}
 
 
-                frame = dev->write_queue;
-                free = dev->free;
+		frame = dev->write_queue;
+		free = dev->free;
 
-                restore_flags(flags);
+		restore_flags(flags);
 
 		if (frame->copied == 0) {
 
-                        /* Type 0 frame */
+			/* Type 0 frame */
 
-                        struct msg_fmt * msg;
+			struct msg_fmt *msg;
 
 			if (frame->skb)
 				totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
@@ -216,67 +214,65 @@
 
 			flen = MIN(totlen, free);
 
-                        msg = (struct msg_fmt *) &(frame->msg);
+			msg = (struct msg_fmt *) &(frame->msg);
+
+			/*
+			 *  Board level 2 header
+			 */
 
-                        /*
-                         *  Board level 2 header 
-                         */
+			pcbit_writew(dev, flen - FRAME_HDR_LEN);
 
-                        pcbit_writew(dev, flen - FRAME_HDR_LEN);
+			pcbit_writeb(dev, msg->cpu);
 
-                        pcbit_writeb(dev, msg->cpu);
+			pcbit_writeb(dev, msg->proc);
 
-                        pcbit_writeb(dev, msg->proc);
+			/* TH */
+			pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
 
-                        /* TH */
-                        pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
+			/* TD */
+			pcbit_writew(dev, frame->dt_len);
 
-                        /* TD */
-                        pcbit_writew(dev, frame->dt_len);
 
+			/*
+			 *  Board level 3 fixed-header
+			 */
 
-                        /*
-                         *  Board level 3 fixed-header 
-                         */
-	
-                        /* LEN = TH */
-                        pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-	
-                        /* XX */
-                        pcbit_writew(dev, 0);
+			/* LEN = TH */
+			pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
 
-                        /* C + S */
-                        pcbit_writeb(dev, msg->cmd);
-                        pcbit_writeb(dev, msg->scmd);
+			/* XX */
+			pcbit_writew(dev, 0);
+
+			/* C + S */
+			pcbit_writeb(dev, msg->cmd);
+			pcbit_writeb(dev, msg->scmd);
+
+			/* NUM */
+			pcbit_writew(dev, frame->refnum);
 
-                        /* NUM */
-                        pcbit_writew(dev, frame->refnum);
-			
 			count = FRAME_HDR_LEN + PREHDR_LEN;
-		}
-		else {
+		} else {
 			/* Type 1 frame */
 
-                        totlen = 2 + (frame->skb->len - frame->copied);
-	  
+			totlen = 2 + (frame->skb->len - frame->copied);
+
 			flen = MIN(totlen, free);
 
-                        /* TT */
-                        tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
-                        pcbit_writew(dev, tt);
+			/* TT */
+			tt = ((ushort) (flen - 2)) | 0x8000U;	/* Type 1 */
+			pcbit_writew(dev, tt);
 
 			count = 2;
 		}
 
 		if (frame->skb) {
-			cp_len = MIN(frame->skb->len - frame->copied, 
-                                     flen - count);
-		
-			memcpy_topcbit(dev, frame->skb->data + frame->copied, 
-                                       cp_len);
+			cp_len = MIN(frame->skb->len - frame->copied,
+				     flen - count);
+
+			memcpy_topcbit(dev, frame->skb->data + frame->copied,
+				       cp_len);
 			frame->copied += cp_len;
 		}
-
 		/* bookkeeping */
 		dev->free -= flen;
 		pcbit_tx_update(dev, flen);
@@ -285,28 +281,24 @@
 		cli();
 
 
-                if (frame->skb == NULL || frame->copied == frame->skb->len) {
-
-                        dev->write_queue = frame->next;
+		if (frame->skb == NULL || frame->copied == frame->skb->len) {
 
-                        if (frame->skb != NULL) {
-                                /* free frame */
-                                dev_kfree_skb(frame->skb, FREE_WRITE);
-                        }
-
-                        kfree(frame);
-                }
+			dev->write_queue = frame->next;
 
+			if (frame->skb != NULL) {
+				/* free frame */
+				dev_kfree_skb(frame->skb, FREE_WRITE);
+			}
+			kfree(frame);
+		}
 		dev->w_busy = 0;
-		restore_flags(flags);				
-        }
-        else
-	{
 		restore_flags(flags);
-#ifdef DEBUG		
-                printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
-                       unacked, dev->free, dev->write_queue ? "not empty" : 
-		       "empty");	
+	} else {
+		restore_flags(flags);
+#ifdef DEBUG
+		printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
+		     unacked, dev->free, dev->write_queue ? "not empty" :
+		       "empty");
 #endif
 	}
 }
@@ -316,18 +308,18 @@
  *  deliver a queued frame to the upper layer
  */
 
-void pcbit_deliver(void * data)
-{ 
-        struct frame_buf *frame;
-        unsigned long flags;
+void
+pcbit_deliver(void *data)
+{
+	struct frame_buf *frame;
+	unsigned long flags;
 	struct msg_fmt msg;
-        struct pcbit_dev *dev = (struct pcbit_dev *) data;
+	struct pcbit_dev *dev = (struct pcbit_dev *) data;
 
 	save_flags(flags);
-        cli();
+	cli();
 
-	while((frame=dev->read_queue))
-	{
+	while ((frame = dev->read_queue)) {
 		dev->read_queue = frame->next;
 		restore_flags(flags);
 
@@ -336,12 +328,12 @@
 		msg.cmd = frame->skb->data[2];
 		msg.scmd = frame->skb->data[3];
 
-		frame->refnum = *((ushort*) frame->skb->data + 4);
-		frame->msg = *((ulong*) &msg);
-		
+		frame->refnum = *((ushort *) frame->skb->data + 4);
+		frame->msg = *((ulong *) & msg);
+
 		skb_pull(frame->skb, 6);
 
-		pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, 
+		pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
 				 frame->refnum);
 
 		kfree(frame);
@@ -354,110 +346,104 @@
 }
 
 /*
- * Reads BANK 2 & Reassembles 
+ * Reads BANK 2 & Reassembles
  */
 
-static void pcbit_receive(struct pcbit_dev * dev)
+static void
+pcbit_receive(struct pcbit_dev *dev)
 {
-        unsigned short tt;
-	u_char cpu, proc;
-        struct frame_buf * frame = NULL;
-        unsigned long flags;
-        u_char type1;
+	unsigned short tt;
+	u_char cpu,
+	 proc;
+	struct frame_buf *frame = NULL;
+	unsigned long flags;
+	u_char type1;
 
-        if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
-                return;
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+		return;
 
-        tt = pcbit_readw(dev);
+	tt = pcbit_readw(dev);
 
-        if ((tt & 0x7fffU) > 511) {
-                printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", 
+	if ((tt & 0x7fffU) > 511) {
+		printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
 		       tt);
-                pcbit_l2_error(dev);
-                return;
-        }
-
-        if (!(tt & 0x8000U))
-        {                       /* Type 0 */
-                type1 = 0;
+		pcbit_l2_error(dev);
+		return;
+	}
+	if (!(tt & 0x8000U)) {  /* Type 0 */
+		type1 = 0;
 
-                if (dev->read_frame) {
-                        printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
+		if (dev->read_frame) {
+			printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
 #if 0
-                        pcbit_l2_error(dev);
-                        return;
+			pcbit_l2_error(dev);
+			return;
 #else
 			/* discard previous queued frame */
 			if (dev->read_frame->skb) {
-				dev->read_frame->skb->free = 1;
+				SET_SKB_FREE(dev->read_frame->skb);
 				kfree_skb(dev->read_frame->skb, FREE_READ);
 			}
 			kfree(dev->read_frame);
 			dev->read_frame = NULL;
 #endif
-                }
+		}
+		frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+
+		if (frame == NULL) {
+			printk(KERN_WARNING "kmalloc failed\n");
+			return;
+		}
+		memset(frame, 0, sizeof(struct frame_buf));
+
+		cpu = pcbit_readb(dev);
+		proc = pcbit_readb(dev);
 
-                frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
-      
-                if (frame == NULL) {
-                        printk(KERN_WARNING "kmalloc failed\n");
-                        return;
-                }
-                memset(frame, 0, sizeof(struct frame_buf));
-      
-                cpu = pcbit_readb(dev);
-                proc = pcbit_readb(dev);
-
-
-                if (cpu != 0x06 && cpu != 0x02)
-                {
-                        printk (KERN_DEBUG "pcbit: invalid cpu value\n");
+
+		if (cpu != 0x06 && cpu != 0x02) {
+			printk(KERN_DEBUG "pcbit: invalid cpu value\n");
 			kfree(frame);
 			pcbit_l2_error(dev);
-                        return;
-                }
-
-                /*
-                 * we discard cpu & proc on receiving
-                 * but we read it to update the pointer
-                 */
-      
-                frame->hdr_len = pcbit_readw(dev);
-                frame->dt_len = pcbit_readw(dev);
-
-		/* 
-                 * 0 sized packet 
-                 * I don't know if they are an error or not...
-                 * But they are very frequent
-                 * Not documented
-                 */
+			return;
+		}
+		/*
+		 * we discard cpu & proc on receiving
+		 * but we read it to update the pointer
+		 */
+
+		frame->hdr_len = pcbit_readw(dev);
+		frame->dt_len = pcbit_readw(dev);
+
+		/*
+		   * 0 sized packet
+		   * I don't know if they are an error or not...
+		   * But they are very frequent
+		   * Not documented
+		 */
 
 		if (frame->hdr_len == 0) {
-                        kfree(frame);
+			kfree(frame);
 #ifdef DEBUG
-                        printk(KERN_DEBUG "0 sized frame\n");
+			printk(KERN_DEBUG "0 sized frame\n");
 #endif
 			pcbit_firmware_bug(dev);
-                        return;
+			return;
 		}
-		
-                /* sanity check the length values */
-                if (frame->hdr_len > 1024 || frame->dt_len > 2048)
-                {
+		/* sanity check the length values */
+		if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
 #ifdef DEBUG
-                        printk(KERN_DEBUG "length problem: ");
-                        printk(KERN_DEBUG "TH=%04x TD=%04x\n", 
-			       frame->hdr_len, 
-                               frame->dt_len);
+			printk(KERN_DEBUG "length problem: ");
+			printk(KERN_DEBUG "TH=%04x TD=%04x\n",
+			       frame->hdr_len,
+			       frame->dt_len);
 #endif
 			pcbit_l2_error(dev);
 			kfree(frame);
-                        return;
-                }
-
-                /* minimum frame read */
+			return;
+		}
+		/* minimum frame read */
 
-		frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + 
+		frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
 					   ((frame->hdr_len + 15) & ~15));
 
 		if (!frame->skb) {
@@ -465,62 +451,57 @@
 			kfree(frame);
 			return;
 		}
-
-                /* 16 byte alignment for IP */		       
+		/* 16 byte alignment for IP */
 		if (frame->dt_len)
-                        skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
+			skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
 
-        }
-        else {
+	} else {
 		/* Type 1 */
-                type1 = 1;
-                tt &= 0x7fffU;
+		type1 = 1;
+		tt &= 0x7fffU;
 
-                if (!(frame = dev->read_frame)) {                
-                        printk("Type 1 frame and no frame queued\n");
+		if (!(frame = dev->read_frame)) {
+			printk("Type 1 frame and no frame queued\n");
 #if 1
 			/* usually after an error: toss frame */
 			dev->readptr += tt;
 			if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
 				dev->readptr -= BANKLEN;
 #else
-                        pcbit_l2_error(dev);
+			pcbit_l2_error(dev);
 #endif
-                        return;
+			return;
 
-                }
-        }
+		}
+	}
 
 	memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
 
 	frame->copied += tt;
 
-        if (frame->copied == frame->hdr_len + frame->dt_len) {
-           
-                save_flags(flags);
-                cli();
-      
-                if (type1) {
-                        dev->read_frame = NULL;
-                }
-      
-                if (dev->read_queue) {
-                        struct frame_buf *ptr;
-                        for(ptr=dev->read_queue;ptr->next;ptr=ptr->next);
-                        ptr->next = frame;
-                }
-                else
-                        dev->read_queue = frame;
-                
-                restore_flags(flags);
-
-        }
-        else {        
-                save_flags(flags);
-                cli();
-                dev->read_frame = frame;
-                restore_flags(flags);
-        }
+	if (frame->copied == frame->hdr_len + frame->dt_len) {
+
+		save_flags(flags);
+		cli();
+
+		if (type1) {
+			dev->read_frame = NULL;
+		}
+		if (dev->read_queue) {
+			struct frame_buf *ptr;
+			for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
+			ptr->next = frame;
+		} else
+			dev->read_queue = frame;
+
+		restore_flags(flags);
+
+	} else {
+		save_flags(flags);
+		cli();
+		dev->read_frame = frame;
+		restore_flags(flags);
+	}
 }
 
 /*
@@ -529,194 +510,173 @@
  *  gotta send a fake acknowledgment to the upper layer somehow
  */
 
-static __inline__ void pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan * chan)
+static __inline__ void
+pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
 {
-     isdn_ctrl ictl;
+	isdn_ctrl ictl;
 
-     if (chan->queued) {
-	     chan->queued--;
-	     
-	     ictl.driver = dev->id;
-	     ictl.command = ISDN_STAT_BSENT;
-	     ictl.arg = chan->id;
-	     dev->dev_if->statcallb(&ictl);     
-     }
+	if (chan->queued) {
+		chan->queued--;
+
+		ictl.driver = dev->id;
+		ictl.command = ISDN_STAT_BSENT;
+		ictl.arg = chan->id;
+		dev->dev_if->statcallb(&ictl);
+	}
 }
 
-static void pcbit_firmware_bug(struct pcbit_dev * dev) 
+static void
+pcbit_firmware_bug(struct pcbit_dev *dev)
 {
-        struct pcbit_chan *chan;
-        
-        chan = dev->b1;
+	struct pcbit_chan *chan;
 
-        if (chan->fsm_state == ST_ACTIVE) {
-	    pcbit_fake_conf(dev, chan);
-        }
+	chan = dev->b1;
 
-        chan = dev->b2;
+	if (chan->fsm_state == ST_ACTIVE) {
+		pcbit_fake_conf(dev, chan);
+	}
+	chan = dev->b2;
 
-        if (chan->fsm_state == ST_ACTIVE) {
-	    pcbit_fake_conf(dev, chan);
-        }
- 
+	if (chan->fsm_state == ST_ACTIVE) {
+		pcbit_fake_conf(dev, chan);
+	}
 }
 
-void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs)
+void
+pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs)
 {
-        struct pcbit_dev * dev;
-        u_char info, ack_seq, read_seq;
+	struct pcbit_dev *dev;
+	u_char info,
+	 ack_seq,
+	 read_seq;
 
 	dev = (struct pcbit_dev *) devptr;
 
-        if (!dev)
-        {
-                printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
-                return;
-        }
-
+	if (!dev) {
+		printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
+		return;
+	}
 	if (dev->interrupt) {
-	        printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
+		printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
 		return;
 	}
-
 	dev->interrupt = 1;
 
-        info = readb(dev->sh_mem + BANK3);
+	info = readb(dev->sh_mem + BANK3);
 
-        if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR)
-        {
-                pcbit_l2_active_conf(dev, info);
+	if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
+		pcbit_l2_active_conf(dev, info);
 		dev->interrupt = 0;
-                return;
-        }
-
-        if (info & 0x40U)       /* E bit set */
-        {
+		return;
+	}
+	if (info & 0x40U) {     /* E bit set */
 #ifdef DEBUG
 		printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
 #endif
-                pcbit_l2_error(dev);
+		pcbit_l2_error(dev);
 		dev->interrupt = 0;
-                return;
-        }
-
-        if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) 
-	{
-	        dev->interrupt = 0;
-                return;
+		return;
 	}
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+		dev->interrupt = 0;
+		return;
+	}
+	ack_seq = (info >> 3) & 0x07U;
+	read_seq = (info & 0x07U);
 
-        ack_seq =  (info >> 3) & 0x07U;
-        read_seq = (info & 0x07U); 
-        
 	dev->interrupt = 0;
 
-        if (read_seq != dev->rcv_seq)
-        {
-		while (read_seq != dev->rcv_seq)
-		{
+	if (read_seq != dev->rcv_seq) {
+		while (read_seq != dev->rcv_seq) {
 			pcbit_receive(dev);
 			dev->rcv_seq = (dev->rcv_seq + 1) % 8;
 		}
 		pcbit_sched_delivery(dev);
-        }
-
-	if (ack_seq != dev->unack_seq)
-        {
-                pcbit_recv_ack(dev, ack_seq);
-        }
-
-
+	}
+	if (ack_seq != dev->unack_seq) {
+		pcbit_recv_ack(dev, ack_seq);
+	}
 	info = dev->rcv_seq << 3;
 	info |= dev->send_seq;
-    
-	writeb(info, dev->sh_mem + BANK4);  
+
+	writeb(info, dev->sh_mem + BANK4);
 }
 
 
-static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
+static void
+pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
 {
-        u_char state;
+	u_char state;
 
-        state = dev->l2_state;
+	state = dev->l2_state;
 
 #ifdef DEBUG
-        printk(KERN_DEBUG "layer2_active_confirm\n");
+	printk(KERN_DEBUG "layer2_active_confirm\n");
 #endif
-        
 
-        if (info & 0x80U ) {
-                dev->rcv_seq = info & 0x07U;
-                dev->l2_state = L2_RUNNING;
-        }
-        else
-                dev->l2_state = L2_DOWN;
-                
-	if (state == L2_STARTING)
-                wake_up_interruptible(&dev->set_running_wq);
 
-        if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
-                pcbit_transmit(dev);
-        }
+	if (info & 0x80U) {
+		dev->rcv_seq = info & 0x07U;
+		dev->l2_state = L2_RUNNING;
+	} else
+		dev->l2_state = L2_DOWN;
+
+	if (state == L2_STARTING)
+		wake_up_interruptible(&dev->set_running_wq);
 
+	if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
+		pcbit_transmit(dev);
+	}
 }
 
-static void pcbit_l2_err_recover(unsigned long data) 
+static void
+pcbit_l2_err_recover(unsigned long data)
 {
 
-        struct pcbit_dev * dev;
-        struct frame_buf *frame;
+	struct pcbit_dev *dev;
+	struct frame_buf *frame;
 
-        dev = (struct pcbit_dev *) data;
+	dev = (struct pcbit_dev *) data;
 
-        del_timer(&dev->error_recover_timer);
-	if (dev->w_busy || dev->r_busy)
-	{
+	del_timer(&dev->error_recover_timer);
+	if (dev->w_busy || dev->r_busy) {
 		init_timer(&dev->error_recover_timer);
 		dev->error_recover_timer.expires = jiffies + ERRTIME;
 		add_timer(&dev->error_recover_timer);
 		return;
 	}
-
 	dev->w_busy = dev->r_busy = 1;
 
-        if (dev->read_frame)
-	{
-                if (dev->read_frame->skb)
-		{
-			dev->read_frame->skb->free = 1; 
-                        kfree_skb(dev->read_frame->skb, FREE_READ);
-		}
-                kfree(dev->read_frame);
-                dev->read_frame = NULL;
-        }
-
-
-        if (dev->write_queue)
-	{
-                frame = dev->write_queue;
+	if (dev->read_frame) {
+		if (dev->read_frame->skb) {
+			SET_SKB_FREE(dev->read_frame->skb);
+			kfree_skb(dev->read_frame->skb, FREE_READ);
+		}
+		kfree(dev->read_frame);
+		dev->read_frame = NULL;
+	}
+	if (dev->write_queue) {
+		frame = dev->write_queue;
 #ifdef FREE_ON_ERROR
-                dev->write_queue = dev->write_queue->next;
+		dev->write_queue = dev->write_queue->next;
 
 		if (frame->skb) {
-                        dev_kfree_skb(frame->skb, FREE_WRITE);
+			dev_kfree_skb(frame->skb, FREE_WRITE);
 		}
-		
-                kfree(frame);
-#else		
-                frame->copied = 0;
+		kfree(frame);
+#else
+		frame->copied = 0;
 #endif
-        }
-
-        dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
-        dev->free = 511;
-        dev->l2_state = L2_ERROR;
+	}
+	dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
+	dev->free = 511;
+	dev->l2_state = L2_ERROR;
 
 	/* this is an hack... */
 	pcbit_firmware_bug(dev);
 
-        dev->writeptr = dev->sh_mem;
-        dev->readptr = dev->sh_mem + BANK2;
+	dev->writeptr = dev->sh_mem;
+	dev->readptr = dev->sh_mem + BANK2;
 
 	writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
 	       dev->sh_mem + BANK4);
@@ -724,24 +684,25 @@
 
 }
 
-static void pcbit_l2_error(struct pcbit_dev *dev)
+static void
+pcbit_l2_error(struct pcbit_dev *dev)
 {
-        if (dev->l2_state == L2_RUNNING) {
+	if (dev->l2_state == L2_RUNNING) {
 
-                printk(KERN_INFO "pcbit: layer 2 error\n");
+		printk(KERN_INFO "pcbit: layer 2 error\n");
 
 #ifdef DEBUG
-                log_state(dev);
+		log_state(dev);
 #endif
-                
-                dev->l2_state = L2_DOWN;
 
-                init_timer(&dev->error_recover_timer);
-                dev->error_recover_timer.function = &pcbit_l2_err_recover;
-                dev->error_recover_timer.data = (ulong) dev;
-                dev->error_recover_timer.expires = jiffies + ERRTIME;
-                add_timer(&dev->error_recover_timer);
-        }
+		dev->l2_state = L2_DOWN;
+
+		init_timer(&dev->error_recover_timer);
+		dev->error_recover_timer.function = &pcbit_l2_err_recover;
+		dev->error_recover_timer.data = (ulong) dev;
+		dev->error_recover_timer.expires = jiffies + ERRTIME;
+		add_timer(&dev->error_recover_timer);
+	}
 }
 
 /*
@@ -751,58 +712,52 @@
  *   call pcbit_transmit to write possible queued frames
  */
 
-static void  pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
+static void
+pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
 {
-        int i, count;
-        int unacked;
+	int i,
+	 count;
+	int unacked;
 
-        unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
+	unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
 
-        /* dev->unack_seq < ack <= dev->send_seq; */
+	/* dev->unack_seq < ack <= dev->send_seq; */
 
-        if (unacked) 
-	{
+	if (unacked) {
 
 		if (dev->send_seq > dev->unack_seq)
-                        if (ack <= dev->unack_seq || ack > dev->send_seq)
-			{
-                                printk(KERN_DEBUG
-				       "layer 2 ack unacceptable - dev %d",
+			if (ack <= dev->unack_seq || ack > dev->send_seq) {
+				printk(KERN_DEBUG
+				     "layer 2 ack unacceptable - dev %d",
 				       dev->id);
 
-                                pcbit_l2_error(dev);
-                        }
-                        else
-                                if (ack > dev->send_seq && ack <= dev->unack_seq)
-				{
-					printk(KERN_DEBUG
-					       "layer 2 ack unacceptable - dev %d",
-					       dev->id);
-                                        pcbit_l2_error(dev);
-                                }
-
-                /* ack is acceptable */
-
-
-                i = dev->unack_seq;
-
-                do {
-                        dev->unack_seq = i = (i + 1) % 8;
-                        dev->free += dev->fsize[i];
-                } while (i != ack);
-
-                count = 0;
-                while (count < 7 && dev->write_queue) 
-		{
+				pcbit_l2_error(dev);
+			} else if (ack > dev->send_seq && ack <= dev->unack_seq) {
+				printk(KERN_DEBUG
+				     "layer 2 ack unacceptable - dev %d",
+				       dev->id);
+				pcbit_l2_error(dev);
+			}
+		/* ack is acceptable */
+
+
+		i = dev->unack_seq;
+
+		do {
+			dev->unack_seq = i = (i + 1) % 8;
+			dev->free += dev->fsize[i];
+		} while (i != ack);
+
+		count = 0;
+		while (count < 7 && dev->write_queue) {
 			u8 lsend_seq = dev->send_seq;
 
-                        pcbit_transmit(dev);
+			pcbit_transmit(dev);
 
 			if (dev->send_seq == lsend_seq)
 				break;
-                        count++;
-                }    
-        }
-        else
-                printk(KERN_DEBUG "recv_ack: unacked = 0\n");
+			count++;
+		}
+	} else
+		printk(KERN_DEBUG "recv_ack: unacked = 0\n");
 }
diff -urN linux-2.0.31-pre2/drivers/isdn/pcbit/module.c linux-2.0.31-pre3/drivers/isdn/pcbit/module.c
--- linux-2.0.31-pre2/drivers/isdn/pcbit/module.c	1996-05-14 23:09:00.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/pcbit/module.c	2003-08-15 15:03:53.000000000 -0700
@@ -22,8 +22,8 @@
 #include <linux/isdnif.h>
 #include "pcbit.h"
 
-int mem[MAX_PCBIT_CARDS] = {0, };
-int irq[MAX_PCBIT_CARDS] = {0, };
+static int mem[MAX_PCBIT_CARDS] = {0, };
+static int irq[MAX_PCBIT_CARDS] = {0, };
 
 int num_boards;
 struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0};
@@ -35,6 +35,10 @@
 extern int pcbit_init_dev(int board, int mem_base, int irq);
 
 #ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+#endif
 #define pcbit_init init_module
 #endif
 
@@ -83,7 +87,11 @@
 	}
 
 	/* No symbols to export, hide all symbols */
+#if (LINUX_VERSION_CODE < 0x020111)
 	register_symtab(NULL);
+#else
+	EXPORT_NO_SYMBOLS;
+#endif
 
 	return 0;
 }
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/card.h linux-2.0.31-pre3/drivers/isdn/sc/card.h
--- linux-2.0.31-pre2/drivers/isdn/sc/card.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/card.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,110 @@
+/*
+ *  $Id: card.h,v 1.1 1996/11/07 13:07:40 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  card.h - Driver parameters for SpellCaster ISA ISDN adapters
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#ifndef CARD_H
+#define CARD_H
+
+/*
+ * We need these if they're not already included
+ */
+#include <linux/timer.h>
+#include <linux/isdnif.h>
+#include "message.h"
+
+/*
+ * Amount of time to wait for a reset to complete
+ */
+#define CHECKRESET_TIME		milliseconds(4000)
+
+/*
+ * Amount of time between line status checks
+ */
+#define CHECKSTAT_TIME		milliseconds(8000)
+
+/*
+ * The maximum amount of time to wait for a message response
+ * to arrive. Use exclusively by send_and_receive
+ */
+#define SAR_TIMEOUT		milliseconds(10000)
+
+/*
+ * Macro to determine is a card id is valid
+ */
+#define IS_VALID_CARD(x)	((x >= 0) && (x <= cinst))
+
+/*
+ * Per channel status and configuration
+ */
+typedef struct {
+	int l2_proto;
+	int l3_proto;
+	char dn[50];
+	unsigned long first_sendbuf;	/* Offset of first send buffer */
+	unsigned int num_sendbufs;	/* Number of send buffers */
+	unsigned int free_sendbufs;	/* Number of free sendbufs */
+	unsigned int next_sendbuf;	/* Next sequential buffer */
+	char eazlist[50];		/* Set with SETEAZ */
+	char sillist[50];		/* Set with SETSIL */
+	int eazclear;			/* Don't accept calls if TRUE */
+} bchan;
+
+/*
+ * Everything you want to know about the adapter ...
+ */
+typedef struct {
+	int model;
+	int driverId;			/* LL Id */
+	char devicename[20];		/* The device name */
+	isdn_if *card;			/* ISDN4Linux structure */
+	bchan *channel;			/* status of the B channels */
+	char nChannels;			/* Number of channels */
+	unsigned int interrupt;		/* Interrupt number */
+	int iobase;			/* I/O Base address */
+	int ioport[MAX_IO_REGS];	/* Index to I/O ports */
+	int shmem_pgport;		/* port for the exp mem page reg. */
+	int shmem_magic;		/* adapter magic number */
+	unsigned int rambase;		/* Shared RAM base address */
+	unsigned int ramsize;		/* Size of shared memory */
+	RspMessage async_msg;		/* Async response message */
+	int want_async_messages;	/* Snoop the Q ? */
+	unsigned char seq_no;		/* Next send seq. number */
+	struct timer_list reset_timer;	/* Check reset timer */
+	struct timer_list stat_timer;	/* Check startproc timer */
+	unsigned char nphystat;		/* Latest PhyStat info */
+	unsigned char phystat;		/* Last PhyStat info */
+	HWConfig_pl hwconfig;		/* Hardware config info */
+	char load_ver[11];		/* CommManage Version string */
+	char proc_ver[11];		/* CommEngine Version */
+	int StartOnReset;		/* Indicates startproc after reset */
+	int EngineUp;			/* Indicates CommEngine Up */
+	int trace_mode;			/* Indicate if tracing is on */
+} board;
+
+#endif /* CARD_H */
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/command.c linux-2.0.31-pre3/drivers/isdn/sc/command.c
--- linux-2.0.31-pre2/drivers/isdn/sc/command.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/command.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,563 @@
+/*
+ *  $Id: command.c,v 1.4 1997/03/30 16:51:34 calle Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"		/* This must be first */
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+#include "scioc.h"
+
+int dial(int card, unsigned long channel, setup_parm setup);
+int hangup(int card, unsigned long channel);
+int answer(int card, unsigned long channel);
+int clreaz(int card, unsigned long channel);
+int seteaz(int card, unsigned long channel, char *);
+int geteaz(int card, unsigned long channel, char *);
+int setsil(int card, unsigned long channel, char *);
+int getsil(int card, unsigned long channel, char *);
+int setl2(int card, unsigned long arg);
+int getl2(int card, unsigned long arg);
+int setl3(int card, unsigned long arg);
+int getl3(int card, unsigned long arg);
+int lock(void);
+int unlock(void);
+int acceptb(int card, unsigned long channel);
+
+extern int cinst;
+extern board *adapter[];
+
+extern int sc_ioctl(int, scs_ioctl *);
+extern int setup_buffers(int, int, unsigned int);
+extern int indicate_status(int, int,ulong,char*);
+extern void check_reset(unsigned long);
+extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
+                unsigned char, unsigned char, unsigned char, unsigned char *,
+                RspMessage *, int);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+                unsigned int, unsigned int, unsigned int, unsigned int *);
+extern inline void pullphone(char *, char *);
+
+#ifdef DEBUG
+/*
+ * Translate command codes to strings
+ */
+static char *commands[] = { "ISDN_CMD_IOCTL",
+			    "ISDN_CMD_DIAL",
+			    "ISDN_CMD_ACCEPTB",
+			    "ISDN_CMD_ACCEPTB",
+			    "ISDN_CMD_HANGUP",
+			    "ISDN_CMD_CLREAZ",
+			    "ISDN_CMD_SETEAZ",
+			    "ISDN_CMD_GETEAZ",
+			    "ISDN_CMD_SETSIL",
+			    "ISDN_CMD_GETSIL",
+			    "ISDN_CMD_SETL2",
+			    "ISDN_CMD_GETL2",
+			    "ISDN_CMD_SETL3",
+			    "ISDN_CMD_GETL3",
+			    "ISDN_CMD_LOCK",
+			    "ISDN_CMD_UNLOCK",
+			    "ISDN_CMD_SUSPEND",
+			    "ISDN_CMD_RESUME" };
+
+/*
+ * Translates ISDN4Linux protocol codes to strings for debug messages
+ */
+static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" };
+static char *l2protos[] = { "ISDN_PROTO_L2_X75I",
+			    "ISDN_PROTO_L2_X75UI",
+			    "ISDN_PROTO_L2_X75BUI",
+			    "ISDN_PROTO_L2_HDLC",
+			    "ISDN_PROTO_L2_TRANS" };
+#endif
+
+int get_card_from_id(int driver)
+{
+	int i;
+
+	for(i = 0 ; i < cinst ; i++) {
+		if(adapter[i]->driverId == driver)
+			return i;
+	}
+	return -NODEV;
+}
+
+/* 
+ * command
+ */
+
+int command(isdn_ctrl *cmd)
+{
+	int card;
+
+	card = get_card_from_id(cmd->driver);
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Received %s command from Link Layer\n",
+		adapter[card]->devicename, commands[cmd->command]);
+
+	/*
+	 * Dispatch the command
+	 */
+	switch(cmd->command) {
+	case ISDN_CMD_IOCTL:
+	{
+		unsigned long 	cmdptr;
+		scs_ioctl	ioc;
+		int		err;
+
+		memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
+		if((err = copy_from_user(&ioc, (scs_ioctl *) cmdptr, 
+			sizeof(scs_ioctl)))) {
+			pr_debug("%s: Failed to verify user space 0x%x\n",
+				adapter[card]->devicename, cmdptr);
+			return err;
+		}
+		return sc_ioctl(card, &ioc);
+	}
+	case ISDN_CMD_DIAL:
+		return dial(card, cmd->arg, cmd->parm.setup);
+	case ISDN_CMD_HANGUP:
+		return hangup(card, cmd->arg);
+	case ISDN_CMD_ACCEPTD:
+		return answer(card, cmd->arg);
+	case ISDN_CMD_ACCEPTB:
+		return acceptb(card, cmd->arg);
+	case ISDN_CMD_CLREAZ:
+		return clreaz(card, cmd->arg);
+	case ISDN_CMD_SETEAZ:
+		return seteaz(card, cmd->arg, cmd->parm.num);
+	case ISDN_CMD_GETEAZ:
+		return geteaz(card, cmd->arg, cmd->parm.num);
+	case ISDN_CMD_SETSIL:
+		return setsil(card, cmd->arg, cmd->parm.num);
+	case ISDN_CMD_GETSIL:
+		return getsil(card, cmd->arg, cmd->parm.num);
+	case ISDN_CMD_SETL2:
+		return setl2(card, cmd->arg);
+	case ISDN_CMD_GETL2:
+		return getl2(card, cmd->arg);
+	case ISDN_CMD_SETL3:
+		return setl3(card, cmd->arg);
+	case ISDN_CMD_GETL3:
+		return getl3(card, cmd->arg);
+	case ISDN_CMD_LOCK:
+		return lock();
+	case ISDN_CMD_UNLOCK:
+		return unlock();
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Confirm our ability to communicate with the board.  This test assumes no
+ * other message activity is present
+ */
+int loopback(int card) 
+{
+
+	int status;
+	static char testmsg[] = "Test Message";
+	RspMessage rspmsg;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Sending loopback message\n", adapter[card]->devicename);
+	
+
+	/*
+	 * Send the loopback message to confirm that memory transfer is
+	 * operational
+	 */
+	status = send_and_receive(card, CMPID, cmReqType1,
+				  cmReqClass0,
+				  cmReqMsgLpbk,
+				  0,
+				  (unsigned char) strlen(testmsg),
+				  (unsigned char *)testmsg,
+				  &rspmsg, SAR_TIMEOUT);
+
+
+	if (!status) {
+		pr_debug("%s: Loopback message successfully sent\n",
+			adapter[card]->devicename);
+		if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
+			pr_debug("%s: Loopback return != sent\n",
+				adapter[card]->devicename);
+			return -EIO;
+		}
+		return 0;
+	}
+	else {
+		pr_debug("%s: Send loopback message failed\n",
+			adapter[card]->devicename);
+		return -EIO;
+	}
+
+}
+
+/*
+ * start the onboard firmware
+ */
+int startproc(int card) 
+{
+	int status;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	/*
+	 * send start msg 
+	 */
+       	status = sendmessage(card, CMPID,cmReqType2,
+			  cmReqClass0,
+			  cmReqStartProc,
+			  0,0,0);
+	pr_debug("%s: Sent startProc\n", adapter[card]->devicename);
+	
+	return status;
+}
+
+
+int loadproc(int card, char *data) 
+{
+	return -1;
+}
+
+
+/*
+ * Dials the number passed in 
+ */
+int dial(int card, unsigned long channel, setup_parm setup) 
+{
+	int status;
+	char Phone[48];
+  
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	/*extract ISDN number to dial from eaz/msn string*/ 
+	strcpy(Phone,setup.phone); 
+
+	/*send the connection message*/
+	status = sendmessage(card, CEPID,ceReqTypePhy,
+				ceReqClass1,
+				ceReqPhyConnect,
+				(unsigned char) channel+1, 
+				strlen(Phone),
+				(unsigned int *) Phone);
+
+	pr_debug("%s: Dialing %s on channel %d\n",
+		adapter[card]->devicename, Phone, channel+1);
+	
+	return status;
+}
+
+/*
+ * Answer an incoming call 
+ */
+int answer(int card, unsigned long channel) 
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
+		hangup(card, channel+1);
+		return -ENOBUFS;
+	}
+
+	indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
+	pr_debug("%s: Answered incoming call on channel %s\n",
+		adapter[card]->devicename, channel+1);
+	return 0;
+}
+
+/*
+ * Hangup up the call on specified channel
+ */
+int hangup(int card, unsigned long channel) 
+{
+	int status;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	status = sendmessage(card, CEPID, ceReqTypePhy,
+						 ceReqClass1,
+						 ceReqPhyDisconnect,
+						 (unsigned char) channel+1,
+						 0,
+						 NULL);
+	pr_debug("%s: Sent HANGUP message to channel %d\n",
+		adapter[card]->devicename, channel+1);
+	return status;
+}
+
+/*
+ * Set the layer 2 protocol (X.25, HDLC, Raw)
+ */
+int setl2(int card, unsigned long arg) 
+{
+	int status =0;
+	int protocol,channel;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+	protocol = arg >> 8;
+	channel = arg & 0xff;
+	adapter[card]->channel[channel].l2_proto = protocol;
+	pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
+		adapter[card]->devicename, channel+1,l2protos[adapter[card]->channel[channel].l2_proto],protocol);
+
+	/*
+	 * check that the adapter is also set to the correct protocol
+	 */
+	pr_debug("%s: Sending GetFrameFormat for channel %d\n",
+		adapter[card]->devicename, channel+1);
+	status = sendmessage(card, CEPID, ceReqTypeCall,
+ 				ceReqClass0,
+ 				ceReqCallGetFrameFormat,
+ 				(unsigned char)channel+1,
+ 				1,
+ 				(unsigned int *) protocol);
+	if(status) 
+		return status;
+	return 0;
+}
+
+/*
+ * Get the layer 2 protocol
+ */
+int getl2(int card, unsigned long channel) {
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Level 2 protocol for channel %d reported as %s\n",
+		adapter[card]->devicename, channel+1,
+		l2protos[adapter[card]->channel[channel].l2_proto]);
+
+	return adapter[card]->channel[channel].l2_proto;
+}
+
+/*
+ * Set the layer 3 protocol
+ */
+int setl3(int card, unsigned long channel) 
+{
+	int protocol = channel >> 8;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	adapter[card]->channel[channel].l3_proto = protocol;
+	pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
+		adapter[card]->devicename, channel+1, l3protos[protocol]);
+	return 0;
+}
+
+/*
+ * Get the layer 3 protocol
+ */
+int getl3(int card, unsigned long arg) 
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Level 3 protocol for channel %d reported as %s\n",
+			adapter[card]->devicename, arg+1,
+			l3protos[adapter[card]->channel[arg].l3_proto]);
+	return adapter[card]->channel[arg].l3_proto;
+}
+
+
+int acceptb(int card, unsigned long channel)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	if(setup_buffers(card, channel+1, BUFFER_SIZE))
+	{
+		hangup(card, channel+1);
+		return -ENOBUFS;
+	}
+
+	pr_debug("%s: B-Channel connection accepted on channel %d\n",
+		adapter[card]->devicename, channel+1);
+	indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
+	return 0;
+}
+
+int clreaz(int card, unsigned long arg)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	strcpy(adapter[card]->channel[arg].eazlist, "");
+	adapter[card]->channel[arg].eazclear = 1;
+	pr_debug("%s: EAZ List cleared for channel %d\n",
+		adapter[card]->devicename, arg+1);
+	return 0;
+}
+
+int seteaz(int card, unsigned long arg, char *num)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	strcpy(adapter[card]->channel[arg].eazlist, num);
+	adapter[card]->channel[arg].eazclear = 0;
+	pr_debug("%s: EAZ list for channel %d set to: %s\n",
+		adapter[card]->devicename, arg+1,
+		adapter[card]->channel[arg].eazlist);
+	return 0;
+}
+
+int geteaz(int card, unsigned long arg, char *num)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	strcpy(num, adapter[card]->channel[arg].eazlist);
+	pr_debug("%s: EAZ List for channel %d reported: %s\n",
+		adapter[card]->devicename, arg+1,
+		adapter[card]->channel[arg].eazlist);
+	return 0;
+}
+
+int setsil(int card, unsigned long arg, char *num)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	strcpy(adapter[card]->channel[arg].sillist, num);
+	pr_debug("%s: Service Indicators for channel %d set: %s\n",
+		adapter[card]->devicename, arg+1,
+		adapter[card]->channel[arg].sillist);
+	return 0;
+}
+
+int getsil(int card, unsigned long arg, char *num)
+{
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	strcpy(num, adapter[card]->channel[arg].sillist);
+	pr_debug("%s: SIL for channel %d reported: %s\n",
+		adapter[card]->devicename, arg+1,
+		adapter[card]->channel[arg].sillist);
+	return 0;
+}
+
+
+int lock()
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+int unlock()
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int reset(int card)
+{
+	unsigned long flags;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	indicate_status(card, ISDN_STAT_STOP, 0, NULL);
+
+	if(adapter[card]->EngineUp) {
+		del_timer(&adapter[card]->stat_timer);	
+	}
+
+	adapter[card]->EngineUp = 0;
+
+	save_flags(flags);
+	cli();
+	init_timer(&adapter[card]->reset_timer);
+	adapter[card]->reset_timer.function = check_reset;
+	adapter[card]->reset_timer.data = card;
+	adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
+	add_timer(&adapter[card]->reset_timer);
+	restore_flags(flags);
+
+	outb(0x1,adapter[card]->ioport[SFT_RESET]); 
+
+	pr_debug("%s: Adapter Reset\n", adapter[card]->devicename);
+	return 0;
+}
+
+void flushreadfifo (int card)
+{
+	while(inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
+		inb(adapter[card]->ioport[FIFO_READ]);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/debug.c linux-2.0.31-pre3/drivers/isdn/sc/debug.c
--- linux-2.0.31-pre2/drivers/isdn/sc/debug.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/debug.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,80 @@
+/*
+ *  $Id: debug.c,v 1.2 1996/11/20 17:49:50 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+#include <linux/kernel.h>
+
+#define NULL	0x0
+
+#if LINUX_VERSION_CODE < 66363	/* Linux 1.3.59 there was a change to interrupts */
+	#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d)
+	#define FREE_IRQ(a,b) free_irq(a)
+#else
+	#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+	#define FREE_IRQ(a,b) free_irq(a,b)
+#endif
+
+inline char *strcpy(char *, const char *);
+
+int dbg_level = 0;
+static char dbg_funcname[255];
+
+void dbg_endfunc(void)
+{
+	if (dbg_level) {
+		printk("<-- Leaving function %s\n", dbg_funcname);
+		strcpy(dbg_funcname, "");
+	}
+}
+
+void dbg_func(char *func)
+{
+	strcpy(dbg_funcname, func);
+	if(dbg_level)
+		printk("--> Entering function %s\n", dbg_funcname);
+}
+
+inline char *strcpy(char *dest, const char *src)
+{
+	char *i = dest;
+	char *j = (char *) src;
+
+	while(*j) {
+		*i = *j;
+		i++; j++;
+	}
+	*(++i) = NULL;
+	return dest;
+}
+
+inline void pullphone(char *dn, char *str)
+{
+	int i = 0;
+
+	while(dn[i] != ',')
+		str[i] = dn[i++];
+	str[i] = 0x0;
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/debug.h linux-2.0.31-pre3/drivers/isdn/sc/debug.h
--- linux-2.0.31-pre2/drivers/isdn/sc/debug.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/debug.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,35 @@
+/*
+ *  $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#if LINUX_VERSION_CODE < 131072
+	#error You cant use this driver on kernels older than 2.0
+#else
+	#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+	#define FREE_IRQ(a,b) free_irq(a,b)
+#endif
+
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/event.c linux-2.0.31-pre3/drivers/isdn/sc/event.c
--- linux-2.0.31-pre2/drivers/isdn/sc/event.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/event.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,75 @@
+/*
+ *  $Id: event.c,v 1.3 1997/02/11 22:53:41 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern int cinst;
+extern board *adapter[];
+
+#ifdef DEBUG
+static char *events[] = { "ISDN_STAT_STAVAIL",
+			  "ISDN_STAT_ICALL",
+			  "ISDN_STAT_RUN",
+			  "ISDN_STAT_STOP",
+			  "ISDN_STAT_DCONN",
+			  "ISDN_STAT_BCONN",
+			  "ISDN_STAT_DHUP",
+			  "ISDN_STAT_BHUP",
+			  "ISDN_STAT_CINF",
+			  "ISDN_STAT_LOAD",
+			  "ISDN_STAT_UNLOAD",
+			  "ISDN_STAT_BSENT",
+			  "ISDN_STAT_NODCH",
+			  "ISDN_STAT_ADDCH",
+			  "ISDN_STAT_CAUSE" };
+#endif
+
+int indicate_status(int card, int event,ulong Channel,char *Data)
+{
+	isdn_ctrl cmd;
+
+	pr_debug("%s: Indicating event %s on Channel %d\n",
+		adapter[card]->devicename, events[event-256], Channel);
+	if (Data != NULL){
+		pr_debug("%s: Event data: %s\n", adapter[card]->devicename,
+			Data);
+		if (event == ISDN_STAT_ICALL)
+			memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
+		else
+			strcpy(cmd.parm.num, Data);
+	}
+
+	cmd.command = event;
+	cmd.driver = adapter[card]->driverId;
+	cmd.arg = Channel;
+	return adapter[card]->card->statcallb(&cmd);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/hardware.h linux-2.0.31-pre3/drivers/isdn/sc/hardware.h
--- linux-2.0.31-pre2/drivers/isdn/sc/hardware.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/hardware.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,117 @@
+/*
+ * Hardware specific macros, defines and structures
+ */
+
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#include <asm/param.h>			/* For HZ */
+
+/*
+ * General hardware parameters common to all ISA adapters
+ */
+
+#define MAX_CARDS	4		/* The maximum number of cards to
+					   control or probe for. If you change
+					   this, you must also change the number
+					   of elements in io, irq, and ram to
+					   match. Initialized in init.c */
+/*
+extern unsigned int io[];
+extern unsigned char irq[];
+extern unsigned long ram[];
+*/
+
+#define SIGNATURE	0x87654321	/* Board reset signature */
+#define SIG_OFFSET	0x1004		/* Where to find signature in shared RAM */
+#define TRACE_OFFSET	0x1008		/* Trace enable word offset in shared RAM */
+#define BUFFER_OFFSET	0x1800		/* Beginning of buffers */
+
+/* I/O Port parameters */
+#define IOBASE_MIN	0x180		/* Lowest I/O port address */
+#define IOBASE_MAX	0x3C0		/* Highest I/O port address */
+#define IOBASE_OFFSET	0x20		/* Inter-board I/O port gap used during
+					   probing */
+#define FIFORD_OFFSET	0x0
+#define FIFOWR_OFFSET	0x400
+#define FIFOSTAT_OFFSET	0x1000
+#define RESET_OFFSET	0x2800
+#define PG0_OFFSET	0x3000		/* Offset from I/O Base for Page 0 register */
+#define PG1_OFFSET	0x3400		/* Offset from I/O Base for Page 1 register */
+#define PG2_OFFSET	0x3800		/* Offset from I/O Base for Page 2 register */
+#define PG3_OFFSET	0x3C00		/* Offset from I/O Base for Page 3 register */
+
+#define FIFO_READ	0		/* FIFO Read register */
+#define FIFO_WRITE	1		/* FIFO Write rgister */
+#define LO_ADDR_PTR	2		/* Extended RAM Low Addr Pointer */
+#define HI_ADDR_PTR	3		/* Extended RAM High Addr Pointer */
+#define NOT_USED_1	4
+#define FIFO_STATUS	5		/* FIFO Status Register */
+#define NOT_USED_2	6
+#define MEM_OFFSET	7
+#define SFT_RESET	10		/* Reset Register */
+#define EXP_BASE	11		/* Shared RAM Base address */
+#define EXP_PAGE0	12		/* Shared RAM Page0 register */
+#define EXP_PAGE1	13		/* Shared RAM Page1 register */
+#define EXP_PAGE2	14		/* Shared RAM Page2 register */
+#define EXP_PAGE3	15		/* Shared RAM Page3 register */
+#define IRQ_SELECT	16		/* IRQ selection register */
+#define MAX_IO_REGS	17		/* Total number of I/O ports */
+
+/* FIFO register values */
+#define RF_HAS_DATA	0x01		/* fifo has data */
+#define RF_QUART_FULL	0x02		/* fifo quarter full */
+#define RF_HALF_FULL	0x04		/* fifo half full */
+#define RF_NOT_FULL	0x08		/* fifo not full */
+#define WF_HAS_DATA	0x10		/* fifo has data */
+#define WF_QUART_FULL	0x20		/* fifo quarter full */
+#define WF_HALF_FULL	0x40		/* fifo half full */
+#define WF_NOT_FULL	0x80		/* fifo not full */
+
+/* Shared RAM parameters */
+#define SRAM_MIN	0xC0000         /* Lowest host shared RAM address */
+#define SRAM_MAX	0xEFFFF         /* Highest host shared RAM address */
+#define SRAM_PAGESIZE	0x4000		/* Size of one RAM page (16K) */
+
+/* Shared RAM buffer parameters */
+#define BUFFER_SIZE	0x800		/* The size of a buffer in bytes */
+#define BUFFER_BASE	BUFFER_OFFSET	/* Offset from start of shared RAM
+					   where buffer start */
+#define BUFFERS_MAX	16		/* Maximum number of send/receive
+					   buffers per channel */
+#define HDLC_PROTO	0x01		/* Frame Format for Layer 2 */
+
+#define BRI_BOARD	0
+#define POTS_BOARD	1
+#define PRI_BOARD	2
+
+/*
+ * Specific hardware parameters for the DataCommute/BRI
+ */
+#define BRI_CHANNELS	2		/* Number of B channels */
+#define BRI_BASEPG_VAL	0x98
+#define BRI_MAGIC	0x60000		/* Magic Number */
+#define BRI_MEMSIZE	0x10000		/* Ammount of RAM (64K) */
+#define BRI_PARTNO	"72-029"
+#define BRI_FEATURES	ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
+/*
+ * Specific hardware parameters for the DataCommute/PRI
+ */
+#define PRI_CHANNELS	23		/* Number of B channels */
+#define PRI_BASEPG_VAL	0x88
+#define PRI_MAGIC	0x20000		/* Magic Number */
+#define PRI_MEMSIZE	0x100000	/* Amount of RAM (1M) */
+#define PRI_PARTNO	"72-030"
+#define PRI_FEATURES	ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
+
+/*
+ * Some handy macros
+ */
+
+/* Return the number of jiffies in a given number of msecs */
+#define milliseconds(x)	(x/(1000/HZ))
+
+/* Determine if a channel number is valid for the adapter */
+#define IS_VALID_CHANNEL(y,x)	((x>0) && (x <= adapter[y]->channels))
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/includes.h linux-2.0.31-pre3/drivers/isdn/sc/includes.h
--- linux-2.0.31-pre2/drivers/isdn/sc/includes.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/includes.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,15 @@
+#include <linux/module.h>
+#include <linux/version.h>
+#include <stdio.h>
+#include <linux/errno.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/isdnif.h>
+#include "debug.h"
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/init.c linux-2.0.31-pre3/drivers/isdn/sc/init.c
--- linux-2.0.31-pre2/drivers/isdn/sc/init.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/init.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,599 @@
+#include "includes.h"
+#include "hardware.h"
+#include "card.h"
+
+board *adapter[MAX_CARDS];
+int cinst;
+
+static char devname[] = "scX";
+const char version[] = "2.0b1";
+
+const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
+
+/* insmod set parameters */
+unsigned int io[] = {0,0,0,0};
+unsigned char irq[] = {0,0,0,0};
+unsigned long ram[] = {0,0,0,0};
+int do_reset = 0;
+
+static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
+#define MAX_IRQS	10
+
+extern void interrupt_handler(int, void *, struct pt_regs *);
+extern int sndpkt(int, int, struct sk_buff *);
+extern int command(isdn_ctrl *);
+extern int indicate_status(int, int, ulong, char*);
+extern int reset(int);
+
+int identify_board(unsigned long, unsigned int);
+
+int irq_supported(int irq_x)
+{
+	int i;
+	for(i=0 ; i < MAX_IRQS ; i++) {
+		if(sup_irq[i] == irq_x)
+			return 1;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(ram, "1-4i");
+MODULE_PARM(do_reset, "i");
+#endif
+#define init_sc init_module
+#else
+/*
+Initialization code for non-module version to be included
+
+void sc_setup(char *str, int *ints)
+{
+}
+*/
+#endif
+
+int init_sc(void)
+{
+	int b = -1;
+	int i, j;
+	int status = -ENODEV;
+
+	unsigned long memsize = 0;
+	unsigned long features = 0;
+	isdn_if *interface;
+	unsigned char channels;
+	unsigned char pgport;
+	unsigned long magic;
+	int model;
+	int last_base = IOBASE_MIN;
+	int probe_exhasted = 0;
+
+#ifdef MODULE
+	pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version);
+#else
+	pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version);
+#endif
+	pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n");
+
+	while(b++ < MAX_CARDS - 1) {
+		pr_debug("Probing for adapter #%d\n", b);
+		/*
+		 * Initialize reusable variables
+		 */
+		model = -1;
+		magic = 0;
+		channels = 0;
+		pgport = 0;
+
+		/* 
+		 * See if we should probe for IO base 
+		 */
+		pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b],
+			io[b] == 0 ? "will" : "won't");
+		if(io[b]) {
+			/*
+			 * No, I/O Base has been provided
+			 */
+			for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
+				if(check_region(io[b] + i * 0x400, 1)) {
+					pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
+					io[b] = 0;
+					break;
+				}
+			}
+
+			/*
+			 * Confirm the I/O Address with a test
+			 */
+			if(io[b] == 0) {
+				pr_debug("I/O Address 0x%x is in use.\n");
+				continue;
+			}
+
+			outb(0x18, io[b] + 0x400 * EXP_PAGE0);
+			if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
+				pr_debug("I/O Base 0x%x fails test\n");
+				continue;
+			}
+		}
+		else {
+			/*
+			 * Yes, probe for I/O Base
+			 */
+			if(probe_exhasted) {
+				pr_debug("All probe addresses exhasted, skipping\n");
+				continue;
+			}
+			pr_debug("Probing for I/O...\n");
+			for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) {
+				int found_io = 1;
+				if (i == IOBASE_MAX) {
+					probe_exhasted = 1; /* No more addresses to probe */
+					pr_debug("End of Probes\n");
+				}
+				last_base = i + IOBASE_OFFSET;
+				pr_debug("  checking 0x%x...", i);
+				for ( j = 0 ; j < MAX_IO_REGS - 1 ; j++) {
+					if(check_region(i + j * 0x400, 1)) {
+						pr_debug("Failed\n");
+						found_io = 0;
+						break;
+					}
+				}	
+
+				if(found_io) {
+					io[b] = i;
+					outb(0x18, io[b] + 0x400 * EXP_PAGE0);
+					if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { 
+						pr_debug("Failed by test\n");
+						continue;
+					}
+					pr_debug("Passed\n");
+					break;
+				}
+			}
+			if(probe_exhasted) {
+				continue;
+			}
+		}
+
+		/*
+		 * See if we should probe for shared RAM
+		 */
+		if(do_reset) {
+			pr_debug("Doing a SAFE probe reset\n");
+			outb(0xFF, io[b] + RESET_OFFSET);
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + milliseconds(10000);
+			schedule();
+		}
+		pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
+			ram[b] == 0 ? "will" : "won't");
+
+		if(ram[b]) {
+			/*
+			 * No, the RAM base has been provided
+			 * Just look for a signature and ID the
+			 * board model
+			 */
+			if(!check_region(ram[b], SRAM_PAGESIZE)) {
+				pr_debug("check_region for RAM base 0x%x succeeded\n", ram[b]);
+			 	model = identify_board(ram[b], io[b]);
+			}
+		}
+		else {
+			/*
+			 * Yes, probe for free RAM and look for
+			 * a signature and id the board model
+			 */
+			for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
+				pr_debug("Checking RAM address 0x%x...\n", i);
+				if(!check_region(i, SRAM_PAGESIZE)) {
+					pr_debug("  check_region succeeded\n");
+					model = identify_board(i, io[b]);
+					if (model >= 0) {
+						pr_debug("  Identified a %s\n",
+							boardname[model]);
+						ram[b] = i;
+						break;
+					}
+					pr_debug("  Unidentifed or inaccessible\n");
+					continue;
+				}
+				pr_debug("  check_region failed\n");
+			}
+		}
+		/*
+		 * See if we found free RAM and the board model
+		 */
+		if(!ram[b] || model < 0) {
+			/*
+			 * Nope, there was no place in RAM for the
+			 * board, or it couldn't be identified
+			 */
+			 pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
+			 continue;
+		}
+
+		/*
+		 * Set the board's magic number, memory size and page register
+		 */
+		switch(model) {
+		case PRI_BOARD:
+			channels = 23;
+			magic = 0x20000;
+			memsize = 0x100000;
+			features = PRI_FEATURES;
+			break;
+
+		case BRI_BOARD:
+		case POTS_BOARD:
+			channels = 2;
+			magic = 0x60000;
+			memsize = 0x10000;
+			features = BRI_FEATURES;
+			break;
+		}
+		switch(ram[b] >> 12 & 0x0F) {
+		case 0x0:
+			pr_debug("RAM Page register set to EXP_PAGE0\n");
+			pgport = EXP_PAGE0;
+			break;
+
+		case 0x4:
+			pr_debug("RAM Page register set to EXP_PAGE1\n");
+			pgport = EXP_PAGE1;
+			break;
+
+		case 0x8:
+			pr_debug("RAM Page register set to EXP_PAGE2\n");
+			pgport = EXP_PAGE2;
+			break;
+
+		case 0xC:
+			pr_debug("RAM Page register set to EXP_PAGE3\n");
+			pgport = EXP_PAGE3;
+			break;
+
+		default:
+			pr_debug("RAM base address doesn't fall on 16K boundary\n");
+			continue;
+		}
+
+		pr_debug("current IRQ: %d  b: %d\n",irq[b],b);
+		/*
+		 * See if we should probe for an irq
+		 */
+		if(irq[b]) {
+			/*
+			 * No we were given one
+			 * See that it is supported and free
+			 */
+			pr_debug("Trying for IRQ: %d\n",irq[b]);
+			if (irq_supported(irq[b])) {
+				if(REQUEST_IRQ(irq[b], interrupt_handler, 
+					SA_PROBE, "sc_probe", NULL)) {
+					pr_debug("IRQ %d is already in use\n", 
+						irq[b]);
+					continue;
+				}
+				FREE_IRQ(irq[b], NULL);
+			}
+		}
+		else {
+			/*
+			 * Yes, we need to probe for an IRQ
+			 */
+			pr_debug("Probing for IRQ...\n");
+			for (i = 0; i < MAX_IRQS ; i++) {
+				if(!REQUEST_IRQ(sup_irq[i], interrupt_handler, SA_PROBE, "sc_probe", NULL)) {
+					pr_debug("Probed for and found IRQ %d\n", sup_irq[i]);
+					FREE_IRQ(sup_irq[i], NULL);
+					irq[b] = sup_irq[i];
+					break;
+				}
+			}
+		}
+
+		/*
+		 * Make sure we got an IRQ
+		 */
+		if(!irq[b]) {
+			/*
+			 * No interrupt could be used
+			 */
+			pr_debug("Failed to aquire an IRQ line\n");
+			continue;
+		}
+
+		/*
+		 * Horray! We found a board, Make sure we can register
+		 * it with ISDN4Linux
+		 */
+		interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+		if (interface == NULL) {
+			/*
+			 * Oops, can't malloc isdn_if
+			 */
+			continue;
+		}
+		memset(interface, 0, sizeof(isdn_if));
+
+		interface->hl_hdrlen = 0;
+		interface->channels = channels;
+		interface->maxbufsize = BUFFER_SIZE;
+		interface->features = features;
+		interface->writebuf_skb = sndpkt;
+		interface->writecmd = NULL;
+		interface->command = command;
+		strcpy(interface->id, devname);
+		interface->id[2] = '0' + cinst;
+
+		/*
+		 * Allocate the board structure
+		 */
+		adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
+		if (adapter[cinst] == NULL) {
+			/*
+			 * Oops, can't alloc memory for the board
+			 */
+			kfree(interface);
+			continue;
+		}
+		memset(adapter[cinst], 0, sizeof(board));
+
+		if(!register_isdn(interface)) {
+			/*
+			 * Oops, couldn't register for some reason
+			 */
+			kfree(interface);
+			kfree(adapter[cinst]);
+			continue;
+		}
+
+		adapter[cinst]->card = interface;
+		adapter[cinst]->driverId = interface->channels;
+		strcpy(adapter[cinst]->devicename, interface->id);
+		adapter[cinst]->nChannels = channels;
+		adapter[cinst]->ramsize = memsize;
+		adapter[cinst]->shmem_magic = magic;
+		adapter[cinst]->shmem_pgport = pgport;
+		adapter[cinst]->StartOnReset = 1;
+
+		/*
+		 * Allocate channels status structures
+		 */
+		adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
+		if (adapter[cinst]->channel == NULL) {
+			/*
+			 * Oops, can't alloc memory for the channels
+			 */
+			indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL);	/* Fix me */
+			kfree(interface);
+			kfree(adapter[cinst]);
+			continue;
+		}
+		memset(adapter[cinst]->channel, 0, sizeof(bchan) * channels);
+
+		/*
+		 * Lock down the hardware resources
+		 */
+		adapter[cinst]->interrupt = irq[b];
+		REQUEST_IRQ(adapter[cinst]->interrupt, interrupt_handler, SA_INTERRUPT, 
+			interface->id, NULL);
+		adapter[cinst]->iobase = io[b];
+		for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
+			adapter[cinst]->ioport[i] = io[b] + i * 0x400;
+			request_region(adapter[cinst]->ioport[i], 1, interface->id);
+			pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[i]);
+		}
+		adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
+		request_region(adapter[cinst]->ioport[IRQ_SELECT], 1, interface->id);
+		pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[IRQ_SELECT]);
+		adapter[cinst]->rambase = ram[b];
+		request_region(adapter[cinst]->rambase, SRAM_PAGESIZE, interface->id);
+
+		pr_info("  %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n", 
+			adapter[cinst]->devicename, adapter[cinst]->driverId, 
+			boardname[model], channels, irq[b], io[b], ram[b]);
+		
+		/*
+		 * reset the adapter to put things in motion
+		 */
+		reset(cinst);
+
+		cinst++;
+		status = 0;
+	}
+	if (status) 
+		pr_info("Failed to find any adapters, driver unloaded\n");
+	return status;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	int i, j;
+
+	for(i = 0 ; i < cinst ; i++) {
+		pr_debug("Cleaning up after adapter %d\n", i);
+		/*
+		 * kill the timers
+		 */
+		del_timer(&(adapter[i]->reset_timer));
+		del_timer(&(adapter[i]->stat_timer));
+
+		/*
+		 * Tell I4L we're toast
+		 */
+		indicate_status(i, ISDN_STAT_STOP, 0, NULL);
+		indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL);
+
+		/*
+		 * Release shared RAM
+		 */
+		release_region(adapter[i]->rambase, SRAM_PAGESIZE);
+
+		/*
+		 * Release the IRQ
+		 */
+		FREE_IRQ(adapter[i]->interrupt, NULL);
+
+		/*
+		 * Reset for a clean start
+		 */
+		outb(0xFF, adapter[i]->ioport[SFT_RESET]);
+
+		/*
+		 * Release the I/O Port regions
+		 */
+		for(j = 0 ; j < MAX_IO_REGS - 1; j++) {
+			release_region(adapter[i]->ioport[j], 1);
+			pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[j]);
+		}
+		release_region(adapter[i]->ioport[IRQ_SELECT], 1);
+		pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[IRQ_SELECT]);
+
+		/*
+		 * Release any memory we alloced
+		 */
+		kfree(adapter[i]->channel);
+		kfree(adapter[i]->card);
+		kfree(adapter[i]);
+	}
+	pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
+}
+#endif
+
+int identify_board(unsigned long rambase, unsigned int iobase) 
+{
+	unsigned int pgport;
+	unsigned long sig;
+	DualPortMemory *dpm;
+	RspMessage rcvmsg;
+	ReqMessage sndmsg;
+	HWConfig_pl hwci;
+	int x;
+
+	pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
+		rambase, iobase);
+
+	/*
+	 * Enable the base pointer
+	 */
+	outb(rambase >> 12, iobase + 0x2c00);
+
+	switch(rambase >> 12 & 0x0F) {
+	case 0x0:
+		pgport = iobase + PG0_OFFSET;
+		pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET);
+		break;
+		
+	case 0x4:
+		pgport = iobase + PG1_OFFSET;
+		pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET);
+		break;
+
+	case 0x8:
+		pgport = iobase + PG2_OFFSET;
+		pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET);
+		break;
+
+	case 0xC:
+		pgport = iobase + PG3_OFFSET;
+		pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET);
+		break;
+	default:
+		pr_debug("Invalid rambase 0x%lx\n", rambase);
+		return -1;
+	}
+
+	/*
+	 * Try to identify a PRI card
+	 */
+	outb(PRI_BASEPG_VAL, pgport);
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + HZ;
+	schedule();
+	sig = readl(rambase + SIG_OFFSET);
+	pr_debug("Looking for a signature, got 0x%x\n", sig);
+#if 0
+/*
+ * For Gary: 
+ * If it's a timing problem, it should be gone with the above schedule()
+ * Another possible reason may be the missing volatile in the original
+ * code. readl() does this for us.
+ */
+	printk("");	/* Hack! Doesn't work without this !!!??? */
+#endif
+	if(sig == SIGNATURE)
+		return PRI_BOARD;
+
+	/*
+	 * Try to identify a PRI card
+	 */
+	outb(BRI_BASEPG_VAL, pgport);
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + HZ;
+	schedule();
+	sig = readl(rambase + SIG_OFFSET);
+	pr_debug("Looking for a signature, got 0x%x\n", sig);
+#if 0
+	printk("");	/* Hack! Doesn't work without this !!!??? */
+#endif
+	if(sig == SIGNATURE)
+		return BRI_BOARD;
+
+	return -1;
+
+	/*
+	 * Try to spot a card
+	 */
+	sig = readl(rambase + SIG_OFFSET);
+	pr_debug("Looking for a signature, got 0x%x\n", sig);
+	if(sig != SIGNATURE)
+		return -1;
+
+	dpm = (DualPortMemory *) rambase;
+
+	memset(&sndmsg, 0, MSG_LEN);
+	sndmsg.msg_byte_cnt = 3;
+	sndmsg.type = cmReqType1;
+	sndmsg.class = cmReqClass0;
+	sndmsg.code = cmReqHWConfig;
+	memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN);
+	outb(0, iobase + 0x400);
+	pr_debug("Sent HWConfig message\n");
+	/*
+	 * Wait for the response
+	 */
+	x = 0;
+	while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 1;
+		schedule();
+		x++;
+	}
+	if(x == 100) {
+		pr_debug("Timeout waiting for response\n");
+		return -1;
+	}
+
+	memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
+	pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
+	memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
+	pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
+		 "                 Part: %s, Rev: %s\n",
+		 hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
+		 hwci.serial_no, hwci.part_no, hwci.rev_no);
+
+	if(!strncmp(PRI_PARTNO, hwci.part_no, 6))
+		return PRI_BOARD;
+	if(!strncmp(BRI_PARTNO, hwci.part_no, 6))
+		return BRI_BOARD;
+		
+	return -1;
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/interrupt.c linux-2.0.31-pre3/drivers/isdn/sc/interrupt.c
--- linux-2.0.31-pre2/drivers/isdn/sc/interrupt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/interrupt.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,258 @@
+/*
+ *  $Id: interrupt.c,v 1.3 1997/02/11 22:53:43 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern indicate_status(int, int, ulong, char *);
+extern void check_phystat(unsigned long);
+extern void dump_messages(int);
+extern int receivemessage(int, RspMessage *);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+        unsigned int, unsigned int, unsigned int, unsigned int *);
+extern void rcvpkt(int, RspMessage *);
+
+extern int cinst;
+extern board *adapter[];
+
+int get_card_from_irq(int irq)
+{
+	int i;
+
+	for(i = 0 ; i < cinst ; i++) {
+		if(adapter[i]->interrupt == irq)
+			return i;
+	}
+	return -1;
+}
+
+/*
+ * 
+ */
+void interrupt_handler(int interrupt, void * cardptr, struct pt_regs *regs ) {
+
+	RspMessage rcvmsg;
+	int channel;
+	int card;
+
+	card = get_card_from_irq(interrupt);
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return;
+	}
+
+	pr_debug("%s: Entered Interrupt handler\n", adapter[card]->devicename);
+	
+ 	/*
+	 * Pull all of the waiting messages off the response queue
+	 */
+	while (!receivemessage(card, &rcvmsg)) {
+		/*
+		 * Push the message to the adapter structure for
+		 * send_and_receive to snoop
+		 */
+		if(adapter[card]->want_async_messages)
+			memcpy(&(adapter[card]->async_msg), &rcvmsg, sizeof(RspMessage));
+
+		channel = (unsigned int) rcvmsg.phy_link_no;
+		
+		/*
+		 * Trap Invalid request messages
+		 */
+		if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
+			pr_debug("%s: Invalid request Message, rsp_status = %d\n", 
+				adapter[card]->devicename, rcvmsg.rsp_status);
+			break;	
+		}
+		
+		/*
+		 * Check for a linkRead message
+		 */
+		if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
+		{
+			pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
+						adapter[card]->devicename,
+						rcvmsg.msg_data.response.msg_len,
+						rcvmsg.msg_data.response.buff_offset);
+			rcvpkt(card, &rcvmsg);
+			continue;
+
+		}
+
+		/*
+		 * Handle a write acknoledgement
+		 */
+		if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
+			pr_debug("%s: Packet Send ACK on channel %d\n", adapter[card]->devicename,
+				rcvmsg.phy_link_no);
+			adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
+			continue;
+		}
+
+		/*
+		 * Handle a connection message
+		 */
+		if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect)) 
+		{
+			unsigned int callid;
+			setup_parm setup;	
+			pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
+						adapter[card]->devicename,
+						rcvmsg.phy_link_no,
+						rcvmsg.rsp_status,
+						rcvmsg.msg_data.byte_array[2]);
+			
+			memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
+			if(callid>=0x8000 && callid<=0xFFFF)
+			{		
+				pr_debug("%s: Got Dial-Out Rsp\n", adapter[card]->devicename);	
+				indicate_status(card, ISDN_STAT_DCONN,
+						(unsigned long)rcvmsg.phy_link_no-1,NULL);
+				
+			}
+			else if(callid>=0x0000 && callid<=0x7FFF)
+			{
+				pr_debug("%s: Got Incomming Call\n", adapter[card]->devicename);	
+				strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
+				strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
+				setup.si1 = 7;
+				setup.si2 = 0;
+				setup.plan = 0;
+				setup.screen = 0;
+
+				indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup);
+				indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+			}
+			continue;
+		}
+
+		/*
+		 * Handle a disconnection message
+		 */
+		if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect)) 
+		{
+			pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
+						adapter[card]->devicename,
+						rcvmsg.phy_link_no,
+						rcvmsg.rsp_status,
+					 	rcvmsg.msg_data.byte_array[2]);
+
+			indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+			indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+			continue;
+
+		}
+
+		/*
+		 * Handle a startProc engine up message
+		 */
+		if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
+			pr_debug("%s: Received EngineUp message\n", adapter[card]->devicename);
+			adapter[card]->EngineUp = 1;
+			sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
+			sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
+			init_timer(&adapter[card]->stat_timer);
+			adapter[card]->stat_timer.function = check_phystat;
+			adapter[card]->stat_timer.data = card;
+			adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
+			add_timer(&adapter[card]->stat_timer);
+			continue;
+		}
+
+		/*
+		 * Start proc response
+		 */
+		if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
+			pr_debug("%s: StartProc Response Status %d\n", adapter[card]->devicename,
+				rcvmsg.rsp_status);
+			continue;
+		}
+
+		/*
+		 * Handle a GetMyNumber Rsp
+		 */
+		if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
+			strcpy(adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
+			continue;
+		}
+			
+		/*
+		 * PhyStatus response
+		 */
+		if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) {
+			unsigned int b1stat, b2stat;
+
+			/*
+			 * Covert the message data to the adapter->phystat code
+			 */
+			b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
+			b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
+
+			adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
+			pr_debug("%s: PhyStat is 0x%2x\n", adapter[card]->devicename,
+				adapter[card]->nphystat);
+			continue;
+		}
+
+
+		/* 
+		 * Handle a GetFramFormat
+		 */
+		if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) {
+			if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) {
+				unsigned int proto = HDLC_PROTO;
+				/*
+				 * Set board format to HDLC if it wasn't already
+				 */
+				pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
+						adapter[card]->devicename,
+					rcvmsg.msg_data.byte_array[0]);
+				sendmessage(card, CEPID, ceReqTypeCall,
+						ceReqClass0,
+						ceReqCallSetFrameFormat,
+						(unsigned char) channel +1,
+						1,&proto);
+				}
+			continue;
+		}
+
+		/*
+		 * Hmm...
+		 */
+		pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
+			adapter[card]->devicename, rcvmsg.type, rcvmsg.class, rcvmsg.code, 
+			rcvmsg.phy_link_no);
+
+	}	/* while */
+
+	pr_debug("%s: Exiting Interrupt Handler\n", adapter[card]->devicename);
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/ioctl.c linux-2.0.31-pre3/drivers/isdn/sc/ioctl.c
--- linux-2.0.31-pre2/drivers/isdn/sc/ioctl.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/ioctl.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,513 @@
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+#include "scioc.h"
+
+extern int indicate_status(int, int, unsigned long, char *);
+extern int startproc(int);
+extern int loadproc(int, char *record);
+extern int reset(int);
+extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
+		unsigned char,unsigned char, 
+		unsigned char, unsigned char *, RspMessage *, int);
+
+extern board *adapter[];
+
+#if 0
+static char *ChannelStates[] = { "Idle", "Ready", "Connecting", "Connected", "Disconnecting" };
+#endif
+
+int GetStatus(int card, boardInfo *);
+
+/*
+ * Process private IOCTL messages (typically from scctrl)
+ */
+int sc_ioctl(int card, scs_ioctl *data)
+{
+	switch(data->command) {
+	case SCIOCRESET:	/* Perform a hard reset of the adapter */
+	{
+		pr_debug("%s: SCIOCRESET: ioctl received\n", adapter[card]->devicename);
+		adapter[card]->StartOnReset = 0;
+		return (reset(card));
+	}
+
+	case SCIOCLOAD:
+	{
+		RspMessage	rcvmsg;
+		char		srec[SCIOC_SRECSIZE];
+		int		status, err;
+
+		pr_debug("%s: SCIOLOAD: ioctl received\n", adapter[card]->devicename);
+		if(adapter[card]->EngineUp) {
+			pr_debug("%s: SCIOCLOAD: Command Failed, LoadProc while engine running.\n",
+				adapter[card]->devicename);
+			return -1;
+		}
+
+		/*
+		 * Get the SRec from user space
+		 */
+		if ((err = copy_from_user(srec, (char *) data->dataptr, sizeof(srec))))
+			return err;
+
+		status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
+				0, sizeof(srec), srec, &rcvmsg, SAR_TIMEOUT);
+		if(status) {
+			pr_debug("%s: SCIOCLOAD: Command Failed, status = %d\n", 
+				adapter[card]->devicename, status);
+			return -1;
+		}
+		else {
+			pr_debug("%s: SCIOCLOAD: Command Sucessful\n", adapter[card]->devicename);
+			return 0;
+		}
+	}
+
+	case SCIOCSTART:
+	{
+		pr_debug("%s: SCIOSTART: ioctl received\n", adapter[card]->devicename);
+		if(adapter[card]->EngineUp) {
+			pr_debug("%s: SCIOCSTART: Command Failed, Engine already running.\n",
+				adapter[card]->devicename);
+			return -1;
+		}
+
+		adapter[card]->StartOnReset = 1;
+		startproc(card);
+		return 0;
+	}
+
+	case SCIOCSETSWITCH:
+	{
+		RspMessage	rcvmsg;
+		char		switchtype;
+		int 		status, err;
+
+		pr_debug("%s: SCIOSETSWITCH: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the switch type from user space
+		 */
+		if ((err = copy_from_user(&switchtype, (char *) data->dataptr, sizeof(char))))
+			return err;
+
+		pr_debug("%s: SCIOCSETSWITCH: Setting switch type to %d\n", adapter[card]->devicename,
+			switchtype);
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
+						0, sizeof(char),&switchtype,&rcvmsg, SAR_TIMEOUT);
+		if(!status && !rcvmsg.rsp_status) {
+			pr_debug("%s: SCIOCSETSWITCH: Command Successful\n", adapter[card]->devicename);
+			return 0;
+		}
+		else {
+			pr_debug("%s: SCIOCSETSWITCH: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+	}
+		
+	case SCIOCGETSWITCH:
+	{
+		RspMessage 	rcvmsg;
+		char		switchtype;
+		int		status, err;
+
+		pr_debug("%s: SCIOGETSWITCH: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the switch type from the board
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
+			ceReqCallGetSwitchType, 0, 0, 0, &rcvmsg, SAR_TIMEOUT);
+		if (!status && !rcvmsg.rsp_status) {
+			pr_debug("%s: SCIOCGETSWITCH: Command Sucessful\n", adapter[card]->devicename);
+		}
+		else {
+			pr_debug("%s: SCIOCGETSWITCH: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+
+		switchtype = rcvmsg.msg_data.byte_array[0];
+
+		/*
+		 * Package the switch type and send to user space
+		 */
+		if ((err = copy_to_user((char *) data->dataptr, &switchtype, sizeof(char))))
+			return err;
+
+		return 0;
+	}
+
+	case SCIOCGETSPID:
+	{
+		RspMessage	rcvmsg;
+		char		spid[SCIOC_SPIDSIZE];
+		int		status, err;
+
+		pr_debug("%s: SCIOGETSPID: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the spid from the board
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
+					data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+		if (!status) {
+			pr_debug("%s: SCIOCGETSPID: Command Sucessful\n", adapter[card]->devicename);
+		}
+		else {
+			pr_debug("%s: SCIOCGETSPID: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+		strcpy(spid, rcvmsg.msg_data.byte_array);
+
+		/*
+		 * Package the switch type and send to user space
+		 */
+		if ((err = copy_to_user((char *) data->dataptr, spid, sizeof(spid))))
+			return err;
+
+		return 0;
+	}	
+
+	case SCIOCSETSPID:
+	{
+		RspMessage	rcvmsg;
+		char		spid[SCIOC_SPIDSIZE];
+		int 		status, err;
+
+		pr_debug("%s: DCBIOSETSPID: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the spid from user space
+		 */
+		if ((err = copy_from_user(spid, (char *) data->dataptr, sizeof(spid))))
+			return err;
+
+		pr_debug("%s: SCIOCSETSPID: Setting channel %d spid to %s\n", 
+			adapter[card]->devicename, data->channel, spid);
+		status = send_and_receive(card, CEPID, ceReqTypeCall, 
+			ceReqClass0, ceReqCallSetSPID, data->channel, 
+			strlen(spid), spid, &rcvmsg, SAR_TIMEOUT);
+		if(!status && !rcvmsg.rsp_status) {
+			pr_debug("%s: SCIOCSETSPID: Command Successful\n", 
+				adapter[card]->devicename);
+			return 0;
+		}
+		else {
+			pr_debug("%s: SCIOCSETSPID: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+	}
+
+	case SCIOCGETDN:
+	{
+		RspMessage	rcvmsg;
+		char		dn[SCIOC_DNSIZE];
+		int		status, err;
+
+		pr_debug("%s: SCIOGETDN: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the dn from the board
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
+					data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+		if (!status) {
+			pr_debug("%s: SCIOCGETDN: Command Sucessful\n", adapter[card]->devicename);
+		}
+		else {
+			pr_debug("%s: SCIOCGETDN: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+
+		strcpy(dn, rcvmsg.msg_data.byte_array);
+
+		/*
+		 * Package the dn and send to user space
+		 */
+		if ((err = copy_to_user((char *) data->dataptr, dn, sizeof(dn))))
+			return err;
+
+		return 0;
+	}	
+
+	case SCIOCSETDN:
+	{
+		RspMessage	rcvmsg;
+		char		dn[SCIOC_DNSIZE];
+		int 		status, err;
+
+		pr_debug("%s: SCIOSETDN: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the spid from user space
+		 */
+		if ((err = copy_from_user(dn, (char *) data->dataptr, sizeof(dn))))
+			return err;
+
+		pr_debug("%s: SCIOCSETDN: Setting channel %d dn to %s\n", 
+			adapter[card]->devicename, data->channel, dn);
+		status = send_and_receive(card, CEPID, ceReqTypeCall, 
+			ceReqClass0, ceReqCallSetMyNumber, data->channel, 
+			strlen(dn),dn,&rcvmsg, SAR_TIMEOUT);
+		if(!status && !rcvmsg.rsp_status) {
+			pr_debug("%s: SCIOCSETDN: Command Successful\n", 
+				adapter[card]->devicename);
+			return 0;
+		}
+		else {
+			pr_debug("%s: SCIOCSETDN: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+	}
+
+	case SCIOCTRACE:
+
+		pr_debug("%s: SCIOTRACE: ioctl received\n", adapter[card]->devicename);
+/*		adapter[card]->trace = !adapter[card]->trace; 
+		pr_debug("%s: SCIOCTRACE: Tracing turned %s\n", adapter[card]->devicename,
+			adapter[card]->trace ? "ON" : "OFF"); */
+		break;
+
+	case SCIOCSTAT:
+	{
+		boardInfo bi;
+		int err;
+
+		pr_debug("%s: SCIOSTAT: ioctl received\n", adapter[card]->devicename);
+		GetStatus(card, &bi);
+		
+		if ((err = copy_to_user((boardInfo *) data->dataptr, &bi, sizeof(boardInfo))))
+			return err;
+
+		return 0;
+	}
+
+	case SCIOCGETSPEED:
+	{
+		RspMessage	rcvmsg;
+		char		speed;
+		int		status, err;
+
+		pr_debug("%s: SCIOGETSPEED: ioctl received\n", adapter[card]->devicename);
+
+		/*
+		 * Get the speed from the board
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, 
+			ceReqCallGetCallType, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+		if (!status && !rcvmsg.rsp_status) {
+			pr_debug("%s: SCIOCGETSPEED: Command Sucessful\n",
+				adapter[card]->devicename);
+		}
+		else {
+			pr_debug("%s: SCIOCGETSPEED: Command Failed (status = %d)\n",
+				adapter[card]->devicename, status);
+			return status;
+		}
+
+		speed = rcvmsg.msg_data.byte_array[0];
+
+		/*
+		 * Package the switch type and send to user space
+		 */
+		if ((err = copy_to_user((char *) data->dataptr, &speed, sizeof(char))))
+			return err;
+
+		return 0;
+	}
+
+	case SCIOCSETSPEED:
+		pr_debug("%s: SCIOCSETSPEED: ioctl received\n", adapter[card]->devicename);
+		break;
+
+	case SCIOCLOOPTST:
+		pr_debug("%s: SCIOCLOOPTST: ioctl received\n", adapter[card]->devicename);
+		break;
+
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+int GetStatus(int card, boardInfo *bi)
+{
+	RspMessage rcvmsg;
+	int i, status;
+
+	/*
+	 * Fill in some of the basic info about the board
+	 */
+	bi->modelid = adapter[card]->model;
+	strcpy(bi->serial_no, adapter[card]->hwconfig.serial_no);
+	strcpy(bi->part_no, adapter[card]->hwconfig.part_no);
+	bi->iobase = adapter[card]->iobase;
+	bi->rambase = adapter[card]->rambase;
+	bi->irq = adapter[card]->interrupt;
+	bi->ramsize = adapter[card]->hwconfig.ram_size;
+	bi->interface = adapter[card]->hwconfig.st_u_sense;
+	strcpy(bi->load_ver, adapter[card]->load_ver);
+	strcpy(bi->proc_ver, adapter[card]->proc_ver);
+
+	/*
+	 * Get the current PhyStats and LnkStats
+	 */
+	status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
+		ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+	if(!status) {
+		if(adapter[card]->model < PRI_BOARD) {
+			bi->l1_status = rcvmsg.msg_data.byte_array[2];
+			for(i = 0 ; i < BRI_CHANNELS ; i++)
+				bi->status.bristats[i].phy_stat =
+					rcvmsg.msg_data.byte_array[i];
+		}
+		else {
+			bi->l1_status = rcvmsg.msg_data.byte_array[0];
+			bi->l2_status = rcvmsg.msg_data.byte_array[1];
+			for(i = 0 ; i < PRI_CHANNELS ; i++)
+				bi->status.pristats[i].phy_stat = 
+					rcvmsg.msg_data.byte_array[i+2];
+		}
+	}
+	
+	/*
+	 * Get the call types for each channel
+	 */
+	for (i = 0 ; i < adapter[card]->nChannels ; i++) {
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+			ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if(!status) {
+			if (adapter[card]->model == PRI_BOARD) {
+				bi->status.pristats[i].call_type = 
+					rcvmsg.msg_data.byte_array[0];
+			}
+			else {
+				bi->status.bristats[i].call_type =
+					rcvmsg.msg_data.byte_array[0];
+			}
+		}
+	}
+	
+	/*
+	 * If PRI, get the call states and service states for each channel
+	 */
+	if (adapter[card]->model == PRI_BOARD) {
+		/*
+		 * Get the call states
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
+			ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if(!status) {
+			for( i = 0 ; i < PRI_CHANNELS ; i++ )
+				bi->status.pristats[i].call_state = 
+					rcvmsg.msg_data.byte_array[i];
+		}
+
+		/*
+		 * Get the service states
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
+			ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if(!status) {
+			for( i = 0 ; i < PRI_CHANNELS ; i++ )
+				bi->status.pristats[i].serv_state = 
+					rcvmsg.msg_data.byte_array[i];
+		}
+
+		/*
+		 * Get the link stats for the channels
+		 */
+		for (i = 1 ; i <= PRI_CHANNELS ; i++) {
+			status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+				ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+			if (!status) {
+				bi->status.pristats[i-1].link_stats.tx_good =
+					(unsigned long)rcvmsg.msg_data.byte_array[0];
+				bi->status.pristats[i-1].link_stats.tx_bad =
+					(unsigned long)rcvmsg.msg_data.byte_array[4];
+				bi->status.pristats[i-1].link_stats.rx_good =
+					(unsigned long)rcvmsg.msg_data.byte_array[8];
+				bi->status.pristats[i-1].link_stats.rx_bad =
+					(unsigned long)rcvmsg.msg_data.byte_array[12];
+			}
+		}
+
+		/*
+		 * Link stats for the D channel
+		 */
+		status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+			ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if (!status) {
+			bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
+			bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
+			bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
+			bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
+		}
+
+		return 0;
+	}
+
+	/*
+	 * If BRI or POTS, Get SPID, DN and call types for each channel
+	 */
+
+	/*
+	 * Get the link stats for the channels
+	 */
+	status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+		ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+	if (!status) {
+		bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
+		bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
+		bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
+		bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
+		bi->status.bristats[0].link_stats.tx_good = 
+			(unsigned long)rcvmsg.msg_data.byte_array[16];
+		bi->status.bristats[0].link_stats.tx_bad = 
+			(unsigned long)rcvmsg.msg_data.byte_array[20];
+		bi->status.bristats[0].link_stats.rx_good = 
+			(unsigned long)rcvmsg.msg_data.byte_array[24];
+		bi->status.bristats[0].link_stats.rx_bad = 
+			(unsigned long)rcvmsg.msg_data.byte_array[28];
+		bi->status.bristats[1].link_stats.tx_good = 
+			(unsigned long)rcvmsg.msg_data.byte_array[32];
+		bi->status.bristats[1].link_stats.tx_bad = 
+			(unsigned long)rcvmsg.msg_data.byte_array[36];
+		bi->status.bristats[1].link_stats.rx_good = 
+			(unsigned long)rcvmsg.msg_data.byte_array[40];
+		bi->status.bristats[1].link_stats.rx_bad = 
+			(unsigned long)rcvmsg.msg_data.byte_array[44];
+	}
+
+	/*
+	 * Get the SPIDs
+	 */
+	for (i = 0 ; i < BRI_CHANNELS ; i++) {
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+			ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if (!status)
+			strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
+	}
+		
+	/*
+	 * Get the DNs
+	 */
+	for (i = 0 ; i < BRI_CHANNELS ; i++) {
+		status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+			ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+		if (!status)
+			strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
+	}
+		
+	return 0;
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/Makefile linux-2.0.31-pre3/drivers/isdn/sc/Makefile
--- linux-2.0.31-pre2/drivers/isdn/sc/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/Makefile	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,44 @@
+#
+#  $Id: Makefile,v 1.1 1997/03/22 02:01:22 fritz Exp $
+#  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#  For more information, please contact gpl-info@spellcast.com or write:
+#
+#     SpellCaster Telecommunications Inc.
+#     5621 Finch Avenue East, Unit #3
+#     Scarborough, Ontario  Canada
+#     M1B 2T9
+#     +1 (416) 297-8565
+#     +1 (416) 297-6433 Facsimile
+#
+
+L_OBJS :=
+M_OBJS :=
+O_OBJS := shmem.o init.o debug.o packet.o command.o event.o \
+	ioctl.o interrupt.o message.o timer.o
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_SC),y)
+	O_TARGET += sc.o
+else
+  ifeq ($(CONFIG_ISDN_DRV_SC),m)
+    O_TARGET += sc.o
+    M_OBJS += sc.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/message.c linux-2.0.31-pre3/drivers/isdn/sc/message.c
--- linux-2.0.31-pre2/drivers/isdn/sc/message.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/message.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,300 @@
+/*
+ *  $Id: message.c,v 1.2 1996/11/20 17:49:54 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  message.c - functions for sending and receiving control messages
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+extern unsigned int cinst;
+
+/*
+ * Obligitory function prototypes
+ */
+extern int indicate_status(int,ulong,char*);
+extern int scm_command(isdn_ctrl *);
+extern void *memcpy_fromshmem(int, void *, const void *, size_t);
+
+/*
+ * Dump message queue in shared memory to screen
+ */
+void dump_messages(int card) 
+{
+	DualPortMemory dpm;
+	unsigned long flags;
+
+	int i =0;
+	
+	if (!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+	}
+
+	save_flags(flags);
+	cli();
+	outb(adapter[card]->ioport[adapter[card]->shmem_pgport], 
+		(adapter[card]->shmem_magic >> 14) | 0x80);
+	memcpy_fromshmem(card, &dpm, 0, sizeof(dpm));
+	restore_flags(flags);
+
+	pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename);
+	for (i = 0; i < dpm.req_head; i++) {
+		pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n",
+				adapter[card]->devicename, i,
+				dpm.req_queue[i].type,
+				dpm.req_queue[i].class,
+				dpm.req_queue[i].code,
+				dpm.req_queue[i].phy_link_no);
+	}
+
+	pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename);
+	for (i = 0; i < dpm.rsp_head; i++) {
+		pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n",
+				adapter[card]->devicename, i,
+				dpm.rsp_queue[i].type,
+				dpm.rsp_queue[i].class,
+				dpm.rsp_queue[i].code,
+				dpm.rsp_queue[i].phy_link_no,
+				dpm.rsp_queue[i].rsp_status);
+	}
+
+}	
+
+/*
+ * receive a message from the board
+ */
+int receivemessage(int card, RspMessage *rspmsg) 
+{
+	DualPortMemory *dpm;
+	unsigned long flags;
+
+	if (!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -EINVAL;
+	}
+	
+	pr_debug("%s: Entered receivemessage\n",adapter[card]->devicename);
+
+	/*
+	 * See if there are messages waiting
+	 */
+	if (inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
+		/*
+		 * Map in the DPM to the base page and copy the message
+		 */
+		save_flags(flags);
+		cli();
+		outb((adapter[card]->shmem_magic >> 14) | 0x80,
+			adapter[card]->ioport[adapter[card]->shmem_pgport]); 
+		dpm = (DualPortMemory *) adapter[card]->rambase;
+		memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), 
+			MSG_LEN);
+		dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
+		inb(adapter[card]->ioport[FIFO_READ]);
+		restore_flags(flags);
+		
+		/*
+		 * Tell the board that the message is received
+		 */
+		pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
+				"cnt:%d (type,class,code):(%d,%d,%d) "
+				"link:%d stat:0x%x\n",
+					adapter[card]->devicename,
+					rspmsg->sequence_no,
+					rspmsg->process_id,
+					rspmsg->time_stamp,
+					rspmsg->cmd_sequence_no,
+					rspmsg->msg_byte_cnt,
+					rspmsg->type,
+					rspmsg->class,
+					rspmsg->code,
+					rspmsg->phy_link_no, 
+					rspmsg->rsp_status);
+
+		return 0;
+	}
+	return -ENOMSG;
+}
+	
+/*
+ * send a message to the board
+ */
+int sendmessage(int card,
+		unsigned int procid,
+		unsigned int type, 
+		unsigned int class, 
+		unsigned int code,
+		unsigned int link, 
+		unsigned int data_len, 
+		unsigned int *data) 
+{
+	DualPortMemory *dpm;
+	ReqMessage sndmsg;
+	unsigned long flags;
+
+	if (!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -EINVAL;
+	}
+
+	/*
+	 * Make sure we only send CEPID messages when the engine is up
+	 * and CMPID messages when it is down
+	 */
+	if(adapter[card]->EngineUp && procid == CMPID) {
+		pr_debug("%s: Attempt to send CM message with engine up\n",
+			adapter[card]->devicename);
+		return -ESRCH;
+	}
+
+	if(!adapter[card]->EngineUp && procid == CEPID) {
+		pr_debug("%s: Attempt to send CE message with engine down\n",
+			adapter[card]->devicename);
+		return -ESRCH;
+	}
+
+	memset(&sndmsg, 0, MSG_LEN);
+	sndmsg.msg_byte_cnt = 4;
+	sndmsg.type = type;
+	sndmsg.class = class;
+	sndmsg.code = code;
+	sndmsg.phy_link_no = link;
+
+	if (data_len > 0) {
+		if (data_len > MSG_DATA_LEN)
+			data_len = MSG_DATA_LEN;
+		memcpy(&(sndmsg.msg_data), data, data_len);
+		sndmsg.msg_byte_cnt = data_len + 8;
+	}
+
+	sndmsg.process_id = procid;
+	sndmsg.sequence_no = adapter[card]->seq_no++ % 256;
+
+	/*
+	 * wait for an empty slot in the queue
+	 */
+	while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
+		SLOW_DOWN_IO;
+
+	/*
+	 * Disable interrupts and map in shared memory
+	 */
+	save_flags(flags);
+	cli();
+	outb((adapter[card]->shmem_magic >> 14) | 0x80,
+		adapter[card]->ioport[adapter[card]->shmem_pgport]); 
+	dpm = (DualPortMemory *) adapter[card]->rambase;	/* Fix me */
+	memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
+	dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
+	outb(sndmsg.sequence_no, adapter[card]->ioport[FIFO_WRITE]);
+	restore_flags(flags);
+		
+	pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
+			"cnt:%d (type,class,code):(%d,%d,%d) "
+			"link:%d\n ",
+				adapter[card]->devicename,
+				sndmsg.sequence_no,
+				sndmsg.process_id,
+				sndmsg.time_stamp,
+				sndmsg.msg_byte_cnt,
+				sndmsg.type,
+				sndmsg.class,
+				sndmsg.code,
+				sndmsg.phy_link_no); 
+		
+	return 0;
+}
+
+int send_and_receive(int card,
+		unsigned int procid, 
+		unsigned char type,
+		unsigned char class, 
+		unsigned char code,
+		unsigned char link,
+	 	unsigned char data_len, 
+		unsigned char *data, 
+		RspMessage *mesgdata,
+		int timeout) 
+{
+	int retval;
+	int tries;
+
+	if (!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -EINVAL;
+	}
+
+	adapter[card]->want_async_messages = 1;
+	retval = sendmessage(card, procid, type, class, code, link, 
+			data_len, (unsigned int *) data);
+  
+	if (retval) {
+		pr_debug("%s: SendMessage failed in SAR\n",
+			adapter[card]->devicename);
+		adapter[card]->want_async_messages = 0;
+		return -EIO;
+	}
+
+	tries = 0;
+	/* wait for the response */
+	while (tries < timeout) {
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 1; 
+		schedule();
+		
+		pr_debug("SAR waiting..\n");
+
+		/*
+		 * See if we got our message back
+		 */
+		if ((adapter[card]->async_msg.type == type) &&
+		    (adapter[card]->async_msg.class == class) &&
+		    (adapter[card]->async_msg.code == code) &&
+		    (adapter[card]->async_msg.phy_link_no == link)) {
+
+			/*
+			 * Got it!
+			 */
+			pr_debug("%s: Got ASYNC message\n",
+				adapter[card]->devicename);
+			memcpy(mesgdata, &(adapter[card]->async_msg), 
+				sizeof(RspMessage));
+			adapter[card]->want_async_messages = 0;
+			return 0;
+		}
+
+   		tries++;
+	}
+
+	pr_debug("%s: SAR message timeout\n", adapter[card]->devicename);
+	adapter[card]->want_async_messages = 0;
+	return -ETIME;
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/message.h linux-2.0.31-pre3/drivers/isdn/sc/message.h
--- linux-2.0.31-pre2/drivers/isdn/sc/message.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/message.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,256 @@
+/*
+ *  $Id: message.h,v 1.1 1996/11/07 13:07:47 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  message.h - structures, macros and defines useful for sending
+ *              messages to the adapter
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+/*
+ * Board message macros, defines and structures
+ */
+ 
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#define MAX_MESSAGES		32	/* Maximum messages that can be
+					   queued */
+#define MSG_DATA_LEN		48	/* Maximum size of message payload */
+#define MSG_LEN			64	/* Size of a message */
+#define CMPID			0	/* Loader message process ID */
+#define CEPID			64	/* Firmware message process ID */
+
+/*
+ * Macro to determine if a message is a loader message
+ */
+#define IS_CM_MESSAGE(mesg, tx, cx, dx)		\
+		((mesg.type == cmRspType##tx)		\
+		&&(mesg.class == cmRspClass##cx)	\
+		&&(mesg.code == cmRsp##dx))
+
+/*
+ * Macro to determine if a message is a firmware message
+ */
+#define IS_CE_MESSAGE(mesg, tx, cx, dx)		\
+		((mesg.type == ceRspType##tx)		\
+		&&(mesg.class == ceRspClass##cx)	\
+		&&(mesg.code == ceRsp##tx##dx))
+
+/* 
+ * Loader Request and Response Messages
+ */
+
+/* message types */
+#define cmReqType1			1
+#define cmReqType2			2
+#define cmRspType0			0
+#define cmRspType1			1
+#define cmRspType2			2
+#define cmRspType5			5
+
+/* message classes */
+#define cmReqClass0			0
+#define cmRspClass0			0
+
+/* message codes */
+#define cmReqHWConfig		1			/* 1,0,1 */
+#define cmReqMsgLpbk		2			/* 1,0,2 */
+#define cmReqVersion		3			/* 1,0,3 */
+#define cmReqLoadProc		1			/* 2,0,1 */
+#define cmReqStartProc		2			/* 2,0,2 */
+#define cmReqReadMem		6			/* 2,0,6 */
+#define cmRspHWConfig		cmReqHWConfig
+#define	cmRspMsgLpbk		cmReqMsgLpbk
+#define cmRspVersion		cmReqVersion
+#define cmRspLoadProc		cmReqLoadProc
+#define cmRspStartProc		cmReqStartProc
+#define	cmRspReadMem		cmReqReadMem
+#define cmRspMiscEngineUp	1			/* 5,0,1 */
+#define cmRspInvalid		0			/* 0,0,0 */
+
+
+/*
+ * Firmware Request and Response Messages
+ */
+
+/* message types */
+#define ceReqTypePhy		1
+#define ceReqTypeLnk		2
+#define ceReqTypeCall		3
+#define ceReqTypeStat		1
+#define ceRspTypeErr		0
+#define	ceRspTypePhy		ceReqTypePhy
+#define ceRspTypeLnk		ceReqTypeLnk
+#define ceRspTypeCall		ceReqTypeCall
+#define ceRspTypeStat		ceReqTypeStat
+
+/* message classes */
+#define ceReqClass0		0
+#define ceReqClass1		1
+#define ceReqClass2		2
+#define ceReqClass3		3
+#define ceRspClass0		ceReqClass0
+#define ceRspClass1		ceReqClass1
+#define ceRspClass2		ceReqClass2
+#define ceRspClass3		ceReqClass3
+
+/* message codes  (B) = BRI only, (P) = PRI only, (V) = POTS only */
+#define ceReqPhyProcInfo	1			/* 1,0,1 */
+#define ceReqPhyConnect		1			/* 1,1,1 */
+#define ceReqPhyDisconnect	2			/* 1,1,2 */
+#define ceReqPhySetParams	3			/* 1,1,3 (P) */
+#define ceReqPhyGetParams	4			/* 1,1,4 (P) */
+#define ceReqPhyStatus		1			/* 1,2,1 */
+#define ceReqPhyAcfaStatus	2			/* 1,2,2 (P) */
+#define ceReqPhyChCallState	3			/* 1,2,3 (P) */
+#define ceReqPhyChServState	4			/* 1,2,4 (P) */
+#define ceReqPhyRLoopBack	1			/* 1,3,1 */
+#define ceRspPhyProcInfo	ceReqPhyProcInfo
+#define	ceRspPhyConnect		ceReqPhyConnect
+#define ceRspPhyDisconnect	ceReqPhyDisconnect
+#define ceRspPhySetParams	ceReqPhySetParams
+#define ceRspPhyGetParams	ceReqPhyGetParams
+#define ceRspPhyStatus		ceReqPhyStatus
+#define ceRspPhyAcfaStatus	ceReqPhyAcfaStatus
+#define ceRspPhyChCallState	ceReqPhyChCallState
+#define ceRspPhyChServState	ceReqPhyChServState
+#define ceRspPhyRLoopBack	ceReqphyRLoopBack
+#define ceReqLnkSetParam	1			/* 2,0,1 */
+#define ceReqLnkGetParam	2			/* 2,0,2 */
+#define ceReqLnkGetStats	3			/* 2,0,3 */
+#define ceReqLnkWrite		1			/* 2,1,1 */
+#define ceReqLnkRead		2			/* 2,1,2 */
+#define ceReqLnkFlush		3			/* 2,1,3 */
+#define ceReqLnkWrBufTrc	4			/* 2,1,4 */
+#define ceReqLnkRdBufTrc	5			/* 2,1,5 */
+#define ceRspLnkSetParam	ceReqLnkSetParam
+#define ceRspLnkGetParam	ceReqLnkGetParam
+#define ceRspLnkGetStats	ceReqLnkGetStats
+#define ceRspLnkWrite		ceReqLnkWrite
+#define ceRspLnkRead		ceReqLnkRead
+#define ceRspLnkFlush		ceReqLnkFlush
+#define ceRspLnkWrBufTrc	ceReqLnkWrBufTrc
+#define ceRspLnkRdBufTrc	ceReqLnkRdBufTrc
+#define ceReqCallSetSwitchType	1			/* 3,0,1 */
+#define ceReqCallGetSwitchType	2			/* 3,0,2 */
+#define ceReqCallSetFrameFormat	3			/* 3,0,3 */
+#define ceReqCallGetFrameFormat	4			/* 3,0,4 */
+#define ceReqCallSetCallType	5			/* 3,0,5 */
+#define ceReqCallGetCallType	6			/* 3,0,6 */
+#define ceReqCallSetSPID	7			/* 3,0,7 (!P) */
+#define ceReqCallGetSPID	8			/* 3,0,8 (!P) */
+#define ceReqCallSetMyNumber	9			/* 3,0,9 (!P) */
+#define ceReqCallGetMyNumber	10			/* 3,0,10 (!P) */
+#define	ceRspCallSetSwitchType	ceReqCallSetSwitchType
+#define ceRspCallGetSwitchType	ceReqCallSetSwitchType
+#define ceRspCallSetFrameFormat	ceReqCallSetFrameFormat
+#define ceRspCallGetFrameFormat	ceReqCallGetFrameFormat
+#define ceRspCallSetCallType	ceReqCallSetCallType
+#define ceRspCallGetCallType	ceReqCallGetCallType
+#define ceRspCallSetSPID	ceReqCallSetSPID
+#define ceRspCallGetSPID	ceReqCallGetSPID
+#define ceRspCallSetMyNumber	ceReqCallSetMyNumber
+#define ceRspCallGetMyNumber	ceReqCallGetMyNumber
+#define ceRspStatAcfaStatus	2
+#define ceRspStat
+#define ceRspErrError		0			/* 0,0,0 */
+
+/*
+ * Call Types
+ */
+#define CALLTYPE_64K		0
+#define CALLTYPE_56K		1
+#define CALLTYPE_SPEECH		2
+#define CALLTYPE_31KHZ		3
+
+/*
+ * Link Level data contains a pointer to and the length of
+ * a buffer in shared RAM. Used by LnkRead and LnkWrite message
+ * types. Part of RspMsgStruct and ReqMsgStruct.
+ */
+typedef struct {
+	unsigned long buff_offset;
+	unsigned short msg_len;
+} LLData;
+
+
+/* 
+ * Message payload template for an HWConfig message
+ */
+typedef struct {
+	char st_u_sense;
+	char powr_sense;
+	char sply_sense;
+	unsigned char asic_id;
+	long ram_size;
+	char serial_no[13];
+	char part_no[13];
+	char rev_no[2];
+} HWConfig_pl;
+
+/*
+ * A Message
+ */
+struct message {
+	unsigned char sequence_no;
+	unsigned char process_id;
+	unsigned char time_stamp;
+	unsigned char cmd_sequence_no;	/* Rsp messages only */
+	unsigned char reserved1[3];
+	unsigned char msg_byte_cnt;
+	unsigned char type;
+	unsigned char class;
+	unsigned char code;
+	unsigned char phy_link_no;
+	unsigned char rsp_status;	/* Rsp messages only */
+	unsigned char reseved2[3];
+	union {
+		unsigned char byte_array[MSG_DATA_LEN];
+		LLData response;
+		HWConfig_pl HWCresponse;
+	} msg_data;
+};
+
+typedef struct message ReqMessage;	/* Request message */
+typedef struct message RspMessage;	/* Response message */
+
+/*
+ * The first 5010 bytes of shared memory contain the message queues,
+ * indexes and other data. This structure is its template
+ */
+typedef struct {
+	volatile ReqMessage req_queue[MAX_MESSAGES];
+	volatile RspMessage rsp_queue[MAX_MESSAGES];
+	volatile unsigned char req_head;
+	volatile unsigned char req_tail;
+	volatile unsigned char rsp_head;
+	volatile unsigned char rsp_tail;
+	volatile unsigned long signature;
+	volatile unsigned long trace_enable;
+	volatile unsigned char reserved[4];
+} DualPortMemory;
+
+#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/packet.c linux-2.0.31-pre3/drivers/isdn/sc/packet.c
--- linux-2.0.31-pre2/drivers/isdn/sc/packet.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/packet.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,228 @@
+/*
+ *  $Id: packet.c,v 1.2 1996/11/20 17:49:55 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+extern unsigned int cinst;
+
+extern int get_card_from_id(int);
+extern int indicate_status(int, int,ulong,char*);
+extern void *memcpy_toshmem(int, void *, const void *, size_t);
+extern void *memcpy_fromshmem(int, void *, const void *, size_t);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+                unsigned int, unsigned int, unsigned int, unsigned int *);
+
+int sndpkt(int devId, int channel, struct sk_buff *data)
+{
+	LLData	ReqLnkWrite;
+	int status;
+	int card;
+
+	card = get_card_from_id(devId);
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Send Packet: frst = 0x%x nxt = %d  f = %d n = %d\n",
+		adapter[card]->devicename,
+		adapter[card]->channel[channel].first_sendbuf,
+		adapter[card]->channel[channel].next_sendbuf,
+		adapter[card]->channel[channel].free_sendbufs,
+		adapter[card]->channel[channel].num_sendbufs);
+
+	if(!adapter[card]->channel[channel].free_sendbufs) {
+		pr_debug("%s: Out out TX buffers\n", adapter[card]->devicename);
+		return -EINVAL;
+	}
+
+	if(data->len > BUFFER_SIZE) {
+		pr_debug("%s: Data overflows buffer size (data > buffer)\n", adapter[card]->devicename);
+		return -EINVAL;
+	}
+
+	ReqLnkWrite.buff_offset = adapter[card]->channel[channel].next_sendbuf *
+		BUFFER_SIZE + adapter[card]->channel[channel].first_sendbuf;
+	ReqLnkWrite.msg_len = data->len; /* sk_buff size */
+	pr_debug("%s: Writing %d bytes to buffer offset 0x%x\n", adapter[card]->devicename,
+			ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
+	memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
+
+	/*
+	 * sendmessage
+	 */
+	pr_debug("%s: Send Packet size=%d, buf_offset=0x%x buf_indx=%d\n",
+		adapter[card]->devicename,
+		ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
+		adapter[card]->channel[channel].next_sendbuf);
+
+	status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
+				channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
+	if(status) {
+		pr_debug("%s: Failed to send packet, status = %d\n", adapter[card]->devicename, status);
+		return -1;
+	}
+	else {
+		adapter[card]->channel[channel].free_sendbufs--;
+		adapter[card]->channel[channel].next_sendbuf =
+			++adapter[card]->channel[channel].next_sendbuf ==
+			adapter[card]->channel[channel].num_sendbufs ? 0 :
+			adapter[card]->channel[channel].next_sendbuf;
+			pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename);
+		dev_kfree_skb(data, FREE_WRITE);
+		indicate_status(card,ISDN_STAT_BSENT,channel,NULL);
+	}
+	return data->len;
+}
+
+void rcvpkt(int card, RspMessage *rcvmsg)
+{
+	LLData newll;
+	struct sk_buff *skb;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return;
+	}
+
+	switch(rcvmsg->rsp_status){
+	case 0x01:
+	case 0x02:
+	case 0x70:
+		pr_debug("%s: Error status code: 0x%x\n", adapter[card]->devicename, rcvmsg->rsp_status);
+		return;
+	case 0x00: 
+	    if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) {
+			printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n",
+				adapter[card]->devicename);
+			return;
+		}
+		skb_put(skb, rcvmsg->msg_data.response.msg_len);
+		pr_debug("%s: getting data from offset: 0x%x\n",
+			adapter[card]->devicename,rcvmsg->msg_data.response.buff_offset);
+		memcpy_fromshmem(card,
+			skb_put(skb, rcvmsg->msg_data.response.msg_len),
+		 	(char *)rcvmsg->msg_data.response.buff_offset,
+			rcvmsg->msg_data.response.msg_len);
+		adapter[card]->card->rcvcallb_skb(adapter[card]->driverId,
+			rcvmsg->phy_link_no-1, skb);
+
+	case 0x03:
+		/*
+	 	 * Recycle the buffer
+	 	 */
+		pr_debug("%s: Buffer size : %d\n", adapter[card]->devicename, BUFFER_SIZE);
+/*		memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
+		newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
+		newll.msg_len = BUFFER_SIZE;
+		pr_debug("%s: recycled buffer at offset 0x%x size %d\n", adapter[card]->devicename,
+			newll.buff_offset, newll.msg_len);
+		sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
+			rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll);
+	}
+
+}
+
+int setup_buffers(int card, int c)
+{
+	unsigned int nBuffers, i, cBase;
+	unsigned int buffer_size;
+	LLData	RcvBuffOffset;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return -ENODEV;
+	}
+
+	/*
+	 * Calculate the buffer offsets (send/recv/send/recv)
+	 */
+	pr_debug("%s: Seting up channel buffer space in shared RAM\n", adapter[card]->devicename);
+	buffer_size = BUFFER_SIZE;
+	nBuffers = ((adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
+	nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers;
+	pr_debug("%s: Calculating buffer space: %d buffers, %d big\n", adapter[card]->devicename,
+		nBuffers, buffer_size);
+	if(nBuffers < 2) {
+		pr_debug("%s: Not enough buffer space\n", adapter[card]->devicename);
+		return -1;
+	}
+	cBase = (nBuffers * buffer_size) * (c - 1);
+	pr_debug("%s: Channel buffer offset from Shared RAM: 0x%x\n", adapter[card]->devicename, cBase);
+	adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
+	adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
+	adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
+	adapter[card]->channel[c-1].next_sendbuf = 0;
+	pr_debug("%s: Send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
+				adapter[card]->devicename,
+				adapter[card]->channel[c-1].first_sendbuf,
+				adapter[card]->channel[c-1].num_sendbufs,
+				adapter[card]->channel[c-1].free_sendbufs,
+				adapter[card]->channel[c-1].next_sendbuf);
+
+	/*
+	 * Prep the receive buffers
+	 */
+	pr_debug("%s: Adding %d RecvBuffers:\n", adapter[card]->devicename, nBuffers /2);
+	for (i = 0 ; i < nBuffers / 2; i++) {
+		RcvBuffOffset.buff_offset = 
+			((adapter[card]->channel[c-1].first_sendbuf +
+			(nBuffers / 2) * buffer_size) + (buffer_size * i));
+		RcvBuffOffset.msg_len = buffer_size;
+		pr_debug("%s: Adding RcvBuffer #%d offset=0x%x sz=%d buffsz:%d\n",
+				adapter[card]->devicename,
+				i + 1, RcvBuffOffset.buff_offset, 
+				RcvBuffOffset.msg_len,buffer_size);
+		sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
+				c, sizeof(LLData), (unsigned int *)&RcvBuffOffset);
+	} 
+	return 0;
+}
+
+int print_skb(int card,char *skb_p, int len){
+	int i,data;
+	pr_debug("%s: data at 0x%x len: 0x%x\n",adapter[card]->devicename,
+			skb_p,len);
+	for(i=1;i<=len;i++,skb_p++){
+		data = (int) (0xff & (*skb_p));
+		pr_debug("%s: data =  0x%x",adapter[card]->devicename,data);
+		if(!(i%4))
+			pr_debug(" ");
+		if(!(i%32))
+			pr_debug("\n");
+	}
+	pr_debug("\n");
+	return 0;
+}		
+
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/scioc.h linux-2.0.31-pre3/drivers/isdn/sc/scioc.h
--- linux-2.0.31-pre2/drivers/isdn/sc/scioc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/scioc.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,101 @@
+
+/*
+ * IOCTL Command Codes
+ */
+#define SCIOCLOAD	0x01	/* Load a firmware record */
+#define SCIOCRESET	0x02	/* Perform hard reset */
+#define SCIOCDEBUG	0x03	/* Set debug level */
+#define SCIOCREV	0x04	/* Get driver revision(s) */
+#define SCIOCSTART	0x05	/* Start the firmware */
+#define SCIOCGETSWITCH	0x06	/* Get switch type */
+#define SCIOCSETSWITCH	0x07	/* Set switch type */
+#define SCIOCGETSPID	0x08	/* Get channel SPID */
+#define SCIOCSETSPID	0x09 	/* Set channel SPID */
+#define SCIOCGETDN	0x0A	/* Get channel DN */
+#define SCIOCSETDN	0x0B 	/* Set channel DN */
+#define SCIOCTRACE	0x0C	/* Toggle trace mode */
+#define SCIOCSTAT	0x0D	/* Get line status */
+#define SCIOCGETSPEED	0x0E	/* Set channel speed */
+#define SCIOCSETSPEED	0x0F	/* Set channel speed */
+#define SCIOCLOOPTST	0x10	/* Perform loopback test */
+
+typedef struct {
+	int device;
+	int channel;
+	unsigned long command;
+	void *dataptr;
+} scs_ioctl;
+
+/* Size of strings */
+#define SCIOC_SPIDSIZE		49
+#define SCIOC_DNSIZE		SCIOC_SPIDSIZE
+#define SCIOC_REVSIZE		SCIOC_SPIDSIZE
+#define SCIOC_SRECSIZE		49
+
+typedef struct {
+	unsigned long tx_good;
+	unsigned long tx_bad;
+	unsigned long rx_good;
+	unsigned long rx_bad;
+} ChLinkStats;
+
+typedef struct {
+	char spid[49];
+	char dn[49];
+	char call_type;
+	char phy_stat;
+	ChLinkStats link_stats;
+} BRIStat;
+
+typedef BRIStat POTStat;
+
+typedef struct {
+	char call_type;
+	char call_state;
+	char serv_state;
+	char phy_stat;
+	ChLinkStats link_stats;
+} PRIStat;
+
+typedef char PRIInfo;
+typedef char BRIInfo;
+typedef char POTInfo;
+
+
+typedef struct {
+	char acfa_nos;
+	char acfa_ais;
+	char acfa_los;
+	char acfa_rra;
+	char acfa_slpp;
+	char acfa_slpn;
+	char acfa_fsrf;
+} ACFAStat;
+
+typedef struct {
+	unsigned char modelid;
+	char serial_no[13];
+	char part_no[13];
+	char load_ver[11];
+	char proc_ver[11];
+	int iobase;
+	long rambase;
+	char irq;
+	long ramsize;
+	char interface;
+	char switch_type;
+	char l1_status;
+	char l2_status;
+	ChLinkStats dch_stats;
+	ACFAStat AcfaStats;
+	union {
+		PRIStat pristats[23];
+		BRIStat bristats[2];
+		POTStat potsstats[2];
+	} status;
+	union {
+		PRIInfo priinfo;
+		BRIInfo briinfo;
+		POTInfo potsinfo;
+	} info;
+} boardInfo;
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/shmem.c linux-2.0.31-pre3/drivers/isdn/sc/shmem.c
--- linux-2.0.31-pre2/drivers/isdn/sc/shmem.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/shmem.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,165 @@
+/*
+ *  $Id: shmem.c,v 1.2 1996/11/20 17:49:56 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  card.c - Card functions implementing ISDN4Linux functionality
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"		/* This must be first */
+#include "hardware.h"
+#include "card.h"
+
+/*
+ * Main adapter array
+ */
+extern board *adapter[];
+extern int cinst;
+
+/*
+ *
+ */
+void *memcpy_toshmem(int card, void *dest, const void *src, size_t n)
+{
+	unsigned long flags;
+	void *ret;
+	unsigned char ch;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return NULL;
+	}
+
+	if(n > SRAM_PAGESIZE) {
+		return NULL;
+	}
+
+	/*
+	 * determine the page to load from the address
+	 */
+	ch = (unsigned long) dest / SRAM_PAGESIZE;
+	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+	/*
+	 * Block interrupts and load the page
+	 */
+	save_flags(flags);
+	cli();
+
+	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		adapter[card]->ioport[adapter[card]->shmem_pgport]);
+	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	ret = memcpy_toio(adapter[card]->rambase + 
+		((unsigned long) dest % 0x4000), src, n);
+	pr_debug("%s: copying %d bytes from %#x to %#x\n",adapter[card]->devicename, n,
+		 (unsigned long) src, adapter[card]->rambase + ((unsigned long) dest %0x4000));
+	restore_flags(flags);
+
+	return ret;
+}
+
+/*
+ * Reverse of above
+ */
+void *memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
+{
+	unsigned long flags;
+	void *ret;
+	unsigned char ch;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return NULL;
+	}
+
+	if(n > SRAM_PAGESIZE) {
+		return NULL;
+	}
+
+	/*
+	 * determine the page to load from the address
+	 */
+	ch = (unsigned long) src / SRAM_PAGESIZE;
+	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+	
+	
+	/*
+	 * Block interrupts and load the page
+	 */
+	save_flags(flags);
+	cli();
+
+	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		adapter[card]->ioport[adapter[card]->shmem_pgport]);
+	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	ret = memcpy_fromio(dest,(void *)(adapter[card]->rambase + 
+		((unsigned long) src % 0x4000)), n);
+/*	pr_debug("%s: copying %d bytes from %#x to %#x\n",
+		adapter[card]->devicename, n,
+		adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
+	restore_flags(flags);
+
+	return ret;
+}
+
+void *memset_shmem(int card, void *dest, int c, size_t n)
+{
+	unsigned long flags;
+	unsigned char ch;
+	void *ret;
+
+	if(!IS_VALID_CARD(card)) {
+		pr_debug("Invalid param: %d is not a valid card id\n", card);
+		return NULL;
+	}
+
+	if(n > SRAM_PAGESIZE) {
+		return NULL;
+	}
+
+	/*
+	 * determine the page to load from the address
+	 */
+	ch = (unsigned long) dest / SRAM_PAGESIZE;
+	pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+
+	/*
+	 * Block interrupts and load the page
+	 */
+	save_flags(flags);
+	cli();
+
+	outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+		adapter[card]->ioport[adapter[card]->shmem_pgport]);
+	pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+		((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+	ret = memset_io(adapter[card]->rambase + 
+		((unsigned long) dest % 0x4000), c, n);
+	restore_flags(flags);
+
+	return ret;
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/sc/timer.c linux-2.0.31-pre3/drivers/isdn/sc/timer.c
--- linux-2.0.31-pre2/drivers/isdn/sc/timer.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/sc/timer.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,172 @@
+/*
+ *  $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $
+ *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  For more information, please contact gpl-info@spellcast.com or write:
+ *
+ *     SpellCaster Telecommunications Inc.
+ *     5621 Finch Avenue East, Unit #3
+ *     Scarborough, Ontario  Canada
+ *     M1B 2T9
+ *     +1 (416) 297-8565
+ *     +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+
+extern void flushreadfifo(int);
+extern int  startproc(int);
+extern int  indicate_status(int, int, unsigned long, char *);
+extern int  sendmessage(int, unsigned int, unsigned int, unsigned int,
+        unsigned int, unsigned int, unsigned int, unsigned int *);
+
+
+/*
+ * Write the proper values into the I/O ports following a reset
+ */
+void setup_ports(int card)
+{
+
+	outb((adapter[card]->rambase >> 12), adapter[card]->ioport[EXP_BASE]);
+
+	/* And the IRQ */
+	outb((adapter[card]->interrupt | 0x80), 
+		adapter[card]->ioport[IRQ_SELECT]);
+}
+
+/*
+ * Timed function to check the status of a previous reset
+ * Must be very fast as this function runs in the context of
+ * an interrupt handler.
+ *
+ * Setup the ioports for the board that were cleared by the reset.
+ * Then, check to see if the signate has been set. Next, set the
+ * signature to a known value and issue a startproc if needed.
+ */
+void check_reset(unsigned long data)
+{
+	unsigned long flags;
+	unsigned long sig;
+	int card = (unsigned int) data;
+
+	pr_debug("%s: check_timer timer called\n", adapter[card]->devicename);
+
+	/* Setup the io ports */
+	setup_ports(card);
+
+  	save_flags(flags);
+	cli();
+	outb(adapter[card]->ioport[adapter[card]->shmem_pgport],
+		(adapter[card]->shmem_magic>>14) | 0x80);	
+	sig = (unsigned long) *((unsigned long *)(adapter[card]->rambase + SIG_OFFSET));	
+
+	/* check the signature */
+	if(sig == SIGNATURE) {
+		flushreadfifo(card);
+		restore_flags(flags);
+		/* See if we need to do a startproc */
+		if (adapter[card]->StartOnReset)
+			startproc(card);
+	}
+	else  {
+		pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
+			adapter[card]->devicename, CHECKRESET_TIME);
+		del_timer(&adapter[card]->reset_timer);
+		adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
+		add_timer(&adapter[card]->reset_timer);
+	}
+	restore_flags(flags);
+		
+}
+
+/*
+ * Timed function to check the status of a previous reset
+ * Must be very fast as this function runs in the context of
+ * an interrupt handler.
+ *
+ * Send check adapter->phystat to see if the channels are up
+ * If they are, tell ISDN4Linux that the board is up. If not,
+ * tell IADN4Linux that it is up. Always reset the timer to
+ * fire again (endless loop).
+ */
+void check_phystat(unsigned long data)
+{
+	unsigned long flags;
+	int card = (unsigned int) data;
+
+	pr_debug("%s: Checking status...\n", adapter[card]->devicename);
+	/* 
+	 * check the results of the last PhyStat and change only if
+	 * has changed drastically
+	 */
+	if (adapter[card]->nphystat && !adapter[card]->phystat) {   /* All is well */
+		pr_debug("PhyStat transition to RUN\n");
+		pr_info("%s: Switch contacted, transmitter enabled\n", 
+			adapter[card]->devicename);
+		indicate_status(card, ISDN_STAT_RUN, 0, NULL);
+	}
+	else if (!adapter[card]->nphystat && adapter[card]->phystat) {   /* All is not well */
+		pr_debug("PhyStat transition to STOP\n");
+		pr_info("%s: Switch connection lost, transmitter disabled\n", 
+			adapter[card]->devicename);
+
+		indicate_status(card, ISDN_STAT_STOP, 0, NULL);
+	}
+
+	adapter[card]->phystat = adapter[card]->nphystat;
+
+	/* Reinitialize the timer */
+	save_flags(flags);
+	cli();
+	del_timer(&adapter[card]->stat_timer);
+	adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
+	add_timer(&adapter[card]->stat_timer);
+	restore_flags(flags);
+
+	/* Send a new cePhyStatus message */
+	sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
+		ceReqPhyStatus,0,0,NULL);
+}
+
+/*
+ * When in trace mode, this callback is used to swap the working shared
+ * RAM page to the trace page(s) and process all received messages. It
+ * must be called often enough to get all of the messages out of RAM before
+ * it loops around.
+ * Trace messages are \n terminated strings.
+ * We output the messages in 64 byte chunks through readstat. Each chunk
+ * is scanned for a \n followed by a time stamp. If the timerstamp is older
+ * than the current time, scanning stops and the page and offset are recorded
+ * as the starting point the next time the trace timer is called. The final
+ * step is to restore the working page and reset the timer.
+ */
+void trace_timer(unsigned long data)
+{
+	unsigned long flags;
+
+	/*
+	 * Disable interrupts and swap the first page
+	 */
+	save_flags(flags);
+	cli();
+}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/buffers.c linux-2.0.31-pre3/drivers/isdn/teles/buffers.c
--- linux-2.0.31-pre2/drivers/isdn/teles/buffers.c	1996-06-01 01:56:51.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/buffers.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,326 +0,0 @@
-/* $Id: buffers.c,v 1.3 1996/05/31 00:56:53 fritz Exp $
- *
- * $Log: buffers.c,v $
- * Revision 1.3  1996/05/31 00:56:53  fritz
- * removed cli() from BufPoolAdd, since it is called
- * with interrupts off anyway.
- *
- * Revision 1.2  1996/04/29 22:48:14  fritz
- * Removed compatibility-macros. No longer needed.
- *
- * Revision 1.1  1996/04/13 10:19:28  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
-	    int maxpages)
-{
-#ifdef DEBUG_MAGIC
-	generateerror
-	    bp->magic = 010167;
-#endif
-
-#if 0
-	printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
-	bp->freelist = NULL;
-	bp->pageslist = NULL;
-	bp->pageorder = order;
-	bp->pagescount = 0;
-	bp->bpps = bpps;
-	bp->bufsize = BUFFER_SIZE(order, bpps);
-	bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
-	struct Pages   *ptr;
-	byte           *bptr;
-	int             i;
-	struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
-	printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
-	ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
-	if (!ptr) {
-		printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
-		return (-1);
-	}
-#if 0
-	printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
-	ptr->next = bp->pageslist;
-	bp->pageslist = ptr;
-	bp->pagescount++;
-
-	bptr = (byte *) ptr + sizeof(struct Pages *);
-
-	i = bp->bpps;
-	first = (struct BufHeader *) bptr;
-	prev = NULL;
-	while (i--) {
-		bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
-		bh->magic = 020167;
-#endif
-		bh->next = prev;
-		prev = bh;
-		bh->bp = bp;
-		bptr += PART_SIZE(bp->pageorder, bp->bpps);
-	}
-
-	first->next = bp->freelist;
-	bp->freelist = bh;
-	return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
-	struct Pages   *p;
-
-#if 0
-	printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
-	while (bp->pagescount--) {
-		p = bp->pageslist->next;
-		free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
-		printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
-		bp->pageslist = p;
-	}
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
-	   struct BufPool *bp, int priority, void *heldby, int where)
-{
-	long            flags;
-	int             i;
-
-#ifdef DEBUG_MAGIC
-	if (bp->magic != 010167) {
-		printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
-		return (-1);
-	}
-#endif
-
-	save_flags(flags);
-	cli();
-	i = 0;
-	while (!0) {
-		if (bp->freelist) {
-			*bh = bp->freelist;
-			bp->freelist = bp->freelist->next;
-			(*bh)->heldby = heldby;
-			(*bh)->where = where;
-			restore_flags(flags);
-			return (0);
-		}
-		if ((i == 0) && (bp->pagescount < bp->maxpages)) {
-                        if (BufPoolAdd(bp, priority)) {
-                                restore_flags(flags);
-                                return -1;
-                        }
-			i++;
-		} else {
-			*bh = NULL;
-			restore_flags(flags);
-			return (-1);
-		}
-	}
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
-	struct BufPool *bp;
-	long            flags;
-
-#ifdef DEBUG_MAGIC
-	if (bh->magic != 020167) {
-		printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
-		printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
-		return;
-	}
-#endif
-
-	bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
-	if (bp->magic != 010167) {
-		printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
-		return;
-	}
-#endif
-
-	save_flags(flags);
-	cli();
-	bh->next = bp->freelist;
-	bp->freelist = bh;
-	restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
-	     struct BufHeader *bh)
-{
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-	if (!bq->head)
-		bq->head = bh;
-	if (bq->tail)
-		bq->tail->next = bh;
-	bq->tail = bh;
-	bh->next = NULL;
-	restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
-		  struct BufHeader *bh)
-{
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-	bh->next = bq->head;
-	bq->head = bh;
-	if (!bq->tail)
-		bq->tail = bh;
-	restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-
-	if (bq->head) {
-		if (bq->tail == bq->head)
-			bq->tail = NULL;
-		*bh = bq->head;
-		bq->head = (*bh)->next;
-		restore_flags(flags);
-		return (0);
-	} else {
-		restore_flags(flags);
-		return (-1);
-	}
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
-	bq->magic = 030167;
-#endif
-	bq->head = NULL;
-	bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
-	struct BufHeader *bh;
-
-	while (bq->head) {
-		BufQueueUnlink(&bh, bq);
-		BufPoolRelease(bh);
-	}
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
-	int             i = 0;
-	struct BufHeader *bh;
-
-	bh = bq->head;
-	while (bh) {
-		i++;
-		bh = bh->next;
-	}
-	return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
-		int releasetoo)
-{
-	long            flags;
-	struct BufHeader *sp;
-
-	save_flags(flags);
-	cli();
-
-	while (!0) {
-		sp = q->head;
-		if (!sp)
-			break;
-		if ((sp->primitive == pr) && (sp->heldby == heldby)) {
-			q->head = sp->next;
-			if (q->tail == sp)
-				q->tail = NULL;
-			if (releasetoo)
-				BufPoolRelease(sp);
-		} else
-			break;
-	}
-
-	sp = q->head;
-	if (sp)
-		while (sp->next) {
-			if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
-				if (q->tail == sp->next)
-					q->tail = sp;
-				if (releasetoo)
-					BufPoolRelease(sp->next);
-				sp->next = sp->next->next;
-			} else
-				sp = sp->next;
-		}
-	restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#if 0
-	printk(KERN_DEBUG "Sfree %x\n", ptr);
-#endif
-	kfree(ptr);
-}
-
-byte           *
-Smalloc(int size, int pr, char *why)
-{
-	byte           *p;
-
-	p = (byte *) kmalloc(size, pr);
-#if 0
-	printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p);
-#endif
-	return (p);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/callc.c linux-2.0.31-pre3/drivers/isdn/teles/callc.c
--- linux-2.0.31-pre2/drivers/isdn/teles/callc.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/callc.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1482 +0,0 @@
-/* $Id: callc.c,v 1.14 1996/10/22 23:14:14 fritz Exp $
- *
- * $Log: callc.c,v $
- * Revision 1.14  1996/10/22 23:14:14  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.13  1996/06/24 17:15:55  fritz
- * corrected return code of teles_writebuf()
- *
- * Revision 1.12  1996/06/12 16:15:33  fritz
- * Extended user-configurable debugging flags.
- *
- * Revision 1.11  1996/06/07 12:32:20  fritz
- * More changes to support suspend/resume.
- *
- * Revision 1.10  1996/06/06 21:24:21  fritz
- * Started adding support for suspend/resume.
- *
- * Revision 1.9  1996/05/31 12:23:57  jdenoud
- * Jan: added channel open check to teles_writebuf
- *
- * Revision 1.8  1996/05/31 01:00:38  fritz
- * Changed return code of teles_writebuf, when out of memory.
- *
- * Revision 1.7  1996/05/17 03:40:37  fritz
- * General cleanup.
- *
- * Revision 1.6  1996/05/10 22:42:07  fritz
- * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
- *
- * Revision 1.5  1996/05/06 10:16:15  fritz
- * Added voice stuff.
- *
- * Revision 1.4  1996/04/30 22:04:05  isdn4dev
- *   improved callback  Karsten Keil
- *
- * Revision 1.3  1996/04/30 10:04:19  fritz
- * Started voice support.
- * Added printk() to debug-switcher for easier
- * synchronization between printk()'s and output
- * of /dev/isdnctrl.
- *
- * Revision 1.2  1996/04/20 16:42:29  fritz
- * Changed statemachine to allow reject of incoming calls.
- *
- * Revision 1.1  1996/04/13 10:20:59  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int      nrcards;
-extern int      drid;
-extern isdn_if  iif;
-extern void     teles_mod_dec_use_count(void);
-extern void     teles_mod_inc_use_count(void);
-
-static int      init_ds(int chan, int incoming);
-static void     release_ds(int chan);
-static char    *strcpyupto(char *dest, char *src, char upto);
-
-static struct Fsm callcfsm =
-{NULL, 0, 0},   lcfsm =
-{NULL, 0, 0};
-
-struct Channel *chanlist;
-static int      chancount = 0;
-unsigned int    debugflags = 0;
-
-#define TMR_DCHAN_EST 2000
-
-static void
-stat_debug(struct Channel *chanp, char *s)
-{
-	char            tmp[100], tm[32];
-
-	jiftime(tm, jiffies);
-	sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
-	teles_putstatus(tmp);
-}
-
-enum {
-        ST_NULL,           /*  0 inactive                                               */
-        ST_OUT,            /*  1 outgoing, awaiting SETUP confirm                       */
-        ST_CLEAR,          /*  2 call release, awaiting RELEASE confirm                 */
-        ST_OUT_W,          /*  3 outgoing, awaiting d-channel establishment             */
-        ST_REL_W,          /*  4 awaiting d-channel release                             */
-        ST_IN_W,           /*  5 incoming, awaiting d-channel establishment             */
-        ST_IN,             /*  6 incoming call received                                 */
-        ST_IN_SETUP,       /*  7 incoming, SETUP response sent                          */
-        ST_IN_DACT,        /*  8 incoming connected, no b-channel prot.                 */
-        ST_OUT_ESTB,       /* 10 outgoing connected, awaiting b-channel prot. estbl.    */
-        ST_ACTIVE,         /* 11 active, b channel prot. established                    */
-        ST_BC_HANGUP,      /* 12 call clear. (initiator), awaiting b channel prot. rel. */
-        ST_PRO_W,          /* 13 call clear. (initiator), DISCONNECT req. sent          */
-        ST_ANT_W,          /* 14 call clear. (receiver), awaiting DISCONNECT ind.       */
-        ST_DISC_BC_HANGUP, /*    d channel gone, wait for b channel deactivation        */
-	ST_OUT_W_HANGUP,      /* Outgoing waiting for D-Channel hangup received */ 
-        ST_D_ERR,          /*    d channel released while active                        */
-};
-
-#define STATE_COUNT (ST_D_ERR+1)
-
-static char    *strState[] =
-{
-        "ST_NULL",
-        "ST_OUT",
-        "ST_CLEAR",
-        "ST_OUT_W",
-        "ST_REL_W",
-        "ST_IN_W",
-        "ST_IN",
-        "ST_IN_SETUP",
-        "ST_IN_DACT",
-        "ST_OUT_ESTB",
-        "ST_ACTIVE",
-        "ST_BC_HANGUP",
-        "ST_PRO_W",
-        "ST_ANT_W",
-        "ST_DISC_BC_HANGUP",
-        "ST_OUT_W_HANGUP",
-        "ST_D_ERR",
-};
-
-enum {
-        EV_DIAL,           /*  0 */
-        EV_SETUP_CNF,      /*  1 */
-        EV_ACCEPTB,        /*  2 */
-        EV_DISCONNECT_CNF, /*  5 */
-        EV_DISCONNECT_IND, /*  6 */
-        EV_RELEASE_CNF,    /*  7 */
-        EV_DLEST,          /*  8 */
-        EV_DLRL,           /*  9 */
-        EV_SETUP_IND,      /* 10 */
-        EV_RELEASE_IND,    /* 11 */
-        EV_ACCEPTD,        /* 12 */
-        EV_SETUP_CMPL_IND, /* 13 */
-        EV_BC_EST,         /* 14 */
-        EV_WRITEBUF,       /* 15 */
-        EV_DATAIN,         /* 16 */
-        EV_HANGUP,         /* 17 */
-        EV_BC_REL,         /* 18 */
-        EV_CINF,           /* 19 */
-        EV_SUSPEND,        /* 20 */
-        EV_RESUME,         /* 21 */
-};
-
-#define EVENT_COUNT (EV_CINF+1)
-
-static char    *strEvent[] =
-{
-        "EV_DIAL",
-        "EV_SETUP_CNF",
-        "EV_ACCEPTB",
-        "EV_DISCONNECT_CNF",
-        "EV_DISCONNECT_IND",
-        "EV_RELEASE_CNF",
-        "EV_DLEST",
-        "EV_DLRL",
-        "EV_SETUP_IND",
-        "EV_RELEASE_IND",
-        "EV_ACCEPTD",
-        "EV_SETUP_CMPL_IND",
-        "EV_BC_EST",
-        "EV_WRITEBUF",
-        "EV_DATAIN",
-        "EV_HANGUP",
-        "EV_BC_REL",
-        "EV_CINF",
-        "EV_SUSPEND",
-        "EV_RESUME",
-};
-
-enum {
-        ST_LC_NULL,
-        ST_LC_ACTIVATE_WAIT,
-        ST_LC_DELAY,
-        ST_LC_ESTABLISH_WAIT,
-        ST_LC_CONNECTED,
-        ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char    *strLcState[] =
-{
-        "ST_LC_NULL",
-        "ST_LC_ACTIVATE_WAIT",
-        "ST_LC_DELAY",
-        "ST_LC_ESTABLISH_WAIT",
-        "ST_LC_CONNECTED",
-        "ST_LC_RELEASE_WAIT",
-};
-
-enum {
-        EV_LC_ESTABLISH,
-        EV_LC_PH_ACTIVATE,
-        EV_LC_PH_DEACTIVATE,
-        EV_LC_DL_ESTABLISH,
-        EV_LC_TIMER,
-        EV_LC_DL_RELEASE,
-        EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char    *strLcEvent[] =
-{
-        "EV_LC_ESTABLISH",
-        "EV_LC_PH_ACTIVATE",
-        "EV_LC_PH_DEACTIVATE",
-        "EV_LC_DL_ESTABLISH",
-        "EV_LC_TIMER",
-        "EV_LC_DL_RELEASE",
-        "EV_LC_RELEASE",
-};
-
-#define LC_D  0
-#define LC_B  1
-
-static int
-my_atoi(char *s)
-{
-        int             i, n;
-
-        n = 0;
-        if (!s)
-                return -1;
-        for (i = 0; *s >= '0' && *s <= '9'; i++, s++)
-                n = 10 * n + (*s - '0');
-        return n;
-}
-
-/*
- * Dial out
- */
-static void
-r1(struct FsmInst *fi, int event, void *arg)
-{
-        isdn_ctrl      *ic = arg;
-        struct Channel *chanp = fi->userdata;
-        char           *ptr;
-        char            sis[3];
-
-        /* Destination Phone-Number */
-        ptr = strcpyupto(chanp->para.called, ic->num, ',');
-        /* Source Phone-Number */
-        ptr = strcpyupto(chanp->para.calling, ptr + 1, ',');
-        if (!strcmp(chanp->para.calling, "0"))
-                chanp->para.calling[0] = '\0';
-
-        /* Service-Indicator 1 */
-        ptr = strcpyupto(sis, ptr + 1, ',');
-        chanp->para.info = my_atoi(sis);
-
-        /* Service-Indicator 2 */
-        ptr = strcpyupto(sis, ptr + 1, '\0');
-        chanp->para.info2 = my_atoi(sis);
-
-        chanp->l2_active_protocol = chanp->l2_protocol;
-        chanp->incoming = 0;
-        chanp->lc_b.l2_start = !0;
-
-        switch (chanp->l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  chanp->lc_b.l2_establish = !0;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  chanp->lc_b.l2_establish = 0;
-                  break;
-          default:
-                  printk(KERN_WARNING "r1 unknown protocol\n");
-                  break;
-        }
-
-        FsmChangeState(fi, ST_OUT_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-ll_hangup(struct Channel *chanp, int bchantoo)
-{
-        isdn_ctrl       ic;
-
-        if (bchantoo) {
-                if (chanp->debug & 1)
-                        stat_debug(chanp, "STAT_BHUP");
-                ic.driver = drid;
-                ic.command = ISDN_STAT_BHUP;
-                ic.arg = chanp->chan;
-                iif.statcallb(&ic);
-        }
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_DHUP");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_DHUP;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static void
-r2(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        FsmChangeState(fi, ST_CLEAR);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r2_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-
-        FsmChangeState(fi, ST_OUT_W_HANGUP);
-}
-
-
-static void
-r2_2(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_REL_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r3(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        FsmChangeState(fi, ST_REL_W);
-}
-
-
-static void
-r3_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-	
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-        FsmChangeState(fi, ST_REL_W);
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r4(struct FsmInst *fi, int event, void *arg)
-{
-	struct Channel *chanp=fi->userdata;  
-  
-        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);                                  
-        FsmChangeState(fi, ST_NULL);
-}
-
-static void
-r5(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->para.callref = chanp->outcallref;
-
-        chanp->outcallref++;
-        if (chanp->outcallref == 128)
-                chanp->outcallref = 64;
-
-        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
-
-        FsmChangeState(fi, ST_OUT);
-}
-
-static void
-r6(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r7(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-        /*
-         * Report incoming calls only once to linklevel, use octet 3 of
-         * channel identification information element. (it's value
-         * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c)
-         */
-        if (((chanp->chan & 1) + 1) & chanp->para.bchannel) {
-                chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
-                FsmChangeState(fi, ST_IN);
-                if (chanp->debug & 1)
-                        stat_debug(chanp, "STAT_ICALL");
-                ic.driver = drid;
-                ic.command = ISDN_STAT_ICALL;
-                ic.arg = chanp->chan;
-                /*
-                 * No need to return "unknown" for calls without OAD,
-                 * cause that's handled in linklevel now (replaced by '0')
-                 */
-                sprintf(ic.num, "%s,%d,0,%s", chanp->para.calling, chanp->para.info,
-                        chanp->para.called);
-                iif.statcallb(&ic);
-        } else {
-                chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-                FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-                FsmChangeState(fi, ST_REL_W);
-        }
-}
-
-static void
-r8(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_SETUP);
-        chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
-
-}
-
-static void
-r9(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_IN_DACT);
-
-        chanp->l2_active_protocol = chanp->l2_protocol;
-        chanp->incoming = !0;
-        chanp->lc_b.l2_start = 0;
-
-        switch (chanp->l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  chanp->lc_b.l2_establish = !0;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  chanp->lc_b.l2_establish = 0;
-                  break;
-          default:
-                  printk(KERN_WARNING "r9 unknown protocol\n");
-                  break;
-        }
-
-        init_ds(chanp->chan, !0);
-
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r10(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_OUT_ESTB);
-
-        init_ds(chanp->chan, 0);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-
-}
-
-static void
-r12(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-        FsmChangeState(fi, ST_ACTIVE);
-        chanp->data_open = !0;
-
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_DCONN");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_DCONN;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-
-        if (chanp->debug & 1)
-                stat_debug(chanp, "STAT_BCONN");
-        ic.driver = drid;
-        ic.command = ISDN_STAT_BCONN;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static void
-r15(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_BC_HANGUP);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r16(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_PRO_W);
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r17(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_ANT_W);
-}
-
-
-static void
-r17_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        release_ds(chanp->chan);
-
-	chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-	
-	FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
-	
-        FsmChangeState(fi, ST_NULL);
-        
-        ll_hangup(chanp,!0); 
-}
-
-static void
-r18(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_REL_W);
-        FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r19(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        FsmChangeState(fi, ST_CLEAR);
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r20(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        
-        chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); 
-        
-        FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); 
-
-        FsmChangeState(fi, ST_NULL);
-
-        ll_hangup(chanp, 0);
-}
-
-
-static void
-r21(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_DISC_BC_HANGUP);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r22(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_CLEAR);
-
-        chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r23(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_PRO_W);
-        chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r23_1(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-	chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL); 
-	
-	FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL); 
-	
-        FsmChangeState(fi, ST_NULL);
-        
-        ll_hangup(chanp,!0); 
-}
-
-static void
-r24(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        chanp->data_open = 0;
-        FsmChangeState(fi, ST_D_ERR);
-        FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r25(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-
-        release_ds(chanp->chan);
-
-        FsmChangeState(fi, ST_NULL);
-
-        ll_hangup(chanp, !0);
-}
-
-static void
-r26(struct FsmInst *fi, int event, void *arg)
-{
-        struct Channel *chanp = fi->userdata;
-        isdn_ctrl       ic;
-
-
-        ic.driver = drid;
-        ic.command = ISDN_STAT_CINF;
-        ic.arg = chanp->chan;
-        sprintf(ic.num, "%d", chanp->para.chargeinfo);
-        iif.statcallb(&ic);
-}
-
-
-
-static struct FsmNode fnlist[] =
-{
-        {ST_NULL,             EV_DIAL,                r1},
-        {ST_OUT_W,            EV_DLEST,               r5},
-        {ST_OUT_W,            EV_DLRL,                r20},
-        {ST_OUT_W,            EV_RELEASE_CNF,         r2_2 },   
-        {ST_OUT,              EV_DISCONNECT_IND,      r2},
-        {ST_OUT,              EV_SETUP_CNF,           r10},
-        {ST_OUT,              EV_HANGUP,              r2_1},
-        {ST_OUT,              EV_RELEASE_IND,         r20},
-        {ST_OUT,              EV_RELEASE_CNF,         r20},
-        {ST_OUT,              EV_DLRL,                r2_2},
-        {ST_OUT_W_HANGUP,     EV_RELEASE_IND,         r2_2},
-        {ST_OUT_W_HANGUP,     EV_DLRL,                r20},
-        {ST_CLEAR,            EV_RELEASE_CNF,         r3},
-        {ST_CLEAR,            EV_DLRL,                r20},
-        {ST_REL_W,            EV_DLRL,                r4},
-        {ST_NULL,             EV_SETUP_IND,           r6},
-        {ST_IN_W,             EV_DLEST,               r7},
-        {ST_IN_W,             EV_DLRL,                r3_1},
-        {ST_IN,               EV_DLRL,                r3_1},
-        {ST_IN,               EV_HANGUP,              r2_1},
-        {ST_IN,               EV_RELEASE_IND,         r2_2},
-        {ST_IN,               EV_RELEASE_CNF,         r2_2},
-        {ST_IN,               EV_ACCEPTD,             r8},
-        {ST_IN_SETUP,         EV_HANGUP,              r2_1},
-        {ST_IN_SETUP,         EV_SETUP_CMPL_IND,      r9},
-        {ST_IN_SETUP,         EV_RELEASE_IND,         r2_2},
-        {ST_IN_SETUP,         EV_DISCONNECT_IND,      r2},
-        {ST_IN_SETUP,         EV_DLRL,                r20},
-        {ST_OUT_ESTB,         EV_BC_EST,              r12},
-        {ST_OUT_ESTB,         EV_BC_REL,              r23},
-        {ST_OUT_ESTB,         EV_DLRL,                r23_1},
-        {ST_IN_DACT,          EV_BC_EST,              r12},
-        {ST_IN_DACT,          EV_BC_REL,              r17},
-        {ST_IN_DACT,          EV_DLRL,                r17_1},
-        {ST_ACTIVE,           EV_HANGUP,              r15},
-        {ST_ACTIVE,           EV_BC_REL,              r17},
-        {ST_ACTIVE,           EV_DISCONNECT_IND,      r21},
-        {ST_ACTIVE,           EV_DLRL,                r24},
-        {ST_ACTIVE,           EV_CINF,                r26},
-        {ST_ACTIVE,           EV_RELEASE_IND,         r17},
-        {ST_BC_HANGUP,        EV_BC_REL,              r16},
-        {ST_BC_HANGUP,        EV_DISCONNECT_IND,      r21},
-        {ST_PRO_W,            EV_RELEASE_IND,         r18},
-        {ST_ANT_W,            EV_DISCONNECT_IND,      r19},
-        {ST_DISC_BC_HANGUP,   EV_BC_REL,              r22},
-        {ST_D_ERR,            EV_BC_REL,              r25},
-};
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
-        FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
-        lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmDelTimer(&lf->act_timer, 50);
-        FsmChangeState(fi, ST_LC_DELAY);
-        FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        if (lf->l2_establish) {
-                FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
-                if (lf->l2_start)
-                        lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
-        } else {
-                FsmChangeState(fi, ST_LC_CONNECTED);
-                lf->lccall(lf, LC_ESTABLISH, NULL);
-        }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_CONNECTED);
-        lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        if (lf->l2_establish) {
-                FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-                lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
-        } else {
-                FsmChangeState(fi, ST_LC_NULL);
-                lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-                lf->lccall(lf, LC_RELEASE, NULL);
-        }
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
-        struct LcFsm   *lf = fi->userdata;
-
-        FsmChangeState(fi, ST_LC_NULL);
-        lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-        lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static struct FsmNode LcFnList[] =
-{
-        {ST_LC_NULL,                  EV_LC_ESTABLISH,        lc_r1},
-        {ST_LC_ACTIVATE_WAIT,         EV_LC_PH_ACTIVATE,      lc_r6},
-        {ST_LC_DELAY,                 EV_LC_TIMER,            lc_r2},
-        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_ESTABLISH,     lc_r3},
-        {ST_LC_CONNECTED,             EV_LC_RELEASE,          lc_r4},
-        {ST_LC_CONNECTED,             EV_LC_DL_RELEASE,       lc_r5},
-        {ST_LC_RELEASE_WAIT,          EV_LC_DL_RELEASE,       lc_r5},
-        {ST_LC_ACTIVATE_WAIT,         EV_LC_TIMER,            lc_r5},
-        {ST_LC_ESTABLISH_WAIT,        EV_LC_DL_RELEASE,       lc_r5},
-};
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
-void
-CallcNew(void)
-{
-        callcfsm.state_count = STATE_COUNT;
-        callcfsm.event_count = EVENT_COUNT;
-        callcfsm.strEvent = strEvent;
-        callcfsm.strState = strState;
-        FsmNew(&callcfsm, fnlist, FNCOUNT);
-
-        lcfsm.state_count = LC_STATE_COUNT;
-        lcfsm.event_count = LC_EVENT_COUNT;
-        lcfsm.strEvent = strLcEvent;
-        lcfsm.strState = strLcState;
-        FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
-}
-
-void
-CallcFree(void)
-{
-        FsmFree(&lcfsm);
-        FsmFree(&callcfsm);
-}
-
-static void
-release_ds(int chan)
-{
-        struct PStack  *st = &chanlist[chan].ds;
-        struct IsdnCardState *sp;
-        struct HscxState *hsp;
-
-        sp = st->l1.hardware;
-        hsp = sp->hs + chanlist[chan].hscx;
-
-        close_hscxstate(hsp);
-
-        switch (chanlist[chan].l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  releasestack_isdnl2(st);
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-          case (ISDN_PROTO_L2_TRANS):
-                  releasestack_transl2(st);
-                  break;
-        }
-}
-
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (PH_ACTIVATE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                  break;
-          case (PH_DEACTIVATE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                  break;
-        }
-}
-
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (DL_ESTABLISH):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
-                  break;
-          case (DL_RELEASE):
-                  FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
-                  break;
-        }
-}
-
-static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (PH_ACTIVATE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                  break;
-          case (PH_DEACTIVATE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                  break;
-        }
-}
-
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (DL_ESTABLISH):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
-                  break;
-          case (DL_RELEASE):
-                  FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
-                  break;
-        }
-}
-
-static void
-ll_handler(struct PStack *st, int pr,
-           struct BufHeader *ibh)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-        switch (pr) {
-          case (CC_DISCONNECT_IND):
-                  FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
-                  break;
-          case (CC_RELEASE_CNF):
-                  FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
-                  break;
-          case (CC_SETUP_IND):
-                  FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
-                  break;
-          case (CC_RELEASE_IND):
-                  FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
-                  break;
-          case (CC_SETUP_COMPLETE_IND):
-                  FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
-                  break;
-          case (CC_SETUP_CNF):
-                  FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
-                  break;
-          case (CC_INFO_CHARGE):
-                  FsmEvent(&chanp->fi, EV_CINF, NULL);
-                  break;
-        }
-}
-
-static void
-init_is(int chan, unsigned int ces)
-{
-        struct PStack  *st = &(chanlist[chan].is);
-        struct IsdnCardState *sp = chanlist[chan].sp;
-        char            tmp[128];
-
-        setstack_teles(st, sp);
-
-        st->l2.sap = 0;
-
-        st->l2.tei = 255;
-
-        st->l2.ces = ces;
-        st->l2.extended = !0;
-        st->l2.laptype = LAPD;
-        st->l2.window = 1;
-        st->l2.orig = !0;
-        st->l2.t200 = 1000;               /* 1000 milliseconds  */
-        if (st->protocol == ISDN_PTYPE_1TR6) {
-                st->l2.n200 = 3;          /* try 3 times        */
-                st->l2.t203 = 10000;      /* 10000 milliseconds */
-        } else {
-                st->l2.n200 = 4;          /* try 4 times        */
-                st->l2.t203 = 5000;       /* 5000 milliseconds  */
-        }
-
-        sprintf(tmp, "Channel %d q.921", chan);
-        setstack_isdnl2(st, tmp);
-        setstack_isdnl3(st);
-        st->l2.debug = 2;
-        st->l3.debug = 2;
-        st->l2.debug = 0xff;
-        st->l3.debug = 0xff;
-        st->l4.userdata = chanlist + chan;
-        st->l4.l2writewakeup = NULL;
-
-        st->l3.l3l4 = ll_handler;
-        st->l1.l1man = cc_l1man;
-        st->l2.l2man = cc_l2man;
-
-        st->pa = &chanlist[chan].para;
-        teles_addlist(sp, st);
-}
-
-static void
-callc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[80], tm[32];
-        struct Channel *chanp = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[256], tm[32];
-        struct LcFsm   *lf = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
-        char            str[256], tm[32];
-        struct LcFsm   *lf = fi->userdata;
-
-        jiftime(tm, jiffies);
-        sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
-        teles_putstatus(str);
-}
-
-static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
-        struct Channel *chanp = lf->ch;
-
-        switch (pr) {
-          case (LC_ESTABLISH):
-                  FsmEvent(&chanp->fi, EV_DLEST, NULL);
-                  break;
-          case (LC_RELEASE):
-                  FsmEvent(&chanp->fi, EV_DLRL, NULL);
-                  break;
-        }
-}
-
-static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
-        struct Channel *chanp = lf->ch;
-
-        switch (pr) {
-          case (LC_ESTABLISH):
-                  FsmEvent(&chanp->fi, EV_BC_EST, NULL);
-                  break;
-          case (LC_RELEASE):
-                  FsmEvent(&chanp->fi, EV_BC_REL, NULL);
-                  break;
-        }
-}
-
-static void
-init_chan(int chan, int cardnr, int hscx,
-          unsigned int ces)
-{
-        struct IsdnCard *card = cards + cardnr;
-        struct Channel *chanp = chanlist + chan;
-
-        chanp->sp = card->sp;
-        chanp->hscx = hscx;
-        chanp->chan = chan;
-        chanp->incoming = 0;
-        chanp->debug = 0;
-        init_is(chan, ces);
-
-        chanp->fi.fsm = &callcfsm;
-        chanp->fi.state = ST_NULL;
-        chanp->fi.debug = 0;
-        chanp->fi.userdata = chanp;
-        chanp->fi.printdebug = callc_debug;
-
-        chanp->lc_d.lcfi.fsm = &lcfsm;
-        chanp->lc_d.lcfi.state = ST_LC_NULL;
-        chanp->lc_d.lcfi.debug = 0;
-        chanp->lc_d.lcfi.userdata = &chanp->lc_d;
-        chanp->lc_d.lcfi.printdebug = lc_debug;
-        chanp->lc_d.type = LC_D;
-        chanp->lc_d.ch = chanp;
-        chanp->lc_d.st = &chanp->is;
-        chanp->lc_d.l2_establish = !0;
-        chanp->lc_d.l2_start = !0;
-        chanp->lc_d.lccall = lccall_d;
-        FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
-        chanp->lc_b.lcfi.fsm = &lcfsm;
-        chanp->lc_b.lcfi.state = ST_LC_NULL;
-        chanp->lc_b.lcfi.debug = 0;
-        chanp->lc_b.lcfi.userdata = &chanp->lc_b;
-        chanp->lc_b.lcfi.printdebug = dlc_debug;
-        chanp->lc_b.type = LC_B;
-        chanp->lc_b.ch = chanp;
-        chanp->lc_b.st = &chanp->ds;
-        chanp->lc_b.l2_establish = !0;
-        chanp->lc_b.l2_start = !0;
-        chanp->lc_b.lccall = lccall_b;
-        FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
-
-        chanp->outcallref = 64;
-        chanp->data_open = 0;
-}
-
-int
-CallcNewChan(void)
-{
-        int             i, ces, c;
-
-        chancount = 0;
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp)
-                        chancount += 2;
-
-        chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
-                                      chancount, GFP_KERNEL, "chanlist");
-
-        c = 0;
-        ces = randomces();
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp) {
-                        init_chan(c++, i, 1, ces++);
-                        ces %= 0xffff;
-                        init_chan(c++, i, 0, ces++);
-                        ces %= 0xffff;
-                }
-        printk(KERN_INFO "channels %d\n", chancount);
-        return (chancount);
-
-}
-
-static void
-release_is(int chan)
-{
-        struct PStack  *st = &chanlist[chan].is;
-
-        releasestack_isdnl2(st);
-        teles_rmlist(st->l1.hardware, st);
-        BufQueueRelease(&st->l2.i_queue);
-}
-
-void
-CallcFreeChan(void)
-{
-        int             i;
-
-        for (i = 0; i < chancount; i++)
-                release_is(i);
-        Sfree((void *) chanlist);
-}
-
-static void
-lldata_handler(struct PStack *st, int pr,
-               void *arg)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-        byte           *ptr;
-        int             size;
-        struct BufHeader *ibh = arg;
-
-        switch (pr) {
-          case (DL_DATA):
-                  if (chanp->data_open) {
-                          ptr = DATAPTR(ibh);
-                          ptr += chanp->ds.l2.ihsize;
-                          size = ibh->datasize - chanp->ds.l2.ihsize;
-                          iif.rcvcallb(drid, chanp->chan, ptr, size);
-                  }
-                  BufPoolRelease(ibh);
-                  break;
-          default:
-                  printk(KERN_WARNING "lldata_handler unknown primitive\n");
-                  break;
-        }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr,
-                struct BufHeader *ibh)
-{
-        struct Channel *chanp = (struct Channel *) st->l4.userdata;
-        byte           *ptr;
-
-        switch (pr) {
-          case (PH_DATA):
-                  if (chanp->data_open) {
-                          ptr = DATAPTR(ibh);
-                          iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
-                  }
-                  BufPoolRelease(ibh);
-                  break;
-          default:
-                  printk(KERN_WARNING "lltrans_handler unknown primitive\n");
-                  break;
-        }
-}
-
-static void
-ll_writewakeup(struct PStack *st)
-{
-        struct Channel *chanp = st->l4.userdata;
-        isdn_ctrl       ic;
-
-        ic.driver = drid;
-        ic.command = ISDN_STAT_BSENT;
-        ic.arg = chanp->chan;
-        iif.statcallb(&ic);
-}
-
-static int
-init_ds(int chan, int incoming)
-{
-        struct PStack  *st = &(chanlist[chan].ds);
-        struct IsdnCardState *sp = (struct IsdnCardState *)
-        chanlist[chan].is.l1.hardware;
-        struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
-        char            tmp[128];
-
-        st->l1.hardware = sp;
-
-        hsp->mode = 2;
-        hsp->transbufsize = 4000;
-
-        if (setstack_hscx(st, hsp))
-                return (-1);
-
-        st->l2.extended = 0;
-        st->l2.laptype = LAPB;
-        st->l2.orig = !incoming;
-        st->l2.t200 = 1000;        /* 1000 milliseconds */
-        st->l2.window = 3;
-        st->l2.n200 = 4;           /* try 4 times       */
-        st->l2.t203 = 5000;        /* 5000 milliseconds */
-
-        st->l2.debug = 0xff;
-        st->l3.debug = 0xff;
-        switch (chanlist[chan].l2_active_protocol) {
-          case (ISDN_PROTO_L2_X75I):
-                  sprintf(tmp, "Channel %d x.75", chan);
-                  setstack_isdnl2(st, tmp);
-                  st->l2.l2l3 = lldata_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l2.l2man = dcc_l2man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = NULL;
-                  st->l4.l2writewakeup = ll_writewakeup;
-                  st->l2.l2m.debug = debugflags & 16;
-                  st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-                  st->l1.hscxmode = 2;        /* Packet-Mode ? */
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-          case (ISDN_PROTO_L2_HDLC):
-                  st->l1.l1l2 = lltrans_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = ll_writewakeup;
-                  st->l1.hscxmode = 2;
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-          case (ISDN_PROTO_L2_TRANS):
-                  st->l1.l1l2 = lltrans_handler;
-                  st->l1.l1man = dcc_l1man;
-                  st->l4.userdata = chanlist + chan;
-                  st->l4.l1writewakeup = ll_writewakeup;
-                  st->l1.hscxmode = 1;
-                  st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
-                  break;
-        }
-
-        return (0);
-
-}
-
-static void
-channel_report(int i)
-{
-}
-
-static void
-command_debug(struct Channel *chanp, char *s)
-{
-        char            tmp[64], tm[32];
-
-        jiftime(tm, jiffies);
-        sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
-        teles_putstatus(tmp);
-}
-
-static void
-distr_debug(void)
-{
-        int             i;
-
-        for (i = 0; i < chancount; i++) {
-                chanlist[i].debug = debugflags & 1;
-                chanlist[i].fi.debug = debugflags & 2;
-                chanlist[i].is.l2.l2m.debug = debugflags & 8;
-                chanlist[i].ds.l2.l2m.debug = debugflags & 16;
-        }
-        for (i = 0; i < nrcards; i++)
-                if (cards[i].sp) {
-                        cards[i].sp->dlogflag = debugflags & 4;
-                        cards[i].sp->debug = debugflags & 32;
-                }
-}
-
-int
-teles_command(isdn_ctrl * ic)
-{
-        struct Channel *chanp;
-        char            tmp[64];
-        int             i;
-        unsigned int    num;
-
-        switch (ic->command) {
-          case (ISDN_CMD_SETEAZ):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "SETEAZ");
-                  return (0);
-          case (ISDN_CMD_DIAL):
-                  chanp = chanlist + (ic->arg & 0xff);
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "DIAL %s", ic->num);
-                          command_debug(chanp, tmp);
-                  }
-                  FsmEvent(&chanp->fi, EV_DIAL, ic);
-                  return (0);
-          case (ISDN_CMD_ACCEPTB):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "ACCEPTB");
-                  FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
-                  break;
-          case (ISDN_CMD_ACCEPTD):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "ACCEPTD");
-                  FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
-                  break;
-          case (ISDN_CMD_HANGUP):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1)
-                          command_debug(chanp, "HANGUP");
-                  FsmEvent(&chanp->fi, EV_HANGUP, NULL);
-                  break;
-          case (ISDN_CMD_SUSPEND):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "SUSPEND %s", ic->num);
-                          command_debug(chanp, tmp);
-                  }
-                 FsmEvent(&chanp->fi, EV_SUSPEND, ic);
-                  break;
-          case (ISDN_CMD_RESUME):
-                  chanp = chanlist + ic->arg;
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "RESUME %s", ic->num);
-                          command_debug(chanp, tmp);
-                  }
-                  FsmEvent(&chanp->fi, EV_RESUME, ic);
-                  break;
-          case (ISDN_CMD_LOCK):
-                  teles_mod_inc_use_count();
-                  break;
-          case (ISDN_CMD_UNLOCK):
-                  teles_mod_dec_use_count();
-                  break;
-          case (ISDN_CMD_IOCTL):
-                  switch (ic->arg) {
-                    case (0):
-                            for (i = 0; i < nrcards; i++)
-                                    if (cards[i].sp)
-                                            teles_reportcard(i);
-                            for (i = 0; i < chancount; i++)
-                                    channel_report(i);
-                            break;
-                    case (1):
-                            debugflags = *(unsigned int *) ic->num;
-                            distr_debug();
-                            sprintf(tmp, "debugging flags set to %x\n", debugflags);
-                            teles_putstatus(tmp);
-			    printk(KERN_DEBUG "%s", tmp);
-                            break;
-                    case (2):
-                            num = *(unsigned int *) ic->num;
-                            i = num >> 8;
-                            if (i >= chancount)
-                                    break;
-                            chanp = chanlist + i;
-                            chanp->impair = num & 0xff;
-                            if (chanp->debug & 1) {
-                                    sprintf(tmp, "IMPAIR %x", chanp->impair);
-                                    command_debug(chanp, tmp);
-                            }
-                            break;
-                  }
-                  break;
-          case (ISDN_CMD_SETL2):
-                  chanp = chanlist + (ic->arg & 0xff);
-                  if (chanp->debug & 1) {
-                          sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
-                          command_debug(chanp, tmp);
-                  }
-                  chanp->l2_protocol = ic->arg >> 8;
-                  break;
-          default:
-                  break;
-        }
-
-        return (0);
-}
-
-int
-teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
-{
-        struct Channel *chanp = chanlist + chan;
-        struct PStack  *st = &chanp->ds;
-        struct BufHeader *ibh;
-        int             err, i;
-        byte           *ptr;
-
-	if (!chanp->data_open) {
-		printk(KERN_DEBUG "teles_writebuf: channel not open\n");
-		return -EIO;
-	}
-	
-        err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
-        if (err)
-                /* Must return 0 here, since this is not an error
-                 * but a temporary lack of resources.
-                 */
-                return 0;
-
-        ptr = DATAPTR(ibh);
-        if (chanp->lc_b.l2_establish)
-                i = st->l2.ihsize;
-        else
-                i = 0;
-
-        if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
-                printk(KERN_WARNING "teles_writebuf: packet too large!\n");
-                return (-EINVAL);
-        }
-
-        ptr += i;
-
-        if (user)
-                copy_from_user(ptr, buf, count);
-        else
-                memcpy(ptr, buf, count);
-        ibh->datasize = count + i;
-
-        if (chanp->data_open) {
-                if (chanp->lc_b.l2_establish)
-                        chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
-                else
-                        chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
-                return (count);
-        } else {
-                BufPoolRelease(ibh);
-                return (0);
-        }
-
-}
-
-static char    *
-strcpyupto(char *dest, char *src, char upto)
-{
-        while (*src && (*src != upto) && (*src != '\0'))
-                *dest++ = *src++;
-        *dest = '\0';
-        return (src);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/card.c linux-2.0.31-pre3/drivers/isdn/teles/card.c
--- linux-2.0.31-pre2/drivers/isdn/teles/card.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/card.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1900 +0,0 @@
-/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
- *
- * card.c     low level stuff for the Teles S0 isdn card
- * 
- * Author     Jan den Ouden
- * 
- * Beat Doebeli         log all D channel traffic
- * 
- * $Log: card.c,v $
- * Revision 1.16  1996/10/22 23:14:16  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.15  1996/09/29 19:41:56  fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.14  1996/09/23 01:53:49  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.13  1996/07/18 11:21:24  jdenoud
- * Use small buffers for incoming audio data
- *
- * Revision 1.12  1996/06/24 17:16:52  fritz
- * Added check for misconfigured membase.
- *
- * Revision 1.11  1996/06/14 03:30:37  fritz
- * Added recovery from EXIR 40 interrupt.
- * Some cleanup.
- *
- * Revision 1.10  1996/06/11 14:57:20  hipp
- * minor changes to ensure, that SKBs are sent in the right order
- *
- * Revision 1.9  1996/06/06 14:42:09  fritz
- * Bugfix: forgot hsp-> in last change.
- *
- * Revision 1.7  1996/05/31 01:02:21  fritz
- * Cosmetic changes.
- *
- * Revision 1.6  1996/05/26 14:58:10  fritz
- * Bugfix: Did not show port correctly, when no card found.
- *
- * Revision 1.5  1996/05/17 03:45:02  fritz
- * Made error messages more clearly.
- * Bugfix: Only 31 bytes of 32-byte audio frames
- *         have been transfered to upper layers.
- *
- * Revision 1.4  1996/05/06 10:17:57  fritz
- * Added voice-send stuff
- *  (Not reporting EXIR when in voice-mode, since it's normal).
- *
- * Revision 1.3  1996/04/30 22:02:40  isdn4dev
- * Bugfixes for 16.3
- *     -improved IO allocation
- *     -fix second B channel problem
- *     -correct ph_command patch
- *
- * Revision 1.2  1996/04/30 10:00:59  fritz
- * Bugfix: Added ph_command(8) for 16.3.
- * Bugfix: Ports did not get registered correctly
- *         when using a 16.3.
- *         Started voice support.
- *         Some experimental changes of waitforXFW().
- *
- * Revision 1.1  1996/04/13 10:22:42  fritz
- * Initial revision
- *
- *
- */
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-
-#undef DCHAN_VERBOSE
-
-extern void     tei_handler(struct PStack *st, byte pr,
-			    struct BufHeader *ibh);
-extern struct   IsdnCard cards[];
-extern int      nrcards;
-
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline   byte
-readisac_0(byte * cardm, byte offset)
-{
-	return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline   byte
-readisac_3(int iobase, byte offset)
-{
-        return (bytein(iobase - 0x420 + offset));
-}
-
-#define READISAC(mbase,ibase,ofs) \
-        ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
-
-static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
-{
-	writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline void
-writeisac_3(int iobase, byte offset, byte value)
-{
-	byteout(iobase - 0x420 + offset, value);
-}
-
-#define WRITEISAC(mbase,ibase,ofs,val) \
-        ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
-
-static inline void
-readisac_s(int iobase, byte offset, byte * dest, int count)
-{
-	insb(iobase - 0x420 + offset, dest, count);
-}
-
-static inline void
-writeisac_s(int iobase, byte offset, byte * src, int count)
-{
-	outsb(iobase - 0x420 + offset, src, count);
-}
-
-static inline   byte
-readhscx_0(byte * base, byte hscx, byte offset)
-{
-	return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
-			  ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline   byte
-readhscx_3(int iobase, byte hscx, byte offset)
-{
-	return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
-}
-
-#define READHSCX(mbase,ibase,hscx,ofs) \
-        ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
-
-static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
-{
-	writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
-		   ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline void
-writehscx_3(int iobase, byte hscx, byte offset, byte data)
-{
-	byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
-}
-
-static inline void
-readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
-{
-	insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
-}
-
-static inline void
-writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
-{
-	outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
-}
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-
-#define ISAC_RBCH 0x2a
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIX0 0x31
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void
-waitforCEC_0(byte * base, byte hscx)
-{
-	long            to = 10;
-
-	while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforCEC_3(int iobase, byte hscx)
-{
-	long            to = 10;
-
-	while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforXFW_0(byte * base, byte hscx)
-{
-	long            to = 20;
-
-	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-waitforXFW_3(int iobase, byte hscx)
-{
-	long            to = 20;
-
-	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-		udelay(5);
-		to--;
-	}
-	if (!to)
-		printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	waitforCEC_0(base, hscx);
-	writehscx_0(base, hscx, HSCX_CMDR, data);
-	restore_flags(flags);
-}
-
-static inline void
-writehscxCMDR_3(int iobase, byte hscx, byte data)
-{
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	waitforCEC_3(iobase, hscx);
-	writehscx_3(iobase, hscx, HSCX_CMDR, data);
-	restore_flags(flags);
-}
-
-#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
-        ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
-
-/*
- * fast interrupt here
- */
-
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE    2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
-
-void
-teles_hscxreport(struct IsdnCardState *sp, int hscx)
-{
-        printk(KERN_DEBUG "HSCX %d\n", hscx);
-        if (sp->membase) {
-                printk(KERN_DEBUG "  ISTA %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readhscx_0(sp->membase,
-                                                          hscx, HSCX_EXIR));
-        } else {
-                printk(KERN_DEBUG "  ISTA %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readhscx_3(sp->iobase,
-                                                          hscx, HSCX_EXIR));
-        }
-}
-
-void
-teles_report(struct IsdnCardState *sp)
-{
-	printk(KERN_DEBUG "ISAC\n");
-        if (sp->membase) {
-               printk(KERN_DEBUG "  ISTA %x\n", readisac_0(sp->membase,
-                                                            ISAC_ISTA));
-               printk(KERN_DEBUG "  STAR %x\n", readisac_0(sp->membase,
-                                                           ISAC_STAR));
-               printk(KERN_DEBUG "  EXIR %x\n", readisac_0(sp->membase,
-                                                           ISAC_EXIR));
-        } else {
-                printk(KERN_DEBUG "  ISTA %x\n", readisac_3(sp->iobase,
-                                                          ISAC_ISTA));
-                printk(KERN_DEBUG "  STAR %x\n", readisac_3(sp->iobase,
-                                                          ISAC_STAR));
-                printk(KERN_DEBUG "  EXIR %x\n", readisac_3(sp->iobase,
-                                                          ISAC_EXIR));
-        }
-	teles_hscxreport(sp, 0);
-	teles_hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
-	hsp->event |= 1 << event;
-	queue_task_irq_off(&hsp->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
-{
-	byte             *ptr;
-	struct BufHeader *ibh = hsp->rcvibh;
-
-	if (hsp->sp->debug)
-		printk(KERN_DEBUG "hscx_empty_fifo\n");
-
-	if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
-					      HSCX_RBUF_BPPS)) {
-		printk(KERN_WARNING
-                       "hscx_empty_fifo: incoming packet too large\n");
-		WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
-		return;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += hsp->rcvptr;
-
-	hsp->rcvptr += count;
-        if (hsp->membase) {
-                while (count--)
-                        *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
-                writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
-        } else {
-                readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
-                writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
-        }
-}
-
-static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
-	struct BufHeader *ibh;
-	int              more, count;
-	byte             *ptr;
-
-	if (hsp->sp->debug)
-		printk(KERN_DEBUG "hscx_fill_fifo\n");
-
-	ibh = hsp->xmtibh;
-	if (!ibh)
-                return;
-
-	count = ibh->datasize - hsp->sendptr;
-	if (count <= 0)
-                return;
-
-	more = (hsp->mode == 1)?1:0;
-	if (count > 32) {
-		more = !0;
-		count = 32;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += hsp->sendptr;
-	hsp->sendptr += count;
-
-#ifdef BCHAN_VERBOSE
-        {
-                int i;
-                printk(KERN_DEBUG "hscx_fill_fifo ");
-                for (i = 0; i < count; i++)
-                        printk(" %2x", ptr[i]);
-                printk("\n");
-        }
-#endif
-        if (hsp->membase) {
-                waitforXFW_0(hsp->membase, hsp->hscx);
-                while (count--)
-                        writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
-                writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
-        } else {
-                waitforXFW_3(hsp->iobase, hsp->hscx);
-                writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
-                writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
-        }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
-{
-	byte             r;
-	struct HscxState *hsp = sp->hs + hscx;
-	int              count, err;
-
-	if (!hsp->init)
-		return;
-
-	if (val & 0x80) {	/* RME */
-
-		r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
-		if ((r & 0xf0) != 0xa0) {
-			if (!r & 0x80)
-				printk(KERN_WARNING
-                                       "Teles: HSCX invalid frame\n");
-			if ((r & 0x40) && hsp->mode)
-				printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
-			if (!r & 0x20)
-				printk(KERN_WARNING "Teles: HSCX CRC error\n");
-			if (hsp->rcvibh)
-				BufPoolRelease(hsp->rcvibh);
-			hsp->rcvibh = NULL;
-			WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
-                                       0x80);
-			goto afterRME;
-		}
-		if (!hsp->rcvibh)
-			if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
-                                       GFP_ATOMIC, (void *) 1, 1)) {
-				printk(KERN_WARNING
-                                       "HSCX RME out of buffers at %ld\n",
-                                       jiffies);
-				WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x80);
-				goto afterRME;
-			} else
-				hsp->rcvptr = 0;
-
-		count = READHSCX(hsp->membase, sp->iobase, hsp->hscx,
-                                 HSCX_RBCL) & 0x1f;
-		if (count == 0)
-			count = 32;
-		hscx_empty_fifo(hsp, count);
-		hsp->rcvibh->datasize = hsp->rcvptr - 1;
-		BufQueueLink(&hsp->rq, hsp->rcvibh);
-		hsp->rcvibh = NULL;
-		hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-	}
-      afterRME:
-	if (val & 0x40) {	/* RPF */
-		if (!hsp->rcvibh) {
-			if (hsp->mode == 1)
-				err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
-					GFP_ATOMIC, (void *)1, 2);
-			else
-				err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
-					GFP_ATOMIC, (void *)1, 2);
-			
-			if (err) {
-				printk(KERN_WARNING
-                                       "HSCX RPF out of buffers at %ld\n",
-                                       jiffies);
-				WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x80);
-				goto afterRPF;
-			} else
-				hsp->rcvptr = 0;
-		}
-		
-		hscx_empty_fifo(hsp, 32);
-                if (hsp->mode == 1) {
-                        /* receive audio data */
-                        hsp->rcvibh->datasize = hsp->rcvptr;
-                        BufQueueLink(&hsp->rq, hsp->rcvibh);
-                        hsp->rcvibh = NULL;
-                        hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-                }
-                
-	}
-      afterRPF:
-	if (val & 0x10) {	/* XPR */
-		if (hsp->xmtibh)
-			if (hsp->xmtibh->datasize > hsp->sendptr) {
-				hscx_fill_fifo(hsp);
-				goto afterXPR;
-			} else {
-				if (hsp->releasebuf)
-					BufPoolRelease(hsp->xmtibh);
-				hsp->sendptr = 0;
-				if (hsp->st->l4.l1writewakeup)
-					hsp->st->l4.l1writewakeup(hsp->st);
-				hsp->xmtibh = NULL;
-			}
-		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
-			hsp->releasebuf = !0;
-			hscx_fill_fifo(hsp);
-		} else
-			hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-	}
-      afterXPR:
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
-	sp->event |= 1 << event;
-	queue_task_irq_off(&sp->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-empty_fifo(struct IsdnCardState *sp, int count)
-{
-	byte             *ptr;
-	struct BufHeader *ibh = sp->rcvibh;
-
-	if (sp->debug)
-		printk(KERN_DEBUG "empty_fifo\n");
-
-	if (sp->rcvptr >= 3072) {
-		printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
-		return;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += sp->rcvptr;
-	sp->rcvptr += count;
-
-        if (sp->membase) {
-#ifdef DCHAN_VERBOSE
-                printk(KERN_DEBUG "empty_fifo ");
-                while (count--) {
-                        *ptr = readisac_0(sp->membase, 0x0);
-                        printk("%2x ", *ptr);
-                        ptr++;
-                }
-                printk("\n");
-#else
-                while (count--)
-                        *ptr++ = readisac_0(sp->membase, 0x0);
-#endif
-                writeisac_0(sp->membase, ISAC_CMDR, 0x80);
-        } else {
-#ifdef DCHAN_VERBOSE
-                int i;
-                printk(KERN_DEBUG "empty_fifo ");
-                readisac_s(sp->iobase, 0x3e, ptr, count);
-                for (i = 0; i < count; i++)
-                        printk("%2x ", ptr[i]);
-                printk("\n");
-#else
-                readisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
-                writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
-        }
-}
-
-static void
-fill_fifo(struct IsdnCardState *sp)
-{
-	struct BufHeader *ibh;
-	int              count, more;
-	byte             *ptr;
-
-	if (sp->debug)
-		printk(KERN_DEBUG "fill_fifo\n");
-
-	ibh = sp->xmtibh;
-	if (!ibh)
-		return;
-
-	count = ibh->datasize - sp->sendptr;
-	if (count <= 0)
-		return;
-	if (count >= 3072)
-		return;
-
-	more = 0;
-	if (count > 32) {
-		more = !0;
-		count = 32;
-	}
-	ptr = DATAPTR(ibh);
-	ptr += sp->sendptr;
-	sp->sendptr += count;
-
-        if (sp->membase) {
-#ifdef DCHAN_VERBOSE
-                printk(KERN_DEBUG "fill_fifo ");
-                while (count--) {
-                        writeisac_0(sp->membase, 0x0, *ptr);
-                        printk("%2x ", *ptr);
-                        ptr++;
-                }
-                printk("\n");
-#else
-                while (count--)
-                        writeisac_0(sp->membase, 0x0, *ptr++);
-#endif
-                writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
-        } else {
-#ifdef DCHAN_VERBOSE
-                int i;
-                writeisac_s(sp->iobase, 0x3e, ptr, count);
-                printk(KERN_DEBUG "fill_fifo ");
-                for (i = 0; i < count; i++)
-                        printk("%2x ", ptr[i]);
-                printk("\n");
-#else
-                writeisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
-                writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
-        }
-}
-
-static int
-act_wanted(struct IsdnCardState *sp)
-{
-	struct PStack  *st;
-
-	st = sp->stlist;
-	while (st)
-		if (st->l1.act_state)
-			return (!0);
-		else
-			st = st->next;
-	return (0);
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
-	printk(KERN_DEBUG "ph_command %d\n", command);
-	WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_new_ph(struct IsdnCardState *sp)
-{
-	int             enq;
-
-	enq = act_wanted(sp);
-
-	switch (sp->ph_state) {
-	  case (0):
-	  case (6):
-		  if (enq)
-			  ph_command(sp, 0);
-		  else
-			  ph_command(sp, 15);
-		  break;
-	  case (7):
-		  if (enq)
-			  ph_command(sp, 9);
-		  break;
-	  case (12):
-	          ph_command(sp, 8);
-		  sp->ph_active = 5;
-		  isac_sched_event(sp, ISAC_PHCHANGE);
-		  if (!sp->xmtibh)
-			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
-				  sp->sendptr = 0;
-		  if (sp->xmtibh)
-			  fill_fifo(sp);
-		  break;
-	  case (13):
-	          ph_command(sp, 9);
-		  sp->ph_active = 5;
-		  isac_sched_event(sp, ISAC_PHCHANGE);
-		  if (!sp->xmtibh)
-			  if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
-				  sp->sendptr = 0;
-		  if (sp->xmtibh)
-			  fill_fifo(sp);
-		  break;
-	  case (4):
-	  case (8):
-		  break;
-	  default:
-		  sp->ph_active = 0;
-		  break;
-	}
-}
-
-static void
-teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
-	byte                 val, r, exval;
-	struct IsdnCardState *sp;
-	unsigned int         count;
-	struct HscxState     *hsp;
-
-	sp = (struct IsdnCardState *) irq2dev_map[intno];
-
-	if (!sp) {
-		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
-		return;
-	}
-	val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
-
-	if (val & 0x01) {
-		hsp = sp->hs + 1;
-                exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
-                if (exval == 0x40) {
-                        if (hsp->mode == 1)
-                                hscx_fill_fifo(hsp);
-                        else {
-                                /* Here we lost an TX interrupt, so
-                                 * restart transmitting the whole frame.
-                                 */
-                                hsp->sendptr = 0;
-			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x01);
-                                printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
-                        }
-                } else
-                        printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
-	}
-	if (val & 0xf8) {
-		if (sp->debug)
-			printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
-		hscx_interrupt(sp, val, 1);
-	}
-	if (val & 0x02) {
-		hsp = sp->hs;
-                exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
-                if (exval == 0x40) {
-                        if (hsp->mode == 1)
-                                hscx_fill_fifo(hsp);
-                        else {
-                                /* Here we lost an TX interrupt, so
-                                 * restart transmitting the whole frame.
-                                 */
-                                hsp->sendptr = 0;
-			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
-                                               hsp->hscx, 0x01);
-                                printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
-                        }
-                } else
-                        printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
-	}
-        if (val & 0x04) {
-                val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
-                if (sp->debug)
-                        printk(KERN_DEBUG "HSCX A interrupt %x\n",
-                               val);
-                hscx_interrupt(sp, val, 0);
-        }
-
-	val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
-
-	if (sp->debug)
-		printk(KERN_DEBUG "ISAC interrupt %x\n", val);
-
-	if (val & 0x80) {	/* RME */
-
-		r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
-		if ((r & 0x70) != 0x20) {
-			if (r & 0x40)
-				printk(KERN_WARNING "Teles: ISAC RDO\n");
-			if (!r & 0x20)
-				printk(KERN_WARNING "Teles: ISAC CRC error\n");
-			if (sp->rcvibh)
-				BufPoolRelease(sp->rcvibh);
-			sp->rcvibh = NULL;
-			WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
-			goto afterRME;
-		}
-		if (!sp->rcvibh)
-			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
-                                       GFP_ATOMIC,
-				       (void *) 1, 3)) {
-				printk(KERN_WARNING
-                                       "ISAC RME out of buffers!\n");
-				WRITEISAC(sp->membase, sp->iobase, 
-                                          ISAC_CMDR, 0x80);
-				goto afterRME;
-			} else
-				sp->rcvptr = 0;
-
-		count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
-		if (count == 0)
-			count = 32;
-		empty_fifo(sp, count);
-		sp->rcvibh->datasize = sp->rcvptr;
-		BufQueueLink(&(sp->rq), sp->rcvibh);
-		sp->rcvibh = NULL;
-		isac_sched_event(sp, ISAC_RCVBUFREADY);
-	}
-      afterRME:
-	if (val & 0x40) {	/* RPF */
-		if (!sp->rcvibh)
-			if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
-                                       GFP_ATOMIC,
-				       (void *) 1, 4)) {
-				printk(KERN_WARNING
-                                       "ISAC RME out of buffers!\n");
-				WRITEISAC(sp->membase, sp->iobase,
-                                          ISAC_CMDR, 0x80);
-				goto afterRPF;
-			} else
-				sp->rcvptr = 0;
-		empty_fifo(sp, 32);
-	}
-      afterRPF:
-	if (val & 0x20) {
-	}
-	if (val & 0x10) {	/* XPR */
-		if (sp->xmtibh)
-			if (sp->xmtibh->datasize > sp->sendptr) {
-				fill_fifo(sp);
-				goto afterXPR;
-			} else {
-				if (sp->releasebuf)
-					BufPoolRelease(sp->xmtibh);
-				sp->xmtibh = NULL;
-				sp->sendptr = 0;
-			}
-		if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
-			sp->releasebuf = !0;
-			fill_fifo(sp);
-		} else
-			isac_sched_event(sp, ISAC_XMTBUFREADY);
-	}
-      afterXPR:
-	if (val & 0x04) {	/* CISQ */
-		sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
-                                >> 2) & 0xf;
-		printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
-		isac_new_ph(sp);
-	}
-        if (sp->membase) {
-                writeisac_0(sp->membase, ISAC_MASK, 0xFF);
-                writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
-                writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
-                writeisac_0(sp->membase, ISAC_MASK, 0x0);
-                writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
-                writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
-        } else {
-                writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
-                writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
-                writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
-                writeisac_3(sp->iobase, ISAC_MASK, 0x0);
-                writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
-                writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
-        }
-}
-
-/*
- * soft interrupt
- */
-
-static void
-act_ivated(struct IsdnCardState *sp)
-{
-	struct PStack  *st;
-
-	st = sp->stlist;
-	while (st) {
-		if (st->l1.act_state == 1) {
-			st->l1.act_state = 2;
-			st->l1.l1man(st, PH_ACTIVATE, NULL);
-		}
-		st = st->next;
-	}
-}
-
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
-	if (sp->ph_active == 5)
-		act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
-{
-	struct PStack  *stptr;
-
-	if (sp->xmtibh)
-		return;
-
-	stptr = sp->stlist;
-	while (stptr != NULL)
-		if (stptr->l1.requestpull) {
-			stptr->l1.requestpull = 0;
-			stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
-			break;
-		} else
-			stptr = stptr->next;
-}
-
-static void
-process_rcv(struct IsdnCardState *sp)
-{
-	struct BufHeader *ibh, *cibh;
-	struct PStack    *stptr;
-	byte             *ptr;
-	int              found, broadc;
-	char             tmp[64];
-
-	while (!BufQueueUnlink(&ibh, &sp->rq)) {
-		stptr = sp->stlist;
-		ptr = DATAPTR(ibh);
-		broadc = (ptr[1] >> 1) == 127;
-
-		if (broadc && sp->dlogflag && (!(ptr[0] >> 2)))
-			dlogframe(sp, ptr + 3, ibh->datasize - 3,
-				  "Q.931 frame network->user broadcast");
-
-		if (broadc) {
-			while (stptr != NULL) {
-				if ((ptr[0] >> 2) == stptr->l2.sap)
-					if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
-							(void *) 1, 5)) {
-						memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
-						cibh->datasize = ibh->datasize;
-						stptr->l1.l1l2(stptr, PH_DATA, cibh);
-					} else
-						printk(KERN_WARNING "isdn broadcast buffer shortage\n");
-				stptr = stptr->next;
-			}
-			BufPoolRelease(ibh);
-		} else {
-			found = 0;
-			while (stptr != NULL)
-				if (((ptr[0] >> 2) == stptr->l2.sap) &&
-				    ((ptr[1] >> 1) == stptr->l2.tei)) {
-					stptr->l1.l1l2(stptr, PH_DATA, ibh);
-					found = !0;
-					break;
-				} else
-					stptr = stptr->next;
-			if (!found) {
-				/* BD 10.10.95
-				 * Print out D-Channel msg not processed
-				 * by isdn4linux
-                                 */
-
-				if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
-					sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1);
-					dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
-				}
-				BufPoolRelease(ibh);
-			}
-		}
-
-	}
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
-	if (!sp)
-		return;
-
-	if (clear_bit(ISAC_PHCHANGE, &sp->event))
-		process_new_ph(sp);
-	if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
-		process_rcv(sp);
-	if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
-		process_xmt(sp);
-}
-
-
-static void
-hscx_process_xmt(struct HscxState *hsp)
-{
-	struct PStack  *st = hsp->st;
-
-	if (hsp->xmtibh)
-		return;
-
-	if (st->l1.requestpull) {
-		st->l1.requestpull = 0;
-		st->l1.l1l2(st, PH_PULL_ACK, NULL);
-	}
-	if (!hsp->active)
-		if ((!hsp->xmtibh) && (!hsp->sq.head))
-			modehscx(hsp, 0, 0);
-}
-
-static void
-hscx_process_rcv(struct HscxState *hsp)
-{
-	struct BufHeader *ibh;
-
-#ifdef DEBUG_MAGIC
-	if (hsp->magic != 301270) {
-		printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
-		return;
-	}
-#endif
-	while (!BufQueueUnlink(&ibh, &hsp->rq)) {
-		hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
-	}
-}
-
-static void
-hscx_bh(struct HscxState *hsp)
-{
-
-	if (!hsp)
-		return;
-
-	if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
-		hscx_process_rcv(hsp);
-	if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
-		hscx_process_xmt(hsp);
-
-}
-
-/*
- * interrupt stuff ends here
- */
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
-	switch (sp->ph_active) {
-	  case (0):
-		  if (sp->ph_state == 6)
-			  ph_command(sp, 0);
-		  else
-			  ph_command(sp, 1);
-		  sp->ph_active = 1;
-		  break;
-	}
-}
-
-static void
-initisac(byte * cardmem, int iobase)
-{
-        if (cardmem) {
-                writeisac_0(cardmem, ISAC_MASK, 0xff);
-                writeisac_0(cardmem, ISAC_ADF2, 0x0);
-                writeisac_0(cardmem, ISAC_SPCR, 0xa);
-                writeisac_0(cardmem, ISAC_ADF1, 0x2);
-                writeisac_0(cardmem, ISAC_STCR, 0x70);
-                writeisac_0(cardmem, ISAC_MODE, 0xc9);
-                writeisac_0(cardmem, ISAC_CMDR, 0x41);
-                writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
-        } else {
-                writeisac_3(iobase, ISAC_MASK, 0xff);
-                writeisac_3(iobase, ISAC_ADF2, 0x80);
-                writeisac_3(iobase, ISAC_SQXR, 0x2f);
-                writeisac_3(iobase, ISAC_SPCR, 0x00);
-                writeisac_3(iobase, ISAC_ADF1, 0x02);
-                writeisac_3(iobase, ISAC_STCR, 0x70);
-                writeisac_3(iobase, ISAC_MODE, 0xc9);
-                writeisac_3(iobase, ISAC_TIMR, 0x00);
-                writeisac_3(iobase, ISAC_ADF1, 0x00);
-                writeisac_3(iobase, ISAC_CMDR, 0x41);
-                writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
-        }
-}
-
-static int
-checkcard(int cardnr)
-{
-	int             timout;
-	byte            cfval, val;
-	struct IsdnCard *card = cards + cardnr;
-
-        if (card->membase)
-                if ((unsigned long)card->membase < 0x10000) {
-                        (unsigned long)card->membase <<= 4;
-                        printk(KERN_INFO
-                               "Teles membase configured DOSish, assuming 0x%lx\n",
-                               (unsigned long)card->membase);
-                }
-        if (!card->iobase) {
-                if (card->membase) {
-                        printk(KERN_NOTICE
-                               "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
-                               (long) card->membase, card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                        printk(KERN_INFO "HSCX version A:%x B:%x\n",
-                               readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
-                               readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
-                }
-        } else {
-                switch (card->iobase) {
-                        case 0x180:
-                        case 0x280:
-                        case 0x380:
-                                card->iobase |= 0xc00;
-                                break;
-                }
-                if (card->membase) {  /* 16.0 */
-                	if (check_region(card->iobase, 8)) {
-                        	printk(KERN_WARNING
-                               		"teles: ports %x-%x already in use\n",
-                               		card->iobase,
-                               		card->iobase + 8 );
-                        	return -1;
-                	}
-                } else { /* 16.3 */
-                	if (check_region(card->iobase, 16)) {
-                        	printk(KERN_WARNING
-                               		"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase,
-                               		card->iobase + 16 );
-                        	return -1;
-                	}
-                	if (check_region((card->iobase - 0xc00) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0xc00,
-                               		card->iobase - 0xc00 + 32);
-                        	return -1;
-                        }
-                	if (check_region((card->iobase - 0x800) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0x800,
-                               		card->iobase - 0x800 + 32);
-                        	return -1;
-                        }
-                	if (check_region((card->iobase - 0x400) , 32)) {
-                        	printk(KERN_WARNING
-                  			"teles: 16.3 ports %x-%x already in use\n",
-                               		card->iobase - 0x400,
-                               		card->iobase - 0x400 + 32);
-                        	return -1;
-                        }
-                }
-                switch (card->interrupt) {
-                case 2:
-                        cfval = 0x00;
-                        break;
-                case 3:
-                        cfval = 0x02;
-                        break;
-                case 4:
-                        cfval = 0x04;
-                        break;
-                case 5:
-                        cfval = 0x06;
-                        break;
-                case 10:
-                        cfval = 0x08;
-                        break;
-                case 11:
-                        cfval = 0x0A;
-                        break;
-                case 12:
-                        cfval = 0x0C;
-                        break;
-                case 15:
-                        cfval = 0x0E;
-                        break;
-                default:
-                        cfval = 0x00;
-                        break;
-                }
-                if (card->membase) {
-                        cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
-                }   
-                if (bytein(card->iobase + 0) != 0x51) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 0,
-                                bytein(card->iobase + 0));
-                        return -2;
-                }
-                if (bytein(card->iobase + 1) != 0x93) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 1,
-                                bytein(card->iobase + 1));
-                        return -2;
-                }
-                val = bytein(card->iobase + 2);	/* 0x1e=without AB
-                                                 * 0x1f=with AB
-                                                 * 0x1c 16.3 ???
-                                                 */
-                if (val != 0x1c && val != 0x1e && val != 0x1f) {
-                        printk(KERN_INFO "XXX Byte at %x is %x\n",
-                                card->iobase + 2,
-                                bytein(card->iobase + 2));
-                        return -2;
-                }
-                if (card->membase) {  /* 16.0 */
-                        request_region(card->iobase, 8, "teles 16.0");
-                } else {
-                	request_region(card->iobase, 16, "teles 16.3");
-                	request_region(card->iobase - 0xC00, 32, "teles HSCX0");
-                	request_region(card->iobase - 0x800, 32, "teles HSCX1");
-                	request_region(card->iobase - 0x400, 32, "teles ISAC");
-                }
-                cli();
-                timout = jiffies + (HZ / 10) + 1;
-                byteout(card->iobase + 4, cfval);
-                sti();
-                while (jiffies <= timout);
-                
-                cli();
-                timout = jiffies + (HZ / 10) + 1;
-                byteout(card->iobase + 4, cfval | 1);
-                sti();
-                while (jiffies <= timout);
-                
-                if (card->membase)
-                        printk(KERN_NOTICE
-                               "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
-                               card->iobase, (long) card->membase,
-                               card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                else
-                        printk(KERN_NOTICE
-                               "Teles 16.3 found, io: %x irq: %d proto: %s\n",
-                               card->iobase, card->interrupt,
-                               (card->protocol == ISDN_PTYPE_1TR6) ?
-                               "1TR6" : "EDSS1");
-                printk(KERN_INFO "HSCX version A:%x B:%x\n",
-                       READHSCX(card->membase, card->iobase, 0,
-                                HSCX_VSTR) & 0xf,
-                       READHSCX(card->membase, card->iobase, 1,
-                                HSCX_VSTR) & 0xf);
-                
-        }
-        if (card->membase) {
-                cli();
-                timout = jiffies + (HZ / 5) + 1;
-                writeb(0, card->membase + 0x80);
-                sti();
-                while (jiffies <= timout);
-                
-                cli();
-                writeb(1, card->membase + 0x80);
-                timout = jiffies + (HZ / 5) + 1;
-                sti();
-                while (jiffies <= timout);
-        }
-	return (0);
-}
-
-void
-modehscx(struct HscxState *hs, int mode,
-	 int ichan)
-{
-	struct IsdnCardState *sp = hs->sp;
-	int             hscx = hs->hscx;
-
-	printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
-	       hscx, mode, ichan);
-
-        hs->mode = mode;
-        if (sp->membase) {
-                /* What's that ??? KKeil */
-		if (hscx == 0)
-			ichan = 1 - ichan;	/* raar maar waar... */
-                writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
-                writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
-                writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
-
-                switch (mode) {
-                case (0):
-                        writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                        writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
-                        writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
-                        writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                        writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
-                        break;
-                case (1):
-                        if (ichan == 0) {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
-                        writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                case (2):
-                        if (ichan == 0) {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
-                                writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
-                        writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                }
-                writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
-        } else {
-                writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
-                writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
-                writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
-                writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
-                
-                switch (mode) {
-                case (0):
-                        writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                        writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
-                        writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
-                        writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                        writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
-                        break;
-                case (1):
-                        if (ichan == 0) {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
-                        writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                case (2):
-                        if (ichan == 0) {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        } else {
-                                writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
-                                writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
-                                writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
-                        }
-                        writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
-                        writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
-                        break;
-                }
-                writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
-        }
-}
-
-void
-teles_addlist(struct IsdnCardState *sp,
-	      struct PStack *st)
-{
-	st->next = sp->stlist;
-	sp->stlist = st;
-}
-
-void
-teles_rmlist(struct IsdnCardState *sp,
-	     struct PStack *st)
-{
-	struct PStack  *p;
-
-	if (sp->stlist == st)
-		sp->stlist = st->next;
-	else {
-		p = sp->stlist;
-		while (p)
-			if (p->next == st) {
-				p->next = st->next;
-				return;
-			} else
-				p = p->next;
-	}
-}
-
-
-static void
-teles_l2l1(struct PStack *st, int pr,
-	   struct BufHeader *ibh)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-
-
-	switch (pr) {
-	  case (PH_DATA):
-		  if (sp->xmtibh)
-			  BufQueueLink(&sp->sq, ibh);
-		  else {
-			  sp->xmtibh = ibh;
-			  sp->sendptr = 0;
-			  sp->releasebuf = !0;
-			  fill_fifo(sp);
-		  }
-		  break;
-	  case (PH_DATA_PULLED):
-		  if (sp->xmtibh) {
-			  printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
-			  break;
-		  }
-		  sp->xmtibh = ibh;
-		  sp->sendptr = 0;
-		  sp->releasebuf = 0;
-		  fill_fifo(sp);
-		  break;
-	  case (PH_REQUEST_PULL):
-		  if (!sp->xmtibh) {
-			  st->l1.requestpull = 0;
-			  st->l1.l1l2(st, PH_PULL_ACK, NULL);
-		  } else
-			  st->l1.requestpull = !0;
-		  break;
-	}
-}
-
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
-	struct PStack  *st = sp->stlist;
-
-	while (st) {
-		if (st->l1.act_state)
-			return;
-		st = st->next;
-	}
-	sp->ph_active = 0;
-}
-
-static void
-teles_manl1(struct PStack *st, int pr,
-	    void *arg)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	long            flags;
-
-	switch (pr) {
-	  case (PH_ACTIVATE):
-		  save_flags(flags);
-		  cli();
-		  if (sp->ph_active == 5) {
-			  st->l1.act_state = 2;
-			  restore_flags(flags);
-			  st->l1.l1man(st, PH_ACTIVATE, NULL);
-		  } else {
-			  st->l1.act_state = 1;
-			  if (sp->ph_active == 0)
-				  restart_ph(sp);
-			  restore_flags(flags);
-		  }
-		  break;
-	  case (PH_DEACTIVATE):
-		  st->l1.act_state = 0;
-		  check_ph_act(sp);
-		  break;
-	}
-}
-
-static void
-teles_l2l1discardq(struct PStack *st, int pr,
-		   void *heldby, int releasetoo)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-
-#ifdef DEBUG_MAGIC
-	if (sp->magic != 301271) {
-		printk(KERN_DEBUG "isac_discardq magic not 301271\n");
-		return;
-	}
-#endif
-
-	BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
-}
-
-void
-setstack_teles(struct PStack *st, struct IsdnCardState *sp)
-{
-	st->l1.hardware = sp;
-	st->l1.sbufpool = &(sp->sbufpool);
-	st->l1.rbufpool = &(sp->rbufpool);
-	st->l1.smallpool = &(sp->smallpool);
-	st->protocol = sp->teistack->protocol;
-
-	setstack_tei(st);
-
-	st->l1.stlistp = &(sp->stlist);
-	st->l1.act_state = 0;
-	st->l2.l2l1 = teles_l2l1;
-	st->l2.l2l1discardq = teles_l2l1discardq;
-	st->ma.manl1 = teles_manl1;
-	st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
-	       int hscx)
-{
-	struct HscxState *hsp = sp->hs + hscx;
-
-	hsp->sp = sp;
-	hsp->hscx = hscx;
-	hsp->membase = sp->membase;
-	hsp->iobase = sp->iobase;
-
-	hsp->tqueue.next = 0;
-	hsp->tqueue.sync = 0;
-	hsp->tqueue.routine = (void *) (void *) hscx_bh;
-	hsp->tqueue.data = hsp;
-
-	hsp->inuse = 0;
-	hsp->init = 0;
-	hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
-	hsp->magic = 301270;
-#endif
-}
-
-void
-initcard(int cardnr)
-{
-	struct IsdnCardState *sp;
-	struct IsdnCard *card = cards + cardnr;
-
-	sp = (struct IsdnCardState *)
-	    Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
-		    "struct IsdnCardState");
-
-	sp->membase = card->membase;
-	sp->iobase = card->iobase;
-	sp->cardnr = cardnr;
-
-	BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
-		    ISAC_SBUF_MAXPAGES);
-	BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
-		    ISAC_RBUF_MAXPAGES);
-	BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
-		    ISAC_SMALLBUF_MAXPAGES);
-
-	sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
-
-	initisac(card->membase, card->iobase);
-
-	sp->rcvibh = NULL;
-	sp->rcvptr = 0;
-	sp->xmtibh = NULL;
-	sp->sendptr = 0;
-	sp->event = 0;
-	sp->tqueue.next = 0;
-	sp->tqueue.sync = 0;
-	sp->tqueue.routine = (void *) (void *) isac_bh;
-	sp->tqueue.data = sp;
-
-	BufQueueInit(&sp->rq);
-	BufQueueInit(&sp->sq);
-
-	sp->stlist = NULL;
-
-	sp->ph_active = 0;
-
-	sp->dlogflag = 0;
-	sp->debug = 0;
-
-	sp->releasebuf = 0;
-#ifdef DEBUG_MAGIC
-	sp->magic = 301271;
-#endif
-
-	cards[sp->cardnr].sp = sp;
-
-	init_hscxstate(sp, 0);
-	init_hscxstate(sp, 1);
-
-	modehscx(sp->hs, 0, 0);
-	modehscx(sp->hs + 1, 0, 0);
-
-	WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
-}
-
-static int
-get_irq(int cardnr)
-{
-	struct IsdnCard *card = cards + cardnr;
-	long            flags;
-
-	save_flags(flags);
-	cli();
-	if (request_irq(card->interrupt, &teles_interrupt,
-			SA_INTERRUPT, "teles", NULL)) {
-		printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
-                       card->interrupt);
-		restore_flags(flags);
-		return (!0);
-	}
-	irq2dev_map[card->interrupt] = (void *) card->sp;
-	restore_flags(flags);
-	return (0);
-}
-
-static void
-release_irq(int cardnr)
-{
-	struct	IsdnCard *card = cards + cardnr;
-
-	irq2dev_map[card->interrupt] = NULL;
-	free_irq(card->interrupt, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
-	modehscx(hs, 0, 0);
-	hs->inuse = 0;
-
-	if (hs->init) {
-		BufPoolFree(&hs->smallpool);
-		BufPoolFree(&hs->rbufpool);
-		BufPoolFree(&hs->sbufpool);
-	}
-	hs->init = 0;
-}
-
-void
-closecard(int cardnr)
-{
-	struct IsdnCardState *sp = cards[cardnr].sp;
-
-	cards[cardnr].sp = NULL;
-
-	Sfree(sp->dlogspace);
-
-	BufPoolFree(&sp->smallpool);
-	BufPoolFree(&sp->rbufpool);
-	BufPoolFree(&sp->sbufpool);
-
-	close_hscxstate(sp->hs + 1);
-	close_hscxstate(sp->hs);
-
-	if (cards[cardnr].iobase)
-        	if (cards[cardnr].membase) {  /* 16.0 */
-			release_region(cards[cardnr].iobase, 8);
-        	} else {
-			release_region(cards[cardnr].iobase, 16);
-                	release_region(cards[cardnr].iobase - 0xC00, 32);
-                	release_region(cards[cardnr].iobase - 0x800, 32);
-                	release_region(cards[cardnr].iobase - 0x400, 32);
-                }
-
-	Sfree((void *) sp);
-}
-
-void
-teles_shiftcards(int idx)
-{
-        int i;
-
-        for (i = idx; i < 15; i++)
-                memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
-}
-
-int
-teles_inithardware(void)
-{
-        int             foundcards = 0;
-	int             i = 0;
-
-	while (i < nrcards) {
-                if (!cards[i].protocol)
-                        break;
-		switch (checkcard(i)) {
-		  case (0):
-			  initcard(i);
-			  if (get_irq(i)) {
-				  closecard(i);
-                                  teles_shiftcards(i);
-                          } else {
-                                  foundcards++;
-                                  i++;
-                          }
-			  break;
-		  case (-1):
-                          teles_shiftcards(i);
-			  break;
-		  case (-2):
-			  release_region(cards[i].iobase, 8);
-			  printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
-                          teles_shiftcards(i);
-			  break;
-		}
-        }
-        return foundcards;
-}
-
-void
-teles_closehardware(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp) {
-			release_irq(i);
-			closecard(i);
-		}
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr,
-	  struct BufHeader *ibh)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-	long flags;
-
-	switch (pr) {
-                case (PH_DATA):
-			save_flags(flags);
-			cli();
-                        if (hsp->xmtibh) {
-                                BufQueueLink(&hsp->sq, ibh);
-				restore_flags(flags);
-			}
-                        else {
-				restore_flags(flags);
-                                hsp->xmtibh = ibh;
-                                hsp->sendptr = 0;
-                                hsp->releasebuf = !0;
-                                hscx_fill_fifo(hsp);
-                        }
-                        break;
-                case (PH_DATA_PULLED):
-                        if (hsp->xmtibh) {
-                                printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
-                                break;
-                        }
-                        hsp->xmtibh = ibh;
-                        hsp->sendptr = 0;
-                        hsp->releasebuf = 0;
-                        hscx_fill_fifo(hsp);
-                        break;
-                case (PH_REQUEST_PULL):
-                        if (!hsp->xmtibh) {
-                                st->l1.requestpull = 0;
-                                st->l1.l1l2(st, PH_PULL_ACK, NULL);
-                        } else
-                                st->l1.requestpull = !0;
-                        break;
-	}
-        
-}
-
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
-		  int releasetoo)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-#ifdef DEBUG_MAGIC
-	if (hsp->magic != 301270) {
-		printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
-		return;
-	}
-#endif
-
-	BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
-	       int hscx)
-{
-	struct HscxState *hsp = sp->hs + hscx;
-
-	if (!hsp->init) {
-		BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
-			    HSCX_SBUF_MAXPAGES);
-		BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
-			    HSCX_RBUF_MAXPAGES);
-		BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
-			    HSCX_SMALLBUF_MAXPAGES);
-	}
-	hsp->init = !0;
-
-	BufQueueInit(&hsp->rq);
-	BufQueueInit(&hsp->sq);
-
-	hsp->releasebuf = 0;
-	hsp->rcvibh = NULL;
-	hsp->xmtibh = NULL;
-	hsp->rcvptr = 0;
-	hsp->sendptr = 0;
-	hsp->event = 0;
-	return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
-	   void *arg)
-{
-	struct IsdnCardState *sp = (struct IsdnCardState *)
-	st->l1.hardware;
-	struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-	switch (pr) {
-	  case (PH_ACTIVATE):
-		  hsp->active = !0;
-		  modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
-		  st->l1.l1man(st, PH_ACTIVATE, NULL);
-		  break;
-	  case (PH_DEACTIVATE):
-		  if (!hsp->xmtibh)
-			  modehscx(hsp, 0, 0);
-
-		  hsp->active = 0;
-		  break;
-	}
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
-	if (open_hscxstate(st->l1.hardware, hs->hscx))
-		return (-1);
-
-	st->l1.hscx = hs->hscx;
-	st->l2.l2l1 = hscx_l2l1;
-	st->ma.manl1 = hscx_manl1;
-	st->l2.l2l1discardq = hscx_l2l1discardq;
-
-	st->l1.sbufpool = &hs->sbufpool;
-	st->l1.rbufpool = &hs->rbufpool;
-	st->l1.smallpool = &hs->smallpool;
-	st->l1.act_state = 0;
-	st->l1.requestpull = 0;
-
-	hs->st = st;
-	return (0);
-}
-
-void
-teles_reportcard(int cardnr)
-{
-	printk(KERN_DEBUG "teles_reportcard\n");
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/config.c linux-2.0.31-pre3/drivers/isdn/teles/config.c
--- linux-2.0.31-pre2/drivers/isdn/teles/config.c	1996-04-21 01:56:15.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/config.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,48 +0,0 @@
-/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $
- *
- * $Log: config.c,v $
- * Revision 1.1  1996/04/13 10:23:11  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include "teles.h"
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- * 
- * { membase,irq,portbase,protocol,NULL }
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
- *
- * Cards which don't have an io port (Teles 8 bit cards for
- * example) can be entered with io port 0x0
- *
- * For the Teles 16.3, membase has to be set to 0.
- *
- */
-
-struct IsdnCard cards[] =
-{
-	{(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL},	/* example */
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-	{NULL, 0, 0, 0, NULL},
-};
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/fsm.c linux-2.0.31-pre3/drivers/isdn/teles/fsm.c
--- linux-2.0.31-pre2/drivers/isdn/teles/fsm.c	1996-05-19 05:29:30.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/fsm.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,159 +0,0 @@
-/* $Id: fsm.c,v 1.2 1996/04/29 22:49:57 fritz Exp $
- *
- * $Log: fsm.c,v $
- * Revision 1.2  1996/04/29 22:49:57  fritz
- * Removed compatibility-macros.
- *
- * Revision 1.1  1996/04/13 10:23:41  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-void
-FsmNew(struct Fsm *fsm,
-       struct FsmNode *fnlist, int fncount)
-{
-	int             i;
-
-	fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
-					  GFP_KERNEL, "Fsm jumpmatrix");
-	memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
-	for (i = 0; i < fncount; i++)
-		fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
-			      fnlist[i].state] = (int) fnlist[i].routine;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
-	Sfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
-	void            (*r) (struct FsmInst *, int, void *);
-	char            str[80];
-
-	r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
-	if (r) {
-		if (fi->debug) {
-			sprintf(str, "State %s Event %s",
-				fi->fsm->strState[fi->state],
-				fi->fsm->strEvent[event]);
-			fi->printdebug(fi, str);
-		}
-		r(fi, event, arg);
-		return (0);
-	} else {
-		if (fi->debug) {
-			sprintf(str, "State %s Event %s no routine",
-				fi->fsm->strState[fi->state],
-				fi->fsm->strEvent[event]);
-			fi->printdebug(fi, str);
-		}
-		return (!0);
-	}
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
-	char            str[80];
-
-	fi->state = newstate;
-	if (fi->debug) {
-		sprintf(str, "ChangeState %s",
-			fi->fsm->strState[newstate]);
-		fi->printdebug(fi, str);
-	}
-}
-
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
-	FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
-	ft->fi = fi;
-	ft->tl.function = (void *) FsmExpireTimer;
-	ft->tl.data = (long) ft;
-	init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
-	long            flags;
-
-#if 0
-	if (ft->fi->debug) {
-		sprintf(str, "FsmDelTimer %lx %d", ft, where);
-		ft->fi->printdebug(ft->fi, str);
-	}
-#endif
-
-	save_flags(flags);
-	cli();
-	if (ft->tl.next)
-		del_timer(&ft->tl);
-	restore_flags(flags);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
-	    int millisec, int event, void *arg, int where)
-{
-
-#if 0
-	if (ft->fi->debug) {
-		sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
-		ft->fi->printdebug(ft->fi, str);
-	}
-#endif
-
-	if (ft->tl.next) {
-		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
-		return -1;
-	}
-	init_timer(&ft->tl);
-	ft->event = event;
-	ft->arg = arg;
-	ft->tl.expires = jiffies + (millisec * HZ) / 1000;
-	add_timer(&ft->tl);
-	return 0;
-}
-
-int
-FsmTimerRunning(struct FsmTimer *ft)
-{
-	return (ft->tl.next != NULL);
-}
-
-void
-jiftime(char *s, long mark)
-{
-	s += 8;
-
-	*s-- = '\0';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = '.';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 6 + '0';
-	mark /= 6;
-	*s-- = ':';
-	*s-- = mark % 10 + '0';
-	mark /= 10;
-	*s-- = mark % 10 + '0';
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/isdnl2.c linux-2.0.31-pre3/drivers/isdn/teles/isdnl2.c
--- linux-2.0.31-pre2/drivers/isdn/teles/isdnl2.c	1996-05-19 05:29:31.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/isdnl2.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1317 +0,0 @@
-/* $Id: isdnl2.c,v 1.2 1996/05/17 03:46:15 fritz Exp $
- *
- * $Log: isdnl2.c,v $
- * Revision 1.2  1996/05/17 03:46:15  fritz
- * General cleanup.
- *
- * Revision 1.1  1996/04/13 10:24:16  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-#define TIMER_1 2000
-
-static void     l2m_debug(struct FsmInst *fi, char *s);
-
-struct Fsm      l2fsm =
-{NULL, 0, 0};
-
-enum {
-	ST_L2_1,
-	ST_L2_3,
-	ST_L2_4,
-	ST_L2_5,
-	ST_L2_6,
-	ST_L2_7,
-	ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8+1)
-
-static char    *strL2State[] =
-{
-	"ST_L2_1",
-	"ST_L2_3",
-	"ST_L2_4",
-	"ST_L2_5",
-	"ST_L2_6",
-	"ST_L2_7",
-	"ST_L2_8",
-};
-
-enum {
-	EV_L2_UI,
-	EV_L2_SABMX,
-	EV_L2_UA,
-	EV_L2_DISC,
-	EV_L2_I,
-	EV_L2_RR,
-	EV_L2_REJ,
-	EV_L2_FRMR,
-	EV_L2_DL_DATA,
-	EV_L2_DL_ESTABLISH,
-	EV_L2_MDL_ASSIGN,
-	EV_L2_DL_UNIT_DATA,
-	EV_L2_DL_RELEASE,
-	EV_L2_MDL_NOTEIPROC,
-	EV_L2_T200,
-	EV_L2_ACK_PULL,
-	EV_L2_T203,
-	EV_L2_RNR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
-
-static char    *strL2Event[] =
-{
-	"EV_L2_UI",
-	"EV_L2_SABMX",
-	"EV_L2_UA",
-	"EV_L2_DISC",
-	"EV_L2_I",
-	"EV_L2_RR",
-	"EV_L2_REJ",
-	"EV_L2_FRMR",
-	"EV_L2_DL_DATA",
-	"EV_L2_DL_ESTABLISH",
-	"EV_L2_MDL_ASSIGN",
-	"EV_L2_DL_UNIT_DATA",
-	"EV_L2_DL_RELEASE",
-	"EV_L2_MDL_NOTEIPROC",
-	"EV_L2_T200",
-	"EV_L2_ACK_PULL",
-	"EV_L2_T203",
-	"EV_L2_RNR",
-};
-
-int             errcount = 0;
-
-static int      l2addrsize(struct Layer2 *tsp);
-
-static int
-cansend(struct PStack *st)
-{
-	int             p1;
-
-	p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
-	return (st->l2.vs != p1);
-}
-
-static void
-discard_i_queue(struct PStack *st)
-{
-	struct BufHeader *ibh;
-
-	while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
-		BufPoolRelease(ibh);
-}
-
-int
-l2headersize(struct Layer2 *tsp, int UI)
-{
-	return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
-}
-
-int
-l2addrsize(struct Layer2 *tsp)
-{
-	return (tsp->laptype == LAPD ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *tsp,
-	   struct BufHeader *ibh, int rsp)
-{
-	byte           *ptr = DATAPTR(ibh);
-	int             crbit;
-
-	if (tsp->laptype == LAPD) {
-		crbit = rsp;
-		if (!tsp->orig)
-			crbit = !crbit;
-		*ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
-		*ptr++ = (tsp->tei << 1) | 1;
-		return (2);
-	} else {
-		crbit = rsp;
-		if (tsp->orig)
-			crbit = !crbit;
-		if (crbit)
-			*ptr++ = 1;
-		else
-			*ptr++ = 3;
-		return (1);
-	}
-}
-
-static void
-enqueue_ui(struct PStack *st,
-	   struct BufHeader *ibh)
-{
-	st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static void
-enqueue_super(struct PStack *st,
-	      struct BufHeader *ibh)
-{
-	st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static int
-legalnr(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-	int             lnr, lvs;
-
-	lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
-	lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
-	return (lnr <= lvs);
-}
-
-static void
-setva(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-
-	if (l2->va != nr) {
-                while (l2->va != nr) {
-                        l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
-                        BufPoolRelease(l2->windowar[l2->sow]);
-                        l2->sow = (l2->sow + 1) % l2->window;
-                }
-                if (st->l4.l2writewakeup)
-                        st->l4.l2writewakeup(st);
-        }
-}
-
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
-	FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2s2(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-
-	byte           *ptr;
-	int             i;
-
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x3;
-
-	enqueue_ui(st, ibh);
-}
-
-static void
-l2s3(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-
-	st->l2.l2l3(st, DL_UNIT_DATA, ibh);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh;
-	int             i;
-	byte           *ptr;
-
-	FsmChangeState(fi, ST_L2_5);
-	st->l2.rc = 0;
-
-	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 1");
-
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-		return;
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	if (st->l2.extended)
-		*ptr = 0x7f;
-	else
-		*ptr = 0x3f;
-	ibh->datasize = i + 1;
-
-	enqueue_super(st, ibh);
-}
-
-static void
-l2s11(struct FsmInst *fi, int event, void *arg)
-{
-	establishlink(fi);
-}
-
-static void
-l2s13(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	byte           *ptr;
-	struct BufHeader *ibh;
-	int             i;
-
-	FsmChangeState(fi, ST_L2_6);
-
-	FsmDelTimer(&st->l2.t203_timer, 1);
-	if (st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t200_timer, 2);
-		st->l2.t200_running = 0;
-	}
-	st->l2.rc = 0;
-	if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 2");
-
-
-	if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
-		goto nodisc;
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
-		return;
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x53;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-      nodisc:
-	discard_i_queue(st);
-}
-
-static void
-l2s12(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	int             i;
-
-	BufPoolRelease(ibh);
-	st->l2.vs = 0;
-	st->l2.va = 0;
-	st->l2.vr = 0;
-	st->l2.sow = 0;
-	FsmChangeState(fi, ST_L2_7);
-	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 3");
-
-	st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
-		return;
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x73;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-}
-
-static void
-l2s14(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	struct Channel *chanp = st->l4.userdata;
-	byte           *ptr;
-	int             i, p;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&(st->l2));
-	p = (*ptr) & 0x10;
-	BufPoolRelease(ibh);
-
-	FsmChangeState(fi, ST_L2_4);
-
-	FsmDelTimer(&st->l2.t203_timer, 3);
-	if (st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t200_timer, 4);
-		st->l2.t200_running = 0;
-	}
-	if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
-		goto noresponse;
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
-		return;
-	i = sethdraddr(&(st->l2), ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x63 | (p ? 0x10 : 0x0);
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-      noresponse:
-	st->l2.l2man(st, DL_RELEASE, NULL);
-
-}
-
-static void
-l2s5(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             f;
-	byte           *data;
-
-	data = DATAPTR(ibh);
-	data += l2addrsize(&(st->l2));
-
-	f = *data & 0x10;
-	BufPoolRelease(ibh);
-
-	if (f) {
-		st->l2.vs = 0;
-		st->l2.va = 0;
-		st->l2.vr = 0;
-		st->l2.sow = 0;
-		FsmChangeState(fi, ST_L2_7);
-
-		FsmDelTimer(&st->l2.t200_timer, 5);
-		if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 4");
-
-
-		st->l2.l2man(st, DL_ESTABLISH, NULL);
-	}
-}
-
-static void
-l2s15(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             f;
-	byte           *data;
-
-	data = DATAPTR(ibh);
-	data += l2addrsize(&st->l2);
-
-	f = *data & 0x10;
-	BufPoolRelease(ibh);
-
-	if (f) {
-		FsmDelTimer(&st->l2.t200_timer, 6);
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	}
-}
-
-static void
-l2s6(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	struct BufHeader *ibh = arg;
-	int             p, i, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
-		goto noresp;
-
-	if ((!rsp) && p) {
-		if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
-			i = sethdraddr(l2, ibh, !0);
-			ptr = DATAPTR(ibh);
-			ptr += i;
-
-			if (l2->extended) {
-				*ptr++ = 0x1;
-				*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-				i += 2;
-			} else {
-				*ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
-				i += 1;
-			}
-			ibh->datasize = i;
-			enqueue_super(st, ibh);
-		}
-	}
-      noresp:
-	if (legalnr(st, seq))
-		if (seq == st->l2.vs) {
-			setva(st, seq);
-			FsmDelTimer(&st->l2.t200_timer, 7);
-			st->l2.t200_running = 0;
-			FsmDelTimer(&st->l2.t203_timer, 8);
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 5");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		} else if (st->l2.va != seq) {
-			setva(st, seq);
-			FsmDelTimer(&st->l2.t200_timer, 9);
-			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 6");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		}
-}
-
-static void
-l2s7(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             i;
-	byte           *ptr;
-	struct IsdnCardState *sp = st->l1.hardware;
-	char            str[64];
-
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-
-	if (st->l2.laptype == LAPD)
-		if (sp->dlogflag) {
-			sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-			dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-				  str);
-		}
-	BufQueueLink(&st->l2.i_queue, ibh);
-
-	st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-l2s8(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	struct BufHeader *ibh2;
-	struct IsdnCardState *sp = st->l1.hardware;
-	struct Layer2  *l2 = &(st->l2);
-	int             i, p, seq, nr, wasok;
-	char            str[64];
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(l2);
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[0] >> 1;
-		nr = (ptr[1] >> 1) & 0x7f;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 1) & 0x7;
-		nr = (ptr[0] >> 5) & 0x7;
-	}
-
-	if (l2->vr == seq) {
-		wasok = !0;
-
-		l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
-		l2->rejexp = 0;
-
-		ptr = DATAPTR(ibh);
-		if (st->l2.laptype == LAPD)
-			if (sp->dlogflag) {
-				sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
-				dlogframe(st->l1.hardware, ptr + l2->ihsize,
-					ibh->datasize - l2->ihsize, str);
-			}
-	      label8_1:
-		if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
-			goto noRR;
-
-		if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
-			i = sethdraddr(&(st->l2), ibh2, p);
-			ptr = DATAPTR(ibh2);
-			ptr += i;
-
-			if (l2->extended) {
-				*ptr++ = 0x1;
-				*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-				i += 2;
-			} else {
-				*ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
-				i += 1;
-			}
-			ibh2->datasize = i;
-			enqueue_super(st, ibh2);
-		      noRR:
-		}
-	} else {
-	        /* n(s)!=v(r) */
-		wasok = 0;
-		BufPoolRelease(ibh);
-		if (st->l2.rejexp) {
-			if (p)
-				goto label8_1;
-		} else {
-			st->l2.rejexp = !0;
-			if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
-				i = sethdraddr(&(st->l2), ibh2, p);
-				ptr = DATAPTR(ibh2);
-				ptr += i;
-
-				if (l2->extended) {
-					*ptr++ = 0x9;
-					*ptr++ = (l2->vr << 1) | (p ? 1 : 0);
-					i += 2;
-				} else {
-					*ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
-					i += 1;
-				}
-				ibh2->datasize = i;
-				enqueue_super(st, ibh2);
-			}
-		}
-	}
-
-	if (legalnr(st, nr))
-		if (nr == st->l2.vs) {
-			setva(st, nr);
-			FsmDelTimer(&st->l2.t200_timer, 10);
-			st->l2.t200_running = 0;
-			FsmDelTimer(&st->l2.t203_timer, 11);
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 5");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		} else if (nr != st->l2.va) {
-			setva(st, nr);
-			FsmDelTimer(&st->l2.t200_timer, 12);
-			if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 6");
-
-			if (st->l2.i_queue.head)
-				st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-		}
-	if (wasok)
-		st->l2.l2l3(st, DL_DATA, ibh);
-
-}
-
-static void
-l2s17(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.tei = (int) arg;
-	establishlink(fi);
-}
-
-static void
-enquiry_response(struct PStack *st)
-{
-	struct BufHeader *ibh2;
-	int             i;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
-		i = sethdraddr(&(st->l2), ibh2, !0);
-		ptr = DATAPTR(ibh2);
-		ptr += i;
-
-		if (l2->extended) {
-			*ptr++ = 0x1;
-			*ptr++ = (l2->vr << 1) | 0x1;
-			i += 2;
-		} else {
-			*ptr++ = (l2->vr << 5) | 0x1 | 0x10;
-			i += 1;
-		}
-		ibh2->datasize = i;
-		enqueue_super(st, ibh2);
-	}
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
-	struct Layer2  *l2 = &st->l2;
-	int             p1;
-
-	if (l2->vs != nr) {
-		while (l2->vs != nr) {
-
-			l2->vs = l2->vs - 1;
-			if (l2->vs < 0)
-				l2->vs += l2->extended ? 128 : 8;
-
-			p1 = l2->vs - l2->va;
-			if (p1 < 0)
-				p1 += l2->extended ? 128 : 8;
-			p1 = (p1 + l2->sow) % l2->window;
-
-			BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
-		}
-		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-	}
-}
-
-static void
-l2s16(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             p, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &(st->l2);
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if ((!rsp) && p)
-		enquiry_response(st);
-
-	if (!legalnr(st, seq))
-		return;
-
-	setva(st, seq);
-	invoke_retransmission(st, seq);
-
-}
-
-static void
-l2s19(struct FsmInst *fi, int event, void *arg)
-{
-	FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2s20(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	int             i;
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (st->l2.rc == st->l2.n200) {
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	} else {
-		st->l2.rc++;
-
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 7");
-
-		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-			return;
-
-		i = sethdraddr(&st->l2, ibh, 0);
-		ptr = DATAPTR(ibh);
-		ptr += i;
-		if (st->l2.extended)
-			*ptr = 0x7f;
-		else
-			*ptr = 0x3f;
-		ibh->datasize = i + 1;
-		enqueue_super(st, ibh);
-	}
-}
-
-static void
-l2s21(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct Channel *chanp = st->l4.userdata;
-	int             i;
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (st->l2.rc == st->l2.n200) {
-		FsmChangeState(fi, ST_L2_4);
-		st->l2.l2man(st, DL_RELEASE, NULL);
-	} else {
-		st->l2.rc++;
-
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 8");
-
-
-		if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
-			goto nodisc;
-
-		if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
-			return;
-
-		i = sethdraddr(&st->l2, ibh, 0);
-		ptr = DATAPTR(ibh);
-		ptr += i;
-		*ptr = 0x53;
-		ibh->datasize = i + 1;
-		enqueue_super(st, ibh);
-	      nodisc:
-
-	}
-}
-
-static void
-l2s22(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh;
-	struct Layer2  *l2 = &st->l2;
-	byte           *ptr;
-	int             p1;
-
-	if (!cansend(st))
-		return;
-
-	if (BufQueueUnlink(&ibh, &l2->i_queue))
-		return;
-
-
-	p1 = l2->vs - l2->va;
-	if (p1 < 0)
-		p1 += l2->extended ? 128 : 8;
-	p1 = (p1 + l2->sow) % l2->window;
-	l2->windowar[p1] = ibh;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		*ptr++ = l2->vs << 1;
-		*ptr++ = (l2->vr << 1) | 0x1;
-		l2->vs = (l2->vs + 1) % 128;
-	} else {
-		*ptr++ = (l2->vr << 5) | (l2->vs << 1) | 0x10;
-		l2->vs = (l2->vs + 1) % 8;
-	}
-
-	st->l2.l2l1(st, PH_DATA_PULLED, ibh);
-
-	if (!st->l2.t200_running) {
-		FsmDelTimer(&st->l2.t203_timer, 13);
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 9");
-
-		st->l2.t200_running = !0;
-	}
-	if (l2->i_queue.head && cansend(st))
-		st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
-	struct BufHeader *ibh;
-	byte           *ptr;
-
-	if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
-		ptr = DATAPTR(ibh);
-		ptr += sethdraddr(&st->l2, ibh, 0);
-
-		if (st->l2.extended) {
-			*ptr++ = 0x1;
-			*ptr++ = (st->l2.vr << 1) | 1;
-		} else {
-			*ptr++ = (st->l2.vr << 5) | 0x11;
-		}
-		ibh->datasize = ptr - DATAPTR(ibh);
-		enqueue_super(st, ibh);
-		if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
-			if (st->l2.l2m.debug)
-				l2m_debug(&st->l2.l2m, "FAT 10");
-
-		st->l2.t200_running = !0;
-	}
-}
-
-static void
-l2s23(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.t200_running = 0;
-
-	st->l2.rc = 1;
-	FsmChangeState(fi, ST_L2_8);
-	transmit_enquiry(st);
-}
-
-static void
-l2s24(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	int             p, seq, rsp;
-	byte           *ptr;
-	struct Layer2  *l2;
-
-	l2 = &st->l2;
-	ptr = DATAPTR(ibh);
-
-	if (l2->laptype == LAPD) {
-		rsp = ptr[0] & 0x2;
-		if (l2->orig)
-			rsp = !rsp;
-	} else {
-		rsp = ptr[0] == 0x3;
-		if (l2->orig)
-			rsp = !rsp;
-	}
-
-
-	ptr += l2addrsize(l2);
-
-	if (l2->extended) {
-		p = (ptr[1] & 0x1) == 0x1;
-		seq = ptr[1] >> 1;
-	} else {
-		p = (ptr[0] & 0x10);
-		seq = (ptr[0] >> 5) & 0x7;
-	}
-	BufPoolRelease(ibh);
-
-	if (rsp && p) {
-		if (legalnr(st, seq)) {
-			FsmChangeState(fi, ST_L2_7);
-			setva(st, seq);
-			if (st->l2.t200_running) {
-				FsmDelTimer(&st->l2.t200_timer, 14);
-				st->l2.t200_running = 0;
-			}
-			if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
-				if (st->l2.l2m.debug)
-					l2m_debug(&st->l2.l2m, "FAT 11");
-
-			invoke_retransmission(st, seq);
-		}
-	} else {
-		if (!rsp && p)
-			enquiry_response(st);
-		if (legalnr(st, seq)) {
-			setva(st, seq);
-		}
-	}
-}
-
-static void
-l2s25(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	st->l2.rc = 0;
-	FsmChangeState(fi, ST_L2_8);
-	transmit_enquiry(st);
-}
-
-static void
-l2s26(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-
-	if (st->l2.rc == st->l2.n200) {
-		l2s13(fi, event, NULL);
-	} else {
-		st->l2.rc++;
-		transmit_enquiry(st);
-	}
-}
-
-static void
-l2s27(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	int             i, p, est;
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&st->l2);
-
-	if (st->l2.extended)
-		p = ptr[1] & 0x1;
-	else
-		p = ptr[0] & 0x10;
-
-	BufPoolRelease(ibh);
-
-	if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
-		return;
-	i = sethdraddr(&st->l2, ibh, 0);
-	ptr = DATAPTR(ibh);
-	ptr += i;
-	*ptr = 0x63 | p;
-	ibh->datasize = i + 1;
-	enqueue_super(st, ibh);
-
-	if (st->l2.vs != st->l2.va) {
-		discard_i_queue(st);
-		est = !0;
-	} else
-		est = 0;
-
-	FsmDelTimer(&st->l2.t200_timer, 15);
-	st->l2.t200_running = 0;
-
-	if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
-		if (st->l2.l2m.debug)
-			l2m_debug(&st->l2.l2m, "FAT 12");
-
-	st->l2.vs = 0;
-	st->l2.va = 0;
-	st->l2.vr = 0;
-	st->l2.sow = 0;
-
-
-	if (est)
-		st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-}
-
-static void
-l2s28(struct FsmInst *fi, int event, void *arg)
-{
-	struct PStack  *st = fi->userdata;
-	struct BufHeader *ibh = arg;
-	byte           *ptr;
-	char            tmp[64];
-
-	ptr = DATAPTR(ibh);
-	ptr += l2addrsize(&st->l2);
-	ptr++;
-
-	if (st->l2.l2m.debug) {
-		if (st->l2.extended)
-			sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
-				ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
-		else
-			sprintf(tmp, "FRMR information %2x %2x %2x",
-				ptr[0], ptr[1], ptr[2]);
-
-		l2m_debug(&st->l2.l2m, tmp);
-	}
-	BufPoolRelease(ibh);
-}
-
-static int
-IsUI(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x3);
-}
-
-static int
-IsUA(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x63);
-}
-
-static int
-IsDISC(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x43);
-}
-
-static int
-IsRR(byte * data, int ext)
-{
-	if (ext)
-		return (data[0] == 0x1);
-	else
-		return ((data[0] & 0xf) == 1);
-}
-
-static int
-IsI(byte * data, int ext)
-{
-	return ((data[0] & 0x1) == 0x0);
-}
-
-static int
-IsSABMX(byte * data, int ext)
-{
-	return (ext ? data[0] == 0x7f : data[0] == 0x3f);
-}
-
-static int
-IsREJ(byte * data, int ext)
-{
-	return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9);
-}
-
-static int
-IsFRMR(byte * data, int ext)
-{
-	return ((data[0] & 0xef) == 0x87);
-}
-
-static int
-IsRNR(byte * data, int ext)
-{
-	if (ext)
-		return (data[0] == 0x5);
-	else
-		return ((data[0] & 0xf) == 5);
-}
-
-static struct FsmNode L2FnList[] =
-{
-	{ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
-	{ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
-	{ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
-	{ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
-	{ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
-	{ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
-	{ST_L2_7, EV_L2_DL_DATA, l2s7},
-	{ST_L2_7, EV_L2_DL_RELEASE, l2s13},
-	{ST_L2_7, EV_L2_ACK_PULL, l2s22},
-	{ST_L2_8, EV_L2_DL_RELEASE, l2s13},
-
-	{ST_L2_1, EV_L2_UI, l2s3},
-	{ST_L2_4, EV_L2_UI, l2s3},
-	{ST_L2_4, EV_L2_SABMX, l2s12},
-	{ST_L2_5, EV_L2_UA, l2s5},
-	{ST_L2_6, EV_L2_UA, l2s15},
-	{ST_L2_7, EV_L2_UI, l2s3},
-	{ST_L2_7, EV_L2_DISC, l2s14},
-	{ST_L2_7, EV_L2_I, l2s8},
-	{ST_L2_7, EV_L2_RR, l2s6},
-	{ST_L2_7, EV_L2_REJ, l2s16},
-	{ST_L2_7, EV_L2_SABMX, l2s27},
-	{ST_L2_7, EV_L2_FRMR, l2s28},
-	{ST_L2_8, EV_L2_RR, l2s24},
-	{ST_L2_8, EV_L2_DISC, l2s14},
-	{ST_L2_8, EV_L2_FRMR, l2s28},
-
-	{ST_L2_5, EV_L2_T200, l2s20},
-	{ST_L2_6, EV_L2_T200, l2s21},
-	{ST_L2_7, EV_L2_T200, l2s23},
-	{ST_L2_7, EV_L2_T203, l2s25},
-	{ST_L2_8, EV_L2_T200, l2s26},
-};
-
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
-{
-	struct BufHeader *ibh;
-	byte           *datap;
-	int             ret = !0;
-
-	switch (pr) {
-	  case (PH_DATA):
-
-		  ibh = arg;
-		  datap = DATAPTR(ibh);
-		  datap += l2addrsize(&st->l2);
-
-		  if (IsI(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
-		  else if (IsRR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
-		  else if (IsUI(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
-		  else if (IsSABMX(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
-		  else if (IsUA(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
-		  else if (IsDISC(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
-		  else if (IsREJ(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
-		  else if (IsFRMR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
-		  else if (IsRNR(datap, st->l2.extended))
-			  ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
-
-		  if (ret)
-			  BufPoolRelease(ibh);
-
-		  break;
-	  case (PH_PULL_ACK):
-		  FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
-		  break;
-	}
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr,
-	    void *arg)
-{
-	switch (pr) {
-	  case (DL_DATA):
-		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
-			  BufPoolRelease((struct BufHeader *) arg);
-		  break;
-	  case (DL_UNIT_DATA):
-		  if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
-			  BufPoolRelease((struct BufHeader *) arg);
-		  break;
-	}
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr,
-	     void *arg)
-{
-	switch (pr) {
-	  case (DL_ESTABLISH):
-		  FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
-		  break;
-	  case (DL_RELEASE):
-		  FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
-		  break;
-	  case (MDL_NOTEIPROC):
-		  FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
-		  break;
-	}
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr,
-	     void *arg)
-{
-	switch (pr) {
-	  case (MDL_ASSIGN):
-		  FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
-		  break;
-	}
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
-	FsmDelTimer(&st->l2.t200_timer, 15);
-	FsmDelTimer(&st->l2.t203_timer, 16);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *s)
-{
-	struct PStack  *st = fi->userdata;
-	char            tm[32], str[256];
-
-	jiftime(tm, jiffies);
-	sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
-	teles_putstatus(str);
-}
-
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
-	st->l1.l1l2 = isdnl2_l1l2;
-	st->l3.l3l2 = isdnl2_l3l2;
-	st->ma.manl2 = isdnl2_manl2;
-	st->ma.teil2 = isdnl2_teil2;
-
-	st->l2.uihsize = l2headersize(&st->l2, !0);
-	st->l2.ihsize = l2headersize(&st->l2, 0);
-	BufQueueInit(&(st->l2.i_queue));
-	st->l2.rejexp = 0;
-	st->l2.debug = 1;
-
-	st->l2.l2m.fsm = &l2fsm;
-	st->l2.l2m.state = ST_L2_1;
-	st->l2.l2m.debug = 0;
-	st->l2.l2m.userdata = st;
-	st->l2.l2m.printdebug = l2m_debug;
-	strcpy(st->l2.debug_id, debug_id);
-
-	FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
-	FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
-	st->l2.t200_running = 0;
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-void
-Isdnl2New(void)
-{
-	l2fsm.state_count = L2_STATE_COUNT;
-	l2fsm.event_count = L2_EVENT_COUNT;
-	l2fsm.strEvent = strL2Event;
-	l2fsm.strState = strL2State;
-	FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
-}
-
-void
-Isdnl2Free(void)
-{
-	FsmFree(&l2fsm);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/isdnl3.c linux-2.0.31-pre3/drivers/isdn/teles/isdnl3.c
--- linux-2.0.31-pre2/drivers/isdn/teles/isdnl3.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/isdnl3.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,663 +0,0 @@
-/* $Id: isdnl3.c,v 1.11 1996/09/29 19:41:58 fritz Exp $
- *
- * $Log: isdnl3.c,v $
- * Revision 1.11  1996/09/29 19:41:58  fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.10  1996/09/25 18:32:43  keil
- * response for STATUS_ENQ message added
- *
- * Revision 1.9  1996/06/06 14:22:27  fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.8  1996/06/03 20:35:04  fritz
- * Fixed typos.
- *
- * Revision 1.7  1996/06/03 20:03:39  fritz
- * Fixed typos.
- *
- * Revision 1.6  1996/05/21 11:33:50  keil
- * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message.
- *
- * Revision 1.5  1996/05/18 01:37:16  fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.4  1996/05/17 03:46:16  fritz
- * General cleanup.
- *
- * Revision 1.3  1996/04/30 21:57:53  isdn4dev
- * remove some debugging code, improve callback   Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:45:05  fritz
- * Changed to report all incoming calls to Linklevel, not just those
- * with Service 7.
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:24:45  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#define P_1TR6
-#include "teles.h"
-#include "l3_1TR6.h"
-#define DEBUG_1TR6 0
-
-static void
-i_down(struct PStack *st,
-       struct BufHeader *ibh)
-{
-	st->l3.l3l2(st, DL_DATA, ibh);
-}
-
-static void
-newl3state(struct PStack *st, int state)
-{
-	st->l3.state = state;
-	if (DEBUG_1TR6 > 4)
-		printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n",
-		       st->pa->bchannel, st->pa->callref, state);
-
-}
-
-static void
-l3_message(struct PStack *st, int mt)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	int             size;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = mt;
-	size += 4;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-}
-
-static void
-l3s3(struct PStack *st, byte pr, void *arg)
-{
-	l3_message(st, MT_RELEASE);
-	newl3state(st, 19);
-}
-
-static void
-l3s4(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s4_1(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 19);
-	l3_message(st, MT_RELEASE);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s5(struct PStack *st, byte pr,
-     void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	char           *teln;
-
-	st->l3.callref = st->pa->callref;
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_SETUP;
-	*p++ = 0xa1;
-
-	/*
-         * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
-         */
-	switch (st->pa->info) {
-	  case 1:		/* Telephony                               */
-		  *p++ = 0x4;	/* BC-IE-code                              */
-		  *p++ = 0x3;	/* Length                                  */
-		  *p++ = 0x90;	/* Coding Std. national, 3.1 kHz audio     */
-		  *p++ = 0x90;	/* Circuit-Mode 64kbps                     */
-		  *p++ = 0xa3;	/* A-Law Audio                             */
-		  break;
-	  case 5:		/* Datatransmission 64k, BTX               */
-	  case 7:		/* Datatransmission 64k                    */
-	  default:
-		  *p++ = 0x4;	/* BC-IE-code                              */
-		  *p++ = 0x2;	/* Length                                  */
-		  *p++ = 0x88;	/* Coding Std. nat., unrestr. dig. Inform. */
-		  *p++ = 0x90;	/* Packet-Mode 64kbps                      */
-		  break;
-	}
-	/*
-	 * What about info2? Mapping to High-Layer-Compatibility?
-	 */
-	if (st->pa->calling[0] != '\0') {
-		*p++ = 0x6c;
-		*p++ = strlen(st->pa->calling) + 1;
-		/* Classify as AnyPref. */
-		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-		teln = st->pa->calling;
-		while (*teln)
-			*p++ = *teln++ & 0x7f;
-	}
-	*p++ = 0x70;
-	*p++ = strlen(st->pa->called) + 1;
-	/* Classify as AnyPref. */
-	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
-	teln = st->pa->called;
-	while (*teln)
-		*p++ = *teln++ & 0x7f;
-
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	newl3state(st, 1);
-	i_down(st, dibh);
-
-}
-
-static void
-l3s6(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			0x18, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_WARNING "octect 3 not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 3);
-	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3s7(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 12);
-	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-static void
-l3s8(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3s11(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 4);
-	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3s12(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int		bcfound = 0;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	p += st->l2.uihsize;
-	st->pa->callref = getcallref(p);
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	/*
-         * Channel Identification
-         */
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x18, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-		bcfound++ ;
-	} else
-		printk(KERN_WARNING "l3s12: Channel ident not found\n");
-
-	p = DATAPTR(ibh);
-	if (st->protocol == ISDN_PTYPE_1TR6) {
-		if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) {
-			st->pa->info = p[2];
-			st->pa->info2 = p[3];
-		} else
-			printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n");
-	} else {
-		/*
-                 * Bearer Capabilities
-                 */
-		if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
-			switch (p[2] & 0x1f) {
-			  case 0x00:
-                                  /* Speech */
-			  case 0x10:
-                                  /* 3.1 Khz audio */
-				  st->pa->info = 1;
-				  break;
-			  case 0x08:
-                                  /* Unrestricted digital information */
-				  st->pa->info = 7;
-				  break;
-			  case 0x09:
-                                  /* Restricted digital information */
-				  st->pa->info = 2;
-				  break;
-			  case 0x11:
-                                  /* Unrestr. digital information  with tones/announcements */
-				  st->pa->info = 3;
-				  break;
-			  case 0x18:
-                                  /* Video */
-				  st->pa->info = 4;
-				  break;
-			  default:
-				  st->pa->info = 0;
-			}
-		} else
-			printk(KERN_WARNING "l3s12: Bearer capabilities not found\n");
-	}
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x70, 0)))
-		iecpy(st->pa->called, p, 1);
-	else
-		strcpy(st->pa->called, "");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			0x6c, 0))) {
-		if (st->protocol == ISDN_PTYPE_1TR6)
-			iecpy(st->pa->calling, p, 1);
-		else
-			iecpy(st->pa->calling, p, 2);
-	} else
-		strcpy(st->pa->calling, "");
-	BufPoolRelease(ibh);
-
-        if (bcfound) {
-                if (st->pa->info != 7) {
-                        printk(KERN_DEBUG "non-digital call: %s -> %s\n",
-                               st->pa->calling,
-                               st->pa->called);
-                }
-                newl3state(st, 6);
-                st->l3.l3l4(st, CC_SETUP_IND, NULL);
-        }
-}
-
-static void
-l3s13(struct PStack *st, byte pr, void *arg)
-{
-	newl3state(st, 0);
-}
-
-static void
-l3s16(struct PStack *st, byte pr,
-      void *arg)
-{
-	st->l3.callref = 0x80 + st->pa->callref;
-	l3_message(st, MT_CONNECT);
-	newl3state(st, 8);
-}
-
-static void
-l3s17(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3s18(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	int             size;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_DISCONNECT;
-	size += 4;
-
-	*p++ = IE_CAUSE;
-	*p++ = 0x2;
-	*p++ = 0x80;
-	*p++ = 0x90;
-	size += 4;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-
-	newl3state(st, 11);
-}
-
-static void
-l3s19(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	l3_message(st, MT_RELEASE_COMPLETE);
-	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-}
-
-static void
-l3s20(struct PStack *st, byte pr,
-      void *arg)
-{
-	l3_message(st, MT_ALERTING);
-	newl3state(st, 7);
-}
-
-static void
-l3s21(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh=arg;
-	byte           *p;
-	int             size;
-
-	BufPoolRelease(dibh);
-	
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-	size = st->l2.ihsize;
-
-	*p++ = 0x8;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_STATUS;
-	size += 4;
-
-	*p++ = IE_CAUSE;
-	*p++ = 0x2;
-	*p++ = 0x80;
-	*p++ = 0x9E; /* answer status enquire */
-	size += 4;
-
-	*p++ = 0x14; /* CallState */
-	*p++ = 0x1;
-	*p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
-	size += 3;
-
-	dibh->datasize = size;
-	i_down(st, dibh);
-
-}
-
-struct stateentry {
-	int             state;
-	byte            primitive;
-	void            (*rout) (struct PStack *, byte, void *);
-};
-
-static struct stateentry downstatelist[] =
-{
-        {0,CC_SETUP_REQ,l3s5},
-        {1,CC_DISCONNECT_REQ,l3s18},
-        {1,CC_RELEASE_REQ,l3s3},
-        {1,CC_DLRL,l3s13},
-        {3,CC_DISCONNECT_REQ,l3s18},
-        {3,CC_RELEASE_REQ,l3s3},
-        {3,CC_DLRL,l3s13},
-        {4,CC_RELEASE_REQ,l3s3},
-        {4,CC_DISCONNECT_REQ,l3s18},
-        {4,CC_DLRL,l3s13},
-        {6,CC_RELEASE_REQ,l3s3},
-        {6,CC_DISCONNECT_REQ,l3s18},
-        {6,CC_ALERTING_REQ,l3s20},
-        {6,CC_DLRL,l3s13},
-        {7,CC_RELEASE_REQ,l3s3},
-        {7,CC_SETUP_RSP,l3s16},
-        {7,CC_DLRL,l3s13},
-        {8,CC_RELEASE_REQ,l3s3},
-        {8,CC_DISCONNECT_REQ,l3s18},
-        {8,CC_DLRL,l3s13},
-        {10,CC_DISCONNECT_REQ,l3s18},
-        {10,CC_RELEASE_REQ,l3s3},
-        {10,CC_DLRL,l3s13},
-        {11,CC_RELEASE_REQ,l3s3},
-        {12,CC_RELEASE_REQ,l3s3},
-        {19,CC_DLRL,l3s13},
-};
-
-static int      downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist[] =
-{
-        {0,MT_STATUS_ENQUIRY,l3s21},
-        {0,MT_SETUP,l3s12},
-        {1,MT_STATUS_ENQUIRY,l3s21},
-        {1,MT_CALL_PROCEEDING,l3s6},
-        {1,MT_SETUP_ACKNOWLEDGE,l3s6},
-        {1,MT_RELEASE_COMPLETE,l3s4},
-        {1,MT_RELEASE,l3s19},
-        {1,MT_DISCONNECT,l3s7},
-        {3,MT_STATUS_ENQUIRY,l3s21},
-        {3,MT_DISCONNECT,l3s7},
-        {3,MT_CONNECT,l3s8},
-        {3,MT_ALERTING,l3s11},
-        {3,MT_RELEASE,l3s19},
-        {3,MT_RELEASE_COMPLETE,l3s4},
-        {4,MT_STATUS_ENQUIRY,l3s21},
-        {4,MT_CONNECT,l3s8},
-        {4,MT_DISCONNECT,l3s7},
-        {4,MT_RELEASE,l3s19},
-        {4,MT_RELEASE_COMPLETE,l3s4},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {6,MT_SETUP,l3s12},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {7,MT_RELEASE,l3s19},
-        {7,MT_RELEASE_COMPLETE,l3s4_1},
-        {7,MT_DISCONNECT,l3s7},
-        {8,MT_STATUS_ENQUIRY,l3s21},
-        {8,MT_RELEASE,l3s19},
-        {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
-        {8,MT_DISCONNECT,l3s7},
-        {8,MT_RELEASE_COMPLETE,l3s4_1},
-        {10,MT_STATUS_ENQUIRY,l3s21},
-        {10,MT_DISCONNECT,l3s7},
-        {10,MT_RELEASE,l3s19},
-        {10,MT_RELEASE_COMPLETE,l3s4_1},
-        {11,MT_STATUS_ENQUIRY,l3s21},
-        {11,MT_RELEASE,l3s19},
-        {11,MT_RELEASE_COMPLETE,l3s4},
-        {19,MT_STATUS_ENQUIRY,l3s21},
-        {19,MT_RELEASE_COMPLETE,l3s4},
-};
-
-static int      datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
-
-#ifdef P_1TR6
-#include "l3_1TR6.c"
-#endif
-
-static void
-l3up(struct PStack *st,
-     int pr, void *arg)
-{
-	int             i, mt, size;
-	byte           *ptr;
-	struct BufHeader *ibh = arg;
-
-	if (pr == DL_DATA) {
-		ptr = DATAPTR(ibh);
-		ptr += st->l2.ihsize;
-		size = ibh->datasize - st->l2.ihsize;
-		mt = ptr[3];
-		switch (ptr[0]) {
-#ifdef P_1TR6
-		  case PROTO_DIS_N0:
-			  BufPoolRelease(ibh);
-			  break;
-		  case PROTO_DIS_N1:
-			  for (i = 0; i < datasl_1tr6t_len; i++)
-				  if ((st->l3.state == datastatelist_1tr6t[i].state) &&
-				      (mt == datastatelist_1tr6t[i].primitive))
-					  break;
-			  if (i == datasl_1tr6t_len) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
-						 st->l3.state, mt);
-			  } else
-				  datastatelist_1tr6t[i].rout(st, pr, ibh);
-			  break;
-#endif
-		  case PROTO_EURO:	/* E-DSS1 */
-			  for (i = 0; i < datasllen; i++)
-				  if ((st->l3.state == datastatelist[i].state) &&
-				      (mt == datastatelist[i].primitive))
-					  break;
-			  if (i == datasllen) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
-				 		st->l3.state, mt);
-			  } else
-				  datastatelist[i].rout(st, pr, ibh);
-			  break;
-		  default:
-		          BufPoolRelease(ibh);
-			  break;
-		}
-	} else if (pr == DL_UNIT_DATA) {
-		ptr = DATAPTR(ibh);
-		ptr += st->l2.uihsize;
-		size = ibh->datasize - st->l2.uihsize;
-		mt = ptr[3];
-		switch (ptr[0]) {
-#ifdef P_1TR6
-		  case PROTO_DIS_N0:
-			  BufPoolRelease(ibh);
-			  break;
-		  case PROTO_DIS_N1:
-			  for (i = 0; i < datasl_1tr6t_len; i++)
-				  if ((st->l3.state == datastatelist_1tr6t[i].state) &&
-				      (mt == datastatelist_1tr6t[i].primitive))
-					  break;
-			  if (i == datasl_1tr6t_len) {
-				  if (DEBUG_1TR6 > 0) {
-					  printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
-						 ,st->l3.state, mt);
-				  }
-				  BufPoolRelease(ibh);
-			  } else
-				  datastatelist_1tr6t[i].rout(st, pr, ibh);
-			  break;
-#endif
-		  case PROTO_EURO:	/* E-DSS1 */
-			  for (i = 0; i < datasllen; i++)
-				  if ((st->l3.state == datastatelist[i].state) &&
-				      (mt == datastatelist[i].primitive))
-					  break;
-			  if (i == datasllen) {
-				  BufPoolRelease(ibh);
-				  if (DEBUG_1TR6 > 0)
-			  	  	printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
-				 		st->l3.state, mt);
-			  } else
-				  datastatelist[i].rout(st, pr, ibh);
-			  break;
-		  default:
-		          BufPoolRelease(ibh);
-			  break;
-		}
-	}
-}
-
-static void
-l3down(struct PStack *st,
-       int pr, void *arg)
-{
-	int             i;
-	struct BufHeader *ibh = arg;
-
-	switch (st->protocol) {
-#ifdef P_1TR6
-	  case ISDN_PTYPE_1TR6:
-		  for (i = 0; i < downsl_1tr6t_len; i++)
-			  if ((st->l3.state == downstatelist_1tr6t[i].state) &&
-			      (pr == downstatelist_1tr6t[i].primitive))
-				  break;
-		  if (i == downsl_1tr6t_len) {
-			  if (DEBUG_1TR6 > 0) {
-				  printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr);
-			  }
-		  } else
-			  downstatelist_1tr6t[i].rout(st, pr, ibh);
-		  break;
-#endif
-	  default:
-		  for (i = 0; i < downsllen; i++)
-			  if ((st->l3.state == downstatelist[i].state) &&
-			      (pr == downstatelist[i].primitive))
-				  break;
-		  if (i == downsllen) {
-			  if (DEBUG_1TR6 > 0) {
-				  printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr);
-			  }
-		  } else
-			  downstatelist[i].rout(st, pr, ibh);
-	}
-}
-
-void
-setstack_isdnl3(struct PStack *st)
-{
-	st->l4.l4l3 = l3down;
-	st->l2.l2l3 = l3up;
-	st->l3.state = 0;
-	st->l3.callref = 0;
-	st->l3.debug = 0;
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/l3_1TR6.c linux-2.0.31-pre3/drivers/isdn/teles/l3_1TR6.c
--- linux-2.0.31-pre2/drivers/isdn/teles/l3_1TR6.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/l3_1TR6.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,535 +0,0 @@
-/* $Id: l3_1TR6.c,v 1.6 1996/09/25 18:34:57 keil Exp $
- *
- * $Log: l3_1TR6.c,v $
- * Revision 1.6  1996/09/25 18:34:57  keil
- * missing states in 1TR6 Statemachine added
- *
- * Revision 1.5  1996/09/23 01:53:51  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.4  1996/06/06 14:22:28  fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.3  1996/04/30 21:54:42  isdn4dev
- * SPV, callback , remove some debugging code  Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:47:23  fritz
- * Changed statemachine to allow reject of an incoming call.
- * Report all incoming calls, not just those with Service = 7.
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:25:16  fritz
- * Initial revision
- *
- *
- */
-
-#include	"proto.h"
-
-static void
-l3_1TR6_message(struct PStack *st, int mt, int pd)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = pd;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = mt;
-
-	dibh->datasize = p - DATAPTR(dibh);
-	i_down(st, dibh);
-}
-
-static void
-l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte           *p;
-	char           *teln;
-
-	st->l3.callref = st->pa->callref;
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_SETUP;
-
-	if ('S' == (st->pa->called[0] & 0x5f)) {	/* SPV ??? */
-		/* NSF SPV */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_SPV;	/* SPV */
-		*p++ = st->pa->info; /* 0 for all Services */
-		*p++ = st->pa->info2; /* 0 for all Services */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_Activate;	/* aktiviere SPV (default) */
-		*p++ = st->pa->info; /* 0 for all Services */
-		*p++ = st->pa->info2; /* 0 for all Services */
-	}
-	if (st->pa->calling[0] != '\0') {
-		*p++ = WE0_origAddr;
-		*p++ = strlen(st->pa->calling) + 1;
-		/* Classify as AnyPref. */
-		*p++ = 0x81;	/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-		teln = st->pa->calling;
-		while (*teln)
-			*p++ = *teln++ & 0x7f;
-	}
-	*p++ = WE0_destAddr;
-	teln = st->pa->called;
-	if ('S' != (st->pa->called[0] & 0x5f)) {	/* Keine SPV ??? */
-		*p++ = strlen(st->pa->called) + 1;
-		st->pa->spv = 0;
-	} else {		/* SPV */
-		*p++ = strlen(st->pa->called);
-		teln++;		/* skip S */
-		st->pa->spv = 1;
-	}
-	/* Classify as AnyPref. */
-	*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-	while (*teln)
-		*p++ = *teln++ & 0x7f;
-
-	*p++ = WE_Shift_F6;
-	/* Codesatz 6 fuer Service */
-	*p++ = WE6_serviceInd;
-	*p++ = 2;		/* len=2 info,info2 */
-	*p++ = st->pa->info;
-	*p++ = st->pa->info2;
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	newl3state(st, 1);
-	i_down(st, dibh);
-
-}
-
-static void
-l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	p += st->l2.uihsize;
-	st->pa->callref = getcallref(p);
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	/* Channel Identification */
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "l3tu_setup: Channel ident not found\n");
-
-	p = DATAPTR(ibh);
-
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
-		st->pa->info = p[2];
-		st->pa->info2 = p[3];
-	} else
-		printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_destAddr, 0)))
-		iecpy(st->pa->called, p, 1);
-	else
-		strcpy(st->pa->called, "");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_origAddr, 0))) {
-		iecpy(st->pa->calling, p, 1);
-	} else
-		strcpy(st->pa->calling, "");
-
-	p = DATAPTR(ibh);
-	st->pa->spv = 0;
-	if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
-			WE0_netSpecFac, 0))) {
-		if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
-			st->pa->spv = 1;
-	}
-	BufPoolRelease(ibh);
-
-        /* Signal all services, linklevel takes care of Service-Indicator */
-	if (st->pa->info != 7) {
-                printk(KERN_DEBUG "non-digital call: %s -> %s\n",
-                       st->pa->calling,
-                       st->pa->called);
-	}
-        newl3state(st, 6);
-        st->l3.l3l4(st, CC_SETUP_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "octect 3 not found\n");
-
-
-	BufPoolRelease(ibh);
-	newl3state(st, 2);
-}
-
-static void
-l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_chanID, 0))) {
-		st->pa->bchannel = p[2] & 0x3;
-	} else
-		printk(KERN_INFO "octect 3 not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 3);
-	st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	struct BufHeader *ibh = arg;
-
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_statusCalled, 6))) {
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "status called %x\n", p[2]);
-	} else if (DEBUG_1TR6 > 0)
-		printk(KERN_INFO "statusCalled not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 4);
-	st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int             i,tmpcharge=0;
-	char            a_charge[8];
-	struct BufHeader *ibh = arg;
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_chargingInfo, 6))) {
-		iecpy(a_charge, p, 1);
-                for (i = 0; i < strlen (a_charge); i++) {
-     	                tmpcharge *= 10;
-     	                tmpcharge += a_charge[i] & 0xf;
-     	        }
-                if (tmpcharge > st->pa->chargeinfo) {
-     	                st->pa->chargeinfo = tmpcharge;
-     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
-     	        }
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
-	} else if (DEBUG_1TR6 > 2)
-		printk(KERN_INFO "chargingInfo not found\n");
-
-	BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
-{
-	byte           *p;
-	int             i;
-	struct BufHeader *ibh = arg;
-
-	if (DEBUG_1TR6 > 4) {
-		p = DATAPTR(ibh);
-		for (i = 0; i < ibh->datasize; i++) {
-			printk(KERN_INFO "Info DATA %x\n", p[i]);
-		}
-	}
-	BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-        st->pa->chargeinfo=0;
-	BufPoolRelease(ibh);
-	st->l3.l3l4(st, CC_SETUP_CNF, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
-	st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-	newl3state(st, 0);
-}
-
-static void
-l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	newl3state(st, 0);
-	st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-	byte           *p;
-	int             i,tmpcharge=0;
-	char            a_charge[8];
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE6_chargingInfo, 6))) {
-		iecpy(a_charge, p, 1);
-                for (i = 0; i < strlen (a_charge); i++) {
-     	                tmpcharge *= 10;
-     	                tmpcharge += a_charge[i] & 0xf;
-     	        }
-                if (tmpcharge > st->pa->chargeinfo) {
-     	                st->pa->chargeinfo = tmpcharge;
-     	                st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
-     	        }
-		if (DEBUG_1TR6 > 2)
-			printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
-	} else if (DEBUG_1TR6 > 2)
-		printk(KERN_INFO "chargingInfo not found\n");
-
-	p = DATAPTR(ibh);
-	if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
-			WE0_cause, 0))) {
-		if (p[1] > 0) {
-			st->pa->cause = p[2];
-		} else {
-			st->pa->cause = 0;
-		}
-		if (DEBUG_1TR6 > 1)
-			printk(KERN_INFO "Cause %x\n", st->pa->cause);
-	} else if (DEBUG_1TR6 > 0)
-		printk(KERN_INFO "Cause not found\n");
-
-	BufPoolRelease(ibh);
-	newl3state(st, 12);
-	st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-
-static void
-l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *ibh = arg;
-
-	BufPoolRelease(ibh);
-	st->pa->chargeinfo = 0;
-	st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
-	newl3state(st, 10);
-}
-
-static void
-l3_1tr6_alert(struct PStack *st, byte pr,
-	      void *arg)
-{
-	l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
-	newl3state(st, 7);
-}
-
-static void
-l3_1tr6_conn(struct PStack *st, byte pr,
-	     void *arg)
-{
-	struct BufHeader *dibh;
-	byte *p;
-
-	st->l3.callref = 0x80 + st->pa->callref;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_CONN;
-
-	if (st->pa->spv) {	/* SPV ??? */
-		/* NSF SPV */
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_SPV;	/* SPV */
-		*p++ = st->pa->info;
-		*p++ = st->pa->info2;
-		*p++ = WE0_netSpecFac;
-		*p++ = 4;	/* Laenge */
-		*p++ = 0;
-		*p++ = FAC_Activate;	/* aktiviere SPV */
-		*p++ = st->pa->info;
-		*p++ = st->pa->info2;
-	}
-	dibh->datasize = p - DATAPTR(dibh);
-
-	i_down(st, dibh);
-
-	newl3state(st, 8);
-}
-
-static void
-l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
-{
-	newl3state(st, 0);
-}
-
-static void
-l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
-{
-	struct BufHeader *dibh;
-	byte             *p;
-        byte             rejflg;
-
-	BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
-	p = DATAPTR(dibh);
-	p += st->l2.ihsize;
-
-	*p++ = PROTO_DIS_N1;
-	*p++ = 0x1;
-	*p++ = st->l3.callref;
-	*p++ = MT_N1_DISC;
-
-        if (st->l3.state == 7) {
-                rejflg = 1;
-                *p++ = WE0_cause;       /* Anruf abweisen                */
-                *p++ = 0x01;            /* Laenge = 1                    */
-                *p++ = CAUSE_CallRejected;
-        } else {
-                rejflg = 0;
-                *p++ = WE0_cause;
-                *p++ = 0x0;             /* Laenge = 0 normales Ausloesen */
-        }
-
-	dibh->datasize = p - DATAPTR(dibh);
-
-	i_down(st, dibh);
-
-        newl3state(st, 11);
-}
-
-static void
-l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
-{
-	l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
-	newl3state(st, 19);
-}
-
-static struct stateentry downstatelist_1tr6t[] =
-{
-	{0, CC_SETUP_REQ, l3_1tr6_setup},
-	{1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{1, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {1, CC_DLRL, l3_1tr6_reset},
-	{2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{2, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {2, CC_DLRL, l3_1tr6_reset},
-	{3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{3, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {3, CC_DLRL, l3_1tr6_reset},
-	{4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{4, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {4, CC_DLRL, l3_1tr6_reset},
-	{6, CC_REJECT_REQ, l3_1tr6_reset},
-	{6, CC_RELEASE_REQ, l3_1tr6_rel_req},
-	{6, CC_SETUP_RSP, l3_1tr6_conn},
-	{6, CC_ALERTING_REQ, l3_1tr6_alert},
-        {6, CC_DLRL, l3_1tr6_reset},
-	{7, CC_SETUP_RSP, l3_1tr6_conn},
-	{7, CC_RELEASE_REQ, l3_1tr6_rel_req},
-	{7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-        {7, CC_DLRL, l3_1tr6_reset},
-	{8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{8, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {8, CC_DLRL, l3_1tr6_reset},
-	{10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
-	{10, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {10, CC_DLRL, l3_1tr6_reset},
-	{12, CC_RELEASE_REQ, l3_1tr6_rel_req},
-        {12, CC_DLRL, l3_1tr6_reset},
-        {19, CC_DLRL, l3_1tr6_reset},
-};
-
-static int      downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist_1tr6t[] =
-{
-	{0, MT_N1_SETUP, l3_1tr6_tu_setup},
-	{0, MT_N1_REL, l3_1tr6_tu_rel},
-	{1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
-	{1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
-	{1, MT_N1_REL, l3_1tr6_tu_rel},
-	{1, MT_N1_DISC, l3_1tr6_tu_disc},
-	{2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
-	{2, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{2, MT_N1_CONN, l3_1tr6_tu_connect},
-	{2, MT_N1_REL, l3_1tr6_tu_rel},
-	{2, MT_N1_DISC, l3_1tr6_tu_disc},
-	{2, MT_N1_INFO, l3_1tr6_tu_info_s2},
-	{3, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{3, MT_N1_CONN, l3_1tr6_tu_connect},
-	{3, MT_N1_REL, l3_1tr6_tu_rel},
-	{3, MT_N1_DISC, l3_1tr6_tu_disc},
-	{4, MT_N1_ALERT, l3_1tr6_tu_alert},
-	{4, MT_N1_CONN, l3_1tr6_tu_connect},
-	{4, MT_N1_REL, l3_1tr6_tu_rel},
-	{4, MT_N1_DISC, l3_1tr6_tu_disc},
-	{7, MT_N1_REL, l3_1tr6_tu_rel},
-	{7, MT_N1_DISC, l3_1tr6_tu_disc},
-	{8, MT_N1_REL, l3_1tr6_tu_rel},
-	{8, MT_N1_DISC, l3_1tr6_tu_disc},
-	{8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
-	{10, MT_N1_REL, l3_1tr6_tu_rel},
-	{10, MT_N1_DISC, l3_1tr6_tu_disc},
-	{10, MT_N1_INFO, l3_1tr6_tu_info},
-	{11, MT_N1_REL, l3_1tr6_tu_rel},
-	{12, MT_N1_REL, l3_1tr6_tu_rel},
-	{19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
-};
-
-static int      datasl_1tr6t_len = sizeof(datastatelist_1tr6t) /
-sizeof(struct stateentry);
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/l3_1TR6.h linux-2.0.31-pre3/drivers/isdn/teles/l3_1TR6.h
--- linux-2.0.31-pre2/drivers/isdn/teles/l3_1TR6.h	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/l3_1TR6.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,160 +0,0 @@
-/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
- *
- * $Log: l3_1TR6.h,v $
- * Revision 1.4  1996/09/23 01:53:52  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.3  1996/04/30 21:53:48  isdn4dev
- * Bugs, SPV, Logging in q931.c  Karsten Keil
- *
- * Revision 1.1  1996/04/13 10:25:42  fritz
- * Initial revision
- *
- *
- */
-#ifndef l3_1TR6
-#define l3_1TR6
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE   0x75
-#define MT_N0_CLO_ACK 0x77
-
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-
-
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-
-#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/llglue.c linux-2.0.31-pre3/drivers/isdn/teles/llglue.c
--- linux-2.0.31-pre2/drivers/isdn/teles/llglue.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/llglue.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,151 +0,0 @@
-/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
- *
- * $Log: llglue.c,v $
- * Revision 1.7  1996/10/22 23:14:17  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.6  1996/06/03 20:03:39  fritz
- * Fixed typos.
- *
- * Revision 1.5  1996/05/31 00:58:47  fritz
- * Errata: Reverted change from rev 1.4.
- *
- * Revision 1.4  1996/05/26 14:59:57  fritz
- * Bugfix: maxbufsize had been set without respect to possible X.75 header.
- *
- * Revision 1.3  1996/05/01 14:19:57  fritz
- * Added ISDN_FEATURE_L2_TRANS
- *
- * Revision 1.2  1996/04/29 23:01:46  fritz
- * Added driverId and channel to readstatus().
- *
- * Revision 1.1  1996/04/13 10:26:29  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/malloc.h>
-#include <linux/timer.h>
-
-
-extern struct Channel *chanlist;
-int             drid;
-char            *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-isdn_if         iif;
-
-#define TELES_STATUS_BUFSIZE 4096
-static byte    *teles_status_buf = NULL;
-static byte    *teles_status_read = NULL;
-static byte    *teles_status_write = NULL;
-static byte    *teles_status_end = NULL;
-
-int
-teles_readstatus(byte * buf, int len, int user, int id, int channel)
-{
-	int             count;
-	byte           *p;
-
-	for (p = buf, count = 0; count < len; p++, count++) {
-		if (user)
-			put_user(*teles_status_read++, p);
-		else
-			*p++ = *teles_status_read++;
-		if (teles_status_read > teles_status_end)
-			teles_status_read = teles_status_buf;
-	}
-	return count;
-}
-
-void
-teles_putstatus(char *buf)
-{
-	long            flags;
-	int             len, count, i;
-	byte           *p;
-	isdn_ctrl       ic;
-
-	save_flags(flags);
-	cli();
-	count = 0;
-	len = strlen(buf);
-	for (p = buf, i = len; i > 0; i--, p++) {
-		*teles_status_write++ = *p;
-		if (teles_status_write > teles_status_end)
-			teles_status_write = teles_status_buf;
-		count++;
-	}
-	restore_flags(flags);
-	if (count) {
-		ic.command = ISDN_STAT_STAVAIL;
-		ic.driver = drid;
-		ic.arg = count;
-		iif.statcallb(&ic);
-	}
-}
-
-
-int
-ll_init(void)
-{
-	isdn_ctrl       ic;
-
-	teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE,
-				   GFP_KERNEL, "teles_status_buf");
-	if (!teles_status_buf) {
-		printk(KERN_ERR "teles: Could not allocate status-buffer\n");
-		return (-EIO);
-	} else {
-		teles_status_read = teles_status_buf;
-		teles_status_write = teles_status_buf;
-		teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1;
-	}
-
-	iif.channels = CallcNewChan();
-	iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
-	iif.features =
-	    ISDN_FEATURE_L2_X75I |
-	    ISDN_FEATURE_L2_HDLC |
-	    ISDN_FEATURE_L2_TRANS |
-	    ISDN_FEATURE_L3_TRANS |
-	    ISDN_FEATURE_P_1TR6 |
-	    ISDN_FEATURE_P_EURO;
-
-	iif.command = teles_command;
-	iif.writebuf = teles_writebuf;
-	iif.writecmd = NULL;
-	iif.readstat = teles_readstatus;
-	strncpy(iif.id, teles_id, sizeof(iif.id) - 1);
-
-	register_isdn(&iif);
-	drid = iif.channels;
-
-	ic.driver = drid;
-	ic.command = ISDN_STAT_RUN;
-	iif.statcallb(&ic);
-	return 0;
-}
-
-void
-ll_stop(void)
-{
-	isdn_ctrl       ic;
-
-	ic.command = ISDN_STAT_STOP;
-	ic.driver = drid;
-	iif.statcallb(&ic);
-
-	CallcFreeChan();
-}
-
-void
-ll_unload(void)
-{
-	isdn_ctrl       ic;
-
-	ic.command = ISDN_STAT_UNLOAD;
-	ic.driver = drid;
-	iif.statcallb(&ic);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/Makefile linux-2.0.31-pre3/drivers/isdn/teles/Makefile
--- linux-2.0.31-pre2/drivers/isdn/teles/Makefile	1996-02-26 01:58:05.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/Makefile	1969-12-31 16:00:00.000000000 -0800
@@ -1,17 +0,0 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
-llglue.o q931.o callc.o fsm.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
-  O_TARGET += teles.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_TELES),m)
-    O_TARGET += teles.o
-    M_OBJS += teles.o
-  endif
-endif
-
-include $(TOPDIR)/Rules.make
- 
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/mod.c linux-2.0.31-pre3/drivers/isdn/teles/mod.c
--- linux-2.0.31-pre2/drivers/isdn/teles/mod.c	1996-04-21 01:56:15.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/mod.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,143 +0,0 @@
-/* $Id: mod.c,v 1.1 1996/04/13 10:27:02 fritz Exp $
- *
- * $Log: mod.c,v $
- * Revision 1.1  1996/04/13 10:27:02  fritz
- * Initial revision
- *
- *
- */
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern char   *teles_id;
-
-int             nrcards;
-
-typedef struct {
-	byte           *membase;
-	int             interrupt;
-	unsigned int    iobase;
-	unsigned int    protocol;
-} io_type;
-
-io_type         io[] =
-{
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-	{0, 0, 0, 0},
-};
-
-void
-teles_mod_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-void
-teles_mod_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-#ifdef MODULE
-#define teles_init init_module
-#else
-void teles_setup(char *str, int *ints)
-{
-        int  i, j, argc;
-	static char sid[20];
-
-        argc = ints[0];
-        i = 0;
-        j = 1;
-        while (argc && (i<16)) {
-                if (argc) {
-                        io[i].iobase    = ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].interrupt = ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].membase   = (byte *)ints[j];
-                        j++; argc--;
-                }
-                if (argc) {
-                        io[i].protocol  = ints[j];
-                        j++; argc--;
-                }
-                i++;
-        }
-	if (strlen(str)) {
-		strcpy(sid,str);
-		teles_id = sid;
-	}
-}
-#endif
-
-int
-teles_init(void)
-{
-	int             i;
-
-	nrcards = 0;
-	for (i = 0; i < 16; i++) {
-		if (io[i].protocol) {
-			cards[i].membase   = io[i].membase;
-			cards[i].interrupt = io[i].interrupt;
-			cards[i].iobase    = io[i].iobase;
-			cards[i].protocol  = io[i].protocol;
-		}
-	}
-	for (i = 0; i < 16; i++)
-                if (cards[i].protocol)
-                        nrcards++;
-	printk(KERN_DEBUG "teles: Total %d card%s defined\n",
-               nrcards, (nrcards > 1) ? "s" : "");
-	if (teles_inithardware()) {
-                /* Install only, if at least one card found */
-                Isdnl2New();
-                TeiNew();
-                CallcNew();
-                ll_init();
-
-		/* No symbols to export, hide all symbols */
-		register_symtab(NULL);
-
-#ifdef MODULE
-                printk(KERN_NOTICE "Teles module installed\n");
-#endif
-                return (0);
-        } else
-                return -EIO;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-
-	ll_stop();
-	TeiFree();
-	Isdnl2Free();
-	CallcFree();
-	teles_closehardware();
-	ll_unload();
-	printk(KERN_NOTICE "Teles module removed\n");
-
-}
-#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/proto.h linux-2.0.31-pre3/drivers/isdn/teles/proto.h
--- linux-2.0.31-pre2/drivers/isdn/teles/proto.h	1996-11-29 01:10:13.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/proto.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,18 +0,0 @@
-/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
- *
- * not much now - just the l3 proto discriminator
- *
- * $Log: proto.h,v $
- * Revision 1.1  1996/09/23 01:53:52  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- */
-
-#ifndef	PROTO_H
-#define	PROTO_H
-
-#define	PROTO_EURO		0x08
-#define	PROTO_DIS_N0	0x40
-#define	PROTO_DIS_N1	0x41
-
-#endif
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/q931.c linux-2.0.31-pre3/drivers/isdn/teles/q931.c
--- linux-2.0.31-pre2/drivers/isdn/teles/q931.c	1996-11-12 22:36:20.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/q931.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1155 +0,0 @@
-/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
- *
- * q931.c               code to decode ITU Q.931 call control messages
- * 
- * Author               Jan den Ouden
- * 
- * Changelog
- * 
- * Pauline Middelink    general improvements
- * 
- * Beat Doebeli         cause texts, display information element
- * 
- * Karsten Keil         cause texts, display information element for 1TR6 
- *
- * 
- * $Log: q931.c,v $
- * Revision 1.6  1996/09/23 01:53:53  fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.5  1996/06/03 20:03:40  fritz
- * Fixed typos.
- *
- * Revision 1.4  1996/05/17 03:46:17  fritz
- * General cleanup.
- *
- * Revision 1.3  1996/04/30 22:06:50  isdn4dev
- *   logging 1TR6 messages correctly   Karsten Keil
- *
- * Revision 1.2  1996/04/20 16:48:19  fritz
- * Misc. typos
- *
- * Revision 1.1  1996/04/13 10:27:49  fritz
- * Initial revision
- *
- *
- */
-
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-#include "l3_1TR6.h"
-
-byte           *
-findie(byte * p, int size, byte ie, int wanted_set)
-{
-	int             l, codeset, maincodeset;
-	byte           *pend = p + size;
-
-	/* skip protocol discriminator, callref and message type */
-	p++;
-	l = (*p++) & 0xf;
-	p += l;
-	p++;
-	codeset = 0;
-	maincodeset = 0;
-	/* while there are bytes left... */
-	while (p < pend) {
-		if ((*p & 0xf0) == 0x90) {
-			codeset = *p & 0x07;
-			if (!(*p & 0x08))
-				maincodeset = codeset;
-		}
-		if (*p & 0x80)
-			p++;
-		else {
-			if (codeset == wanted_set) {
-				if (*p == ie)
-					return (p);
-				if (*p > ie)
-					return (NULL);
-			}
-			p++;
-			l = *p++;
-			p += l;
-			codeset = maincodeset;
-		}
-	}
-	return (NULL);
-}
-
-void
-iecpy(byte * dest, byte * iestart, int ieoffset)
-{
-	byte           *p;
-	int             l;
-
-	p = iestart + ieoffset + 2;
-	l = iestart[1] - ieoffset;
-	while (l--)
-		*dest++ = *p++;
-	*dest++ = '\0';
-}
-
-int
-getcallref(byte * p)
-{
-	p++;			/* prot discr */
-	p++;			/* callref length */
-	return (*p);		/* assuming one-byte callref */
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
-	byte            nr;
-	char           *descr;
-} mtlist[] = {
-
-	{
-		0x1, "ALERTING"
-	},
-	{
-		0x2, "CALL PROCEEDING"
-	},
-	{
-		0x7, "CONNECT"
-	},
-	{
-		0xf, "CONNECT ACKNOWLEDGE"
-	},
-	{
-		0x3, "PROGRESS"
-	},
-	{
-		0x5, "SETUP"
-	},
-	{
-		0xd, "SETUP ACKNOWLEDGE"
-	},
-	{
-		0x26, "RESUME"
-	},
-	{
-		0x2e, "RESUME ACKNOWLEDGE"
-	},
-	{
-		0x22, "RESUME REJECT"
-	},
-	{
-		0x25, "SUSPEND"
-	},
-	{
-		0x2d, "SUSPEND ACKNOWLEDGE"
-	},
-	{
-		0x21, "SUSPEND REJECT"
-	},
-	{
-		0x20, "USER INFORMATION"
-	},
-	{
-		0x45, "DISCONNECT"
-	},
-	{
-		0x4d, "RELEASE"
-	},
-	{
-		0x5a, "RELEASE COMPLETE"
-	},
-	{
-		0x46, "RESTART"
-	},
-	{
-		0x4e, "RESTART ACKNOWLEDGE"
-	},
-	{
-		0x60, "SEGMENT"
-	},
-	{
-		0x79, "CONGESTION CONTROL"
-	},
-	{
-		0x7b, "INFORMATION"
-	},
-	{
-		0x62, "FACILITY"
-	},
-	{
-		0x6e, "NOTIFY"
-	},
-	{
-		0x7d, "STATUS"
-	},
-	{
-		0x75, "STATUS ENQUIRY"
-	}
-};
-
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
-
-static
-struct MessageType mt_n0[] =
-{
-	{MT_N0_REG_IND, "REGister INDication"},
-	{MT_N0_CANC_IND, "CANCel INDication"},
-	{MT_N0_FAC_STA, "FACility STAtus"},
-	{MT_N0_STA_ACK, "STAtus ACKnowledge"},
-	{MT_N0_STA_REJ, "STAtus REJect"},
-	{MT_N0_FAC_INF, "FACility INFormation"},
-	{MT_N0_INF_ACK, "INFormation ACKnowledge"},
-	{MT_N0_INF_REJ, "INFormation REJect"},
-	{MT_N0_CLOSE, "CLOSE"},
-	{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
-
-static
-struct MessageType mt_n1[] =
-{
-	{MT_N1_ESC, "ESCape"},
-	{MT_N1_ALERT, "ALERT"},
-	{MT_N1_CALL_SENT, "CALL SENT"},
-	{MT_N1_CONN, "CONNect"},
-	{MT_N1_CONN_ACK, "CONNect ACKnowledge"},
-	{MT_N1_SETUP, "SETUP"},
-	{MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
-	{MT_N1_RES, "RESume"},
-	{MT_N1_RES_ACK, "RESume ACKnowledge"},
-	{MT_N1_RES_REJ, "RESume REJect"},
-	{MT_N1_SUSP, "SUSPend"},
-	{MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
-	{MT_N1_SUSP_REJ, "SUSPend REJect"},
-	{MT_N1_USER_INFO, "USER INFO"},
-	{MT_N1_DET, "DETach"},
-	{MT_N1_DISC, "DISConnect"},
-	{MT_N1_REL, "RELease"},
-	{MT_N1_REL_ACK, "RELease ACKnowledge"},
-	{MT_N1_CANC_ACK, "CANCel ACKnowledge"},
-	{MT_N1_CANC_REJ, "CANCel REJect"},
-	{MT_N1_CON_CON, "CONgestion CONtrol"},
-	{MT_N1_FAC, "FACility"},
-	{MT_N1_FAC_ACK, "FACility ACKnowledge"},
-	{MT_N1_FAC_CAN, "FACility CANcel"},
-	{MT_N1_FAC_REG, "FACility REGister"},
-	{MT_N1_FAC_REJ, "FACility REJect"},
-	{MT_N1_INFO, "INFOrmation"},
-	{MT_N1_REG_ACK, "REGister ACKnowledge"},
-	{MT_N1_REG_REJ, "REGister REJect"},
-	{MT_N1_STAT, "STATus"}
-};
-
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
-
-static struct MessageType fac_1tr6[] =
-{
-	{FAC_Sperre, "Sperre"},
-	{FAC_Forward1, "Forward 1"},
-	{FAC_Forward2, "Forward 2"},
-	{FAC_Konferenz, "Konferenz"},
-	{FAC_GrabBchan, "Grab Bchannel"},
-	{FAC_Reactivate, "Reactivate"},
-	{FAC_Konferenz3, "Dreier Konferenz"},
-	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
-	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
-	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
-	{FAC_GBG, "GBG"},
-	{FAC_DisplayUebergeben, "Display Uebergeben"},
-	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
-	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
-	{FAC_Deactivate, "Deactivate"},
-	{FAC_Activate, "Activate"},
-	{FAC_SPV, "SPV"},
-	{FAC_Rueckwechsel, "Rueckwechsel"},
-	{FAC_Umleitung, "Umleitung"}
-};
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
-
-static int 
-prbits(char *dest, byte b, int start, int len)
-{
-	char           *dp = dest;
-
-	b = b << (8 - start);
-	while (len--) {
-		if (b & 0x80)
-			*dp++ = '1';
-		else
-			*dp++ = '0';
-		b = b << 1;
-	}
-	return (dp - dest);
-}
-
-static
-byte           *
-skipext(byte * p)
-{
-	while (!(*p++ & 0x80));
-	return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- *         not yet written...
- */
-
-static
-struct CauseValue {
-	byte            nr;
-	char           *edescr;
-	char           *ddescr;
-} cvlist[] = {
-
-	{
-		0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
-	},
-	{
-		0x02, "No route to specified transit network", ""
-	},
-	{
-		0x03, "No route to destination", ""
-	},
-	{
-		0x04, "Send special information tone", ""
-	},
-	{
-		0x05, "Misdialled trunk prefix", ""
-	},
-	{
-		0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
-	},
-	{
-		0x07, "Channel awarded and being delivered in an established channel", ""
-	},
-	{
-		0x08, "Preemption", ""
-	},
-	{
-		0x09, "Preemption - circuit reserved for reuse", ""
-	},
-	{
-		0x10, "Normal call clearing", "Normale Ausloesung"
-	},
-	{
-		0x11, "User busy", "TNB besetzt"
-	},
-	{
-		0x12, "No user responding", ""
-	},
-	{
-		0x13, "No answer from user (user alerted)", ""
-	},
-	{
-		0x14, "Subscriber absent", ""
-	},
-	{
-		0x15, "Call rejected", ""
-	},
-	{
-		0x16, "Number changed", ""
-	},
-	{
-		0x1a, "non-selected user clearing", ""
-	},
-	{
-		0x1b, "Destination out of order", ""
-	},
-	{
-		0x1c, "Invalid number format (address incomplete)", ""
-	},
-	{
-		0x1d, "Facility rejected", ""
-	},
-	{
-		0x1e, "Response to Status enquiry", ""
-	},
-	{
-		0x1f, "Normal, unspecified", ""
-	},
-	{
-		0x22, "No circuit/channel available", ""
-	},
-	{
-		0x26, "Network out of order", ""
-	},
-	{
-		0x27, "Permanent frame mode connection out-of-service", ""
-	},
-	{
-		0x28, "Permanent frame mode connection operational", ""
-	},
-	{
-		0x29, "Temporary failure", ""
-	},
-	{
-		0x2a, "Switching equipment congestion", ""
-	},
-	{
-		0x2b, "Access information discarded", ""
-	},
-	{
-		0x2c, "Requested circuit/channel not available", ""
-	},
-	{
-		0x2e, "Precedence call blocked", ""
-	},
-	{
-		0x2f, "Resource unavailable, unspecified", ""
-	},
-	{
-		0x31, "Quality of service unavailable", ""
-	},
-	{
-		0x32, "Requested facility not subscribed", ""
-	},
-	{
-		0x35, "Outgoing calls barred within CUG", ""
-	},
-	{
-		0x37, "Incoming calls barred within CUG", ""
-	},
-	{
-		0x39, "Bearer capability not authorized", ""
-	},
-	{
-		0x3a, "Bearer capability not presently available", ""
-	},
-	{
-		0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
-	},
-	{
-		0x3f, "Service or option not available, unspecified", ""
-	},
-	{
-		0x41, "Bearer capability not implemented", ""
-	},
-	{
-		0x42, "Channel type not implemented", ""
-	},
-	{
-		0x43, "Requested facility not implemented", ""
-	},
-	{
-		0x44, "Only restricted digital information bearer capability is available", ""
-	},
-	{
-		0x4f, "Service or option not implemented", ""
-	},
-	{
-		0x51, "Invalid call reference value", ""
-	},
-	{
-		0x52, "Identified channel does not exist", ""
-	},
-	{
-		0x53, "A suspended call exists, but this call identity does not", ""
-	},
-	{
-		0x54, "Call identity in use", ""
-	},
-	{
-		0x55, "No call suspended", ""
-	},
-	{
-		0x56, "Call having the requested call identity has been cleared", ""
-	},
-	{
-		0x57, "User not member of CUG", ""
-	},
-	{
-		0x58, "Incompatible destination", ""
-	},
-	{
-		0x5a, "Non-existent CUG", ""
-	},
-	{
-		0x5b, "Invalid transit network selection", ""
-	},
-	{
-		0x5f, "Invalid message, unspecified", ""
-	},
-	{
-		0x60, "Mandatory information element is missing", ""
-	},
-	{
-		0x61, "Message type non-existent or not implemented", ""
-	},
-	{
-		0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
-	},
-	{
-		0x63, "Information element/parameter non-existent or not implemented", ""
-	},
-	{
-		0x64, "Invalid information element contents", ""
-	},
-	{
-		0x65, "Message not compatible with call state", ""
-	},
-	{
-		0x66, "Recovery on timer expiry", ""
-	},
-	{
-		0x67, "Parameter non-existent or not implemented - passed on", ""
-	},
-	{
-		0x6e, "Message with unrecognized parameter discarded", ""
-	},
-	{
-		0x6f, "Protocol error, unspecified", ""
-	},
-	{
-		0x7f, "Interworking, unspecified", ""
-	},
-};
-
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
-
-static
-int
-prcause(char *dest, byte * p)
-{
-	byte           *end;
-	char           *dp = dest;
-	int             i, cause;
-
-	end = p + p[1] + 1;
-	p += 2;
-	dp += sprintf(dp, "    coding ");
-	dp += prbits(dp, *p, 7, 2);
-	dp += sprintf(dp, " location ");
-	dp += prbits(dp, *p, 4, 4);
-	*dp++ = '\n';
-	p = skipext(p);
-
-	cause = 0x7f & *p++;
-
-	/* locate cause value */
-	for (i = 0; i < CVSIZE; i++)
-		if (cvlist[i].nr == cause)
-			break;
-
-	/* display cause value if it exists */
-	if (i == CVSIZE)
-		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
-	else
-		dp += sprintf(dp, "  cause value %x : %s \n", cause, cvlist[i].edescr);
-
-	while (!0) {
-		if (p > end)
-			break;
-		dp += sprintf(dp, "    diag attribute %d ", *p++ & 0x7f);
-		dp += sprintf(dp, " rej %d ", *p & 0x7f);
-		if (*p & 0x80) {
-			*dp++ = '\n';
-			break;
-		} else
-			dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
-	}
-	return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
-	{CAUSE_InvCRef, "Invalid Call Reference"},
-	{CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
-	{CAUSE_CIDunknown, "Caller Identity unknown"},
-	{CAUSE_CIDinUse, "Caller Identity in Use"},
-	{CAUSE_NoChans, "No Channels available"},
-	{CAUSE_FacNotImpl, "Facility Not Implemented"},
-	{CAUSE_FacNotSubscr, "Facility Not Subscribed"},
-	{CAUSE_OutgoingBarred, "Outgoing calls barred"},
-	{CAUSE_UserAccessBusy, "User Access Busy"},
-	{CAUSE_NegativeGBG, "Negative GBG"},
-	{CAUSE_UnknownGBG, "Unknown  GBG"},
-	{CAUSE_NoSPVknown, "No SPV known"},
-	{CAUSE_DestNotObtain, "Destination not obtainable"},
-	{CAUSE_NumberChanged, "Number changed"},
-	{CAUSE_OutOfOrder, "Out Of Order"},
-	{CAUSE_NoUserResponse, "No User Response"},
-	{CAUSE_UserBusy, "User Busy"},
-	{CAUSE_IncomingBarred, "Incoming Barred"},
-	{CAUSE_CallRejected, "Call Rejected"},
-	{CAUSE_NetworkCongestion, "Network Congestion"},
-	{CAUSE_RemoteUser, "Remote User initiated"},
-	{CAUSE_LocalProcErr, "Local Procedure Error"},
-	{CAUSE_RemoteProcErr, "Remote Procedure Error"},
-	{CAUSE_RemoteUserSuspend, "Remote User Suspend"},
-	{CAUSE_RemoteUserResumed, "Remote User Resumed"},
-	{CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
-
-static int
-prcause_1tr6(char *dest, byte * p) 
-{
-	char           *dp = dest;
-	int i, cause;
-
-	p++;
-	if (0 == *p) {
-		dp += sprintf(dp, "   OK (cause length=0)\n");
-		return (dp - dest);
-	} else if (*p > 1) {
-		dp += sprintf(dp, "    coding ");
-		dp += prbits(dp, p[2], 7, 2);
-		dp += sprintf(dp, " location ");
-		dp += prbits(dp, p[2], 4, 4);
-		*dp++ = '\n';
-	}
-	p++;
-	cause = 0x7f & *p;
-
-	/* locate cause value */
-	for (i = 0; i < cause_1tr6_len; i++)
-		if (cause_1tr6[i].nr == cause)
-			break;
-
-	/* display cause value if it exists */
-	if (i == cause_1tr6_len)
-		dp += sprintf(dp, "Unknown cause type %x!\n", cause);
-	else
-		dp += sprintf(dp, "  cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
-	return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, byte * p) {
-	char *dp = dest;
-
-	p += 2;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-static int
-prcalled(char *dest, byte * p) {
-	int             l;
-	char           *dp = dest;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p++, 8, 8);
-	*dp++ = '\n';
-	dp += sprintf(dp, "    number digits ");
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-static int
-prcalling(char *dest, byte * p) {
-	int             l;
-	char           *dp = dest;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	if (!(*p & 0x80)) {
-		dp += sprintf(dp, "    octet 3a ");
-		dp += prbits(dp, *++p, 8, 8);
-		*dp++ = '\n';
-		l--;
-	};
-	p++;
-
-	dp += sprintf(dp, "    number digits ");
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, byte * p)
-{
-	char           *dp = dest, ch;
-
-	p += 2;
-	dp += sprintf(dp, "    octet 3  ");
-	dp += prbits(dp, *p++, 8, 8);
-	*dp++ = '\n';
-	dp += sprintf(dp, "    octet 4  ");
-	dp += prbits(dp, *p, 8, 8);
-	*dp++ = '\n';
-	if ((*p++ & 0x1f) == 0x18) {
-		dp += sprintf(dp, "    octet 4.1 ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	/* check for user information layer 1 */
-	if ((*p & 0x60) == 0x20) {
-		ch = ' ';
-		do {
-			dp += sprintf(dp, "    octet 5%c ", ch);
-			dp += prbits(dp, *p, 8, 8);
-			*dp++ = '\n';
-			if (ch == ' ')
-				ch = 'a';
-			else
-				ch++;
-		}
-		while (!(*p++ & 0x80));
-	}
-	/* check for user information layer 2 */
-	if ((*p & 0x60) == 0x40) {
-		dp += sprintf(dp, "    octet 6  ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	/* check for user information layer 3 */
-	if ((*p & 0x60) == 0x60) {
-		dp += sprintf(dp, "    octet 7  ");
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-	}
-	return (dp - dest);
-}
-
-static int
-general(char *dest, byte * p) {
-	char           *dp = dest;
-	char            ch = ' ';
-	int             l, octet = 3;
-
-	p++;
-	l = *p++;
-	/* Iterate over all octets in the information element */
-	while (l--) {
-		dp += sprintf(dp, "    octet %d%c ", octet, ch);
-		dp += prbits(dp, *p++, 8, 8);
-		*dp++ = '\n';
-
-		/* last octet in group? */
-		if (*p & 0x80) {
-			octet++;
-			ch = ' ';
-		} else if (ch == ' ')
-			ch = 'a';
-		else
-			ch++;
-	}
-	return (dp - dest);
-}
-
-static int
-prcharge(char *dest, byte * p) {
-	char *dp = dest;
-	int l;
-
-	p++;
-	l = *p++ - 1;
-	dp += sprintf(dp, "    GEA ");
-	dp += prbits(dp, *p++, 8, 8);
-	dp += sprintf(dp, "  Anzahl: ");
-	/* Iterate over all octets in the * information element */
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-} 
-static int
-prtext(char *dest, byte * p) {
-	char *dp = dest;
-	int l;
-
-	p++;
-	l = *p++;
-	dp += sprintf(dp, "    ");
-	/* Iterate over all octets in the * information element */
-	while (l--)
-		*dp++ = *p++;
-	*dp++ = '\n';
-	return (dp - dest);
-}
-static int
-display(char *dest, byte * p) {
-	char           *dp = dest;
-	char            ch = ' ';
-	int             l, octet = 3;
-
-	p++;
-	l = *p++;
-	/* Iterate over all octets in the * display-information element */
-	dp += sprintf(dp, "   \"");
-	while (l--) {
-		dp += sprintf(dp, "%c", *p++);
-
-		/* last octet in group? */
-		if (*p & 0x80) {
-			octet++;
-			ch = ' ';
-		} else if (ch == ' ')
-			ch = 'a';
-
-		else
-			ch++;
-	}
-	*dp++ = '\"';
-	*dp++ = '\n';
-	return (dp - dest);
-}
-
-int
-prfacility(char *dest, byte * p)
-{
-	char           *dp = dest;
-	int             l, l2;
-
-	p++;
-	l = *p++;
-	dp += sprintf(dp, "    octet 3 ");
-	dp += prbits(dp, *p++, 8, 8);
-	dp += sprintf(dp, "\n");
-	l -= 1;
-
-	while (l > 0) {
-		dp += sprintf(dp, "   octet 4 ");
-		dp += prbits(dp, *p++, 8, 8);
-		dp += sprintf(dp, "\n");
-		dp += sprintf(dp, "   octet 5 %d\n", l2 = *p++ & 0x7f);
-		l -= 2;
-		dp += sprintf(dp, "   contents ");
-		while (l2--) {
-			dp += sprintf(dp, "%2x ", *p++);
-			l--;
-		}
-		dp += sprintf(dp, "\n");
-	}
-
-	return (dp - dest);
-}
-
-static
-struct InformationElement {
-	byte            nr;
-	char           *descr;
-	int             (*f) (char *, byte *);
-} ielist[] = {
-
-	{
-		0x00, "Segmented message", general
-	},
-	{
-		0x04, "Bearer capability", prbearer
-	},
-	{
-		0x08, "Cause", prcause
-	},
-	{
-		0x10, "Call identity", general
-	},
-	{
-		0x14, "Call state", general
-	},
-	{
-		0x18, "Channel identification", prchident
-	},
-	{
-		0x1c, "Facility", prfacility
-	},
-	{
-		0x1e, "Progress indicator", general
-	},
-	{
-		0x20, "Network-specific facilities", general
-	},
-	{
-		0x27, "Notification indicator", general
-	},
-	{
-		0x28, "Display", display
-	},
-	{
-		0x29, "Date/Time", general
-	},
-	{
-		0x2c, "Keypad facility", general
-	},
-	{
-		0x34, "Signal", general
-	},
-	{
-		0x40, "Information rate", general
-	},
-	{
-		0x42, "End-to-end delay", general
-	},
-	{
-		0x43, "Transit delay selection and indication", general
-	},
-	{
-		0x44, "Packet layer binary parameters", general
-	},
-	{
-		0x45, "Packet layer window size", general
-	},
-	{
-		0x46, "Packet size", general
-	},
-	{
-		0x47, "Closed user group", general
-	},
-	{
-		0x4a, "Reverse charge indication", general
-	},
-	{
-		0x6c, "Calling party number", prcalling
-	},
-	{
-		0x6d, "Calling party subaddress", general
-	},
-	{
-		0x70, "Called party number", prcalled
-	},
-	{
-		0x71, "Called party subaddress", general
-	},
-	{
-		0x74, "Redirecting number", general
-	},
-	{
-		0x78, "Transit network selection", general
-	},
-	{
-		0x79, "Restart indicator", general
-	},
-	{
-		0x7c, "Low layer compatibility", general
-	},
-	{
-		0x7d, "High layer compatibility", general
-	},
-	{
-		0x7e, "User-user", general
-	},
-	{
-		0x7f, "Escape for extension", general
-	},
-};
-
-
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
-
-static struct InformationElement we_0[] =
-{
-	{WE0_cause, "Cause", prcause_1tr6},
-	{WE0_connAddr, "Connecting Address", prcalled},
-	{WE0_callID, "Call IDentity", general},
-	{WE0_chanID, "Channel IDentity", general},
-	{WE0_netSpecFac, "Network Specific Facility", general},
-	{WE0_display, "Display", general},
-	{WE0_keypad, "Keypad", general},
-	{WE0_origAddr, "Origination Address", prcalled},
-	{WE0_destAddr, "Destination Address", prcalled},
-	{WE0_userInfo, "User Info", general}
-};
-
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
-
-static struct InformationElement we_6[] =
-{
-	{WE6_serviceInd, "Service Indicator", general},
-	{WE6_chargingInfo, "Charging Information", prcharge},
-	{WE6_date, "Date", prtext},
-	{WE6_facSelect, "Facility Select", general},
-	{WE6_facStatus, "Facility Status", general},
-	{WE6_statusCalled, "Status Called", general},
-	{WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
-
-void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
-	byte           *bend = buf + size;
-	char           *dp;
-	int i, cs = 0, cs_old = 0, cs_fest = 0;
-
-	/* display header */
-	dp = sp->dlogspace;
-	dp += sprintf(dp, "%s\n", comment);
-
-	{
-		byte *p = buf;
-		dp += sprintf(dp, "hex: ");
-		while (p < bend)
-		dp += sprintf(dp, "%02x ", *p++);
-		dp += sprintf(dp, "\n");
-		teles_putstatus(sp->dlogspace);
-		dp = sp->dlogspace;
-	} 
-	if ((0xfe & buf[0]) == PROTO_DIS_N0) {	/* 1TR6 */
-		/* locate message type */
-		if (buf[0] == PROTO_DIS_N0) {	/* N0 */
-			for (i = 0; i < mt_n0_len; i++)
-				if (mt_n0[i].nr == buf[3])
-					break;
-			/* display message type iff it exists */
-			if (i == mt_n0_len)
-				dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
-			else
-				dp += sprintf(dp, "call reference %d size %d message type %s\n",
-					      buf[2], size, mt_n0[i].descr);
-		} else {	/* N1 */
-			for (i = 0; i < mt_n1_len; i++)
-				if (mt_n1[i].nr == buf[3])
-					break;
-			/* display message type iff it exists */
-			if (i == mt_n1_len)
-				dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
-			else
-				dp += sprintf(dp, "call reference %d size %d message type %s\n",
-					      buf[2], size, mt_n1[i].descr);
-		}
-
-		/* display each information element */
-		buf += 4;
-		while (buf < bend) {
-			/* Is it a single octet information element? */
-			if (*buf & 0x80) {
-				switch ((*buf >> 4) & 7) {
-				  case 1:
-					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-					cs_old = cs;
-					cs = *buf & 7;
-					cs_fest = *buf & 8;
-					break;
-				  case 3:
-					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
-					break;
-				  case 2:
-					if (*buf == 0xa0) {
-						dp += sprintf(dp, "  More data\n");
-						break;
-					}
-					if (*buf == 0xa1) {
-						dp += sprintf(dp, "  Sending complete\n");
-					}
-					break;
-				  /* fall through */
-				  default:
-					dp += sprintf(dp, "  Reserved %x\n", *buf);
-					break;
-				}
-				buf++;
-				continue;
-			}
-			/* No, locate it in the table */
-			if (cs == 0) {
-				for (i = 0; i < we_0_len; i++)
-					if (*buf == we_0[i].nr)
-						break;
-
-				/* When found, give appropriate msg */
-				if (i != we_0_len) {
-					dp += sprintf(dp, "  %s\n", we_0[i].descr);
-					dp += we_0[i].f(dp, buf);
-				} else
-					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			} else if (cs == 6) {
-				for (i = 0; i < we_6_len; i++)
-					if (*buf == we_6[i].nr)
-						break;
-
-				/* When found, give appropriate msg */
-				if (i != we_6_len) {
-					dp += sprintf(dp, "  %s\n", we_6[i].descr);
-					dp += we_6[i].f(dp, buf);
-				} else
-					dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			} else
-				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-			/* Skip to next element */
-			if (cs_fest == 8) {
-				cs = cs_old;
-				cs_old = 0;
-				cs_fest = 0;
-			}
-			buf += buf[1] + 2;
-		}
-	} else if (buf[0]==PROTO_EURO) {	/* EURO */
-		/* locate message type */
-		for (i = 0; i < MTSIZE; i++)
-			if (mtlist[i].nr == buf[3])
-				break;
-
-		/* display message type iff it exists */
-		if (i == MTSIZE)
-			dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
-		else
-			dp += sprintf(dp, "call reference %d size %d message type %s\n",
-		buf[2], size, mtlist[i].descr);
-
-		/* display each information element */
-		buf += 4;
-		while (buf < bend) {
-			/* Is it a single octet information element? */
-			if (*buf & 0x80) {
-				switch ((*buf >> 4) & 7) {
-				  case 1:
-					dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-					break;
-				  case 3:
-					dp += sprintf(dp, "  Congestion level %x\n", *buf & 0xf);
-					break;
-				  case 5:
-					dp += sprintf(dp, "  Repeat indicator %x\n", *buf & 0xf);
-					break;
-				  case 2:
-					if (*buf == 0xa0) {
-						dp += sprintf(dp, "  More data\n");
-						break;
-					}
-					if (*buf == 0xa1) {
-						dp += sprintf(dp, "  Sending complete\n");
-					}
-					break;
-				  /* fall through */
-				  default:
-					dp += sprintf(dp, "  Reserved %x\n", *buf);
-					break;
-				}
-				buf++;
-				continue;
-			}
-			/* No, locate it in the table */
-			for (i = 0; i < IESIZE; i++)
-				if (*buf == ielist[i].nr)
-					break;
-
-			/* When not found, give appropriate msg */
-			if (i != IESIZE) {
-				dp += sprintf(dp, "  %s\n", ielist[i].descr);
-				dp += ielist[i].f(dp, buf);
-			} else
-				dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
-
-			/* Skip to next element */
-			buf += buf[1] + 2;
-		}
-	}
-	else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
-
-	dp += sprintf(dp, "\n");
-	teles_putstatus(sp->dlogspace);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/tei.c linux-2.0.31-pre3/drivers/isdn/teles/tei.c
--- linux-2.0.31-pre2/drivers/isdn/teles/tei.c	1996-04-21 01:56:15.000000000 -0700
+++ linux-2.0.31-pre3/drivers/isdn/teles/tei.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,248 +0,0 @@
-/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $
- *
- * $Log: tei.c,v $
- * Revision 1.1  1996/04/13 10:28:25  fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int      nrcards;
-
-static struct PStack *
-findces(struct PStack *st, int ces)
-{
-	struct PStack  *ptr = *(st->l1.stlistp);
-
-	while (ptr)
-		if (ptr->l2.ces == ces)
-			return (ptr);
-		else
-			ptr = ptr->next;
-	return (NULL);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
-	struct PStack  *ptr = *(st->l1.stlistp);
-
-	if (tei == 127)
-		return (NULL);
-
-	while (ptr)
-		if (ptr->l2.tei == tei)
-			return (ptr);
-		else
-			ptr = ptr->next;
-	return (NULL);
-}
-
-void 
-tei_handler(struct PStack *st,
-	    byte pr, struct BufHeader *ibh)
-{
-	byte           *bp;
-	unsigned int    tces;
-	struct PStack  *otsp, *ptr;
-	unsigned int    data;
-
-	if (st->l2.debug)
-		printk(KERN_DEBUG "teihandler %d\n", pr);
-
-	switch (pr) {
-	  case (MDL_ASSIGN):
-		  data = (unsigned int) ibh;
-		  BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
-		  if (!ibh)
-			  return;
-		  bp = DATAPTR(ibh);
-		  bp += st->l2.uihsize;
-		  bp[0] = 0xf;
-		  bp[1] = data >> 8;
-		  bp[2] = data & 0xff;
-		  bp[3] = 0x1;
-		  bp[4] = 0xff;
-		  ibh->datasize = 8;
-		  st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-		  break;
-	  case (DL_UNIT_DATA):
-		  bp = DATAPTR(ibh);
-		  bp += 3;
-		  if (bp[0] != 0xf)
-			  break;
-		  switch (bp[3]) {
-		    case (2):
-			    tces = (bp[1] << 8) | bp[2];
-			    BufPoolRelease(ibh);
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
-					   bp[4] >> 1);
-			    if ((otsp = findces(st, tces)))
-				    otsp->ma.teil2(otsp, MDL_ASSIGN,
-						   (void *)(bp[4] >> 1));
-			    break;
-		    case (4):
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
-			    if (bp[4] >> 1 == 0x7f) {
-				    BufPoolRelease(ibh);
-				    ptr = *(st->l1.stlistp);
-				    while (ptr) {
-					    if ((ptr->l2.tei & 0x7f) != 0x7f) {
-						    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
-							    break;
-						    bp = DATAPTR(ibh);
-						    bp += 3;
-						    bp[0] = 0xf;
-						    bp[1] = ptr->l2.ces >> 8;
-						    bp[2] = ptr->l2.ces & 0xff;
-						    bp[3] = 0x5;
-						    bp[4] = (ptr->l2.tei << 1) | 1;
-						    ibh->datasize = 8;
-						    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-					    }
-					    ptr = ptr->next;
-				    }
-			    } else {
-				    otsp = findtei(st, bp[4] >> 1);
-				    BufPoolRelease(ibh);
-				    if (!otsp)
-					    break;
-				    if (st->l3.debug)
-					    printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
-				    if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
-					    break;
-				    bp = DATAPTR(ibh);
-				    bp += 3;
-				    bp[0] = 0xf;
-				    bp[1] = otsp->l2.ces >> 8;
-				    bp[2] = otsp->l2.ces & 0xff;
-				    bp[3] = 0x5;
-				    bp[4] = (otsp->l2.tei << 1) | 1;
-				    ibh->datasize = 8;
-				    st->l3.l3l2(st, DL_UNIT_DATA, ibh);
-			    }
-			    break;
-		    default:
-			    BufPoolRelease(ibh);
-			    if (st->l3.debug)
-				    printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
-		  }
-		  break;
-	  default:
-		  printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
-		  break;
-	}
-}
-
-unsigned int 
-randomces(void)
-{
-	int             x = jiffies & 0xffff;
-
-	return (x);
-}
-
-static void 
-tei_man(struct PStack *sp, int i, void *v)
-{
-	printk(KERN_DEBUG "tei_man\n");
-}
-
-static void 
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
-	struct IsdnCardState *sp = st->l1.hardware;
-
-	tei_handler(sp->teistack, pr, arg);
-}
-
-void 
-setstack_tei(struct PStack *st)
-{
-	st->l2.l2tei = tei_l2tei;
-}
-
-static void 
-init_tei(struct IsdnCardState *sp, int protocol)
-{
-	struct PStack  *st;
-	char            tmp[128];
-
-#define DIRTY_HACK_AGAINST_SIGSEGV
-
-	st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
-				       "struct PStack");
-
-#ifdef DIRTY_HACK_AGAINST_SIGSEGV
-	sp->teistack = st;	                /* struct is not initialized yet */
-	sp->teistack->protocol = protocol;	/* struct is not initialized yet */
-#endif	                                        /* DIRTY_HACK_AGAINST_SIGSEGV    */
-
-
-	setstack_teles(st, sp);
-
-	st->l2.extended = !0;
-	st->l2.laptype = LAPD;
-	st->l2.window = 1;
-	st->l2.orig = !0;
-	st->protocol = protocol;
-
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
-
-	st->l2.t200 = 500;	/* 500 milliseconds */
-	st->l2.n200 = 4;	/* try 4 times */
-
-	st->l2.sap = 63;
-	st->l2.tei = 127;
-
-	sprintf(tmp, "Card %d tei ", sp->cardnr);
-	setstack_isdnl2(st, tmp);
-	st->l2.debug = 0;
-	st->l3.debug = 0;
-
-	st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-
-	st->l2.l2l3 = (void *) tei_handler;
-	st->l1.l1man = tei_man;
-	st->l2.l2man = tei_man;
-	st->l4.l2writewakeup = NULL;
-	
-	teles_addlist(sp, st);
-	sp->teistack = st;
-}
-
-static void 
-release_tei(struct IsdnCardState *sp)
-{
-	struct PStack  *st = sp->teistack;
-
-	teles_rmlist(sp, st);
-	Sfree((void *) st);
-}
-
-void 
-TeiNew(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp)
-			init_tei(cards[i].sp, cards[i].protocol);
-}
-
-void 
-TeiFree(void)
-{
-	int             i;
-
-	for (i = 0; i < nrcards; i++)
-		if (cards[i].sp)
-			release_tei(cards[i].sp);
-}
diff -urN linux-2.0.31-pre2/drivers/isdn/teles/teles.h linux-2.0.31-pre3/drivers/isdn/teles/teles.h
--- linux-2.0.31-pre2/drivers/isdn/teles/teles.h	1996-12-01 10:01:37.000000000 -0800
+++ linux-2.0.31-pre3/drivers/isdn/teles/teles.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,487 +0,0 @@
-/* $Id: teles.h,v 1.2 1996/04/30 21:52:04 isdn4dev Exp $
- *
- * $Log: teles.h,v $
- * Revision 1.2  1996/04/30 21:52:04  isdn4dev
- * SPV for 1TR6 - Karsten
- *
- * Revision 1.1  1996/04/13 10:29:00  fritz
- * Initial revision
- *
- *
- */
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/isdnif.h>
-#include <linux/tty.h>
-
-#define PH_ACTIVATE   1
-#define PH_DATA       2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN       4
-#define DL_UNIT_DATA     5
-#define SC_STARTUP       6
-#define CC_ESTABLISH     7
-#define DL_ESTABLISH     8
-#define DL_DATA          9
-#define CC_S_STATUS_ENQ  10
-
-#define CC_CONNECT       15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF                 17
-#define SC_DISCONNECT          18
-#define CO_DTMF                19
-#define DL_RELEASE             20
-
-#define CO_ALARM               22
-#define CC_REJECT              23
-
-#define CC_SETUP_REQ           24
-#define CC_SETUP_CNF           25
-#define CC_SETUP_IND           26
-#define CC_SETUP_RSP           27
-#define CC_SETUP_COMPLETE_IND  28
-
-#define CC_DISCONNECT_REQ      29
-#define CC_DISCONNECT_IND      30
-
-#define CC_RELEASE_CNF         31
-#define CC_RELEASE_IND         32
-#define CC_RELEASE_REQ         33
-
-#define CC_REJECT_REQ          34
-
-#define CC_PROCEEDING_IND      35
-
-#define CC_DLRL                36
-#define CC_DLEST               37
-
-#define CC_ALERTING_REQ        38
-#define CC_ALERTING_IND        39
-
-#define DL_STOP                40
-#define DL_START               41
-
-#define MDL_NOTEIPROC          46
-
-#define LC_ESTABLISH           47
-#define LC_RELEASE             48
-
-#define PH_REQUEST_PULL        49
-#define PH_PULL_ACK            50
-#define	PH_DATA_PULLED	       51
-#define CC_INFO_CHARGE         52
-
-/*
- * Message-Types 
- */
-
-#define MT_ALERTING            0x01
-#define MT_CALL_PROCEEDING     0x02
-#define MT_CONNECT             0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS            0x03
-#define MT_SETUP               0x05
-#define MT_SETUP_ACKNOWLEDGE   0x0d
-#define MT_RESUME              0x26
-#define MT_RESUME_ACKNOWLEDGE  0x2e
-#define MT_RESUME_REJECT       0x22
-#define MT_SUSPEND             0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT      0x21
-#define MT_USER_INFORMATION    0x20
-#define MT_DISCONNECT          0x45
-#define MT_RELEASE             0x4d
-#define MT_RELEASE_COMPLETE    0x5a
-#define MT_RESTART             0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT             0x60
-#define MT_CONGESTION_CONTROL  0x79
-#define MT_INFORMATION         0x7b
-#define MT_FACILITY            0x62
-#define MT_NOTIFY              0x6e
-#define MT_STATUS              0x7d
-#define MT_STATUS_ENQUIRY      0x75
-
-#define IE_CAUSE               0x08
-
-struct HscxIoctlArg {
-	int             channel;
-	int             mode;
-	int             transbufsize;
-};
-
-#ifdef __KERNEL__
-
-#undef DEBUG_MAGIC
-
-#define HSCX_SBUF_ORDER     1
-#define HSCX_SBUF_BPPS      2
-#define HSCX_SBUF_MAXPAGES  3
-
-#define HSCX_RBUF_ORDER     1
-#define HSCX_RBUF_BPPS      2
-#define HSCX_RBUF_MAXPAGES  3
-
-#define HSCX_SMALLBUF_ORDER     0
-#define HSCX_SMALLBUF_BPPS      40
-#define HSCX_SMALLBUF_MAXPAGES  1
-
-#define ISAC_SBUF_ORDER     0
-#define ISAC_SBUF_BPPS      16
-#define ISAC_SBUF_MAXPAGES  1
-
-#define ISAC_RBUF_ORDER     0
-#define ISAC_RBUF_BPPS      16
-#define ISAC_RBUF_MAXPAGES  1
-
-#define ISAC_SMALLBUF_ORDER     0
-#define ISAC_SMALLBUF_BPPS      40
-#define ISAC_SMALLBUF_MAXPAGES  1
-
-#define byte unsigned char
-
-#define MAX_WINDOW 8
-
-byte           *Smalloc(int size, int pr, char *why);
-void            Sfree(byte * ptr);
-
-/*
- * Statemachine 
- */
-struct Fsm {
-	int            *jumpmatrix;
-	int             state_count, event_count;
-	char          **strEvent, **strState;
-};
-
-struct FsmInst {
-	struct Fsm     *fsm;
-	int             state;
-	int             debug;
-	void           *userdata;
-	int             userint;
-	void            (*printdebug) (struct FsmInst *, char *);
-};
-
-struct FsmNode {
-	int             state, event;
-	void            (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
-	struct FsmInst *fi;
-	struct timer_list tl;
-	int             event;
-	void           *arg;
-};
-
-struct BufHeader {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *next;
-	struct BufPool *bp;
-	int             datasize;
-	byte            primitive, where;
-	void           *heldby;
-};
-
-struct Pages {
-	struct Pages   *next;
-};
-
-struct BufPool {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *freelist;
-	struct Pages   *pageslist;
-	int             pageorder;
-	int             pagescount;
-	int             bpps;
-	int             bufsize;
-	int             maxpages;
-};
-
-struct BufQueue {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	struct BufHeader *head, *tail;
-};
-
-struct Layer1 {
-	void           *hardware;
-	int             hscx;
-	struct BufPool *sbufpool, *rbufpool, *smallpool;
-	struct PStack **stlistp;
-	int             act_state;
-	void            (*l1l2) (struct PStack *, int, struct BufHeader *);
-        void            (*l1man) (struct PStack *, int, void *);
-	int             hscxmode, hscxchannel, requestpull;
-};
-
-struct Layer2 {
-	int             sap, tei, ces;
-	int             extended, laptype;
-	int             uihsize, ihsize;
-	int             vs, va, vr;
-	struct BufQueue i_queue;
-	int             window, orig;
-	int             rejexp;
-	int             debug;
-	struct BufHeader *windowar[MAX_WINDOW];
-	int             sow;
-	struct FsmInst  l2m;
-	void            (*l2l1) (struct PStack *, int, struct BufHeader *);
-        void            (*l2l1discardq) (struct PStack *, int, void *, int);
-        void            (*l2man) (struct PStack *, int, void *);
-	void            (*l2l3) (struct PStack *, int, void *);
-	void            (*l2tei) (struct PStack *, int, void *);
-	struct FsmTimer t200_timer, t203_timer;
-	int             t200, n200, t203;
-	int             rc, t200_running;
-	char            debug_id[32];
-};
-
-struct Layer3 {
-	void            (*l3l4) (struct PStack *, int, struct BufHeader *);
-        void            (*l3l2) (struct PStack *, int, void *);
-	int             state, callref;
-	int             debug;
-};
-
-struct Layer4 {
-	void            (*l4l3) (struct PStack *, int, void *);
-	void           *userdata;
-	void            (*l1writewakeup) (struct PStack *);
-	void		(*l2writewakeup) (struct PStack *);
-};
-
-struct Management {
-	void            (*manl1) (struct PStack *, int, void *);
-        void            (*manl2) (struct PStack *, int, void *);
-	void            (*teil2) (struct PStack *, int, void *);
-};
-
-struct Param {
-	int             cause;
-	int             bchannel;
-	int             callref;     /* TEI-Number                      */
-	int             itc;
-	int             info;	     /* Service-Indicator               */
-	int             info2;	     /* Service-Indicator, second octet */
-	char            calling[40]; /* Called Id                       */
-	char            called[40];  /* Caller Id                       */
-	int             chargeinfo;  /* Charge Info - only for 1tr6 in
-				      * the moment 
-				      */
-	int		spv;	     /* SPV Flag */
-};
-
-struct PStack {
-	struct PStack  *next;
-	struct Layer1   l1;
-	struct Layer2   l2;
-	struct Layer3   l3;
-	struct Layer4   l4;
-	struct Management ma;
-	struct Param   *pa;
-	int             protocol;     /* EDSS1 or 1TR6 */
-};
-
-struct HscxState {
-	byte           *membase;
-	int             iobase;
-	int             inuse, init, active;
-	struct BufPool  sbufpool, rbufpool, smallpool;
-	struct IsdnCardState *sp;
-	int             hscx, mode;
-	int             transbufsize, receive;
-	struct BufHeader *rcvibh, *xmtibh;
-	int             rcvptr, sendptr;
-	struct PStack  *st;
-	struct tq_struct tqueue;
-	int             event;
-	struct BufQueue rq, sq;
-	int             releasebuf;
-#ifdef DEBUG_MAGIC
-	int             magic;	/* 301270 */
-#endif
-};
-
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
-	int             magic;
-#endif
-	byte           *membase;
-	int             iobase;
-	struct BufPool  sbufpool, rbufpool, smallpool;
-	struct PStack  *stlist;
-	struct BufHeader *xmtibh, *rcvibh;
-	int             rcvptr, sendptr;
-	int             event;
-	struct tq_struct tqueue;
-	int             ph_active;
-	struct BufQueue rq, sq;
-
-	int             cardnr, ph_state;
-	struct PStack  *teistack;
-	struct HscxState hs[2];
-
-	int             dlogflag;
-	char           *dlogspace;
-	int             debug;
-	int             releasebuf;
-};
-
-struct IsdnCard {
-	byte           *membase;
-	int             interrupt;
-	unsigned int    iobase;
-	int             protocol;	/* EDSS1 or 1TR6 */
-	struct IsdnCardState *sp;
-};
-
-#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
-
-#define LAPD 0
-#define LAPB 1
-
-void            BufPoolInit(struct BufPool *bp, int order, int bpps,
-			    int maxpages);
-int             BufPoolAdd(struct BufPool *bp, int priority);
-void            BufPoolFree(struct BufPool *bp);
-int             BufPoolGet(struct BufHeader **bh,
-	      struct BufPool *bp, int priority, void *heldby, int where);
-void            BufPoolRelease(struct BufHeader *bh);
-void            BufQueueLink(struct BufQueue *bq,
-			     struct BufHeader *bh);
-int             BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
-void            BufQueueInit(struct BufQueue *bq);
-void            BufQueueRelease(struct BufQueue *bq);
-void            BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
-				int releasetoo);
-int             BufQueueLength(struct BufQueue *bq);
-void            BufQueueLinkFront(struct BufQueue *bq,
-				  struct BufHeader *bh);
-
-void            l2down(struct PStack *st,
-		       byte pr, struct BufHeader *ibh);
-void            l2up(struct PStack *st,
-		     byte pr, struct BufHeader *ibh);
-void            acceptph(struct PStack *st,
-			 struct BufHeader *ibh);
-void            setstack_isdnl2(struct PStack *st, char *debug_id);
-int             teles_inithardware(void);
-void            teles_closehardware(void);
-
-void            setstack_teles(struct PStack *st, struct IsdnCardState *sp);
-unsigned int    randomces(void);
-void            setstack_isdnl3(struct PStack *st);
-void            teles_addlist(struct IsdnCardState *sp,
-			      struct PStack *st);
-void            releasestack_isdnl2(struct PStack *st);
-void            teles_rmlist(struct IsdnCardState *sp,
-			     struct PStack *st);
-void            newcallref(struct PStack *st);
-
-int             ll_init(void);
-void            ll_stop(void), ll_unload(void);
-int             setstack_hscx(struct PStack *st, struct HscxState *hs);
-void            modehscx(struct HscxState *hs, int mode, int ichan);
-byte           *findie(byte * p, int size, byte ie, int wanted_set);
-int             getcallref(byte * p);
-
-void            FsmNew(struct Fsm *fsm,
-		       struct FsmNode *fnlist, int fncount);
-void            FsmFree(struct Fsm *fsm);
-int             FsmEvent(struct FsmInst *fi,
-			 int event, void *arg);
-void            FsmChangeState(struct FsmInst *fi,
-			       int newstate);
-void            FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int             FsmAddTimer(struct FsmTimer *ft,
-			  int millisec, int event, void *arg, int where);
-void            FsmDelTimer(struct FsmTimer *ft, int where);
-int             FsmTimerRunning(struct FsmTimer *ft);
-void            jiftime(char *s, long mark);
-
-void            CallcNew(void);
-void            CallcFree(void);
-int             CallcNewChan(void);
-void            CallcFreeChan(void);
-int             teles_command(isdn_ctrl * ic);
-int             teles_writebuf(int id, int chan, const u_char * buf, int count, int user);
-void            teles_putstatus(char *buf);
-void            teles_reportcard(int cardnr);
-int             ListLength(struct BufHeader *ibh);
-void            dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
-void            iecpy(byte * dest, byte * iestart, int ieoffset);
-void            setstack_transl2(struct PStack *st);
-void            releasestack_transl2(struct PStack *st);
-void            close_hscxstate(struct HscxState *);
-void            setstack_tei(struct PStack *st);
-
-struct LcFsm {
-	struct FsmInst  lcfi;
-	int             type;
-	struct Channel *ch;
-	void            (*lccall) (struct LcFsm *, int, void *);
-	struct PStack  *st;
-	int             l2_establish;
-	int             l2_start;
-	struct FsmTimer act_timer;
-	char            debug_id[32];
-};
-
-struct Channel {
-	struct PStack   ds, is;
-	struct IsdnCardState *sp;
-	int             hscx;
-	int             chan;
-	int             incoming;
-	struct FsmInst  fi;
-	struct LcFsm    lc_d, lc_b;
-	struct Param    para;
-	int             debug;
-#ifdef DEBUG_MAGIC
-	int             magic;	/* 301272 */
-#endif
-	int             l2_protocol, l2_active_protocol;
-	int             l2_primitive, l2_headersize;
-	int             data_open;
-	int             outcallref;
-	int             impair;
-};
-
-#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
-  sizeof(void *))/bpps)
-#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
-  sizeof(struct BufHeader))
-
-#endif
-
-void            Isdnl2New(void);
-void            Isdnl2Free(void);
-void            TeiNew(void);
-void            TeiFree(void);
-
-
-
-
diff -urN linux-2.0.31-pre2/drivers/net/ne.c linux-2.0.31-pre3/drivers/net/ne.c
--- linux-2.0.31-pre2/drivers/net/ne.c	1997-03-01 18:09:39.000000000 -0800
+++ linux-2.0.31-pre3/drivers/net/ne.c	2003-08-15 15:03:53.000000000 -0700
@@ -24,6 +24,7 @@
     Paul Gortmaker	: multiple card support for module users.
     Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
     Paul Gortmaker	: Allow users with bad cards to avoid full probe.
+    Paul Gortmaker	: PCI probe changes, more PCI cards supported.
 
 */
 
@@ -61,12 +62,21 @@
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
-/* ---- No user-serviceable parts below ---- */
-
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int netcard_portlist[] =
 { 0x300, 0x280, 0x320, 0x340, 0x360, 0};
 
+#ifdef CONFIG_PCI
+/* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */
+static struct { unsigned short vendor, dev_id;}
+pci_clone_list[] = {
+	{PCI_VENDOR_ID_REALTEK,		PCI_DEVICE_ID_REALTEK_8029},
+	{PCI_VENDOR_ID_WINBOND2,	PCI_DEVICE_ID_WINBOND2_89C940},
+	{PCI_VENDOR_ID_COMPEX,		PCI_DEVICE_ID_COMPEX_RL2000},
+	{0,}
+};
+#endif
+
 #ifdef SUPPORT_NE_BAD_CLONES
 /* A list of bad clones that we none-the-less recognize. */
 static struct { const char *name8, *name16; unsigned char SAprefix[4];}
@@ -80,10 +90,14 @@
     {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
     {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
     {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
+    {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
+    {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
     {0,}
 };
 #endif
 
+/* ---- No user-serviceable parts below ---- */
+
 #define NE_BASE	 (dev->base_addr)
 #define NE_CMD	 	0x00
 #define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
@@ -99,6 +113,7 @@
 static unsigned char pci_irq_line = 0;
 
 int ne_probe(struct device *dev);
+static int ne_probe_pci(struct device *dev);
 static int ne_probe1(struct device *dev, int ioaddr);
 
 static int ne_open(struct device *dev);
@@ -154,42 +169,13 @@
     else if (base_addr != 0)	/* Don't probe at all. */
 	return ENXIO;
 
+#ifdef CONFIG_PCI
     /* Then look for any installed PCI clones */
-#if defined(CONFIG_PCI)
-    if (pcibios_present()) {
-	int pci_index;
-	for (pci_index = 0; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn;
-		unsigned int pci_ioaddr;
-
-		/* Currently only Realtek are making PCI ne2k clones. */
-		if (pcibios_find_device (PCI_VENDOR_ID_REALTEK,
-				PCI_DEVICE_ID_REALTEK_8029, pci_index,
-				&pci_bus, &pci_device_fn) != 0)
-			break;	/* OK, now try to probe for std. ISA card */
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-				PCI_INTERRUPT_LINE, &pci_irq_line);
-		pcibios_read_config_dword(pci_bus, pci_device_fn,
-				PCI_BASE_ADDRESS_0, &pci_ioaddr);
-		/* Strip the I/O address out of the returned value */
-		pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
-		/* Avoid already found cards from previous ne_probe() calls */
-		if (check_region(pci_ioaddr, NE_IO_EXTENT)) {
-			pci_irq_line=0;
-			continue;
-		}
-		printk("ne.c: PCI BIOS reports ne2000 clone at i/o %#x, irq %d.\n",
-				pci_ioaddr, pci_irq_line);
-		if (ne_probe1(dev, pci_ioaddr) != 0) {	/* Shouldn't happen. */
-			printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
-			break;	/* Hrmm, try to probe for ISA card... */
-		}
-		pci_irq_line = 0;
-		return 0;
-	}
-    }
-#endif  /* defined(CONFIG_PCI) */
+    if (pcibios_present() && (ne_probe_pci(dev) == 0))
+  return 0;
+#endif
 
+#ifndef MODULE
     /* Last resort. The semi-risky ISA auto-probe. */
     for (i = 0; netcard_portlist[i]; i++) {
 	int ioaddr = netcard_portlist[i];
@@ -198,11 +184,53 @@
 	if (ne_probe1(dev, ioaddr) == 0)
 	    return 0;
     }
+#endif
 
     return ENODEV;
 }
 #endif
 
+#ifdef CONFIG_PCI
+static int ne_probe_pci(struct device *dev)
+{
+	int i;
+
+	for (i = 0; pci_clone_list[i].vendor != 0; i++) {
+		unsigned char pci_bus, pci_device_fn;
+		unsigned int pci_ioaddr;
+		int pci_index;
+		
+		for (pci_index = 0; pci_index < 8; pci_index++) {
+			if (pcibios_find_device (pci_clone_list[i].vendor,
+					pci_clone_list[i].dev_id, pci_index,
+					&pci_bus, &pci_device_fn) != 0)
+				break;	/* No more of these type of cards */
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+					PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			/* Strip the I/O address out of the returned value */
+			pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+			/* Avoid already found cards from previous calls */
+			if (check_region(pci_ioaddr, NE_IO_EXTENT))
+				continue;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+					PCI_INTERRUPT_LINE, &pci_irq_line);
+			break;	/* Beauty -- got a valid card. */
+		}
+		if (pci_irq_line == 0) continue;	/* Try next PCI ID */
+		printk("ne.c: PCI BIOS reports NE 2000 clone at i/o %#x, irq %d.\n",
+				pci_ioaddr, pci_irq_line);
+		if (ne_probe1(dev, pci_ioaddr) != 0) {	/* Shouldn't happen. */
+			printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
+			pci_irq_line = 0;
+			return -ENXIO;
+		}
+		pci_irq_line = 0;
+		return 0;
+	}
+	return -ENODEV;
+}
+#endif  /* CONFIG_PCI */
+
 static int ne_probe1(struct device *dev, int ioaddr)
 {
     int i;
@@ -310,8 +338,8 @@
 	for (i = 0; i < 16; i++)
 		SA_prom[i] = SA_prom[i+i];
     
-    if (pci_irq_line)
-	wordlength = 2;		/* Catch broken cards mentioned above. */
+    if (pci_irq_line || ioaddr >= 0x400)
+	wordlength = 2;		/* Catch broken PCI cards mentioned above. */
 
     if (wordlength == 2) {
 	/* We must set the 8390 for word mode. */
@@ -361,9 +389,8 @@
 
     }
 
-    if (pci_irq_line) {
+    if (pci_irq_line)
 	dev->irq = pci_irq_line;
-    }
 
     if (dev->irq < 2) {
 	autoirq_setup(0);
@@ -713,17 +740,17 @@
 		dev->irq = irq[this_dev];
 		dev->base_addr = io[this_dev];
 		dev->init = ne_probe;
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only complain once */
-			printk(KERN_NOTICE "ne.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
-			return -EPERM;
-		}
-		if (register_netdev(dev) != 0) {
-			printk(KERN_WARNING "ne.c: No NE*000 card found (i/o = 0x%x).\n", io[this_dev]);
-			if (found != 0) return 0;	/* Got at least one. */
-			return -ENXIO;
+		if (register_netdev(dev) == 0) {
+			found++;
+			continue;
 		}
-		found++;
+		if (found != 0) 	/* Got at least one. */
+			return 0;
+		if (io[this_dev] != 0)
+			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+		else
+			printk(KERN_NOTICE "ne.c: No PCI cards found. Use \"io=0xNNN\" value(s) for ISA cards.\n");
+		return -ENXIO;
 	}
 
 	return 0;
diff -urN linux-2.0.31-pre2/drivers/pci/pci.c linux-2.0.31-pre3/drivers/pci/pci.c
--- linux-2.0.31-pre2/drivers/pci/pci.c	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/drivers/pci/pci.c	2003-08-15 15:03:53.000000000 -0700
@@ -119,6 +119,7 @@
 	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER,    "MultiMaster"),
 	DEVICE( BUSLOGIC,	BUSLOGIC_FLASHPOINT,     "FlashPoint"),
 	DEVICE( OAK,		OAK_OTI107,	"OTI107"),
+	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI"),
 	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
 	DEVICE( N9,		N9_I128,	"Imagine 128"),
 	DEVICE( N9,		N9_I128_2,	"Imagine 128v2"),
@@ -199,6 +200,7 @@
 	DEVICE( ZEITNET,	ZEITNET_1225,	"1225"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
+	DEVICE( COMPEX,		COMPEX_RL2000,	"ReadyLink 2000"),
 	DEVICE( RP,             RP8OCTA,        "RocketPort 8 Oct"),
 	DEVICE( RP,             RP8INTF,        "RocketPort 8 Intf"),
 	DEVICE( RP,             RP16INTF,       "RocketPort 16 Intf"),
@@ -482,6 +484,7 @@
 	      case PCI_VENDOR_ID_SGS:		return "SGS Thomson";
 	      case PCI_VENDOR_ID_BUSLOGIC:	return "BusLogic";
 	      case PCI_VENDOR_ID_OAK: 		return "OAK";
+	      case PCI_VENDOR_ID_WINBOND2:	return "Winbond";
 	      case PCI_VENDOR_ID_PROMISE:	return "Promise Technology";
 	      case PCI_VENDOR_ID_N9:		return "Number Nine";
 	      case PCI_VENDOR_ID_UMC:		return "UMC";
@@ -520,6 +523,7 @@
 	      case PCI_VENDOR_ID_TOSHIBA:	return "Toshiba";
 	      case PCI_VENDOR_ID_ZEITNET:	return "ZeitNet";
 	      case PCI_VENDOR_ID_SPECIALIX:	return "Specialix";
+	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
 	      case PCI_VENDOR_ID_RP:		return "Comtrol";
 	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
 	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
diff -urN linux-2.0.31-pre2/drivers/scsi/Config.in linux-2.0.31-pre3/drivers/scsi/Config.in
--- linux-2.0.31-pre2/drivers/scsi/Config.in	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/drivers/scsi/Config.in	2003-08-15 15:03:53.000000000 -0700
@@ -87,5 +87,6 @@
     int  '  maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
   fi
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 endmenu
diff -urN linux-2.0.31-pre2/drivers/scsi/gdth.c linux-2.0.31-pre3/drivers/scsi/gdth.c
--- linux-2.0.31-pre2/drivers/scsi/gdth.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/scsi/gdth.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,3275 @@
+/************************************************************************
+ * GDT ISA/EISA/PCI Disk Array Controller driver for Linux              *
+ *                                                                      *
+ * gdth.c                                                               *
+ * Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner *
+ *                                                                      *
+ * <achim@vortex.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 of the License,    *
+ * or (at your option) any later version.                               *
+ *                                                                      *
+ * This program is distributed in the hope that it will be useful,      *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
+ * GNU General Public License for more details.                         *
+ *                                                                      *
+ * You should have received a copy of the GNU General Public License    *
+ * along with this kernel; if not, write to the Free Software           *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
+ *                                                                      *
+ * Tested with Linux 1.2.13, ..., 2.0.29                                *
+ *                                                                      *
+ * $Log: gdth.c,v $
+ * Revision 1.8  1997/04/02 12:14:30  achim
+ * Version 1.00 (see gdth.h), tested with kernel 2.0.29
+ *
+ * Revision 1.7  1997/03/12 13:33:37  achim
+ * gdth_reset() changed, new async. events
+ *
+ * Revision 1.6  1997/03/04 14:01:11  achim
+ * Shutdown routine gdth_halt() implemented
+ *
+ * Revision 1.5  1997/02/21 09:08:36  achim
+ * New controller included (RP, RP1, RP2 series)
+ * IOCTL interface implemented
+ *
+ * Revision 1.4  1996/07/05 12:48:55  achim
+ * Function gdth_bios_param() implemented
+ * New constant GDTH_MAXC_P_L inserted
+ * GDT_WRITE_THR, GDT_EXT_INFO implemented
+ * Function gdth_reset() changed
+ *
+ * Revision 1.3  1996/05/10 09:04:41  achim
+ * Small changes for Linux 1.2.13
+ *
+ * Revision 1.2  1996/05/09 12:45:27  achim
+ * Loadable module support implemented
+ * /proc support corrections made
+ *
+ * Revision 1.1  1996/04/11 07:35:57  achim
+ * Initial revision
+ *
+ *
+ * $Id: gdth.c,v 1.8 1997/04/02 12:14:30 achim Exp $ 
+ ************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/proc_fs.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#if LINUX_VERSION_CODE >= 0x010300
+#include <linux/blk.h>
+#else
+#include "../block/blk.h"
+#endif
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+
+#include "gdth.h"
+
+#if LINUX_VERSION_CODE >= 0x010346
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs);
+#endif
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
+static int gdth_async_event(int hanum,int service);
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
+static void gdth_next(int hanum);
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
+static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
+                                      gdth_evt_data *evt);
+static int gdth_read_event(int handle, gdth_evt_str *estr);
+static void gdth_readapp_event(unchar application, gdth_evt_str *estr);
+static void gdth_clear_events(void);
+
+static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count);
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
+                                   unchar b,ulong *flags);
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+
+static int gdth_search_eisa(ushort eisa_adr);
+static int gdth_search_isa(ulong bios_adr);
+static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr);
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime);
+static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime);
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime);
+
+static void gdth_enable_int(int hanum);
+static int gdth_get_status(unchar *pIStatus,int irq);
+static int gdth_test_busy(int hanum);
+static int gdth_get_cmd_index(int hanum);
+static void gdth_release_event(int hanum);
+static int gdth_wait(int hanum,int index,ulong time);
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
+                             ulong p2,ulong p3);
+static int gdth_search_drives(int hanum,int firsttime);
+
+static const char *gdth_ctr_name(int hanum);
+void gdth_halt(void);
+
+#ifdef DEBUG_GDTH
+static unchar   DebugState = DEBUG_GDTH;
+extern int sys_syslog(int,char*,int);
+#define LOGEN           sys_syslog(7,NULL,0);
+#define WAITSEC(a)      {ulong idx; for(idx=0;idx<a*1000L;++idx) udelay(1000);}
+
+#ifdef SLOWMOTION_GDTH
+#define SLOWM   WAITSEC(2)  
+#undef  INIT_RETRIES
+#undef  INIT_TIMEOUT
+#undef  POLL_TIMEOUT
+#define INIT_RETRIES    15
+#define INIT_TIMEOUT    150
+#define POLL_TIMEOUT    150
+#else
+#define SLOWM
+#endif
+
+#ifdef __SERIAL__
+#define MAX_SERBUF 160
+static void ser_init(void);
+static void ser_puts(char *str);
+static void ser_putc(char c);
+static int  ser_printk(const char *fmt, ...);
+static char strbuf[MAX_SERBUF+1];
+#ifdef __COM2__
+#define COM_BASE 0x2f8
+#else
+#define COM_BASE 0x3f8
+#endif
+static void ser_init()
+{
+    unsigned port=COM_BASE;
+
+    outb(0x80,port+3);
+    outb(0,port+1);
+    /* 19200 Baud, if 9600: outb(12,port) */
+    outb(6, port);
+    outb(3,port+3);
+    outb(0,port+1);
+    /*
+    ser_putc('I');
+    ser_putc(' ');
+    */
+}
+
+static void ser_puts(char *str)
+{
+    char *ptr;
+
+    ser_init();
+    for (ptr=str;*ptr;++ptr)
+        ser_putc(*ptr);
+}
+
+static void ser_putc(char c)
+{
+    unsigned port=COM_BASE;
+
+    while ((inb(port+5) & 0x20)==0);
+    outb(c,port);
+    if (c==0x0a)
+    {
+        while ((inb(port+5) & 0x20)==0);
+        outb(0x0d,port);
+    }
+}
+
+static int ser_printk(const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args,fmt);
+    i = vsprintf(strbuf,fmt,args);
+    ser_puts(strbuf);
+    va_end(args);
+    return i;
+}
+
+#define TRACE(a)    {if (DebugState==1) {ser_printk a; SLOWM}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a; SLOWM}}
+#define TRACE3(a)   {if (DebugState!=0) {ser_printk a; SLOWM}}
+
+#else /* !__SERIAL__ */
+#define TRACE(a)    {if (DebugState==1) {LOGEN;printk a; SLOWM}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a; SLOWM}}
+#define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a; SLOWM}}
+#endif
+
+#else /* !DEBUG */
+#define TRACE(a)
+#define TRACE2(a)
+#define TRACE3(a)
+#endif
+
+
+#ifdef GDTH_STATISTICS
+static ulong max_rq=0, max_index=0, max_sg=0;
+static ulong act_ints=0, act_ios=0, act_stats=0, act_rq=0;
+#define GDTH_TIMER      31                      /* see linux/timer.h ! */
+#endif
+
+#define PTR2USHORT(a)   (ushort)(ulong)(a)
+#define JIFFYWAIT(a)    {ulong gdtjf;gdtjf=jiffies+(a);while(gdtjf>jiffies);}
+#define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)   
+#define INDEX_OK(i,t)   ((i)<sizeof(t)/sizeof((t)[0]))
+
+#define NUMDATA(a)      ( (gdth_num_str  *)((a)->hostdata))
+#define HADATA(a)       (&((gdth_ext_str *)((a)->hostdata))->haext)
+#define CMDDATA(a)      (&((gdth_ext_str *)((a)->hostdata))->cmdext)
+#define DMADATA(a)      (&((gdth_ext_str *)((a)->hostdata))->dmaext)
+
+static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
+static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
+static unchar   gdth_polling;                           /* polling if TRUE */
+static unchar   gdth_from_wait  = FALSE;                /* gdth_wait() */
+static int      wait_index,wait_hanum;                  /* gdth_wait() */
+static int      gdth_ctr_count  = 0;                    /* controller count */
+static int      gdth_ctr_vcount = 0;                    /* virt. ctr. count */
+static struct Scsi_Host *gdth_ctr_tab[MAXHA];           /* controller table */
+static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS];   /* virt. ctr. table */
+static unchar   gdth_write_through = FALSE;             /* write through */
+static char *gdth_ioctl_tab[4][MAXHA];                  /* ioctl buffer */
+static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
+static int elastidx;
+static int eoldidx;
+
+static struct {
+    Scsi_Cmnd   *cmnd;                          /* pending request */
+    ushort      service;                        /* service */
+} gdth_cmd_tab[GDTH_MAXCMDS][MAXHA];            /* table of pend. requests */
+
+#define DIN     1                               /* IN data direction */
+#define DOU     2                               /* OUT data direction */
+#define DNO     DIN                             /* no data transfer */
+#define DUN     DIN                             /* unknown data direction */
+static unchar gdth_direction_tab[0x100] = {
+    DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
+    DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
+    DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DIN,DUN,DUN,DIN,DIN,DIN,
+    DIN,DIN,DIN,DNO,DIN,DNO,DNO,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,
+    DIN,DIN,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DIN,DIN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DIN,DUN,DNO,DUN,DIN,DIN,
+    DIN,DIN,DIN,DNO,DUN,DIN,DIN,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
+};
+
+/* LILO params: gdth=<IRQ>
+ *
+ * Where: <IRQ> is any of the valid IRQs for EISA controllers (10,11,12,14)
+ * Sets the IRQ of the GDT3000/3020 EISA controller to this value,
+ * if the IRQ can not automat. detect (controller BIOS disabled)
+ * See gdth_init_eisa() 
+ *
+ * You can use the command line gdth=0 to disable the driver 
+ */
+static unchar irqs[MAXHA] = {0xff};
+static unchar disable_gdth_scan = FALSE;
+
+/* /proc support */
+#if LINUX_VERSION_CODE >= 0x010300
+#include <linux/stat.h> 
+struct proc_dir_entry proc_scsi_gdth = {
+    PROC_SCSI_GDTH, 4, "gdth",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#include "gdth_proc.h"
+#include "gdth_proc.c"
+#endif
+
+
+/* controller search and initialization functions */
+
+static int gdth_search_eisa(ushort eisa_adr)
+{
+    ulong id;
+    
+    TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
+    id = inl(eisa_adr+ID0REG);
+    if (id == GDT3A_ID || id == GDT3B_ID) {     /* GDT3000A or GDT3000B */
+        if ((inb(eisa_adr+EISAREG) & 8) == 0)   
+            return 0;                           /* not EISA configured */
+        return 1;
+    }
+    if (id == GDT3_ID)                          /* GDT3000 */
+        return 1;
+
+    return 0;                                   
+}
+
+
+static int gdth_search_isa(ulong bios_adr)
+{
+    ulong id;
+
+    TRACE(("gdth_search_isa() bios adr. %lx\n",bios_adr));
+    id = *(ulong *)(bios_adr+BIOS_ID_OFFS);
+    if (id == GDT2_ID)                          /* GDT2000 */
+        return 1;
+    return 0;
+}
+
+
+static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
+{
+    int error;
+    ulong base0,base1,base2;
+
+    TRACE(("gdth_search_pci() device_id %d, index %d\n",
+                 device_id,index));
+
+    if (!pcibios_present())
+        return 0;
+
+    if (pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,index,
+                             &pcistr->bus,&pcistr->device_fn))
+        return 0;
+
+    /* GDT PCI controller found, now read resources from config space */
+#if LINUX_VERSION_CODE >= 0x010300
+#define GDTH_BASEP      (int *)
+#else
+#define GDTH_BASEP
+#endif
+    if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_0,
+                                           GDTH_BASEP&base0)) ||
+        (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_1,
+                                           GDTH_BASEP&base1)) ||
+        (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_2,
+                                           GDTH_BASEP&base2)) ||
+        (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+                                           PCI_ROM_ADDRESS,
+                                           GDTH_BASEP&pcistr->bios)) ||
+        (error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
+                                          PCI_INTERRUPT_LINE,&pcistr->irq))) {
+        printk("GDT-PCI: error %s reading configuration space",
+               pcibios_strerror(error));
+        return -1;
+    }
+
+    pcistr->device_id = device_id;
+    if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000 or GDT6000B */
+        device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
+        if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY)
+            return -1;
+        pcistr->dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+    } else {                                    /* GDT6110, GDT6120, .. */
+        if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
+            (base2 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
+            (base1 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO)
+            return -1;
+        pcistr->dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
+        pcistr->io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+        pcistr->io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
+    }
+    return 1;
+}
+
+
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
+{
+    ulong retries,id;
+    unchar prot_ver,eisacf,i,irq_found;
+
+    TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
+    
+    /* disable board interrupts, deinitialize services */
+    outb(0xff,eisa_adr+EDOORREG);
+    outb(0x00,eisa_adr+EDENABREG);
+    outb(0x00,eisa_adr+EINTENABREG);
+    
+    outb(0xff,eisa_adr+LDOORREG);
+    retries = INIT_RETRIES;
+    JIFFYWAIT(2);
+    while (inb(eisa_adr+EDOORREG) != 0xff) {
+        if (--retries == 0) {
+            printk("GDT-EISA: Initialization error (DEINIT failed)\n");
+            return 0;
+        }
+        udelay(1000);
+        TRACE2(("wait for DEINIT: retries=%ld\n",retries));
+    }
+    prot_ver = inb(eisa_adr+MAILBOXREG);
+    outb(0xff,eisa_adr+EDOORREG);
+    if (prot_ver != PROTOCOL_VERSION) {
+        printk("GDT-EISA: Illegal protocol version\n");
+        return 0;
+    }
+    ha->brd = (ulong)eisa_adr;
+    ha->brd_phys = (ulong)eisa_adr >> 12;
+
+    outl(0,eisa_adr+MAILBOXREG);
+    outl(0,eisa_adr+MAILBOXREG+4);
+    outl(0,eisa_adr+MAILBOXREG+8);
+    outl(0,eisa_adr+MAILBOXREG+12);
+
+    /* detect IRQ */ 
+    if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) {
+        ha->type = GDT_EISA;
+        ha->stype = id;
+        outl(1,eisa_adr+MAILBOXREG+8);
+        outb(0xfe,eisa_adr+LDOORREG);
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (inb(eisa_adr+EDOORREG) != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-EISA: Initialization error (get IRQ failed)\n");
+                return 0;
+            }
+            udelay(1000);
+        }
+        if (firsttime)
+            ha->irq = inb(eisa_adr+MAILBOXREG);
+        outb(0xff,eisa_adr+EDOORREG);
+        TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
+        if (firsttime) {
+            /* check the result */
+            if (ha->irq == 0) {
+                TRACE2(("Unknown IRQ, check IRQ table from cmd line !\n"));
+                for (i=0,irq_found=FALSE; i<MAXHA && irqs[i]!=0xff; ++i) {
+                    if (irqs[i]!=0) {
+                        irq_found=TRUE;
+                        break;
+                    }
+                }
+                if (irq_found) {
+                    ha->irq = irqs[i];
+                    irqs[i] = 0;
+                    printk("GDT-EISA: Can not detect controller IRQ,\n");
+                    printk("Use IRQ setting from command line (IRQ = %d)\n",
+                           ha->irq);
+                } else {
+                    printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
+                    printk("the controller BIOS or use command line parameters\n");
+                    return 0;
+                }
+            }
+        }
+    } else {
+        eisacf = inb(eisa_adr+EISAREG) & 7;
+        if (eisacf > 4)                         /* level triggered */
+            eisacf -= 4;
+        ha->irq = gdth_irq_tab[eisacf];
+        ha->type = GDT_EISA;
+        ha->stype= id;
+    }
+    return 1;
+}
+
+       
+static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
+{
+    register gdt2_dpram_str *dp2_ptr;
+    int i;
+    unchar irq_drq,prot_ver;
+    ulong retries;
+
+    TRACE(("gdth_init_isa() bios adr. %lx\n",bios_adr));
+
+    ha->brd = bios_adr;
+    dp2_ptr = (gdt2_dpram_str *)ha->brd;
+    dp2_ptr->io.memlock = 1;            /* switch off write protection */
+    /* reset interface area */
+    memset((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
+
+    /* disable board interrupts, read DRQ and IRQ */
+    dp2_ptr->io.irqdel     = 0xff;
+    dp2_ptr->io.irqen      = 0x00;
+    dp2_ptr->u.ic.S_Status = 0x00;
+    dp2_ptr->u.ic.Cmd_Index= 0x00;
+
+    irq_drq = dp2_ptr->io.rq;
+    for (i=0; i<3; ++i) {
+        if ((irq_drq & 1)==0)
+            break;
+        irq_drq >>= 1;
+    }
+    ha->drq = gdth_drq_tab[i];
+
+    irq_drq = dp2_ptr->io.rq >> 3;
+    for (i=1; i<5; ++i) {
+        if ((irq_drq & 1)==0)
+            break;
+        irq_drq >>= 1;
+    }
+    ha->irq = gdth_irq_tab[i];
+
+    /* deinitialize services */
+    dp2_ptr->u.ic.S_Info[0] = bios_adr;
+    dp2_ptr->u.ic.S_Cmd_Indx= 0xff;
+    dp2_ptr->io.event = 0;
+    retries = INIT_RETRIES;
+    JIFFYWAIT(2);
+    while (dp2_ptr->u.ic.S_Status != 0xff) {
+        if (--retries == 0) {
+            printk("GDT-ISA: Initialization error (DEINIT failed)\n");
+            return 0;
+        }
+        udelay(1000);
+    }
+    prot_ver = (unchar)dp2_ptr->u.ic.S_Info[0];
+    dp2_ptr->u.ic.Status = 0;
+    dp2_ptr->io.irqdel = 0xff;
+    if (prot_ver != PROTOCOL_VERSION) {
+        printk("GDT-ISA: Illegal protocol version\n");
+        return 0;
+    }
+
+    ha->type = GDT_ISA;
+    ha->ic_all_size = sizeof(dp2_ptr->u);
+    ha->stype= GDT2_ID;
+    ha->brd_phys = bios_adr >> 4;
+
+    /* special request to controller BIOS */
+    dp2_ptr->u.ic.S_Info[0] = 0x00;
+    dp2_ptr->u.ic.S_Info[1] = 0x00;
+    dp2_ptr->u.ic.S_Info[2] = 0x01;
+    dp2_ptr->u.ic.S_Info[3] = 0x00;
+    dp2_ptr->u.ic.S_Cmd_Indx= 0xfe;
+    dp2_ptr->io.event = 0;
+    retries = INIT_RETRIES;
+    JIFFYWAIT(2);
+    while (dp2_ptr->u.ic.S_Status != 0xfe) {
+        if (--retries == 0) {
+            printk("GDT-ISA: Initialization error\n");
+            return 0;
+        }
+        udelay(1000);
+    }
+    dp2_ptr->u.ic.Status = 0;
+    dp2_ptr->io.irqdel = 0xff;
+    return 1;
+}
+
+
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
+{
+    register gdt6_dpram_str *dp6_ptr;
+    register gdt6c_dpram_str *dp6c_ptr;
+    register gdt6m_dpram_str *dp6m_ptr;
+    ulong retries;
+    unchar prot_ver;
+    unchar remapped = FALSE;
+
+    TRACE(("gdth_init_pci()\n"));
+
+    if (firsttime) {
+        ha->brd      = pcistr->dpmem;
+        ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
+        ha->stype    = (ulong)pcistr->device_id;
+        ha->irq      = pcistr->irq;
+    }
+
+    if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {   /* GDT6000 or GDT6000B */
+        TRACE2(("init_pci() dpmem %lx irq %d\n",ha->brd,ha->irq));
+        dp6_ptr = (gdt6_dpram_str *)ha->brd;
+        /* reset interface area */
+        memset((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
+        if (*(ulong *)&dp6_ptr->u != 0) {
+            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+            return 0;
+        }
+        
+        /* disable board interrupts, deinit services */
+        dp6_ptr->io.irqdel     = 0xff;
+        dp6_ptr->io.irqen      = 0x00;
+        dp6_ptr->u.ic.S_Status = 0x00;
+        dp6_ptr->u.ic.Cmd_Index= 0x00;
+
+        dp6_ptr->u.ic.S_Info[0] = ha->brd;
+        dp6_ptr->u.ic.S_Cmd_Indx= 0xff;
+        dp6_ptr->io.event = 0;
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6_ptr->u.ic.S_Status != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                return 0;
+            }
+            udelay(1000);
+        }
+        prot_ver = (unchar)dp6_ptr->u.ic.S_Info[0];
+        dp6_ptr->u.ic.S_Status = 0;
+        dp6_ptr->io.irqdel = 0xff;
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+            return 0;
+        }
+
+        ha->type = GDT_PCI;
+        ha->ic_all_size = sizeof(dp6_ptr->u);
+        
+        /* special command to controller BIOS */
+        dp6_ptr->u.ic.S_Info[0] = 0x00;
+        dp6_ptr->u.ic.S_Info[1] = 0x00;
+        dp6_ptr->u.ic.S_Info[2] = 0x01;
+        dp6_ptr->u.ic.S_Info[3] = 0x00;
+        dp6_ptr->u.ic.S_Cmd_Indx= 0xfe;
+        dp6_ptr->io.event = 0;
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6_ptr->u.ic.S_Status != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+                return 0;
+            }
+            udelay(1000);
+        }
+        dp6_ptr->u.ic.S_Status = 0;
+        dp6_ptr->io.irqdel = 0xff;
+
+    } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, GDT6120, .. */
+        if (firsttime) {
+            ha->plx = (gdt6c_plx_regs *)pcistr->io;
+        }
+        TRACE2(("init_pci_new() dpmem %lx io %lx irq %d\n",
+                      ha->brd,(ulong)ha->plx,ha->irq));
+        dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+        /* reset interface area */
+        memset((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
+        if (*(ulong *)&dp6c_ptr->u != 0) {
+            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+            return 0;
+        }
+        
+        /* disable board interrupts, deinit services */
+        outb(0x00,PTR2USHORT(&ha->plx->control1));
+        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+        
+        dp6c_ptr->u.ic.S_Status = 0x00;
+        dp6c_ptr->u.ic.Cmd_Index= 0x00;
+
+        dp6c_ptr->u.ic.S_Info[0] = ha->brd;
+        dp6c_ptr->u.ic.S_Cmd_Indx= 0xff;
+
+        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6c_ptr->u.ic.S_Status != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                return 0;
+            }
+            udelay(1000);
+        }
+        prot_ver = (unchar)dp6c_ptr->u.ic.S_Info[0];
+        dp6c_ptr->u.ic.Status = 0;
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+            return 0;
+        }
+
+        ha->type = GDT_PCINEW;
+        ha->ic_all_size = sizeof(dp6c_ptr->u);
+
+        /* special command to controller BIOS */
+        dp6c_ptr->u.ic.S_Info[0] = 0x00;
+        dp6c_ptr->u.ic.S_Info[1] = 0x00;
+        dp6c_ptr->u.ic.S_Info[2] = 0x01;
+        dp6c_ptr->u.ic.S_Info[3] = 0x00;
+        dp6c_ptr->u.ic.S_Cmd_Indx= 0xfe;
+        
+        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6c_ptr->u.ic.S_Status != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+                return 0;
+            }
+            udelay(1000);
+        }
+        dp6c_ptr->u.ic.S_Status = 0;
+
+    } else {                                            /* MPR */
+        if (ha->brd > 0xfffff) {                        /* NOT below 1MB */
+#if LINUX_VERSION_CODE >= 0x010300
+            /* Linux 1.3.X allow to remap physical pages adresses greater
+               than the highest physical memory address to kernel virtual
+               pages using vremap()/vfree(), Linux 1.2.X doesn't */
+            TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",ha->brd,ha->irq));
+            ha->brd = (ulong)vremap(ha->brd, sizeof(gdt6m_dpram_str));
+            if (ha->brd == 0L) {
+                printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                return 0;
+            }
+            TRACE2(("init_pci_mpr() remapped dpmem %lx\n",ha->brd));
+            remapped = TRUE;
+#else
+            printk("GDT-PCI: Initialization error (DPMEM not below 1MB)\n");
+            return 0;
+#endif
+        }
+
+        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+        /* reset interface area */
+        memset((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u));
+        if (*(ulong *)&dp6m_ptr->u != 0) {
+            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+#if LINUX_VERSION_CODE >= 0x010300
+            if (remapped)
+                vfree((void *)ha->brd);
+#endif
+            return 0;
+        }
+        
+        /* disable board interrupts, deinit services */
+        dp6m_ptr->i960r.edoor_en_reg |= 4;
+        dp6m_ptr->i960r.edoor_reg = 0xff;
+        dp6m_ptr->u.ic.S_Status   = 0x00;
+        dp6m_ptr->u.ic.Cmd_Index  = 0x00;
+
+        dp6m_ptr->u.ic.S_Info[0]  = ha->brd;
+        dp6m_ptr->u.ic.S_Cmd_Indx = 0xff;
+        dp6m_ptr->i960r.ldoor_reg = 1;
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6m_ptr->u.ic.S_Status != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+#if LINUX_VERSION_CODE >= 0x010300
+                if (remapped)
+                    vfree((void *)ha->brd);
+#endif
+                return 0;
+            }
+            udelay(1000);
+        }
+        prot_ver = (unchar)dp6m_ptr->u.ic.S_Info[0];
+        dp6m_ptr->u.ic.S_Status = 0;
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+#if LINUX_VERSION_CODE >= 0x010300
+            if (remapped)
+                vfree((void *)ha->brd);
+#endif
+            return 0;
+        }
+
+        ha->type = GDT_PCIMPR;
+        ha->ic_all_size = sizeof(dp6m_ptr->u);
+        
+        /* special command to controller BIOS */
+        dp6m_ptr->u.ic.S_Info[0]  = 0x00;
+        dp6m_ptr->u.ic.S_Info[1]  = 0x00;
+        dp6m_ptr->u.ic.S_Info[2]  = 0x01;
+        dp6m_ptr->u.ic.S_Info[3]  = 0x00;
+        dp6m_ptr->u.ic.S_Cmd_Indx = 0xfe;
+        dp6m_ptr->i960r.ldoor_reg = 1;
+        retries = INIT_RETRIES;
+        JIFFYWAIT(2);
+        while (dp6m_ptr->u.ic.S_Status != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+#if LINUX_VERSION_CODE >= 0x010300
+                if (remapped)
+                    vfree((void *)ha->brd);
+#endif
+                return 0;
+            }
+            udelay(1000);
+        }
+        dp6m_ptr->u.ic.S_Status = 0;
+    }
+
+    return 1;
+}
+
+
+/* controller protocol functions */
+
+static void gdth_enable_int(int hanum)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    ushort addr;
+    gdt2_dpram_str *dp2_ptr;
+    gdt6_dpram_str *dp6_ptr;
+    gdt6m_dpram_str *dp6m_ptr;
+
+    TRACE(("gdth_enable_int() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    save_flags(flags);
+    cli();
+
+    if (ha->type == GDT_EISA) {
+        addr = (ushort)ha->brd;
+        outb(0xff,addr+EDOORREG);
+        outb(0xff,addr+EDENABREG);
+        outb(0x01,addr+EINTENABREG);
+    } else if (ha->type == GDT_ISA) {
+        dp2_ptr = (gdt2_dpram_str *)ha->brd;
+        dp2_ptr->io.irqdel = 1;
+        dp2_ptr->u.ic.Cmd_Index = 0;
+        dp2_ptr->io.irqen = 1;
+    } else if (ha->type == GDT_PCI) {
+        dp6_ptr = (gdt6_dpram_str *)ha->brd;
+        dp6_ptr->io.irqdel = 1;
+        dp6_ptr->u.ic.Cmd_Index = 0;
+        dp6_ptr->io.irqen = 1;
+    } else if (ha->type == GDT_PCINEW) {
+        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+        outb(0x03,PTR2USHORT(&ha->plx->control1));
+    } else if (ha->type == GDT_PCIMPR) {
+        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+        dp6m_ptr->i960r.edoor_reg = 0xff;
+        dp6m_ptr->i960r.edoor_en_reg &= ~4;
+    }
+    restore_flags(flags);
+}
+
+
+static int gdth_get_status(unchar *pIStatus,int irq)
+{
+    register gdth_ha_str *ha;
+    int i;
+
+    TRACE(("gdth_get_status() irq %d ctr_count %d\n",
+                 irq,gdth_ctr_count));
+    
+    *pIStatus = 0;
+    for (i=0; i<gdth_ctr_count; ++i) {
+        ha = HADATA(gdth_ctr_tab[i]);
+        if (ha->irq != (unchar)irq)             /* check IRQ */
+            continue;
+        if (ha->type == GDT_EISA)
+            *pIStatus = inb((ushort)ha->brd+EDOORREG);
+        else if (ha->type == GDT_ISA)
+            *pIStatus = ((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+        else if (ha->type == GDT_PCI)
+            *pIStatus = ((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+        else if (ha->type == GDT_PCINEW) 
+            *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+        else if (ha->type == GDT_PCIMPR)
+            *pIStatus = ((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg;
+   
+        if (*pIStatus)                                  
+            return i;                           /* board found */
+    }
+    return -1;
+}
+                 
+    
+static int gdth_test_busy(int hanum)
+{
+    register gdth_ha_str *ha;
+    register int gdtsema0 = 0;
+
+    TRACE(("gdth_test_busy() hanum %d\n",hanum));
+    
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (ha->type == GDT_EISA)
+        gdtsema0 = (int)inb((ushort)ha->brd+SEMA0REG);
+    else if (ha->type == GDT_ISA)
+        gdtsema0 = (int)((gdt2_dpram_str *)ha->brd)->u.ic.Sema0;
+    else if (ha->type == GDT_PCI)
+        gdtsema0 = (int)((gdt6_dpram_str *)ha->brd)->u.ic.Sema0;
+    else if (ha->type == GDT_PCINEW) 
+        gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
+    else if (ha->type == GDT_PCIMPR)
+        gdtsema0 = (int)((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg;
+
+    return (gdtsema0 & 1);
+}
+
+
+static int gdth_get_cmd_index(int hanum)
+{
+    register gdth_ha_str *ha;
+    int i;
+
+    TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    for (i=0; i<GDTH_MAXCMDS; ++i) {
+        if (gdth_cmd_tab[i][hanum].cmnd == UNUSED_CMND) {
+            gdth_cmd_tab[i][hanum].cmnd = ha->pccb->RequestBuffer;
+            gdth_cmd_tab[i][hanum].service = ha->pccb->Service;
+            ha->pccb->CommandIndex = (ulong)i+2;
+            return (i+2);
+        }
+    }
+    return 0;
+}
+
+
+static void gdth_set_sema0(int hanum)
+{
+    register gdth_ha_str *ha;
+
+    TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (ha->type == GDT_EISA)
+        outb(1,(ushort)ha->brd+SEMA0REG);
+    else if (ha->type == GDT_ISA)
+        ((gdt2_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+    else if (ha->type == GDT_PCI)
+        ((gdt6_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+    else if (ha->type == GDT_PCINEW)  
+        outb(1,PTR2USHORT(&ha->plx->sema0_reg));
+    else if (ha->type == GDT_PCIMPR)
+        ((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg = 1;
+    
+}
+
+
+static void gdth_copy_command(int hanum)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmd_ptr;
+    register gdt6m_dpram_str *dp6m_ptr;
+    register gdt6c_dpram_str *dp6c_ptr;
+    gdt6_dpram_str *dp6_ptr;
+    gdt2_dpram_str *dp2_ptr;
+    ushort cp_count,dp_offset,cmd_no;
+    
+    TRACE(("gdth_copy_command() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cp_count = ha->cmd_len;
+    dp_offset= ha->cmd_offs_dpmem;
+    cmd_no   = ha->cmd_cnt;
+    cmd_ptr  = ha->pccb;
+
+    ++ha->cmd_cnt;                                                      
+    if (ha->type == GDT_EISA)
+        return;                                 /* no DPMEM, no copy */
+
+    /* set cpcount dword aligned */
+    if (cp_count & 3)
+        cp_count += (4 - (cp_count & 3));
+
+    ha->cmd_offs_dpmem += cp_count;
+    
+    /* set offset and service, copy command to DPMEM */
+    if (ha->type == GDT_ISA) {
+        dp2_ptr = (gdt2_dpram_str *)ha->brd;
+        dp2_ptr->u.ic.comm_queue[cmd_no].offset =
+            dp_offset + DPMEM_COMMAND_OFFSET;
+        dp2_ptr->u.ic.comm_queue[cmd_no].serv_id =
+            (ushort)cmd_ptr->Service;
+        memcpy(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCI) {
+        dp6_ptr = (gdt6_dpram_str *)ha->brd;
+        dp6_ptr->u.ic.comm_queue[cmd_no].offset =
+            dp_offset + DPMEM_COMMAND_OFFSET;
+        dp6_ptr->u.ic.comm_queue[cmd_no].serv_id =
+            (ushort)cmd_ptr->Service;
+        memcpy(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCINEW) {
+        dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+        dp6c_ptr->u.ic.comm_queue[cmd_no].offset =
+            dp_offset + DPMEM_COMMAND_OFFSET;
+        dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id =
+            (ushort)cmd_ptr->Service;
+        memcpy(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCIMPR) {
+        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+        dp6m_ptr->u.ic.comm_queue[cmd_no].offset =
+            dp_offset + DPMEM_COMMAND_OFFSET;
+        dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id =
+            (ushort)cmd_ptr->Service;
+        memcpy(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    }
+}
+
+
+static void gdth_release_event(int hanum)
+{
+    register gdth_ha_str *ha;
+
+#ifdef GDTH_STATISTICS
+    ulong i,j;
+    for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
+        if (gdth_cmd_tab[j][hanum].cmnd != UNUSED_CMND)
+            ++i;
+    }
+    if (max_index < i) {
+        max_index = i;
+        TRACE3(("GDT: max_index = %d\n",(ushort)i));
+    }
+#endif
+
+    TRACE(("gdth_release_event() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (ha->pccb->OpCode == GDT_INIT)
+        ha->pccb->Service |= 0x80;
+
+    if (ha->type == GDT_EISA) {
+        outb(ha->pccb->Service,(ushort)ha->brd+LDOORREG);
+        if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
+            outl((ulong)ha->pccb,(ushort)ha->brd+MAILBOXREG);
+    } else if (ha->type == GDT_ISA)
+        ((gdt2_dpram_str *)ha->brd)->io.event = 0;
+    else if (ha->type == GDT_PCI)
+        ((gdt6_dpram_str *)ha->brd)->io.event = 0;
+    else if (ha->type == GDT_PCINEW) 
+        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+    else if (ha->type == GDT_PCIMPR)
+        ((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg = 1;
+}
+
+    
+static int gdth_wait(int hanum,int index,ulong time)
+{
+    gdth_ha_str *ha;
+    int answer_found = FALSE;
+
+    TRACE(("gdth_wait() hanum %d index %d time %ld\n",hanum,index,time));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (index == 0)
+        return 1;                               /* no wait required */
+
+    gdth_from_wait = TRUE;
+    do {
+#if LINUX_VERSION_CODE >= 0x010346
+        gdth_interrupt((int)ha->irq,NULL,NULL);
+#else
+        gdth_interrupt((int)ha->irq,NULL);
+#endif
+        if (wait_hanum==hanum && wait_index==index) {
+            answer_found = TRUE;
+            break;
+        }
+        udelay(1000);
+    } while (--time);
+    gdth_from_wait = FALSE;
+    
+    while (gdth_test_busy(hanum))
+        udelay(1);
+
+    return (answer_found);
+}
+
+
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
+                             ulong p2,ulong p3)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmd_ptr;
+    int retries,index;
+
+    TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cmd_ptr = ha->pccb;
+    memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
+
+    /* make command  */
+    for (retries = INIT_RETRIES;;) {
+        cmd_ptr->Service          = service;
+        cmd_ptr->RequestBuffer    = INTERNAL_CMND;
+        if (!(index=gdth_get_cmd_index(hanum))) {
+            TRACE(("GDT: No free command index found\n"));
+            return 0;
+        }
+        gdth_set_sema0(hanum);
+        cmd_ptr->OpCode           = opcode;
+        cmd_ptr->BoardNode        = LOCALBOARD;
+        if (service == CACHESERVICE) {
+            if (opcode == GDT_IOCTL) {
+                cmd_ptr->u.ioctl.subfunc = p1;
+                cmd_ptr->u.ioctl.channel = p2;
+                cmd_ptr->u.ioctl.param_size = (ushort)p3;
+                cmd_ptr->u.ioctl.p_param = (ulong)ha->pscratch;
+            } else {
+                cmd_ptr->u.cache.DeviceNo = (ushort)p1;
+                cmd_ptr->u.cache.BlockNo  = p2;
+            }
+        } else if (service == SCSIRAWSERVICE) {
+            cmd_ptr->u.raw.direction  = p1;
+            cmd_ptr->u.raw.bus        = (unchar)p2;
+            cmd_ptr->u.raw.target     = (unchar)p3;
+            cmd_ptr->u.raw.lun        = 0;
+        }
+        ha->cmd_len          = sizeof(gdth_cmd_str);
+        ha->cmd_offs_dpmem   = 0;
+        ha->cmd_cnt          = 0;
+        gdth_copy_command(hanum);
+        gdth_release_event(hanum);
+        JIFFYWAIT(2);
+        if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+            printk("GDT: Initialization error (timeout service %d)\n",service);
+            return 0;
+        }
+        if (ha->status != S_BSY || --retries == 0)
+            break;
+        udelay(1000);   
+    }   
+    
+    return (ha->status != S_OK ? 0:1);
+}
+    
+
+/* search for devices */
+
+static int gdth_search_drives(int hanum,int firsttime)
+{
+    register gdth_ha_str *ha;
+    ushort cdev_cnt,i;
+    unchar b,t,pos_found;
+    ulong drv_cyls, drv_hds, drv_secs;
+    ulong bus_no;
+    gdth_getch_str *chn;
+    
+    TRACE(("gdth_search_drives() hanum %d flag %d\n",hanum,firsttime));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    /* initialize controller services, at first: screen service */
+    if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) {
+        printk("GDT: Initialization error screen service (code %d)\n",
+               ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
+    
+    /* initialize cache service */
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
+        printk("GDT: Initialization error cache service (code %d)\n",
+               ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
+    cdev_cnt = (ushort)ha->info;
+
+    if (firsttime) {
+        /* mount all cache devices */
+        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0)) {
+            printk("GDT: Initialization error cache service (code %d)\n",
+                   ha->status);
+            return 0;
+        }
+        TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
+
+        /* initialize cache service after mountall */
+        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
+            printk("GDT: Initialization error cache service (code %d)\n",
+                   ha->status);
+            return 0;
+        }
+        TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
+        cdev_cnt = (ushort)ha->info;
+
+        /* detect number of SCSI buses */
+        chn = (gdth_getch_str *)DMADATA(gdth_ctr_tab[hanum]);
+        for (bus_no=0; bus_no<MAXBUS; ++bus_no) {
+            chn->channel_no = bus_no;
+            if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                   SCSI_CHAN_CNT | L_CTRL_PATTERN,
+                                   IO_CHANNEL | INVALID_CHANNEL,
+                                   sizeof(gdth_getch_str))) {
+                if (bus_no == 0) {
+                    printk("GDT: Error detecting SCSI channel count (0x%x)\n",
+                           ha->status);
+                    return 0;
+                }
+                break;
+            }
+            if (chn->siop_id < MAXID)
+                ha->id[bus_no][chn->siop_id].type = SIOP_DTYP;
+        }       
+        ha->bus_cnt = (unchar)bus_no;
+        TRACE2(("gdth_search_drives() %d SCSI channels\n",ha->bus_cnt));
+
+        /* read cache configuration */
+        if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+                               INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
+            printk("GDT: Initialization error cache service (code %d)\n",
+                   ha->status);
+            return 0;
+        }
+        ha->cpar = ((gdth_cinfo_str *)DMADATA(gdth_ctr_tab[hanum]))->cpar;
+        TRACE2(("gdth_search_drives() cinfo: vs %lx sta %d str %d dw %d b %d\n",
+                ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
+                ha->cpar.write_back,ha->cpar.block_size));
+    }
+
+    /* initialize raw service */
+    if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
+        printk("GDT: Initialization error raw service (code %d)\n",
+               ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
+
+    /* set/get features raw service (scatter/gather) */
+    ha->raw_feat = 0;
+    if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
+                          0,0)) {
+        TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
+        if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0))
+        {
+            TRACE2(("gdth_search_dr(): get feat RAWSERVICE %ld\n",
+                          ha->info));
+            ha->raw_feat = (ushort)ha->info;
+        }
+    } 
+
+    /* set/get features cache service (equal to raw service) */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+                          SCATTER_GATHER,0)) {
+        TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+            TRACE2(("gdth_search_dr(): get feat CACHESERV. %ld\n",
+                          ha->info));
+            ha->cache_feat = (ushort)ha->info;
+        }
+    }
+
+    /* if it is not the first scan, we are ready */
+    if (!firsttime)
+        return 1;
+
+    /* scanning for raw devices */
+    for (b=0; b<ha->bus_cnt; ++b) {
+        for (t=0; t<MAXID; ++t) {
+            TRACE(("gdth_search_drives() rawd. bus %d id %d\n",b,t));
+            if (ha->id[b][t].type != SIOP_DTYP && 
+                gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INFO,0,b,t)) {
+                ha->id[b][t].type = RAW_DTYP;
+            }
+        }
+    }
+
+    /* scanning for cache devices */
+    for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
+        TRACE(("gdth_search_drives() cachedev. %d\n",i));
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
+            /* dynamic relation between host drive number and Bus/ID */
+            /* search free position */
+            pos_found = FALSE;
+            for (b=0,t=0; b<ha->bus_cnt; ++b) {
+                for (t=0; t<MAXID; ++t) {
+                    if (ha->id[b][t].type == EMPTY_DTYP) {
+                        pos_found = TRUE;
+                        break;
+                    }
+                }
+                if (pos_found)
+                    break;
+            }
+            TRACE(("gdth_search_dr() drive %d free pos at bus/id %d/%d\n",
+                         i,b,t));
+
+            ha->id[b][t].type      = CACHE_DTYP;
+            ha->id[b][t].devtype   = 0;
+            ha->id[b][t].size      = ha->info;
+            ha->id[b][t].hostdrive = i;
+
+            /* evaluate mapping (sectors per head, heads per cylinder) */
+            ha->id[b][t].size &= ~SECS32;
+            drv_cyls = ha->id[b][t].size /HEADS/SECS;
+            if (drv_cyls <= MAXCYLS) {
+                drv_hds = HEADS;
+                drv_secs= SECS;
+            } else {                            /* too high for 64*32 */
+                drv_cyls = ha->id[b][t].size /MEDHEADS/MEDSECS;
+                if (drv_cyls <= MAXCYLS) {
+                    drv_hds = MEDHEADS;
+                    drv_secs= MEDSECS;
+                } else {                        /* too high for 127*63 */
+                    drv_cyls = ha->id[b][t].size /BIGHEADS/BIGSECS;
+                    drv_hds = BIGHEADS;
+                    drv_secs= BIGSECS;
+                }
+            }
+            ha->id[b][t].heads = (unchar)drv_hds;
+            ha->id[b][t].secs  = (unchar)drv_secs;
+            /* round size */
+            ha->id[b][t].size  = drv_cyls * drv_hds * drv_secs;
+            TRACE(("gdth_search_dr() cdr. %d size %ld hds %ld scs %ld\n",
+                   i,ha->id[b][t].size,drv_hds,drv_secs));
+            
+            /* get informations about device */
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
+                                  0,0)) {
+                TRACE(("gdth_search_dr() cache drive %d devtype %ld\n",
+                       i,ha->info));
+                ha->id[b][t].devtype = (ushort)ha->info;
+            }
+        }
+    }
+
+    TRACE(("gdth_search_drives() OK\n"));
+    return 1;
+}
+
+
+/* command queueing/sending functions */
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+{
+    register gdth_ha_str *ha;
+    register Scsi_Cmnd *pscp;
+    register Scsi_Cmnd *nscp;
+    ulong flags;
+    unchar b, t;
+
+    TRACE(("gdth_putq() priority %d\n",priority));
+    save_flags(flags);
+    cli();
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    scp->SCp.this_residual = (int)priority;
+    gdth_update_timeout(scp, scp->timeout * 6);
+#if LINUX_VERSION_CODE >= 0x010400
+    b = scp->channel;
+#else
+    b = NUMDATA(nscp->host)->busnum;
+#endif
+    t = scp->target;
+#if LINUX_VERSION_CODE >= 0x010300
+    if (priority >= DEFAULT_PRI && ha->id[b][t].lock) {
+        TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
+        scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+    }
+#endif
+
+    if (ha->req_first==NULL) {
+        ha->req_first = scp;                    /* queue was empty */
+        scp->SCp.ptr = NULL;
+    } else {                                    /* queue not empty */
+        pscp = ha->req_first;
+        nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+        /* priority: 0-highest,..,0xff-lowest */
+        while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+            pscp = nscp;
+            nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+        }
+        pscp->SCp.ptr = (char *)scp;
+        scp->SCp.ptr  = (char *)nscp;
+    }
+    restore_flags(flags);
+
+#ifdef GDTH_STATISTICS
+    flags = 0;
+    for (nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+        ++flags;
+    if (max_rq < flags) {
+        max_rq = flags;
+        TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq));
+    }
+#endif
+}
+
+static void gdth_next(int hanum)
+{
+    register gdth_ha_str *ha;
+    register Scsi_Cmnd *pscp;
+    register Scsi_Cmnd *nscp;
+    unchar b, t, next_cmd, firsttime;
+    ushort hdrive;
+    ulong flags;
+    int cmd_index;
+
+    TRACE(("gdth_next() hanum %d\n",hanum));
+    save_flags(flags);
+    cli();
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
+    next_cmd = firsttime = TRUE;
+    cmd_index = 0;
+
+    for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+        if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
+            pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+#if LINUX_VERSION_CODE >= 0x010400
+        b = nscp->channel;
+#else
+        b = NUMDATA(nscp->host)->busnum;
+#endif
+        t = nscp->target;
+        if (nscp->SCp.this_residual < DEFAULT_PRI || !ha->id[b][t].lock) {
+
+            if (firsttime) {
+                if (gdth_test_busy(hanum)) {        /* controller busy ? */
+                    TRACE(("gdth_next() controller %d busy !\n",hanum));
+                    if (!gdth_polling) {
+                        restore_flags(flags);
+                        return;
+                    }
+                    while (gdth_test_busy(hanum))
+                        udelay(1000);
+                }
+                firsttime = FALSE;
+            }
+
+#if LINUX_VERSION_CODE >= 0x010300
+            if (nscp->done == gdth_scsi_done) {
+                if (!(cmd_index=gdth_special_cmd(hanum,nscp,b)))
+                    next_cmd = FALSE;
+            } else
+#endif
+            if (ha->id[b][t].type != CACHE_DTYP) {
+                if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,b)))
+                    next_cmd = FALSE;
+            } else {
+                hdrive = ha->id[b][t].hostdrive;
+                switch (nscp->cmnd[0]) {
+                  case TEST_UNIT_READY:
+                  case INQUIRY:
+                  case REQUEST_SENSE:
+                  case READ_CAPACITY:
+                  case VERIFY:
+                  case START_STOP:
+                  case MODE_SENSE:
+                    TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                        nscp->cmnd[4],nscp->cmnd[5]));
+                        gdth_internal_cache_cmd(hanum,nscp,b,&flags);
+                    break;
+
+                  case ALLOW_MEDIUM_REMOVAL:
+                    TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                        nscp->cmnd[4],nscp->cmnd[5]));
+                    if ( (nscp->cmnd[4]&1) && !(ha->id[b][t].devtype&1) ) {
+                        TRACE2(("Prevent r. nonremov. drive->do nothing\n"));
+                        nscp->result = DID_OK << 16;
+                        restore_flags( flags );
+                        nscp->scsi_done(nscp);
+                        save_flags( flags );
+                        cli();
+                    } else {
+                        nscp->cmnd[3] = (ha->id[b][t].devtype&1) ? 1:0;
+                        TRACE2(("Prevent/allow r. %d rem. drive %d\n",
+                            nscp->cmnd[4],nscp->cmnd[3]));
+                        if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
+                            next_cmd = FALSE;
+                    }
+                    break;
+
+                  case READ_6:
+                  case WRITE_6:
+                  case READ_10:
+                  case WRITE_10:
+                    if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
+                        next_cmd = FALSE;
+                    break;
+
+                  default:
+                    TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                        nscp->cmnd[4],nscp->cmnd[5]));
+                    printk("GDT: Unknown SCSI command 0x%x to cache service !\n",
+                       nscp->cmnd[0]);
+                    nscp->result = DID_ABORT << 16;
+                    restore_flags( flags );
+                    nscp->scsi_done( nscp );
+                    save_flags( flags );
+                    cli();
+                    break;
+                }
+            }
+
+            if (!next_cmd)
+                break;
+            if (nscp == ha->req_first)
+                ha->req_first = pscp = (Scsi_Cmnd *)nscp->SCp.ptr;
+            else
+                pscp->SCp.ptr = nscp->SCp.ptr;
+            if (gdth_polling)
+                break;
+        }
+    }
+
+    if (ha->cmd_cnt > 0) {
+        gdth_release_event(hanum);
+    }
+
+    restore_flags(flags);
+
+    if (gdth_polling && ha->cmd_cnt > 0) {
+        if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+            printk("GDT: Controller %d: Command %d timed out !\n",
+                   hanum,cmd_index);
+    }
+}
+    
+static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count)
+{
+    ushort cpcount,i;
+    ushort cpsum,cpnow;
+    struct scatterlist *sl;
+
+    cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
+    if (scp->use_sg) {
+        sl = (struct scatterlist *)scp->request_buffer;
+        for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+            cpnow = (ushort)sl->length;
+            TRACE(("copy_internal() now %d sum %d count %d %d\n",
+                          cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+            if (cpsum+cpnow > cpcount) 
+                cpnow = cpcount - cpsum;
+            cpsum += cpnow;
+            memcpy((char*)sl->address,buffer,cpnow);
+            if (cpsum == cpcount)
+                break;
+            buffer += cpnow;
+        }
+    } else {
+        TRACE(("copy_internal() count %d\n",cpcount));
+        memcpy((char*)scp->request_buffer,buffer,cpcount);
+    }
+}
+
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
+                                   unchar b,ulong *flags)
+{
+    register gdth_ha_str *ha;
+    ushort hdrive;
+    unchar t;
+    gdth_inq_data inq;
+    gdth_rdcap_data rdc;
+    gdth_sense_data sd;
+    gdth_modep_data mpd;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    t  = scp->target;
+    hdrive = ha->id[b][t].hostdrive;
+    TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
+                 scp->cmnd[0],hdrive));
+
+    if (scp->lun !=0)
+        scp->result = DID_BAD_TARGET << 16;
+    else {
+        switch (scp->cmnd[0]) {
+          case TEST_UNIT_READY:
+          case VERIFY:
+          case START_STOP:
+            TRACE2(("Test/Verify/Start hdrive %d\n",hdrive));
+            break;
+
+          case INQUIRY:
+            TRACE2(("Inquiry hdrive %d devtype %d\n",
+                          hdrive,ha->id[b][t].devtype));
+            inq.type_qual = (ha->id[b][t].devtype&4) ? TYPE_ROM:TYPE_DISK;
+            /* you can here set all disks to removable, if you want to do
+               a flush using the ALLOW_MEDIUM_REMOVAL command */
+            inq.modif_rmb = ha->id[b][t].devtype&1 ? 0x80:0x00;
+            inq.version   = 2;
+            inq.resp_aenc = 2;
+            inq.add_length= 32;
+            strcpy(inq.vendor,"ICP    ");
+            sprintf(inq.product,"Host Drive  #%02d",hdrive);
+            strcpy(inq.revision,"   ");
+            gdth_copy_internal_data(scp,(char*)&inq,sizeof(gdth_inq_data));
+            break;
+
+          case REQUEST_SENSE:
+            TRACE2(("Request sense hdrive %d\n",hdrive));
+            sd.errorcode = 0x70;
+            sd.segno     = 0x00;
+            sd.key       = NO_SENSE;
+            sd.info      = 0;
+            sd.add_length= 0;
+            gdth_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data));
+            break;
+
+          case MODE_SENSE:
+            TRACE2(("Mode sense hdrive %d\n",hdrive));
+            memset((char*)&mpd,0,sizeof(gdth_modep_data));
+            mpd.hd.data_length = sizeof(gdth_modep_data);
+            mpd.hd.dev_par     = (ha->id[b][t].devtype&2) ? 0x80:0;
+            mpd.hd.bd_length   = sizeof(mpd.bd);
+            mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
+            mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
+            mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
+            gdth_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data));
+            break;
+
+          case READ_CAPACITY:
+            TRACE2(("Read capacity hdrive %d\n",hdrive));
+            rdc.last_block_no = ntohl(ha->id[b][t].size-1);
+            rdc.block_length  = ntohl(SECTOR_SIZE);
+            gdth_copy_internal_data(scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+            break;
+
+          default:
+            TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
+            break;
+        }
+        scp->result = DID_OK << 16;
+    }
+
+    restore_flags(*flags);
+    scp->scsi_done(scp);
+    save_flags(*flags);
+    cli();
+    return 1;
+}
+    
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    struct scatterlist *sl;
+    ushort i;
+    int cmd_index;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cmdp = ha->pccb;
+    TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
+                 scp->cmnd[0],scp->cmd_len,hdrive));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    cmdp->Service = CACHESERVICE;
+    cmdp->RequestBuffer = scp;
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+        gdth_set_sema0(hanum);
+
+    /* fill command */
+    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+        if (scp->cmnd[4] & 1)                   /* prevent ? */
+            cmdp->OpCode      = GDT_MOUNT;
+        else if (scp->cmnd[3] & 1)              /* removable drive ? */
+            cmdp->OpCode      = GDT_UNMOUNT;
+        else
+            cmdp->OpCode      = GDT_FLUSH;
+    } else {
+        if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
+            if (gdth_write_through)
+                cmdp->OpCode  = GDT_WRITE_THR;
+            else
+                cmdp->OpCode  = GDT_WRITE;
+        } else {
+            cmdp->OpCode      = GDT_READ;
+        }
+    }
+
+    cmdp->BoardNode           = LOCALBOARD;
+    cmdp->u.cache.DeviceNo    = hdrive;
+
+    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+        cmdp->u.cache.BlockNo = 1;
+        cmdp->u.cache.sg_canz = 0;
+    } else {
+        if (scp->cmd_len != 6) {
+            cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[2]);
+            cmdp->u.cache.BlockCnt= (ulong)ntohs(*(ushort*)&scp->cmnd[7]);
+        } else {
+            cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[0]) & 0x001fffffUL;
+            cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+        }
+
+        if (scp->use_sg) {
+            cmdp->u.cache.DestAddr= -1UL;
+            sl = (struct scatterlist *)scp->request_buffer;
+            for (i=0; i<scp->use_sg; ++i,++sl) {
+                cmdp->u.cache.sg_lst[i].sg_ptr = (ulong)sl->address;
+                cmdp->u.cache.sg_lst[i].sg_len = (ulong)sl->length;
+            }
+            cmdp->u.cache.sg_canz = (ulong)i;
+
+#ifdef GDTH_STATISTICS
+            if (max_sg < (ulong)i) {
+                max_sg = (ulong)i;
+                TRACE3(("GDT: max_sg = %d\n",i));
+            }
+#endif
+            if (i<GDTH_MAXSG)
+                cmdp->u.cache.sg_lst[i].sg_len = 0;
+        } else {
+            if (ha->cache_feat & SCATTER_GATHER) {
+                cmdp->u.cache.DestAddr = -1UL;
+                cmdp->u.cache.sg_canz = 1;
+                cmdp->u.cache.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+                cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
+                cmdp->u.cache.sg_lst[1].sg_len = 0;
+            } else {
+                cmdp->u.cache.DestAddr  = (ulong)scp->request_buffer;
+                cmdp->u.cache.sg_canz= 0;
+            }
+        }
+    }
+    TRACE(("cache cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
+                  cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
+                  cmdp->u.cache.sg_lst[0].sg_ptr,
+                  cmdp->u.cache.sg_lst[0].sg_len));
+    TRACE(("cache cmd: cmd %d blockno. %ld, blockcnt %ld\n",
+                  cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
+
+    /* evaluate command size, check space */
+    ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
+        (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_fill_cache() DPMEM overflow\n"));
+            gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}
+
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    struct scatterlist *sl;
+    ushort i;
+    int cmd_index;
+    unchar t,l;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    t = scp->target;
+    l = scp->lun;
+    cmdp = ha->pccb;
+    TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n",
+                 scp->cmnd[0],b,t,l));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    cmdp->Service = SCSIRAWSERVICE;
+    cmdp->RequestBuffer = scp;
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+        gdth_set_sema0(hanum);
+
+    /* fill command */  
+    cmdp->OpCode           = GDT_WRITE;         /* always */
+    cmdp->BoardNode        = LOCALBOARD;
+    cmdp->u.raw.reserved   = 0;
+    cmdp->u.raw.mdisc_time = 0;
+    cmdp->u.raw.mcon_time  = 0;
+    cmdp->u.raw.clen       = scp->cmd_len;
+    cmdp->u.raw.target     = t;
+    cmdp->u.raw.lun        = l;
+    cmdp->u.raw.bus        = b;
+    cmdp->u.raw.priority   = 0;
+    cmdp->u.raw.link_p     = NULL;
+    cmdp->u.raw.sdlen      = scp->request_bufflen;
+    cmdp->u.raw.sense_len  = 16;
+    cmdp->u.raw.sense_data = (ulong)scp->sense_buffer;
+    cmdp->u.raw.direction  = 
+        gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
+    memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+
+    if (scp->use_sg) {
+        cmdp->u.raw.sdata  = -1UL;
+        sl = (struct scatterlist *)scp->request_buffer;
+        for (i=0; i<scp->use_sg; ++i,++sl) {
+            cmdp->u.raw.sg_lst[i].sg_ptr = (ulong)sl->address;
+            cmdp->u.raw.sg_lst[i].sg_len = (ulong)sl->length;
+        }
+        cmdp->u.raw.sg_ranz = (ulong)i;
+
+#ifdef GDTH_STATISTICS
+        if (max_sg < (ulong)i) {
+            max_sg = (ulong)i;
+            TRACE3(("GDT: max_sg = %d\n",i));
+        }
+#endif
+        if (i<GDTH_MAXSG)
+            cmdp->u.raw.sg_lst[i].sg_len = 0;
+    } else {
+        if (ha->raw_feat & SCATTER_GATHER) {
+            cmdp->u.raw.sdata  = -1UL;
+            cmdp->u.raw.sg_ranz= 1;
+            cmdp->u.raw.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+            cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
+            cmdp->u.raw.sg_lst[1].sg_len = 0;
+        } else {
+            cmdp->u.raw.sdata  = (ulong)scp->request_buffer;
+            cmdp->u.raw.sg_ranz= 0;
+        }
+    }
+    TRACE(("raw cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
+                  cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
+                  cmdp->u.raw.sg_lst[0].sg_ptr,
+                  cmdp->u.raw.sg_lst[0].sg_len));
+
+    /* evaluate command size, check space */
+    ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
+        (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_fill_raw() DPMEM overflow\n"));
+            gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}
+
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    int cmd_index;
+
+    ha  = HADATA(gdth_ctr_tab[hanum]);
+    cmdp= ha->pccb;
+    TRACE2(("gdth_special_cmd(): "));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+    cmdp->RequestBuffer = scp;
+
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+       gdth_set_sema0(hanum);
+
+    /* evaluate command size, check space */
+    if (cmdp->OpCode == GDT_IOCTL) {
+        TRACE2(("IOCTL\n"));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong);
+    } else if (cmdp->Service == CACHESERVICE) {
+        TRACE2(("cache command %d\n",cmdp->OpCode));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
+    } else if (cmdp->Service == SCSIRAWSERVICE) {
+        TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0]));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
+    }
+
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_special_cmd() DPMEM overflow\n"));
+            gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}    
+
+
+/* Controller event handling functions */
+static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
+                                      gdth_evt_data *evt)
+{
+    gdth_evt_str *e;
+    ulong flags;
+    struct timeval tv;
+
+    TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
+    if (source == 0)                        /* no source -> no event */
+        return 0;
+
+    save_flags(flags);
+    cli();
+    if (ebuffer[elastidx].event_source == source &&
+        ebuffer[elastidx].event_idx == idx &&
+        !memcmp((char *)&ebuffer[elastidx].event_data.eu,
+            (char *)&evt->eu, evt->size)) {
+        e = &ebuffer[elastidx];
+        do_gettimeofday(&tv);
+        e->last_stamp = tv.tv_sec;
+        ++e->same_count;
+    } else {
+        if (ebuffer[elastidx].event_source != 0) {  /* entry not free ? */
+            ++elastidx;
+            if (elastidx == MAX_EVENTS)
+                elastidx = 0;
+            if (elastidx == eoldidx) {              /* reached mark ? */
+                ++eoldidx;
+                if (eoldidx == MAX_EVENTS)
+                    eoldidx = 0;
+            }
+        }
+        e = &ebuffer[elastidx];
+        e->event_source = source;
+        e->event_idx = idx;
+        do_gettimeofday(&tv);
+        e->first_stamp = e->last_stamp = tv.tv_sec;
+        e->same_count = 1;
+        e->event_data = *evt;
+    }
+    restore_flags(flags);
+    return e;
+}
+
+static int gdth_read_event(int handle, gdth_evt_str *estr)
+{
+    gdth_evt_str *e;
+    int eindex;
+    ulong flags;
+
+    TRACE2(("gdth_read_event() handle %d\n", handle));
+    save_flags(flags);
+    cli();
+    if (handle == -1)
+        eindex = eoldidx;
+    else
+        eindex = handle;
+    estr->event_source = 0;
+
+    if (eindex >= MAX_EVENTS) {
+        restore_flags(flags);
+        return eindex;
+    }
+    e = &ebuffer[eindex];
+    if (e->event_source != 0) {
+        if (eindex != elastidx) {
+            if (++eindex == MAX_EVENTS)
+                eindex = 0;
+        } else {
+            eindex = -1;
+        }
+        memcpy(estr, e, sizeof(gdth_evt_str));
+    }
+    restore_flags(flags);
+    return eindex;
+}
+
+static void gdth_readapp_event(unchar application, gdth_evt_str *estr)
+{
+    gdth_evt_str *e;
+    int eindex;
+    ulong flags;
+    unchar found = FALSE;
+
+    TRACE2(("gdth_readapp_event() app. %d\n", application));
+    save_flags(flags);
+    cli();
+    eindex = eoldidx;
+    for (;;) {
+        e = &ebuffer[eindex];
+        if (e->event_source == 0)
+            break;
+        if ((e->application & application) == 0) {
+            e->application |= application;
+            found = TRUE;
+            break;
+        }
+        if (eindex == elastidx)
+            break;
+        if (++eindex == MAX_EVENTS)
+            eindex = 0;
+    }
+    if (found)
+        memcpy(estr, e, sizeof(gdth_evt_str));
+    else
+        estr->event_source = 0;
+    restore_flags(flags);
+}
+
+static void gdth_clear_events()
+{
+    ulong flags;
+
+    TRACE(("gdth_clear_events()"));
+    save_flags(flags);
+    cli();
+
+    eoldidx = elastidx = 0;
+    ebuffer[0].event_source = 0;
+    restore_flags(flags);
+}
+
+
+/* SCSI interface functions */
+
+#if LINUX_VERSION_CODE >= 0x010346
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs)
+#endif
+{
+    register gdth_ha_str *ha;
+    gdt6m_dpram_str *dp6m_ptr;
+    gdt6_dpram_str *dp6_ptr;
+    gdt2_dpram_str *dp2_ptr;
+    Scsi_Cmnd *scp;
+    int hanum;
+    unchar IStatus;
+    ushort CmdStatus, Service = 0;
+    ulong InfoBytes, InfoBytes2 = 0;
+    gdth_evt_data dvr;
+
+    TRACE(("gdth_interrupt() IRQ %d\n",irq));
+
+    /* if polling and not from gdth_wait() -> return */
+    if (gdth_polling) {
+        if (!gdth_from_wait) {
+            return;
+        }
+    }
+
+    wait_index = 0;
+
+    /* search controller */
+    if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+        /*
+        TRACE2(("gdth_interrupt(): Spurious interrupt received\n"));
+        */
+        return;
+    }
+
+#ifdef GDTH_STATISTICS
+    ++act_ints;
+#endif
+    
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (ha->type == GDT_EISA) {
+        if (IStatus & 0x80) {                   /* error flag */
+            IStatus &= ~0x80;
+            CmdStatus = inw((ushort)ha->brd+MAILBOXREG+8);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+            if (IStatus == ASYNCINDEX) {        /* async. event ? */
+                Service = inw((ushort)ha->brd+MAILBOXREG+10);
+                InfoBytes2 = inl((ushort)ha->brd+MAILBOXREG+4);
+            }
+        } else                                  /* no error */
+            CmdStatus = S_OK;
+        InfoBytes = inl((ushort)ha->brd+MAILBOXREG+12);
+        outb(0xff,(ushort)ha->brd+EDOORREG);    /* acknowledge interrupt */
+        outb(0x00,(ushort)ha->brd+SEMA1REG);    /* reset status semaphore */
+    } else if (ha->type == GDT_ISA) {
+        dp2_ptr = (gdt2_dpram_str *)ha->brd;
+        if (IStatus & 0x80) {                   /* error flag */
+            IStatus &= ~0x80;
+            CmdStatus = dp2_ptr->u.ic.Status;
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+            if (IStatus == ASYNCINDEX) {        /* async. event ? */
+                Service = dp2_ptr->u.ic.Service;
+                InfoBytes2 = dp2_ptr->u.ic.Info[1];
+            }
+        } else                                  /* no error */
+            CmdStatus = S_OK;
+        InfoBytes = dp2_ptr->u.ic.Info[0];
+        dp2_ptr->io.irqdel = 0xff;              /* acknowledge interrupt */
+        dp2_ptr->u.ic.Cmd_Index = 0;            /* reset command index */
+        dp2_ptr->io.Sema1  = 0;                 /* reset status semaphore */
+    } else if (ha->type == GDT_PCI) {
+        dp6_ptr = (gdt6_dpram_str *)ha->brd;
+        if (IStatus & 0x80) {                   /* error flag */
+            IStatus &= ~0x80;
+            CmdStatus = dp6_ptr->u.ic.Status;
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+            if (IStatus == ASYNCINDEX) {        /* async. event ? */
+                Service = dp6_ptr->u.ic.Service;
+                InfoBytes2 = dp6_ptr->u.ic.Info[1];
+            }
+        } else                                  /* no error */
+            CmdStatus = S_OK;
+        InfoBytes = dp6_ptr->u.ic.Info[0];
+        dp6_ptr->io.irqdel = 0xff;              /* acknowledge interrupt */
+        dp6_ptr->u.ic.Cmd_Index = 0;            /* reset command index */
+        dp6_ptr->io.Sema1  = 0;                 /* reset status semaphore */
+    } else if (ha->type == GDT_PCINEW) {
+        if (IStatus & 0x80) {                   /* error flag */
+            IStatus &= ~0x80;
+            CmdStatus = inw(PTR2USHORT(&ha->plx->status));
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+            if (IStatus == ASYNCINDEX) {        /* async. event ? */
+                Service = inw(PTR2USHORT(&ha->plx->service));
+                InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
+            }
+        } else
+            CmdStatus = S_OK;
+
+        InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
+        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); 
+        outb(0x00,PTR2USHORT(&ha->plx->sema1_reg)); 
+    } else if (ha->type == GDT_PCIMPR) {
+        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+        if (IStatus & 0x80) {                   /* error flag */
+            IStatus &= ~0x80;
+            CmdStatus = dp6m_ptr->i960r.status;
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+            if (IStatus == ASYNCINDEX) {        /* async. event ? */
+                Service = dp6m_ptr->i960r.service;
+                InfoBytes2 = dp6m_ptr->i960r.info[1];
+            }
+        } else                                  /* no error */
+            CmdStatus = S_OK;
+        InfoBytes = dp6m_ptr->i960r.info[0];
+        dp6m_ptr->i960r.edoor_reg = 0xff;
+        dp6m_ptr->i960r.sema1_reg = 0;
+    } else {
+        TRACE2(("gdth_interrupt() unknown controller type\n"));
+        return;
+    }
+
+    TRACE(("gdth_interrupt() index %d stat %d info %ld\n",
+                 IStatus,CmdStatus,InfoBytes));
+    ha->status = CmdStatus;
+    ha->info   = InfoBytes;
+    ha->info2  = InfoBytes2;
+
+    if (gdth_from_wait) {
+        wait_hanum = hanum;
+        wait_index = (int)IStatus;
+    }
+
+    if (IStatus == ASYNCINDEX) {
+        TRACE2(("gdth_interrupt() async. event\n"));
+        gdth_async_event(hanum,Service);
+    } else {
+        if (IStatus == SPEZINDEX) {
+            TRACE2(("Service unknown or not initialized !\n"));
+            dvr.size = sizeof(dvr.eu.driver);
+            dvr.eu.driver.ionode = hanum;
+            gdth_store_event(ES_DRIVER, 4, &dvr);
+            return;
+        }
+        scp     = gdth_cmd_tab[IStatus-2][hanum].cmnd;
+        Service = gdth_cmd_tab[IStatus-2][hanum].service;
+        gdth_cmd_tab[IStatus-2][hanum].cmnd = UNUSED_CMND;
+        if (scp == UNUSED_CMND) {
+            TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
+            dvr.size = sizeof(dvr.eu.driver);
+            dvr.eu.driver.ionode = hanum;
+            dvr.eu.driver.index = IStatus;
+            gdth_store_event(ES_DRIVER, 1, &dvr);
+            return;
+        }
+        if (scp == INTERNAL_CMND) {
+            TRACE(("gdth_interrupt() answer to internal command\n"));
+            return;
+        }
+        TRACE(("gdth_interrupt() sync. status\n"));
+        gdth_sync_event(hanum,Service,IStatus,scp);
+    }
+    gdth_next(hanum);
+}
+
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+{
+    register gdth_ha_str *ha;
+    gdth_msg_str *msg;
+    gdth_cmd_str *cmdp;
+    char c='\r';
+    ushort i;
+    gdth_evt_data dvr;
+
+    ha   = HADATA(gdth_ctr_tab[hanum]);
+    cmdp = ha->pccb;
+    TRACE(("gdth_sync_event() scp %lx serv %d status %d\n",
+                 (ulong)scp,service,ha->status));
+
+    if (service == SCREENSERVICE) {
+        msg  = (gdth_msg_str *)ha->pscratch;
+        TRACE(("len: %ld, answer: %d, ext: %d, alen: %ld\n",
+                     msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
+        if (msg->msg_len)
+            if (!(msg->msg_answer && msg->msg_ext)) {
+                msg->msg_text[msg->msg_len] = '\0';
+                printk("%s",msg->msg_text);
+            }
+
+        if (msg->msg_ext && !msg->msg_answer) {
+            while (gdth_test_busy(hanum))
+                udelay(1);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_READ;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.msg_handle= msg->msg_handle;
+            cmdp->u.screen.msg_addr  = (ulong)msg;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+                + sizeof(ulong);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            gdth_release_event(hanum);
+            return 1;
+        }
+
+        if (msg->msg_answer && msg->msg_alen) {
+            for (i=0; i<msg->msg_alen && i<MSGLEN; ++i) {
+                /* getchar() ?? */           
+                /* .. */
+                if (c == '\r')
+                    break;
+                msg->msg_text[i] = c; 
+            }
+            msg->msg_alen -= i;
+            if (c!='\r' && msg->msg_alen!=0) {
+                msg->msg_answer = 1;
+                msg->msg_ext    = 1;
+            } else {
+                msg->msg_ext    = 0;
+                msg->msg_answer = 0;
+            }
+            msg->msg_len = i;
+            while (gdth_test_busy(hanum))
+                udelay(1);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_WRITE;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.msg_handle= msg->msg_handle;
+            cmdp->u.screen.msg_addr  = (ulong)msg;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+                + sizeof(ulong);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            gdth_release_event(hanum);
+            return 1;
+        }
+        printk("\n");
+
+    } else {
+        scp->SCp.Message = (int)ha->status;
+        /* cache or raw service */
+        if (ha->status == S_OK) {
+            scp->result = DID_OK << 16;
+        } else if (ha->status == S_BSY) {
+            TRACE2(("Controller busy -> retry !\n"));
+            gdth_putq(hanum,scp,DEFAULT_PRI);
+            return 1;
+        } else {
+            if (service == CACHESERVICE) {
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+
+                if (scp->done != gdth_scsi_done) {
+                    dvr.size = sizeof(dvr.eu.sync);
+                    dvr.eu.sync.ionode  = hanum;
+                    dvr.eu.sync.service = service;
+                    dvr.eu.sync.status  = ha->status;
+                    dvr.eu.sync.info    = ha->info;
+                    dvr.eu.sync.hostdrive =
+#if LINUX_VERSION_CODE >= 0x010400
+                        ha->id[scp->channel][scp->target].hostdrive;
+#else
+                        ha->id[NUMDATA(scp->host)->busnum][scp->target].hostdrive;
+#endif
+                    if (ha->status >= 0x8000)
+                        gdth_store_event(ES_SYNC, 0, &dvr);
+                    else
+                        gdth_store_event(ES_SYNC, service, &dvr);
+                }
+            } else {
+                if (ha->status!=S_RAW_SCSI || ha->status==S_RAW_ILL) {
+                    scp->result = DID_BAD_TARGET << 16;
+                } else {
+                    scp->result = (DID_OK << 16) | ha->info;
+                }
+            }
+        }
+        scp->SCp.have_data_in++;
+        scp->scsi_done(scp);
+    }
+
+    return 1;
+}
+
+static char *async_cache_tab[] = {
+/* 0*/  "\011\000\002\002\002\004\002\006\004"
+        "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 1*/  "\011\000\002\002\002\004\002\006\004"
+        "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 2*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu not ready",
+/* 3*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 4*/  "\005\000\002\006\004"
+        "GDT HA %u, mirror update on Host Drive %lu failed",
+/* 5*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu failed",
+/* 6*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 7*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu write protected",
+/* 8*/  "\005\000\002\006\004"
+        "GDT HA %u, media changed in Host Drive %lu",
+/* 9*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu is offline",
+/*10*/  "\005\000\002\006\004"
+        "GDT HA %u, media change of Mirror Drive %lu",
+/*11*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu is write protected",
+/*12*/  "\005\000\002\006\004"
+        "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!",
+/*13*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: Cache Drive %u failed",
+/*14*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: FAIL state entered",
+/*15*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: error",
+/*16*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u",
+/*17*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity build failed",
+/*18*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild failed",
+/*19*/  "\007\000\002\010\002"
+        "GDT HA %u, Test of Hot Fix %u failed",
+/*20*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive build finished successfully",
+/*21*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild finished successfully",
+/*22*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: Hot Fix %u activated",
+/*23*/  "\005\000\002\006\002"
+        "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error",
+/*24*/  "\005\000\002\010\002"
+        "GDT HA %u, mirror update on Cache Drive %u completed",
+/*25*/  "\005\000\002\010\002"
+        "GDT HA %u, mirror update on Cache Drive %lu failed",
+/*26*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild started",
+/*27*/  "\005\000\002\012\001"
+        "GDT HA %u, Fault bus %u: SHELF OK detected",
+/*28*/  "\005\000\002\012\001"
+        "GDT HA %u, Fault bus %u: SHELF not OK detected",
+/*29*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started",
+/*30*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: new disk detected",
+/*31*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: old disk detected",
+/*32*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is illegal",
+/*33*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: illegal device detected",
+/*34*/  "\011\000\002\012\001\013\001\006\004"
+        "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)",
+/*35*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: disk write protected",
+/*36*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: disk not available",
+/*37*/  "\007\000\002\012\001\006\004"
+        "GDT HA %u, Fault bus %u: swap detected (%lu)",
+/*38*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully",
+/*39*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug",
+/*40*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted",
+/*41*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started",
+/*42*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive build started",
+/*43*/  "\003\000\002"
+        "GDT HA %u, DRAM parity error detected",
+/*44*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: update started",
+/*45*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Mirror Drive %u: Hot Fix %u activated",
+/*46*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available",
+/*47*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available",
+/*48*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available",
+/*49*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available",
+/*50*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received",
+/*51*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand started",
+/*52*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand finished successfully",
+/*53*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand failed",
+/*54*/  "\003\000\002"
+        "GDT HA %u, CPU temperature critical",
+/*55*/  "\003\000\002"
+        "GDT HA %u, CPU temperature OK",
+};
+
+
+static int gdth_async_event(int hanum,int service)
+{
+    gdth_stackframe stack;
+    gdth_evt_data dvr;
+    char *f = NULL;
+    int i,j;
+    gdth_ha_str *ha;
+    gdth_msg_str *msg;
+    gdth_cmd_str *cmdp;
+    int cmd_index;
+
+    ha  = HADATA(gdth_ctr_tab[hanum]);
+    cmdp= ha->pccb;
+    msg = (gdth_msg_str *)ha->pscratch;
+    TRACE2(("gdth_async_event() ha %d serv %d\n",
+                 hanum,service));
+
+    if (service == SCREENSERVICE) {
+        if (ha->status == MSG_REQUEST) {
+            while (gdth_test_busy(hanum))
+                udelay(1);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            cmd_index = gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_READ;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.msg_handle= MSG_INV_HANDLE;
+            cmdp->u.screen.msg_addr  = (ulong)msg;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+                + sizeof(ulong);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            if (ha->type == GDT_EISA)
+                printk("[EISA slot %d] ",(ushort)ha->brd_phys);
+            else if (ha->type == GDT_ISA)
+                printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys);
+            else 
+                printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
+                       (ushort)((ha->brd_phys>>3)&0x1f));
+            gdth_release_event(hanum);
+        }
+
+    } else {
+        dvr.size = sizeof(dvr.eu.async);
+        dvr.eu.async.ionode   = hanum;
+        dvr.eu.async.service = service;
+        dvr.eu.async.status  = ha->status;
+        dvr.eu.async.info    = ha->info;
+        *(ulong *)dvr.eu.async.scsi_coord  = ha->info2;
+        gdth_store_event(ES_ASYNC, service, &dvr);
+
+        if (service==CACHESERVICE && INDEX_OK(ha->status,async_cache_tab)) {
+            TRACE2(("GDT: Async. event cache service, event no.: %d\n",
+                ha->status));
+        
+            f = async_cache_tab[ha->status];
+
+            /* i: parameter to push, j: stack element to fill */
+            for (j=0,i=1; i < f[0]; i+=2) {
+                switch (f[i+1]) {
+                  case 4:
+                    stack.b[j++] = *(ulong*)&dvr.eu.stream[(int)f[i]];
+                    break;
+                  case 2:
+                    stack.b[j++] = *(ushort*)&dvr.eu.stream[(int)f[i]];
+                    break;
+                  case 1:
+                    stack.b[j++] = *(unchar*)&dvr.eu.stream[(int)f[i]];
+                    break;
+                  default:
+                    break;
+                }
+            }
+
+            printk(&f[f[0]],stack); printk("\n");
+
+        } else {
+            printk("GDT: Unknown async. event service %d event no. %d\n",
+                service,ha->status);
+        }
+    }
+    return 1;
+}
+
+#ifdef GDTH_STATISTICS
+void gdth_timeout(void)
+{
+    ulong flags,i;
+    Scsi_Cmnd *nscp;
+    gdth_ha_str *ha;
+    int hanum = 0;
+
+    save_flags(flags);
+    cli();
+
+    for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) 
+        if (gdth_cmd_tab[i][hanum].cmnd != UNUSED_CMND)
+            ++act_stats;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    for (act_rq=0,nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+        ++act_rq;
+
+    TRACE2(("gdth_to(): ints %ld, ios %ld, act_stats %ld, act_rq %ld\n",
+            act_ints, act_ios, act_stats, act_rq));
+    act_ints = act_ios = 0;
+
+    timer_table[GDTH_TIMER].expires = jiffies + 30*HZ;
+    timer_active |= 1<<GDTH_TIMER;
+    sti();
+}
+#endif
+
+int gdth_detect(Scsi_Host_Template *shtp)
+{
+    struct Scsi_Host *shp;
+    gdth_ha_str *ha;
+    unsigned long flags;
+    ulong isa_bios;
+    ushort eisa_slot,device_id,index;
+    gdth_pci_str pcistr;
+    int i,j,hanum;
+    unchar b;
+    
+ 
+#ifdef DEBUG_GDTH
+    printk("GDT: This driver contains debugging information !! Trace level = %d\n",
+        DebugState);
+    printk("     Destination of debugging information: ");
+#ifdef __SERIAL__
+#ifdef __COM2__
+    printk("Serial port COM2\n");
+#else
+    printk("Serial port COM1\n");
+#endif
+#else
+    printk("Console\n");
+#endif
+    WAITSEC(3);
+#endif
+
+    TRACE(("gdth_detect()\n"));
+
+    if (disable_gdth_scan) {
+        printk("GDT: Controller driver disabled from command line !\n");
+        return 0;
+    }
+
+    /* initializations */
+    gdth_polling = TRUE; b = 0;
+    for (i=0; i<GDTH_MAXCMDS; ++i)
+        for (j=0; j<MAXHA; ++j)
+            gdth_cmd_tab[i][j].cmnd = UNUSED_CMND;
+    for (i=0; i<4; ++i)
+        for (j=0; j<MAXHA; ++j)
+            gdth_ioctl_tab[i][j] = NULL;
+    gdth_clear_events();
+
+    /* scanning for controllers, at first: ISA controller */
+    for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
+        if (gdth_search_isa(isa_bios)) {        /* controller found */
+            shp = scsi_register(shtp,sizeof(gdth_ext_str));
+            ha = HADATA(shp);
+            if (!gdth_init_isa(isa_bios,ha,TRUE)) {
+                scsi_unregister(shp);
+                continue;
+            }
+            /* controller found and initialized */
+            printk("Configuring GDT-ISA HA at BIOS 0x%05lX IRQ %u DRQ %u\n",
+                   isa_bios,ha->irq,ha->drq);
+
+            save_flags(flags);
+            cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+#endif
+            {
+                printk("GDT-ISA: Unable to allocate IRQ\n");
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+            if (request_dma(ha->drq,"gdth")) {
+                printk("GDT-ISA: Unable to allocate DMA channel\n");
+#if LINUX_VERSION_CODE >= 0x010346 
+                free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+            set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+            enable_dma(ha->drq);
+            shp->unchecked_isa_dma = 1;
+            shp->irq = ha->irq;
+            shp->dma_channel = ha->drq;
+            for (i=0; i<MAXID; ++i) {
+                if (ha->id[0][i].type==SIOP_DTYP) {
+                    shp->this_id = i;
+                    break;
+                }
+            }
+            hanum = gdth_ctr_count;         
+            gdth_ctr_tab[gdth_ctr_count++] = shp;
+            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+            NUMDATA(shp)->hanum = (ushort)hanum;
+            NUMDATA(shp)->busnum= 0;
+
+            ha->pccb = CMDDATA(shp);
+            ha->pscratch = DMADATA(shp);
+            ha->req_first = NULL;
+            for (i=0; i<MAXBUS; ++i) {
+                for (j=0; j<MAXID; ++j) {
+                    ha->id[i][j].type = EMPTY_DTYP;
+                    ha->id[i][j].lock = 0;
+                }
+            }
+            restore_flags(flags);
+
+            if (!gdth_search_drives(hanum,TRUE)) {
+                printk("GDT-ISA: Error during device scan\n");
+                --gdth_ctr_count;
+                save_flags(flags);
+                cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+                free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+
+#if LINUX_VERSION_CODE >= 0x010400
+            shp->max_id      = 8;
+            shp->max_lun     = 8;
+            shp->max_channel = ha->bus_cnt - 1;
+#else
+            /* register addit. SCSI channels as virtual controllers */
+            for (b=1; b<ha->bus_cnt; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 1;
+                shp->irq = ha->irq;
+                shp->dma_channel = ha->drq;
+                for (i=0; i<MAXID; ++i) {
+                    if (ha->id[b][i].type==SIOP_DTYP) {
+                        shp->this_id = i;
+                        break;
+                    }
+                }
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
+            }
+#endif
+
+            gdth_enable_int(hanum);
+        }
+    }
+
+    /* scanning for EISA controllers */
+    for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
+        if (gdth_search_eisa(eisa_slot)) {      /* controller found */
+            shp = scsi_register(shtp,sizeof(gdth_ext_str));
+            ha = HADATA(shp);
+            if (!gdth_init_eisa(eisa_slot,ha,TRUE)) {
+                scsi_unregister(shp);
+                continue;
+            }
+            /* controller found and initialized */
+            printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+                   eisa_slot>>12,ha->irq);
+
+            save_flags(flags);
+            cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+#endif
+            {
+                printk("GDT-EISA: Unable to allocate IRQ\n");
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+            shp->unchecked_isa_dma = 0;
+            shp->irq = ha->irq;
+            shp->dma_channel = 0xff;
+            for (i=0; i<MAXID; ++i) {
+                if (ha->id[0][i].type==SIOP_DTYP) {
+                    shp->this_id = i;
+                    break;
+                }
+            }
+            hanum = gdth_ctr_count;
+            gdth_ctr_tab[gdth_ctr_count++] = shp;
+            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+            NUMDATA(shp)->hanum = (ushort)hanum;
+            NUMDATA(shp)->busnum= 0;
+            TRACE2(("EISA detect Bus 0: shp %lx hanum %d\n",
+                          (ulong)shp,NUMDATA(shp)->hanum));
+
+            ha->pccb = CMDDATA(shp);
+            ha->pscratch = DMADATA(shp);
+            ha->req_first = NULL;
+            for (i=0; i<MAXBUS; ++i) {
+                for (j=0; j<MAXID; ++j) {
+                    ha->id[i][j].type = EMPTY_DTYP;
+                    ha->id[i][j].lock = 0;
+                }
+            }
+            restore_flags(flags);
+
+            if (!gdth_search_drives(hanum,TRUE)) {
+                printk("GDT-EISA: Error during device scan\n");
+                --gdth_ctr_count;
+                save_flags(flags);
+                cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+                free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+
+#if LINUX_VERSION_CODE >= 0x010400
+            shp->max_id      = 8;
+            shp->max_lun     = 8;
+            shp->max_channel = ha->bus_cnt - 1;
+#else
+            /* register addit. SCSI channels as virtual controllers */
+            for (b=1; b<ha->bus_cnt; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                for (i=0; i<MAXID; ++i) {
+                    if (ha->id[b][i].type==SIOP_DTYP) {
+                        shp->this_id = i;
+                        break;
+                    }
+                }
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
+                TRACE2(("EISA detect Bus %d: shp %lx hanum %d\n",
+                              NUMDATA(shp)->busnum,(ulong)shp,
+                              NUMDATA(shp)->hanum));
+            }
+#endif
+
+            gdth_enable_int(hanum);
+        }
+    }
+
+    /* scanning for PCI controllers */
+    for (device_id = 0; device_id <= PCI_DEVICE_ID_VORTEX_GDT6x21RP2; ++device_id) {
+        if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
+            device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
+            continue;
+        for (index = 0; ; ++index) {
+            if (!gdth_search_pci(device_id,index,&pcistr)) 
+                break;                          /* next device_id */
+            shp = scsi_register(shtp,sizeof(gdth_ext_str));
+            ha = HADATA(shp);
+            if (!gdth_init_pci(&pcistr,ha,TRUE)) {
+                scsi_unregister(shp);
+                continue;
+            }
+            /* controller found and initialized */
+            printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+                   pcistr.bus,pcistr.device_fn>>3,ha->irq);
+
+            save_flags(flags);
+            cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+#endif
+            {
+                printk("GDT-PCI: Unable to allocate IRQ\n");
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+            shp->unchecked_isa_dma = 0;
+            shp->irq = ha->irq;
+            shp->dma_channel = 0xff;
+            for (i=0; i<MAXID; ++i) {
+                if (ha->id[0][i].type==SIOP_DTYP) {
+                    shp->this_id = i;
+                    break;
+                }
+            }
+            hanum = gdth_ctr_count;
+            gdth_ctr_tab[gdth_ctr_count++] = shp;
+            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+            NUMDATA(shp)->hanum = (ushort)hanum;
+            NUMDATA(shp)->busnum= 0;
+
+            ha->pccb = CMDDATA(shp);
+            ha->pscratch = DMADATA(shp);
+            ha->req_first = NULL;
+            for (i=0; i<MAXBUS; ++i) {
+                for (j=0; j<MAXID; ++j) {
+                    ha->id[i][j].type = EMPTY_DTYP;
+                    ha->id[i][j].lock = 0;
+                }
+            }
+            restore_flags(flags);
+
+            if (!gdth_search_drives(hanum,TRUE)) {
+                printk("GDT-PCI: Error during device scan\n");
+                --gdth_ctr_count;
+                save_flags(flags);
+                cli();
+#if LINUX_VERSION_CODE >= 0x010346 
+                free_irq(ha->irq,NULL);
+#else
+                free_irq(ha->irq);
+#endif
+                restore_flags(flags);
+                scsi_unregister(shp);
+                continue;
+            }
+
+#if LINUX_VERSION_CODE >= 0x010400
+            shp->max_id      = 8;
+            shp->max_lun     = 8;
+            shp->max_channel = ha->bus_cnt - 1;
+#else
+            /* register addit. SCSI channels as virtual controllers */
+            for (b=1; b<ha->bus_cnt; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                for (i=0; i<MAXID; ++i) {
+                    if (ha->id[b][i].type==SIOP_DTYP) {
+                        shp->this_id = i;
+                        break;
+                    }
+                }
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
+            }
+#endif
+
+            gdth_enable_int(hanum);
+        }
+    }
+
+    TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
+
+#ifdef GDTH_STATISTICS
+    TRACE2(("gdth_detect(): Initializing timer !\n"));
+    timer_table[GDTH_TIMER].fn = gdth_timeout;
+    timer_table[GDTH_TIMER].expires = jiffies + HZ;
+    timer_active |= 1<<GDTH_TIMER;
+#endif
+
+    gdth_polling = FALSE;
+    return gdth_ctr_vcount;
+}
+
+
+int gdth_release(struct Scsi_Host *shp)
+{
+    unsigned long flags;
+
+    TRACE2(("gdth_release()\n"));
+
+    save_flags(flags);
+    cli();
+    if (NUMDATA(shp)->busnum == 0) {
+        if (shp->irq) {
+#if LINUX_VERSION_CODE >= 0x010346
+            free_irq(shp->irq,NULL);
+#else
+            free_irq(shp->irq);
+#endif
+        }
+        if (shp->dma_channel != 0xff) {
+            free_dma(shp->dma_channel);
+        }
+    }
+
+    restore_flags(flags);
+    scsi_unregister(shp);
+    return 0;
+}
+            
+
+static const char *gdth_ctr_name(int hanum)
+{
+    gdth_ha_str *ha;
+
+    TRACE2(("gdth_ctr_name()\n"));
+
+    ha    = HADATA(gdth_ctr_tab[hanum]);
+
+    if (ha->type == GDT_EISA) {
+        switch (ha->stype) {
+          case GDT3_ID:
+            return("GDT3000/3020 (EISA)");
+          case GDT3A_ID:
+            return("GDT3000A/3020A/3050A (EISA)");
+          case GDT3B_ID:
+            return("GDT3000B/3010A (EISA)");
+        }
+    } else if (ha->type == GDT_ISA) {
+        return("GDT2000/2020 (ISA)");
+    } else if (ha->type == GDT_PCI) {
+        switch (ha->stype) {
+          case PCI_DEVICE_ID_VORTEX_GDT60x0:
+            return("GDT6000/6020/6050 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6000B:
+            return("GDT6000B/6010 (PCI)");
+        }
+    } else if (ha->type == GDT_PCINEW) {
+        switch (ha->stype) {
+          case PCI_DEVICE_ID_VORTEX_GDT6x10:
+            return("GDT6110/6510 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x20:
+            return("GDT6120/6520 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6530:
+            return("GDT6530 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6550:
+            return("GDT6550 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x17:
+            return("GDT6117/6517 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x27:
+            return("GDT6127/6527 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6537:
+            return("GDT6537 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6557:
+            return("GDT6557/6557-ECC (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x15:
+            return("GDT6115/6515 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x25:
+            return("GDT6125/6525 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6535:
+            return("GDT6535 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6555:
+            return("GDT6555/6555-ECC (PCI)");
+        }
+    } else if (ha->type == GDT_PCIMPR) {
+        switch (ha->stype) {
+          case PCI_DEVICE_ID_VORTEX_GDT6x17RP:
+            return("GDT6117RP/GDT6517RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x27RP:
+            return("GDT6127RP/GDT6527RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6537RP:
+            return("GDT6537RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6557RP:
+            return("GDT6557RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x11RP:
+            return("GDT6111RP/GDT6511RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x21RP:
+            return("GDT6121RP/GDT6521RP (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x17RP1:
+            return("GDT6117RP1/GDT6517RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x27RP1:
+            return("GDT6127RP1/GDT6527RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6537RP1:
+            return("GDT6537RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6557RP1:
+            return("GDT6557RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x11RP1:
+            return("GDT6111RP1/GDT6511RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x21RP1:
+            return("GDT6121RP1/GDT6521RP1 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x17RP2:
+            return("GDT6117RP2/GDT6517RP2 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x27RP2:
+            return("GDT6127RP2/GDT6527RP2 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6537RP2:
+            return("GDT6537RP2 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6557RP2:
+            return("GDT6557RP2 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x11RP2:
+            return("GDT6111RP2/GDT6511RP2 (PCI)");
+          case PCI_DEVICE_ID_VORTEX_GDT6x21RP2:
+            return("GDT6121RP2/GDT6521RP2 (PCI)");
+        }
+    }
+    return("");
+}
+
+const char *gdth_info(struct Scsi_Host *shp)
+{
+    int hanum;
+    
+    TRACE2(("gdth_info()\n"));
+    hanum = NUMDATA(shp)->hanum;
+
+    return (gdth_ctr_name(hanum));
+}
+
+
+int gdth_abort(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_abort() reason %d\n",scp->abort_reason));
+    return SCSI_ABORT_SNOOZE;
+}
+
+#if LINUX_VERSION_CODE >= 0x010346
+int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
+#else
+int gdth_reset(Scsi_Cmnd *scp)
+#endif
+{
+    TRACE2(("gdth_reset()\n"));
+    return SCSI_RESET_PUNT;
+}
+
+
+#if LINUX_VERSION_CODE >= 0x010300
+int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+#else
+int gdth_bios_param(Disk *disk,int dev,int *ip)
+#endif
+{
+    TRACE2(("gdth_bios_param()\n"));
+
+    ip[2] = disk->capacity / HEADS / SECS;
+    if (ip[2] <= MAXCYLS) {
+        ip[0] = HEADS;
+        ip[1] = SECS;
+    } else {
+        ip[2] = disk->capacity / MEDHEADS / MEDSECS;
+        if (ip[2] <= MAXCYLS) {
+            ip[0] = MEDHEADS;
+            ip[1] = MEDSECS;
+        } else {
+            ip[2] = disk->capacity / BIGHEADS / BIGSECS;
+            ip[0] = BIGHEADS;
+            ip[1] = BIGSECS;
+        }
+    }
+    TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
+            ip[0],ip[1],ip[2]));
+    return 0;
+}
+
+
+static void internal_done(Scsi_Cmnd *scp)
+{
+    scp->SCp.sent_command++;
+}
+
+int gdth_command(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_command()\n"));
+
+    scp->SCp.sent_command = 0;
+    gdth_queuecommand(scp,internal_done);
+
+    while (!scp->SCp.sent_command)
+        barrier();
+    return scp->result;
+}
+
+
+int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+{
+    int hanum;
+    int priority;
+
+    TRACE(("gdth_queuecommand() cmd 0x%x id %d lun %d\n",
+                  scp->cmnd[0],scp->target,scp->lun));
+    
+    scp->scsi_done = (void *)done;
+    scp->SCp.have_data_in = 0;
+    hanum = NUMDATA(scp->host)->hanum;
+#ifdef GDTH_STATISTICS
+    ++act_ios;
+#endif
+
+    priority = DEFAULT_PRI;
+#if LINUX_VERSION_CODE >= 0x010300
+    if (scp->done == gdth_scsi_done)
+        priority = scp->SCp.this_residual;
+#endif
+    gdth_putq( hanum, scp, priority );
+    gdth_next( hanum );
+    return 0;
+}
+
+
+/* shutdown routine */
+void gdth_halt()
+{
+    int             hanum, i, j;
+    gdth_ha_str     *ha;
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+    gdth_cmd_str    gdtcmd;
+    char            cmnd[12];
+
+    TRACE2(("gdth_halt()\n"));
+    printk("GDT: Flushing all host drives .. ");
+
+    for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
+        ha = HADATA(gdth_ctr_tab[hanum]);
+        memset(&sdev,0,sizeof(Scsi_Device));
+        memset(&scp, 0,sizeof(Scsi_Cmnd));
+        sdev.host = gdth_ctr_tab[hanum];
+        sdev.id = sdev.host->this_id;
+        scp.cmd_len = 12;
+        scp.host = gdth_ctr_tab[hanum];
+        scp.target = sdev.host->this_id;
+        scp.device = &sdev;
+        scp.use_sg = 0;
+
+        /* flush */
+        for (i = 0; i < MAXBUS; ++i) {
+            for (j = 0; j < MAXID; ++j) {
+                if (ha->id[i][j].type == CACHE_DTYP) {
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_FLUSH;
+                    gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
+                    gdtcmd.u.cache.BlockNo = 1;
+                    gdtcmd.u.cache.sg_canz = 0;
+                    TRACE2(("gdth_halt(): flush ha %d drive %d\n",
+                        hanum, ha->id[i][j].hostdrive));
+                    {
+                        struct semaphore sem = MUTEX_LOCKED;
+                        scp.request.rq_status = RQ_SCSI_BUSY;
+                        scp.request.sem = &sem;
+                        scsi_do_cmd(&scp, cmnd, &gdtcmd,
+                                    sizeof(gdth_cmd_str), gdth_scsi_done,
+                                    30*HZ, 1);
+                        down(&sem);
+                    }
+                }
+            }
+        }
+
+        /* controller reset */
+        gdtcmd.BoardNode = LOCALBOARD;
+        gdtcmd.Service = CACHESERVICE;
+        gdtcmd.OpCode = GDT_RESET;
+        TRACE2(("gdth_halt(): reset controller %d\n", hanum));
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            scp.request.rq_status = RQ_SCSI_BUSY;
+            scp.request.sem = &sem;
+            scsi_do_cmd(&scp, cmnd, &gdtcmd,
+                sizeof(gdth_cmd_str), gdth_scsi_done,
+                10*HZ, 1);
+            down(&sem);
+        }
+    }
+    printk("Done.\n");
+}
+
+
+/* called from init/main.c */
+void gdth_setup(char *str,int *ints)
+{
+    static size_t setup_idx = 0;
+
+    TRACE2(("gdth_setup() str %s ints[0] %d ints[1] %d\n",
+                  str ? str:"NULL", ints[0],
+                  ints[0] ? ints[1]:0));
+
+    if (setup_idx >= MAXHA) {
+        printk("GDT: gdth_setup() called too many times. Bad LILO params ?\n");
+        return;
+    }
+    if (ints[0] != 1) {
+        printk("GDT: Illegal command line !\n");
+        printk("Usage: gdth=<IRQ>\n");
+        printk("Where: <IRQ>: valid EISA controller IRQ (10,11,12,14)\n");
+        printk("              or 0 to disable controller driver\n");
+        return;
+    }
+    if (ints[1] == 10 || ints[1] == 11 || ints[1] == 12 || ints[1] == 14) {
+        irqs[setup_idx++] = ints[1];
+        irqs[setup_idx]   = 0xff;
+        return;
+    }
+    if (ints[1] == 0) {
+        disable_gdth_scan = TRUE;
+        return;
+    }
+    printk("GDT: Invalid IRQ (%d) specified\n",ints[1]);
+}
+
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = GDTH;
+#include "scsi_module.c"
+#endif
+
diff -urN linux-2.0.31-pre2/drivers/scsi/gdth.h linux-2.0.31-pre3/drivers/scsi/gdth.h
--- linux-2.0.31-pre2/drivers/scsi/gdth.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/scsi/gdth.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,719 @@
+#ifndef _GDTH_H
+#define _GDTH_H
+
+/*
+ * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
+ * 
+ * gdth.h Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner
+ * See gdth.c for further informations and 
+ * below for supported controller types
+ *
+ * <achim@vortex.de>
+ *
+ * $Id: gdth.h,v 1.7 1997/03/20 16:01:59 achim Exp $
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* defines, macros */
+
+/* driver version */
+#define GDTH_VERSION_STR        "1.00"
+#define GDTH_VERSION            1
+#define GDTH_SUBVERSION         0
+
+/* protocol version */
+#define PROTOCOL_VERSION        1
+
+/* controller classes */
+#define GDT_ISA         0x01                    /* ISA controller */
+#define GDT_EISA        0x02                    /* EISA controller */
+#define GDT_PCI         0x03                    /* PCI controller */
+#define GDT_PCINEW      0x04                    /* new PCI controller */
+#define GDT_PCIMPR      0x05                    /* PCI MPR controller */
+/* GDT_EISA, controller subtypes EISA */
+#define GDT3_ID         0x0130941c              /* GDT3000/3020 */
+#define GDT3A_ID        0x0230941c              /* GDT3000A/3020A/3050A */
+#define GDT3B_ID        0x0330941c              /* GDT3000B/3010A */
+/* GDT_ISA */
+#define GDT2_ID         0x0120941c              /* GDT2000/2020 */
+/* vendor ID, device IDs (PCI) */
+/* these defines should already exist in <linux/pci.h> */
+#ifndef PCI_VENDOR_ID_VORTEX
+#define PCI_VENDOR_ID_VORTEX            0x1119  /* PCI controller vendor ID */
+#endif
+#ifndef PCI_DEVICE_ID_VORTEX_GDT60x0
+/* GDT_PCI */
+#define PCI_DEVICE_ID_VORTEX_GDT60x0    0       /* GDT6000/6020/6050 */
+#define PCI_DEVICE_ID_VORTEX_GDT6000B   1       /* GDT6000B/6010 */
+/* GDT_PCINEW */
+#define PCI_DEVICE_ID_VORTEX_GDT6x10    2       /* GDT6110/6510 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x20    3       /* GDT6120/6520 */
+#define PCI_DEVICE_ID_VORTEX_GDT6530    4       /* GDT6530 */
+#define PCI_DEVICE_ID_VORTEX_GDT6550    5       /* GDT6550 */
+/* GDT_PCINEW, wide/ultra SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17    6       /* GDT6117/6517 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27    7       /* GDT6127/6527 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537    8       /* GDT6537 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557    9       /* GDT6557/6557-ECC */
+/* GDT_PCINEW, wide SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x15    10      /* GDT6115/6515 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x25    11      /* GDT6125/6525 */
+#define PCI_DEVICE_ID_VORTEX_GDT6535    12      /* GDT6535 */
+#define PCI_DEVICE_ID_VORTEX_GDT6555    13      /* GDT6555/6555-ECC */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RP
+/* GDT_MPR, RP series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP  0x100   /* GDT6117RP/GDT6517RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP  0x101   /* GDT6127RP/GDT6527RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP  0x102   /* GDT6537RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP  0x103   /* GDT6557RP */
+/* GDT_MPR, RP series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP  0x104   /* GDT6111RP/GDT6511RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP  0x105   /* GDT6121RP/GDT6521RP */
+/* GDT_MPR, RP1 series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1 0x110   /* GDT6117RP1/GDT6517RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1 0x111   /* GDT6127RP1/GDT6527RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP1 0x112   /* GDT6537RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP1 0x113   /* GDT6557RP1 */
+/* GDT_MPR, RP1 series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1 0x114   /* GDT6111RP1/GDT6511RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1 0x115   /* GDT6121RP1/GDT6521RP1 */
+/* GDT_MPR, RP2 series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2 0x120   /* GDT6117RP2/GDT6517RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2 0x121   /* GDT6127RP2/GDT6527RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP2 0x122   /* GDT6537RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP2 0x123   /* GDT6557RP2 */
+/* GDT_MPR, RP2 series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2 0x124   /* GDT6111RP2/GDT6511RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2 0x125   /* GDT6121RP2/GDT6521RP2 */
+#endif
+
+/* limits */
+#define GDTH_SCRATCH    4096                    /* 4KB scratch buffer */
+#define GDTH_MAXCMDS    124
+#define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
+#define MAXOFFSETS      128
+#define MAXHA           8
+#define MAXID           8
+#define MAXLUN          8
+#define MAXBUS          5
+#define MAX_HDRIVES     35                      /* max. host drive count */
+#define MAX_EVENTS      100                     /* event buffer count */
+#define MAXCYLS         1024
+#define HEADS           64
+#define SECS            32                      /* mapping 64*32 */
+#define MEDHEADS        127
+#define MEDSECS         63                      /* mapping 127*63 */
+#define BIGHEADS        255
+#define BIGSECS         63                      /* mapping 255*63 */
+
+/* special command ptr. */
+#define UNUSED_CMND     ((Scsi_Cmnd *)-1)
+#define INTERNAL_CMND   ((Scsi_Cmnd *)-2)
+#define SCREEN_CMND     ((Scsi_Cmnd *)-3)
+#define SPECIAL_SCP(p)  (p==UNUSED_CMND || p==INTERNAL_CMND || p==SCREEN_CMND)
+
+/* device types */
+#define EMPTY_DTYP      0
+#define CACHE_DTYP      1
+#define RAW_DTYP        2
+#define SIOP_DTYP       3                       /* the SCSI processor */
+
+/* controller services */
+#define SCSIRAWSERVICE  3
+#define CACHESERVICE    9
+#define SCREENSERVICE   11
+
+/* screenservice defines */
+#define MSG_INV_HANDLE  -1                      /* special message handle */
+#define MSGLEN          16                      /* size of message text */
+#define MSG_SIZE        34                      /* size of message structure */
+#define MSG_REQUEST     0                       /* async. event: message */
+
+/* cacheservice defines */
+#define SECTOR_SIZE     0x200                   /* always 512 bytes per sector */
+
+/* DPMEM constants */
+#define IC_HEADER_BYTES 48
+#define IC_QUEUE_BYTES  4
+#define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
+
+/* service commands */
+#define GDT_INIT        0                       /* service initialization */
+#define GDT_READ        1                       /* read command */
+#define GDT_WRITE       2                       /* write command */
+#define GDT_INFO        3                       /* information about devices */
+#define GDT_FLUSH       4                       /* flush dirty cache buffers */
+#define GDT_IOCTL       5                       /* ioctl command */
+#define GDT_DEVTYPE     9                       /* additional information */
+#define GDT_MOUNT       10                      /* mount cache device */
+#define GDT_UNMOUNT     11                      /* unmount cache device */
+#define GDT_SET_FEAT    12                      /* set feat. (scatter/gather) */
+#define GDT_GET_FEAT    13                      /* get features */
+#define GDT_RESERVE     14                      /* reserve dev. to raw service */
+#define GDT_WRITE_THR   16                      /* write through */
+#define GDT_EXT_INFO    18                      /* extended info */
+#define GDT_RESET       19                      /* controller reset */
+
+/* IOCTL command defines */
+#define SCSI_CHAN_CNT   5                       /* subfunctions */
+#define L_CTRL_PATTERN  0x20000000L
+#define CACHE_INFO      4
+#define CACHE_CONFIG    5
+#define IO_CHANNEL      0x00020000L             /* channels */
+#define INVALID_CHANNEL 0x0000ffffL     
+
+/* IOCTLs */
+#define GDTIOCTL_MASK       ('J'<<8)
+#define GDTIOCTL_GENERAL    (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+
+/* service errors */
+#define S_OK            1                       /* no error */
+#define S_BSY           7                       /* controller busy */
+#define S_RAW_SCSI      12                      /* raw serv.: target error */
+#define S_RAW_ILL       0xff                    /* raw serv.: illegal */
+
+/* timeout values */
+#define INIT_RETRIES    10000                   /* 10000 * 1ms = 10s */
+#define INIT_TIMEOUT    100000                  /* 1000 * 1ms = 1s */
+#define POLL_TIMEOUT    10000                   /* 10000 * 1ms = 10s */
+
+/* priorities */
+#define DEFAULT_PRI     0x20
+#define IOCTL_PRI       0x10
+
+/* data directions */
+#define DATA_IN         0x01000000L             /* data from target */
+#define DATA_OUT        0x00000000L             /* data to target */
+
+/* BMIC registers (EISA controllers) */
+#define ID0REG          0x0c80                  /* board ID */
+#define EINTENABREG     0x0c89                  /* interrupt enable */
+#define SEMA0REG        0x0c8a                  /* command semaphore */
+#define SEMA1REG        0x0c8b                  /* status semaphore */
+#define LDOORREG        0x0c8d                  /* local doorbell */
+#define EDENABREG       0x0c8e                  /* EISA system doorbell enable */
+#define EDOORREG        0x0c8f                  /* EISA system doorbell */
+#define MAILBOXREG      0x0c90                  /* mailbox reg. (16 bytes) */
+#define EISAREG         0x0cc0                  /* EISA configuration */
+
+/* other defines */
+#define LINUX_OS        8                       /* used for cache optim. */
+#define SCATTER_GATHER  1                       /* s/g feature */
+#define GDTH_MAXSG      32                      /* max. s/g elements */
+#define SECS32          0x1f                    /* round capacity */
+#define BIOS_ID_OFFS    0x10                    /* offset contr. ID in ISABIOS */
+#define LOCALBOARD      0                       /* board node always 0 */
+#define ASYNCINDEX      0                       /* cmd index async. event */
+#define SPEZINDEX       1                       /* cmd index unknown service */
+#define GDT_WR_THROUGH  0x100                   /* WRITE_THROUGH supported */
+
+/* typedefs */
+
+#pragma pack(1)
+
+typedef struct {
+    char        buffer[GDTH_SCRATCH];           /* scratch buffer */
+} gdth_scratch_str;
+
+/* screenservice message */
+typedef struct {                               
+    ulong       msg_handle;                     /* message handle */
+    ulong       msg_len;                        /* size of message */
+    ulong       msg_alen;                       /* answer length */
+    unchar      msg_answer;                     /* answer flag */
+    unchar      msg_ext;                        /* more messages */
+    unchar      msg_reserved[2];
+    char        msg_text[MSGLEN+2];             /* the message text */
+} gdth_msg_str;
+
+/* get channel count IOCTL */
+typedef struct {
+    ulong       channel_no;                     /* number of channel */
+    ulong       drive_cnt;                      /* number of drives */
+    unchar      siop_id;                        /* SCSI processor ID */
+    unchar      siop_state;                     /* SCSI processor state */ 
+} gdth_getch_str;
+
+/* cache info/config IOCTL */
+typedef struct {
+    ulong       version;                        /* firmware version */
+    ushort      state;                          /* cache state (on/off) */
+    ushort      strategy;                       /* cache strategy */
+    ushort      write_back;                     /* write back state (on/off) */
+    ushort      block_size;                     /* cache block size */
+} gdth_cpar_str;
+
+typedef struct {
+    ulong       csize;                          /* cache size */
+    ulong       read_cnt;                       /* read/write counter */
+    ulong       write_cnt;
+    ulong       tr_hits;                        /* hits */
+    ulong       sec_hits;
+    ulong       sec_miss;                       /* misses */
+} gdth_cstat_str;
+
+typedef struct {
+    gdth_cpar_str   cpar;
+    gdth_cstat_str  cstat;
+} gdth_cinfo_str;
+
+/* scatter/gather element */
+typedef struct {
+    ulong       sg_ptr;                         /* address */
+    ulong       sg_len;                         /* length */
+} gdth_sg_str;
+
+/* command structure */
+typedef struct {
+    ulong       BoardNode;                      /* board node (always 0) */
+    ulong       CommandIndex;                   /* command number */
+    ushort      OpCode;                         /* the command (READ,..) */
+    union {
+        struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong       BlockNo;                /* block number */
+            ulong       BlockCnt;               /* block count */
+            ulong       DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong       sg_canz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } cache;                                /* cache service cmd. str. */
+        struct {
+            ushort      param_size;             /* size of p_param buffer */
+            ulong       subfunc;                /* IOCTL function */
+            ulong       channel;                /* device */
+            ulong       p_param;                /* buffer */
+        } ioctl;                                /* IOCTL command structure */
+        struct {
+            ushort      reserved;
+            ulong       msg_handle;             /* message handle */
+            ulong       msg_addr;               /* message buffer address */
+        } screen;                               /* screen service cmd. str. */
+        struct {
+            ushort      reserved;
+            ulong       direction;              /* data direction */
+            ulong       mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong       mcon_time;              /* connect time(0: no to.) */
+            ulong       sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong       sdlen;                  /* data length (bytes) */
+            ulong       clen;                   /* SCSI cmd. length(6,10,12) */
+            unchar      cmd[12];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong       sense_len;              /* sense data length */
+            ulong       sense_data;             /* sense data addr. */
+            struct raw  *link_p;                /* linked cmds (not supp.) */
+            ulong       sg_ranz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } raw;                                  /* raw service cmd. struct. */
+    } u;
+    /* additional variables */
+    unchar      Service;                        /* controller service */
+    ushort      Status;                         /* command result */
+    ulong       Info;                           /* additional information */
+    Scsi_Cmnd   *RequestBuffer;                 /* request buffer */
+} gdth_cmd_str;
+
+/* controller event structure */
+#define ES_ASYNC    1
+#define ES_DRIVER   2
+#define ES_TEST     3
+#define ES_SYNC     4
+typedef struct {
+    ushort                  size;               /* size of structure */
+    union {
+        char                stream[16];
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ulong           index;
+        } driver;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong           info;
+            unchar          scsi_coord[3];
+        } async;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong           info;
+            ushort          hostdrive;
+            unchar          scsi_coord[3];
+            unchar          sense_key;
+        } sync;
+        struct {
+            ulong           l1, l2, l3, l4;
+        } test;
+    } eu;
+} gdth_evt_data;
+
+typedef struct {
+    ulong           first_stamp;
+    ulong           last_stamp;
+    ushort          same_count;
+    ushort          event_source;
+    ushort          event_idx;
+    unchar          application;
+    unchar          reserved;
+    gdth_evt_data   event_data;
+} gdth_evt_str;
+
+
+/* DPRAM structures */
+
+/* interface area ISA/PCI */
+typedef struct {
+    unchar              S_Cmd_Indx;             /* special command */
+    unchar volatile     S_Status;               /* status special command */
+    ushort              reserved1;
+    ulong               S_Info[4];              /* add. info special command */
+    unchar volatile     Sema0;                  /* command semaphore */
+    unchar              reserved2[3];
+    unchar              Cmd_Index;              /* command number */
+    unchar              reserved3[3];
+    ushort volatile     Status;                 /* command status */
+    ushort              Service;                /* service(for async.events) */
+    ulong               Info[2];                /* additional info */
+    struct {
+        ushort          offset;                 /* command offs. in the DPRAM*/
+        ushort          serv_id;                /* service */
+    } comm_queue[MAXOFFSETS];                   /* command queue */
+    ulong               bios_reserved[2];
+    unchar              gdt_dpr_cmd[1];         /* commands */
+} gdt_dpr_if;
+
+/* SRAM structure PCI controllers */
+typedef struct {
+    ulong       magic;                          /* controller ID from BIOS */
+    ushort      need_deinit;                    /* switch betw. BIOS/driver */
+    unchar      switch_support;                 /* see need_deinit */
+    unchar      padding[9];
+    unchar      os_used[16];                    /* OS code per service */
+    unchar      unused[28];
+    unchar      fw_magic;                       /* contr. ID from firmware */
+} gdt_pci_sram;
+
+/* SRAM structure EISA controllers (but NOT GDT3000/3020) */
+typedef struct {
+    unchar      os_used[16];                    /* OS code per service */
+    ushort      need_deinit;                    /* switch betw. BIOS/driver */
+    unchar      switch_support;                 /* see need_deinit */
+    unchar      padding;
+} gdt_eisa_sram;
+
+
+/* DPRAM ISA controllers */
+typedef struct {
+    union {
+        struct {
+            unchar      bios_used[0x3c00-32];   /* 15KB - 32Bytes BIOS */
+            ulong       magic;                  /* controller (EISA) ID */
+            ushort      need_deinit;            /* switch betw. BIOS/driver */
+            unchar      switch_support;         /* see need_deinit */
+            unchar      padding[9];
+            unchar      os_used[16];            /* OS code per service */
+        } dp_sram;
+        unchar          bios_area[0x4000];      /* 16KB reserved for BIOS */
+    } bu;
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x3000];        /* 12KB for interface */
+    } u;
+    struct {
+        unchar          memlock;                /* write protection DPRAM */
+        unchar          event;                  /* release event */
+        unchar          irqen;                  /* board interrupts enable */
+        unchar          irqdel;                 /* acknowledge board int. */
+        unchar volatile Sema1;                  /* status semaphore */
+        unchar          rq;                     /* IRQ/DRQ configuration */
+    } io;
+} gdt2_dpram_str;
+
+/* DPRAM PCI controllers */
+typedef struct {
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0xff0-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+    struct {
+        unchar          unused0[1];
+        unchar volatile Sema1;                  /* command semaphore */
+        unchar          unused1[3];
+        unchar          irqen;                  /* board interrupts enable */
+        unchar          unused2[2];
+        unchar          event;                  /* release event */
+        unchar          unused3[3];
+        unchar          irqdel;                 /* acknowledge board int. */
+        unchar          unused4[3];
+    } io;
+} gdt6_dpram_str;
+
+/* PLX register structure (new PCI controllers) */
+typedef struct {
+    unchar              cfg_reg;        /* DPRAM cfg.(2:below 1MB,0:anywhere)*/
+    unchar              unused1[0x3f];
+    unchar volatile     sema0_reg;              /* command semaphore */
+    unchar volatile     sema1_reg;              /* status semaphore */
+    unchar              unused2[2];
+    ushort volatile     status;                 /* command status */
+    ushort              service;                /* service */
+    ulong               info[2];                /* additional info */
+    unchar              unused3[0x10];
+    unchar              ldoor_reg;              /* PCI to local doorbell */
+    unchar              unused4[3];
+    unchar volatile     edoor_reg;              /* local to PCI doorbell */
+    unchar              unused5[3];
+    unchar              control0;               /* control0 register(unused) */
+    unchar              control1;               /* board interrupts enable */
+    unchar              unused6[0x16];
+} gdt6c_plx_regs;
+
+/* DPRAM new PCI controllers */
+typedef struct {
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x4000-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+} gdt6c_dpram_str;
+
+/* i960 register structure (PCI MPR controllers) */
+typedef struct {
+    unchar              unused1[16];
+    unchar volatile     sema0_reg;              /* command semaphore */
+    unchar              unused2;
+    unchar volatile     sema1_reg;              /* status semaphore */
+    unchar              unused3;
+    ushort volatile     status;                 /* command status */
+    ushort              service;                /* service */
+    ulong               info[2];                /* additional info */
+    unchar              ldoor_reg;              /* PCI to local doorbell */
+    unchar              unused4[11];
+    unchar volatile     edoor_reg;              /* local to PCI doorbell */
+    unchar              unused5[7];
+    unchar              edoor_en_reg;           /* board interrupts enable */
+    unchar              unused6[27];
+    ulong               unused7[1004];          /* size: 4 KB */
+} gdt6m_i960_regs;
+
+/* DPRAM PCI MPR controllers */
+typedef struct {
+    gdt6m_i960_regs     i960r;                  /* 4KB i960 registers */
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x3000-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+} gdt6m_dpram_str;
+
+
+/* PCI resources */
+typedef struct {
+    ushort      device_id;                      /* device ID (0,..,9) */
+    unchar      bus;                            /* PCI bus */
+    unchar      device_fn;                      /* PCI device/function no. */
+    ulong       dpmem;                          /* DPRAM address */
+    ulong       io;                             /* IO address */
+    ulong       io_mm;                          /* IO address mem. mapped */
+    ulong       bios;                           /* BIOS address */
+    unchar      irq;                            /* IRQ */
+} gdth_pci_str;
+
+
+/* controller information structure */
+typedef struct {
+    unchar              bus_cnt;                /* SCSI bus count */
+    unchar              type;                   /* controller class */
+    ushort              raw_feat;               /* feat. raw service (s/g,..) */
+    ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
+    ulong               stype;                  /* controller subtype */
+    ulong               brd;                    /* BMIC/DPRAM address */
+    ulong               brd_phys;               /* slot number/BIOS address */
+    gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
+    gdth_cmd_str        *pccb;                  /* address command structure */
+    gdth_scratch_str    *pscratch;
+    unchar              irq;                    /* IRQ */
+    unchar              drq;                    /* DRQ (ISA controllers) */
+    ushort              status;                 /* command status */
+    ulong               info;
+    ulong               info2;                  /* additional info */
+    Scsi_Cmnd           *req_first;             /* top of request queue */
+    struct {
+        unchar          type;                   /* device type */
+        unchar          heads;                  /* mapping */
+        unchar          secs;
+        unchar          lock;                   /* drive locked ? (hot plug) */
+        ushort          hostdrive;              /* host drive number */
+        ushort          devtype;                /* further information */
+        ulong           size;                   /* capacity */
+    } id[MAXBUS][MAXID];         
+    ushort              cmd_cnt;                /* command count in DPRAM */
+    ushort              cmd_len;                /* length of actual command */
+    ushort              cmd_offs_dpmem;         /* actual offset in DPRAM */
+    ushort              ic_all_size;            /* sizeof DPRAM interf. area */
+    unchar              reserved;
+    unchar              mode;                   /* information from /proc */
+    ushort              param_size;
+    gdth_cpar_str       cpar;                   /* controller cache par. */
+} gdth_ha_str;
+
+/* structure for scsi_register(), SCSI bus != 0 */
+typedef struct {
+    ushort      hanum;
+    ushort      busnum;
+} gdth_num_str;
+
+/* structure for scsi_register() */
+typedef struct {
+    gdth_num_str        numext;                 /* must be the first element */
+    gdth_ha_str         haext;
+    gdth_cmd_str        cmdext;
+    gdth_scratch_str    dmaext;
+} gdth_ext_str;
+
+
+/* INQUIRY data format */
+typedef struct {
+    unchar      type_qual;
+    unchar      modif_rmb;
+    unchar      version;
+    unchar      resp_aenc;
+    unchar      add_length;
+    unchar      reserved1;
+    unchar      reserved2;
+    unchar      misc;
+    unchar      vendor[8];
+    unchar      product[16];
+    unchar      revision[4];
+} gdth_inq_data;
+
+/* READ_CAPACITY data format */
+typedef struct {
+    ulong       last_block_no;
+    ulong       block_length;
+} gdth_rdcap_data;
+
+/* REQUEST_SENSE data format */
+typedef struct {
+    unchar      errorcode;
+    unchar      segno;
+    unchar      key;
+    ulong       info;
+    unchar      add_length;
+    ulong       cmd_info;
+    unchar      adsc;
+    unchar      adsq;
+    unchar      fruc;
+    unchar      key_spec[3];
+} gdth_sense_data;
+
+/* MODE_SENSE data format */
+typedef struct {
+    struct {
+        unchar  data_length;
+        unchar  med_type;
+        unchar  dev_par;
+        unchar  bd_length;
+    } hd;
+    struct {
+        unchar  dens_code;
+        unchar  block_count[3];
+        unchar  reserved;
+        unchar  block_length[3];
+    } bd;
+} gdth_modep_data;
+
+typedef struct {
+    ulong       b[10];                          /* 32 bit compiler ! */
+} gdth_stackframe;
+
+#pragma pack()
+
+/* function prototyping */
+
+int gdth_detect(Scsi_Host_Template *);
+int gdth_release(struct Scsi_Host *);
+int gdth_command(Scsi_Cmnd *);
+int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
+int gdth_abort(Scsi_Cmnd *);
+#if LINUX_VERSION_CODE >= 0x010346
+int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags);
+#else
+int gdth_reset(Scsi_Cmnd *);
+#endif
+const char *gdth_info(struct Scsi_Host *);
+
+
+#if LINUX_VERSION_CODE >= 0x010300
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+#define GDTH { NULL, NULL,                              \
+                   &proc_scsi_gdth,                     \
+                   gdth_proc_info,                      \
+                   "GDT SCSI Disk Array Controller",    \
+                   gdth_detect,                         \
+                   gdth_release,                        \
+                   gdth_info,                           \
+                   gdth_command,                        \
+                   gdth_queuecommand,                   \
+                   gdth_abort,                          \
+                   gdth_reset,                          \
+                   NULL,                                \
+                   gdth_bios_param,                     \
+                   GDTH_MAXCMDS,                        \
+                   -1,                                  \
+                   GDTH_MAXSG,                          \
+                   GDTH_MAXC_P_L,                       \
+                   0,                                   \
+                   1,                                   \
+                   ENABLE_CLUSTERING}
+#else
+int gdth_bios_param(Disk *,int,int *);
+#define GDTH { NULL, NULL,                              \
+                   "GDT SCSI Disk Array Controller",    \
+                   gdth_detect,                         \
+                   gdth_release,                        \
+                   gdth_info,                           \
+                   gdth_command,                        \
+                   gdth_queuecommand,                   \
+                   gdth_abort,                          \
+                   gdth_reset,                          \
+                   NULL,                                \
+                   gdth_bios_param,                     \
+                   GDTH_MAXCMDS,                        \
+                   -1,                                  \
+                   GDTH_MAXSG,                          \
+                   GDTH_MAXC_P_L,                       \
+                   0,                                   \
+                   1,                                   \
+                   ENABLE_CLUSTERING}
+#endif
+
+#endif
+
diff -urN linux-2.0.31-pre2/drivers/scsi/gdth_ioctl.h linux-2.0.31-pre3/drivers/scsi/gdth_ioctl.h
--- linux-2.0.31-pre2/drivers/scsi/gdth_ioctl.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/scsi/gdth_ioctl.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,86 @@
+#ifndef _GDTH_IOCTL_H
+#define _GDTH_IOCTL_H
+
+/* gdth_ioctl.h
+ * $Id: gdth_ioctl.h,v 1.1 1997/02/21 08:07:27 achim Exp $
+ */
+
+/* IOCTLs */
+#define GDTIOCTL_MASK       ('J'<<8)
+#define GDTIOCTL_GENERAL    (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_OSVERS     (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+
+#define GDTIOCTL_MAGIC      0x06030f07UL
+
+
+/* IOCTL structure (write) */
+typedef struct {
+    ulong                   magic;              /* IOCTL magic */
+    ushort                  ioctl;              /* IOCTL */
+    ushort                  ionode;             /* controller number */
+    ushort                  service;            /* controller service */
+    ushort                  timeout;            /* timeout */
+    union {
+        struct {
+            unchar          command[512];       /* controller command */
+            unchar          data[1];            /* add. data */
+        } general;
+        struct {
+            unchar          lock;               /* lock/unlock */
+            unchar          drive_cnt;          /* drive count */
+            ushort          drives[35];         /* drives */
+        } lockdrv;
+        struct {
+            unchar          lock;               /* lock/unlock */
+            unchar          channel;            /* channel */
+        } lockchn;
+        struct {
+            int             erase;              /* erase event ? */
+            int             handle;
+        } event;
+    } iu;
+} gdth_iowr_str;
+
+/* IOCTL structure (read) */
+typedef struct {
+    ulong                   size;               /* buffer size */
+    ulong                   status;             /* IOCTL error code */
+    union {
+        struct {
+            unchar          data[1];            /* data */
+        } general;
+        struct {
+            ushort          version;            /* driver version */
+        } drvers;
+        struct {
+            unchar          type;               /* controller type */
+            ushort          info;               /* slot etc. */
+            ushort          oem_id;             /* OEM ID */
+            ushort          bios_ver;           /* not used */
+            ushort          access;             /* not used */
+            ushort          ext_type;           /* extended type */
+        } ctrtype;
+        struct {
+            unchar          version;            /* OS version */
+            unchar          subversion;         /* OS subversion */
+            ushort          revision;           /* revision */
+        } osvers;
+        struct {
+            ushort          count;              /* controller count */
+        } ctrcnt;
+        struct {
+            int             handle;
+            unchar          evt[32];            /* event structure */
+        } event;
+    } iu;
+} gdth_iord_str;
+
+
+#endif
+
diff -urN linux-2.0.31-pre2/drivers/scsi/gdth_proc.c linux-2.0.31-pre3/drivers/scsi/gdth_proc.c
--- linux-2.0.31-pre2/drivers/scsi/gdth_proc.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/scsi/gdth_proc.c	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,635 @@
+/* gdth_proc.c 
+ * $Id: gdth_proc.c,v 1.4 1997/02/25 13:33:47 achim Exp $
+ */
+
+#include "gdth_ioctl.h"
+
+int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
+                   int hostno,int inout)
+{
+    int hanum,busnum,i;
+
+    TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
+            length,hostno,offset,inout));
+
+    for (i=0; i<gdth_ctr_vcount; ++i) {
+        if (gdth_ctr_vtab[i]->host_no == hostno)
+            break;
+    }
+    if (i==gdth_ctr_vcount)
+        return(-EINVAL);
+
+    hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
+    busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
+
+    if (inout)
+        return(gdth_set_info(buffer,length,i,hanum,busnum));
+    else
+        return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum));
+}
+
+static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
+{
+    int             ret_val;
+    Scsi_Cmnd       scp;
+    Scsi_Device     sdev;
+    gdth_iowr_str   *piowr;
+
+    TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+    piowr = (gdth_iowr_str *)buffer;
+
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = gdth_ctr_vtab[vh];
+    sdev.id = sdev.host->this_id;
+    scp.cmd_len = 12;
+    scp.host = gdth_ctr_vtab[vh];
+    scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+    scp.use_sg = 0;
+
+    if (length >= 4) {
+        if (strncmp(buffer,"gdth",4) == 0) {
+            buffer += 5;
+            length -= 5;
+            ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
+        } else if (piowr->magic == GDTIOCTL_MAGIC) {
+            ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
+        } else {
+            printk("GDT: Wrong signature: %6s\n",buffer);
+            ret_val = -EINVAL;
+        }
+    } else {
+        ret_val = -EINVAL;
+    }
+    return ret_val;
+}
+         
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+{
+    int             orig_length, drive, wb_mode;
+    char            cmnd[12];
+    int             i, j, found;
+    gdth_ha_str     *ha;
+    gdth_cmd_str    gdtcmd;
+    gdth_cpar_str   *pcpar;
+
+    TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(cmnd, 0,10);
+    orig_length = length + 5;
+    drive = -1;
+    wb_mode = 0;
+    found = FALSE;
+
+    if (length >= 5 && strncmp(buffer,"flush",5)==0) {
+        buffer += 6;
+        length -= 6;
+        if (length && *buffer>='0' && *buffer<='9') {
+            drive = (int)(*buffer-'0');
+            ++buffer; --length;
+            if (length && *buffer>='0' && *buffer<='9') {
+                drive = drive*10 + (int)(*buffer-'0');
+                ++buffer; --length;
+            }
+            printk("GDT: Flushing host drive %d .. ",drive);
+        } else {
+            printk("GDT: Flushing all host drives .. ");
+        }
+        for (i = 0; i < MAXBUS; ++i) {
+            for (j = 0; j < MAXID; ++j) {
+                if (ha->id[i][j].type == CACHE_DTYP) {
+                    if (drive != -1 &&
+                        ha->id[i][j].hostdrive != (ushort)drive)
+                        continue;
+                    found = TRUE;
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_FLUSH;
+                    gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
+                    gdtcmd.u.cache.BlockNo = 1;
+                    gdtcmd.u.cache.sg_canz = 0;
+                    {
+                        struct semaphore sem = MUTEX_LOCKED;
+                        scp.request.rq_status = RQ_SCSI_BUSY;
+                        scp.request.sem = &sem;
+                        scsi_do_cmd(&scp, cmnd, &gdtcmd,
+                                    sizeof(gdth_cmd_str), gdth_scsi_done,
+                                    30*HZ, 1);
+                        down(&sem);
+                    }
+                }
+            }
+        }
+        if (!found)
+            printk("\nNo host drive found !\n");
+        else
+            printk("Done.\n");
+        return(orig_length);
+    }
+
+    if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
+        buffer += 8;
+        length -= 8;
+        printk("GDT: Disabling write back permanently .. ");
+        wb_mode = 1;
+    } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
+        buffer += 7;
+        length -= 7;
+        printk("GDT: Enabling write back permanently .. ");
+        wb_mode = 2;
+    } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
+        buffer += 7;
+        length -= 7;
+        printk("GDT: Disabling write back commands .. ");
+        if (ha->cache_feat & GDT_WR_THROUGH) {
+            gdth_write_through = TRUE;
+            printk("Done.\n");
+        } else {
+            printk("Not supported !\n");
+        }
+        return(orig_length);
+    } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
+        buffer += 6;
+        length -= 6;
+        printk("GDT: Enabling write back commands .. ");
+        gdth_write_through = FALSE;
+        printk("Done.\n");
+        return(orig_length);
+    }
+
+    if (wb_mode) {
+        pcpar = (gdth_cpar_str *)kmalloc( sizeof(gdth_cpar_str),
+            GFP_ATOMIC | GFP_DMA );
+        if (pcpar == NULL) {
+            TRACE2(("gdth_set_info(): Unable to allocate memory.\n"));
+            printk("Unable to allocate memory.\n");
+            return(-EINVAL);
+        }
+        memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
+        gdtcmd.BoardNode = LOCALBOARD;
+        gdtcmd.Service = CACHESERVICE;
+        gdtcmd.OpCode = GDT_IOCTL;
+        gdtcmd.u.ioctl.p_param = (ulong)pcpar;
+        gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
+        gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
+        gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
+        pcpar->write_back = wb_mode==1 ? 0:1;
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            scp.request.rq_status = RQ_SCSI_BUSY;
+            scp.request.sem = &sem;
+            scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str),
+                        gdth_scsi_done, 30*HZ, 1);
+            down(&sem);
+        }
+        kfree( pcpar );
+        printk("Done.\n");
+        return(orig_length);
+    }
+
+    printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
+    return(-EINVAL);
+}
+
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+{
+    char            cmnd[12];
+    int             id;
+    unchar          i, j, k, found;
+    gdth_ha_str     *ha;
+    gdth_iowr_str   *piowr;
+    gdth_iord_str   *piord;
+    gdth_cmd_str    *pcmd;
+    ulong           *ppadd;
+    ulong           add_size, flags;
+
+
+    TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(cmnd, 0,10);
+    piowr = (gdth_iowr_str *)buffer;
+    piord = NULL;
+    pcmd = NULL;
+
+    if (length < GDTOFFSOF(gdth_iowr_str,iu))
+        return(-EINVAL);
+
+    switch (piowr->ioctl) {
+      case GDTIOCTL_GENERAL:
+        if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0]))
+            return(-EINVAL);
+        pcmd = (gdth_cmd_str *)piowr->iu.general.command;
+        pcmd->Service = piowr->service;
+        if (pcmd->OpCode == GDT_IOCTL) {
+            ppadd = &pcmd->u.ioctl.p_param;
+            add_size = pcmd->u.ioctl.param_size;
+        } else if (piowr->service == CACHESERVICE) {
+            add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE;
+            if (ha->cache_feat & SCATTER_GATHER) {
+                ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr;
+                pcmd->u.cache.DestAddr = -1UL;
+                pcmd->u.cache.sg_lst[0].sg_len = add_size;
+                pcmd->u.cache.sg_canz = 1;
+            } else {
+                ppadd = &pcmd->u.cache.DestAddr;
+                pcmd->u.cache.sg_canz = 0;
+            }
+        } else if (piowr->service == SCSIRAWSERVICE) {
+            add_size = pcmd->u.raw.sdlen;
+            if (ha->raw_feat & SCATTER_GATHER) {
+                ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
+                pcmd->u.raw.sdata = -1UL;
+                pcmd->u.raw.sg_lst[0].sg_len = add_size;
+                pcmd->u.raw.sg_ranz = 1;
+            } else {
+                ppadd = &pcmd->u.raw.sdata;
+                pcmd->u.raw.sg_ranz = 0;
+            }
+        } else {
+            return(-EINVAL);
+        }
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) + add_size );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+
+        piord->size = sizeof(gdth_iord_str) + add_size;
+        if (add_size > 0) {
+            memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
+            *ppadd = (ulong)piord->iu.general.data;
+        }
+        /* do IOCTL */
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            scp.request.rq_status = RQ_SCSI_BUSY;
+            scp.request.sem = &sem;
+            scp.SCp.this_residual = IOCTL_PRI;
+            scsi_do_cmd(&scp, cmnd, pcmd,
+                        sizeof(gdth_cmd_str), gdth_scsi_done,
+                        piowr->timeout*HZ, 1);
+            down(&sem);
+            piord->status = (ulong)scp.SCp.Message;
+        }
+        break;
+
+      case GDTIOCTL_DRVERS:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
+        break;
+
+      case GDTIOCTL_CTRTYPE:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
+            piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 10);
+        } else if (ha->type != GDT_PCIMPR) {
+            piord->iu.ctrtype.type = (unchar)((ha->stype<<8) + 6);
+        } else {
+            piord->iu.ctrtype.type = 0xfe;
+            piord->iu.ctrtype.ext_type = 0x6000 | ha->stype;
+        }
+        piord->iu.ctrtype.info = ha->brd_phys;
+        piord->iu.ctrtype.oem_id = (ushort)GDT3_ID;
+        break;
+
+      case GDTIOCTL_CTRCNT:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        piord->iu.ctrcnt.count = (ushort)gdth_ctr_count;
+        break;
+
+      case GDTIOCTL_OSVERS:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16);
+        piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
+        piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
+        break;
+
+      case GDTIOCTL_LOCKDRV:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        for (i = k = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) {
+            found = FALSE;
+            for (j = 0; j < ha->bus_cnt; ++j) {
+                for (k = 0; k < MAXID; ++k) {
+                    if (ha->id[j][k].type == CACHE_DTYP &&
+                        ha->id[j][k].hostdrive == piowr->iu.lockdrv.drives[i]) {
+                        found = TRUE;
+                        break;
+                    }
+                }
+                if (found)
+                    break;
+            }
+            if (!found)
+                continue;
+
+            if (piowr->iu.lockdrv.lock) {
+                save_flags( flags );
+                cli();
+                ha->id[j][k].lock = 1;
+                restore_flags( flags );
+                gdth_wait_completion( hanum, j, k );
+                gdth_stop_timeout( hanum, j, k );
+            } else {
+                save_flags( flags );
+                cli();
+                ha->id[j][k].lock = 0;
+                restore_flags( flags );
+                gdth_start_timeout( hanum, j, k );
+                gdth_next( hanum );
+            }
+        }
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        break;
+
+      case GDTIOCTL_LOCKCHN:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        for (k = 0, j = piowr->iu.lockchn.channel; k < MAXID; ++k) {
+            if (ha->id[j][k].type != RAW_DTYP)
+                continue;
+
+            if (piowr->iu.lockchn.lock) {
+                save_flags( flags );
+                cli();
+                ha->id[j][k].lock = 1;
+                restore_flags( flags );
+                gdth_wait_completion( hanum, j, k );
+                gdth_stop_timeout( hanum, j, k );
+            } else {
+                save_flags( flags );
+                cli();
+                ha->id[j][k].lock = 0;
+                restore_flags( flags );
+                gdth_start_timeout( hanum, j, k );
+                gdth_next( hanum );
+            }
+        }
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        break;
+
+      case GDTIOCTL_EVENT:
+        id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+        if (id == -1)
+            return(-EBUSY);
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        if (piowr->iu.event.erase == 0) {
+            piord->iu.event.handle = gdth_read_event( piowr->iu.event.handle,
+                (gdth_evt_str *)piord->iu.event.evt );
+        } else {
+            piord->iu.event.handle = piowr->iu.event.handle;
+            gdth_readapp_event( (unchar)piowr->iu.event.erase,
+                (gdth_evt_str *)piord->iu.event.evt );
+        }
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        break;
+
+      default:
+        return(-EINVAL);
+    }
+    /* we return a buffer ID to detect the right buffer during READ-IOCTL */
+    return id;
+}
+
+static int gdth_get_info(char *buffer,char **start,off_t offset,
+                         int length,int vh,int hanum,int busnum)
+{
+    int size = 0,len = 0;
+    off_t begin = 0,pos = 0;
+    gdth_ha_str *ha;
+    gdth_iord_str *piord;
+    int id;
+
+    TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    id = length;
+
+    /* look for buffer ID in length */
+    if (id > 4) {
+#if LINUX_VERSION_CODE >= 0x010400
+        size = sprintf(buffer+len,
+                       "%s SCSI Disk Array Controller\n",
+                       gdth_ctr_name(hanum));
+#else
+        size = sprintf(buffer+len,
+                       "%s SCSI Disk Array Controller (SCSI Bus %d)\n",
+                       gdth_ctr_name(hanum),busnum);
+#endif
+        len += size;  pos = begin + len;
+        size = sprintf(buffer+len,
+                       "Firmware Version: %d.%2d\tDriver Version: %s\n",
+                       (unchar)(ha->cpar.version>>8),
+                       (unchar)(ha->cpar.version),GDTH_VERSION_STR);
+        len += size;  pos = begin + len;
+ 
+        if (pos < offset) {
+            len = 0;
+            begin = pos;
+        }
+        if (pos > offset + length)
+            goto stop_output;
+
+    } else {
+        piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+        if (piord == NULL)
+            goto stop_output;
+        length = piord->size;
+        memcpy(buffer+len, (char *)piord, length);
+        gdth_ioctl_free(hanum, id);
+        len += length; pos = begin + len;
+
+        if (pos < offset) {
+            len = 0;
+            begin = pos;
+        }
+        if (pos > offset + length)
+            goto stop_output;
+    }
+
+stop_output:
+    *start = buffer +(offset-begin);
+    len -= (offset-begin);
+    if (len > length)
+        len = length;
+    TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
+            len,pos,begin,offset,length,size));
+    return(len);
+}
+
+
+void gdth_scsi_done(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_scsi_done()\n"));
+
+    scp->request.rq_status = RQ_SCSI_DONE;
+
+    if (scp->request.sem != NULL)
+        up(scp->request.sem);
+}
+
+static int gdth_ioctl_alloc(int hanum, ushort size)
+{
+    ulong flags;
+    int i;
+
+    if (size == 0)
+        return -1;
+
+    save_flags(flags);
+    cli();
+
+    for (i = 0; i < 4; ++i) {
+        if (gdth_ioctl_tab[i][hanum] == NULL) {
+            gdth_ioctl_tab[i][hanum] = kmalloc( size, GFP_ATOMIC | GFP_DMA );
+            break;
+        }
+    }
+
+    restore_flags(flags);
+    if (i == 4 || gdth_ioctl_tab[i][hanum] == NULL)
+        return -1;
+    return (i+1);
+}
+
+static void gdth_ioctl_free(int hanum, int idx)
+{
+    ulong flags;
+
+    save_flags(flags);
+    cli();
+
+    kfree( gdth_ioctl_tab[idx-1][hanum] );
+    gdth_ioctl_tab[idx-1][hanum] = NULL;
+
+    restore_flags(flags);
+}
+
+static void gdth_wait_completion(int hanum, int busnum, int id)
+{
+    ulong flags;
+    int i;
+    Scsi_Cmnd *scp;
+
+    save_flags(flags);
+    cli();
+
+    for (i = 0; i < GDTH_MAXCMDS; ++i) {
+        scp = gdth_cmd_tab[i][hanum].cmnd;
+        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+            scp->channel == (unchar)busnum)
+#else
+            NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+        {
+            restore_flags(flags);
+            while (!scp->SCp.have_data_in)
+                barrier();
+            save_flags(flags);
+            cli();
+        }
+    }
+    restore_flags(flags);
+}
+
+static void gdth_stop_timeout(int hanum, int busnum, int id)
+{
+    ulong flags;
+    Scsi_Cmnd *scp;
+    gdth_ha_str *ha;
+
+    save_flags(flags);
+    cli();
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+        if (scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+            scp->channel == (unchar)busnum)
+#else
+            NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+        {
+            TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
+            scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+        }
+    }
+    restore_flags(flags);
+}
+
+static void gdth_start_timeout(int hanum, int busnum, int id)
+{
+    ulong flags;
+    Scsi_Cmnd *scp;
+    gdth_ha_str *ha;
+
+    save_flags(flags);
+    cli();
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+        if (scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+            scp->channel == (unchar)busnum)
+#else
+            NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+        {
+            TRACE2(("gdth_start_timeout(): update_timeout()\n"));
+            gdth_update_timeout(scp, scp->SCp.buffers_residual);
+        }
+    }
+    restore_flags(flags);
+}
+
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
+{
+    ulong flags;
+    int oldto;
+
+    save_flags(flags);
+    cli();
+
+    oldto = scp->timeout;
+    scp->timeout = timeout;
+    if (timeout > 0) {
+        if (timer_table[SCSI_TIMER].expires == 0) {
+            timer_table[SCSI_TIMER].expires = jiffies + timeout;
+            timer_active |= 1 << SCSI_TIMER;
+        } else {
+            if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
+                timer_table[SCSI_TIMER].expires = jiffies + timeout;
+        }
+    }
+
+    restore_flags(flags);
+    return oldto;
+}
+
diff -urN linux-2.0.31-pre2/drivers/scsi/gdth_proc.h linux-2.0.31-pre3/drivers/scsi/gdth_proc.h
--- linux-2.0.31-pre2/drivers/scsi/gdth_proc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/drivers/scsi/gdth_proc.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,24 @@
+#ifndef _GDTH_PROC_H
+#define _GDTH_PROC_H
+
+/* gdth_proc.h 
+ * $Id: gdth_proc.h,v 1.2 1997/02/21 08:08:51 achim Exp $
+ */
+
+static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_get_info(char *buffer,char **start,off_t offset,
+                         int length,int vh,int hanum,int busnum);
+
+static int gdth_ioctl_alloc(int hanum, ushort size);
+static void gdth_ioctl_free(int hanum, int id);
+static void gdth_wait_completion(int hanum, int busnum, int id);
+static void gdth_stop_timeout(int hanum, int busnum, int id);
+static void gdth_start_timeout(int hanum, int busnum, int id);
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
+
+void gdth_scsi_done(Scsi_Cmnd *scp);
+
+#endif
+
diff -urN linux-2.0.31-pre2/drivers/scsi/hosts.c linux-2.0.31-pre3/drivers/scsi/hosts.c
--- linux-2.0.31-pre2/drivers/scsi/hosts.c	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/drivers/scsi/hosts.c	2003-08-15 15:03:53.000000000 -0700
@@ -169,6 +169,10 @@
 #include "ide-scsi.h"
 #endif
 
+#ifdef CONFIG_SCSI_GDTH
+#include "gdth.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -307,6 +311,9 @@
 #ifdef CONFIG_SCSI_SUNESP
     SCSI_SPARC_ESP,
 #endif
+#ifdef CONFIG_SCSI_GDTH
+    GDTH,
+#endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
     IDESCSI,
 #endif
diff -urN linux-2.0.31-pre2/drivers/scsi/Makefile linux-2.0.31-pre3/drivers/scsi/Makefile
--- linux-2.0.31-pre2/drivers/scsi/Makefile	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/drivers/scsi/Makefile	2003-08-15 15:03:53.000000000 -0700
@@ -19,6 +19,7 @@
 SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
 
 AHA152X	= -DDEBUG_AHA152X -DAUTOCONF
+GDTH = #-DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
 
 .SUFFIXES:
 .SUFFIXES: .c .o .h .a
@@ -225,6 +226,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_GDTH),y)
+L_OBJS += gdth.o
+else
+  ifeq ($(CONFIG_SCSI_GDTH),m)
+  M_OBJS += gdth.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DEBUG),y)
 L_OBJS += scsi_debug.o
 else
@@ -364,6 +373,9 @@
 aha152x.o: aha152x.c
 	$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
+gdth.o: gdth.c gdth.h gdth_proc.c gdth_proc.h
+	$(CC) $(CFLAGS) $(GDTH) -c gdth.c 
+
 aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
 	$(CC) $(CFLAGS) -c -o $@ aic7xxx.c
 
diff -urN linux-2.0.31-pre2/include/linux/b1lli.h linux-2.0.31-pre3/include/linux/b1lli.h
--- linux-2.0.31-pre2/include/linux/b1lli.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/include/linux/b1lli.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,141 @@
+/*
+ * $Id: b1lli.h,v 1.1 1997/03/04 21:27:32 calle Exp $
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+ * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1lli.h,v $
+ * Revision 1.1  1997/03/04 21:27:32  calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ */
+
+#ifndef _B1LLI_H_
+#define _B1LLI_H_
+/*
+ * struct for loading t4 file 
+ */
+typedef struct avmb1_t4file {
+	int len;
+	unsigned char *data;
+} avmb1_t4file;
+
+typedef struct avmb1_loaddef {
+	int contr;
+	avmb1_t4file t4file;
+} avmb1_loaddef;
+
+typedef struct avmb1_resetdef {
+	int contr;
+} avmb1_resetdef;
+
+/*
+ * struct for adding new cards 
+ */
+typedef struct avmb1_carddef {
+	int port;
+	int irq;
+} avmb1_carddef;
+
+#define	AVMB1_LOAD	0	/* load image to card */
+#define AVMB1_ADDCARD	1	/* add a new card */
+#define AVMB1_RESETCARD	2	/* reset a card */
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * card states for startup
+ */
+
+#define CARD_NONE	0
+#define CARD_DETECTED	1
+#define CARD_LOADING	2
+#define CARD_INITSTATE	4
+#define CARD_RUNNING	5
+#define CARD_ACTIVE	6
+
+#define	AVMB1_PORTLEN	0x1f
+
+#define AVM_MAXVERSION	8
+#define AVM_NBCHAN	2
+
+#define AVM_NAPPS	30
+#define AVM_NPLCI	5
+#define AVM_NNCCI	6
+
+/*
+ * Main driver data
+ */
+
+typedef struct avmb1_card {
+	struct avmb1_card *next;
+	int cnr;
+	unsigned short port;
+	unsigned irq;
+	volatile unsigned short cardstate;
+	int interrupt;
+	int blocked;
+	int versionlen;
+	char versionbuf[1024];
+	char *version[AVM_MAXVERSION];
+	char msgbuf[128];	/* capimsg msg part */
+	char databuf[2048];	/* capimsg data part */
+	capi_version cversion;
+	char name[10];
+} avmb1_card;
+
+/*
+ * Versions
+ */
+
+#define	VER_DRIVER	0
+#define	VER_CARDTYPE	1
+#define	VER_HWID	2
+#define	VER_SERIAL	3
+#define	VER_OPTION	4
+#define	VER_PROTO	5
+#define	VER_PROFILE	6
+#define	VER_CAPI	7
+
+
+/* b1lli.c */
+int B1_detect(unsigned short base);
+void B1_reset(unsigned short base);
+int B1_load_t4file(unsigned short base, avmb1_t4file * t4file);
+int B1_loaded(unsigned short base);
+unsigned char B1_assign_irq(unsigned short base, unsigned irq);
+unsigned char B1_enable_irq(unsigned short base);
+unsigned char B1_disable_irq(unsigned short base);
+int B1_valid_irq(unsigned irq);
+void B1_handle_interrupt(avmb1_card * card);
+void B1_send_init(unsigned short port,
+	    unsigned int napps, unsigned int nncci, unsigned int cardnr);
+void B1_send_register(unsigned short port,
+		      __u16 appid, __u32 nmsg,
+		      __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize);
+void B1_send_release(unsigned short port, __u16 appid);
+void B1_send_message(unsigned short port, struct sk_buff *skb);
+
+/* b1capi.c */
+void avmb1_handle_new_ncci(avmb1_card * card,
+			   __u16 appl, __u32 ncci, __u32 winsize);
+void avmb1_handle_free_ncci(avmb1_card * card,
+			    __u16 appl, __u32 ncci);
+void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb);
+void avmb1_card_ready(avmb1_card * card);
+
+int avmb1_addcard(int port, int irq);
+int avmb1_probecard(int port, int irq);
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _B1LLI_H_ */
diff -urN linux-2.0.31-pre2/include/linux/capi.h linux-2.0.31-pre3/include/linux/capi.h
--- linux-2.0.31-pre2/include/linux/capi.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/include/linux/capi.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,127 @@
+/*
+ * $Id: capi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ * 
+ * CAPI 2.0 Interface for Linux
+ * 
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: capi.h,v $
+ * Revision 1.1  1997/03/04 21:27:33  calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+
+#ifndef __LINUX_CAPI_H__
+#define __LINUX_CAPI_H__
+
+#include <asm/types.h>
+#include <linux/ioctl.h>
+#ifndef __KERNEL__
+#include <linux/kernelcapi.h>
+#endif
+
+/*
+ * CAPI_REGISTER
+ */
+
+typedef struct capi_register_params {	/* CAPI_REGISTER */
+	__u32 level3cnt;	/* No. of simulatneous user data connections */
+	__u32 datablkcnt;	/* No. of buffered data messages */
+	__u32 datablklen;	/* Size of buffered data messages */
+} capi_register_params;
+
+#define	CAPI_REGISTER	_IOW('C',0x01,struct capi_register_params)
+
+/*
+ * CAPI_GET_MANUFACTURER
+ */
+
+#define CAPI_MANUFACTURER_LEN		64
+
+#define	CAPI_GET_MANUFACTURER	_IOWR('C',0x06,CAPI_MANUFACTURER_LEN)
+
+/*
+ * CAPI_GET_VERSION
+ */
+
+typedef struct capi_version {
+	__u32 majorversion;
+	__u32 minorversion;
+	__u32 majormanuversion;
+	__u32 minormanuversion;
+} capi_version;
+
+#define CAPI_GET_VERSION	_IOWR('C',0x07,struct capi_version)
+
+/*
+ * CAPI_GET_SERIAL
+ */
+
+#define CAPI_SERIAL_LEN		8
+#define CAPI_GET_SERIAL		_IOWR('C',0x08, CAPI_SERIAL_LEN)
+
+/*
+ * CAPI_GET_PROFILE
+ */
+
+typedef struct capi_profile {
+	__u16 ncontroller;	/* number of installed controller */
+	__u16 nbchannel;	/* number of B-Channels */
+	__u32 goptions;		/* global options */
+	__u32 support1;		/* B1 protocols support */
+	__u32 support2;		/* B2 protocols support */
+	__u32 support3;		/* B3 protocols support */
+	__u32 reserved[6];	/* reserved */
+	__u32 manu[5];		/* manufacturer specific information */
+} capi_profile;
+
+#define CAPI_GET_PROFILE	_IOWR('C',0x09,struct capi_profile)
+
+typedef struct capi_manufacturer_cmd {
+	unsigned long cmd;
+	void *data;
+} capi_manufacturer_cmd;
+
+/*
+ * CAPI_MANUFACTURER_CMD
+ */
+
+#define CAPI_MANUFACTURER_CMD	_IOWR('C',0x20, struct capi_manufacturer_cmd)
+
+/*
+ * CAPI_GET_ERRCODE
+ * capi errcode is set, * if read, write, or ioctl returns EIO,
+ * ioctl returns errcode directly, and in arg, if != 0
+ */
+
+#define CAPI_GET_ERRCODE	_IOR('C',0x21, __u16)
+
+/*
+ * CAPI_INSTALLED
+ */
+#define CAPI_INSTALLED		_IOR('C',0x22, __u16)
+
+/*
+ * member contr is input for
+ * CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL
+ * and CAPI_GET_PROFILE
+ */
+typedef union capi_ioctl_struct {
+	__u32 contr;
+	capi_register_params rparams;
+	__u8 manufacturer[CAPI_MANUFACTURER_LEN];
+	capi_version version;
+	__u8 serial[CAPI_SERIAL_LEN];
+	capi_profile profile;
+	capi_manufacturer_cmd cmd;
+	__u16 errcode;
+} capi_ioctl_struct;
+
+#endif				/* __LINUX_CAPI_H__ */
diff -urN linux-2.0.31-pre2/include/linux/isdn.h linux-2.0.31-pre3/include/linux/isdn.h
--- linux-2.0.31-pre2/include/linux/isdn.h	1996-12-01 10:02:03.000000000 -0800
+++ linux-2.0.31-pre3/include/linux/isdn.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.18 1996/11/06 17:37:50 keil Exp $
+/* $Id: isdn.h,v 1.30 1997/06/17 13:07:23 hipp Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,49 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.30  1997/06/17 13:07:23  hipp
+ * compression changes , MP changes
+ *
+ * Revision 1.29  1997/05/27 15:18:02  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.28  1997/03/07 01:33:01  fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.27  1997/03/05 21:11:49  fritz
+ * Minor fixes.
+ *
+ * Revision 1.26  1997/02/28 02:37:53  fritz
+ * Added some comments.
+ *
+ * Revision 1.25  1997/02/23 16:54:23  hipp
+ * some initial changes for future PPP compresion
+ *
+ * Revision 1.24  1997/02/18 09:42:45  fritz
+ * Bugfix: Increased ISDN_MODEM_ANZREG.
+ * Increased TTY_DV.
+ *
+ * Revision 1.23  1997/02/10 22:07:13  fritz
+ * Added 2 modem registers for numbering plan and screening info.
+ *
+ * Revision 1.22  1997/02/03 23:42:08  fritz
+ * Added ISDN_TIMER_RINGING
+ * Misc. changes for Kernel 2.1.X compatibility
+ *
+ * Revision 1.21  1997/01/17 01:19:10  fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.20  1997/01/17 00:41:19  fritz
+ * Increased TTY_DV.
+ *
+ * Revision 1.19  1997/01/14 01:41:07  fritz
+ * Added ATI2 related variables.
+ * Added variables for audio support in skbuffs.
+ *
  * Revision 1.18  1996/11/06 17:37:50  keil
  * more changes for 2.1.X
  *
@@ -159,7 +202,7 @@
 #define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
 #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing  */
 
-#define ISDN_MODEM_ANZREG    21        /* Number of Modem-Registers        */
+#define ISDN_MODEM_ANZREG    23        /* Number of Modem-Registers        */
 #define ISDN_MSNLEN          20
 
 typedef struct {
@@ -175,12 +218,12 @@
 
 typedef struct {
   char name[10];
-  char phone[20];
+  char phone[ISDN_MSNLEN];
   int  outgoing;
 } isdn_net_ioctl_phone;
 
-#define NET_DV 0x01 /* Data version for net_cfg     */
-#define TTY_DV 0x01 /* Data version for iprofd etc. */
+#define NET_DV 0x03 /* Data version for net_cfg     */
+#define TTY_DV 0x04 /* Data version for iprofd etc. */
 
 typedef struct {
   char name[10];     /* Name of interface                     */
@@ -196,6 +239,7 @@
   int  exclusive;    /* Channel, if bound exclusive           */
   int  dialmax;      /* Dial Retry-Counter                    */
   int  slavedelay;   /* Delay until slave starts up           */
+  int  triggercps;   /* BogoCPS needed for triggering slave   */
   int  cbdelay;      /* Delay before Callback                 */
   int  chargehup;    /* Flag: Charge-Hangup                   */
   int  ihup;         /* Flag: Hangup-Timeout on incoming line */
@@ -203,6 +247,7 @@
   int  callback;     /* Flag: Callback                        */
   int  cbhup;        /* Flag: Reject Call before Callback     */
   int  pppbind;      /* ippp device for bindings              */
+  int  chargeint;    /* Use fixed charge interval length      */
 } isdn_net_ioctl_cfg;
 
 #ifdef __KERNEL__
@@ -279,6 +324,7 @@
 #define ISDN_TIMER_RES       3                     /* Main Timer-Resolution  */
 #define ISDN_TIMER_02SEC     (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */
 #define ISDN_TIMER_1SEC      (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec   */
+#define ISDN_TIMER_RINGING   5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */
 #define ISDN_TIMER_MODEMREAD 1
 #define ISDN_TIMER_MODEMPLUS 2
 #define ISDN_TIMER_MODEMRING 4
@@ -317,7 +363,7 @@
 /* Phone-list-element */
 typedef struct {
   void *next;
-  char num[20];
+  char num[ISDN_MSNLEN];
 } isdn_net_phone;
 
 /* Local interface-data */
@@ -361,6 +407,7 @@
 				       /* bit0: chargeint is invalid       */
 				       /* bit1: Getting charge-interval    */
                                        /* bit2: Do charge-unit-hangup      */
+                                       /* bit3: Do hangup even on incoming */
   int                    outgoing;     /* Flag: outgoing call              */
   int                    onhtime;      /* Time to keep link up             */
   int                    chargeint;    /* Interval between charge-infos    */
@@ -370,6 +417,7 @@
   int                    sqfull;       /* Flag: netdev-queue overloaded    */
   ulong                  sqfull_stamp; /* Start-Time of overload           */
   ulong                  slavedelay;   /* Dynamic bundling delaytime       */
+  int                    triggercps;   /* BogoCPS needed for trigger slave */
   struct device          *srobin;      /* Ptr to Master device for slaves  */
   isdn_net_phone         *phone[2];    /* List of remote-phonenumbers      */
 				       /* phone[0] = Incoming Numbers      */
@@ -382,11 +430,28 @@
   struct isdn_net_dev_s  *netdev;      /* Ptr to netdev                    */
   struct sk_buff         *first_skb;   /* Ptr to skb that triggers dialing */
   struct sk_buff         *sav_skb;     /* Ptr to skb, rejected by LL-driver*/
+#if (LINUX_VERSION_CODE < 0x02010F)
                                        /* Ptr to orig. header_cache_bind   */
-  void                   (*org_hcb)(struct hh_cache **, struct device *,
-                                    unsigned short, __u32);
+  void                   (*org_hcb)(struct hh_cache **,
+				    struct device *,
+                                    unsigned short, 
+				    __u32);
+#else
+#if (LINUX_VERSION_CODE < 0x2011E)
+                                       /* Ptr to orig. hard_header_cache   */
+  int                    (*org_hhc)(struct dst_entry *dst,
+				    struct dst_entry *neigh,
+				    struct hh_cache *hh);
+#else
+                                       /* Ptr to orig. hard_header_cache   */
+  int                    (*org_hhc)(struct dst_entry *dst,
+				    struct neighbour *neigh,
+				    struct hh_cache *hh);
+#endif
+#endif
                                        /* Ptr to orig. header_cache_update */
-  void                   (*org_hcu)(struct hh_cache *, struct device *,
+  void                   (*org_hcu)(struct hh_cache *,
+				    struct device *,
                                     unsigned char *);
   int  pppbind;                        /* ippp device for bindings         */
 } isdn_net_local;
@@ -435,17 +500,35 @@
 #define ISDN_SERIAL_TYPE_NORMAL            1
 #define ISDN_SERIAL_TYPE_CALLOUT           2
 
+#ifdef CONFIG_ISDN_AUDIO
+/* For using sk_buffs with audio we need some private variables
+ * within each sk_buff. For this purpose, we declare a struct here,
+ * and put it always at skb->head. A few macros help accessing the
+ * variables. Of course, we need to check skb_headroom prior to
+ * any access.
+ */
+typedef struct isdn_audio_skb {
+  unsigned short dle_count;
+  unsigned char  lock;
+} isdn_audio_skb;
+
+#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_skb*)skb->head)->dle_count)
+#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_skb*)skb->head)->lock)
+#endif
+
 /* Private data of AT-command-interpreter */
 typedef struct atemu {
   u_char              profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */
   u_char              mdmreg[ISDN_MODEM_ANZREG];  /* Modem-Registers       */
   char                pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0             */
   char                msn[ISDN_MSNLEN];/* EAZ/MSN                          */
+#ifdef CONFIG_ISDN_AUDIO
   u_char              vpar[10];        /* Voice-parameters                 */
+  int                 lastDLE;         /* Flag for voice-coding: DLE seen  */
+#endif
   int                 mdmcmdl;         /* Length of Modem-Commandbuffer    */
   int                 pluscount;       /* Counter for +++ sequence         */
   int                 lastplus;        /* Timestamp of last +              */
-  int                 lastDLE;         /* Flag for voice-coding: DLE seen  */
   char                mdmcmd[255];     /* Modem-Commandbuffer              */
 } atemu;
 
@@ -462,26 +545,39 @@
   int			blocked_open;	 /* # of blocked opens             */
   long			session;	 /* Session of opening process     */
   long			pgrp;		 /* pgrp of opening process        */
-  int                   online;          /* B-Channel is up                */
-  int                   vonline;         /* Voice-channel status           */
+  int                   online;          /* 1 = B-Channel is up, drop data */
+					 /* 2 = B-Channel is up, deliver d.*/
   int                   dialing;         /* Dial in progress               */
   int                   rcvsched;        /* Receive needs schedule         */
   int                   isdn_driver;	 /* Index to isdn-driver           */
   int                   isdn_channel;    /* Index to isdn-channel          */
   int                   drv_index;       /* Index to dev->usage            */
   int                   ncarrier;        /* Flag: schedule NO CARRIER      */
+  unsigned char         last_cause[8];   /* Last cause message             */
+  unsigned char         last_num[ISDN_MSNLEN];
+	                                 /* Last phone-number              */
+  unsigned char         last_l2;         /* Last layer-2 protocol          */
+  unsigned char         last_si;         /* Last service                   */
+  unsigned char         last_lhup;       /* Last hangup local?             */
+  unsigned char         last_dir;        /* Last direction (in or out)     */
   struct timer_list     nc_timer;        /* Timer for delayed NO CARRIER   */
   int                   send_outstanding;/* # of outstanding send-requests */
   int                   xmit_size;       /* max. # of chars in xmit_buf    */
   int                   xmit_count;      /* # of chars in xmit_buf         */
   unsigned char         *xmit_buf;       /* transmit buffer                */
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
+#ifdef CONFIG_ISDN_AUDIO
+  int                   vonline;         /* Voice-channel status           */
+					 /* Bit 0 = recording              */
+					 /* Bit 1 = playback               */
+					 /* Bit 2 = playback, DLE-ETX seen */
   struct sk_buff_head   dtmf_queue;      /* queue for dtmf results         */
-  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
-  atemu                 emu;             /* AT-emulator data               */
   void                  *adpcms;         /* state for adpcm decompression  */
   void                  *adpcmr;         /* state for adpcm compression    */
   void                  *dtmf_state;     /* state for dtmf decoder         */
+#endif
+  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
+  atemu                 emu;             /* AT-emulator data               */
   struct termios	normal_termios;  /* For saving termios structs     */
   struct termios	callout_termios;
   struct wait_queue	*open_wait;
@@ -513,8 +609,8 @@
 
 struct sqqueue {
   struct sqqueue *next;
-  int sqno_start;
-  int sqno_end;
+  long sqno_start;
+  long sqno_end;
   struct sk_buff *skb;
   long timer;
 };
@@ -522,7 +618,7 @@
 struct mpqueue {
   struct mpqueue *next;
   struct mpqueue *last;
-  int    sqno;
+  long sqno;
   struct sk_buff *skb;
   int BEbyte;
   unsigned long time;
@@ -561,6 +657,8 @@
   struct slcompress *slcomp;
 #endif
   unsigned long debug;
+  struct isdn_ppp_compressor *compressor,*link_compressor;
+  void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
 };
 
 #endif
@@ -588,7 +686,9 @@
   isdn_if            *interface;        /* Interface to driver              */
   int                *rcverr;           /* Error-counters for B-Ch.-receive */
   int                *rcvcount;         /* Byte-counters for B-Ch.-receive  */
+#ifdef CONFIG_ISDN_AUDIO
   unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
+#endif
   struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
   struct wait_queue  **rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
   struct wait_queue  **snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
@@ -612,7 +712,8 @@
   int               chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel  */
   int               drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index    */
   int               usage[ISDN_MAX_CHANNELS];  /* Used by tty/ip/voice       */
-  char              num[ISDN_MAX_CHANNELS][20];/* Remote number of active ch.*/
+  char              num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+                                               /* Remote number of active ch.*/
   int               m_idx[ISDN_MAX_CHANNELS];  /* Index for mdm....          */
   driver            *drv[ISDN_MAX_DRIVERS];    /* Array of drivers           */
   isdn_net_dev      *netdev;		       /* Linked list of net-if's    */
diff -urN linux-2.0.31-pre2/include/linux/isdnif.h linux-2.0.31-pre3/include/linux/isdnif.h
--- linux-2.0.31-pre2/include/linux/isdnif.h	1996-12-01 10:01:37.000000000 -0800
+++ linux-2.0.31-pre3/include/linux/isdnif.h	2003-08-15 15:03:53.000000000 -0700
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.13 1996/11/13 02:39:59 fritz Exp $
+/* $Id: isdnif.h,v 1.20 1997/05/27 15:18:06 fritz Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,32 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.20  1997/05/27 15:18:06  fritz
+ * Added changes for recent 2.1.x kernels:
+ *   changed return type of isdn_close
+ *   queue_task_* -> queue_task
+ *   clear/set_bit -> test_and_... where apropriate.
+ *   changed type of hard_header_cache parameter.
+ *
+ * Revision 1.19  1997/03/25 23:13:56  keil
+ * NI-1 US protocol
+ *
+ * Revision 1.18  1997/03/04 22:09:18  calle
+ * Change macros copy_from_user and copy_to_user in inline function.
+ * These are now correct replacements of the functions for 2.1.xx
+ *
+ * Revision 1.17  1997/02/10 21:12:53  fritz
+ * More setup-interface changes.
+ *
+ * Revision 1.16  1997/02/10 19:42:57  fritz
+ * New interface for reporting incoming calls.
+ *
+ * Revision 1.15  1997/02/09 00:18:42  keil
+ * leased line support
+ *
+ * Revision 1.14  1997/02/03 23:43:00  fritz
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
  * Revision 1.13  1996/11/13 02:39:59  fritz
  * More compatibility changes.
  *
@@ -76,6 +102,8 @@
 #define ISDN_PTYPE_UNKNOWN   0   /* Protocol undefined   */
 #define ISDN_PTYPE_1TR6      1   /* german 1TR6-protocol */
 #define ISDN_PTYPE_EURO      2   /* EDSS1-protocol       */
+#define ISDN_PTYPE_LEASED    3   /* for leased lines     */
+#define ISDN_PTYPE_NI1       4   /* US NI-1 protocol     */
 
 /*
  * Values for Layer-2-protocol-selection
@@ -156,6 +184,16 @@
 #define ISDN_FEATURE_P_UNKNOWN  (0x1000 << ISDN_PTYPE_UNKNOWN)
 #define ISDN_FEATURE_P_1TR6     (0x1000 << ISDN_PTYPE_1TR6)
 #define ISDN_FEATURE_P_EURO     (0x1000 << ISDN_PTYPE_EURO)
+#define ISDN_FEATURE_P_NI1      (0x1000 << ISDN_PTYPE_NI1)
+
+typedef struct setup_parm {
+    char phone[32];         /* Remote Phone-Number */
+    char eazmsn[32];        /* Local EAZ or MSN    */
+    unsigned char si1;      /* Service Indicator 1 */
+    unsigned char si2;      /* Service Indicator 2 */
+    unsigned char plan;     /* Numbering plan      */
+    unsigned char screen;   /* Screening info      */
+} setup_parm;
 
 /*
  * Structure for exchanging above infos
@@ -165,7 +203,10 @@
   int   driver;                  /* Lowlevel-Driver-ID                    */
   int   command;                 /* Command or Status (see above)         */
   ulong arg;                     /* Additional Data                       */
-  char  num[50];                 /* Additional Data                       */
+  union {
+	char  num[50];               /* Additional Data                       */
+	setup_parm setup;
+  } parm;
 } isdn_ctrl;
 
 /*
@@ -321,8 +362,25 @@
 #endif
 #if (LINUX_VERSION_CODE < 0x020100)
 #include <linux/mm.h>
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
+
+static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n)
+{
+	int i;
+	if ((i = verify_area(VERIFY_READ, from, n)) != 0)
+		return i;
+	memcpy_fromfs(to, from, n);
+	return 0;
+}
+
+static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n)
+{
+	int i;
+	if ((i = verify_area(VERIFY_WRITE, to, n)) != 0)
+		return i;
+	memcpy_tofs(to, from, n);
+	return 0;
+}
+
 #define GET_USER(x, addr) ( x = get_user(addr) )
 #define RWTYPE int
 #define LSTYPE int
@@ -338,6 +396,24 @@
 #define LSARG long long
 #endif
 
+#if (LINUX_VERSION_CODE < 0x02010F)
+#define SET_SKB_FREE(x) ( x->free = 1 )
+#else
+#define SET_SKB_FREE(x)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02011F)
+#define CLOSETYPE void
+#define CLOSEVAL
+#else
+#define CLOSETYPE int
+#define CLOSEVAL (0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020125)
+#define test_and_clear_bit clear_bit
+#define test_and_set_bit set_bit
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* isdnif_h */
-
diff -urN linux-2.0.31-pre2/include/linux/isdn_ppp.h linux-2.0.31-pre3/include/linux/isdn_ppp.h
--- linux-2.0.31-pre2/include/linux/isdn_ppp.h	1996-05-19 05:29:31.000000000 -0700
+++ linux-2.0.31-pre3/include/linux/isdn_ppp.h	2003-08-15 15:03:53.000000000 -0700
@@ -4,25 +4,29 @@
 extern int isdn_ppp_dial_slave(char *);
 extern int isdn_ppp_hangup_slave(char *);
 
-struct pppinfo
+#define CALLTYPE_INCOMING 0x1
+#define CALLTYPE_OUTGOING 0x2
+#define CALLTYPE_CALLBACK 0x4
+
+struct pppcallinfo
 {
-  int type; /* set by user */
-  union {
-    char clid[32]; /* calling ID */
-    int  bundles;
-    int  linknumber;
-  } info;
+	int calltype;
+	unsigned char local_num[64];
+	unsigned char remote_num[64];
+	int charge_units;
 };
 
- 
-#define PPPIOCLINKINFO _IOWR('t',128,struct pppinfo)
+#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
 #define PPPIOCBUNDLE   _IOW('t',129,int)
 #define PPPIOCGMPFLAGS _IOR('t',130,int)
 #define PPPIOCSMPFLAGS _IOW('t',131,int)
 #define PPPIOCSMPMTU   _IOW('t',132,int)
 #define PPPIOCSMPMRU   _IOW('t',133,int)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long)
+#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
 
-#define PPP_MP         0x003d
+#define PPP_MP          0x003d
+#define PPP_LINK_COMP   0x00fb
 
 #define SC_MP_PROT       0x00000200
 #define SC_REJ_MP_PROT   0x00000400
@@ -32,4 +36,36 @@
 #define MP_END_FRAG    0x40
 #define MP_BEGIN_FRAG  0x80
 
-#endif
+#ifdef __KERNEL__
+/*
+ * this is an 'old friend' from ppp-comp.h under a new name 
+ * check the original include for more information
+ */
+struct isdn_ppp_compressor {
+	struct isdn_ppp_compressor *next,*prev;
+	int num; /* CCP compression protocol number */
+	void *(*comp_alloc) (unsigned char *options, int opt_len);
+	void (*comp_free) (void *state);
+	int  (*comp_init) (void *state, unsigned char *options, int opt_len,
+		 int unit, int opthdr, int debug);
+	void (*comp_reset) (void *state);
+	int  (*compress) (void *state,struct sk_buff *in, struct sk_buff *skb_out,
+		 int proto);
+	void (*comp_stat) (void *state, struct compstat *stats);
+	void *(*decomp_alloc) (unsigned char *options, int opt_len);
+	void (*decomp_free) (void *state);
+	int  (*decomp_init) (void *state, unsigned char *options,
+			int opt_len, int unit, int opthdr, int mru, int debug);
+	void (*decomp_reset) (void *state);
+	int  (*decompress) (void *state, unsigned char *ibuf, int isize, unsigned char *obuf, int osize);
+	void (*incomp) (void *state, unsigned char *ibuf, int icnt);
+	void (*decomp_stat) (void *state, struct compstat *stats);
+};
+
+extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_ISDN_PPP_H */
+
diff -urN linux-2.0.31-pre2/include/linux/kernelcapi.h linux-2.0.31-pre3/include/linux/kernelcapi.h
--- linux-2.0.31-pre2/include/linux/kernelcapi.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre3/include/linux/kernelcapi.h	2003-08-15 15:03:53.000000000 -0700
@@ -0,0 +1,96 @@
+/*
+ * $Id: kernelcapi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ * 
+ * Kernel CAPI 2.0 Interface for Linux
+ * 
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: kernelcapi.h,v $
+ * Revision 1.1  1997/03/04 21:27:33  calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2  1997/02/12 09:31:39  calle
+ * new version
+ *
+ * Revision 1.1  1997/01/31 10:32:20  calle
+ * Initial revision
+ *
+ * 
+ */
+#ifndef __KERNEL_CAPI_H__
+#define __KERNEL_CAPI_H__
+
+#define CAPI_MAXAPPL	20	/*
+				   * maximum number of applications 
+				 */
+#define CAPI_MAXCONTR	4	/*
+				   * maximum number of controller 
+				 */
+#define CAPI_MAXDATAWINDOW	8
+
+#ifdef __KERNEL__
+
+struct capi_interface {
+	int (*capi_installed) (void);
+
+	 __u16(*capi_register) (capi_register_params * rparam, __u16 * applidp);
+	 __u16(*capi_release) (__u16 applid);
+	 __u16(*capi_put_message) (__u16 applid, struct sk_buff * msg);
+	 __u16(*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
+	 __u16(*capi_set_signal) (__u16 applid,
+			      void (*signal) (__u16 applid, __u32 param),
+				  __u32 param);
+	 __u16(*capi_get_manufacturer) (__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
+	 __u16(*capi_get_version) (__u16 contr, struct capi_version * verp);
+	 __u16(*capi_get_serial) (__u16 contr, __u8 serial[CAPI_SERIAL_LEN]);
+	 __u16(*capi_get_profile) (__u16 contr, struct capi_profile * profp);
+
+	/*
+	 * to init controllers, data is always in user memory
+	 */
+	int (*capi_manufacturer) (unsigned int cmd, void *data);
+
+};
+
+#define	KCI_CONTRUP	0
+#define	KCI_CONTRDOWN	1
+
+struct capi_interface_user {
+	char name[20];
+	void (*callback) (unsigned int cmd, __u16 contr, void *data);
+	struct capi_interface_user *next;
+};
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *);
+int detach_capi_interface(struct capi_interface_user *);
+
+
+#define CAPI_NOERROR                      0x0000
+
+#define CAPI_TOOMANYAPPLS		  0x1001
+#define CAPI_LOGBLKSIZETOSMALL	          0x1002
+#define CAPI_BUFFEXECEEDS64K 	          0x1003
+#define CAPI_MSGBUFSIZETOOSMALL	          0x1004
+#define CAPI_ANZLOGCONNNOTSUPPORTED	  0x1005
+#define CAPI_REGRESERVED		  0x1006
+#define CAPI_REGBUSY 		          0x1007
+#define CAPI_REGOSRESOURCEERR	          0x1008
+#define CAPI_REGNOTINSTALLED 	          0x1009
+#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP  0x100a
+#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b
+
+#define CAPI_ILLAPPNR		          0x1101
+#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL   0x1102
+#define CAPI_SENDQUEUEFULL		  0x1103
+#define CAPI_RECEIVEQUEUEEMPTY	          0x1104
+#define CAPI_RECEIVEOVERFLOW 	          0x1105
+#define CAPI_UNKNOWNNOTPAR		  0x1106
+#define CAPI_MSGBUSY 		          0x1107
+#define CAPI_MSGOSRESOURCEERR	          0x1108
+#define CAPI_MSGNOTINSTALLED 	          0x1109
+#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP  0x110a
+#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
+
+#endif				/* __KERNEL__ */
+
+#endif				/* __KERNEL_CAPI_H__ */
diff -urN linux-2.0.31-pre2/include/linux/pci.h linux-2.0.31-pre3/include/linux/pci.h
--- linux-2.0.31-pre2/include/linux/pci.h	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/include/linux/pci.h	2003-08-15 15:03:53.000000000 -0700
@@ -351,6 +351,10 @@
 #define PCI_VENDOR_ID_OAK		0x104e
 #define PCI_DEVICE_ID_OAK_OTI107	0x0107
 
+/* Winbond have two vendor ID! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2		0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
+
 #define PCI_VENDOR_ID_PROMISE		0x105a
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
@@ -507,6 +511,9 @@
 #define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
 
+#define PCI_VENDOR_ID_COMPEX		0x11f6
+#define PCI_DEVICE_ID_COMPEX_RL2000	0x1401
+
 #define PCI_VENDOR_ID_RP               0x11fe
 #define PCI_DEVICE_ID_RP8OCTA          0x0001
 #define PCI_DEVICE_ID_RP8INTF          0x0002
diff -urN linux-2.0.31-pre2/include/linux/proc_fs.h linux-2.0.31-pre3/include/linux/proc_fs.h
--- linux-2.0.31-pre2/include/linux/proc_fs.h	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/include/linux/proc_fs.h	2003-08-15 15:03:53.000000000 -0700
@@ -141,6 +141,7 @@
 	PROC_SCSI_A2091,
 	PROC_SCSI_GVP11,
 	PROC_SCSI_ATARI,
+	PROC_SCSI_GDTH,
 	PROC_SCSI_IDESCSI,
 	PROC_SCSI_SCSI_DEBUG,	
 	PROC_SCSI_NOT_PRESENT,
diff -urN linux-2.0.31-pre2/init/main.c linux-2.0.31-pre3/init/main.c
--- linux-2.0.31-pre2/init/main.c	2003-08-15 15:03:53.000000000 -0700
+++ linux-2.0.31-pre3/init/main.c	2003-08-15 15:03:53.000000000 -0700
@@ -89,6 +89,7 @@
 extern void generic_NCR53C400_setup(char *str, int *intr);
 extern void aha152x_setup(char *str, int *ints);
 extern void aha1542_setup(char *str, int *ints);
+extern void gdth_setup(char *str, int *ints);
 extern void aic7xxx_setup(char *str, int *ints);
 extern void AM53C974_setup(char *str, int *ints);
 extern void BusLogic_Setup(char *str, int *ints);
@@ -147,8 +148,11 @@
 #ifdef CONFIG_ISDN_DRV_ICN
 extern void icn_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_ISDN_DRV_TELES
-extern void teles_setup(char *str, int *ints);
+#ifdef CONFIG_ISDN_DRV_HISAX
+extern void HiSax_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ISDN_DRV_PCBIT
+extern void pcbit_setup(char *str, int *ints);
 #endif
 
 #ifdef CONFIG_ATARIMOUSE
@@ -166,9 +170,6 @@
 #ifdef CONFIG_DIGI
 extern void pcxx_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_setup(char *str, int *ints);
-#endif
 #ifdef CONFIG_RISCOM8
 extern void riscom8_setup(char *str, int *ints);
 #endif
@@ -318,6 +319,9 @@
 #ifdef CONFIG_SCSI_AHA1542
 	{ "aha1542=", aha1542_setup},
 #endif
+#ifdef CONFIG_SCSI_GDTH
+	{ "gdth=", gdth_setup},
+#endif
 #ifdef CONFIG_SCSI_AIC7XXX
 	{ "aic7xxx=", aic7xxx_setup},
 #endif
@@ -393,8 +397,9 @@
 #ifdef CONFIG_ISDN_DRV_ICN
 	{ "icn=", icn_setup },
 #endif
-#ifdef CONFIG_ISDN_DRV_TELES
-	{ "teles=", teles_setup },
+#ifdef CONFIG_ISDN_DRV_HISAX
+       { "hisax=", HiSax_setup },
+       { "HiSax=", HiSax_setup },
 #endif
 #ifdef CONFIG_ISDN_DRV_PCBIT
 	{ "pcbit=", pcbit_setup },
diff -urN linux-2.0.31-pre2/kernel/panic.c linux-2.0.31-pre3/kernel/panic.c
--- linux-2.0.31-pre2/kernel/panic.c	1996-04-11 23:49:47.000000000 -0700
+++ linux-2.0.31-pre3/kernel/panic.c	2003-08-15 15:03:53.000000000 -0700
@@ -17,6 +17,7 @@
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void hard_reset_now(void);
 extern void do_unblank_screen(void);
+extern void gdth_halt(void);
 extern int C_A_D;
 
 int panic_timeout = 0;
@@ -53,6 +54,9 @@
 		printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
 		for(i = 0; i < (panic_timeout*1000); i++)
 			udelay(1000);
+#ifdef CONFIG_SCSI_GDTH
+		gdth_halt();
+#endif
 		hard_reset_now();
 	}
 	for(;;);
diff -urN linux-2.0.31-pre2/kernel/sys.c linux-2.0.31-pre3/kernel/sys.c
--- linux-2.0.31-pre2/kernel/sys.c	1997-04-08 08:47:47.000000000 -0700
+++ linux-2.0.31-pre3/kernel/sys.c	2003-08-15 15:03:53.000000000 -0700
@@ -34,6 +34,7 @@
 int C_A_D = 1;
 
 extern void adjust_clock(void);
+extern void gdth_halt(void);
 
 asmlinkage int sys_ni_syscall(void)
 {
@@ -186,9 +187,12 @@
 		return -EPERM;
 	if (magic != 0xfee1dead || magic_too != 672274793)
 		return -EINVAL;
-	if (flag == 0x01234567)
+	if (flag == 0x01234567) {
+#ifdef CONFIG_SCSI_GDTH
+		gdth_halt();
+#endif
 		hard_reset_now();
-	else if (flag == 0x89ABCDEF)
+	} else if (flag == 0x89ABCDEF)
 		C_A_D = 1;
 	else if (!flag)
 		C_A_D = 0;
@@ -211,9 +215,12 @@
  */
 void ctrl_alt_del(void)
 {
-	if (C_A_D)
+	if (C_A_D) {
+#ifdef CONFIG_SCSI_GDTH
+		gdth_halt();
+#endif
 		hard_reset_now();
-	else
+	} else
 		kill_proc(1, SIGINT, 1);
 }
 	
