]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.31pre3 2.0.31pre3
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:28 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:28 +0000 (15:11 -0500)
128 files changed:
Documentation/Configure.help
Documentation/isdn/00-INDEX
Documentation/isdn/CREDITS
Documentation/isdn/INTERFACE
Documentation/isdn/README
Documentation/isdn/README.HiSax [new file with mode: 0644]
Documentation/isdn/README.audio
Documentation/isdn/README.avmb1 [new file with mode: 0644]
Documentation/isdn/README.icn
Documentation/isdn/README.sc [new file with mode: 0644]
Documentation/isdn/README.teles [deleted file]
arch/alpha/defconfig
arch/i386/defconfig
drivers/isdn/Config.in
drivers/isdn/Makefile
drivers/isdn/avmb1/Makefile [new file with mode: 0644]
drivers/isdn/avmb1/b1capi.c [new file with mode: 0644]
drivers/isdn/avmb1/b1lli.c [new file with mode: 0644]
drivers/isdn/avmb1/b1pci.c [new file with mode: 0644]
drivers/isdn/avmb1/capi.c [new file with mode: 0644]
drivers/isdn/avmb1/capicmd.h [new file with mode: 0644]
drivers/isdn/avmb1/capidev.h [new file with mode: 0644]
drivers/isdn/avmb1/capidrv.c [new file with mode: 0644]
drivers/isdn/avmb1/capidrv.h [new file with mode: 0644]
drivers/isdn/avmb1/capiutil.c [new file with mode: 0644]
drivers/isdn/avmb1/capiutil.h [new file with mode: 0644]
drivers/isdn/avmb1/compat.h [new file with mode: 0644]
drivers/isdn/hisax/Makefile [new file with mode: 0644]
drivers/isdn/hisax/avm_a1.c [new file with mode: 0644]
drivers/isdn/hisax/avm_a1.h [new file with mode: 0644]
drivers/isdn/hisax/callc.c [new file with mode: 0644]
drivers/isdn/hisax/config.c [new file with mode: 0644]
drivers/isdn/hisax/elsa.c [new file with mode: 0644]
drivers/isdn/hisax/elsa.h [new file with mode: 0644]
drivers/isdn/hisax/fsm.c [new file with mode: 0644]
drivers/isdn/hisax/hisax.h [new file with mode: 0644]
drivers/isdn/hisax/isdnl1.c [new file with mode: 0644]
drivers/isdn/hisax/isdnl1.h [new file with mode: 0644]
drivers/isdn/hisax/isdnl2.c [new file with mode: 0644]
drivers/isdn/hisax/isdnl2.h [new file with mode: 0644]
drivers/isdn/hisax/isdnl3.c [new file with mode: 0644]
drivers/isdn/hisax/isdnl3.h [new file with mode: 0644]
drivers/isdn/hisax/ix1_micro.c [new file with mode: 0644]
drivers/isdn/hisax/ix1_micro.h [new file with mode: 0644]
drivers/isdn/hisax/l3_1tr6.c [new file with mode: 0644]
drivers/isdn/hisax/l3_1tr6.h [new file with mode: 0644]
drivers/isdn/hisax/l3dss1.c [new file with mode: 0644]
drivers/isdn/hisax/q931.c [new file with mode: 0644]
drivers/isdn/hisax/siemens.h [new file with mode: 0644]
drivers/isdn/hisax/tei.c [new file with mode: 0644]
drivers/isdn/hisax/teles0.c [new file with mode: 0644]
drivers/isdn/hisax/teles0.h [new file with mode: 0644]
drivers/isdn/hisax/teles3.c [new file with mode: 0644]
drivers/isdn/hisax/teles3.h [new file with mode: 0644]
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/isdn/isdn_audio.c
drivers/isdn/isdn_audio.h
drivers/isdn/isdn_cards.c
drivers/isdn/isdn_cards.h
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_net.c
drivers/isdn/isdn_net.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_ppp.h
drivers/isdn/isdn_syms.c [new file with mode: 0644]
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_tty.h
drivers/isdn/pcbit/callbacks.c
drivers/isdn/pcbit/capi.c
drivers/isdn/pcbit/drv.c
drivers/isdn/pcbit/layer2.c
drivers/isdn/pcbit/module.c
drivers/isdn/sc/Makefile [new file with mode: 0644]
drivers/isdn/sc/card.h [new file with mode: 0644]
drivers/isdn/sc/command.c [new file with mode: 0644]
drivers/isdn/sc/debug.c [new file with mode: 0644]
drivers/isdn/sc/debug.h [new file with mode: 0644]
drivers/isdn/sc/event.c [new file with mode: 0644]
drivers/isdn/sc/hardware.h [new file with mode: 0644]
drivers/isdn/sc/includes.h [new file with mode: 0644]
drivers/isdn/sc/init.c [new file with mode: 0644]
drivers/isdn/sc/interrupt.c [new file with mode: 0644]
drivers/isdn/sc/ioctl.c [new file with mode: 0644]
drivers/isdn/sc/message.c [new file with mode: 0644]
drivers/isdn/sc/message.h [new file with mode: 0644]
drivers/isdn/sc/packet.c [new file with mode: 0644]
drivers/isdn/sc/scioc.h [new file with mode: 0644]
drivers/isdn/sc/shmem.c [new file with mode: 0644]
drivers/isdn/sc/timer.c [new file with mode: 0644]
drivers/isdn/teles/Makefile [deleted file]
drivers/isdn/teles/buffers.c [deleted file]
drivers/isdn/teles/callc.c [deleted file]
drivers/isdn/teles/card.c [deleted file]
drivers/isdn/teles/config.c [deleted file]
drivers/isdn/teles/fsm.c [deleted file]
drivers/isdn/teles/isdnl2.c [deleted file]
drivers/isdn/teles/isdnl3.c [deleted file]
drivers/isdn/teles/l3_1TR6.c [deleted file]
drivers/isdn/teles/l3_1TR6.h [deleted file]
drivers/isdn/teles/llglue.c [deleted file]
drivers/isdn/teles/mod.c [deleted file]
drivers/isdn/teles/proto.h [deleted file]
drivers/isdn/teles/q931.c [deleted file]
drivers/isdn/teles/tei.c [deleted file]
drivers/isdn/teles/teles.h [deleted file]
drivers/net/ne.c
drivers/pci/pci.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/gdth.c [new file with mode: 0644]
drivers/scsi/gdth.h [new file with mode: 0644]
drivers/scsi/gdth_ioctl.h [new file with mode: 0644]
drivers/scsi/gdth_proc.c [new file with mode: 0644]
drivers/scsi/gdth_proc.h [new file with mode: 0644]
drivers/scsi/hosts.c
include/linux/b1lli.h [new file with mode: 0644]
include/linux/capi.h [new file with mode: 0644]
include/linux/isdn.h
include/linux/isdn_ppp.h
include/linux/isdnif.h
include/linux/kernelcapi.h [new file with mode: 0644]
include/linux/pci.h
include/linux/proc_fs.h
init/main.c
kernel/panic.c
kernel/sys.c

index 17db40aa897dd4e115ffd5c55b64400dcaa572b6..89e81e97a7de135e59a03b27778de9842605d930 100644 (file)
@@ -1747,6 +1747,15 @@ CONFIG_SCSI_AM53C974
   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 @@ CONFIG_ISDN_AUDIO
   (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 @@ CONFIG_ISDN_DRV_ICN
   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 @@ CONFIG_ISDN_DRV_PCBIT
   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
index b707c346d48b70540ca8c9aa4d961d3e1cd9b72a..401697921b9dc5a77fd5df14647e45cb8f763164 100644 (file)
@@ -10,12 +10,13 @@ README.audio
        - 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
index 6c546c4e1e6d495355f3a1da48a2aaee46557fdb..44e6554a7647dff2ff68c3d5dd342da03db864bb 100644 (file)
@@ -12,11 +12,18 @@ Volker G
   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 @@ Max Riegel (riegel@max.franken.de)
 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
index fe2a4440cd808abf8d757f1572de4d775746fd6c..81dddb08177b8757c92b9146099c6d70dce8ae6d 100644 (file)
@@ -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 @@ Description of the Interface between Linklevel and Hardwarelevel
 
   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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
 
    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 @@ Description of the Interface between Linklevel and Hardwarelevel
        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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       driver      = driver-Id.
       command     = ISDN_CMD_LOCK
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_CMD_UNLOCK:
 
@@ -462,7 +467,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       driver      = driver-Id
       command     = ISDN_STAT_RUN
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_STOP:
 
@@ -524,7 +533,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       driver      = driver-Id
       command     = ISDN_STAT_STOP
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_DCONN:
 
@@ -535,7 +544,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       driver      = driver-Id
       command     = ISDN_STAT_UNLOAD
       arg         = unused.
-      num         = unused.
+      para        = unused.
 
   ISDN_STAT_BSENT:
 
@@ -608,7 +617,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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 @@ Description of the Interface between Linklevel and Hardwarelevel
       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.
 
index 36cc1336f0334a7786ccb1d5779f558c68ef4b77..770694f2b819457de752904d6069a733180754ee 100644 (file)
@@ -27,7 +27,14 @@ README for the ISDN-subsystem
    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 @@ README for the ISDN-subsystem
   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 @@ README for the ISDN-subsystem
               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 @@ README for the ISDN-subsystem
               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 @@ README for the ISDN-subsystem
                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 @@ README for the ISDN-subsystem
                                       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 @@ README for the ISDN-subsystem
              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 @@ README for the ISDN-subsystem
              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 @@ README for the ISDN-subsystem
 
 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 @@ README for the ISDN-subsystem
      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 @@ README for the ISDN-subsystem
 
    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 @@ README for the ISDN-subsystem
 
    "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 --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax
new file mode 100644 (file)
index 0000000..20b578d
--- /dev/null
@@ -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.
index c2c2d272d1882bcf4a744cd8470a150df2e5c3b7..c01a116bcf2d0920c882741c6f7e934e6a12e018 100644 (file)
@@ -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 @@ Commands for enabling/disabling audio mode:
 
         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 @@ General behavior and description of data formats/protocol.
     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 @@ General behavior and description of data formats/protocol.
     <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 --git a/Documentation/isdn/README.avmb1 b/Documentation/isdn/README.avmb1
new file mode 100644 (file)
index 0000000..68bdf09
--- /dev/null
@@ -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)
index f2dd3ba03ed1aa16bb7a8769e62fb3aa756ae468..cb8908d58767c5e2b0f8f28edbc5b724efc86615 100644 (file)
@@ -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 @@ Setting up the IO-address dipswitches for the ICN-ISDN-card:
       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 --git a/Documentation/isdn/README.sc b/Documentation/isdn/README.sc
new file mode 100644 (file)
index 0000000..0ea8ca1
--- /dev/null
@@ -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 --git a/Documentation/isdn/README.teles b/Documentation/isdn/README.teles
deleted file mode 100644 (file)
index 904a559..0000000
+++ /dev/null
@@ -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
-
index d10428b032d371923984c7e5968f249400157d2f..c6e8bd8dc77bbb248e4d43be87710c1cc3d2e3a0 100644 (file)
@@ -169,6 +169,7 @@ CONFIG_DE4X5=y
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
 
 #
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
index 07227fdb3faee29f45bb06fce7370d208715dde3..74dbc3f86961062bb498c1bcc829940f71ae7a52 100644 (file)
@@ -124,6 +124,7 @@ CONFIG_EL3=y
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
 
 #
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
index 96f7e5a43b8eef41ddee598e28cb277cc960ed19..2213ac6dc7d5cebe43cff3a2e178319353049b96 100644 (file)
@@ -11,4 +11,21 @@ fi
 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
index 3b441835e722f94bf11b3871aa5162bd107fb904..6de0041579431e27334bf5fef0f0df8bec654b37 100644 (file)
@@ -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 @@ O_TARGET :=
 
 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 @@ else
   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 @@ else
   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 @@ else
   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 --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
new file mode 100644 (file)
index 0000000..cce4af1
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/b1capi.c b/drivers/isdn/avmb1/b1capi.c
new file mode 100644 (file)
index 0000000..b379d8f
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/b1lli.c b/drivers/isdn/avmb1/b1lli.c
new file mode 100644 (file)
index 0000000..bc1cb1c
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
new file mode 100644 (file)
index 0000000..af7b584
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
new file mode 100644 (file)
index 0000000..34fde7b
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capicmd.h b/drivers/isdn/avmb1/capicmd.h
new file mode 100644 (file)
index 0000000..104ef82
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h
new file mode 100644 (file)
index 0000000..f2e0d6d
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
new file mode 100644 (file)
index 0000000..f6bb51f
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capidrv.h b/drivers/isdn/avmb1/capidrv.h
new file mode 100644 (file)
index 0000000..f30c3f4
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capiutil.c b/drivers/isdn/avmb1/capiutil.c
new file mode 100644 (file)
index 0000000..b3c25cd
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/capiutil.h b/drivers/isdn/avmb1/capiutil.h
new file mode 100644 (file)
index 0000000..3820921
--- /dev/null
@@ -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 --git a/drivers/isdn/avmb1/compat.h b/drivers/isdn/avmb1/compat.h
new file mode 100644 (file)
index 0000000..551b20d
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
new file mode 100644 (file)
index 0000000..2cc325b
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
new file mode 100644 (file)
index 0000000..43b1470
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/avm_a1.h b/drivers/isdn/hisax/avm_a1.h
new file mode 100644 (file)
index 0000000..85f4467
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
new file mode 100644 (file)
index 0000000..91c8689
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
new file mode 100644 (file)
index 0000000..595fb71
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
new file mode 100644 (file)
index 0000000..0eb0253
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/elsa.h b/drivers/isdn/hisax/elsa.h
new file mode 100644 (file)
index 0000000..5187e6a
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
new file mode 100644 (file)
index 0000000..d0bb2f1
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
new file mode 100644 (file)
index 0000000..efe7d53
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
new file mode 100644 (file)
index 0000000..f0aaba0
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
new file mode 100644 (file)
index 0000000..98418c8
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
new file mode 100644 (file)
index 0000000..87f4814
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h
new file mode 100644 (file)
index 0000000..ac21d1c
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
new file mode 100644 (file)
index 0000000..e945bd4
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
new file mode 100644 (file)
index 0000000..bed989a
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
new file mode 100644 (file)
index 0000000..c55faa9
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/ix1_micro.h b/drivers/isdn/hisax/ix1_micro.h
new file mode 100644 (file)
index 0000000..b180097
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
new file mode 100644 (file)
index 0000000..99e318a
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h
new file mode 100644 (file)
index 0000000..6e2fee7
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
new file mode 100644 (file)
index 0000000..73c49d9
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
new file mode 100644 (file)
index 0000000..1e1ee47
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/siemens.h b/drivers/isdn/hisax/siemens.h
new file mode 100644 (file)
index 0000000..f356a30
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
new file mode 100644 (file)
index 0000000..f13f9cd
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
new file mode 100644 (file)
index 0000000..2e063fd
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/teles0.h b/drivers/isdn/hisax/teles0.h
new file mode 100644 (file)
index 0000000..3baaa5c
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
new file mode 100644 (file)
index 0000000..d93ca76
--- /dev/null
@@ -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 --git a/drivers/isdn/hisax/teles3.h b/drivers/isdn/hisax/teles3.h
new file mode 100644 (file)
index 0000000..8f8dc80
--- /dev/null
@@ -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);
index f65becc50d5e8700c47d99de8ea0d896d5d5b2dd..1d61ac8d11fb8d79f21b62b36906fb957f9d9ecb 100644 (file)
@@ -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)
  *
  * 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.
 #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 @@ static void icn_free_queue(struct sk_buff_head *queue)
  *            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 @@ static inline void icn_map_channel(icn_card *card, int channel)
  * 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 @@ static inline void icn_maprelease_channel(icn_card *card, int channel)
  * 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 @@ static void icn_pollbchan_receive(int channel, icn_card *card)
  * 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;
-
-        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;
+       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;
                        } 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 @@ static void icn_pollbchan_send(int channel, icn_card *card)
  * 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;
-
-                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;
+       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;
 }
 
 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 @@ static icn_stat icn_stat_table[] = {
  * 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->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;
+       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)
+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);
+       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)
+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 @@ static void icn_polldchan(unsigned long data)
  *   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 @@ static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
  *   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 @@ int slsec = sec; \
 #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));
+       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)
+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;
+       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;
-
-        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;
+       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;
 }
 
 /* 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;
-
-        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);
+       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)
+static void
+icn_stopallcards(void)
 {
-        icn_card *p = cards;
+       icn_card *p = cards;
 
-        while (p) {
-                icn_stopcard(p);
-                p = p->next;
-        }
+       while (p) {
+               icn_stopcard(p);
+               p = p->next;
+       }
 }
 
-static int icn_command(isdn_ctrl * c, icn_card * card)
+/*
+ * Unmap all cards, because some of them may be mapped accidetly during
+ * autoprobing of some network drivers (SMC-driver?)
+ */
+static void
+icn_disable_cards(void)
 {
-        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;
+       icn_card *card = cards;
+       unsigned long flags;
+
+       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;
 }
 
 /*
  * Find card with given driverId
  */
 static inline icn_card *
-  icn_findcard(int driverid)
+icn_findcard(int driverid)
 {
-        icn_card *p = cards;
-
-        while (p) {
-                if (p->myid == driverid)
-                        return p;
-                p = p->next;
-        }
-        return (icn_card *)0;
+       icn_card *p = cards;
+
+       while (p) {
+               if (p->myid == driverid)
+                       return p;
+               p = p->next;
+       }
+       return (icn_card *) 0;
 }
 
 /*
  * Wrapper functions for interface to linklevel
  */
-static int if_command(isdn_ctrl * c)
+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;
+       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)
+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;
+       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 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;
+       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)
+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;
+       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;
+       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)
+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;
+       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)
+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));
+       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
index 7ce78b434b6159bbe70d47f19a2eebac3178737c..991d57e4ddee48dbf5710d72b665fd1e285d67a6 100644 (file)
@@ -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)
  *
  * 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.
  *
 
 /* 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 @@ typedef struct icn_cdef {
 #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 @@ typedef struct icn_cdef {
 #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_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_BOOT_TIMEOUT1  (HZ) /* Delay for Boot-download (jiffies)       */
+#define ICN_CHANLOCK_DELAY (HZ/10)     /* Delay for Channel-mapping (jiffies)     */
 
-#define ICN_TIMER_BCREAD       /* B-Channel poll-cycle                    */
-#define ICN_TIMER_DCREAD 50      /* D-Channel poll-cycle                    */
+#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_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_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 @@ char *icn_id2 = "\0";
 
 /* 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 @@ char *icn_id2 = "\0";
 
 /* 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 @@ char *icn_id2 = "\0";
 
 /* 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 @@ char *icn_id2 = "\0";
 
 /* 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 @@ char *icn_id2 = "\0";
 #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 */
index a356b512e7c59b17868f394d94d2420d96ffd6df..89446a4fa216daafdf0fe63c3d7135c241217cc1 100644 (file)
@@ -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)
  *
  * 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.
  *
 #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 @@ static char isdn_audio_ulaw_to_alaw[] = {
 #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 @@ isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
  */
 
 
-#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 @@ isdn_audio_xlaw2adpcm (adpcm_state *s, int fmt, unsigned char *in,
  * 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 @@ isdn_audio_eval_dtmf(modem_info *info)
  *   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;
+       }
 }
-
-
index a4a5c9a13b2238237ef0f76f7c0212e6502259a0..0cf8267cfa59e8e9d37cb88d8eca1105114e9dac 100644 (file)
@@ -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)
  *
  * 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.
  *
  *
  */
 
-#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 *);
index a70d6992ec33546ac2b098ce3326bd6d4c3d0f70..c7f4e8b08c89b174aa8c13bc49f1b57f228ca66b 100644 (file)
@@ -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)
  *
  * 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
  *
 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 HiSax_init(void);
 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
 }
-
index 5bece603b93be6fb2b277e33ba6236e2602cd393..e6e2aa12763f7bb43472d253b1be89389dd44d48 100644 (file)
@@ -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)
  *
  * 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);
-
index 61212368e1012a1b95c106ba9a977149a805cb00..86ef2fbe0a3afdb205ab8451e7cb94560aa77d88 100644 (file)
@@ -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)
  *
  * 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.
  *
  */
 
 #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"
 #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 @@ extern char *isdn_audio_revision;
 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 @@ void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 }
 #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;
-
-        save_flags(flags);
-        cli();
-        if (skb_queue_len(queue))
-                while ((skb = skb_dequeue(queue)))
-                        isdn_trash_skb(skb, FREE_READ);
-        restore_flags(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);
 }
 
-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 @@ int isdn_dc2minor(int di, int ch)
 
 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 @@ static void isdn_timer_funct(ulong dummy)
                        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 @@ void isdn_timer_ctrl(int tf, int onoff)
                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 @@ static int isdn_status_callback(isdn_ctrl * c)
 /*
  * 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 @@ int isdn_getnum(char **p)
  * 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 @@ int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int
        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 @@ static char *
 
 /* Module interface-code */
 
-void isdn_info_update(void)
+void
+isdn_info_update(void)
 {
        infostruct *p = dev->infochain;
 
@@ -924,7 +848,8 @@ void isdn_info_update(void)
        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 @@ static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG
        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 @@ static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG
                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 @@ static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG
                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 @@ static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG
                        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 @@ static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG
        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 @@ static RWTYPE isdn_write(struct inode *inode, struct file *file, const char *buf
        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 @@ static int isdn_select(struct inode *inode, struct file *file, int type, select_
                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 @@ static int isdn_set_allcfg(char *src)
                        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 @@ static int isdn_set_allcfg(char *src)
        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 @@ static int isdn_get_allcfg(char *dest)
        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 @@ static int isdn_get_allcfg(char *dest)
                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 @@ static int isdn_get_allcfg(char *dest)
                        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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
        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);
+                       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) {
-                                        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 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;
-                                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 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++) {
+                                               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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
  * 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 @@ static int isdn_open(struct inode *ino, struct file *filep)
        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 @@ static void isdn_close(struct inode *ino, struct file *filep)
                                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 @@ static struct file_operations isdn_fops =
        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 @@ char *
  * 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 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                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 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                        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 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
 /*
  * 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 @@ void isdn_free_channel(int di, int ch, int usage)
                    (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 @@ void isdn_free_channel(int di, int ch, int usage)
 /*
  * 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 @@ void isdn_unexclusive_channel(int di, int ch)
  * 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 @@ int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len,
  * 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 @@ int register_isdn(isdn_if * i)
                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 @@ int register_isdn(isdn_if * i)
                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 @@ int register_isdn(isdn_if * i)
                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 @@ extern int printk(const char *fmt,...);
 #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 @@ static char *isdn_getrev(const char *revision)
        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 @@ int isdn_init(void)
                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 @@ int isdn_init(void)
                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 @@ int isdn_init(void)
 /*
  * Unload module
  */
-void cleanup_module(void)
+void
+cleanup_module(void)
 {
        int flags;
        int i;
@@ -2214,9 +2182,9 @@ void cleanup_module(void)
                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 {
index 81d7905a2d7194f8e63715d0953ca3416210ed79..d0df7fe7965ae28d0c1a9d69a359e48abaa4a493 100644 (file)
@@ -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)
  *
  * 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.
  *
 #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
index e1da45bf34d4ba4c2711163edfe4717a30244c97..65a58c1ae926130fa7ced8eb364c2ebec7cd5b83 100644 (file)
@@ -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)
  *
  * 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.
  *
 #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 @@ isdn_net_open(struct device *dev)
                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 @@ isdn_net_open(struct device *dev)
                        p = (((isdn_net_local *) p->priv)->slave);
                }
        }
-
        isdn_MOD_INC_USE_COUNT();
        return 0;
 }
@@ -211,15 +283,15 @@ isdn_net_open(struct device *dev)
 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 @@ isdn_net_unbind_channel(isdn_net_local * lp)
 
        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 @@ void
 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 @@ isdn_net_stat_callback(int idx, int cmd)
 
        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 @@ isdn_net_stat_callback(int idx, int cmd)
                                        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 @@ isdn_net_stat_callback(int idx, int cmd)
                                 * 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_dial(void)
        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_net_hangup(struct device *d)
        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 @@ isdn_net_hangup(struct device *d)
                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 @@ typedef struct {
 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 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
                               p[14], p[15], p[16], p[17],
                               p[24], p[25], p[26], p[27]);
                        break;
-        }
+       }
 }
 
 /*
@@ -772,28 +890,27 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
  * 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 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local *lp,
  */
 
 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 @@ isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb)
                                /* 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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
        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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                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 @@ isdn_net_close(struct device *dev)
 
        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 @@ isdn_net_close(struct device *dev)
                        p = (((isdn_net_local *) p->priv)->slave);
                }
        }
+       isdn_net_hangup(dev);
        isdn_MOD_DEC_USE_COUNT();
        return 0;
 }
@@ -1016,7 +1127,7 @@ isdn_net_close(struct device *dev)
  * 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 @@ static struct enet_statistics *
  *      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_receive(struct device *ndev, struct sk_buff *skb)
 {
        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 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
                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;
+               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;
+               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 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
  * 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 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
 
 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 @@ my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
  *  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;
-
-        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  
-        }
+       int ret = 0;
+
+       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
+       }
        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 @@ static int
 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 @@ isdn_net_init(struct device *ndev)
                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;
-
-        for (i = 0; i < ETH_ALEN; i++)
-                ndev->broadcast[i]=0xff;
+       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 < 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 @@ isdn_net_wildmat(char *s, char *p)
 
        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 @@ isdn_net_swapbind(int drvidx)
        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 @@ isdn_net_swap_usage(int i1, int i2)
  *               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_find_icall(int di, int ch, int idx, char *num)
        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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
        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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
 #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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                                        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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
 #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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                           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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
  * 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 @@ isdn_net_dev *
  * 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 @@ int isdn_net_force_dial_lp(isdn_net_local * lp)
                        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 @@ int isdn_net_force_dial_lp(isdn_net_local * lp)
  * 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 @@ isdn_net_new(char *name, struct device *master)
                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 @@ isdn_net_new(char *name, struct device *master)
        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 @@ isdn_net_new(char *name, struct device *master)
        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 @@ isdn_net_newslave(char *parm)
                /* 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 @@ isdn_net_newslave(char *parm)
  * 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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        /* 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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
 /*
  * 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 @@ int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
                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 @@ int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
 /*
  * 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 @@ int isdn_net_addphone(isdn_net_ioctl_phone * phone)
 /*
  * 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 @@ int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
        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 @@ int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
  * 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 @@ int isdn_net_delphone(isdn_net_ioctl_phone * phone)
                        m = n;
                        n = (isdn_net_phone *) n->next;
                }
+               restore_flags(flags);
                return -EINVAL;
        }
        return -ENODEV;
@@ -2298,7 +2443,8 @@ int isdn_net_delphone(isdn_net_ioctl_phone * phone)
 /*
  * 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 @@ static int isdn_net_rmallphone(isdn_net_dev * p)
                }
                p->local.phone[i] = NULL;
        }
+       p->local.dial = NULL;
        restore_flags(flags);
        return 0;
 }
@@ -2323,7 +2470,8 @@ static int isdn_net_rmallphone(isdn_net_dev * p)
 /*
  * 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 @@ int isdn_net_force_hangup(char *name)
        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 @@ int isdn_net_force_hangup(char *name)
 /*
  * 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 @@ static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
                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 @@ static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
 /*
  * 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 @@ int isdn_net_rm(char *name)
 /*
  * Remove all network-interfaces
  */
-int isdn_net_rmall(void)
+int
+isdn_net_rmall(void)
 {
        int flags;
        int ret;
@@ -2446,7 +2594,7 @@ int isdn_net_rmall(void)
                        /* 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 @@ int isdn_net_rmall(void)
        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);
+       }
+
 }
index 5b6754e662712ea4d33bb781c16135358ce1a939..56df21081e9c555c0e86500081cffcd7578418fe 100644 (file)
@@ -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)
  *
  * 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
  *
  *
  */
 
-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 *);
index f7ec2e7d4fc3638c9deab582cfab9bc8dd4a0db9..c13dadd485f7ce5a11a9ea5272f7dbd29cade780 100644 (file)
@@ -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)
  *
  * 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.
  *
 
 /* 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 @@ int isdn_ppp_free(isdn_net_local *lp)
        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 @@ int isdn_ppp_free(isdn_net_local *lp)
        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 @@ int isdn_ppp_free(isdn_net_local *lp)
 /*
  * 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 @@ int isdn_ppp_bind(isdn_net_local * lp)
        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 @@ int isdn_ppp_bind(isdn_net_local * lp)
                 * 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 @@ int isdn_ppp_bind(isdn_net_local * lp)
                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 @@ int isdn_ppp_bind(isdn_net_local * lp)
  * (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 @@ void isdn_ppp_wakeup_daemon(isdn_net_local *lp)
 
 /*
  * 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 @@ static int isdn_ppp_closewait(int slot)
  * 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);
+
+       /* 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 = 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 */
+       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 @@ int isdn_ppp_open(int min, struct file *file)
 /*
  * 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 @@ void isdn_ppp_release(int min, struct file *file)
                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 @@ void isdn_ppp_release(int min, struct file *file)
                        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 @@ void isdn_ppp_release(int min, struct file *file)
 /*
  * 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 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
                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 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
        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 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
                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 @@ static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
  *           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 @@ int isdn_ppp_read(int min, struct file *file, char *buf, int count)
        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 @@ int isdn_ppp_write(int min, struct file *file,  const char *buf, int count)
        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 isdn_ppp_write(int min, struct file *file,  const char *buf, int count)
                        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);
+                       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);
+                       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 @@ int isdn_ppp_write(int min, struct file *file,  const char *buf, int count)
 }
 
 /*
- * 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 @@ int isdn_ppp_init(void)
        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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                }
                        }
                        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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                         * 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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                        }
                                }
                        } 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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
 }
 
 /*
- * 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 @@ printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
        }
        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 @@ printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
        }
 #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 @@ printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
                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 */
+       /*
+        * 'link' compression 
+        */
+       skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
 
-       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( (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 */
        }
 
-       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
+       /* 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 @@ printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
 
 #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_sqqueue(isdn_net_dev * p)
 
 }
 
-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 int isdn_ppp_bundle(struct ippp_struct *is, int unit)
 }
 
 
-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 void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
        }
 }
 
-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 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
                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 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
        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 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
  * 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 @@ static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
 /* 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 @@ static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
 
 #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 @@ void isdn_ppp_timer_timeout(void)
                                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 @@ void isdn_ppp_timer_timeout(void)
  * 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 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
        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 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                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 @@ int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
        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 @@ int isdn_ppp_dial_slave(char *name)
 #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 @@ int isdn_ppp_hangup_slave(char *name)
 #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
-static struct symbol_table isdn_ppp_syms = {
+       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 =
+{
 #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
 
 
+
+
index 4568f8d2b1fe0187d41ad4bd560e0281b46f1182..d19f1e09e351c3a4a4e471b545493425084461ce 100644 (file)
@@ -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)
  *
  * 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.
  *
  */
 
-#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 --git a/drivers/isdn/isdn_syms.c b/drivers/isdn/isdn_syms.c
new file mode 100644 (file)
index 0000000..567f8dd
--- /dev/null
@@ -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
index 3a0b7ab0e557b55fda23fed99372fa0696fdc0bf..a5f31eaf3e29356f97f1fc595b0b90e769202bc2 100644 (file)
@@ -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)
  *
  * 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.
  *
  * Initial revision
  *
  */
+#undef ISDN_TTY_STAT_DEBUG
 
 #define __NO_VERSION__
 #include <linux/config.h>
 
 /* 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 @@ char *isdn_tty_revision        = "$Revision: 1.23 $";
  *  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 @@ int isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
  * 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 @@ void isdn_tty_readmodem(void)
 
        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 @@ void isdn_tty_readmodem(void)
                                        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 @@ void isdn_tty_readmodem(void)
                                } 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)
+{
+       ulong flags;
+       int midx;
+#ifdef CONFIG_ISDN_AUDIO
+       int ifmt;
+#endif
+       modem_info *info;
+
+       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))) {
-                        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);
+       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
+       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)
+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);
+       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
-int isdn_tty_countDLE(unsigned char *buf, int len)
+static int
+isdn_tty_countDLE(unsigned char *buf, int len)
 {
-        int count = 0;
+       int count = 0;
 
-        while (len--)
-                if (*buf++ == DLE)
-                        count++;
-        return count;
+       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;
-
-        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;
+       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;
+#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;
+       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 & 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);
+       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
-        }
-#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;
+       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 @@ static void isdn_tty_senddown(modem_info * info)
  * 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;
-                }
+       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;
-                }
+       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 @@ static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
                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 @@ static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
  * 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);
-#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;
+       printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
+#endif
+       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
-        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->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;
        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 @@ static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, cons
  * 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 @@ static void isdn_tty_change_speed(modem_info * info)
        }
        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 void isdn_tty_change_speed(modem_info * info)
        }
 }
 
-static int isdn_tty_startup(modem_info * info)
+static int
+isdn_tty_startup(modem_info * info)
 {
        ulong flags;
 
@@ -750,12 +978,12 @@ static int isdn_tty_startup(modem_info * info)
                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 @@ static int isdn_tty_startup(modem_info * info)
  * 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 @@ static void isdn_tty_shutdown(modem_info * info)
        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 @@ static void isdn_tty_shutdown(modem_info * info)
  *  - 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 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
                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);
+               if ((info->online > 1)
+#ifdef CONFIG_ISDN_AUDIO
+                   || (info->vonline & 3)
+#endif
+                       ) {
+                       atemu *m = &info->emu;
+
+#ifdef CONFIG_ISDN_AUDIO
+                       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 & 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
-#endif
-                                info->xmit_count += c;
+                       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
+                               info->xmit_count += c;
                        if (m->mdmreg[13] & 1) {
-                                isdn_tty_senddown(info);
-                                isdn_tty_tint(info);
-                        }
+                               isdn_tty_senddown(info);
+                               isdn_tty_tint(info);
+                       }
                } else {
-                        info->msr |= UART_MSR_CTS;
-                        info->lsr |= UART_LSR_TEMT;
-#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
-#endif
-                                if (info->dialing) {
-                                        info->dialing = 0;
+                       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 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
        }
        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 @@ static int isdn_tty_write_room(struct tty_struct *tty)
        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 @@ static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
        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;
-
-        save_flags(flags);
-        cli();
-        if (!tty) {
-                restore_flags(flags);
-                return;
-        }
-        info =  (modem_info *) tty->driver_data;
+       unsigned long flags;
+
+       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 @@ static void isdn_tty_flush_chars(struct tty_struct *tty)
 /*
  * ------------------------------------------------------------
  * 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 @@ static void isdn_tty_throttle(struct tty_struct *tty)
        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 @@ static void isdn_tty_unthrottle(struct tty_struct *tty)
  *          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_lsr_info(modem_info * info, uint * value)
 }
 
 
-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 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value)
        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);
-#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:
+                       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:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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);
+                       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);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                                        printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
-#endif
-                                        if (info->online)
-                                                info->ncarrier = 1;
-                                        isdn_tty_modem_hup(info);
-                                }
-                        }
-                        break;
-                case TIOCMSET:
+                                       printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
+#endif
+                                       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);
-#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);
+                       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);
 #ifdef ISDN_DEBUG_MODEM_HUP
-                                                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;
+                                               printk(KERN_DEBUG "Mhup in TIOCMSET\n");
+#endif
+                                               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 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
 
        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);
-#endif
-                        retval = tty_check_change(tty);
-                        if (retval)
-                                return retval;
-                        tty_wait_until_sent(tty, 0);
-                        return 0;
-                case TCSBRKP:          /* support for POSIX tcsendbreak() */
+                       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() */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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:
+                       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:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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:
+                       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:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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:
+                       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:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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 */
+                       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 */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
-                        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:
+                       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:
 #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 @@ static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_ter
  * 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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
         */
        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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
         * 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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
        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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
  * 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 @@ static int isdn_tty_open(struct tty_struct *tty, struct file *filp)
        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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
        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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
         * 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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
        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 @@ static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
 /*
  * 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 @@ static void isdn_tty_hangup(struct tty_struct *tty)
 
 /* 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 @@ static void isdn_tty_reset_profile(atemu * m)
        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 @@ static void modem_write_profile(atemu * m)
                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 @@ int isdn_tty_modem_init(void)
        }
        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 @@ int isdn_tty_modem_init(void)
                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 @@ int isdn_tty_modem_init(void)
  * 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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
                                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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
        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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
  * 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 @@ static void isdn_tty_at_cout(char *msg, modem_info * info)
        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 @@ static void isdn_tty_at_cout(char *msg, modem_info * info)
 /*
  * 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 @@ static void isdn_tty_off_hook(void)
  *   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 @@ static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pl
  * 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 @@ void isdn_tty_modem_result(int code, modem_info * info)
         "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 @@ void isdn_tty_modem_result(int code, modem_info * info)
                        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 @@ void isdn_tty_modem_result(int code, modem_info * info)
                        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 @@ void isdn_tty_modem_result(int code, modem_info * info)
 /*
  * 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 @@ static void isdn_tty_show_profile(int ridx, modem_info * info)
 /*
  * 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 @@ static void isdn_tty_get_msnstr(char *n, char **p)
 /*
  * 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 @@ static void isdn_tty_getdial(char *p, char *q)
 #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;
+       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;
+                       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];
+       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;
-#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);
+               /* 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);
-#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;
+       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
-                        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);
+       if (!info->vonline)
+#endif
+               isdn_tty_modem_result(0, info);
 }
 
 /* Need own toupper() because standard-toupper is not available
@@ -2669,7 +3246,8 @@ static void isdn_tty_parse_at(modem_info * info)
  *   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 @@ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int use
                        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 @@ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int use
 /*
  * 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 @@ void isdn_tty_modem_escape(void)
        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 @@ void isdn_tty_modem_escape(void)
                                                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 @@ void isdn_tty_modem_ring(void)
  * 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;
-}
index f317d23ae3d27a7a00b4b607becef627e25286ec..986cb54f7640d36ee3841bba9535e83a50816972 100644 (file)
@@ -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)
  *
  * 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.
  *
  *
  */
 
-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 *);
index f3051e2e51020a8ae9eadc09d896ffddfa4a5149..14c0bdcb89cdc04630792ff9f86f7550b2fde623 100644 (file)
@@ -164,18 +164,12 @@ void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
          *  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);
index 1c752835da30d30980ebd9128c674f17c70a6984..790da879248db88f3364aeaae54046a8cb3441c7 100644 (file)
@@ -147,7 +147,7 @@ int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
@@ -170,7 +170,7 @@ int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -200,7 +200,7 @@ int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -222,7 +222,7 @@ int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
   
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -285,7 +285,7 @@ int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -338,7 +338,7 @@ int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
@@ -357,7 +357,7 @@ int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2) ) = callref;  
 
@@ -382,7 +382,7 @@ int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
                return -1;
        }
 
-        (*skb)->free = 1;
+        SET_SKB_FREE((*skb));
 
         *((ushort*) skb_put(*skb, 2)) = chan->callref;  
 
index dc386a13387207c8fab30ac98c9f4950304d2a44..e7d765a95c87cf51edd3e4e5230fbddaf80dd098 100644 (file)
@@ -226,7 +226,6 @@ int pcbit_command(isdn_ctrl* ctl)
        struct pcbit_dev  *dev;
        struct pcbit_chan *chan;
        struct callb_data info;
-       char *cp;
 
        dev = finddev(ctl->driver);
 
@@ -245,14 +244,7 @@ int pcbit_command(isdn_ctrl* ctl)
                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 @@ int pcbit_command(isdn_ctrl* ctl)
                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 @@ int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel
                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 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
 #endif
        }
 
-       skb->free = 1;
+       SET_SKB_FREE(skb);
 
        kfree_skb(skb, FREE_READ);
 
@@ -944,7 +930,7 @@ static int pcbit_ioctl(isdn_ctrl* ctl)
                return -ENODEV;
        }
 
-       cmd = (struct pcbit_ioctl *) ctl->num;
+       cmd = (struct pcbit_ioctl *) ctl->parm.num;
 
        switch(ctl->arg) {
        case PCBIT_IOCTL_GETSTAT:
index 4410d1e0c2d16e9094d0bc90da05721a9f22341b..96e47976149969e5711f05348d09305ec8ba4879 100644 (file)
@@ -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
- */ 
+ */
 
 
 
  *  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_error(struct pcbit_dev *dev);
 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 @@ static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev)
  *  Called from layer3
  */
 
-int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, 
-                  struct sk_buff *skb, unsigned short hdr_len)
-        
+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;
+       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");
+       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;
 
-        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;
 
-        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 @@ static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len)
  * 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 @@ static void pcbit_transmit(struct pcbit_dev * dev)
 
                        flen = MIN(totlen, free);
 
-                        msg = (struct msg_fmt *) &(frame->msg);
+                       msg = (struct msg_fmt *) &(frame->msg);
+
+                       /*
+                        *  Board level 2 header
+                        */
+
+                       pcbit_writew(dev, flen - FRAME_HDR_LEN);
 
-                        /*
-                         *  Board level 2 header 
-                         */
+                       pcbit_writeb(dev, msg->cpu);
 
-                        pcbit_writew(dev, flen - FRAME_HDR_LEN);
+                       pcbit_writeb(dev, msg->proc);
 
-                        pcbit_writeb(dev, msg->cpu);
+                       /* TH */
+                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
 
-                        pcbit_writeb(dev, msg->proc);
+                       /* TD */
+                       pcbit_writew(dev, frame->dt_len);
 
-                        /* TH */
-                        pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
 
-                        /* TD */
-                        pcbit_writew(dev, frame->dt_len);
+                       /*
+                        *  Board level 3 fixed-header
+                        */
 
+                       /* LEN = TH */
+                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
 
-                        /*
-                         *  Board level 3 fixed-header 
-                         */
-       
-                        /* LEN = TH */
-                        pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-       
-                        /* XX */
-                        pcbit_writew(dev, 0);
+                       /* XX */
+                       pcbit_writew(dev, 0);
 
-                        /* C + S */
-                        pcbit_writeb(dev, msg->cmd);
-                        pcbit_writeb(dev, msg->scmd);
+                       /* 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 @@ static void pcbit_transmit(struct pcbit_dev * dev)
                cli();
 
 
-                if (frame->skb == NULL || frame->copied == frame->skb->len) {
-
-                        dev->write_queue = frame->next;
-
-                        if (frame->skb != NULL) {
-                                /* free frame */
-                                dev_kfree_skb(frame->skb, FREE_WRITE);
-                        }
+               if (frame->skb == NULL || frame->copied == frame->skb->len) {
 
-                        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 @@ static void pcbit_transmit(struct pcbit_dev * dev)
  *  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 @@ void pcbit_deliver(void * data)
                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 @@ void pcbit_deliver(void * data)
 }
 
 /*
- * 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);
-
-
-                if (cpu != 0x06 && cpu != 0x02)
-                {
-                        printk (KERN_DEBUG "pcbit: invalid cpu value\n");
+               }
+               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");
                        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 @@ static void pcbit_receive(struct pcbit_dev * dev)
                        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 @@ static void pcbit_receive(struct pcbit_dev * dev)
  *  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;
-
-     if (chan->queued) {
-            chan->queued--;
-            
-            ictl.driver = dev->id;
-            ictl.command = ISDN_STAT_BSENT;
-            ictl.arg = chan->id;
-            dev->dev_if->statcallb(&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);
+       }
 }
 
-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);
+       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;
+               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_err_recover(unsigned long data)
 
 }
 
-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 @@ static void pcbit_l2_error(struct pcbit_dev *dev)
  *   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 */
+                               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;
+               i = dev->unack_seq;
 
-                do {
-                        dev->unack_seq = i = (i + 1) % 8;
-                        dev->free += dev->fsize[i];
-                } while (i != ack);
+               do {
+                       dev->unack_seq = i = (i + 1) % 8;
+                       dev->free += dev->fsize[i];
+               } while (i != ack);
 
-                count = 0;
-                while (count < 7 && dev->write_queue) 
-               {
+               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");
 }
index 2f2aa374f1ce94c7baba38f443776acffa3ef0e4..29e11b4866b2eea740e139a2eb592129ad93dc99 100644 (file)
@@ -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 void pcbit_terminate(int board);
 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 @@ int pcbit_init(void)
        }
 
        /* No symbols to export, hide all symbols */
+#if (LINUX_VERSION_CODE < 0x020111)
        register_symtab(NULL);
+#else
+       EXPORT_NO_SYMBOLS;
+#endif
 
        return 0;
 }
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
new file mode 100644 (file)
index 0000000..ff87210
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
new file mode 100644 (file)
index 0000000..3e5370f
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
new file mode 100644 (file)
index 0000000..28accdc
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
new file mode 100644 (file)
index 0000000..3a814de
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h
new file mode 100644 (file)
index 0000000..bb55535
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
new file mode 100644 (file)
index 0000000..3452cbf
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/hardware.h b/drivers/isdn/sc/hardware.h
new file mode 100644 (file)
index 0000000..b0f07ac
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
new file mode 100644 (file)
index 0000000..6ce4fb0
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
new file mode 100644 (file)
index 0000000..eeaecdd
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
new file mode 100644 (file)
index 0000000..18f6029
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
new file mode 100644 (file)
index 0000000..9915cb0
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c
new file mode 100644 (file)
index 0000000..26f0cfe
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/message.h b/drivers/isdn/sc/message.h
new file mode 100644 (file)
index 0000000..9b8bcb0
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
new file mode 100644 (file)
index 0000000..ccd3b20
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/scioc.h b/drivers/isdn/sc/scioc.h
new file mode 100644 (file)
index 0000000..19db0b7
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
new file mode 100644 (file)
index 0000000..6ff0812
--- /dev/null
@@ -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 --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
new file mode 100644 (file)
index 0000000..42abb3a
--- /dev/null
@@ -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 --git a/drivers/isdn/teles/Makefile b/drivers/isdn/teles/Makefile
deleted file mode 100644 (file)
index a252f46..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/buffers.c b/drivers/isdn/teles/buffers.c
deleted file mode 100644 (file)
index 2b76d95..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/callc.c b/drivers/isdn/teles/callc.c
deleted file mode 100644 (file)
index 7333fdc..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/card.c b/drivers/isdn/teles/card.c
deleted file mode 100644 (file)
index 2ada8a2..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/config.c b/drivers/isdn/teles/config.c
deleted file mode 100644 (file)
index 1a9d2d8..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/fsm.c b/drivers/isdn/teles/fsm.c
deleted file mode 100644 (file)
index c0b2f49..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/isdnl2.c b/drivers/isdn/teles/isdnl2.c
deleted file mode 100644 (file)
index 779b7b7..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/isdnl3.c b/drivers/isdn/teles/isdnl3.c
deleted file mode 100644 (file)
index 31f616f..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/l3_1TR6.c b/drivers/isdn/teles/l3_1TR6.c
deleted file mode 100644 (file)
index 1e237e1..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/l3_1TR6.h b/drivers/isdn/teles/l3_1TR6.h
deleted file mode 100644 (file)
index e3b538e..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/llglue.c b/drivers/isdn/teles/llglue.c
deleted file mode 100644 (file)
index 7e32c2f..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/mod.c b/drivers/isdn/teles/mod.c
deleted file mode 100644 (file)
index 821ac8e..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/proto.h b/drivers/isdn/teles/proto.h
deleted file mode 100644 (file)
index 0d7ae8e..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/q931.c b/drivers/isdn/teles/q931.c
deleted file mode 100644 (file)
index c9f5fa6..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/tei.c b/drivers/isdn/teles/tei.c
deleted file mode 100644 (file)
index 3ab9f36..0000000
+++ /dev/null
@@ -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 --git a/drivers/isdn/teles/teles.h b/drivers/isdn/teles/teles.h
deleted file mode 100644 (file)
index 15ce659..0000000
+++ /dev/null
@@ -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);
-
-
-
-
index fb139862fefe1374f69bd2abaa92fe5584f491ba..dc657089e3cc9f5ec234e6109b8be36aa38765b2 100644 (file)
@@ -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 @@ static const char *version =
 /* 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 @@ bad_clone_list[] = {
     {"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 @@ bad_clone_list[] = {
 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 @@ int ne_probe(struct device *dev)
     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 @@ int ne_probe(struct device *dev)
        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 @@ static int ne_probe1(struct device *dev, int ioaddr)
        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 @@ static int ne_probe1(struct device *dev, int ioaddr)
 
     }
 
-    if (pci_irq_line) {
+    if (pci_irq_line)
        dev->irq = pci_irq_line;
-    }
 
     if (dev->irq < 2) {
        autoirq_setup(0);
@@ -713,17 +740,17 @@ init_module(void)
                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;
index 74dca22f53afcc06bf61b449af23eca2f0ae083d..eddd11b0dc99b48bd6f1d7cabac7ad1f5369e918 100644 (file)
@@ -119,6 +119,7 @@ struct pci_dev_info dev_info[] = {
        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 @@ struct pci_dev_info dev_info[] = {
        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 @@ const char *pci_strvendor(unsigned int vendor)
              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 @@ const char *pci_strvendor(unsigned int vendor)
              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";
index 816cfe532c4a16c0515a6f272a36f4ad3ada53b6..1c6328fc99d3d7c328b7a35dcb0837de47ee36f2 100644 (file)
@@ -87,5 +87,6 @@ dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
     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
index caeb342eaae5134e8e10f3a26dba6a248bed0340..f1b16eaa3a718c1532e0c464b648ce2a5d37a4d6 100644 (file)
@@ -19,6 +19,7 @@ MOD_LIST_NAME := SCSI_MODULES
 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 @@ else
   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 @@ BusLogic.o: BusLogic.c FlashPoint.c
 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 --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
new file mode 100644 (file)
index 0000000..e909bf0
--- /dev/null
@@ -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 --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
new file mode 100644 (file)
index 0000000..3c92be2
--- /dev/null
@@ -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 --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h
new file mode 100644 (file)
index 0000000..01f5db4
--- /dev/null
@@ -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 --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
new file mode 100644 (file)
index 0000000..269a3c8
--- /dev/null
@@ -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 --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
new file mode 100644 (file)
index 0000000..a3d5dcd
--- /dev/null
@@ -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
+
index de8305b2345705aeddf7c39a96ce26b680ed02cb..287344ea9eebfe63698501093a2fb0a60c6ed093 100644 (file)
 #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 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_SUNESP
     SCSI_SPARC_ESP,
 #endif
+#ifdef CONFIG_SCSI_GDTH
+    GDTH,
+#endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
     IDESCSI,
 #endif
diff --git a/include/linux/b1lli.h b/include/linux/b1lli.h
new file mode 100644 (file)
index 0000000..401933c
--- /dev/null
@@ -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 --git a/include/linux/capi.h b/include/linux/capi.h
new file mode 100644 (file)
index 0000000..9876da0
--- /dev/null
@@ -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__ */
index cf6a8bf6ae2ed99e8dd3d8e3e3ab6fa3289aebf0..5e8f35b6ada0484fcdde76640e0251be44143104 100644 (file)
@@ -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).
  *
  * 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
  *
 #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 {
 
 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 @@ typedef struct {
   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 @@ typedef struct {
   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 @@ typedef struct {
 #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 @@ typedef struct {
 /* Phone-list-element */
 typedef struct {
   void *next;
-  char num[20];
+  char num[ISDN_MSNLEN];
 } isdn_net_phone;
 
 /* Local interface-data */
@@ -361,6 +407,7 @@ typedef struct isdn_net_local_s {
                                       /* 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 @@ typedef struct isdn_net_local_s {
   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 @@ typedef struct isdn_net_local_s {
   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 @@ typedef struct isdn_net_dev_s {
 #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 @@ typedef struct modem_info {
   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 @@ typedef struct {
 
 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 sqqueue {
 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 ippp_struct {
   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 @@ typedef struct {
   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 @@ typedef struct isdn_devt {
   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    */
index 5ce86f868e2781d11c179ca7db9357d2d18a0b6f..177646520470eea38c33e9c4da7021f7365b4319 100644 (file)
@@ -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 @@ struct pppinfo
 #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 */
+
index 76837784710eece5fff4775085644f90dfa5be68..5b1f18a882136410b9f2a1dc8ff52b47e0083bcc 100644 (file)
@@ -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
  *
  * 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.
  *
 #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
 #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 @@ typedef struct {
   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 @@ extern int register_isdn(isdn_if*);
 #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 @@ extern int register_isdn(isdn_if*);
 #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 --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
new file mode 100644 (file)
index 0000000..da0dea8
--- /dev/null
@@ -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__ */
index d6cfad56df2a673068c4e02ca64ccb67f99c2611..4cdf7ae0d45d8dfb3350fd3562696e85b7284c27 100644 (file)
 #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
 
 #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
index 08cc269e38e4d33908272b2a1471d8dc74bbed77..2498662facdcde9ab26c47e14a2b0f019b1ff2c3 100644 (file)
@@ -141,6 +141,7 @@ enum scsi_directory_inos {
        PROC_SCSI_A2091,
        PROC_SCSI_GVP11,
        PROC_SCSI_ATARI,
+       PROC_SCSI_GDTH,
        PROC_SCSI_IDESCSI,
        PROC_SCSI_SCSI_DEBUG,   
        PROC_SCSI_NOT_PRESENT,
index 1943074a2f0a7f7f5c55f63710b4ae5cf7e349b8..de32b6164bbfd98946d203bda1b62cbf3a05a2ee 100644 (file)
@@ -89,6 +89,7 @@ extern void generic_NCR5380_setup(char *str, int *intr);
 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 @@ static void no_initrd(char *s,int *ints);
 #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 @@ extern void gvp11_setup (char *str, int *ints);
 #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 @@ struct {
 #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 @@ struct {
 #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 },
index 78459e8383da1c8a11ca22d3cee9e95f931e968f..9d2693bd7f99ab488d322cea8d1ea85a2077332a 100644 (file)
@@ -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 @@ NORET_TYPE void panic(const char * fmt, ...)
                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(;;);
index 377fcc649ddf8de65412d1c035e42301e8e121e2..d4f3c12aaba5a3dcb569d9b9ca5449cd151ddfcb 100644 (file)
@@ -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 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
                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 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
  */
 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);
 }