]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.1.92 - Feature Freeze 2.1.92
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:05 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:05 +0000 (15:15 -0500)
Ok, there's a fairly large patch out there, but as of 2.1.92 I think we
have a real feature-freeze, and we'll try to get a real code-freeze going
soon. There are known problems with the sound drivers etc, which is why a
code-freeze isn't the best suggestion right now, and there are probably
still bugs with some of the new code, but I'll freeze new features for the
upcoming 2.2 kernel.

Yes, some people will scream bloody murder, but others will be relieved
that it finally happened. Thanks especially to David Miller who has been
doing a great job of getting the TCP stack from its problems just a few
weeks ago to really shining new heights. That was my main worry about 2.2
not all that long ago, and was the main reason for having such a slushy
period for a while.

2.1.92 does:
 - ISDN updates
 - alpha update (yes, SMP finally works, although not really stable yet)
 - networking fixes
 - "getcwd()" system call (not very long, the dcache makes this so
   trivial it is scary)
 - the mm responsiveness updates (they were in 2.1.92-pre2, people seemed
   to have found them very effective)
 - some other (mainly driver updates)

Please do test it all out. Feature-freeze doesn't mean that it is supposed
to be bug-free yet, but it does mean that we should be moving into
bugfixing mode in quick order.
And no, this is not an April 1 thing. But this way I can use April 1 as an
excuse if something doesn't actually compile.

                Linus

176 files changed:
CREDITS
Documentation/Configure.help
Documentation/isdn/00-INDEX
Documentation/isdn/CREDITS
Documentation/isdn/INTERFACE
Documentation/isdn/README
Documentation/isdn/README.HiSax
Documentation/isdn/README.act2000 [new file with mode: 0644]
Documentation/isdn/README.concap [new file with mode: 0644]
Documentation/isdn/README.x25 [new file with mode: 0644]
Documentation/serial-console.txt
arch/i386/kernel/entry.S
arch/i386/kernel/ioport.c
drivers/char/apm_bios.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/serial.c
drivers/isdn/Config.in
drivers/isdn/Makefile
drivers/isdn/act2000/Makefile [new file with mode: 0644]
drivers/isdn/act2000/act2000.h [new file with mode: 0644]
drivers/isdn/act2000/act2000_isa.c [new file with mode: 0644]
drivers/isdn/act2000/act2000_isa.h [new file with mode: 0644]
drivers/isdn/act2000/capi.c [new file with mode: 0644]
drivers/isdn/act2000/capi.h [new file with mode: 0644]
drivers/isdn/act2000/module.c [new file with mode: 0644]
drivers/isdn/avmb1/b1capi.c
drivers/isdn/avmb1/b1lli.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/capi.c
drivers/isdn/avmb1/capidrv.c
drivers/isdn/avmb1/capiutil.c
drivers/isdn/avmb1/compat.h
drivers/isdn/hisax/Makefile
drivers/isdn/hisax/amd7930.c [new file with mode: 0644]
drivers/isdn/hisax/arcofi.c [new file with mode: 0644]
drivers/isdn/hisax/arcofi.h [new file with mode: 0644]
drivers/isdn/hisax/asuscom.c [new file with mode: 0644]
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/avm_a1.h [deleted file]
drivers/isdn/hisax/buffers.c [deleted file]
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c [new file with mode: 0644]
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa.h [deleted file]
drivers/isdn/hisax/fsm.c
drivers/isdn/hisax/hfc_2bds0.c [new file with mode: 0644]
drivers/isdn/hisax/hfc_2bds0.h [new file with mode: 0644]
drivers/isdn/hisax/hfc_2bs0.c [new file with mode: 0644]
drivers/isdn/hisax/hfc_2bs0.h [new file with mode: 0644]
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hscx.c [new file with mode: 0644]
drivers/isdn/hisax/hscx.h [new file with mode: 0644]
drivers/isdn/hisax/hscx_irq.c [new file with mode: 0644]
drivers/isdn/hisax/ipac.h [new file with mode: 0644]
drivers/isdn/hisax/isac.c [new file with mode: 0644]
drivers/isdn/hisax/isac.h [new file with mode: 0644]
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/isdnl1.h
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hisax/isdnl3.c
drivers/isdn/hisax/isdnl3.h
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/ix1_micro.h [deleted file]
drivers/isdn/hisax/l3_1tr6.c
drivers/isdn/hisax/l3_1tr6.h
drivers/isdn/hisax/l3dss1.c
drivers/isdn/hisax/l3dss1.h [new file with mode: 0644]
drivers/isdn/hisax/lmgr.c [new file with mode: 0644]
drivers/isdn/hisax/mic.c [new file with mode: 0644]
drivers/isdn/hisax/netjet.c [new file with mode: 0644]
drivers/isdn/hisax/niccy.c [new file with mode: 0644]
drivers/isdn/hisax/q931.c
drivers/isdn/hisax/rawhdlc.c [new file with mode: 0644]
drivers/isdn/hisax/rawhdlc.h [new file with mode: 0644]
drivers/isdn/hisax/sedlbauer.c [new file with mode: 0644]
drivers/isdn/hisax/siemens.h [deleted file]
drivers/isdn/hisax/sportster.c [new file with mode: 0644]
drivers/isdn/hisax/tei.c
drivers/isdn/hisax/teleint.c [new file with mode: 0644]
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles0.h [deleted file]
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/teles3.h [deleted file]
drivers/isdn/hisax/teles3c.c [new file with mode: 0644]
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/isdn/isdn_audio.c
drivers/isdn/isdn_cards.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_concap.c [new file with mode: 0644]
drivers/isdn/isdn_concap.h [new file with mode: 0644]
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 [deleted file]
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_v110.c [new file with mode: 0644]
drivers/isdn/isdn_v110.h [new file with mode: 0644]
drivers/isdn/isdn_x25iface.c [new file with mode: 0644]
drivers/isdn/isdn_x25iface.h [new file with mode: 0644]
drivers/isdn/isdnloop/Makefile [new file with mode: 0644]
drivers/isdn/isdnloop/isdnloop.c [new file with mode: 0644]
drivers/isdn/isdnloop/isdnloop.h [new file with mode: 0644]
drivers/isdn/pcbit/capi.c
drivers/isdn/pcbit/drv.c
drivers/isdn/pcbit/layer2.c
drivers/isdn/pcbit/module.c
drivers/isdn/sc/debug.c
drivers/isdn/sc/event.c
drivers/isdn/sc/hardware.h
drivers/isdn/sc/init.c
drivers/isdn/sc/interrupt.c
drivers/isdn/sc/message.c
drivers/isdn/sc/packet.c
drivers/misc/parport_pc.c
drivers/net/smc-mca.c
drivers/scsi/sg.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/buffer.c
fs/dcache.c
fs/exec.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/proc/fd.c
fs/proc/inode.c
fs/proc/link.c
fs/proc/mem.c
include/asm-i386/bugs.h
include/asm-i386/unistd.h
include/linux/b1lli.h
include/linux/binfmts.h
include/linux/capability.h [new file with mode: 0644]
include/linux/concap.h [new file with mode: 0644]
include/linux/console.h
include/linux/if_ppp.h
include/linux/isdn.h
include/linux/isdn_ppp.h
include/linux/isdnif.h
include/linux/proc_fs.h
include/linux/sched.h
include/linux/securebits.h [new file with mode: 0644]
include/linux/skbuff.h
include/linux/sysctl.h
include/linux/types.h
include/linux/vmalloc.h
include/net/sock.h
include/net/tcp.h
init/main.c
kernel/kmod.c
kernel/ksyms.c
kernel/printk.c
kernel/sched.c
kernel/sysctl.c
mm/vmalloc.c
net/bridge/br.c
net/bridge/br_tree.c
net/ipv4/ip_masq_app.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv6/ip6_output.c
net/ipv6/tcp_ipv6.c
net/netsyms.c
scripts/Configure
scripts/Menuconfig
scripts/header.tk
scripts/tail.tk
scripts/tkgen.c

diff --git a/CREDITS b/CREDITS
index 5bed63d68fbd77b466407cf63ca1d6f99c8c253f..82b2c2092163465848bf3f35bf617d0f57778b2f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -438,8 +438,8 @@ E: bj0rn@blox.se
 W: http://www.pi.se/blox/
 D: Extended support for loadable modules
 D: D-Link pocket adapter drivers
-S: Myrstuguv. 83
-S: S-143 32 VARBY
+S: Grevgatan 11
+S: S-114 53 Stockholm
 S: Sweden
 
 N: Paal-Kristian Engstad
@@ -1625,11 +1625,13 @@ S: F-35042 Rennes Cedex
 S: France
 
 N: Jon Tombs
-E: jon@gtex02.us.es
+E: jon@gte.esi.us.es
+W: http://www.esi.us.es/~jon
 D: NFS mmap()
 D: XF86_S3
 D: Kernel modules
-S: C/ Carlos de Cepeda 36 2-5
+D: Parts of varios other programs (xfig, open, ...)
+S: C/ Federico Garcia Lorca 1 10-A
 S: Sevilla 41005
 S: Spain
 
index 71ca8d481ab8f6f667be2ee35daaf8afa5fe7bb9..64cb0570272850d564d8e4d961b7e6d94c2deb71 100644 (file)
@@ -7066,6 +7066,12 @@ CONFIG_ISDN_AUDIO
   is the only voice-supporting driver. See
   Documentation/isdn/README.audio for more information.
 
+X.25 PLP on top of ISDN (EXPERIMENTAL)
+CONFIG_ISDN_X25
+  This experimental feature provides X.25 over ISDN. See
+  Documentation/isdn/README.x25 for more information about how to
+  configure and what other options must be enabled for using X.25.
+
 ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
   This enables support for two kinds of ISDN-cards made by a German
@@ -7079,6 +7085,14 @@ CONFIG_ISDN_DRV_ICN
   want), say M here and read Documentation/modules.txt. The module
   will be called icn.o.
 
+isdnloop support
+CONFIG_ISDN_DRV_LOOP
+  This driver provides a virtual ISDN card. It's primary purpose is
+  testing of linklevel features or configuration without getting
+  charged by your service-provider for lots of phone calls.
+  You need will need the loopctrl utility from the latest isdn4k-utils
+  package to set up this driver.
+
 HiSax SiemensChipSet driver support
 CONFIG_ISDN_DRV_HISAX
   This is a driver supporting the Siemens chipset on various
@@ -7104,36 +7118,95 @@ CONFIG_HISAX_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.
+  non-standard irq/port settings.
+
+HiSax Support for Teles 16.3c
+CONFIG_HISAX_TELES3C
+  This enables HiSax support for the Teles ISDN-cards 16.3c.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port settings.
 
 HiSax Support for 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.
+  non-standard irq/port settings.
 
 HiSax Support for Elsa ISA cards
-CONFIG_HISAX_ELSA_PCC
-  This enables HiSax support for the Elsa Mircolink ISA cards and
-  for the Elsa Quickstep series cards.
+CONFIG_HISAX_ELSA
+  This enables HiSax support for the Elsa Mircolink ISA cards,
+  for the Elsa Quickstep series cards and Elsa 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 Elsa PCMCIA card
-CONFIG_HISAX_ELSA_PCMCIA
-  This enables HiSax support for the Elsa PCMCIA cards.
-  See Documentation/isdn/README.HiSax on how to configure it 
-  using the different cards, a different D-channel protocol, or
-  non-standard IRQ/port/shmem settings.
+  non-standard irq/port 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.
+  non-standard irq/port settings.
+
+HiSax Support for Eicon.Diehl Diva cards
+CONFIG_HISAX_DIEHLDIVA
+  This enables HiSax support for the Eicon.Diehl Diva none PRO versions
+  passive ISDN cards.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port settings.
+
+HiSax Support for ASUSCOM cards
+CONFIG_HISAX_ASUSCOM
+  This enables HiSax support for the AsusCom and their OEM versions
+  passive ISDN cards.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port settings.
+
+HiSax Support for TELEINT cards
+CONFIG_HISAX_TELEINT
+  This enables HiSax support for the TELEINT SA1 semiactiv ISDN 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 settings.
+
+HiSax Support for Sedlbauer speed card/win-star
+CONFIG_HISAX_SEDLBAUER
+  This enables HiSax support for the Sedlbauer passive ISDN cards.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port settings.
+
+HiSax Support for USR Sportster internal TA
+CONFIG_HISAX_SPORTSTER
+  This enables HiSax support for the USR Sportster internal TA card.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using a different D-channel protocol, or non-standard irq/port settings.
+
+HiSax Support for MIC card
+CONFIG_HISAX_MIC
+  This enables HiSax support for the ITH MIC card.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using a different D-channel protocol, or non-standard irq/port settings.
+
+HiSax Support for NETjet card
+CONFIG_HISAX_NETJET
+  This enables HiSax support for the NetJet from Traverse Technologies.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using a different D-channel protocol, or non-standard irq/port settings.
+
+HiSax Support for Niccy PnP/PCI card
+CONFIG_HISAX_NICCY
+  This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using a different D-channel protocol, or non-standard irq/port settings.
+
+HiSax Support for Am7930 (EXPERIMENTAL)
+CONFIG_HISAX_AMD7930
+  This enables HiSax support for the AMD7930 chips on some sparcs.
+  This code is not finished yet.
 
 HiSax Support for EURO/DSS1
 CONFIG_HISAX_EURO
@@ -7142,7 +7215,18 @@ CONFIG_HISAX_EURO
   NOTE: This is mutually exclusive with HiSax Support for
   German 1TR6 if you have only one ISDN card installed.
 
-HiSax Support for US/NI-1
+Support for german tarifinfo
+CONFIG_DE_AOC
+  If you want, that HiSax send messages to the linklevel on each
+  AOCD/AOCE, enable this. This works only in Germany.
+
+Support for australian Microlink service (not for std. EURO)
+CONFIG_HISAX_ML
+  If you are in Australia and connected on the Microlink telephone
+  network enable this, because here are little differences in protocol.
+  Please don't enable this in other countries.
+
+HiSax Support for US/NI-1 (not released yet)
 CONFIG_HISAX_NI1
   You should choose the D-channel protocol your local
   telephone service provider uses here by saying Y or N.
@@ -7199,6 +7283,14 @@ CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
   disconnecting. This will increase the size of the kernel by 7K. If
   unsure, say Y.
 
+IBM Active 2000 support (EXPERIMENTAL)
+CONFIG_ISDN_DRV_ACT2000
+  This enables support for IBM Active 2000 ISDN card. In order to use
+  this card, additional firmware is necessary, which has to be loaded
+  into the card using a utility which is part of the latest isdn4k-utils
+  package. Please read the file Documentation/isdn/README.act2000 for
+  more information.
+
 Support for AP1000 multicomputer
 CONFIG_AP1000
   This enables support for a sparc based parallel multi-computer
index 401697921b9dc5a77fd5df14647e45cb8f763164..919af90576546aa79caea0142a13258f0a369d3f 100644 (file)
@@ -19,4 +19,12 @@ README.syncppp
 syncPPP.FAQ
        - frequently asked questions about running PPP over ISDN.
 README.avmb1
-       - info on driver for AVM-B1 ISDN card
+       - info on driver for AVM-B1 ISDN card.
+README.act2000
+       - info on driver for IBM ACT-2000 card.
+README.concap
+       - info on "CONCAP" ecapsulation protocol interface used for X.25.
+README.sc
+       - info on driver for Spellcaster cards.
+README.x25
+    _ info for running X.25 over ISDN.
index 44e6554a7647dff2ff68c3d5dd342da03db864bb..6fd4c9ed5beba7dfaef4b81be2f49e3d0a89dc5a 100644 (file)
@@ -8,6 +8,9 @@ Thomas Bogend
 Alan Cox (alan@cymru.net)
   For help getting into standard-kernel.
 
+Henner Eisen (eis@baty.hanse.de)
+  For X.25 implementation.
+
 Volker Götz (volker@oops.franken.de)
   For contribution of man-pages, the imontty-tool and a perfect
   maintaining of the mailing-list at hub-wue.
@@ -37,18 +40,24 @@ Pedro Roque Marques (roque@di.fc.ul.pt)
 Eberhard Moenkeberg (emoenke@gwdg.de)
   For testing and help to get into kernel.
 
+Thomas Neumann (tn@ruhr.de)
+  For help with Cisco-SLARP and keepalive
+
 Jan den Ouden (denouden@groovin.xs4all.nl)
-  For contribution of the teles-driver
+  For contribution of the original teles-driver
+
+Carsten Paeth (calle@calle.in-berlin.de)
+  For the AVM-B1-CAPI2.0 driver
+
+Thomas Pfeiffer (pfeiffer@pds.de)
+  For V.110, extended T.70 and Hylafax extensions in isdn_tty.c
 
 Max Riegel (riegel@max.franken.de)
   For making the ICN hardware-documentation and test-equipment available.
 
-Gerhard 'Fido' Schneider (fido@wuff.franken.de)
+Gerhard 'Fido' Schneider (fido@wuff.mayn.de)
   For heavy-duty-beta-testing with his BBS ;)
 
 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 81dddb08177b8757c92b9146099c6d70dce8ae6d..5b25c959708826424e16922cde446d657fdf5a99 100644 (file)
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.6 1997/02/10 22:40:57 fritz Exp $
+$Id: INTERFACE,v 1.8 1998/02/20 17:38:20 fritz Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -22,7 +22,7 @@ Description of the Interface between Linklevel and Hardwarelevel
   got a separate version number. These numbers are shown at initialization,
   separated by slashes:
 
-     c.c/t.t/n.n/p.p/a.a
+     c.c/t.t/n.n/p.p/a.a/v.v
 
   where
 
@@ -31,11 +31,13 @@ Description of the Interface between Linklevel and Hardwarelevel
    n.n is the revision of the network related code.
    p.p is the revision of the ppp related code.
    a.a is the revision of the audio related code.
+   v.v is the revision of the V.110 related code.
 
   Changes in this document are marked with '***CHANGEx' where x representing
   the version number. If that number starts with 0, it refers to the old,
   separately distributed package. If it starts with one of the letters
   above, it refers to the revision of the corresponding module. 
+  ***CHANGEIx refers to the revision number of the isdnif.h  
 
 1. Description of the fields of isdn_if:
 
@@ -65,32 +67,16 @@ Description of the Interface between Linklevel and Hardwarelevel
 
   unsigned short hl_hdrlen;
 
-    ***CHANGED.7.4: New field.
+    ***CHANGE0.7.4: New field.
 
     To be preset by the HL-driver, if it supports sk_buff's. The driver
     should put here the amount of additional space needed in sk-buff's for
     its internal purposes. Drivers not supporting sk_buff's should put
     initialize this field to 0.
 
-  void (*rcvcallb)(int, int, u_char*, int);
-
-    ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function
-                    anymore, since it will be removed when all current
-                    LL drivers have been changed accordingly. Use
-                    rcvcallb_skb instead.
-
-    This field will be set by LL. The HL-driver delivers received data-
-    packets by calling this function.
-
-    Parameter:
-      int    driver-Id
-      int    Channel-number locally to the driver. (starting with 0)
-      u_char Pointer to received data. (in kernel-space)
-      int    length of data-packet.
-
   void (*rcvcallb_skb)(int, int, struct sk_buff *)
 
-    ***CHANGED.7.4: New field.
+    ***CHANGE0.7.4: New field.
 
     This field will be set by LL. The HL-driver delivers received data-
     packets by calling this function. Upon calling, the HL-driver must
@@ -138,41 +124,22 @@ Description of the Interface between Linklevel and Hardwarelevel
     Returnvalue:
       >=0 on success, else error-code (-ENODEV etc.)
 
-  int (*writebuf)(int, int, u_char*, int, int);
+  int (*writebuf_skb)(int, int, int, struct sk_buff *)
 
-    ***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.
-
-    This field has to be preset by the HL-driver. The given function will
-    be called by the LL for delivering data to be send via B-Channel.
-
-    Parameter:
-      int     driver-Id ***CHANGE.7.4: New parameter.
-      int     channel-number locally to the HL-driver. (starts with 0)
-      u_char* pointer to data.
-      int     length of data-packet.
-      int     flag: 0 = call from within kernel-space. (HL-driver must use
-                        memcpy, may NOT use schedule())
-                    1 = call from user-space. (HL-driver must use
-                        memcpy_fromfs, use of schedule() allowed)
-
-    Returnvalue:
-      Length of data accepted on success, else error-code (-EINVAL on
-      oversized packets etc.)
-
-  int (*writebuf_skb)(int, int, struct sk_buff *)
-
-    ***CHANGED.7.4: New field.
+    ***CHANGE0.7.4: New field.
+    ***CHANGEI.1.21: New field.
 
     This field has to be preset by the HL-driver. The given function will
     be called by the LL for delivering data to be send via B-Channel.
 
  
     Parameter:
-      int              driver-Id ***CHANGE.7.4: New parameter.
+      int              driver-Id ***CHANGE0.7.4: New parameter.
       int              channel-number locally to the HL-driver. (starts with 0)
+      int             ack ***ChangeI1.21: New parameter
+                      If this is !0, the driver has to signal the delivery
+                      by sending an ISDN_STAT_BSENT. If this is 0, the driver
+                      MUST NOT send an ISDN_STAT_BSENT.
       struct sk_buff * Pointer to sk_buff containing data to be send via
                        B-channel.
 
@@ -199,7 +166,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       int     driver-Id.
       int     channel-number locally to the HL-driver. (starts with 0)
 
-***CHANGED1.14: The driver-Id and channel-number are new since this revision.
+***CHANGEI1.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 +190,7 @@ Description of the Interface between Linklevel and Hardwarelevel
       int     driver-Id.
       int     channel-number locally to the HL-driver. (starts with 0)
 
-***CHANGED1.14: The driver-Id and channel-number are new since this revision.
+***CHANGEI1.14: The driver-Id and channel-number are new since this revision.
 
     Returnvalue:
       Length of data on success, else error-code (-EINVAL etc.)
@@ -249,7 +216,7 @@ 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
+***CHANGEI1.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.
 
@@ -552,6 +519,9 @@ Description of the Interface between Linklevel and Hardwarelevel
    a B-Channel-connection. (Response to ISDN_CMD_ACCEPTB or because the
    remote-station has initiated establishment)
 
+   The HL driver should call this when the logical l2/l3 protocol 
+   connection on top of the physical B-channel is esatblished .
+
     Parameter:
       driver      = driver-Id
       command     = ISDN_STAT_BCONN
@@ -577,6 +547,9 @@ Description of the Interface between Linklevel and Hardwarelevel
    B-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
    or caused by a remote-hangup.
 
+   The HL driver should call this as soon as the logical l2/l3 protocol 
+   connection on top of the physical B-channel is released.
+
     Parameter:
       driver      = driver-Id
       command     = ISDN_STAT_BHUP
@@ -617,7 +590,9 @@ 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)
-      para        = unused.
+      para.length = ***CHANGEI.1.21: New field.
+                   the driver has to set this to the original length
+                   of the skb at the time of receiving it from the linklevel.
 
   ISDN_STAT_NODCH:
 
@@ -657,3 +632,16 @@ Description of the Interface between Linklevel and Hardwarelevel
       arg         = channel-number, locally to the driver. (starting with 0)
       para.num    = ASCII string containing CAUSE-message.
 
+  ISDN_STAT_L1ERR:
+
+    ***CHANGEI1.21 new status message.
+    A signal can be sent to the linklevel if an Layer1-error results in
+    packet-loss on receive or send. The field errcode of the cmd.parm
+    union describes the error more precisely.
+
+    Parameter:
+      driver      = driver-Id
+      command     = ISDN_STAT_L1ERR
+      arg         = channel-number, locally to the driver. (starting with 0)
+      para.errcode= ISDN_STAT_L1ERR_SEND:     Packet lost while sending.
+                   ISDN_STAT_L1ERR_RECV:     Packet lost while receiving.
index 48dec2d836c86bf29e5f7b33cc6a84c7d209b39b..1d94afb689092f7b5ce381cf907f5a4bf5475b1a 100644 (file)
@@ -120,12 +120,35 @@ 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&Rx    Select V.110 bitrate adaption.
+                        This command enables V.110 protocol with 9600 baud
+                        (x=9600), 19200 baud (x=19200) or 38400 baud
+                        (x=38400). A value of x=0 disables V.110 switching
+                        back to default X.75. This command sets the following
+                        Registers:
+                          Reg 14 (Layer-2 protocol):
+                            x = 0:     0
+                            x = 9600:  7
+                            x = 19200: 8
+                            x = 38400: 9
+                          Reg 18.2 = 1
+                          Reg 19 (Additional Service Indicator):
+                            x = 0:       0
+                            x = 9600:  197
+                            x = 19200: 199
+                            x = 38400: 198
+                          Note on value in Reg 19:
+                            There is _NO_ common convention for 38400 baud.
+                            The value 198 is choosen arbitrarily. Users
+                            _MUST_ negotiate this value before establishing
+                            a connection.
               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).
-               AT&X0   BTX-mode off (default)
-              AT&X1    BTX-mode on. (S13.1=1, S14=0, S16=7, S18=7, S19=0)
+               AT&X0   BTX-mode and T.70-mode off (default)
+              AT&X1    BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0)
+              AT&X2    T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0)
 
            For voice-mode commands refer to README.audio
 
@@ -184,12 +207,23 @@ README for the ISDN-subsystem
                                      1 = Extended response messages
                             Bit 4:    0 = CALLER NUMBER before every RING.
                                       1 = CALLER NUMBER after first RING.
+                            Bit 5:    0 = T.70 extended protocol off
+                                      1 = T.70 extended protocol on
+                            Bit 6:    0 = Special RUNG Message off
+                                      1 = Special RUNG Message on
+                                          "RUNG" is delivered on a ttyI, if
+                                          an incoming call happened (RING) and
+                                          the remote party hung up before any
+                                          local ATA was given.
             14   0         Layer-2 protocol:
                                      0 = X75/LAPB with I-frames
                                      1 = X75/LAPB with UI-frames
                                       2 = X75/LAPB with BUI-frames
                                       3 = HDLC
                                       4 = Transparent (audio)
+                                      7 = V.110, 9600 baud
+                                      8 = V.110, 19200 baud
+                                      9 = V.110, 38400 baud
              15   0         Layer-3 protocol: (at the moment always 0)
                                       0 = transparent
             16   250       Send-Packet-size/16
@@ -406,6 +440,9 @@ README for the ISDN-subsystem
             are stripped off.  
    ip       IP with type-field. Same as IP but the type-field of the MAC-header
             is preserved.
+   x25iface x25 interface encapsulation (first byte semantics as defined in
+           ../networking/x25-iface.txt). Use this for running the linux
+           x25 network protocol stack (AF_X25 sockets) on top of isdn.
    cisco-h  A special-mode for communicating with a Cisco, which is configured
             to do "hdlc"
    ethernet No stripping. Packets are sent with full MAC-header.
@@ -415,6 +452,11 @@ README for the ISDN-subsystem
 
    uihdlc   HDLC with UI-frame-header (for use with DOS ISPA, option -h1)
 
+
+   NOTE:    x25iface encapsulation is currently experimental. Please
+           read README.x25 for further details    
+
+
    Watching packets, using standard-tcpdump will fail for all encapsulations
    except ethernet because tcpdump does not know how to handle packets
    without MAC-header. A patch for tcpdump is included in the utility-package
@@ -423,7 +465,8 @@ README for the ISDN-subsystem
    "isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>" 
    Selects a layer-2-protocol. 
    (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
-   With other drivers, "x75ui", "x75bui" may be possible too.)
+   With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be
+   possible too. See README.x25 for x25 related l2 protocols.)
 
    isdnctrl l3_prot <InterfaceName> <L3-ProtocolName> 
    The same for layer-3. (At the moment only "trans" is allowed)
index 20b578d8322172d8a96f610210685631f323fbd2..21f849cbd62b8106bbf84eb1ce31bcf126ce87dd 100644 (file)
@@ -23,24 +23,39 @@ Supported cards
 ---------------
 
 Teles 8.0/16.0/16.3 and compatible ones
+Teles 16.3c
 Teles S0/PCMCIA
 Creatix PnP S0 
-AVM A1 (Fritz)
+Compaq ISDN S0 ISA card
+AVM A1 (Fritz, Teledat 150)
 ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8
 ELSA Quickstep 1000
+ELSA Quickstep 1000PCI
+ELSA Quickstep 3000 (same settings as QS1000)
 ELSA PCMCIA
 ITK ix1-micro Rev.2
+Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
+Eicon.Diehl Diva Piccola
+ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
+Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
+HFC-2BS0 based cards (TeleInt SA1)
+Sedlbauer Speed Card (Speed Win, Teledat 100)
+Sedlbauer Speed Star (PCMCIA)
+USR Sportster internal TA (compatible Stollmann tina-pp V3)
+ith Kommunikationstechnik GmbH MIC 16 ISA card 
+Traverse Technologie NETjet PCI S0 card
+Dr. Neuhaus Niccy PnP/PCI
 
 Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
       PCC-8: not tested yet
       Teles PCMCIA is EXPERIMENTAL
+      Teles 16.3c is EXPERIMENTAL
+      Eicon.Diehl Diva U interface not tested
 
 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.
+(io, mem, irq).
 
 
 Configuring the driver
@@ -113,10 +128,26 @@ Card types:
     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)
+    7   ELSA Quickstep 1000      irq, io  (from isapnp setup)
     8   Teles 16.3 PCMCIA       irq, io
     9   ITK ix1-micro Rev.2      irq, io
+   10   ELSA PCMCIA             irq, io  (set with card manager)
+   11   Eicon.Diehl Diva ISA PnP irq, io
+   11   Eicon.Diehl Diva PCI     no parameter
+   12   ASUS COM ISDNLink        irq, io  (from isapnp setup)
+   13   HFC-2BS0 based cards     irq, io  
+   14   Teles 16.3c PnP          irq, io
+   15   Sedlbauer Speed Card     irq, io  
+   16   USR Sportster internal   irq, io  
+   17   MIC card                 irq, io  
+   18   ELSA Quickstep 1000PCI   no parameter
+   19   Compaq ISDN S0 ISA card  irq, io0, io1, io (from isapnp setup io=IO2)
+   20   NETjet PCI card          no parameter
+   22   Sedlbauer Speed Star (PCMCIA) irq, io (set with card manager)
+   24   Dr. Neuhaus Niccy PnP    irq, io0, io1 (from isapnp setup)
+   24   Dr. Neuhaus Niccy PCI    no parameter
+
+
         
 At the moment IRQ sharing is not possible. Please make sure that your IRQ
 is free and enabled for ISA use.
@@ -181,17 +212,28 @@ where
 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
+    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
+    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
+    7   ELSA Quickstep 1000     ONLY WORKS AS A MODULE !
+    8   Teles S0 PCMCIA         pa=irq  pb=iobase
     9   ITK ix1-micro Rev.2     pa=irq  pb=iobase
-
+   10   ELSA PCMCIA             pa=irq, pb=io  (set with card manager)
+   11   Eicon.Diehl Diva ISAPnP ONLY WORKS AS A MODULE !
+   11   Eicon.Diehl Diva PCI    no parameter
+   12   ASUS COM ISDNLink       ONLY WORKS AS A MODULE !
+   13  HFC-2BS0 based cards    pa=irq  pb=io
+   14   Teles 16.3c PnP         ONLY WORKS AS A MODULE !
+   15  Sedlbauer Speed Card    pa=irq  pb=io (Speed Win only as module !)  
+   16   USR Sportster internal  pa=irq  pb=io
+   17   MIC card                pa=irq  pb=io
+   18   ELSA Quickstep 1000PCI  no parameter
+   19   Compaq ISDN S0 ISA card ONLY WORKS AS A MODULE !
+   20   NETjet PCI card         no parameter
+   21   Sedlbauer Speed Star (PCMCIA)  pa=irq, pb=io  (set with card manager)
 
 Running the driver
 ------------------
@@ -215,8 +257,8 @@ 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.
+Cabling problems or line-downs are not detected, and only some 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
@@ -226,9 +268,9 @@ 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:
+At the moment, debugging messages are enabled with the hisaxctrl tool:
 
-    telesctrl <DriverId> DebugCmd <debugging_flags>
+    hisaxctrl <DriverId> DebugCmd <debugging_flags>
 
 <DriverId> default is HiSax, if you didn't specified one.
 
@@ -271,7 +313,14 @@ With DebugCmd set to 13:
          4  l3 state machine
          8  charge info debugging (1TR6)
 
-For example, 'telesctrl HiSax 1 0x3ff' enables full generic debugging.
+For example, 'hisaxctrl HiSax 1 0x3ff' enables full generic debugging.
+
+Because of some obscure problems with some switch equipment, the delay
+between CONNECT message and sending the first data on th B-channel is now
+configurable with 
+
+hisaxctrl <DriverId> 2 <delay>
+<delay> in ms Value between 50 an 800 ms are recommended.
 
 
 Warning
@@ -284,7 +333,7 @@ illegal.
 Limitations
 -----------
 At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines.
-
+For leased lines see appendix. 
 
 Bugs 
 ----
@@ -301,10 +350,20 @@ Special thanks to:
         Andreas Kool, Pekka Sarnila, Sim Yskes, Johan Myrre'en,
        Klaus-Peter Nischke (ITK AG), Christof Petig, Werner Fehn (ELSA GmbH),
        Volker Schmidt
+       Edgar Toernig and Marcus Niemann for the Sedlbauer driver
+       Stephan von Krawczynski
+       Juergen Quade for the Leased Line part
+       Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE), for ELSA PCMCIA support
         and more people who are hunting bugs. (If I forgot somebody, please
        send me a mail). 
 
         Firma ELSA GmbH
+        Firma Eicon.Diehl GmbH
+        Firma Dynalink NL
+       Firma ASUSCOM NETWORK INC. Taiwan
+       Firma S.u.S.E
+       Firma ith Kommunikationstechnik GmbH
+       Firma Traverse Technologie Australia
         
         My girl friend and partner in life Ute for her patience with me.
 
@@ -321,3 +380,171 @@ Appendix: Teles PCMCIA driver
 See 
    http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
 for instructions.
+
+Appendix: Linux and ISDN-leased lines
+-------------------------------------
+
+Original from Juergen Quade, new version KKe.
+
+Attention NEW VERSION, the old leased line syntax won't work !!!
+
+You can use HiSax to connect your Linux-Box via an ISDN leased line
+to i.e. the internet:
+
+1. Build a kernel which includes the HiSax driver either as a module
+   or as part of the kernel.
+     cd /usr/src/linux
+     make menuconfig
+     <ISDN subsystem - ISDN support -- HiSax>
+     make clean; make dep; make zImage; make modules; make modules_install
+2. Install the new kernel
+     cp /usr/src/linux/arch/i386/boot/zImage /etc/kernel/linux.isdn
+     vi /etc/lilo.conf
+     <add new kernel in the bootable image section>
+     lilo
+3. in case the hisax driver is a "fixed" part of the kernel, configure
+   the driver with lilo:
+     vi /etc/lilo.conf
+     <add HiSax driver parameter in the global section (see below)>
+     lilo
+   Your lilo.conf _might_ look as the following:
+
+       # LILO configuration-file
+       # global section
+    # teles 16.0 on IRQ=5, MEM=0xd8000, PORT=0xd80
+       append="hisax=1,3,5,0xd8000,0xd80,HiSax"
+    # teles 16.3 (non pnp) on IRQ=15, PORT=0xd80
+       # append="hisax=3,3,5,0xd8000,0xd80,HiSax"
+       boot=/dev/sda
+       compact        # faster, but won't work on all systems.
+       linear
+       read-only
+       prompt
+       timeout=100
+       vga = normal    # force sane state
+       # Linux bootable partition config begins
+       image = /etc/kernel/linux.isdn
+       root = /dev/sda1
+       label = linux.isdn
+       #
+       image = /etc/kernel/linux-2.0.30
+       root = /dev/sda1
+       label = linux.secure
+
+   In the line starting with "append" you have to adapt the parameters
+   according to your card (see above in this file)
+
+3. boot the new linux.isdn kernel
+4. start the ISDN subsystem:
+   a) load - if necessary - the modules (depends, whether you compiled
+      the ISDN driver as module or not)
+      According to the type of card you have to specify the necessary
+      driver parameter (irq, io, mem, type, protocol).
+      For the leased line the protocol is "3". See the table above for
+      the parameters, which you have to specify depending on your card.
+   b) configure i4l
+      /sbin/isdnctrl addif isdn0
+      # EAZ  1 -- B1 channel   2 --B2 channel
+      /sbin/isdnctrl eaz isdn0 1
+      /sbin/isdnctrl secure isdn0 on
+      /sbin/isdnctrl huptimeout isdn0 0
+      /sbin/isdnctrl l2_prot isdn0 hdlc
+      # Attention you must not set a outgoing number !!! This won't work !!!
+      # The incomming number is LEASED0 for the first card, LEASED1 for the
+      # second and so on. 
+      /sbin/isdnctrl addphone isdn0 in LEASED0
+      # Here is no need to bind the channel.
+   c) in case the remote partner is a CISCO:
+      /sbin/isdnctrl encap isdn0 cisco-h
+   d) configure the interface
+      /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP}
+   e) set the routes
+      /sbin/route add -host ${REMOTE_IP} isdn0
+      /sbin/route add default gw ${REMOTE_IP}
+   f) switch the card into leased mode for each used B-channel 
+      /sbin/hisaxctrl HiSax 5 1
+Remarks:
+a) If you have a CISCO don´t forget to switch off the KEEP ALIVE option!
+
+Here an example script:
+#!/bin/sh
+# Start/Stop ISDN lesaed line connection
+
+I4L_AS_MODULE=yes
+I4L_REMOTE_IS_CISCO=no
+I4L_MODULE_PARAMS="type=16 io=0x268 irq=7 "
+I4L_DEBUG=no
+I4L_LEASED_128K=yes
+LOCAL_IP=192.168.1.1
+REMOTE_IP=192.168.2.1
+
+case "$1" in
+    start)
+       echo "Starting ISDN ..."
+        if [ ${I4L_AS_MODULE} = "yes" ]; then
+               echo "loading modules..."
+               /sbin/modprobe hisax ${I4L_MODULE_PARAMS}
+       fi
+       # configure interface
+       /sbin/isdnctrl addif isdn0
+       /sbin/isdnctrl secure isdn0 on
+       if [ ${I4L_DEBUG} = "yes" ]; then
+               /sbin/isdnctrl verbose 7
+               /sbin/hisaxctrl HiSax 1 0xffff
+               /sbin/hisaxctrl HiSax 11 0xff
+               cat  /dev/isdnctrl >/tmp/lea.log &
+       fi
+       if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then
+               /sbin/isdnctrl encap isdn0 cisco-h
+       fi
+       /sbin/isdnctrl huptimeout isdn0 0
+       # B-CHANNEL 1
+       /sbin/isdnctrl eaz isdn0 1
+       /sbin/isdnctrl l2_prot isdn0 hdlc
+       # 1. card
+       /sbin/isdnctrl addphone isdn0 in LEASED0
+        if [ ${I4L_LEASED_128K} = "yes" ]; then
+               /sbin/isdnctrl addslave isdn0 isdn0s
+               /sbin/isdnctrl secure isdn0s on
+               /sbin/isdnctrl huptimeout isdn0s 0
+               # B-CHANNEL 2
+               /sbin/isdnctrl eaz isdn0s 2
+               /sbin/isdnctrl l2_prot isdn0s hdlc
+               # 1. card
+               /sbin/isdnctrl addphone isdn0s in LEASED0
+               if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then
+                       /sbin/isdnctrl encap isdn0s cisco-h
+               fi
+       fi
+       # configure tcp/ip
+       /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP}
+       /sbin/route add -host ${REMOTE_IP} isdn0
+       /sbin/route add default gw ${REMOTE_IP}
+       # switch to leased mode
+       # B-CHANNEL 1
+       /sbin/hisaxctrl HiSax 5 1
+        if [ ${I4L_LEASED_128K} = "yes" ]; then
+               # B-CHANNEL 2
+               /sbin/hisaxctrl HiSax 5 2
+       fi
+       ;;
+    stop)
+       /sbin/ifconfig isdn0 down
+       /sbin/isdnctrl delif isdn0
+       if [ ${I4L_DEBUG} = "yes" ]; then
+               killall cat
+       fi
+       if [ ${I4L_AS_MODULE} = "yes" ]; then
+               /sbin/rmmod hisax
+               /sbin/rmmod isdn
+               /sbin/rmmod ppp
+               /sbin/rmmod slhc
+       fi
+       ;;
+    *)
+       echo "Usage: $0 {start|stop}"
+       exit 1
+esac
+exit 0
+
diff --git a/Documentation/isdn/README.act2000 b/Documentation/isdn/README.act2000
new file mode 100644 (file)
index 0000000..9535822
--- /dev/null
@@ -0,0 +1,104 @@
+$Id: README.act2000,v 1.1 1997/09/24 23:50:16 fritz Exp $
+
+This document describes the ACT2000 driver for the
+IBM Active 2000 ISDN card.
+
+There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
+Version. Currently, only the ISA-Bus version of the card is supported.
+However MCA and PCMCIA will follow soon.
+
+The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set
+manually using the DIP switches.
+
+Setting up the DIP switches for the IBM Active 2000 ISDN card:
+
+        Note: S5 and S6 always set off!
+
+     S1  S2  S3  S4  Base-port
+     on  on  on  on  0x0200 (Factory default)
+     off on  on  on  0x0240 
+     on  off on  on  0x0280 
+     off off on  on  0x02c0 
+     on  on  off on  0x0300 
+     off on  off on  0x0340 
+     on  off off on  0x0380 
+     on  on  on  off 0xcfe0
+     off on  on  off 0xcfa0 
+     on  off on  off 0xcf60 
+     off off on  off 0xcf20 
+     on  on  off off 0xcee0 
+     off on  off off 0xcea0 
+     on  off off off 0xce60 
+     off off off off Card disabled 
+
+IRQ is configured by software. Possible values are:
+
+  3, 5, 7, 10, 11, 12, 15 and none (polled mode)
+
+
+The ACT2000 driver either may be build into kernel or as a module.
+Initialization depends on how the driver is built:
+
+Driver built into the kernel:
+
+  The ACT2000 driver can be configured using the commandline-feature while
+  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
+
+  act2000=b,p,i[,idstring]
+
+  where
+
+    b = Bus-Type      (1=ISA, 2=MCA, 3=PCMCIA)
+    p = portbase      (-1 means autoprobe)
+    i = Interrupt     (-1 means use next free IRQ, 0 means polled mode)
+
+  The idstring is an arbitrary string used for referencing the card
+  by the actctrl tool later.
+
+  Defaults used, when no parameters given at all:
+
+    1,-1,-1,""
+
+  which means: Autoprobe for an ISA card, use next free IRQ, let the
+  ISDN linklevel fill the IdString (usually "line0" for the first card).
+  If you like to use more than one card, you can use the program
+  "actctrl" from the utility-package to configure additional cards.
+
+  Using the "actctrl"-utility, portbase and irq can also be changed
+  during runtime. The D-channel protocol is configured by the "dproto"
+  option of the "actctrl"-utility after loading the firmware into the
+  card's memory using the "actctrl"-utility.
+
+Driver built as module:
+
+  The module act2000.o can be configured during modprobe (insmod) by
+  appending its parameters to the modprobe resp. insmod commandline.
+  The following syntax is accepted:
+
+    act_bus=b act_port=p act_irq=i act_id=idstring
+
+  where b, p, i and idstring have the same meanings like parameters
+  described for the builtin version above.
+
+  Using the "actctrl"-utility, the same features apply to the modularized
+  version like to the kernel-builtin one. (i.e. loading of firmware and
+  configuring the D-channel protocol)
+
+Loading the firmware into the card:
+
+  The firmware is supplied together with the isdn4k-utils package. It
+  can be found in the subdirectory act2000/firmware/
+
+  Assumed you have installed the utility-package correctly, the firmware
+  will be downloaded into the card using the following command:
+
+    actctrl -d idstring load /etc/isdn/bip11.btl
+
+  where idstring is the Name of the card, given during insmod-time or
+  (for kernel-builtin driver) on the kernel commandline. If only one
+  ISDN card is used, the -d isdstrin may be omitted.
+
+  For further documentation (adding more IBM Active 2000 cards), refer to
+  the manpage actctrl.8 which is included in the isdn4k-utils package.
+
diff --git a/Documentation/isdn/README.concap b/Documentation/isdn/README.concap
new file mode 100644 (file)
index 0000000..b6ff4d2
--- /dev/null
@@ -0,0 +1,258 @@
+Description of the "concap" encapsulation protocol interface
+============================================================
+
+The "concap" interface is intended to be used by network device
+drivers that need to process an encapsulation protocol. 
+It is assumed that the protocol interacts with a linux network device by
+- data transmission
+- connection control (establish, release)
+Thus, the mnemonic: "CONnection CONtrolling eNCAPsulation Protocol".
+
+This is currently only used inside the isdn subsystem. But it might
+also be useful to other kinds of network devices. Thus, if you want
+to suggest changes that improve usability or performace of the
+interface, please let me know. I'm willing to include them in future
+releases (even if I needed to adapt the current isdn code to the
+changed interface).
+
+
+Why is this useful?
+===================
+
+The encapsulation protocol used on top of WAN connections or permanent
+point-to-point links are frequently chosen upon bilateral agreement.
+Thus, a device driver for a certain type of hardware must support
+several different encapsulation protocols at once.
+
+The isdn device driver did already support several different
+encapsulation protocols. The encapsulation protocol is configuered by a
+user space utility (isdnctrl). The isdn network interface code then
+uses several case statements which select appropriate actions
+depending on the currently configuered encapsulation protocol.
+
+In contrast, LAN network interfaces always used a single encapsulation
+protocol which is unique to the hardware type of the interface. The LAN
+encapsulation is usually done by just sticking a header at the data. Thus,
+traditional linux network device drivers used to process the
+encapsulation protocol directly (usually by just providing a hard_header()
+method in the device structure) using some hardware type specific support
+functions. This is simple, direct and efficient. But it doesn't fit all
+the requirements for complex WAN encapsulations. 
+
+
+   The configurability of the encapsulation protocol to be used
+   makes isdn network interfaces more flexible, but also much more
+   complex than traditional lan network interfaces.
+
+
+Many Encapsulation protocols used on top of WAN connections will not just
+stick a header at the data. They also might need to set up or release
+the WAN connection. They also might want to send other data for their
+private purpose over the wire. I.e. ppp does a lot of link level
+negotiation before the first peace of user data can be transmitted.
+Such encapsulation protocols for WAN devices are typically more complex
+than encapsulation protocols for lan devices. Thus, network interfaces
+code for typical WAN devices also tends to be more more complex.
+
+
+In order to support Linux' x25 PLP implementation on top of
+isdn network interfaces I could have introduced yet another branch to
+the various case statements inside drivers/isdn/isdn_net.c.
+This eventually made isdn_net.c even more complex. In addition, it made
+isdn_net.c harder to maintain. Thus, by identifying an abstract
+interface between the network interface code and the encapsulation
+protocol, complexity could be reduced and maintainability could be
+increased.
+
+
+Likewise, a same encapsulation protocol will frequently be needed by
+several different interfaces of even different hardware type. I.e. the
+synchronous ppp implementaion used by the isdn driver and the
+asyncronous ppp implemntation used by the ppp driver have a lot of
+similar code in them. By cleanly separating the encapsulation protocol
+from the hardware specific interface stuff such code could be shared
+better in future.
+
+
+When operating over dial-up-connections (i.e. telephone lines via modem,
+non-permanent virtual circuits of wide area networks, ISDN) many
+encapsulation protocols will need to control the connection. Therfore,
+some basic connection control primitives are supported. The type and
+semantics of the connection (i.e the ISO layer where connection service
+is provided) is outside our scope and might be different depending on
+the encapsulation protocol used. I.e. for a ppp module using our service
+on top of a modem connection a connect_request will result in dialing
+a (somewhere else configured) remote phone number. For an X25-interface
+module (LAPB semantics, as defined in Documentation/networking/x25-iface.txt)
+a connect_request will ask for establishing a reliable lapb
+datalink connection.
+
+
+The encapsulation protocol currently provides the follwing
+service primitives to the network device.
+
+- create a new encapsulation protocol instance
+- delete encapsulation protocol instance and free all its resources
+- initialize (open) the encapsulation protocol instance for use.
+- deactivate (close) an encapsulation protocol instance.
+- process (xmit) data handed down by upper protocol layer
+- receive data from lower (hardware) layer
+- process connect indication from lower (hardware) layer
+- process disconnect indication from lower (hardware) layer
+
+
+The network interface driver accesses those primitives via callbacks
+provided by the encapsulation protocol instance within a
+struct concap_proto_ops.
+
+struct concap_proto_ops{
+
+       /* create a new encapsulation protocol instance of same type */
+       struct concap_proto *  (*proto_new) (void);
+
+       /* delete encapsulation protocol instance and free all its resources.
+          cprot may no loger be referenced after calling this */
+       void (*proto_del)(struct concap_proto *cprot);
+
+       /* initialize the protocol's data. To be called at interface startup
+          or when the device driver resets the interface. All services of the
+          encapsulation protocol may be used after this*/
+       int (*restart)(struct concap_proto *cprot, 
+                      struct device *ndev,
+                      struct concap_device_ops *dops);
+
+       /* inactivate an encapsulation protocol instance. The encapsulation
+          protocol may not call any *dops methods after this. */
+       int (*close)(struct concap_proto *cprot);
+
+       /* process a frame handed down to us by upper layer */
+       int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
+
+       /* to be called for each data entity received from lower layer*/ 
+       int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
+
+       /* to be called when a connection was set up/down.
+          Protocols that don't process these primitives might fill in
+          dummy methods here */
+       int (*connect_ind)(struct concap_proto *cprot);
+       int (*disconn_ind)(struct concap_proto *cprot);
+};
+
+
+The data structures are defined in the header file include/linux/concap.h.
+
+
+A Network interface using encapsulation protocols must also provide
+some service primitives to the encapsulation protocol:
+
+- request data beeing submitted by lower layer (device hardware) 
+- request a connection beeing set up by lower layer 
+- request a connection beeing released by lower layer
+
+The encapsulations protocol accesses those primitives via callbacks
+provided by the network interface within a struct concap_device_ops.
+
+struct concap_device_ops{
+
+       /* to request data is submitted by device*/ 
+       int (*data_req)(struct concap_proto *, struct sk_buff *);
+
+       /* Control methods must be set to NULL by devices which do not
+          support connection control.*/
+       /* to request a connection is set up */ 
+       int (*connect_req)(struct concap_proto *);
+
+       /* to request a connection is released */
+       int (*disconn_req)(struct concap_proto *);      
+};
+
+The network interface does not explicitly provide a receive service
+because the encapsulation protocol directly calls netif_rx(). 
+
+
+
+
+An encapsulation protocol itsself is actually the
+struct concap_proto{
+       struct device *net_dev;         /* net device using our service  */
+       struct concap_device_ops *dops; /* callbacks provided by device */
+       struct concap_proto_ops  *pops; /* callbacks provided by us */
+       int flags;
+       void *proto_data;               /* protocol specific private data, to
+                                          be accessed via *pops methods only*/
+       /*
+         :
+         whatever 
+         :
+         */
+};
+
+Most of this is filled in when the device requests the protocol to 
+be reset (opend). The network interface must provide the net_dev and
+dops pointers. Other concap_proto members should be considerd private
+data that are only accessed by the pops callback functions. Likewise,
+a concap proto should access the network device's private data
+only by means of the callbacks referred to by the dops pointer.
+
+
+A possible extended device structure which uses the connection controlling
+encapsulation services could look like this:
+
+struct concap_device{
+       struct device net_dev;
+       struct my_priv  /* device->local stuff */
+                       /* the my_priv struct might contain a 
+                          struct concap_device_ops *dops;
+                          to provide the device specific callbacks
+                       */
+       struct concap_proto *cprot;        /* callbacks provided by protocol */
+};
+
+
+
+Misc Thoughts
+=============
+
+The concept of the concap proto might help to reuse protocol code and
+reduce the complexity of certain network interface implementations.
+The trade off is that it introduces yet another procedure call layer
+when processing the protocol. This has of course some impact on
+performace. However, typically the concap interface will be used by
+devices attached to slow lines (like telephone, isdn, leased synchronous
+lines). For such slow lines, the overhead is probably neglectable.
+This might no longer hold for certain high speed WAN links (like
+ATM).
+
+
+If general linux network interfaces explicitly supported concap
+protocols (i.e. by a member struct concap_proto* in struct device)
+then the interface of the service function could be changed
+by passing a pointer of type (struct device*) instead of
+type (struct concap_proto*). Doing so would make many of the service
+functions compatible to network device support fuctions. i.e.
+
+i.e. instead of the concap protocol's service function
+
+  int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
+
+we could have
+
+  int (*encap_and_xmit)(struct device *ndev, struct sk_buff *skb);
+
+As this is compatible to the dev->hard_start_xmit() method, the device
+driver could directly register the concap protocol's encap_and_xmit()
+fuction as its hard_start_xmit() method. This would eliminate one
+procedure call layer.
+
+
+The device's data request function could also be defined as
+  int (*data_req)(struct device *ndev, struct sk_buff *skb);
+
+This might even allow for some protocol stacking. And the network
+interface might even register the same data_req() function directly
+as its hard_start_xmit() method when a zero layer encapsulation
+protocol is configured. Thus, eliminating the performace penalty
+of the concap interface when a trivial concap protocol is used.
+Nevertheless, the device remains able to support encapsulation
+protocol configuration.
diff --git a/Documentation/isdn/README.x25 b/Documentation/isdn/README.x25
new file mode 100644 (file)
index 0000000..3737bc9
--- /dev/null
@@ -0,0 +1,217 @@
+X25 support within isdn4linux
+
+
+This is experimental code and should be used with linux version 2.1.72.
+or later. Use it completely on your own risk.
+
+
+As new versions appear, the stuff described here might suddenly change
+or become invalid without notice.
+
+Keep in mind:
+
+You are using an experimental kernel (2.1.x series) with an experimental
+x25 protocol implementation and experimental x25-on-top-of-isdn extensions.
+Thus, be prepared to face problems related therefrom.
+
+- If you connect to an x25 neighbour not operated by yourself, ASK the
+  other side first. Be prepared that bugs in the protocol implementation
+  might result in problems (even crashing the peer, however such ugly events
+  should only happen if your peer's protocol implementation has serious bugs).
+
+- This implementation has never wiped out my whole hard disk yet. But as
+  this is experimental code, don't blame me if that happened to you. Take
+  appropriate actions (such as backing up important data) before
+  trying this code.
+
+- Monitor your isdn connections while using this software. This should
+  prevent you from undesired phone bills in case of driver problems.
+  
+
+
+How to configure the kernel
+
+The ITU-T (former CCITT) X.25 network protocol layer has been implemented
+in the Linux source tree since version 2.1.16. The isdn subsystem might be 
+useful to run X.25 on top of ISDN. If you want to try it, select
+
+   "CCITT X.25 Packet Layer"
+
+from the networking options as well as
+
+   "ISDN Support" and "X.25 PLP on Top of ISDN"
+
+from the ISDN subsystem options when you configure your kernel for
+compilation. You currently also need to enable
+"Prompt for development and/or incomplete code/drivers" from the
+"Code maturity level options" menu. For the x25trace utility to work
+you also need to enable "Packet socket" (I recommend to choose "y",
+not "m" for testing) from the networking options.
+
+
+For testing you should also select the isdnloop driver from the
+isdn subsystem's configuration menu.
+
+
+
+What's it for? How to use it?
+
+
+X25 on top of isdn might be useful with two different scenarios:
+
+- You might want to access a public X.25 data network from your Linux box.
+  You can use i4l if you were physically connected to the X.25 switch
+  by an ISDN line (leased line as well as dial up connection should work,
+  but connecting to x.25 network switches is currently untested. Testing
+  needs to be done by somebody with access to such a switch.) 
+
+- Or you might want to operate certain ISDN teleservices on 
+  your linux box. A lot of those teleservices run on top of the ISO-8208 
+  network layer protocol. ISO-8208 is essentially the same as ITU-T X.25.
+
+  Popular candidates of such teleservices are EUROFILE transfer or any
+  teleservice applying ITU-T recommendation T.90 (i.e., AFAIK, G4 Fax).
+
+To use the X.25 protocol on top of isdn, just create an isdn network
+interface as usual, configure your own and/or peer's ISDN numbers,
+and choose x25iface encapsulation by
+
+   isdnctrl encap <iface-name> x25iface.
+
+Once encap is set like this, the device can be used by the x25 packet layer.
+
+All the stuff needed for x25 is implemented inside the isdn link
+level (mainly isdn_net.c and some new source files). Thus, it should
+work with every existing HL driver. I was able to successfully open x25
+connections on top of the isdnloop driver and the hisax driver.
+"x25iface"-encapsulation bypasses demand dialing. Dialing will be
+initiated when the upper (x25 packet) layer requests the lapb datalink to
+be established. But hangup timeout is still active. The connection
+will not automatically be re-established by the isdn_net module
+itself when new data arrives after the hangup timeout. But
+the x25 network code will re-establish the datalink connection
+(resulting in re-dialing and an x25 protocol reset) when new data is
+to be transmitted. (This currently does not work properly with the
+isdnloop driver, see "known problems" below)
+
+
+In order to set up a conforming protocol stack you also need to
+specify the proper l2_prot parameter:
+
+To operate in ISO-8208  X.25 DTE-DTE mode, use
+
+   isdnctrl l2_prot <iface-name> x75i
+
+To access an X.25 network switch via isdn (your linux box is the DTE), use
+
+   isdnctrl l2_prot <iface-name> x25dte
+
+To mimic an X.25 network switch (DCE side of the connection), use
+
+   isdnctrl l2_prot <iface-name> x25dce
+
+However, x25dte or x25dce is currently not supported by any real HL
+level driver. The main difference between x75 and x25dte/dce is that
+x25d[tc]e uses fixed lap_b addresses. With x75i, the side which
+initiates the isdn connection uses the DTE's lap_b address while the
+called side used the DCE's lap_b address. Thus, l2_prot x75i will
+probably work if you access a public x25 network as long as the
+corresponding isdn connection is set up by you. However, I've never
+tested this.
+
+
+
+How to use the test installation?
+
+
+To test x25 on top of isdn, you need to get
+
+- a patched version of the "isdnctrl" program that supports setting the new
+  x25 specific parameters.
+
+- the x25-utils-2.1.x package from ftp.pspt.fi/pub/ham/linux/ax25
+  or any mirror site (i.e. ftp://ftp.gwdg.de/pub/linux/misc/ax25/).
+
+- a kernel patch that enhances isdn4linux to provide x25 network
+  interface support. (This file is part of that kernel patch).
+
+- an application that uses linux AF_X25 sockets program. 
+
+Before compiling the user level utilities make sure that the compiler/
+preprocessor will fetch the proper (patched) kernel header files. Either make
+/usr/include/linux a symbolic link pointing to your developer kernel's
+include/linux directory or set the appropriate compiler flags.
+
+It is recommended that all isdn drivers and the x25 PLP protocol 
+are compiled as loadable modules. Like this, you can recover
+from certain errors by simply unloading and reloading the modules.
+
+When all drivers and interfaces are loaded and configured you need to
+ifconfig the network interfaces up and add x25-routes to them. Use
+the usual ifconfig tool.
+
+ifconfig <iface-name> up
+
+But a special x25route tool (distributed with the x25-util package)
+is needed to set up x25 routes. I.e. 
+
+x25route add 01 <iface-name>
+
+will cause all x.25 connections to the destination x.25-address
+"01" beeing routed to your created isdn network interface.
+
+
+There are currently no real x25 applications available. However, for
+tests, the x25-utils package contains a modified version of telnet
+and telnetd that uses x25 sockets instead of tcp/ip sockets. Use
+this for your first tests. Furthermore, there is an x25.echod and a client
+named "eftp" (which contains some experimental code to download files
+from a remote eft server using the EUROfile transfer protocol).
+It available at ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/eftp4linux-*
+
+The x25-utility package also contains an x25trace tool that can be
+used to monitor x25 packets received by the network interfaces.
+The /proc/net/x25* files also contain useful information. 
+
+The eftp4linux test release also contains an "ix25test" script that can
+be used for testing x25 on top of isdn4linux. Edit
+this script according to your local needs and then call it as
+
+ix25test start
+
+This will set up a sample configuration using the isdnloop and hisax
+driver and create some isdn network interfaces.
+It is recommended that all other isdn drivers and the
+x25 module is unloaded before calling this script.
+
+
+
+Known problems and deficiencies:
+
+The isdnloop HL driver apparently has problems to re-establish a
+connection that has been hang up from the outgoing device. You have to
+unload the isdnloop driver after the faked isdn-connection is closed
+and insmod it again. With the Hisax driver, this problem is not present.
+
+Sometimes the x25 module cannot be unloaded (decrementation of its use
+count seems to get lost occasionally).
+
+Using the x25 based telnet and telnetd programm to establish connection
+from your own to your own computer repeatedly sometimes totally locked
+up my system. However, this kernel patch also modifies
+net/x25/af_x25.c to include a workaround. With this workaround
+enabled, my system is stable. (If you want to disable the
+workaround, just undefine ISDN_X25_FIXES in af_x25.c).
+
+The latter problem could be reproduced by using hisax as well as the
+isdnloop driver. It seems that it is not caused by the isdn code.
+Somehow, the inode of a socket is freed while a process still refers
+the socket's wait queue. This causes problems when the process tries to
+remove itsself from the wait queue (refered by the dangling
+sock->sleep pointer) before returning from a select() system call.
+
+- Henner
+
index 36a3e9c811a51c151aaa72a750b5b33358325c8c..2894b8008110f039d71a746abd1af6a75b86fb8e 100644 (file)
@@ -19,10 +19,10 @@ The format of this option is:
                        9600n8. The maximum baudrate is 115200.
 
 You can specify multiple console= options on the kernel command line.
-Output will appear on all of them. The first device will be used when
+Output will appear on all of them. The last device will be used when
 you open /dev/console. So, for example:
 
-       console=tty0 console=ttyS1,9600
+       console=ttyS1,9600 console=tty0
 
 defines that opening /dev/console will get you the current foreground
 virtual console, and kernel messages will appear on both the VGA
@@ -91,4 +91,4 @@ Replace the sample values as needed.
    for porting the patches from 2.1.4x to 2.1.6x for taking care of
    the integration of these patches into m68k, ppc and alpha.
 
-Miquel van Smoorenburg <miquels@cistron.nl>, 03-Dec-1997
+Miquel van Smoorenburg <miquels@cistron.nl>, 21-Mar-1998
index edec2e2500feab21a0cd06c952650d198eb043cf..a4ee0abb2a34c7b45c49cbc885930e352d646fb6 100644 (file)
@@ -543,6 +543,7 @@ ENTRY(sys_call_table)
        .long SYMBOL_NAME(sys_pread)            /* 180 */
        .long SYMBOL_NAME(sys_pwrite)
        .long SYMBOL_NAME(sys_chown)
+       .long SYMBOL_NAME(sys_getcwd)
        
        .rept NR_syscalls-182
                .long SYMBOL_NAME(sys_ni_syscall)
index 44fd26530d673c0686cad512a456641d6e338845..19587312a0da7b90b9cb2d808e3961f7ed4545b0 100644 (file)
@@ -76,8 +76,6 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
        return 0;
 }
 
-unsigned int *stack;
-
 /*
  * sys_iopl has to be used when you want to access the IO ports
  * beyond the 0x3ff range: to get the full 65536 ports bitmapped
index 29aeaa48bc02c2ee702e0c775edb6725e1fa5c6d..f4fcf4f7bb92371663f1ccab88918cf328f7fe32 100644 (file)
@@ -1159,8 +1159,10 @@ __initfunc(void apm_bios_init(void))
        static struct proc_dir_entry *ent;
 
 #ifdef __SMP__
-       printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
-       return;
+       if (smp_num_cpus > 1) {
+               printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
+               return;
+       }
 #endif
        if (apm_bios_info.version == 0) {
                printk(KERN_INFO "APM BIOS not found.\n");
index 8c024bba58da7862ed5ff4b487511b3120106742..2999b70ddfb3ef53eb60e6643c697d015b7070eb 100644 (file)
@@ -163,14 +163,22 @@ static inline int lp_char(char lpchar, int minor)
        unsigned long count = 0;
        struct lp_stats *stats;
 
-       do {
-               status = r_str (minor);
-               count++;
+       for (;;) {
                lp_yield(minor);
-       } while (!LP_READY(minor, status) && count < LP_CHAR(minor));
-
-       if (count == LP_CHAR(minor))
-               return 0;
+               status = r_str (minor);
+               if (++count == LP_CHAR(minor))
+                       return 0;
+               if (LP_POLLING(minor))
+               {
+                       if (LP_READY(minor, status))
+                               break;
+               } else {
+                       if (!LP_READY(minor, status))
+                               return 0;
+                       else
+                               break;
+               }
+       }
 
        w_dtr(minor, lpchar);
        stats = &LP_STAT(minor);
index 1ca4412af999b6af8f4f0a2e853ff75a1fd7afaa..4216d14bd8bdb7462e76396880a56a93b1830ec4 100644 (file)
@@ -385,9 +385,6 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
                default:
                        return -EINVAL;
        }
-       if (file->f_pos < 0)
-               return 0;
-       return file->f_pos;
 }
 
 #define mmap_kmem      mmap_mem
index ce45a97aa561ed68571afb939237a0eb20388683..f5d5895a2002ee7d85c2dd13942f082334de8479 100644 (file)
@@ -3212,7 +3212,7 @@ __initfunc(int rs_init(void))
         *      The interrupt of the serial console port
         *      can't be shared.
         */
-       if (sercons.flags & CON_FIRST) {
+       if (sercons.flags & CON_CONSDEV) {
                for(i = 0; i < NR_PORTS; i++)
                        if (i != sercons.index &&
                            rs_table[i].irq == rs_table[sercons.index].irq)
index 758e30d2bcaef0c731c1aa4ce3cf8f1cc37d9da6..3787c735fbe1116773284aad9271c7a82fdbb54e 100644 (file)
@@ -9,24 +9,44 @@ if [ "$CONFIG_INET" != "n" ]; then
   fi
 fi
 bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+if [ "$CONFIG_X25" != "n" ]; then
+  bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
+fi
 dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
 dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
 dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+    if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+           bool 'Support for german tarifinfo' CONFIG_DE_AOC
+           bool 'Support for australian Microlink service (not for std. EURO)' CONFIG_HISAX_ML
+    fi
+    bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
     bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
     bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+    bool 'HiSax Support for Teles 16.3c' CONFIG_HISAX_TELES3C 
     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 Elsa cards' CONFIG_HISAX_ELSA
     bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
-    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
-    bool 'HiSax Support for US/NI-1' CONFIG_HISAX_NI1
-    bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+    bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+    bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
+    bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
+    bool 'HiSax Support for Sedlbauer speed card/win/star' CONFIG_HISAX_SEDLBAUER
+    bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+    bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
+    bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
+    bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+        bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+    fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
        dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+       dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
 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 c5f508217d884aef270e3d918df535165054ca69..35d56d14222da29e6090b647da9774bb6e0ec1e6 100644 (file)
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn pcbit hisax avmb1
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000
 
 L_OBJS :=
 LX_OBJS :=
@@ -13,11 +13,15 @@ O_TARGET :=
 
 ifeq ($(CONFIG_ISDN),y)
   L_TARGET := isdn.a
-  L_OBJS += isdn_common.o isdn_net.o isdn_tty.o isdn_cards.o
-  LX_OBJS += isdn_syms.o
+  L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o
+  LX_OBJS += isdn_common.o 
   ifdef CONFIG_ISDN_PPP
     L_OBJS += isdn_ppp.o
   endif
+  ifdef CONFIG_ISDN_X25
+    L_OBJS += isdn_x25iface.o
+    L_OBJS += isdn_concap.o
+  endif
   ifdef CONFIG_ISDN_AUDIO
     L_OBJS += isdn_audio.o
   endif
@@ -25,11 +29,15 @@ else
   ifeq ($(CONFIG_ISDN),m)
     M_OBJS += isdn.o
     O_TARGET += isdn.o
-    O_OBJS += isdn_common.o isdn_net.o isdn_tty.o
-    OX_OBJS += isdn_syms.o
+    O_OBJS += isdn_net.o isdn_tty.o isdn_v110.o
+    OX_OBJS += isdn_common.o
     ifdef CONFIG_ISDN_PPP
       O_OBJS += isdn_ppp.o
     endif
+    ifdef CONFIG_ISDN_X25
+      O_OBJS += isdn_x25iface.o
+      O_OBJS += isdn_concap.o
+    endif  
     ifdef CONFIG_ISDN_AUDIO
       O_OBJS += isdn_audio.o
     endif
@@ -96,5 +104,15 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
+  L_OBJS += act2000/act2000.o
+  SUB_DIRS += act2000
+  MOD_SUB_DIRS += act2000
+else
+  ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
+    MOD_SUB_DIRS += act2000
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
new file mode 100644 (file)
index 0000000..0e3c4a7
--- /dev/null
@@ -0,0 +1,15 @@
+L_OBJS :=
+M_OBJS :=
+O_OBJS := module.o capi.o act2000_isa.o
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
+  O_TARGET += act2000.o
+else
+  ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
+       O_TARGET += act2000.o
+       M_OBJS = act2000.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
new file mode 100644 (file)
index 0000000..534cc42
--- /dev/null
@@ -0,0 +1,239 @@
+/* $Id: act2000.h,v 1.5 1997/10/09 22:22:59 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: act2000.h,v $
+ * Revision 1.5  1997/10/09 22:22:59  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.4  1997/09/25 17:25:37  fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3  1997/09/24 23:11:43  fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.2  1997/09/24 19:44:12  fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1  1997/09/23 18:00:05  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef act2000_h
+#define act2000_h
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#define ACT2000_IOCTL_SETPORT    1
+#define ACT2000_IOCTL_GETPORT    2
+#define ACT2000_IOCTL_SETIRQ     3
+#define ACT2000_IOCTL_GETIRQ     4
+#define ACT2000_IOCTL_SETBUS     5
+#define ACT2000_IOCTL_GETBUS     6
+#define ACT2000_IOCTL_SETPROTO   7
+#define ACT2000_IOCTL_GETPROTO   8
+#define ACT2000_IOCTL_SETMSN     9
+#define ACT2000_IOCTL_GETMSN    10
+#define ACT2000_IOCTL_LOADBOOT  11
+#define ACT2000_IOCTL_ADDCARD   12
+
+#define ACT2000_IOCTL_TEST      98
+#define ACT2000_IOCTL_DEBUGVAR  99
+
+#define ACT2000_BUS_ISA          1
+#define ACT2000_BUS_MCA          2
+#define ACT2000_BUS_PCMCIA       3
+
+/* Struct for adding new cards */
+typedef struct act2000_cdef {
+       int bus;
+        int port;
+        int irq;
+        char id[10];
+} act2000_cdef;
+
+/* Struct for downloading firmware */
+typedef struct act2000_ddef {
+        int length;             /* Length of code */
+        char *buffer;           /* Ptr. to code   */
+} act2000_ddef;
+
+typedef struct act2000_fwid {
+        char isdn[4];
+        char revlen[2];
+        char revision[504];
+} act2000_fwid;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.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/delay.h>
+#include <linux/ctype.h>
+#include <linux/isdnif.h>
+
+#endif                           /* __KERNEL__ */
+
+#define ACT2000_PORTLEN        8
+
+#define ACT2000_FLAGS_RUNNING  1 /* Cards driver activated */
+#define ACT2000_FLAGS_PVALID   2 /* Cards port is valid    */
+#define ACT2000_FLAGS_IVALID   4 /* Cards irq is valid     */
+#define ACT2000_FLAGS_LOADED   8 /* Firmware loaded        */
+
+#define ACT2000_BCH            2 /* # of channels per card */
+
+/* D-Channel states */
+#define ACT2000_STATE_NULL     0
+#define ACT2000_STATE_ICALL    1
+#define ACT2000_STATE_OCALL    2
+#define ACT2000_STATE_IWAIT    3
+#define ACT2000_STATE_OWAIT    4
+#define ACT2000_STATE_IBWAIT   5
+#define ACT2000_STATE_OBWAIT   6
+#define ACT2000_STATE_BWAIT    7
+#define ACT2000_STATE_BHWAIT   8
+#define ACT2000_STATE_BHWAIT2  9
+#define ACT2000_STATE_DHWAIT  10
+#define ACT2000_STATE_DHWAIT2 11
+#define ACT2000_STATE_BSETUP  12
+#define ACT2000_STATE_ACTIVE  13
+
+#define ACT2000_MAX_QUEUED  8000 /* 2 * maxbuff */
+
+#define ACT2000_LOCK_TX 0
+#define ACT2000_LOCK_RX 1
+
+typedef struct act2000_chan {
+       unsigned short callref;          /* Call Reference              */
+       unsigned short fsm_state;        /* Current D-Channel state     */
+       unsigned short eazmask;          /* EAZ-Mask for this Channel   */
+       short queued;                    /* User-Data Bytes in TX queue */
+       unsigned short plci;
+       unsigned short ncci;
+       unsigned char  l2prot;           /* Layer 2 protocol            */
+       unsigned char  l3prot;           /* Layer 3 protocol            */
+} act2000_chan;
+
+typedef struct msn_entry {
+       char eaz;
+        char msn[16];
+        struct msn_entry * next;
+} msn_entry;
+
+typedef struct irq_data_isa {
+       __u8           *rcvptr;
+       __u16           rcvidx;
+       __u16           rcvlen;
+       struct sk_buff *rcvskb;
+       __u8            rcvignore;
+       __u8            rcvhdr[8];
+} irq_data_isa;
+
+typedef union irq_data {
+       irq_data_isa isa;
+} irq_data;
+
+/*
+ * Per card driver data
+ */
+typedef struct act2000_card {
+        unsigned short port;             /* Base-port-address                */
+        unsigned short irq;              /* Interrupt                        */
+        u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
+        u_char bus;                      /* Cardtype (ISA, MCA, PCMCIA)      */
+        struct act2000_card *next;      /* Pointer to next device struct    */
+        int myid;                        /* Driver-Nr. assigned by linklevel */
+        unsigned long flags;             /* Statusflags                      */
+        unsigned long ilock;             /* Semaphores for IRQ-Routines      */
+       struct sk_buff_head rcvq;        /* Receive-Message queue            */
+       struct sk_buff_head sndq;        /* Send-Message queue               */
+       struct sk_buff_head ackq;        /* Data-Ack-Message queue           */
+       u_char *ack_msg;                 /* Ptr to User Data in User skb     */
+       __u16 need_b3ack;                /* Flag: Need ACK for current skb   */
+       struct sk_buff *sbuf;            /* skb which is currently sent      */
+       struct timer_list ptimer;        /* Poll timer                       */
+       struct tq_struct snd_tq;         /* Task struct for xmit bh          */
+       struct tq_struct rcv_tq;         /* Task struct for rcv bh           */
+       struct tq_struct poll_tq;        /* Task struct for polled rcv bh    */
+       msn_entry *msn_list;
+       unsigned short msgnum;           /* Message number fur sending       */
+       act2000_chan bch[ACT2000_BCH];   /* B-Channel status/control         */
+       char   status_buf[256];          /* Buffer for status messages       */
+       char   *status_buf_read;
+       char   *status_buf_write;
+       char   *status_buf_end;
+       irq_data idat;                   /* Data used for IRQ handler        */
+        isdn_if interface;               /* Interface to upper layer         */
+        char regname[35];                /* Name used for request_region     */
+} act2000_card;
+
+extern act2000_card *cards;
+
+extern __inline__ void act2000_schedule_tx(act2000_card *card)
+{
+        queue_task(&card->snd_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void act2000_schedule_rx(act2000_card *card)
+{
+        queue_task(&card->rcv_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void act2000_schedule_poll(act2000_card *card)
+{
+        queue_task(&card->poll_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern char *act2000_find_eaz(act2000_card *, char);
+
+#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif                          /* act2000_h */
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
new file mode 100644 (file)
index 0000000..078760a
--- /dev/null
@@ -0,0 +1,525 @@
+/* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: act2000_isa.c,v $
+ * Revision 1.5  1998/02/12 23:06:47  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.4  1997/10/09 22:23:00  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.3  1997/09/25 17:25:38  fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.2  1997/09/24 23:11:44  fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.1  1997/09/23 18:00:05  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#define __NO_VERSION__
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+
+static act2000_card *irq2card_map[16] =
+{
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int isa_irqs[] =
+{
+        3, 5, 7, 10, 11, 12, 15
+};
+#define ISA_NRIRQS (sizeof(isa_irqs)/sizeof(int))
+
+static void
+isa_delay(long t)
+{
+        sti();
+        current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + t;
+        schedule();
+        sti();
+}
+
+/*
+ * Reset Controller, then try to read the Card's signature.
+ + Return:
+ *   1 = Signature found.
+ *   0 = Signature not found.
+ */
+static int
+isa_reset(unsigned short portbase)
+{
+        unsigned char reg;
+        int i;
+        int found;
+        int serial = 0;
+
+        found = 0;
+        if ((reg = inb(portbase + ISA_COR)) != 0xff) {
+                outb(reg | ISA_COR_RESET, portbase + ISA_COR);
+                udelay(10000);
+                outb(reg, portbase + ISA_COR);
+                udelay(10000);
+
+                for (i = 0; i < 16; i++) {
+                        if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
+                                serial |= 0x10000;
+                        serial >>= 1;
+                }
+                if (serial == ISA_SER_ID)
+                        found++;
+        }
+        return found;
+}
+
+int
+isa_detect(unsigned short portbase)
+{
+        int ret = 0;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+        if (!check_region(portbase, ISA_REGION))
+                ret = isa_reset(portbase);
+        restore_flags(flags);
+        return ret;
+}
+
+static void
+isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        act2000_card *card = irq2card_map[irq];
+        u_char istatus;
+
+        if (!card) {
+                printk(KERN_WARNING
+                       "act2000: Spurious interrupt!\n");
+                return;
+        }
+        istatus = (inb(ISA_PORT_ISR) & 0x07);
+        if (istatus & ISA_ISR_OUT) {
+                /* RX fifo has data */
+               istatus &= ISA_ISR_OUT_MASK;
+               outb(0, ISA_PORT_SIS);
+               isa_receive(card);
+               outb(ISA_SIS_INT, ISA_PORT_SIS);
+        }
+        if (istatus & ISA_ISR_ERR) {
+                /* Error Interrupt */
+               istatus &= ISA_ISR_ERR_MASK;
+                printk(KERN_WARNING "act2000: errIRQ\n");
+        }
+       if (istatus)
+               printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
+}
+
+static void
+isa_select_irq(act2000_card * card)
+{
+       unsigned char reg;
+
+       reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
+       switch (card->irq) {
+               case 3:
+                       reg = ISA_COR_IRQ03;
+                       break;
+               case 5:
+                       reg = ISA_COR_IRQ05;
+                       break;
+               case 7:
+                       reg = ISA_COR_IRQ07;
+                       break;
+               case 10:
+                       reg = ISA_COR_IRQ10;
+                       break;
+               case 11:
+                       reg = ISA_COR_IRQ11;
+                       break;
+               case 12:
+                       reg = ISA_COR_IRQ12;
+                       break;
+               case 15:
+                       reg = ISA_COR_IRQ15;
+                       break;
+       }
+       outb(reg, ISA_PORT_COR);
+}
+
+static void
+isa_enable_irq(act2000_card * card)
+{
+       isa_select_irq(card);
+       /* Enable READ irq */
+       outb(ISA_SIS_INT, ISA_PORT_SIS);
+}
+
+/*
+ * Install interrupt handler, enable irq on card.
+ * If irq is -1, choose next free irq, else irq is given explicitely.
+ */
+int
+isa_config_irq(act2000_card * card, short irq)
+{
+        int i;
+        unsigned long flags;
+
+        if (card->flags & ACT2000_FLAGS_IVALID) {
+                free_irq(card->irq, NULL);
+                irq2card_map[card->irq] = NULL;
+        }
+        card->flags &= ~ACT2000_FLAGS_IVALID;
+        outb(ISA_COR_IRQOFF, ISA_PORT_COR);
+        if (!irq)
+                return 0;
+        save_flags(flags);
+        cli();
+        if (irq == -1) {
+                /* Auto select */
+                for (i = 0; i < ISA_NRIRQS; i++) {
+                        if (!request_irq(isa_irqs[i], &isa_interrupt, 0, card->regname, NULL)) {
+                                card->irq = isa_irqs[i];
+                                irq2card_map[card->irq] = card;
+                                card->flags |= ACT2000_FLAGS_IVALID;
+                                break;
+                        }
+                }
+        } else {
+                /* Fixed irq */
+                if (!request_irq(irq, &isa_interrupt, 0, card->regname, NULL)) {
+                        card->irq = irq;
+                        irq2card_map[card->irq] = card;
+                       card->flags |= ACT2000_FLAGS_IVALID;
+                }
+        }
+        restore_flags(flags);
+        if (!card->flags & ACT2000_FLAGS_IVALID) {
+                printk(KERN_WARNING
+                       "act2000: Could not request irq\n");
+                return -EBUSY;
+        } else {
+               isa_select_irq(card);
+                /* Disable READ and WRITE irq */
+                outb(0, ISA_PORT_SIS);
+                outb(0, ISA_PORT_SOS);
+        }
+        return 0;
+}
+
+int
+isa_config_port(act2000_card * card, unsigned short portbase)
+{
+        if (card->flags & ACT2000_FLAGS_PVALID) {
+                release_region(card->port, ISA_REGION);
+                card->flags &= ~ACT2000_FLAGS_PVALID;
+        }
+        if (!check_region(portbase, ISA_REGION)) {
+                request_region(portbase, ACT2000_PORTLEN, card->regname);
+                card->port = portbase;
+                card->flags |= ACT2000_FLAGS_PVALID;
+                return 0;
+        }
+        return -EBUSY;
+}
+
+/*
+ * Release ressources, used by an adaptor.
+ */
+void
+isa_release(act2000_card * card)
+{
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+        if (card->flags & ACT2000_FLAGS_IVALID) {
+                free_irq(card->irq, NULL);
+                irq2card_map[card->irq] = NULL;
+        }
+        card->flags &= ~ACT2000_FLAGS_IVALID;
+        if (card->flags & ACT2000_FLAGS_PVALID)
+                release_region(card->port, ISA_REGION);
+        card->flags &= ~ACT2000_FLAGS_PVALID;
+        restore_flags(flags);
+}
+
+static int
+isa_writeb(act2000_card * card, u_char data)
+{
+        u_char timeout = 40;
+
+        while (timeout) {
+                if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
+                        outb(data, ISA_PORT_SDO);
+                        return 0;
+                } else {
+                        timeout--;
+                        udelay(10);
+                }
+        }
+        return 1;
+}
+
+static int
+isa_readb(act2000_card * card, u_char * data)
+{
+        u_char timeout = 40;
+
+        while (timeout) {
+                if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
+                        *data = inb(ISA_PORT_SDI);
+                        return 0;
+                } else {
+                        timeout--;
+                        udelay(10);
+                }
+        }
+        return 1;
+}
+
+void
+isa_receive(act2000_card *card)
+{
+       u_char c;
+
+        if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
+               return;
+       while (!isa_readb(card, &c)) {
+               if (card->idat.isa.rcvidx < 8) {
+                        card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
+                       if (card->idat.isa.rcvidx == 8) {
+                               int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
+
+                               if (valid) {
+                                       card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
+                                       card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
+                                       if (card->idat.isa.rcvskb == NULL) {
+                                               card->idat.isa.rcvignore = 1;
+                                               printk(KERN_WARNING
+                                                      "isa_receive: no memory\n");
+                                               test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+                                               return;
+                                       }
+                                       memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
+                                       card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
+                               } else {
+                                       card->idat.isa.rcvidx = 0;
+                                       printk(KERN_WARNING
+                                              "isa_receive: Invalid CAPI msg\n");
+                                       {
+                                               int i; __u8 *p; __u8 *c; __u8 tmp[30];
+                                               for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
+                                                       c += sprintf(c, "%02x ", *(p++));
+                                               printk(KERN_WARNING "isa_receive: %s\n", tmp);
+                                       }
+                               }
+                       }
+               } else {
+                       if (!card->idat.isa.rcvignore)
+                               *card->idat.isa.rcvptr++ = c;
+                       if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
+                               if (!card->idat.isa.rcvignore) {
+                                       skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
+                                       act2000_schedule_rx(card);
+                               }
+                               card->idat.isa.rcvidx = 0;
+                               card->idat.isa.rcvlen = 8;
+                               card->idat.isa.rcvignore = 0;
+                               card->idat.isa.rcvskb = NULL;
+                               card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
+                       }
+               }
+       }
+       if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+               /* In polling mode, schedule myself */
+               if ((card->idat.isa.rcvidx) &&
+                   (card->idat.isa.rcvignore ||
+                    (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
+                       act2000_schedule_poll(card);
+       }
+       test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+}
+
+void
+isa_send(act2000_card * card)
+{
+       unsigned long flags;
+       struct sk_buff *skb;
+       actcapi_msg *msg;
+       int l;
+
+        if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
+               return;
+       while (1) {
+               save_flags(flags);
+               cli();
+               if (!(card->sbuf)) {
+                       if ((card->sbuf = skb_dequeue(&card->sndq))) {
+                               card->ack_msg = card->sbuf->data;
+                               msg = (actcapi_msg *)card->sbuf->data;
+                               if ((msg->hdr.cmd.cmd == 0x86) &&
+                                   (msg->hdr.cmd.subcmd == 0)   ) {
+                                       /* Save flags in message */
+                                       card->need_b3ack = msg->msg.data_b3_req.flags;
+                                       msg->msg.data_b3_req.flags = 0;
+                               }
+                       }
+               }
+               restore_flags(flags);
+               if (!(card->sbuf)) {
+                       /* No more data to send */
+                       test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+                       return;
+               }
+               skb = card->sbuf;
+               l = 0;
+               while (skb->len) {
+                       if (isa_writeb(card, *(skb->data))) {
+                               /* Fifo is full, but more data to send */
+#if 0
+                               printk(KERN_DEBUG "isa_send: %d bytes\n", l);
+#endif
+                               test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+                               /* Schedule myself */
+                               act2000_schedule_tx(card);
+                               return;
+                       }
+                       skb_pull(skb, 1);
+                       l++;
+               }
+               msg = (actcapi_msg *)card->ack_msg;
+               if ((msg->hdr.cmd.cmd == 0x86) &&
+                   (msg->hdr.cmd.subcmd == 0)   ) {
+                       /*
+                        * If it's user data, reset data-ptr
+                        * and put skb into ackq.
+                        */
+                       skb->data = card->ack_msg;
+                       /* Restore flags in message */
+                       msg->msg.data_b3_req.flags = card->need_b3ack;
+                       skb_queue_tail(&card->ackq, skb);
+               } else
+                       dev_kfree_skb(skb);
+               card->sbuf = NULL;
+#if 0
+               printk(KERN_DEBUG "isa_send: %d bytes\n", l);
+#endif
+       }
+}
+
+/*
+ * Get firmware ID, check for 'ISDN' signature.
+ */
+static int
+isa_getid(act2000_card * card)
+{
+
+        act2000_fwid fid;
+        u_char *p = (u_char *) & fid;
+        int count = 0;
+
+        while (1) {
+                if (count > 510)
+                        return -EPROTO;
+                if (isa_readb(card, p++))
+                        break;
+                count++;
+        }
+        if (count <= 20) {
+                printk(KERN_WARNING "act2000: No Firmware-ID!\n");
+                return -ETIME;
+        }
+        *p = '\0';
+        fid.revlen[0] = '\0';
+        if (strcmp(fid.isdn, "ISDN")) {
+                printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
+                return -EPROTO;
+        }
+       if ((p = strchr(fid.revision, '\n')))
+               *p = '\0';
+        printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
+       if (card->flags & ACT2000_FLAGS_IVALID) {
+               printk(KERN_DEBUG "Enabling Interrupts ...\n");
+               isa_enable_irq(card);
+       }
+        return 0;
+}
+
+/*
+ * Download microcode into card, check Firmware signature.
+ */
+int
+isa_download(act2000_card * card, act2000_ddef * cb)
+{
+        int length;
+        int ret;
+        int l;
+        int c;
+        long timeout;
+        u_char *b;
+        u_char *p;
+        u_char *buf;
+        act2000_ddef cblock;
+
+        if (!isa_reset(card->port))
+                return -ENXIO;
+        isa_delay(HZ / 2);
+        if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
+                return ret;
+        copy_from_user(&cblock, (char *) cb, sizeof(cblock));
+        length = cblock.length;
+        p = cblock.buffer;
+        if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
+                return ret;
+        buf = (u_char *) kmalloc(1024, GFP_KERNEL);
+        if (!buf)
+                return -ENOMEM;
+        timeout = 0;
+        while (length) {
+                l = (length > 1024) ? 1024 : length;
+                c = 0;
+                b = buf;
+                copy_from_user(buf, p, l);
+                while (c < l) {
+                        if (isa_writeb(card, *b++)) {
+                                printk(KERN_WARNING
+                                       "act2000: loader timed out"
+                                       " len=%d c=%d\n", length, c);
+                                kfree(buf);
+                                return -ETIME;
+                        }
+                        c++;
+                }
+                length -= l;
+                p += l;
+        }
+        kfree(buf);
+        isa_delay(HZ / 2);
+        return (isa_getid(card));
+}
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
new file mode 100644 (file)
index 0000000..b7c01ee
--- /dev/null
@@ -0,0 +1,149 @@
+/* $Id: act2000_isa.h,v 1.1 1997/09/23 18:00:07 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: act2000_isa.h,v $
+ * Revision 1.1  1997/09/23 18:00:07  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef act2000_isa_h
+#define act2000_isa_h
+
+#define ISA_POLL_LOOP 40        /* Try to read-write before give up */
+
+typedef enum {
+        INT_NO_CHANGE = 0,      /* Do not change the Mask */
+        INT_ON = 1,             /* Set to Enable */
+        INT_OFF = 2,            /* Set to Disable */
+} ISA_INT_T;
+
+/**************************************************************************/
+/*      Configuration Register COR (RW)                                   */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/* Soft Res|  IRQM  |        IRQ Select        |   N/A  |  WAIT  |Proc err */
+/**************************************************************************/
+#define        ISA_COR             0   /* Offset for ISA config register */
+#define        ISA_COR_PERR     0x01   /* Processor Error Enabled        */
+#define        ISA_COR_WS       0x02   /* Insert Wait State if 1         */
+#define        ISA_COR_IRQOFF   0x38   /* No Interrupt                   */
+#define        ISA_COR_IRQ07    0x30   /* IRQ 7 Enable                   */
+#define        ISA_COR_IRQ05    0x28   /* IRQ 5 Enable                   */
+#define        ISA_COR_IRQ03    0x20   /* IRQ 3 Enable                   */
+#define        ISA_COR_IRQ10    0x18   /* IRQ 10 Enable                  */
+#define        ISA_COR_IRQ11    0x10   /* IRQ 11 Enable                  */
+#define        ISA_COR_IRQ12    0x08   /* IRQ 12 Enable                  */
+#define        ISA_COR_IRQ15    0x00   /* IRQ 15 Enable                  */
+#define        ISA_COR_IRQPULSE 0x40   /* 0 = Level 1 = Pulse Interrupt  */
+#define        ISA_COR_RESET    0x80   /* Soft Reset for Transputer      */
+
+/**************************************************************************/
+/*      Interrupt Source Register ISR (RO)                                */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |Err sig |Ser ID  |IN Intr |Out Intr| Error  */
+/**************************************************************************/
+#define        ISA_ISR             1   /* Offset for Interrupt Register  */
+#define        ISA_ISR_ERR      0x01   /* Error Interrupt                */
+#define        ISA_ISR_OUT      0x02   /* Output Interrupt               */
+#define        ISA_ISR_INP      0x04   /* Input Interrupt                */
+#define        ISA_ISR_SERIAL   0x08   /* Read out Serial ID after Reset */
+#define        ISA_ISR_ERRSIG   0x10   /* Error Signal Input             */
+#define        ISA_ISR_ERR_MASK 0xfe    /* Mask Error Interrupt           */
+#define        ISA_ISR_OUT_MASK 0xfd    /* Mask Output Interrupt          */
+#define        ISA_ISR_INP_MASK 0xfb    /* Mask Input Interrupt           */
+
+/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first)          */
+#define        ISA_SER_ID     0x0201   /* ID for ISA Card                */
+
+/**************************************************************************/
+/*      EEPROM Register EPR (RW)                                          */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
+/**************************************************************************/
+#define        ISA_EPR             2   /* Offset for this Register       */
+#define        ISA_EPR_OUT      0x01   /* Rome Register Out (RO)         */
+#define        ISA_EPR_IN       0x02   /* Rom Register In (WR)           */
+#define        ISA_EPR_CLK      0x04   /* Rom Clock (WR)                 */
+#define        ISA_EPR_CS       0x08   /* Rom Cip Select (WR)            */
+#define        ISA_EPR_HOLD     0x10   /* Rom Hold Signal (WR)           */
+
+/**************************************************************************/
+/*      EEPROM enable Register EER (unused)                               */
+/**************************************************************************/
+#define        ISA_EER             3   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      SLC Data Input SDI (RO)                                           */
+/**************************************************************************/
+#define        ISA_SDI             4   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      SLC Data Output SDO (WO)                                          */
+/**************************************************************************/
+#define        ISA_SDO             5   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW)      */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Data Pre */
+/**************************************************************************/
+#define        ISA_SIS             6   /* Offset for this Register       */
+#define        ISA_SIS_READY    0x01   /* If 1 : data is available       */
+#define        ISA_SIS_INT      0x02   /* Enable Interrupt for READ      */
+
+/**************************************************************************/
+/*      IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW)    */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Out Rdy */
+/**************************************************************************/
+#define        ISA_SOS             7   /* Offset for this Register       */
+#define        ISA_SOS_READY    0x01   /* If 1 : we can write Data       */
+#define        ISA_SOS_INT      0x02   /* Enable Interrupt for WRITE     */
+
+#define        ISA_REGION          8   /* Number of Registers            */
+
+
+/* Macros for accessing ports */
+#define ISA_PORT_COR (card->port+ISA_COR)
+#define ISA_PORT_ISR (card->port+ISA_ISR)
+#define ISA_PORT_EPR (card->port+ISA_EPR)
+#define ISA_PORT_EER (card->port+ISA_EER)
+#define ISA_PORT_SDI (card->port+ISA_SDI)
+#define ISA_PORT_SDO (card->port+ISA_SDO)
+#define ISA_PORT_SIS (card->port+ISA_SIS)
+#define ISA_PORT_SOS (card->port+ISA_SOS)
+
+/* Prototypes */
+
+extern int isa_detect(unsigned short portbase);
+extern int isa_config_irq(act2000_card * card, short irq);
+extern int isa_config_port(act2000_card * card, unsigned short portbase);
+extern int isa_download(act2000_card * card, act2000_ddef * cb);
+extern void isa_release(act2000_card * card);
+extern void isa_receive(act2000_card *card);
+extern void isa_send(act2000_card *card);
+
+#endif                          /* act2000_isa_h */
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
new file mode 100644 (file)
index 0000000..d0310bc
--- /dev/null
@@ -0,0 +1,1218 @@
+/* $Id: capi.c,v 1.7 1998/02/23 23:35:41 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *        CAPI encoder/decoder
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: capi.c,v $
+ * Revision 1.7  1998/02/23 23:35:41  fritz
+ * Eliminated some compiler warnings.
+ *
+ * Revision 1.6  1998/02/12 23:06:50  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.5  1997/10/09 22:23:02  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.4  1997/09/25 17:25:39  fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3  1997/09/24 19:44:14  fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.2  1997/09/23 19:41:24  fritz
+ * Disabled Logging of DATA_B3_IND/RESP/REQ/CONF Messages.
+ *
+ * Revision 1.1  1997/09/23 18:00:08  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#define __NO_VERSION__
+#include "act2000.h"
+#include "capi.h"
+
+static actcapi_msgdsc valid_msg[] = {
+       {{ 0x86, 0x02}, "DATA_B3_IND"},       /* DATA_B3_IND/CONF must be first because of speed!!! */
+       {{ 0x86, 0x01}, "DATA_B3_CONF"},
+       {{ 0x02, 0x01}, "CONNECT_CONF"},
+       {{ 0x02, 0x02}, "CONNECT_IND"},
+       {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
+       {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
+       {{ 0x04, 0x01}, "DISCONNECT_CONF"},
+       {{ 0x04, 0x02}, "DISCONNECT_IND"},
+       {{ 0x05, 0x01}, "LISTEN_CONF"},
+       {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
+       {{ 0x07, 0x01}, "INFO_CONF"},
+       {{ 0x07, 0x02}, "INFO_IND"},
+       {{ 0x08, 0x01}, "DATA_CONF"},
+       {{ 0x08, 0x02}, "DATA_IND"},
+       {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
+       {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
+       {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
+       {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
+       {{ 0x82, 0x02}, "CONNECT_B3_IND"},
+       {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
+       {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
+       {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
+       {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
+       {{ 0x01, 0x01}, "RESET_B3_CONF"},
+       {{ 0x01, 0x02}, "RESET_B3_IND"},
+       /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
+       {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
+       {{ 0xff, 0x02}, "MANUFACTURER_IND"},
+#ifdef DEBUG_MSG
+       /* Requests */
+       {{ 0x01, 0x00}, "RESET_B3_REQ"},
+       {{ 0x02, 0x00}, "CONNECT_REQ"},
+       {{ 0x04, 0x00}, "DISCONNECT_REQ"},
+       {{ 0x05, 0x00}, "LISTEN_REQ"},
+       {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
+       {{ 0x07, 0x00}, "INFO_REQ"},
+       {{ 0x08, 0x00}, "DATA_REQ"},
+       {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
+       {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
+       {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
+       {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
+       {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
+       {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
+       {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
+       {{ 0x86, 0x00}, "DATA_B3_REQ"},
+       {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
+       /* Responses */
+       {{ 0x01, 0x03}, "RESET_B3_RESP"},       
+       {{ 0x02, 0x03}, "CONNECT_RESP"},        
+       {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"}, 
+       {{ 0x04, 0x03}, "DISCONNECT_RESP"},     
+       {{ 0x07, 0x03}, "INFO_RESP"},   
+       {{ 0x08, 0x03}, "DATA_RESP"},   
+       {{ 0x82, 0x03}, "CONNECT_B3_RESP"},     
+       {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},      
+       {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
+       {{ 0x86, 0x03}, "DATA_B3_RESP"},
+       {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
+#if 0
+/* CAPI 2.0 */
+       {{ 0x05, 0x80}, "LISTEN_REQ (CAPI 2.0)"},
+#endif
+#endif
+       {{ 0x00, 0x00}, NULL},
+};
+#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
+#define num_valid_imsg 27 /* MANUFACTURER_IND */
+
+/*
+ * Check for a valid incoming CAPI message.
+ * Return:
+ *   0 = Invalid message
+ *   1 = Valid message, no B-Channel-data
+ *   2 = Valid message, B-Channel-data
+ */
+int
+actcapi_chkhdr(act2000_card * card, actcapi_msghdr *hdr)
+{
+       int i;
+
+       if (hdr->applicationID != 1)
+               return 0;
+       if (hdr->len < 9)
+               return 0;
+       for (i = 0; i < num_valid_imsg; i++)
+               if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
+                   (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+                       return (i?1:2);
+               }
+       return 0;
+}
+
+#define ACTCAPI_MKHDR(l, c, s) { \
+       skb = alloc_skb(l + 8, GFP_ATOMIC); \
+       if (skb) { \
+               m = (actcapi_msg *)skb_put(skb, l + 8); \
+               m->hdr.len = l + 8; \
+               m->hdr.applicationID = 1; \
+               m->hdr.cmd.cmd = c; \
+               m->hdr.cmd.subcmd = s; \
+               m->hdr.msgnum = actcapi_nextsmsg(card); \
+       } \
+}
+
+#define ACTCAPI_CHKSKB if (!skb) { \
+       printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
+       return; \
+}
+
+#define ACTCAPI_QUEUE_TX { \
+       actcapi_debug_msg(skb, 1); \
+       skb_queue_tail(&card->sndq, skb); \
+       act2000_schedule_tx(card); \
+}
+
+int
+actcapi_listen_req(act2000_card *card)
+{
+       __u16 eazmask = 0;
+       int i;
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       for (i = 0; i < ACT2000_BCH; i++)
+               eazmask |= card->bch[i].eazmask;
+       ACTCAPI_MKHDR(9, 0x05, 0x00);
+        if (!skb) {
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+       m->msg.listen_req.controller = 0;
+       m->msg.listen_req.infomask = 0x3f; /* All information */
+       m->msg.listen_req.eazmask = eazmask;
+       m->msg.listen_req.simask = (eazmask)?0x86:0; /* All SI's  */
+       ACTCAPI_QUEUE_TX;
+        return 0;
+}
+
+int
+actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
+                   char eaz, int si1, int si2)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
+       if (!skb) {
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               chan->fsm_state = ACT2000_STATE_NULL;
+               return -ENOMEM;
+       }
+       m->msg.connect_req.controller = 0;
+       m->msg.connect_req.bchan = 0x83;
+       m->msg.connect_req.infomask = 0x3f;
+       m->msg.connect_req.si1 = si1;
+       m->msg.connect_req.si2 = si2;
+       m->msg.connect_req.eaz = eaz?eaz:'0';
+       m->msg.connect_req.addr.len = strlen(phone) + 1;
+       m->msg.connect_req.addr.tnp = 0x81;
+       memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
+       chan->callref = m->hdr.msgnum;
+       ACTCAPI_QUEUE_TX;
+       return 0;
+}
+
+static void
+actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x82, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_req.plci = chan->plci;
+       memset(&m->msg.connect_b3_req.ncpi, 0,
+              sizeof(m->msg.connect_b3_req.ncpi));
+       m->msg.connect_b3_req.ncpi.len = 13;
+       m->msg.connect_b3_req.ncpi.modulo = 8;
+       ACTCAPI_QUEUE_TX;
+}
+
+/*
+ * Set net type (1TR6) or (EDSS1)
+ */
+int
+actcapi_manufacturer_req_net(act2000_card *card)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(5, 0xff, 0x00);
+        if (!skb) {
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+       m->msg.manufacturer_req_net.manuf_msg = 0x11;
+       m->msg.manufacturer_req_net.controller = 1;
+       m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO)?1:0;
+       ACTCAPI_QUEUE_TX;
+       printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
+              card->interface.id, (card->ptype == ISDN_PTYPE_EURO)?"euro":"1tr6");
+       card->interface.features &=
+               ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
+       card->interface.features |=
+               ((card->ptype == ISDN_PTYPE_EURO)?ISDN_FEATURE_P_EURO:ISDN_FEATURE_P_1TR6);
+        return 0;
+}
+
+/*
+ * Switch V.42 on or off
+ */
+int
+actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(8, 0xff, 0x00);
+        if (!skb) {
+
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+       m->msg.manufacturer_req_v42.manuf_msg = 0x10;
+       m->msg.manufacturer_req_v42.controller = 0;
+       m->msg.manufacturer_req_v42.v42control = (arg?1:0);
+       ACTCAPI_QUEUE_TX;
+        return 0;
+}
+
+/*
+ * Set error-handler
+ */
+int
+actcapi_manufacturer_req_errh(act2000_card *card)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(4, 0xff, 0x00);
+        if (!skb) {
+
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+       m->msg.manufacturer_req_err.manuf_msg = 0x03;
+       m->msg.manufacturer_req_err.controller = 0;
+       ACTCAPI_QUEUE_TX;
+        return 0;
+}
+
+/*
+ * Set MSN-Mapping.
+ */
+int
+actcapi_manufacturer_req_msn(act2000_card *card)
+{
+       msn_entry *p = card->msn_list;
+       actcapi_msg *m;
+       struct sk_buff *skb;
+       int len;
+
+       while (p) {
+               int i;
+
+               len = strlen(p->msn);
+               for (i = 0; i < 2; i++) {
+                       ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
+                       if (!skb) {
+                               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                               return -ENOMEM;
+                       }
+                       m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
+                       m->msg.manufacturer_req_msn.controller = 0;
+                       m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
+                       m->msg.manufacturer_req_msn.msnmap.len = len;
+                       memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
+                       ACTCAPI_QUEUE_TX;
+               }
+               p = p->next;
+       }
+        return 0;
+}
+
+void
+actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(10, 0x40, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.select_b2_protocol_req.plci = chan->plci;
+       memset(&m->msg.select_b2_protocol_req.dlpd, 0,
+              sizeof(m->msg.select_b2_protocol_req.dlpd));
+       m->msg.select_b2_protocol_req.dlpd.len = 6;
+       switch (chan->l2prot) {
+               case ISDN_PROTO_L2_TRANS:
+                       m->msg.select_b2_protocol_req.protocol = 0x03;
+                       m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+                       break;
+               case ISDN_PROTO_L2_HDLC:
+                       m->msg.select_b2_protocol_req.protocol = 0x02;
+                       m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+                       break;
+               case ISDN_PROTO_L2_X75I:
+               case ISDN_PROTO_L2_X75UI:
+               case ISDN_PROTO_L2_X75BUI:
+                       m->msg.select_b2_protocol_req.protocol = 0x01;
+                       m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+                       m->msg.select_b2_protocol_req.dlpd.laa = 3;
+                       m->msg.select_b2_protocol_req.dlpd.lab = 1;
+                       m->msg.select_b2_protocol_req.dlpd.win = 7;
+                       m->msg.select_b2_protocol_req.dlpd.modulo = 8;
+                       break;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x80, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.select_b3_protocol_req.plci = chan->plci;
+       memset(&m->msg.select_b3_protocol_req.ncpd, 0,
+              sizeof(m->msg.select_b3_protocol_req.ncpd));
+       switch (chan->l3prot) {
+               case ISDN_PROTO_L3_TRANS:
+                       m->msg.select_b3_protocol_req.protocol = 0x04;
+                       m->msg.select_b3_protocol_req.ncpd.len = 13;
+                       m->msg.select_b3_protocol_req.ncpd.modulo = 8;
+                       break;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x81, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.listen_b3_req.plci = chan->plci;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(3, 0x04, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_req.plci = chan->plci;
+       m->msg.disconnect_req.cause = 0;
+       ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x84, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_b3_req.ncci = chan->ncci;
+       memset(&m->msg.disconnect_b3_req.ncpi, 0,
+              sizeof(m->msg.disconnect_b3_req.ncpi));
+       m->msg.disconnect_b3_req.ncpi.len = 13;
+       m->msg.disconnect_b3_req.ncpi.modulo = 8;
+       chan->fsm_state = ACT2000_STATE_BHWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(3, 0x02, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_resp.plci = chan->plci;
+       m->msg.connect_resp.rejectcause = cause;
+       if (cause) {
+               chan->fsm_state = ACT2000_STATE_NULL;
+               chan->plci = 0x8000;
+       } else
+               chan->fsm_state = ACT2000_STATE_IWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x03, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_resp.plci = chan->plci;
+       if (chan->fsm_state == ACT2000_STATE_IWAIT)
+               chan->fsm_state = ACT2000_STATE_IBWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR((rejectcause?3:17), 0x82, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_resp.ncci = chan->ncci;
+       m->msg.connect_b3_resp.rejectcause = rejectcause;
+       if (!rejectcause) {
+               memset(&m->msg.connect_b3_resp.ncpi, 0,
+                      sizeof(m->msg.connect_b3_resp.ncpi));
+               m->msg.connect_b3_resp.ncpi.len = 13;
+               m->msg.connect_b3_resp.ncpi.modulo = 8;
+               chan->fsm_state = ACT2000_STATE_BWAIT;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x83, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_active_resp.ncci = chan->ncci;
+       chan->fsm_state = ACT2000_STATE_ACTIVE;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_info_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x07, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.info_resp.plci = chan->plci;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x84, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_b3_resp.ncci = chan->ncci;
+       chan->ncci = 0x8000;
+       chan->queued = 0;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x04, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_resp.plci = chan->plci;
+       chan->plci = 0x8000;
+       ACTCAPI_QUEUE_TX;
+}
+
+static int
+new_plci(act2000_card *card, __u16 plci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].plci == 0x8000) {
+                       card->bch[i].plci = plci;
+                       return i;
+               }
+       return -1;
+}
+
+static int
+find_plci(act2000_card *card, __u16 plci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].plci == plci)
+                       return i;
+       return -1;
+}
+
+static int
+find_ncci(act2000_card *card, __u16 ncci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].ncci == ncci)
+                       return i;
+       return -1;
+}
+
+static int
+find_dialing(act2000_card *card, __u16 callref)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if ((card->bch[i].callref == callref) &&
+                   (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
+                       return i;
+       return -1;
+}
+
+static int
+actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
+       __u16 plci;
+       __u16 ncci;
+       __u16 controller;
+       __u8  blocknr;
+       int chan;
+       actcapi_msg *msg = (actcapi_msg *)skb->data;
+
+       EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
+       chan = find_ncci(card, ncci);
+       if (chan < 0)
+               return 0;
+       if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
+               return 0;
+       if (card->bch[chan].plci != plci)
+               return 0;
+       blocknr = msg->msg.data_b3_ind.blocknr;
+       skb_pull(skb, 19);
+       card->interface.rcvcallb_skb(card->myid, chan, skb);
+        if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
+                printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                return 1;
+        }
+       msg = (actcapi_msg *)skb_put(skb, 11);
+       msg->hdr.len = 11;
+       msg->hdr.applicationID = 1;
+       msg->hdr.cmd.cmd = 0x86;
+       msg->hdr.cmd.subcmd = 0x03;
+       msg->hdr.msgnum = actcapi_nextsmsg(card);
+       msg->msg.data_b3_resp.ncci = ncci;
+       msg->msg.data_b3_resp.blocknr = blocknr;
+       ACTCAPI_QUEUE_TX;
+       return 1;
+}
+
+/*
+ * Walk over ackq, unlink DATA_B3_REQ from it, if
+ * ncci and blocknr are matching.
+ * Decrement queued-bytes counter.
+ */
+static int
+handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct sk_buff *tmp;
+       struct actcapi_msg *m;
+       int ret = 0;
+
+       save_flags(flags);
+       cli();
+       skb = skb_peek(&card->ackq);
+       restore_flags(flags);
+        if (!skb) {
+               printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+               return 0;
+       }
+        tmp = skb;
+        while (1) {
+                m = (actcapi_msg *)tmp->data;
+                if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
+                   (m->msg.data_b3_req.blocknr == blocknr)) {
+                       /* found corresponding DATA_B3_REQ */
+                        skb_unlink(tmp);
+                       chan->queued -= m->msg.data_b3_req.datalen;
+                       if (m->msg.data_b3_req.flags)
+                               ret = m->msg.data_b3_req.datalen;
+                       dev_kfree_skb(tmp);
+                       if (chan->queued < 0)
+                               chan->queued = 0;
+                        return ret;
+                }
+               save_flags(flags);
+               cli();
+                tmp = skb_peek((struct sk_buff_head *)tmp);
+               restore_flags(flags);
+                if ((tmp == skb) || (tmp == NULL)) {
+                       /* reached end of queue */
+                       printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+                        return 0;
+               }
+        }
+}
+
+void
+actcapi_dispatch(act2000_card *card)
+{
+       struct sk_buff *skb;
+       actcapi_msg *msg;
+       __u16 ccmd;
+       int chan;
+       int len;
+       act2000_chan *ctmp;
+       isdn_ctrl cmd;
+       char tmp[170];
+
+       while ((skb = skb_dequeue(&card->rcvq))) {
+               actcapi_debug_msg(skb, 0);
+               msg = (actcapi_msg *)skb->data;
+               ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
+               switch (ccmd) {
+                       case 0x8602:
+                               /* DATA_B3_IND */
+                               if (actcapi_data_b3_ind(card, skb))
+                                       return;
+                               break;
+                       case 0x8601:
+                               /* DATA_B3_CONF */
+                               chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
+                               if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
+                                       if (msg->msg.data_b3_conf.info != 0)
+                                               printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
+                                                      msg->msg.data_b3_conf.info);
+                                       len = handle_ack(card, &card->bch[chan],
+                                                        msg->msg.data_b3_conf.blocknr);
+                                       if (len) {
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_BSENT;
+                                               cmd.arg = chan;
+                                               cmd.parm.length = len;
+                                               card->interface.statcallb(&cmd);
+                                       }
+                               }
+                               break;
+                       case 0x0201:
+                               /* CONNECT_CONF */
+                               chan = find_dialing(card, msg->hdr.msgnum);
+                               if (chan >= 0) {
+                                       if (msg->msg.connect_conf.info) {
+                                               card->bch[chan].fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       } else {
+                                               card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
+                                               card->bch[chan].plci = msg->msg.connect_conf.plci;
+                                       }
+                               }
+                               break;
+                       case 0x0202:
+                               /* CONNECT_IND */
+                               chan = new_plci(card, msg->msg.connect_ind.plci);
+                               if (chan < 0) {
+                                       ctmp = (act2000_chan *)tmp;
+                                       ctmp->plci = msg->msg.connect_ind.plci;
+                                       actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+                               } else {
+                                       card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_ICALL;
+                                       cmd.arg = chan;
+                                       cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
+                                       cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
+                                       if (card->ptype == ISDN_PTYPE_EURO)
+                                               strcpy(cmd.parm.setup.eazmsn,
+                                                      act2000_find_eaz(card, msg->msg.connect_ind.eaz));
+                                       else {
+                                               cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
+                                               cmd.parm.setup.eazmsn[1] = 0;
+                                       }
+                                       memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
+                                       memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
+                                              msg->msg.connect_ind.addr.len - 1);
+                                       cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
+                                       cmd.parm.setup.screen = 0;
+                                       if (card->interface.statcallb(&cmd) == 2)
+                                               actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
+                               }
+                               break;
+                       case 0x0302:
+                               /* CONNECT_ACTIVE_IND */
+                               chan = find_plci(card, msg->msg.connect_active_ind.plci);
+                               if (chan >= 0)
+                                       switch (card->bch[chan].fsm_state) {
+                                               case ACT2000_STATE_IWAIT:
+                                                       actcapi_connect_active_resp(card, &card->bch[chan]);
+                                                       break;
+                                               case ACT2000_STATE_OWAIT:
+                                                       actcapi_connect_active_resp(card, &card->bch[chan]);
+                                                       actcapi_select_b2_protocol_req(card, &card->bch[chan]);
+                                                       break;
+                                       }
+                               break;
+                       case 0x8202:
+                               /* CONNECT_B3_IND */
+                               chan = find_plci(card, msg->msg.connect_b3_ind.plci);
+                               if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
+                                       card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
+                                       actcapi_connect_b3_resp(card, &card->bch[chan], 0);
+                               } else {
+                                       ctmp = (act2000_chan *)tmp;
+                                       ctmp->ncci = msg->msg.connect_b3_ind.ncci;
+                                       actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+                               }
+                               break;
+                       case 0x8302:
+                               /* CONNECT_B3_ACTIVE_IND */
+                               chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
+                               if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
+                                       actcapi_connect_b3_active_resp(card, &card->bch[chan]);
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_BCONN;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                               }
+                               break;
+                       case 0x8402:
+                               /* DISCONNECT_B3_IND */
+                               chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
+                               if (chan >= 0) {
+                                       ctmp = &card->bch[chan];
+                                       actcapi_disconnect_b3_resp(card, ctmp);
+                                       switch (ctmp->fsm_state) {
+                                               case ACT2000_STATE_ACTIVE:
+                                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
+                                                       cmd.driver = card->myid;
+                                                       cmd.command = ISDN_STAT_BHUP;
+                                                       cmd.arg = chan;
+                                                       card->interface.statcallb(&cmd);
+                                                       break;
+                                               case ACT2000_STATE_BHWAIT2:
+                                                       actcapi_disconnect_req(card, ctmp);
+                                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT;
+                                                       cmd.driver = card->myid;
+                                                       cmd.command = ISDN_STAT_BHUP;
+                                                       cmd.arg = chan;
+                                                       card->interface.statcallb(&cmd);
+                                                       break;
+                                       }
+                               }
+                               break;
+                       case 0x0402:
+                               /* DISCONNECT_IND */
+                               chan = find_plci(card, msg->msg.disconnect_ind.plci);
+                               if (chan >= 0) {
+                                       ctmp = &card->bch[chan];
+                                       actcapi_disconnect_resp(card, ctmp);
+                                       ctmp->fsm_state = ACT2000_STATE_NULL;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_DHUP;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                               } else {
+                                       ctmp = (act2000_chan *)tmp;
+                                       ctmp->plci = msg->msg.disconnect_ind.plci;
+                                       actcapi_disconnect_resp(card, ctmp);
+                               }
+                               break;
+                       case 0x4001:
+                               /* SELECT_B2_PROTOCOL_CONF */
+                               chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
+                               if (chan >= 0)
+                                       switch (card->bch[chan].fsm_state) {
+                                               case ACT2000_STATE_ICALL:
+                                               case ACT2000_STATE_OWAIT:
+                                                       ctmp = &card->bch[chan];
+                                                       if (msg->msg.select_b2_protocol_conf.info == 0)
+                                                               actcapi_select_b3_protocol_req(card, ctmp);
+                                                       else {
+                                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                                               cmd.driver = card->myid;
+                                                               cmd.command = ISDN_STAT_DHUP;
+                                                               cmd.arg = chan;
+                                                               card->interface.statcallb(&cmd);
+                                                       }
+                                                       break;
+                                       }
+                               break;
+                       case 0x8001:
+                               /* SELECT_B3_PROTOCOL_CONF */
+                               chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
+                               if (chan >= 0)
+                                       switch (card->bch[chan].fsm_state) {
+                                               case ACT2000_STATE_ICALL:
+                                               case ACT2000_STATE_OWAIT:
+                                                       ctmp = &card->bch[chan];
+                                                       if (msg->msg.select_b3_protocol_conf.info == 0)
+                                                               actcapi_listen_b3_req(card, ctmp);
+                                                       else {
+                                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                                               cmd.driver = card->myid;
+                                                               cmd.command = ISDN_STAT_DHUP;
+                                                               cmd.arg = chan;
+                                                               card->interface.statcallb(&cmd);
+                                                       }
+                                       }
+                               break;
+                       case 0x8101:
+                               /* LISTEN_B3_CONF */
+                               chan = find_plci(card, msg->msg.listen_b3_conf.plci);
+                               if (chan >= 0)
+                                       switch (card->bch[chan].fsm_state) {
+                                               case ACT2000_STATE_ICALL:
+                                                       ctmp = &card->bch[chan];
+                                                       if (msg->msg.listen_b3_conf.info == 0)
+                                                               actcapi_connect_resp(card, ctmp, 0);
+                                                       else {
+                                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                                               cmd.driver = card->myid;
+                                                               cmd.command = ISDN_STAT_DHUP;
+                                                               cmd.arg = chan;
+                                                               card->interface.statcallb(&cmd);
+                                                       }
+                                                       break;
+                                               case ACT2000_STATE_OWAIT:
+                                                       ctmp = &card->bch[chan];
+                                                       if (msg->msg.listen_b3_conf.info == 0) {
+                                                               actcapi_connect_b3_req(card, ctmp);
+                                                               ctmp->fsm_state = ACT2000_STATE_OBWAIT;
+                                                               cmd.driver = card->myid;
+                                                               cmd.command = ISDN_STAT_DCONN;
+                                                               cmd.arg = chan;
+                                                               card->interface.statcallb(&cmd);
+                                                       } else {
+                                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                                               cmd.driver = card->myid;
+                                                               cmd.command = ISDN_STAT_DHUP;
+                                                               cmd.arg = chan;
+                                                               card->interface.statcallb(&cmd);
+                                                       }
+                                                       break;
+                                       }
+                               break;
+                       case 0x8201:
+                               /* CONNECT_B3_CONF */
+                               chan = find_plci(card, msg->msg.connect_b3_conf.plci);
+                               if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
+                                       ctmp = &card->bch[chan];
+                                       if (msg->msg.connect_b3_conf.info) {
+                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       } else {
+                                               ctmp->ncci = msg->msg.connect_b3_conf.ncci;
+                                               ctmp->fsm_state = ACT2000_STATE_BWAIT;
+                                       }
+                               }
+                               break;
+                       case 0x8401:
+                               /* DISCONNECT_B3_CONF */
+                               chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
+                               if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
+                                       card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
+                               break;
+                       case 0x0702:
+                               /* INFO_IND */
+                               chan = find_plci(card, msg->msg.info_ind.plci);
+                               if (chan >= 0)
+                                       /* TODO: Eval Charging info / cause */
+                                       actcapi_info_resp(card, &card->bch[chan]);
+                               break;
+                       case 0x0401:
+                               /* LISTEN_CONF */
+                       case 0x0501:
+                               /* LISTEN_CONF */
+                       case 0xff01:
+                               /* MANUFACTURER_CONF */
+                               break;
+                       case 0xff02:
+                               /* MANUFACTURER_IND */
+                               if (msg->msg.manuf_msg == 3) {
+                                       memset(tmp, 0, sizeof(tmp));
+                                       strncpy(tmp,
+                                               &msg->msg.manufacturer_ind_err.errstring,
+                                               msg->hdr.len - 16);
+                                       if (msg->msg.manufacturer_ind_err.errcode)
+                                               printk(KERN_WARNING "act2000: %s\n", tmp);
+                                       else {
+                                               printk(KERN_DEBUG "act2000: %s\n", tmp);
+                                               if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
+                                                   (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
+                                                       card->flags |= ACT2000_FLAGS_RUNNING;
+                                                       cmd.command = ISDN_STAT_RUN;
+                                                       cmd.driver = card->myid;
+                                                       cmd.arg = 0;
+                                                       actcapi_manufacturer_req_net(card);
+                                                       actcapi_manufacturer_req_msn(card);
+                                                       actcapi_listen_req(card);
+                                                       card->interface.statcallb(&cmd);
+                                               }
+                                       }
+                               }
+                               break;
+                       default:
+                               printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
+                               break;
+               }
+               dev_kfree_skb(skb);
+       }
+}
+
+#ifdef DEBUG_MSG
+static void
+actcapi_debug_caddr(actcapi_addr *addr)
+{
+       char tmp[30];
+
+       printk(KERN_DEBUG " Alen  = %d\n", addr->len);
+       if (addr->len > 0)
+               printk(KERN_DEBUG " Atnp  = 0x%02x\n", addr->tnp);
+       if (addr->len > 1) {
+               memset(tmp, 0, 30);
+               memcpy(tmp, addr->num, addr->len - 1);
+               printk(KERN_DEBUG " Anum  = '%s'\n", tmp);
+       }
+}
+
+static void
+actcapi_debug_ncpi(actcapi_ncpi *ncpi)
+{
+       printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
+       if (ncpi->len >= 2)
+               printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
+       if (ncpi->len >= 4)
+               printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
+       if (ncpi->len >= 6)
+               printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
+       if (ncpi->len >= 8)
+               printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
+       if (ncpi->len >= 10)
+               printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
+       if (ncpi->len >= 12)
+               printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
+       if (ncpi->len >= 13)
+               printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
+}
+
+static void
+actcapi_debug_dlpd(actcapi_dlpd *dlpd)
+{
+       printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
+       if (dlpd->len >= 2)
+               printk(KERN_DEBUG " dlpd.dlen   = 0x%04x\n", dlpd->dlen);
+       if (dlpd->len >= 3)
+               printk(KERN_DEBUG " dlpd.laa    = 0x%02x\n", dlpd->laa);
+       if (dlpd->len >= 4)
+               printk(KERN_DEBUG " dlpd.lab    = 0x%02x\n", dlpd->lab);
+       if (dlpd->len >= 5)
+               printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
+       if (dlpd->len >= 6)
+               printk(KERN_DEBUG " dlpd.win    = %d\n", dlpd->win);
+}
+
+#ifdef DEBUG_DUMP_SKB
+static void dump_skb(struct sk_buff *skb) {
+       char tmp[80];
+       char *p = skb->data;
+       char *t = tmp;
+       int i;
+
+       for (i = 0; i < skb->len; i++) {
+               t += sprintf(t, "%02x ", *p++ & 0xff);
+               if ((i & 0x0f) == 8) {
+                       printk(KERN_DEBUG "dump: %s\n", tmp);
+                       t = tmp;
+               }
+       }
+       if (i & 0x07)
+               printk(KERN_DEBUG "dump: %s\n", tmp);
+}
+#endif
+
+void
+actcapi_debug_msg(struct sk_buff *skb, int direction)
+{
+       actcapi_msg *msg = (actcapi_msg *)skb->data;
+       char *descr;
+       int i;
+       char tmp[170];
+       
+#ifndef DEBUG_DATA_MSG
+       if (msg->hdr.cmd.cmd == 0x86)
+               return;
+#endif
+       descr = "INVALID";
+#ifdef DEBUG_DUMP_SKB
+       dump_skb(skb);
+#endif
+       for (i = 0; i < num_valid_msg; i++)
+               if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
+                   (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+                       descr = valid_msg[i].description;
+                       break;
+               }
+       printk(KERN_DEBUG "%s %s msg\n", direction?"Outgoing":"Incoming", descr);
+       printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
+       printk(KERN_DEBUG " Len    = %d\n", msg->hdr.len);
+       printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
+       printk(KERN_DEBUG " Cmd    = 0x%02x\n", msg->hdr.cmd.cmd);
+       printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
+       switch (i) {
+               case 0:
+                       /* DATA B3 IND */
+                       printk(KERN_DEBUG " BLOCK = 0x%02x\n",
+                              msg->msg.data_b3_ind.blocknr);
+                       break;
+               case 2:
+                       /* CONNECT CONF */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.connect_conf.plci);
+                       printk(KERN_DEBUG " Info = 0x%04x\n",
+                              msg->msg.connect_conf.info);
+                       break;
+               case 3:
+                       /* CONNECT IND */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.connect_ind.plci);
+                       printk(KERN_DEBUG " Contr = %d\n",
+                              msg->msg.connect_ind.controller);
+                       printk(KERN_DEBUG " SI1   = %d\n",
+                              msg->msg.connect_ind.si1);
+                       printk(KERN_DEBUG " SI2   = %d\n",
+                              msg->msg.connect_ind.si2);
+                       printk(KERN_DEBUG " EAZ   = '%c'\n",
+                              msg->msg.connect_ind.eaz);
+                       actcapi_debug_caddr(&msg->msg.connect_ind.addr);
+                       break;
+               case 5:
+                       /* CONNECT ACTIVE IND */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.connect_active_ind.plci);
+                       actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
+                       break;
+               case 8:
+                       /* LISTEN CONF */
+                       printk(KERN_DEBUG " Contr = %d\n",
+                              msg->msg.listen_conf.controller);
+                       printk(KERN_DEBUG " Info = 0x%04x\n",
+                              msg->msg.listen_conf.info);
+                       break;
+               case 11:
+                       /* INFO IND */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.info_ind.plci);
+                       printk(KERN_DEBUG " Imsk = 0x%04x\n",
+                              msg->msg.info_ind.nr.mask);
+                       if (msg->hdr.len > 12) {
+                               int l = msg->hdr.len - 12;
+                               int j;
+                               char *p = tmp;
+                               for (j = 0; j < l ; j++)
+                                       p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
+                               printk(KERN_DEBUG " D = '%s'\n", tmp);
+                       }
+                       break;
+               case 14:
+                       /* SELECT B2 PROTOCOL CONF */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.select_b2_protocol_conf.plci);
+                       printk(KERN_DEBUG " Info = 0x%04x\n",
+                              msg->msg.select_b2_protocol_conf.info);
+                       break;
+               case 15:
+                       /* SELECT B3 PROTOCOL CONF */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.select_b3_protocol_conf.plci);
+                       printk(KERN_DEBUG " Info = 0x%04x\n",
+                              msg->msg.select_b3_protocol_conf.info);
+                       break;
+               case 16:
+                       /* LISTEN B3 CONF */
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.listen_b3_conf.plci);
+                       printk(KERN_DEBUG " Info = 0x%04x\n",
+                              msg->msg.listen_b3_conf.info);
+                       break;
+               case 18:
+                       /* CONNECT B3 IND */
+                       printk(KERN_DEBUG " NCCI = 0x%04x\n",
+                              msg->msg.connect_b3_ind.ncci);
+                       printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                              msg->msg.connect_b3_ind.plci);
+                       actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
+                       break;
+               case 19:
+                       /* CONNECT B3 ACTIVE IND */
+                       printk(KERN_DEBUG " NCCI = 0x%04x\n",
+                              msg->msg.connect_b3_active_ind.ncci);
+                       actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
+                       break;
+               case 26:
+                       /* MANUFACTURER IND */
+                       printk(KERN_DEBUG " Mmsg = 0x%02x\n",
+                              msg->msg.manufacturer_ind_err.manuf_msg);
+                       switch (msg->msg.manufacturer_ind_err.manuf_msg) {
+                               case 3:
+                                       printk(KERN_DEBUG " Contr = %d\n",
+                                              msg->msg.manufacturer_ind_err.controller);
+                                       printk(KERN_DEBUG " Code = 0x%08x\n",
+                                              msg->msg.manufacturer_ind_err.errcode);
+                                       memset(tmp, 0, sizeof(tmp));
+                                       strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
+                                               msg->hdr.len - 16);
+                                       printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
+                                       break;
+                       }
+                       break;
+               case 30:
+                       /* LISTEN REQ */
+                       printk(KERN_DEBUG " Imsk = 0x%08x\n",
+                              msg->msg.listen_req.infomask);
+                       printk(KERN_DEBUG " Emsk = 0x%04x\n",
+                              msg->msg.listen_req.eazmask);
+                       printk(KERN_DEBUG " Smsk = 0x%04x\n",
+                              msg->msg.listen_req.simask);
+                       break;
+               case 35:
+                       /* SELECT_B2_PROTOCOL_REQ */
+                       printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                              msg->msg.select_b2_protocol_req.plci);
+                       printk(KERN_DEBUG " prot  = 0x%02x\n",
+                              msg->msg.select_b2_protocol_req.protocol);
+                       if (msg->hdr.len >= 11)
+                               printk(KERN_DEBUG "No dlpd\n");
+                       else
+                               actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
+                       break;
+               case 44:
+                       /* CONNECT RESP */
+                       printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                              msg->msg.connect_resp.plci);
+                       printk(KERN_DEBUG " CAUSE = 0x%02x\n",
+                              msg->msg.connect_resp.rejectcause);
+                       break;
+               case 45:
+                       /* CONNECT ACTIVE RESP */
+                       printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                              msg->msg.connect_active_resp.plci);
+                       break;
+       }
+}
+#endif
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
new file mode 100644 (file)
index 0000000..901f15e
--- /dev/null
@@ -0,0 +1,406 @@
+/* $Id: capi.h,v 1.4 1997/10/01 09:21:04 fritz Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: capi.h,v $
+ * Revision 1.4  1997/10/01 09:21:04  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.3  1997/09/25 17:25:41  fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.2  1997/09/24 19:44:15  fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1  1997/09/23 18:00:10  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#ifndef CAPI_H
+#define CAPI_H
+
+/* Command-part of a CAPI message */
+typedef struct actcapi_msgcmd {
+       __u8 cmd;
+       __u8 subcmd;
+} actcapi_msgcmd;
+
+/* CAPI message header */
+typedef struct actcapi_msghdr {
+       __u16 len;
+       __u16 applicationID;
+       actcapi_msgcmd cmd;
+       __u16 msgnum;
+} actcapi_msghdr;
+
+/* CAPI message description (for debugging) */
+typedef struct actcapi_msgdsc {
+       actcapi_msgcmd cmd;
+       char *description;
+} actcapi_msgdsc;
+
+/* CAPI Adress */
+typedef struct actcapi_addr {
+       __u8 len;                            /* Length of element            */
+       __u8 tnp;                            /* Type/Numbering Plan          */
+       __u8 num[20];                        /* Caller ID                    */
+} actcapi_addr;
+
+/* CAPI INFO element mask */
+typedef  union actcapi_infonr {              /* info number                  */
+       __u16 mask;                          /* info-mask field              */
+       struct bmask {                       /* bit definitions              */
+               unsigned  codes : 3;         /* code set                     */
+               unsigned  rsvd  : 5;         /* reserved                     */
+               unsigned  svind : 1;         /* single, variable length ind. */
+               unsigned  wtype : 7;         /* W-element type               */
+       } bmask;
+} actcapi_infonr;
+
+/* CAPI INFO element */
+typedef union  actcapi_infoel {              /* info element                 */
+       __u8 len;                            /* length of info element       */
+       __u8 display[40];                    /* display contents             */
+       __u8 uuinfo[40];                     /* User-user info field         */
+       struct cause {                       /* Cause information            */
+               unsigned ext2  : 1;          /* extension                    */
+               unsigned cod   : 2;          /* coding standard              */
+               unsigned spare : 1;          /* spare                        */
+               unsigned loc   : 4;          /* location                     */
+               unsigned ext1  : 1;          /* extension                    */
+               unsigned cval  : 7;          /* Cause value                  */
+       } cause;                     
+       struct charge {                      /* Charging information         */
+               __u8 toc;                    /* type of charging info        */
+               __u8 unit[10];               /* charging units               */
+       } charge;
+       __u8 date[20];                       /* date fields                  */
+       __u8 stat;                           /* state of remote party        */
+} actcapi_infoel;
+
+/* Message for EAZ<->MSN Mapping */
+typedef struct actcapi_msn {
+       __u8 eaz;
+       __u8 len;                            /* Length of MSN                */
+       __u8 msn[15] __attribute__ ((packed));
+} actcapi_msn;
+
+typedef struct actcapi_dlpd {
+       __u8 len;                            /* Length of structure          */
+       __u16 dlen __attribute__ ((packed)); /* Data Length                  */
+       __u8 laa __attribute__ ((packed));   /* Link Address A               */
+       __u8 lab;                            /* Link Address B               */
+       __u8 modulo;                         /* Modulo Mode                  */
+       __u8 win;                            /* Window size                  */
+       __u8 xid[100];                       /* XID Information              */
+} actcapi_dlpd;
+
+typedef struct actcapi_ncpd {
+       __u8   len;                          /* Length of structure          */
+       __u16  lic __attribute__ ((packed));
+       __u16  hic __attribute__ ((packed));
+       __u16  ltc __attribute__ ((packed));
+       __u16  htc __attribute__ ((packed));
+       __u16  loc __attribute__ ((packed));
+       __u16  hoc __attribute__ ((packed));
+       __u8   modulo __attribute__ ((packed));
+} actcapi_ncpd;
+#define actcapi_ncpi actcapi_ncpd
+
+/*
+ * Layout of NCCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4  = PLCI
+ * Bit 5-7  = Controller
+ * Bit 8-15 = NCCI
+ */
+#define MAKE_NCCI(plci,contr,ncci) \
+        ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
+
+#define EVAL_NCCI(fakencci,plci,contr,ncci) { \
+       plci  = fakencci & 0x1f; \
+       contr = (fakencci >> 5) & 0x7; \
+       ncci  = (fakencci >> 8) & 0xff; \
+}
+
+/*
+ * Layout of PLCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4  = PLCI
+ * Bit 5-7  = Controller
+ * Bit 8-15 = reserved (must be 0)
+ */
+#define MAKE_PLCI(plci,contr) \
+        ((plci & 0x1f) | ((contr & 0x7) << 5))
+
+#define EVAL_PLCI(fakeplci,plci,contr) { \
+       plci  = fakeplci & 0x1f; \
+       contr = (fakeplci >> 5) & 0x7; \
+}
+
+typedef struct actcapi_msg {
+       actcapi_msghdr hdr;
+       union msg {
+               __u16 manuf_msg;
+               struct manufacturer_req_net {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u8  nettype;
+               } manufacturer_req_net;
+               struct manufacturer_req_v42 {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u32 v42control;
+               } manufacturer_req_v42;
+               struct manufacturer_conf_v42 {
+                       __u16 manuf_msg;
+                       __u16 controller;
+               } manufacturer_conf_v42;
+               struct manufacturer_req_err {
+                       __u16 manuf_msg;
+                       __u16 controller;
+               } manufacturer_req_err;
+               struct manufacturer_ind_err {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u32 errcode;
+                       __u8  errstring; /* actually up to 160 */
+               } manufacturer_ind_err;
+               struct manufacturer_req_msn {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       actcapi_msn msnmap;
+               } manufacturer_req_msn;
+               /* TODO: TraceInit-req/conf/ind/resp and
+                *       TraceDump-req/conf/ind/resp
+                */
+               struct connect_req {
+                       __u8  controller;
+                       __u8  bchan;
+                       __u32 infomask __attribute__ ((packed));
+                       __u8  si1;
+                       __u8  si2;
+                       __u8  eaz;
+                       actcapi_addr addr;
+               } connect_req;
+               struct connect_conf {
+                       __u16 plci;
+                       __u16 info;
+               } connect_conf;
+               struct connect_ind {
+                       __u16 plci;
+                       __u8  controller;
+                       __u8  si1;
+                       __u8  si2;
+                       __u8  eaz;
+                       actcapi_addr addr;
+               } connect_ind;
+               struct connect_resp {
+                       __u16 plci;
+                       __u8  rejectcause;
+               } connect_resp;
+               struct connect_active_ind {
+                       __u16 plci;
+                       actcapi_addr addr;
+               } connect_active_ind;
+               struct connect_active_resp {
+                       __u16 plci;
+               } connect_active_resp;
+               struct connect_b3_req {
+                       __u16 plci;
+                       actcapi_ncpi ncpi;
+               } connect_b3_req;
+               struct connect_b3_conf {
+                       __u16 plci;
+                       __u16 ncci;
+                       __u16 info;
+               } connect_b3_conf;
+               struct connect_b3_ind {
+                       __u16 ncci;
+                       __u16 plci;
+                       actcapi_ncpi ncpi;
+               } connect_b3_ind;
+               struct connect_b3_resp {
+                       __u16 ncci;
+                       __u8  rejectcause;
+                       actcapi_ncpi ncpi __attribute__ ((packed));
+               } connect_b3_resp;
+               struct disconnect_req {
+                       __u16 plci;
+                       __u8  cause;
+               } disconnect_req;
+               struct disconnect_conf {
+                       __u16 plci;
+                       __u16 info;
+               } disconnect_conf;
+               struct disconnect_ind {
+                       __u16 plci;
+                       __u16 info;
+               } disconnect_ind;
+               struct disconnect_resp {
+                       __u16 plci;
+               } disconnect_resp;
+               struct connect_b3_active_ind {
+                       __u16 ncci;
+                       actcapi_ncpi ncpi;
+               } connect_b3_active_ind;
+               struct connect_b3_active_resp {
+                       __u16 ncci;
+               } connect_b3_active_resp;
+               struct disconnect_b3_req {
+                       __u16 ncci;
+                       actcapi_ncpi ncpi;
+               } disconnect_b3_req;
+               struct disconnect_b3_conf {
+                       __u16 ncci;
+                       __u16 info;
+               } disconnect_b3_conf;
+               struct disconnect_b3_ind {
+                       __u16 ncci;
+                       __u16 info;
+                       actcapi_ncpi ncpi;
+               } disconnect_b3_ind;
+               struct disconnect_b3_resp {
+                       __u16 ncci;
+               } disconnect_b3_resp;
+               struct info_ind {
+                       __u16 plci;
+                       actcapi_infonr nr;
+                       actcapi_infoel el;
+               } info_ind;
+               struct info_resp {
+                       __u16 plci;
+               } info_resp;
+               struct listen_b3_req {
+                       __u16 plci;
+               } listen_b3_req;
+               struct listen_b3_conf {
+                       __u16 plci;
+                       __u16 info;
+               } listen_b3_conf;
+               struct select_b2_protocol_req {
+                       __u16 plci;
+                       __u8  protocol;
+                       actcapi_dlpd dlpd __attribute__ ((packed));
+               } select_b2_protocol_req;
+               struct select_b2_protocol_conf {
+                       __u16 plci;
+                       __u16 info;
+               } select_b2_protocol_conf;
+               struct select_b3_protocol_req {
+                       __u16 plci;
+                       __u8  protocol;
+                       actcapi_ncpd ncpd __attribute__ ((packed));
+               } select_b3_protocol_req;
+               struct select_b3_protocol_conf {
+                       __u16 plci;
+                       __u16 info;
+               } select_b3_protocol_conf;
+#if 0
+               struct listen_req {
+                       __u32 controller;
+                       __u32 infomask;  
+                       __u32 cipmask;
+                       __u32 cipmask2;
+                       __u16 dummy; /* 2 Length-bytes of 2 Structs MUST always be 0!!! */
+               } listen_req;
+               struct listen_conf {
+                       __u32  controller;
+                       __u16 info;
+               } listen_conf;
+#else
+               struct listen_req {
+                       __u8  controller;
+                       __u32 infomask __attribute__ ((packed));  
+                       __u16 eazmask __attribute__ ((packed));
+                       __u16 simask __attribute__ ((packed));
+               } listen_req;
+               struct listen_conf {
+                       __u8  controller;
+                       __u16 info __attribute__ ((packed));
+               } listen_conf;
+#endif
+               struct data_b3_req {
+                       __u16 fakencci;
+                       __u16 datalen;
+                       __u32 unused;
+                       __u8  blocknr;
+                       __u16 flags __attribute__ ((packed));
+               } data_b3_req;
+               struct data_b3_ind {
+                       __u16 fakencci;
+                       __u16 datalen;
+                       __u32 unused;
+                       __u8  blocknr;
+                       __u16 flags __attribute__ ((packed));
+               } data_b3_ind;
+               struct data_b3_resp {
+                       __u16 ncci;
+                       __u8  blocknr;
+               } data_b3_resp;
+               struct data_b3_conf {
+                       __u16 ncci;
+                       __u8  blocknr;
+                       __u16 info __attribute__ ((packed));
+               } data_b3_conf;
+       } msg;
+} actcapi_msg;
+
+extern __inline__ unsigned short
+actcapi_nextsmsg(act2000_card *card)
+{
+       unsigned long flags;
+       unsigned short n;
+
+       save_flags(flags);
+       cli();
+       n = card->msgnum;
+       card->msgnum++;
+       card->msgnum &= 0x7fff;
+       restore_flags(flags);
+       return n;
+}
+#define DEBUG_MSG
+#undef DEBUG_DATA_MSG
+#undef DEBUG_DUMP_SKB
+
+extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
+extern int actcapi_listen_req(act2000_card *);
+extern int actcapi_manufacturer_req_net(act2000_card *);
+extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
+extern int actcapi_manufacturer_req_errh(act2000_card *);
+extern int actcapi_manufacturer_req_msn(act2000_card *);
+extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
+extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
+extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
+extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
+extern void actcapi_dispatch(act2000_card *);
+#ifdef DEBUG_MSG
+extern void actcapi_debug_msg(struct sk_buff *skb, int);
+#else
+#define actcapi_debug_msg(skb, len)
+#endif
+#endif
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
new file mode 100644 (file)
index 0000000..76be187
--- /dev/null
@@ -0,0 +1,953 @@
+/* $Id: module.c,v 1.7 1998/02/12 23:06:52 keil Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ * 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: module.c,v $
+ * Revision 1.7  1998/02/12 23:06:52  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6  1998/01/31 22:10:42  keil
+ * changes for 2.1.82
+ *
+ * Revision 1.5  1997/10/09 22:23:04  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.4  1997/09/25 17:25:43  fritz
+ * Support for adding cards at runtime.
+ * Support for new Firmware.
+ *
+ * Revision 1.3  1997/09/24 23:11:45  fritz
+ * Optimized IRQ load and polling-mode.
+ *
+ * Revision 1.2  1997/09/24 19:44:17  fritz
+ * Added MSN mapping support, some cleanup.
+ *
+ * Revision 1.1  1997/09/23 18:00:13  fritz
+ * New driver for IBM Active 2000.
+ *
+ */
+
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+
+static unsigned short isa_ports[] =
+{
+        0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
+        0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
+};
+#define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
+
+act2000_card *cards = (act2000_card *) NULL;
+
+/* Parameters to be set by insmod */
+static int   act_bus  =  0;
+static int   act_port = -1;  /* -1 = Autoprobe  */
+static int   act_irq  = -1;  /* -1 = Autoselect */
+static char *act_id   = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+MODULE_DESCRIPTION(       "Driver for IBM Active 2000 ISDN card");
+MODULE_AUTHOR(            "Fritz Elfert");
+MODULE_SUPPORTED_DEVICE(  "ISDN subsystem");
+MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
+MODULE_PARM_DESC(membase, "Base port address of first card");
+MODULE_PARM_DESC(act_irq, "IRQ of first card (-1 = grab next free IRQ)");
+MODULE_PARM_DESC(act_id,  "ID-String of first card");
+MODULE_PARM(act_bus,  "i");
+MODULE_PARM(act_port, "i");
+MODULE_PARM(act_irq,  "i");
+MODULE_PARM(act_id,   "s");
+
+static int act2000_addcard(int, int, int, char *);
+
+static act2000_chan *
+find_channel(act2000_card *card, int channel)
+{
+       if ((channel >= 0) && (channel < ACT2000_BCH))
+               return &(card->bch[channel]);
+       printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
+       return NULL;
+}
+
+/*
+ * Free MSN list
+ */
+static void
+act2000_clear_msn(act2000_card *card)
+{
+        struct msn_entry *p = card->msn_list;
+        struct msn_entry *q;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+        card->msn_list = NULL;
+       restore_flags(flags);
+        while (p) {
+                q  = p->next;
+                kfree(p);
+                p = q;
+        }
+}
+
+/*
+ * Find an MSN entry in the list.
+ * If ia5 != 0, return IA5-encoded EAZ, else
+ * return a bitmask with corresponding bit set.
+ */
+static __u16
+act2000_find_msn(act2000_card *card, char *msn, int ia5)
+{
+        struct msn_entry *p = card->msn_list;
+       __u8 eaz = '0';
+
+       while (p) {
+               if (!strcmp(p->msn, msn)) {
+                       eaz = p->eaz;
+                       break;
+               }
+               p = p->next;
+       }
+       if (!ia5)
+               return (1 << (eaz - '0'));
+       else
+               return eaz;
+}
+
+/*
+ * Find an EAZ entry in the list.
+ * return a string with corresponding msn.
+ */
+char *
+act2000_find_eaz(act2000_card *card, char eaz)
+{
+        struct msn_entry *p = card->msn_list;
+
+       while (p) {
+               if (p->eaz == eaz)
+                       return(p->msn);
+               p = p->next;
+       }
+       return("\0");
+}
+
+/*
+ * Add or delete an MSN to the MSN list
+ *
+ * First character of msneaz is EAZ, rest is MSN.
+ * If length of eazmsn is 1, delete that entry.
+ */
+static int
+act2000_set_msn(act2000_card *card, char *eazmsn)
+{
+        struct msn_entry *p = card->msn_list;
+        struct msn_entry *q = NULL;
+       unsigned long flags;
+       int i;
+       
+       if (!strlen(eazmsn))
+               return 0;
+       if (strlen(eazmsn) > 16)
+               return -EINVAL;
+       for (i = 0; i < strlen(eazmsn); i++)
+               if (!isdigit(eazmsn[i]))
+                       return -EINVAL;
+        if (strlen(eazmsn) == 1) {
+               /* Delete a single MSN */
+               while (p) {
+                       if (p->eaz == eazmsn[0]) {
+                               save_flags(flags);
+                               cli();
+                               if (q)
+                                       q->next = p->next;
+                               else
+                                       card->msn_list = p->next;
+                               restore_flags(flags);
+                               kfree(p);
+                               printk(KERN_DEBUG
+                                      "Mapping for EAZ %c deleted\n",
+                                      eazmsn[0]);
+                               return 0;
+                       }
+                       q = p;
+                       p = p->next;
+               }
+               return 0;
+        }
+       /* Add a single MSN */
+       while (p) {
+               /* Found in list, replace MSN */
+               if (p->eaz == eazmsn[0]) {
+                       save_flags(flags);
+                       cli();
+                       strcpy(p->msn, &eazmsn[1]);
+                       restore_flags(flags);
+                       printk(KERN_DEBUG
+                              "Mapping for EAZ %c changed to %s\n",
+                              eazmsn[0],
+                              &eazmsn[1]);
+                       return 0;
+               }
+               p = p->next;
+       }
+       /* Not found in list, add new entry */
+       p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->eaz = eazmsn[0];
+       strcpy(p->msn, &eazmsn[1]);
+       p->next = card->msn_list;
+       save_flags(flags);
+       cli();
+       card->msn_list = p;
+       restore_flags(flags);
+       printk(KERN_DEBUG
+              "Mapping %c -> %s added\n",
+              eazmsn[0],
+              &eazmsn[1]);
+       return 0;
+}
+
+static void
+act2000_transmit(struct act2000_card *card)
+{
+       switch (card->bus) {
+               case ACT2000_BUS_ISA:
+                       isa_send(card);
+                       break;
+               case ACT2000_BUS_PCMCIA:
+               case ACT2000_BUS_MCA:
+               default:
+                       printk(KERN_WARNING
+                              "act2000_transmit: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+act2000_receive(struct act2000_card *card)
+{
+       switch (card->bus) {
+               case ACT2000_BUS_ISA:
+                       isa_receive(card);
+                       break;
+               case ACT2000_BUS_PCMCIA:
+               case ACT2000_BUS_MCA:
+               default:
+                       printk(KERN_WARNING
+                              "act2000_receive: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+act2000_poll(unsigned long data)
+{
+       act2000_card * card = (act2000_card *)data;
+       unsigned long flags;
+
+       act2000_receive(card);
+        save_flags(flags);
+        cli();
+        del_timer(&card->ptimer);
+        card->ptimer.expires = jiffies + 3;
+        add_timer(&card->ptimer);
+        restore_flags(flags);
+}
+
+static int
+act2000_command(act2000_card * card, isdn_ctrl * c)
+{
+        ulong a;
+        act2000_chan *chan;
+       act2000_cdef cdef;
+       isdn_ctrl cmd;
+       char tmp[17];
+       int ret;
+       unsigned long flags;
+        switch (c->command) {
+               case ISDN_CMD_IOCTL:
+                       memcpy(&a, c->parm.num, sizeof(ulong));
+                       switch (c->arg) {
+                               case ACT2000_IOCTL_LOADBOOT:
+                                       switch (card->bus) {
+                                               case ACT2000_BUS_ISA:
+                                                       ret = isa_download(card,
+                                                                          (act2000_ddef *)a);
+                                                       if (!ret) {
+                                                               card->flags |= ACT2000_FLAGS_LOADED;
+                                                               if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+                                                                       card->ptimer.expires = jiffies + 3;
+                                                                       card->ptimer.function = act2000_poll;
+                                                                       card->ptimer.data = (unsigned long)card;
+                                                                       add_timer(&card->ptimer);
+                                                               }
+                                                               actcapi_manufacturer_req_errh(card);
+                                                       }
+                                                       break;
+                                               default:
+                                                       printk(KERN_WARNING
+                                                              "act2000: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -EIO;
+                                       }
+                                       return ret;
+                               case ACT2000_IOCTL_SETPROTO:
+                                       card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;
+                                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                                               return 0;
+                                       actcapi_manufacturer_req_net(card);
+                                       return 0;
+                               case ACT2000_IOCTL_SETMSN:
+                                       if ((ret = copy_from_user(tmp, (char *)a, sizeof(tmp))))
+                                               return ret;
+                                       if ((ret = act2000_set_msn(card, tmp)))
+                                               return ret;
+                                       if (card->flags & ACT2000_FLAGS_RUNNING)
+                                               return(actcapi_manufacturer_req_msn(card));
+                                       return 0;
+                               case ACT2000_IOCTL_ADDCARD:
+                                       if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
+                                               return ret;
+                                       if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
+                                               return -EIO;
+                                       return 0;
+                               case ACT2000_IOCTL_TEST:
+                                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                                               return -ENODEV;
+                                       return 0;
+                               default:
+                                       return -EINVAL;
+                       }
+                       break;
+               case ISDN_CMD_DIAL:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       save_flags(flags);
+                       cli();
+                       if (chan->fsm_state != ACT2000_STATE_NULL) {
+                               restore_flags(flags);
+                               printk(KERN_WARNING "Dial on channel with state %d\n",
+                                       chan->fsm_state);
+                               return -EBUSY;
+                       }
+                       if (card->ptype == ISDN_PTYPE_EURO)
+                               tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
+                       else
+                               tmp[0] = c->parm.setup.eazmsn[0];
+                       chan->fsm_state = ACT2000_STATE_OCALL;
+                       chan->callref = 0xffff;
+                       restore_flags(flags);
+                       ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
+                                                 tmp[0], c->parm.setup.si1,
+                                                 c->parm.setup.si2);
+                       if (ret) {
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_DHUP;
+                               cmd.arg &= 0x0f;
+                               card->interface.statcallb(&cmd);
+                       }
+                       return ret;
+               case ISDN_CMD_ACCEPTD:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       if (chan->fsm_state == ACT2000_STATE_ICALL)
+                               actcapi_select_b2_protocol_req(card, chan);
+                       return 0;
+               case ISDN_CMD_ACCEPTB:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       return 0;
+               case ISDN_CMD_HANGUP:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       switch (chan->fsm_state) {
+                               case ACT2000_STATE_ICALL:
+                               case ACT2000_STATE_BSETUP:
+                                       actcapi_connect_resp(card, chan, 0x15);
+                                       break;
+                               case ACT2000_STATE_ACTIVE:
+                                       actcapi_disconnect_b3_req(card, chan);
+                                       break;
+                       }
+                       return 0;
+               case ISDN_CMD_SETEAZ:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       if (strlen(c->parm.num)) {
+                               if (card->ptype == ISDN_PTYPE_EURO) {
+                                       chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
+                               }
+                               if (card->ptype == ISDN_PTYPE_1TR6) {
+                                       int i;
+                                       chan->eazmask = 0;
+                                       for (i = 0; i < strlen(c->parm.num); i++)
+                                               if (isdigit(c->parm.num[i]))
+                                                       chan->eazmask |= (1 << (c->parm.num[i] - '0'));
+                               }
+                       } else
+                               chan->eazmask = 0x3ff;
+                       actcapi_listen_req(card);
+                       return 0;
+               case ISDN_CMD_CLREAZ:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       chan->eazmask = 0;
+                       actcapi_listen_req(card);
+                       return 0;
+               case ISDN_CMD_SETL2:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       chan->l2prot = (c->arg >> 8);
+                       return 0;
+               case ISDN_CMD_GETL2:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       return chan->l2prot;
+               case ISDN_CMD_SETL3:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
+                               printk(KERN_WARNING "L3 protocol unknown\n");
+                               return -1;
+                       }
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       chan->l3prot = (c->arg >> 8);
+                       return 0;
+               case ISDN_CMD_GETL3:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x0f)))
+                               break;
+                       return chan->l3prot;
+               case ISDN_CMD_GETEAZ:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       printk(KERN_DEBUG "act2000 CMD_GETEAZ not implemented\n");
+                       return 0;
+               case ISDN_CMD_SETSIL:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       printk(KERN_DEBUG "act2000 CMD_SETSIL not implemented\n");
+                       return 0;
+               case ISDN_CMD_GETSIL:
+                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                               return -ENODEV;
+                       printk(KERN_DEBUG "act2000 CMD_GETSIL not implemented\n");
+                       return 0;
+               case ISDN_CMD_LOCK:
+                       MOD_INC_USE_COUNT;
+                       return 0;
+               case ISDN_CMD_UNLOCK:
+                       MOD_DEC_USE_COUNT;
+                       return 0;
+        }
+       
+        return -EINVAL;
+}
+
+static int
+act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
+{
+        struct sk_buff *xmit_skb;
+        int len;
+        act2000_chan *chan;
+       actcapi_msg *msg;
+
+        if (!(chan = find_channel(card, channel)))
+               return -1;
+        if (chan->fsm_state != ACT2000_STATE_ACTIVE)
+                return -1;
+        len = skb->len;
+        if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
+                return 0;
+       if (!len)
+               return 0;
+       if (skb_headroom(skb) < 19) {
+               printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
+                      skb_headroom(skb));
+               xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
+               if (!xmit_skb) {
+                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+                       return 0;
+               }
+               skb_reserve(xmit_skb, 19);
+               memcpy(skb_put(xmit_skb, len), skb->data, len);
+       } else {
+               xmit_skb = skb_clone(skb, GFP_ATOMIC);
+               if (!xmit_skb) {
+                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+                       return 0;
+               }
+       }
+       dev_kfree_skb(skb);
+       msg = (actcapi_msg *)skb_push(xmit_skb, 19);
+       msg->hdr.len = 19 + len;
+       msg->hdr.applicationID = 1;
+       msg->hdr.cmd.cmd = 0x86;
+       msg->hdr.cmd.subcmd = 0x00;
+       msg->hdr.msgnum = actcapi_nextsmsg(card);
+       msg->msg.data_b3_req.datalen = len;
+       msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
+       msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
+       msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
+       actcapi_debug_msg(xmit_skb, 1);
+        chan->queued += len;
+       skb_queue_tail(&card->sndq, xmit_skb);
+       act2000_schedule_tx(card);
+        return len;
+}
+
+
+/* Read the Status-replies from the Interface */
+static int
+act2000_readstatus(u_char * buf, int len, int user, act2000_card * card)
+{
+        int count;
+        u_char *p;
+
+        for (p = buf, count = 0; count < len; p++, count++) {
+                if (card->status_buf_read == card->status_buf_write)
+                        return count;
+                if (user)
+                        put_user(*card->status_buf_read++, p);
+                else
+                        *p = *card->status_buf_read++;
+                if (card->status_buf_read > card->status_buf_end)
+                        card->status_buf_read = card->status_buf;
+        }
+        return count;
+}
+
+static void
+act2000_putmsg(act2000_card *card, char c)
+{
+        ulong flags;
+
+        save_flags(flags);
+        cli();
+        *card->status_buf_write++ = c;
+        if (card->status_buf_write == card->status_buf_read) {
+                if (++card->status_buf_read > card->status_buf_end)
+                card->status_buf_read = card->status_buf;
+        }
+        if (card->status_buf_write > card->status_buf_end)
+                card->status_buf_write = card->status_buf;
+        restore_flags(flags);
+}
+
+static void
+act2000_logstat(struct act2000_card *card, char *str)
+{
+        char *p = str;
+        isdn_ctrl c;
+
+       while (*p)
+               act2000_putmsg(card, *p++);
+        c.command = ISDN_STAT_STAVAIL;
+        c.driver = card->myid;
+        c.arg = strlen(str);
+        card->interface.statcallb(&c);
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline act2000_card *
+act2000_findcard(int driverid)
+{
+        act2000_card *p = cards;
+
+        while (p) {
+                if (p->myid == driverid)
+                        return p;
+                p = p->next;
+        }
+        return (act2000_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+        act2000_card *card = act2000_findcard(c->driver);
+
+        if (card)
+                return (act2000_command(card, c));
+        printk(KERN_ERR
+             "act2000: 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)
+{
+        act2000_card *card = act2000_findcard(id);
+
+        if (card) {
+                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (len);
+        }
+        printk(KERN_ERR
+               "act2000: if_writecmd called with invalid driverId!\n");
+        return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+        act2000_card *card = act2000_findcard(id);
+       
+        if (card) {
+                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (act2000_readstatus(buf, len, user, card));
+        }
+        printk(KERN_ERR
+               "act2000: if_readstatus called with invalid driverId!\n");
+        return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+        act2000_card *card = act2000_findcard(id);
+       
+        if (card) {
+                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                        return -ENODEV;
+               return (act2000_sendbuf(card, channel, ack, skb));
+        }
+        printk(KERN_ERR
+               "act2000: if_sendbuf called with invalid driverId!\n");
+        return -ENODEV;
+}
+
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list.
+ */
+static void
+act2000_alloccard(int bus, int port, int irq, char *id)
+{
+       int i;
+        act2000_card *card;
+        if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
+                printk(KERN_WARNING
+                      "act2000: (%s) Could not allocate card-struct.\n", id);
+                return;
+        }
+        memset((char *) card, 0, sizeof(act2000_card));
+       skb_queue_head_init(&card->sndq);
+       skb_queue_head_init(&card->rcvq);
+       skb_queue_head_init(&card->ackq);
+       card->snd_tq.routine = (void *) (void *) act2000_transmit;
+       card->snd_tq.data = card;
+       card->rcv_tq.routine = (void *) (void *) actcapi_dispatch;
+       card->rcv_tq.data = card;
+       card->poll_tq.routine = (void *) (void *) act2000_receive;
+       card->poll_tq.data = card;
+       init_timer(&card->ptimer);
+        card->interface.channels = ACT2000_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 |
+#if 0
+/* Not yet! New Firmware is on the way ... */
+               ISDN_FEATURE_L2_TRANS |
+#endif
+               ISDN_FEATURE_L3_TRANS |
+               ISDN_FEATURE_P_UNKNOWN;
+        card->interface.hl_hdrlen = 20;
+        card->ptype = ISDN_PTYPE_EURO;
+        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+        for (i=0; i<ACT2000_BCH; i++) {
+                card->bch[i].plci = 0x8000;
+                card->bch[i].ncci = 0x8000;
+                card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
+                card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
+        }
+        card->myid = -1;
+        card->bus = bus;
+        card->port = port;
+        card->irq = irq;
+        card->next = cards;
+        cards = card;
+}
+
+/*
+ * register card at linklevel
+ */
+static int
+act2000_registercard(act2000_card * card)
+{
+        switch (card->bus) {
+               case ACT2000_BUS_ISA:
+                       break;
+               case ACT2000_BUS_MCA:
+               case ACT2000_BUS_PCMCIA:
+               default:
+                       printk(KERN_WARNING
+                              "act2000: Illegal BUS type %d\n",
+                              card->bus);
+                       return -1;
+        }
+        if (!register_isdn(&card->interface)) {
+                printk(KERN_WARNING
+                       "act2000: Unable to register %s\n",
+                       card->interface.id);
+                return -1;
+        }
+        card->myid = card->interface.channels;
+        sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
+        return 0;
+}
+
+static void
+unregister_card(act2000_card * card)
+{
+        isdn_ctrl cmd;
+
+        cmd.command = ISDN_STAT_UNLOAD;
+        cmd.driver = card->myid;
+        card->interface.statcallb(&cmd);
+        switch (card->bus) {
+               case ACT2000_BUS_ISA:
+                       isa_release(card);
+                       break;
+               case ACT2000_BUS_MCA:
+               case ACT2000_BUS_PCMCIA:
+               default:
+                       printk(KERN_WARNING
+                              "act2000: Invalid BUS type %d\n",
+                              card->bus);
+                       break;
+        }
+}
+
+static int
+act2000_addcard(int bus, int port, int irq, char *id)
+{
+       act2000_card *p;
+       act2000_card *q = NULL;
+       int initialized;
+       int added = 0;
+       int failed = 0;
+       int i;
+
+       if (!bus)
+               bus = ACT2000_BUS_ISA;
+       if (port != -1) {
+               /* Port defined, do fixed setup */
+               act2000_alloccard(bus, port, irq, id);
+       } else {
+               /* No port defined, perform autoprobing.
+                * This may result in more than one card detected.
+                */
+               switch (bus) {
+                       case ACT2000_BUS_ISA:
+                               for (i = 0; i < ISA_NRPORTS; i++)
+                                       if (isa_detect(isa_ports[i])) {
+                                               printk(KERN_INFO
+                                                      "act2000: Detected ISA card at port 0x%x\n",
+                                                      isa_ports[i]);
+                                               act2000_alloccard(bus, isa_ports[i], irq, id);
+                                       }
+                               break;
+                       case ACT2000_BUS_MCA:
+                       case ACT2000_BUS_PCMCIA:
+                       default:
+                               printk(KERN_WARNING
+                                      "act2000: addcard: Invalid BUS type %d\n",
+                                      bus);
+               }
+       }
+       if (!cards)
+               return 1;
+        p = cards;
+        while (p) {
+               initialized = 0;
+               if (!p->interface.statcallb) {
+                       /* Not yet registered.
+                        * Try to register and activate it.
+                        */
+                       added++;
+                       switch (p->bus) {
+                               case ACT2000_BUS_ISA:
+                                       if (isa_detect(p->port)) {
+                                               if (act2000_registercard(p))
+                                                       break;
+                                               if (isa_config_port(p, p->port)) {
+                                                       printk(KERN_WARNING
+                                                              "act2000: Could not request port 0x%04x\n",
+                                                              p->port);
+                                                       unregister_card(p);
+                                                       p->interface.statcallb = NULL;
+                                                       break;
+                                               }
+                                               if (isa_config_irq(p, p->irq)) {
+                                                       printk(KERN_INFO
+                                                              "act2000: No IRQ available, fallback to polling\n");
+                                                       /* Fall back to polled operation */
+                                                       p->irq = 0;
+                                               }
+                                               printk(KERN_INFO
+                                                      "act2000: ISA"
+                                                      "-type card at port "
+                                                      "0x%04x ",
+                                                      p->port);
+                                               if (p->irq)
+                                                       printk("irq %d\n", p->irq);
+                                               else
+                                                       printk("polled\n");
+                                               initialized = 1;
+                                       }
+                                       break;
+                               case ACT2000_BUS_MCA:
+                               case ACT2000_BUS_PCMCIA:
+                               default:
+                                       printk(KERN_WARNING
+                                              "act2000: addcard: Invalid BUS type %d\n",
+                                              p->bus);
+                       }
+               } else
+                       /* Card already initialized */
+                       initialized = 1;
+                if (initialized) {
+                       /* Init OK, next card ... */
+                        q = p;
+                        p = p->next;
+                } else {
+                        /* Init failed, remove card from list, free memory */
+                        printk(KERN_WARNING
+                               "act2000: Initialization of %s failed\n",
+                               p->interface.id);
+                        if (q) {
+                                q->next = p->next;
+                                kfree(p);
+                                p = q->next;
+                        } else {
+                                cards = p->next;
+                                kfree(p);
+                                p = cards;
+                        }
+                       failed++;
+                }
+       }
+        return (added - failed);
+}
+
+#define DRIVERNAME "IBM Active 2000 ISDN driver"
+
+#ifdef MODULE
+#define act2000_init init_module
+#endif
+
+int
+act2000_init(void)
+{
+        printk(KERN_INFO "%s\n", DRIVERNAME);
+        if (!cards)
+               act2000_addcard(act_bus, act_port, act_irq, act_id);
+        if (!cards)
+                printk(KERN_INFO "act2000: No cards defined yet\n");
+        /* No symbols to export, hide all symbols */
+        EXPORT_NO_SYMBOLS;
+        return 0;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+        act2000_card *card = cards;
+        act2000_card *last;
+        while (card) {
+                unregister_card(card);
+               del_timer(&card->ptimer);
+                card = card->next;
+        }
+        card = cards;
+        while (card) {
+                last = card;
+                card = card->next;
+               act2000_clear_msn(last);
+                kfree(last);
+        }
+        printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
+}
+
+#else
+void
+act2000_setup(char *str, int *ints)
+{
+        int i, j, argc, port, irq, bus;
+       
+        argc = ints[0];
+        i = 1;
+        if (argc)
+                while (argc) {
+                        port = irq = -1;
+                       bus = 0;
+                        if (argc) {
+                                bus = ints[i];
+                                i++;
+                                argc--;
+                        }
+                        if (argc) {
+                                port = ints[i];
+                                i++;
+                                argc--;
+                        }
+                        if (argc) {
+                                irq = ints[i];
+                                i++;
+                                argc--;
+                        }
+                       act2000_addcard(bus, port, irq, act_id);
+               }
+}
+#endif
index 00be6fef778c9a7732c76f7aef24c0c09f55ff4d..648f19fc23723ee3e148172a5c40f885c65648e0 100644 (file)
@@ -1,11 +1,39 @@
 /*
- * $Id: b1capi.c,v 1.4 1997/05/27 15:17:45 fritz Exp $
+ * $Id: b1capi.c,v 1.10 1998/02/13 07:09:10 calle 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.10  1998/02/13 07:09:10  calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.9  1998/01/31 11:14:39  calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8  1997/12/10 20:00:46  calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.4.2.5  1997/12/07 19:59:54  calle
+ * more changes for M1/T1/B1 + config
+ *
+ * Revision 1.4.2.4  1997/11/26 16:57:20  calle
+ * more changes for B1/M1/T1.
+ *
+ * Revision 1.7  1997/10/19 14:45:40  calle
+ * fixed capi_get_version.
+ *
+ * Revision 1.6  1997/10/01 09:21:09  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.5  1997/07/12 08:22:26  calle
+ * Correct bug in CARD_NR macro, so now more than one card will work.
+ * Allow card reset, even if card is in running state.
+ *
+ *
  * Revision 1.4  1997/05/27 15:17:45  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.10 $";
 
 /* ------------------------------------------------------------- */
 
 int showcapimsgs = 0;          /* used in lli.c */
 int loaddebug = 0;
-static int portbase = 0x150;
-#ifdef MODULE
-static int irq = 15;
 
-#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
-#endif
 
 /* ------------------------------------------------------------- */
 
@@ -97,7 +117,7 @@ typedef struct avmb1_appl {
 
 /* ------------------------------------------------------------- */
 
-static struct capi_version driver_version = {2, 0, 0, 9};
+static struct capi_version driver_version = {2, 0, 1, 1<<4};
 static char driver_serial[CAPI_SERIAL_LEN] = "4711";
 static char capi_manufakturer[64] = "AVM Berlin";
 
@@ -109,9 +129,9 @@ static char capi_manufakturer[64] = "AVM Berlin";
 
 #define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
 
-#define VALID_CARD(c)     ((c) > 0 && (c) <= ncards)
+#define VALID_CARD(c)     ((c) > 0 && (c) <= CAPI_MAXCONTR)
 #define CARD(c)                   (&cards[(c)-1])
-#define CARDNR(cp)        ((cards-(cp))+1)
+#define CARDNR(cp)        (((cp)-cards)+1)
 
 static avmb1_appl applications[CAPI_MAXAPPL];
 static avmb1_card cards[CAPI_MAXCONTR];
@@ -126,6 +146,17 @@ static struct tq_struct tq_recv_notify;
 
 /* -------- util functions ------------------------------------ */
 
+static char *cardtype2str(int cardtype)
+{
+       switch (cardtype) {
+               default:
+               case AVM_CARDTYPE_B1: return "B1";
+               case AVM_CARDTYPE_M1: return "M1";
+               case AVM_CARDTYPE_M2: return "M2";
+               case AVM_CARDTYPE_T1: return "T1";
+       }
+}
+
 static inline int capi_cmd_valid(__u8 cmd)
 {
        switch (cmd) {
@@ -287,6 +318,8 @@ static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci)
        return 0;
 }
 
+
+
 /* -------- Receiver ------------------------------------------ */
 
 
@@ -367,6 +400,7 @@ static void notify_up(__u16 contr)
 {
        struct capi_interface_user *p;
 
+        printk(KERN_NOTICE "b1capi: notify up contr %d\n", contr);
        for (p = capi_users; p; p = p->next) {
                if (p->callback)
                        (*p->callback) (KCI_CONTRUP, contr,
@@ -378,6 +412,7 @@ static void notify_up(__u16 contr)
 static void notify_down(__u16 contr)
 {
        struct capi_interface_user *p;
+        printk(KERN_NOTICE "b1capi: notify down contr %d\n", contr);
        for (p = capi_users; p; p = p->next) {
                if (p->callback)
                        (*p->callback) (KCI_CONTRDOWN, contr, 0);
@@ -400,18 +435,22 @@ static void notify_handler(void *dummy)
 
 void avmb1_card_ready(avmb1_card * card)
 {
+        struct capi_profile *profp =
+                       (struct capi_profile *)card->version[VER_PROFILE];
+       char *dversion = card->version[VER_DRIVER];
        __u16 appl;
+       char *cardname, cname[20];
+       __u32 flag;
 
        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->cversion.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
+       card->cversion.majormanuversion |= ((dversion[2] - '0') & 0xf);
+       card->cversion.minormanuversion = (dversion[3] - '0') << 4;
+       card->cversion.minormanuversion |=
+               (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
        card->cardstate = CARD_RUNNING;
 
-
        for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
                if (VALID_APPLID(appl) && !APPL(appl)->releasing) {
                        B1_send_register(card->port, appl,
@@ -424,56 +463,190 @@ void avmb1_card_ready(avmb1_card * card)
 
         set_bit(CARDNR(card), &notify_up_set);
         queue_task(&tq_state_notify, &tq_scheduler);
+
+        flag = ((__u8 *)(profp->manu))[1];
+        switch (flag) {
+       case 0: cardname = cardtype2str(card->cardtype); break;
+       case 3: cardname = "PCMCIA B"; break;
+       case 4: cardname = "PCMCIA M1"; break;
+       case 5: cardname = "PCMCIA M2"; break;
+       case 6: cardname = "B1 V3.0"; break;
+       case 7: cardname = "B1 PCI"; break;
+       default: cardname = cname; break;
+                 sprintf(cname, "AVM?%u", (unsigned int)flag);
+                 break;
+        }
+        printk(KERN_NOTICE "b1capi: card %d \"%s\" ready.\n",
+               CARDNR(card), cardname);
+        flag = ((__u8 *)(profp->manu))[3];
+        if (flag)
+               printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n",
+                       CARDNR(card),
+                       (flag & 0x01) ? " DSS1" : "",
+                       (flag & 0x02) ? " CT1" : "",
+                       (flag & 0x04) ? " VN3" : "",
+                       (flag & 0x08) ? " NI1" : "",
+                       (flag & 0x10) ? " AUSTEL" : "",
+                       (flag & 0x20) ? " ESS" : "",
+                       (flag & 0x40) ? " 1TR6" : ""
+                       );
+        flag = ((__u8 *)(profp->manu))[5];
+       if (flag)
+               printk(KERN_NOTICE "b1capi: card %d Linetype:%s%s%s%s\n",
+                       CARDNR(card),
+                       (flag & 0x01) ? " point to point" : "",
+                       (flag & 0x02) ? " point to multipoint" : "",
+                       (flag & 0x08) ? " leased line without D-channel" : "",
+                       (flag & 0x04) ? " leased line with D-channel" : ""
+                       );
+}
+
+static void avmb1_card_down(avmb1_card * card, int notify)
+{
+       __u16 appl;
+
+        card->cardstate = CARD_DETECTED;
+
+       for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+               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 forced down!\n", appl, np->ncci);
+                               kfree(np);
+                               nextpp = pp;
+                       } else {
+                               nextpp = &(*pp)->next;
+                       }
+               }
+       }
+       set_bit(CARDNR(card), &notify_down_set);
+       queue_task(&tq_state_notify, &tq_scheduler);
+       printk(KERN_NOTICE "b1capi: card %d down.\n", CARDNR(card));
 }
 
 /* ------------------------------------------------------------- */
 
-int avmb1_addcard(int port, int irq)
+
+int avmb1_registercard(int port, int irq, int cardtype, int allocio)
 {
        struct avmb1_card *card;
-       int irqval;
+       int irqval,i;
+
 
+       for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ;
+   
+       if (i == CAPI_MAXCONTR) {
+               printk(KERN_ERR "b1capi: out of controller slots\n");
+               return -ENFILE;
+       }
 
-       card = &cards[ncards];
+       card = &cards[i];
        memset(card, 0, sizeof(avmb1_card));
-       sprintf(card->name, "avmb1-%d", ncards + 1);
+       sprintf(card->name, "avmb1-%d", CARDNR(card));
 
-       request_region(port, AVMB1_PORTLEN, card->name);
+        if (allocio)
+               request_region(port, AVMB1_PORTLEN, card->name);
 
-       if ((irqval = request_irq(irq, avmb1_interrupt, SA_SHIRQ, card->name, card)) != 0) {
+       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;
        }
+
+       card->cardstate = CARD_DETECTED;
        ncards++;
-       card->cnr = ncards;
+       card->cnr = CARDNR(card);
        card->port = port;
        card->irq = irq;
-       card->cardstate = CARD_DETECTED;
-       return 0;
+       card->cardtype = cardtype;
+       return card->cnr;
+}
+
+int avmb1_addcard(int port, int irq, int cardtype)
+{
+       return avmb1_registercard(port, irq, cardtype, 1);
 }
 
-int avmb1_probecard(int port, int irq)
+int avmb1_detectcard(int port, int irq, int cardtype)
 {
        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);
+       if (!B1_valid_irq(irq, cardtype)) {
+               printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n",
+                               irq, cardtype2str(cardtype));
                return -EIO;
        }
-       if (!B1_valid_irq(irq)) {
-               printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq);
+       if ((rc = B1_detect(port, cardtype)) != 0) {
+               printk(KERN_NOTICE "b1capi: NO %s-card at 0x%x (%d)\n",
+                                         cardtype2str(cardtype), port, rc);
                return -EIO;
        }
-       if ((rc = B1_detect(port)) != 0) {
-               printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc);
+       B1_reset(port);
+       switch (cardtype) {
+               default:
+               case AVM_CARDTYPE_M1:
+               case AVM_CARDTYPE_M2:
+               case AVM_CARDTYPE_B1:
+                       printk(KERN_NOTICE "b1capi: AVM-%s-Controller detected at 0x%x\n", cardtype2str(cardtype), port);
+                       break;
+               case AVM_CARDTYPE_T1:
+                       printk(KERN_NOTICE "b1capi: AVM-%s-Controller may be at 0x%x\n", cardtype2str(cardtype), port);
+                       break;
+       }
+
+       return 0;
+}
+
+int avmb1_probecard(int port, int irq, int cardtype)
+{
+       if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
+               printk(KERN_WARNING
+                      "b1capi: ports 0x%03x-0x%03x in use.\n",
+                      port, port + AVMB1_PORTLEN);
                return -EIO;
        }
-       B1_reset(port);
-       printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", port);
+        return avmb1_detectcard(port, irq, cardtype);
+}
+
+int avmb1_unregistercard(int cnr, int freeio)
+{
+       avmb1_card * card;
+       if (!VALID_CARD(cnr)) 
+               return -ESRCH;
+       card = CARD(cnr);
+       if (card->cardstate == CARD_FREE)
+               return -ESRCH;
+       if (card->cardstate == CARD_RUNNING)
+               avmb1_card_down(card, freeio);
+
+       free_irq(card->irq, card);
+       if (freeio)
+               release_region(card->port, AVMB1_PORTLEN);
+       card->cardstate = CARD_FREE;
+       return 0;
+}
+
+int avmb1_resetcard(int cnr)
+{
+       avmb1_card * card;
+
+       if (!VALID_CARD(cnr))
+               return -ESRCH;
+       card = CARD(cnr);
+       if (card->cardstate == CARD_FREE)
+               return -ESRCH;
+
+       if (card->cardstate == CARD_RUNNING)
+               avmb1_card_down(card, 0);
+
+       B1_reset(card->port);
+       B1_reset(card->port);
+
+       card->cardstate = CARD_DETECTED;
 
        return 0;
 }
@@ -485,7 +658,7 @@ int avmb1_probecard(int port, int irq)
 static int capi_installed(void)
 {
        int i;
-       for (i = 0; i < ncards; i++) {
+       for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (cards[i].cardstate == CARD_RUNNING)
                        return 1;
        }
@@ -512,7 +685,7 @@ static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
 
        memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
 
-       for (i = 0; i < ncards; i++) {
+       for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (cards[i].cardstate != CARD_RUNNING)
                        continue;
                B1_send_register(cards[i].port, appl,
@@ -538,9 +711,10 @@ static __u16 capi_release(__u16 applid)
                return CAPI_ILLAPPNR;
        while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
                kfree_skb(skb);
-       for (i = 0; i < ncards; i++) {
-               if (cards[i].cardstate != CARD_RUNNING)
+       for (i = 0; i < CAPI_MAXCONTR; i++) {
+               if (cards[i].cardstate != CARD_RUNNING) {
                        continue;
+               }
                APPL(applid)->releasing++;
                B1_send_release(cards[i].port, applid);
        }
@@ -628,7 +802,7 @@ static __u16 capi_get_version(__u16 contr, struct capi_version *verp)
        if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) 
                return 0x2002;
 
-       memcpy((void *) verp, CARD(contr)->version[VER_SERIAL],
+       memcpy((void *) verp, &CARD(contr)->cversion,
               sizeof(capi_version));
        return CAPI_NOERROR;
 }
@@ -665,33 +839,52 @@ static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp)
 static int capi_manufacturer(unsigned int cmd, void *data)
 {
        unsigned long flags;
-       avmb1_loaddef ldef;
-       avmb1_carddef cdef;
+       avmb1_loadandconfigdef ldef;
+       avmb1_extcarddef cdef;
        avmb1_resetdef rdef;
+       avmb1_getdef gdef;
        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;
+       case AVMB1_ADDCARD_WITH_TYPE:
+               if (cmd == AVMB1_ADDCARD) {
+                  if ((rc = copy_from_user((void *) &cdef, data,
+                                           sizeof(avmb1_carddef))))
+                          return rc;
+                  cdef.cardtype = AVM_CARDTYPE_B1;
+               } else {
+                  if ((rc = copy_from_user((void *) &cdef, data,
+                                           sizeof(avmb1_extcarddef))))
+                          return rc;
+               }
 
-               if ((rc = avmb1_probecard(cdef.port, cdef.irq)) != 0)
+               if ((rc = avmb1_probecard(cdef.port, cdef.irq, cdef.cardtype)) != 0)
                        return rc;
 
-               return avmb1_addcard(cdef.port, cdef.irq);
+               return avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype);
 
        case AVMB1_LOAD:
+       case AVMB1_LOAD_AND_CONFIG:
+
+               if (cmd == AVMB1_LOAD) {
+                       if ((rc = copy_from_user((void *) &ldef, data,
+                                               sizeof(avmb1_loaddef))))
+                               return rc;
+                       ldef.t4config.len = 0;
+                       ldef.t4config.data = 0;
+               } else {
+                       if ((rc = copy_from_user((void *) &ldef, data,
+                                               sizeof(avmb1_loadandconfigdef))))
+                               return rc;
+               }
+               if (!VALID_CARD(ldef.contr))
+                       return -ESRCH;
 
-               if ((rc = copy_from_user((void *) &ldef, data,
-                                        sizeof(avmb1_loaddef))))
-                       return rc;
-               if (!VALID_CARD(ldef.contr) || ldef.t4file.len <= 0) {
+               if (ldef.t4file.len <= 0) {
                        if (loaddebug)
-                               printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len);
+                               printk(KERN_DEBUG "b1capi: load: invalid parameter length of t4file is %d ?\n", ldef.t4file.len);
                        return -EINVAL;
                }
 
@@ -720,6 +913,20 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                        return rc;
                }
                B1_disable_irq(card->port);
+
+               if (ldef.t4config.len > 0) { /* load config */
+                       if (loaddebug) {
+                               printk(KERN_DEBUG "b1capi: loading config to contr %d\n",
+                                                       ldef.contr);
+                       }
+                       if ((rc = B1_load_config(card->port, &ldef.t4config))) {
+                               B1_reset(card->port);
+                               printk(KERN_ERR "b1capi: failed to load config!!\n");
+                               card->cardstate = CARD_DETECTED;
+                               return rc;
+                       }
+               }
+
                if (loaddebug) {
                        printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n",
                                ldef.contr);
@@ -737,7 +944,7 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                card->cardstate = CARD_INITSTATE;
                save_flags(flags);
                cli();
-               B1_assign_irq(card->port, card->irq);
+               B1_assign_irq(card->port, card->irq, card->cardtype);
                B1_enable_irq(card->port);
                restore_flags(flags);
 
@@ -766,23 +973,31 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                                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;
+               return avmb1_resetcard(rdef.contr);
+
+       case AVMB1_GET_CARDINFO:
+               if ((rc = copy_from_user((void *) &gdef, data,
+                                        sizeof(avmb1_getdef))))
+                       return rc;
 
-               card = CARD(rdef.contr);
+               if (!VALID_CARD(gdef.contr))
+                       return -ESRCH;
 
-               if (card->cardstate == CARD_RUNNING)
-                       return -EBUSY;
+               card = CARD(gdef.contr);
 
-               B1_reset(card->port);
-               B1_reset(card->port);
+               gdef.cardstate = card->cardstate;
+               gdef.cardtype = card->cardtype;
+
+               if ((rc = copy_to_user(data, (void *) &gdef,
+                                        sizeof(avmb1_getdef))))
+                       return rc;
 
-               card->cardstate = CARD_DETECTED;
                return 0;
        }
        return -EINVAL;
@@ -845,22 +1060,14 @@ int detach_capi_interface(struct capi_interface_user *userp)
 /* -------- 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
+EXPORT_SYMBOL(avmb1_registercard);
+EXPORT_SYMBOL(avmb1_unregistercard);
+EXPORT_SYMBOL(avmb1_resetcard);
+EXPORT_SYMBOL(avmb1_detectcard);
 
 
 /*
@@ -876,11 +1083,6 @@ 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); */
 
@@ -899,15 +1101,7 @@ int avmb1_init(void)
                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);
-       }
+        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
@@ -929,20 +1123,20 @@ void cleanup_module(void)
                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);
-
+       for (i = 0; i < CAPI_MAXCONTR; i++) {
+               if (cards[i].cardstate != CARD_FREE) {
+                       /*
+                        * disable card
+                        */
+                       B1_disable_irq(cards[i].port);
+                       avmb1_resetcard(i+1);
+                       /*
+                        * free kernel resources
+                        */
+                       avmb1_unregistercard(i+1, 1);
+               }
        }
+       schedule(); /* execute queued tasks .... */
        printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev);
 }
 #endif
index 64292ef2189e0311382e0204c793c1b4089eb096..1c4c0b80671ed3f2c372a250b7fecd698834aea8 100644 (file)
@@ -1,11 +1,35 @@
 /*
- * $Id: b1lli.c,v 1.1 1997/03/04 21:50:28 calle Exp $
+ * $Id: b1lli.c,v 1.6 1998/02/13 07:09:11 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.6  1998/02/13 07:09:11  calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.5  1998/01/31 11:14:41  calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.4  1997/12/10 20:00:48  calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.1.2.2  1997/11/26 10:46:55  calle
+ * prepared for M1 (Mobile) and T1 (PMX) cards.
+ * prepared to set configuration after load to support other D-channel
+ * protocols, point-to-point and leased lines.
+ *
+ * Revision 1.3  1997/10/01 09:21:13  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.2  1997/07/13 12:22:42  calle
+ * bug fix for more than one controller in connect_req.
+ * debugoutput now with contrnr.
+ *
+ *
  * Revision 1.1  1997/03/04 21:50:28  calle
  * Frirst version in isdn4linux
  *
@@ -66,6 +90,9 @@
                                           * B3Length data .... 
                                         */
 
+#define SEND_CONFIG            0x21    /*
+                                         */
+
 /*
  * LLI Messages from the ISDN-ControllerISDN Controller 
  */
                                           * int32 AppllID int32 0xffffffff 
                                         */
 
+#define WRITE_REGISTER         0x00
+#define READ_REGISTER          0x01
+
 /*
  * port offsets
  */
 #define B1_OUTSTAT             0x03
 #define B1_RESET               0x10
 #define B1_ANALYSE             0x04
+#define B1_IDENT               0x17  /* Hema card T1 */
+#define B1_IRQ_MASTER          0x12  /* Hema card T1 */
 
+#define B1_STAT0(cardtype)  ((cardtype) == AVM_CARDTYPE_M1 ? 0x81200000l : 0x80A00000l)
+#define B1_STAT1(cardtype)  (0x80E00000l)
 
 
 static inline unsigned char b1outp(unsigned short base,
@@ -131,6 +165,100 @@ static inline unsigned char b1outp(unsigned short base,
        return inb(base + B1_ANALYSE);
 }
 
+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++);
+}
+
+static void b1_wr_reg(unsigned short base,
+                      unsigned int reg,
+                     unsigned int value)
+{
+       B1_put_byte(base, WRITE_REGISTER);
+        B1_put_word(base, reg);
+        B1_put_word(base, value);
+}
+
+static inline unsigned int b1_rd_reg(unsigned short base,
+                                     unsigned int reg)
+{
+       B1_put_byte(base, READ_REGISTER);
+        B1_put_word(base, reg);
+        return B1_get_word(base);
+       
+}
+
+static inline void b1_set_test_bit(unsigned short base,
+                                  int cardtype,
+                                  int onoff)
+{
+    b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
+}
+
+static inline int b1_get_test_bit(unsigned short base,
+                                  int cardtype)
+{
+    return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
+}
+
 static int irq_table[16] =
 {0,
  0,
@@ -150,14 +278,30 @@ static int irq_table[16] =
  112,                          /* irq 15 */
 };
 
-int B1_valid_irq(unsigned irq)
+int B1_valid_irq(unsigned irq, int cardtype)
 {
-       return irq_table[irq] != 0;
+       switch (cardtype) {
+          default:
+          case AVM_CARDTYPE_M1:
+          case AVM_CARDTYPE_M2:
+          case AVM_CARDTYPE_B1:
+               return irq_table[irq] != 0;
+          case AVM_CARDTYPE_T1:
+               return irq == 5;
+       }
 }
 
-unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype)
 {
-       return b1outp(base, B1_RESET, irq_table[irq]);
+       switch (cardtype) {
+          case AVM_CARDTYPE_T1:
+             return b1outp(base, B1_IRQ_MASTER, 0x08);
+          default:
+          case AVM_CARDTYPE_M1:
+          case AVM_CARDTYPE_M2:
+          case AVM_CARDTYPE_B1:
+             return b1outp(base, B1_RESET, irq_table[irq]);
+        }
 }
 
 unsigned char B1_enable_irq(unsigned short base)
@@ -182,24 +326,27 @@ void B1_reset(unsigned short base)
        udelay(55 * 2 * 1000);  /* 2 TIC's */
 }
 
-int B1_detect(unsigned short base)
+int B1_detect(unsigned short base, int cardtype)
 {
+       int onoff, i;
+
+       if (cardtype == AVM_CARDTYPE_T1)
+          return 0;
+
        /*
         * 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);
+       /* b1outp(base, B1_OUTSTAT, 0x2); */
        if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
-           || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2)
+           /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
                return 2;
-
        /*
         * Statusregister 0000 000x 
         */
@@ -208,72 +355,23 @@ int B1_detect(unsigned short base)
        if ((inb(base + B1_INSTAT) & 0xfe)
            || (inb(base + B1_OUTSTAT) & 0xfe))
                return 3;
+        
+       for (onoff = !0, i= 0; i < 10 ; i++) {
+               b1_set_test_bit(base, cardtype, onoff);
+               if (b1_get_test_bit(base, cardtype) != onoff)
+                  return 4;
+               onoff = !onoff;
+       }
 
-       return 0;
-}
+       if (cardtype == AVM_CARDTYPE_M1)
+          return 0;
 
-static inline int B1_rx_full(unsigned short base)
-{
-       return inb(base + B1_INSTAT) & 0x1;
-}
+        if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
+          return 5;
 
-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;
 
@@ -316,6 +414,62 @@ int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
        return 0;
 }
 
+int B1_load_config(unsigned short base, avmb1_t4file * config)
+{
+       /*
+        * Data is in user space !!!
+        */
+       unsigned char buf[256];
+       unsigned char *dp;
+       int i, j, left, retval;
+
+
+       dp = config->data;
+       left = config->len;
+       if (left) {
+               B1_put_byte(base, SEND_CONFIG);
+               B1_put_word(base, 1);
+               B1_put_byte(base, SEND_CONFIG);
+               B1_put_word(base, left);
+       }
+       while (left > sizeof(buf)) {
+               retval = copy_from_user(buf, dp, sizeof(buf));
+               if (retval)
+                       return -EFAULT;
+               if (loaddebug)
+                       printk(KERN_DEBUG "b1capi: conf load: %d bytes ..", sizeof(buf));
+               for (i = 0; i < sizeof(buf); ) {
+                       B1_put_byte(base, SEND_CONFIG);
+                       for (j=0; j < 4; j++) {
+                               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: conf load: %d bytes ..", left);
+               for (i = 0; i < left; ) {
+                       B1_put_byte(base, SEND_CONFIG);
+                       for (j=0; j < 4; j++) {
+                               if (i < left)
+                                       B1_put_byte(base, buf[i++]);
+                               else
+                                       B1_put_byte(base, 0);
+                       }
+               }
+               if (loaddebug)
+                  printk("ok\n");
+       }
+       return 0;
+}
+
 int B1_loaded(unsigned short base)
 {
        int i;
@@ -428,7 +582,9 @@ void B1_send_message(unsigned short port, struct sk_buff *skb)
                                       CAPIMSG_APPID(skb->data),
                                       capi_cmd2str(cmd, subcmd), len);
                        } else {
-                               printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+                               printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n",
+                                               (unsigned long) contr,
+                                               capi_message2str(skb->data));
                        }
 
                }
@@ -447,7 +603,7 @@ void B1_send_message(unsigned short port, struct sk_buff *skb)
                                       CAPIMSG_APPID(skb->data),
                                       capi_cmd2str(cmd, subcmd), len);
                        } else {
-                               printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+                               printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n", (unsigned long)contr, capi_message2str(skb->data));
                        }
                }
                save_flags(flags);
@@ -499,13 +655,12 @@ void B1_handle_interrupt(avmb1_card * card)
                                       capi_cmd2str(cmd, subcmd),
                                       MsgLen, DataB3Len);
                        } else {
-                               printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+                               printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n", (unsigned long)contr, 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);
@@ -528,14 +683,15 @@ void B1_handle_interrupt(avmb1_card * card)
                                       capi_cmd2str(cmd, subcmd),
                                       MsgLen);
                        } else {
-                               printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+                               printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n",
+                                               (unsigned long) contr,
+                                               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);
                }
@@ -581,10 +737,9 @@ void B1_handle_interrupt(avmb1_card * card)
                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",
+               printk(KERN_INFO "b1lli: %s-card (%s) now active\n",
                       card->version[VER_CARDTYPE],
-                      card->version[VER_DRIVER],
-                      card->version[VER_PROTO]);
+                      card->version[VER_DRIVER]);
                avmb1_card_ready(card);
                break;
        default:
index af7b58407795f068684409382f4705833b51b3fb..5a31d7992bf896e22eb21961f815be32b29e257b 100644 (file)
@@ -1,11 +1,22 @@
 /*
- * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $
+ * $Id: b1pci.c,v 1.5 1998/01/31 11:14:43 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.5  1998/01/31 11:14:43  calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.4  1997/12/10 20:00:50  calle
+ * get changes from 2.0 version
+ *
+ * Revision 1.3  1997/10/01 09:21:14  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.2  1997/05/18 09:24:13  calle
  * added verbose disconnect reason reporting to avmb1.
  * some fixes in capi20 interface.
@@ -19,7 +30,6 @@
 #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"
 #define PCI_DEVICE_ID_AVM_B1   0x700
 #endif
 
-static char *revision = "$Revision: 1.2 $";
+static char *revision = "$Revision: 1.5 $";
 
 /* ------------------------------------------------------------- */
 
-#ifdef HAS_NEW_SYMTAB
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-#endif
 
 /* ------------------------------------------------------------- */
 
@@ -61,7 +69,7 @@ int b1pci_init(void)
        char *p;
        char rev[10];
        int rc;
-       int pci_index;
+       struct pci_dev *dev = NULL;
 
        if ((p = strchr(revision, ':'))) {
                strcpy(rev, p + 1);
@@ -72,39 +80,26 @@ int b1pci_init(void)
 
 
 #ifdef CONFIG_PCI
-       if (!pcibios_present()) {
-               printk(KERN_ERR "b1pci: no PCI-BIOS present\n");
+       if (!pci_present()) {
+               printk(KERN_ERR "b1pci: no PCI bus 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;
+       while (dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev)) {
+               unsigned int ioaddr = dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+               unsigned int irq = dev->irq;
                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) {
+               if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1)) != 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)
+               if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1)) < 0)
                        return rc;
        }
        return 0;
index 14a5e7d0f052ac6130c7e8ddb7a8a80e58c90603..67c39c675de38237883941b1a2c5c55cfbddfc29 100644 (file)
@@ -1,11 +1,34 @@
 /*
- * $Id: capi.c,v 1.4 1997/05/27 15:17:50 fritz Exp $
+ * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.10  1998/02/13 07:09:13  calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.9  1998/01/31 11:14:44  calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8  1997/11/04 06:12:08  calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.7  1997/10/11 10:29:34  calle
+ * llseek() parameters changed in 2.1.56.
+ *
+ * Revision 1.6  1997/10/01 09:21:15  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.5  1997/08/21 23:11:55  fritz
+ * Added changes for kernels >= 2.1.45
+ *
  * Revision 1.4  1997/05/27 15:17:50  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/skbuff.h>
+#include <linux/poll.h>
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
-#include <linux/poll.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 ---------------------------------------- */
 
@@ -94,21 +113,25 @@ static void capi_signal(__u16 applid, __u32 minor)
 
 /* -------- file_operations ----------------------------------------- */
 
-static loff_t capi_llseek(struct file *file, loff_t offset, int origin)
+static long long capi_llseek(struct file *file,
+                            long long offset, int origin)
 {
        return -ESPIPE;
 }
 
-static ssize_t capi_read(struct file *file,
-                     char *buf, size_t count,
-                     loff_t *off)
+static ssize_t capi_read(struct file *file, char *buf,
+                     size_t count, loff_t *ppos)
 {
-       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+        struct inode *inode = file->f_dentry->d_inode;
+       unsigned int minor = MINOR(inode->i_rdev);
        struct capidev *cdev;
        struct sk_buff *skb;
        int retval;
        size_t copied;
 
+       if (ppos != &file->f_pos)
+               return -ESPIPE;
+
        if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
                return -ENODEV;
 
@@ -149,11 +172,11 @@ static ssize_t capi_read(struct file *file,
        return copied;
 }
 
-static ssize_t capi_write(struct file *file,
-                      const char *buf, size_t count,
-                      loff_t *off)
+static ssize_t capi_write(struct file *file, const char *buf,
+                      size_t count, loff_t *ppos)
 {
-       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+        struct inode *inode = file->f_dentry->d_inode;
+       unsigned int minor = MINOR(inode->i_rdev);
        struct capidev *cdev;
        struct sk_buff *skb;
        int retval;
@@ -161,6 +184,9 @@ static ssize_t capi_write(struct file *file,
        __u8 subcmd;
        __u16 mlen;
 
+       if (ppos != &file->f_pos)
+               return -ESPIPE;
+
        if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
                return -ENODEV;
 
@@ -200,7 +226,11 @@ static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
        unsigned int mask = 0;
+#if (LINUX_VERSION_CODE >= 0x02012d)
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+#else
+       unsigned int minor = MINOR(file->f_inode->i_rdev);
+#endif
        struct capidev *cdev;
 
        if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
@@ -394,7 +424,7 @@ static int capi_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-static CLOSETYPE
+static int
 capi_release(struct inode *inode, struct file *file)
 {
        unsigned int minor = MINOR(inode->i_rdev);
@@ -403,7 +433,7 @@ capi_release(struct inode *inode, struct file *file)
 
        if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
                printk(KERN_ERR "capi20: release minor %d ???\n", minor);
-               return CLOSEVAL;
+               return 0;
        }
        cdev = &capidevs[minor];
 
@@ -421,7 +451,7 @@ capi_release(struct inode *inode, struct file *file)
        cdev->is_open = 0;
 
        MOD_DEC_USE_COUNT;
-       return CLOSEVAL;
+       return 0;
 }
 
 static struct file_operations capi_fops =
index c1dfcdafe1a3d6a4eea1cca0e235afa93d1961b6..1d4a7c2e863cb15092c387869a4cdb2e339708e6 100644 (file)
@@ -1,11 +1,42 @@
 /*
- * $Id: capidrv.c,v 1.3 1997/05/18 09:24:15 calle Exp $
+ * $Id: capidrv.c,v 1.11 1998/02/13 07:09: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.11  1998/02/13 07:09:15  calle
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.10  1998/02/02 19:52:23  calle
+ * Fixed vbox (audio) acceptb.
+ *
+ * Revision 1.9  1998/01/31 11:14:45  calle
+ * merged changes to 2.0 tree, prepare 2.1.82 to work.
+ *
+ * Revision 1.8  1997/11/04 06:12:09  calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.7  1997/10/11 10:36:34  calle
+ * Added isdnlog support. patch to isdnlog needed.
+ *
+ * Revision 1.6  1997/10/11 10:25:55  calle
+ * New interface for lowlevel drivers. BSENT with nr. of bytes sent,
+ * allow sending without ACK.
+ *
+ * Revision 1.5  1997/10/01 09:21:16  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4  1997/07/13 12:22:43  calle
+ * bug fix for more than one controller in connect_req.
+ * debugoutput now with contrnr.
+ *
  * Revision 1.3  1997/05/18 09:24:15  calle
  * added verbose disconnect reason reporting to avmb1.
  * some fixes in capi20 interface.
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.11 $";
 int debugmode = 0;
 
-#ifdef HAS_NEW_SYMTAB
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 MODULE_PARM(debugmode, "i");
-#endif
 
 /* -------- type definitions ----------------------------------------- */
 
@@ -116,14 +145,26 @@ struct capidrv_contr {
                                int oldstate;
                                /* */
                                __u16 datahandle;
+                               struct ncci_datahandle_queue {
+                                   struct ncci_datahandle_queue *next;
+                                   __u16                         datahandle;
+                                   int                           len;
+                               } *ackqueue;
                        } *ncci_list;
                } *plcip;
                struct capidrv_ncci *nccip;
        } *bchans;
 
        struct capidrv_plci *plci_list;
+
+       /* for q931 data */
+       __u8  q931_buf[4096];
+       __u8 *q931_read;
+       __u8 *q931_write;
+       __u8 *q931_end;
 };
 
+
 struct capidrv_data {
        __u16 appid;
        int ncontr;
@@ -141,6 +182,9 @@ typedef struct capidrv_bchan capidrv_bchan;
 static capidrv_data global;
 static struct capi_interface *capifuncs;
 
+static void handle_dtrace_data(capidrv_contr *card,
+       int send, int level2, __u8 *data, __u16 len);
+
 /* -------- convert functions ---------------------------------------- */
 
 static inline __u32 b1prot(int l2, int l3)
@@ -167,9 +211,8 @@ static inline __u32 b2prot(int l2, int l3)
        default:
                return 0;
        case ISDN_PROTO_L2_HDLC:
-               return 1;
        case ISDN_PROTO_L2_TRANS:
-               return 0;
+               return 1;
        }
 }
 
@@ -410,6 +453,42 @@ static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
        kfree(nccip);
 }
 
+static int capidrv_add_ack(struct capidrv_ncci *nccip,
+                          __u16 datahandle, int len)
+{
+       struct ncci_datahandle_queue *n, **pp;
+
+       n = (struct ncci_datahandle_queue *)
+               kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
+       if (!n) {
+          printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
+          return -1;
+       }
+       n->next = 0;
+       n->datahandle = datahandle;
+       n->len = len;
+       for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
+       *pp = n;
+       return 0;
+}
+
+static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
+{
+       struct ncci_datahandle_queue **pp, *p;
+       int len;
+
+       for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
+               if ((*pp)->datahandle == datahandle) {
+                       p = *pp;
+                       len = p->len;
+                       *pp = (*pp)->next;
+                       kfree(p);
+                       return len;
+               }
+       }
+       return -1;
+}
+
 /* -------- convert and send capi message ---------------------------- */
 
 static void send_message(capidrv_contr * card, _cmsg * cmsg)
@@ -419,7 +498,6 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg)
        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);
 }
@@ -686,8 +764,53 @@ static void handle_controller(_cmsg * cmsg)
                break;
 
        case CAPI_MANUFACTURER_IND:     /* Controller */
+               if (   cmsg->ManuID == 0x214D5641
+                   && cmsg->Class == 0
+                   && cmsg->Function == 1) {
+                  __u8  *data = cmsg->ManuData+3;
+                  __u16  len = cmsg->ManuData[0];
+                  __u16 layer;
+                  int direction;
+                  if (len == 255) {
+                     len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
+                     data += 2;
+                  }
+                  len -= 2;
+                  layer = ((*(data-1)) << 8) | *(data-2);
+                  if (layer & 0x300)
+                       direction = (layer & 0x200) ? 0 : 1;
+                  else direction = (layer & 0x800) ? 0 : 1;
+                  if (layer & 0x0C00) {
+                       if ((layer & 0xff) == 0x80) {
+                          handle_dtrace_data(card, direction, 1, data, len);
+                          break;
+                       }
+                  } else if ((layer & 0xff) < 0x80) {
+                     handle_dtrace_data(card, direction, 0, data, len);
+                     break;
+                  }
+                  printk(KERN_INFO "capidrv: %s from controller 0x%x layer 0x%x, ignored\n",
+                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+                       cmsg->adr.adrController, layer);
+                   break;
+               }
                goto ignored;
        case CAPI_MANUFACTURER_CONF:    /* Controller */
+               if (cmsg->ManuID == 0x214D5641) {
+                  char *s = 0;
+                  switch (cmsg->Class) {
+                     case 0: break;
+                     case 1: s = "unknown class"; break;
+                     case 2: s = "unknown function"; break;
+                     default: s = "unkown error"; break;
+                  }
+                  if (s)
+                  printk(KERN_INFO "capidrv: %s from controller 0x%x function %d: %s\n",
+                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+                       cmsg->adr.adrController,
+                       cmsg->Function, s);
+                  break;
+               }
                goto ignored;
        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
                goto ignored;
@@ -996,6 +1119,7 @@ static void handle_ncci(_cmsg * cmsg)
        capidrv_plci *plcip;
        capidrv_ncci *nccip;
        isdn_ctrl cmd;
+       int len;
 
        if (!card) {
                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
@@ -1093,11 +1217,14 @@ static void handle_ncci(_cmsg * cmsg)
                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);
-
+               len = capidrv_del_ack(nccip, cmsg->DataHandle);
+               if (len < 0)
+                       break;
+               cmd.command = ISDN_STAT_BSENT;
+               cmd.driver = card->myid;
+               cmd.arg = nccip->chan;
+               cmd.parm.length = len;
+               card->interface.statcallb(&cmd);
                break;
 
        case CAPI_DISCONNECT_B3_IND:    /* ncci */
@@ -1206,6 +1333,60 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
 
 /* ------------------------------------------------------------------- */
 
+#define PUTBYTE_TO_STATUS(card, byte) \
+       do { \
+               *(card)->q931_write++ = (byte); \
+               if ((card)->q931_write > (card)->q931_end) \
+                       (card)->q931_write = (card)->q931_buf; \
+       } while (0)
+
+static void handle_dtrace_data(capidrv_contr *card,
+                            int send, int level2, __u8 *data, __u16 len)
+{
+    long flags;
+    __u8 *p, *end;
+    isdn_ctrl cmd;
+
+    if (!len) {
+       printk(KERN_DEBUG "avmb1_q931_data: len == %d\n", len);
+       return;
+    }
+
+    save_flags(flags);
+    cli();
+
+    if (level2) {
+        PUTBYTE_TO_STATUS(card, 'D');
+        PUTBYTE_TO_STATUS(card, '2');
+        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        PUTBYTE_TO_STATUS(card, ':');
+    } else {
+        PUTBYTE_TO_STATUS(card, 'D');
+        PUTBYTE_TO_STATUS(card, '3');
+        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        PUTBYTE_TO_STATUS(card, ':');
+    }
+
+    for (p = data, end = data+len; p < end; p++) {
+       __u8 w;
+       PUTBYTE_TO_STATUS(card, ' ');
+       w = (*p >> 4) & 0xf;
+       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+       w = *p & 0xf;
+       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+    }
+    PUTBYTE_TO_STATUS(card, '\n');
+
+    restore_flags(flags);
+    
+    cmd.command = ISDN_STAT_STAVAIL;
+    cmd.driver = card->myid;
+    cmd.arg = len*3+5;
+    card->interface.statcallb(&cmd);
+}
+
+/* ------------------------------------------------------------------- */
+
 static _cmsg cmdcmsg;
 
 static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
@@ -1270,7 +1451,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
                        capi_fill_CONNECT_REQ(&cmdcmsg,
                                              global.appid,
                                              card->msgid++,
-                                             1,        /* adr */
+                                             card->contrnr,    /* adr */
                                          si2cip(bchan->si1, bchan->si2),       /* cipvalue */
                                              called,   /* CalledPartyNumber */
                                              calling,  /* CallingPartyNumber */
@@ -1471,7 +1652,7 @@ static int if_command(isdn_ctrl * c)
 
 static _cmsg sendcmsg;
 
-static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
 {
        capidrv_contr *card = findcontrbydriverid(id);
        capidrv_bchan *bchan;
@@ -1479,6 +1660,7 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
        int len = skb->len;
        size_t msglen;
        __u16 errcode;
+       __u16 datahandle;
 
        if (!card) {
                printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
@@ -1492,51 +1674,128 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
                       card->name, channel);
                return 0;
        }
+       datahandle = nccip->datahandle;
        capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
                              nccip->ncci,      /* adr */
                              (__u32) skb->data,        /* Data */
                              skb->len,         /* DataLength */
-                             nccip->datahandle++,      /* DataHandle */
+                             datahandle,       /* DataHandle */
                              0 /* Flags */
            );
+
+       if (capidrv_add_ack(nccip, datahandle, doack ? skb->len : -1) < 0)
+          return 0;
+
        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");
+                       (void)capidrv_del_ack(nccip, datahandle);
                        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:
+               if (errcode == CAPI_NOERROR) {
                        dev_kfree_skb(skb);
+                       nccip->datahandle++;
                        return len;
-               case CAPI_SENDQUEUEFULL:
-                       dev_kfree_skb(nskb);
-                       return 0;
-               default:
-                       return -1;
                }
+               (void)capidrv_del_ack(nccip, datahandle);
+               dev_kfree_skb(nskb);
+               return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
        } else {
                memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
                errcode = (*capifuncs->capi_put_message) (global.appid, skb);
-               switch (errcode) {
-               case CAPI_NOERROR:
+               if (errcode == CAPI_NOERROR) {
+                       nccip->datahandle++;
                        return len;
-               case CAPI_SENDQUEUEFULL:
-                       return 0;
-               default:
-                       return -1;
                }
+               (void)capidrv_del_ack(nccip, datahandle);
+               return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
+       }
+}
+
+static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
+{
+       capidrv_contr *card = findcontrbydriverid(id);
+       int count;
+       __u8 *p;
+
+       if (!card) {
+               printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
+                      id);
+               return -ENODEV;
+       }
+
+       for (p=buf, count=0; count < len; p++, count++) {
+               if (user)
+                       put_user(*card->q931_read++, p);
+               else
+                       *p = *card->q931_read++;
+               if (card->q931_read > card->q931_end)
+                       card->q931_read = card->q931_buf;
+       }
+       return count;
+
+}
+
+static void enable_dchannel_trace(capidrv_contr *card)
+{
+        __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+        capi_version version;
+       __u16 contr = card->contrnr;
+       __u16 errcode;
+       __u16 avmversion[3];
+
+        errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
+        if (errcode != CAPI_NOERROR) {
+          printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
+                       card->name, errcode);
+          return;
+       }
+       if (strstr(manufacturer, "AVM") == 0) {
+          printk(KERN_ERR "%s: not from AVM, no d-channel trace possible\n",
+                       card->name);
+          return;
+       }
+        errcode = (*capifuncs->capi_get_version)(contr, &version);
+        if (errcode != CAPI_NOERROR) {
+          printk(KERN_ERR "%s: can't get version (0x%x)\n",
+                       card->name, errcode);
+          return;
+       }
+       avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
+       avmversion[1] = (version.majormanuversion << 4) & 0xf0;
+       avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
+       avmversion[2] |= version.minormanuversion & 0x0f;
+
+        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
+               printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
+               capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
+                                          card->msgid++,
+                                          contr,
+                                          0x214D5641,  /* ManuID */
+                                          0,           /* Class */
+                                          1,           /* Function */
+                                          (_cstruct)"\004\200\014\000\000");
+       } else {
+               printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
+               capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
+                                          card->msgid++,
+                                          contr,
+                                          0x214D5641,  /* ManuID */
+                                          0,           /* Class */
+                                          1,           /* Function */
+                                          (_cstruct)"\004\002\003\000\000");
        }
+       send_message(card, &cmdcmsg);
 }
 
 static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
@@ -1568,7 +1827,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        card->interface.command = if_command;
        card->interface.writebuf_skb = if_sendbuf;
        card->interface.writecmd = 0;
-       card->interface.readstat = 0;
+       card->interface.readstat = if_readstat;
        card->interface.features = ISDN_FEATURE_L2_X75I |
            ISDN_FEATURE_L2_X75UI |
            ISDN_FEATURE_L2_X75BUI |
@@ -1581,6 +1840,9 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        card->next = global.contr_list;
        global.contr_list = card;
        global.ncontr++;
+       card->q931_read = card->q931_buf;
+       card->q931_write = card->q931_buf;
+       card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
 
        if (!register_isdn(&card->interface)) {
                global.contr_list = global.contr_list->next;
@@ -1600,7 +1862,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        cmd.command = ISDN_STAT_RUN;
        card->interface.statcallb(&cmd);
 
-       card->cipmask = 1;      /* any */
+       card->cipmask = 0x1FFF03FF;     /* any */
        card->cipmask2 = 0;
 
        capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
@@ -1616,6 +1878,8 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        printk(KERN_INFO "%s: now up (%d B channels)\n",
                card->name, card->nbchan);
 
+        enable_dchannel_trace(card);
+
        return 0;
 }
 
@@ -1694,11 +1958,6 @@ int capidrv_init(void)
        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, '$');
index 9eb60afed999a94450d5d2cd471e9a42cfa2ef76..8eb7d3ae15d9bef859cf6755b175973eae6b3eb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: capiutil.c,v 1.3 1997/05/18 09:24:18 calle Exp $
+ * $Id: capiutil.c,v 1.6 1997/11/04 06:12:12 calle Exp $
  *
  * CAPI 2.0 convert capi message to capi message struct
  *
@@ -7,6 +7,20 @@
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capiutil.c,v $
+ * Revision 1.6  1997/11/04 06:12:12  calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.5  1997/10/01 09:21:19  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4  1997/08/10 07:43:55  calle
+ * forgot to export symbol capi_info2str for 2.1.x
+ *
  * Revision 1.3  1997/05/18 09:24:18  calle
  * added verbose disconnect reason reporting to avmb1.
  * some fixes in capi20 interface.
  *
  */
 #include <linux/module.h>
-#include <linux/config.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 <linux/config.h>
 
 #include "compat.h"
 #include "capiutil.h"
@@ -936,35 +950,18 @@ char *capi_cmsg2str(_cmsg * cmsg)
 }
 
 
-#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
+EXPORT_SYMBOL(capi_info2str);
 
 #ifdef MODULE
 
 int init_module(void)
 {
-#ifndef HAS_NEW_SYMTAB
-       register_symtab(&capifunc_syms);
-#endif
        return 0;
 }
 
index 551b20d604e17929887cb68ada2c7e103869585f..41ad2b6263123c0dc29789c9cbacb4d2283f744f 100644 (file)
@@ -1,11 +1,22 @@
 /*
- * $Id: compat.h,v 1.1 1997/03/04 21:50:36 calle Exp $
+ * $Id: compat.h,v 1.3 1997/11/04 06:12:15 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.3  1997/11/04 06:12:15  calle
+ * capi.c: new read/write in file_ops since 2.1.60
+ * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
+ * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
+ * compat.h: added #define LinuxVersionCode
+ *
+ * Revision 1.2  1997/10/01 09:21:22  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.1  1997/03/04 21:50:36  calle
  * Frirst version in isdn4linux
  *
@@ -23,8 +34,8 @@
 #include <linux/version.h>
 #include <linux/isdnif.h>
 
-#if LINUX_VERSION_CODE >= 0x020112     /* 2.1.18 */
-#define HAS_NEW_SYMTAB
+#ifndef LinuxVersionCode
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #endif
 
 #endif                         /* __COMPAT_H__ */
index 2cc325b1f24636a092d4ac2210402f170db2213b..a8e1f83effa58285df1e58ac8c0308ed8e6dec05 100644 (file)
@@ -1,7 +1,14 @@
 L_OBJS :=
 M_OBJS :=
-O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \
-          q931.o callc.o fsm.o
+LX_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \
+          lmgr.o q931.o callc.o fsm.o
 
 # EXTRA_CFLAGS += -S
 
@@ -17,31 +24,105 @@ ifeq ($(CONFIG_HISAX_1TR6),y)
         O_OBJS += l3_1tr6.o
 endif
 
+ISAC_OBJ :=
+ARCOFI_OBJ :=
+HSCX_OBJ :=
+HFC_OBJ :=
+HFC_2BDS0 :=
+RAWHDLC_OBJ :=
+
 ifeq ($(CONFIG_HISAX_16_0),y)
         O_OBJS += teles0.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
 endif
 
 ifeq ($(CONFIG_HISAX_16_3),y)
         O_OBJS += teles3.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
 endif
 
 ifeq ($(CONFIG_HISAX_AVM_A1),y)
         O_OBJS += avm_a1.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
 endif
 
-ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
-        O_OBJS += elsa.o
-endif
-
-ifeq ($(CONFIG_HISAX_ELSA_PCMCIA),y)
+ifeq ($(CONFIG_HISAX_ELSA),y)
         O_OBJS += elsa.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+        ARCOFI_OBJ := arcofi.o
 endif
 
 ifeq ($(CONFIG_HISAX_IX1MICROR2),y)
         O_OBJS += ix1_micro.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_DIEHLDIVA),y)
+        O_OBJS += diva.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_ASUSCOM),y)
+        O_OBJS += asuscom.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_TELEINT),y)
+        O_OBJS += teleint.o
+        ISAC_OBJ := isac.o
+        HFC_OBJ := hfc_2bs0.o
+endif
+
+ifeq ($(CONFIG_HISAX_SEDLBAUER),y)
+        O_OBJS += sedlbauer.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
 endif
 
+ifeq ($(CONFIG_HISAX_SPORTSTER),y)
+        O_OBJS += sportster.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_MIC),y)
+        O_OBJS += mic.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+ifeq ($(CONFIG_HISAX_NETJET),y)
+        O_OBJS += netjet.o
+        ISAC_OBJ := isac.o
+endif
+
+ifeq ($(CONFIG_HISAX_TELES3C),y)
+        O_OBJS += teles3c.o
+        HFC_2BDS0 := hfc_2bds0.o
+endif
+ifeq ($(CONFIG_HISAX_AMD7930),y)
+        O_OBJS += amd7930.o
+        RAWHDLC_OBJ := rawhdlc.o
+endif
+
+ifeq ($(CONFIG_HISAX_NICCY),y)
+        O_OBJS += niccy.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(ARCOFI_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ)
+OX_OBJS += config.o
+
 O_TARGET :=
+
 ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
   O_TARGET += hisax.o
 else
diff --git a/drivers/isdn/hisax/amd7930.c b/drivers/isdn/hisax/amd7930.c
new file mode 100644 (file)
index 0000000..2025999
--- /dev/null
@@ -0,0 +1,768 @@
+/* $Id: amd7930.c,v 1.2 1998/02/12 23:07:10 keil Exp $
+ *
+ * HiSax ISDN driver - chip specific routines for AMD 7930
+ *
+ * Author       Brent Baccala (baccala@FreeSoft.org)
+ *
+ *
+ *
+ * $Log: amd7930.c,v $
+ * Revision 1.2  1998/02/12 23:07:10  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.1  1998/02/03 23:20:51  keil
+ * New files for SPARC isdn support
+ *
+ * Revision 1.1  1998/01/08 04:17:12  baccala
+ * ISDN comes to the Sparc.  Key points:
+ *
+ *    - Existing ISDN HiSax driver provides all the smarts
+ *    - it compiles, runs, talks to an isolated phone switch, connects
+ *      to a Cisco, pings go through
+ *    - AMD 7930 support only (no DBRI yet)
+ *    - no US NI-1 support (may not work on US phone system - untested)
+ *    - periodic packet loss, apparently due to lost interrupts
+ *    - ISDN sometimes freezes, requiring reboot before it will work again
+ *
+ * The code is unreliable enough to be consider alpha
+ *
+ *
+ * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
+ * SparcStation 1+.  The chip provides microphone and speaker interfaces
+ * which provide mono-channel audio at 8K samples per second via either
+ * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
+ * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
+ * which performs basic D channel LAPD processing and provides raw
+ * B channel data.  The digital audio channel, the two ISDN B channels,
+ * and two 64 Kbps channels to the microprocessor are all interconnected
+ * via a multiplexer.
+ *
+ * This driver interfaces to the Linux HiSax ISDN driver, which performs
+ * all high-level Q.921 and Q.931 ISDN functions.  The file is not
+ * itself a hardware driver; rather it uses functions exported by
+ * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
+ * allowing the chip to be simultaneously used for both audio and ISDN data.
+ * The hardware driver does _no_ buffering, but provides several callbacks
+ * which are called during interrupt service and should therefore run quickly.
+ *
+ * D channel transmission is performed by passing the hardware driver the
+ * address and size of an skb's data area, then waiting for a callback
+ * to signal successful transmission of the packet.  A task is then
+ * queued to notify the HiSax driver that another packet may be transmitted.
+ *
+ * D channel reception is quite simple, mainly because of:
+ *   1) the slow speed of the D channel - 16 kbps, and
+ *   2) the presence of an 8- or 32-byte (depending on chip version) FIFO
+ *      to buffer the D channel data on the chip
+ * Worst case scenario of back-to-back packets with the 8 byte buffer
+ * at 16 kbps yields an service time of 4 ms - long enough to preclude
+ * the need for fancy buffering.  We queue a background task that copies
+ * data out of the receive buffer into an skb, and the hardware driver
+ * simply does nothing until we're done with the receive buffer and
+ * reset it for a new packet.
+ *
+ * B channel processing is more complex, because of:
+ *   1) the faster speed - 64 kbps,
+ *   2) the lack of any on-chip buffering (it interrupts for every byte), and
+ *   3) the lack of any chip support for HDLC encapsulation
+ *
+ * The HiSax driver can put each B channel into one of three modes -
+ * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
+ * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
+ * L1_MODE_HDLC is the most common, used for almost all "pure" digital
+ * data sessions.  L1_MODE_TRANS is used for ISDN audio.
+ *
+ * HDLC B channel transmission is performed via a large buffer into
+ * which the skb is copied while performing HDLC bit-stuffing.  A CRC
+ * is computed and attached to the end of the buffer, which is then
+ * passed to the low-level routines for raw transmission.  Once
+ * transmission is complete, the hardware driver is set to enter HDLC
+ * idle by successive transmission of mark (all 1) bytes, waiting for
+ * the ISDN driver to prepare another packet for transmission and
+ * deliver it.
+ *
+ * HDLC B channel reception is performed via an X-byte ring buffer
+ * divided into N sections of X/N bytes each.  Defaults: X=256 bytes, N=4.
+ * As the hardware driver notifies us that each section is full, we
+ * hand it the next section and schedule a background task to peruse
+ * the received section, bit-by-bit, with an HDLC decoder.  As
+ * packets are detected, they are copied into a large buffer while
+ * decoding HDLC bit-stuffing.  The ending CRC is verified, and if
+ * it is correct, we alloc a new skb of the correct length (which we
+ * now know), copy the packet into it, and hand it to the upper layers.
+ * Optimization: for large packets, we hand the buffer (which also
+ * happens to be an skb) directly to the upper layer after an skb_trim,
+ * and alloc a new large buffer for future packets, thus avoiding a copy.
+ * Then we return to HDLC processing; state is saved between calls.
+ * 
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "../../sbus/audio/amd7930.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include "rawhdlc.h"
+#include <linux/interrupt.h>
+
+static const char *amd7930_revision = "$Revision: 1.2 $";
+
+#define RCV_BUFSIZE    1024    /* Size of raw receive buffer in bytes */
+#define RCV_BUFBLKS    4       /* Number of blocks to divide buffer into
+                                * (must divide RCV_BUFSIZE) */
+
+static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
+
+static void
+Bchan_xmt_bh(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       if (bcs->hw.amd7930.tx_skb != NULL) {
+               dev_kfree_skb(bcs->hw.amd7930.tx_skb);
+               bcs->hw.amd7930.tx_skb = NULL;
+       }
+
+       if ((skb = skb_dequeue(&bcs->squeue))) {
+               Bchan_fill_fifo(bcs, skb);
+       } else {
+               clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               bcs->event |= 1 << B_XMTBUFREADY;
+               queue_task(&bcs->tqueue, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
+}
+
+static void
+Bchan_xmit_callback(struct BCState *bcs)
+{
+       queue_task(&bcs->hw.amd7930.tq_xmt, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
+ *
+ * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting
+ * the packet (i.e. make_raw_hdlc_data).  Since this can be a
+ * time-consuming operation, our completion callback just schedules
+ * a bottom half to do encapsulation for the next packet.  In between,
+ * the link will just idle
+ *
+ * L1_MODE_TRANS - Data goes through, well, transparent.  No HDLC encap,
+ * and we can't just let the link idle, so the "bottom half" actually
+ * gets called during the top half (it's our callback routine in this case),
+ * but it's a lot faster now since we don't call make_raw_hdlc_data
+ */
+
+static void
+Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int len;
+
+       if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) {
+               char tmp[1024];
+               char *t = tmp;
+
+               t += sprintf(t, "amd7930_fill_fifo %c cnt %d",
+                            bcs->channel ? 'B' : 'A', skb->len);
+               if (cs->debug & L1_DEB_HSCX_FIFO)
+                       QuickHex(t, skb->data, skb->len);
+               debugl1(cs, tmp);
+       }
+
+       if (bcs->mode == L1_MODE_HDLC) {
+               len = make_raw_hdlc_data(skb->data, skb->len,
+                                        bcs->hw.amd7930.tx_buff, RAW_BUFMAX);
+               if (len > 0)
+                       amd7930_bxmit(0, bcs->channel,
+                                     bcs->hw.amd7930.tx_buff, len,
+                                     (void *) &Bchan_xmit_callback,
+                                     (void *) bcs);
+               dev_kfree_skb(skb);
+       } else if (bcs->mode == L1_MODE_TRANS) {
+               amd7930_bxmit(0, bcs->channel,
+                             bcs->hw.amd7930.tx_buff, skb->len,
+                             (void *) &Bchan_xmt_bh,
+                             (void *) bcs);
+               bcs->hw.amd7930.tx_skb = skb;
+       } else {
+               dev_kfree_skb(skb);
+       }
+}
+
+static void
+Bchan_mode(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+
+       if (cs->debug & L1_DEB_HSCX) {
+               char tmp[40];
+               sprintf(tmp, "AMD 7930 mode %d bchan %d/%d",
+                       mode, bc, bcs->channel);
+               debugl1(cs, tmp);
+       }
+       bcs->mode = mode;
+}
+
+/* Bchan_l2l1 is the entry point for upper layer routines that want to
+ * transmit on the B channel.  PH_DATA_REQ is a normal packet that
+ * we either start transmitting (if idle) or queue (if busy).
+ * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF)
+ * once the link is idle.  After a "pull" callback, the upper layer
+ * routines can use PH_PULL_IND to send data.
+ */
+
+static void
+Bchan_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                       } else {
+                               test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                               Bchan_fill_fifo(st->l1.bcs, skb);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+                               printk(KERN_WARNING "amd7930: this shouldn't happen\n");
+                               break;
+                       }
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       Bchan_fill_fifo(st->l1.bcs, skb);
+                       break;
+               case (PH_PULL_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
+                               clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+/* Receiver callback and bottom half - decodes HDLC at leisure (if
+ * L1_MODE_HDLC) and passes newly received skb on via bcs->rqueue.  If
+ * a large packet is received, stick rv_skb (the buffer that the
+ * packet has been decoded into) on the receive queue and alloc a new
+ * (large) skb to act as buffer for future receives.  If a small
+ * packet is received, leave rv_skb alone, alloc a new skb of the
+ * correct size, and copy the packet into it
+ */
+
+static void
+Bchan_recv_callback(struct BCState *bcs)
+{
+       struct amd7930_hw *hw = &bcs->hw.amd7930;
+
+       hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS;
+       hw->rv_buff_in %= RCV_BUFSIZE;
+
+       if (hw->rv_buff_in != hw->rv_buff_out) {
+               amd7930_brecv(0, bcs->channel,
+                             hw->rv_buff + hw->rv_buff_in,
+                             RCV_BUFSIZE/RCV_BUFBLKS,
+                             (void *) &Bchan_recv_callback, (void *) bcs);
+       }
+
+       queue_task(&hw->tq_rcv, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static void
+Bchan_rcv_bh(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       struct amd7930_hw *hw = &bcs->hw.amd7930;
+       struct sk_buff *skb;
+       int len;
+
+       if (cs->debug & L1_DEB_HSCX) {
+               char tmp[1024];
+
+               sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)",
+                       hw->rv_buff_in, hw->rv_buff_out);
+               debugl1(cs, tmp);
+               QuickHex(tmp, hw->rv_buff + hw->rv_buff_out,
+                        RCV_BUFSIZE/RCV_BUFBLKS);
+               debugl1(cs, tmp);
+       }
+
+       do {
+               if (bcs->mode == L1_MODE_HDLC) {
+                       while ((len = read_raw_hdlc_data(hw->hdlc_state,
+                                                        hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS,
+                                                        hw->rv_skb->tail, HSCX_BUFMAX))) {
+                               if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) {
+                                       char tmp[1024];
+                                       char *t = tmp;
+
+                                       t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len);
+                                       QuickHex(t, hw->rv_skb->tail, len);
+                                       debugl1(cs, tmp);
+                               }
+
+                               if (len > HSCX_BUFMAX/2) {
+                                       /* Large packet received */
+
+                                       if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) {
+                                               printk(KERN_WARNING "amd7930: receive out of memory");
+                                       } else {
+                                               skb_put(hw->rv_skb, len);
+                                               skb_queue_tail(&bcs->rqueue, hw->rv_skb);
+                                               hw->rv_skb = skb;
+                                               bcs->event |= 1 << B_RCVBUFREADY;
+                                               queue_task(&bcs->tqueue, &tq_immediate);
+                                       }
+                               } else if (len > 0) {
+                                       /* Small packet received */
+
+                                       if (!(skb = dev_alloc_skb(len))) {
+                                               printk(KERN_WARNING "amd7930: receive out of memory\n");
+                                       } else {
+                                               memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
+                                               skb_queue_tail(&bcs->rqueue, skb);
+                                               bcs->event |= 1 << B_RCVBUFREADY;
+                                               queue_task(&bcs->tqueue, &tq_immediate);
+                                               mark_bh(IMMEDIATE_BH);
+                                       }
+                               } else {
+                                       /* Reception Error */
+                                       /* printk("amd7930: B channel receive error\n"); */
+                               }
+                       }
+               } else if (bcs->mode == L1_MODE_TRANS) {
+                       if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) {
+                               printk(KERN_WARNING "amd7930: receive out of memory\n");
+                       } else {
+                               memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS),
+                                      hw->rv_buff + hw->rv_buff_out,
+                                      RCV_BUFSIZE/RCV_BUFBLKS);
+                               skb_queue_tail(&bcs->rqueue, skb);
+                               bcs->event |= 1 << B_RCVBUFREADY;
+                               queue_task(&bcs->tqueue, &tq_immediate);
+                               mark_bh(IMMEDIATE_BH);
+                       }
+               }
+
+               if (hw->rv_buff_in == hw->rv_buff_out) {
+                       /* Buffer was filled up - need to restart receiver */
+                       amd7930_brecv(0, bcs->channel,
+                                     hw->rv_buff + hw->rv_buff_in,
+                                     RCV_BUFSIZE/RCV_BUFBLKS,
+                                     (void *) &Bchan_recv_callback,
+                                     (void *) bcs);
+               }
+
+               hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS;
+               hw->rv_buff_out %= RCV_BUFSIZE;
+
+       } while (hw->rv_buff_in != hw->rv_buff_out);
+}
+
+static void
+Bchan_close(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       Bchan_mode(bcs, 0, 0);
+       amd7930_bclose(0, bcs->channel);
+
+       if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+       }
+       test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+}
+
+static int
+Bchan_open(struct BCState *bcs)
+{
+       struct amd7930_hw *hw = &bcs->hw.amd7930;
+
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+
+       amd7930_bopen(0, bcs->channel, 0xff);
+       hw->rv_buff_in = 0;
+       hw->rv_buff_out = 0;
+       hw->tx_skb = NULL;
+       init_hdlc_state(hw->hdlc_state, 0);
+       amd7930_brecv(0, bcs->channel,
+                     hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS,
+                     (void *) &Bchan_recv_callback, (void *) bcs);
+
+       bcs->event = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+static void
+Bchan_init(struct BCState *bcs)
+{
+       if (!(bcs->hw.amd7930.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for amd7930.tx_buff\n");
+               return;
+       }
+       if (!(bcs->hw.amd7930.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for amd7930.rv_buff\n");
+               return;
+       }
+       if (!(bcs->hw.amd7930.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for amd7930.rv_skb\n");
+               return;
+       }
+       if (!(bcs->hw.amd7930.hdlc_state = kmalloc(sizeof(struct hdlc_state),
+                                                  GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for amd7930.hdlc_state\n");
+               return;
+       }
+
+       bcs->hw.amd7930.tq_rcv.sync = 0;
+       bcs->hw.amd7930.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh;
+       bcs->hw.amd7930.tq_rcv.data = (void *) bcs;
+
+       bcs->hw.amd7930.tq_xmt.sync = 0;
+       bcs->hw.amd7930.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh;
+       bcs->hw.amd7930.tq_xmt.data = (void *) bcs;
+}
+
+static void
+Bchan_manl1(struct PStack *st, int pr,
+         void *arg)
+{
+       switch (pr) {
+               case (PH_ACTIVATE_REQ):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       break;
+               case (PH_DEACTIVATE_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+                               Bchan_mode(st->l1.bcs, 0, 0);
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       break;
+       }
+}
+
+int
+setstack_amd7930(struct PStack *st, struct BCState *bcs)
+{
+       if (Bchan_open(bcs))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = Bchan_l2l1;
+       st->ma.manl1 = Bchan_manl1;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+
+static void
+amd7930_drecv_callback(void *arg, int error, unsigned int count)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) arg;
+       static struct tq_struct task;
+       struct sk_buff *skb;
+
+        /* NOTE: This function is called directly from an interrupt handler */
+
+       if (1) {
+               if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+                       printk(KERN_WARNING "HiSax: D receive out of memory\n");
+               else {
+                       memcpy(skb_put(skb, count), cs->rcvbuf, count);
+                       skb_queue_tail(&cs->rq, skb);
+               }
+
+               task.routine = (void *) DChannel_proc_rcv;
+               task.data = (void *) cs;
+               queue_task(&task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
+
+       if (cs->debug & L1_DEB_ISAC_FIFO) {
+               char tmp[128];
+               char *t = tmp;
+
+               t += sprintf(t, "amd7930 Drecv cnt %d", count);
+               if (error) t += sprintf(t, " ERR %x", error);
+               QuickHex(t, cs->rcvbuf, count);
+               debugl1(cs, tmp);
+       }
+
+       amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
+                     &amd7930_drecv_callback, cs);
+}
+
+static void
+amd7930_dxmit_callback(void *arg, int error)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) arg;
+       static struct tq_struct task;
+
+        /* NOTE: This function is called directly from an interrupt handler */
+
+       /* may wish to do retransmission here, if error indicates collision */
+
+       if (cs->debug & L1_DEB_ISAC_FIFO) {
+               char tmp[128];
+               char *t = tmp;
+
+               t += sprintf(t, "amd7930 Dxmit cnt %d", cs->tx_skb->len);
+               if (error) t += sprintf(t, " ERR %x", error);
+               QuickHex(t, cs->tx_skb->data, cs->tx_skb->len);
+               debugl1(cs, tmp);
+       }
+
+       cs->tx_skb = NULL;
+
+       task.routine = (void *) DChannel_proc_xmt;
+       task.data = (void *) cs;
+       queue_task(&task, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static void
+amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       struct sk_buff *skb = arg;
+       char str[64];
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       if (cs->tx_skb) {
+                               skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+                       } else {
+                               if ((cs->dlogflag) && (!(skb->data[2] & 1))) {
+                                       /* I-FRAME */
+                                       LogFrame(cs, skb->data, skb->len);
+                                       sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                                       dlogframe(cs, skb->data+4, skb->len-4,
+                                                 str);
+                               }
+                               cs->tx_skb = skb;
+                               cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+                               amd7930_dxmit(0, skb->data, skb->len,
+                                             &amd7930_dxmit_callback, cs);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (cs->tx_skb) {
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+                               skb_queue_tail(&cs->sq, skb);
+                               break;
+                       }
+                       if ((cs->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
+                               LogFrame(cs, skb->data, skb->len);
+                               sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                               dlogframe(cs, skb->data + 4, skb->len - 4,
+                                         str);
+                       }
+                       cs->tx_skb = skb;
+                       cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+                       amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len,
+                                     &amd7930_dxmit_callback, cs);
+                       break;
+               case (PH_PULL_REQ):
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+                       if (!cs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+int
+setDstack_amd7930(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l2.l2l1 = amd7930_Dchan_l2l1;
+       if (! cs->rcvbuf) {
+               printk("setDstack_amd7930: No cs->rcvbuf!\n");
+       } else {
+               amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
+                             &amd7930_drecv_callback, cs);
+       }
+       return (0);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+       struct PStack *st;
+
+       st = cs->stlist;
+       while (st) {
+               st->ma.manl1(st, msg, arg);
+               st = st->next;
+       }
+}
+
+static void
+amd7930_new_ph(struct IsdnCardState *cs)
+{
+       switch (amd7930_get_liu_state(0)) {
+               case 3:
+                       manl1_msg(cs, PH_POWERUP_CNF, NULL);
+                        break;
+
+               case 7:
+                       manl1_msg(cs, PH_I4_P8_IND, NULL);
+                       break;
+
+               case 8:
+                       manl1_msg(cs, PH_RSYNC_IND, NULL);
+                       break;
+       }
+}
+
+/* amd7930 LIU state change callback */
+
+static void
+amd7930_liu_callback(struct IsdnCardState *cs)
+{
+       static struct tq_struct task;
+
+       if (!cs)
+               return;
+
+       if (cs->debug & L1_DEB_ISAC) {
+               char tmp[32];
+               sprintf(tmp, "amd7930_liu state %d", amd7930_get_liu_state(0));
+               debugl1(cs, tmp);
+       }
+
+       task.sync = 0;
+       task.routine = (void *) &amd7930_new_ph;
+       task.data = (void *) cs;
+       queue_task(&task, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+void
+amd7930_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+       u_char val;
+       char tmp[32];
+       
+       if (cs->debug & L1_DEB_ISAC) {
+               char tmp[32];
+               sprintf(tmp, "amd7930_l1cmd msg %x", msg);
+               debugl1(cs, tmp);
+       }
+
+       switch(msg) {
+               case PH_RESET_REQ:
+                       if (amd7930_get_liu_state(0) <= 3)
+                               amd7930_liu_activate(0,0);
+                       else
+                               amd7930_liu_deactivate(0);
+                       break;
+               case PH_ENABLE_REQ:
+                       break;
+               case PH_INFO3_REQ:
+                       amd7930_liu_activate(0,0);
+                       break;
+               case PH_TESTLOOP_REQ:
+                       break;
+               default:
+                       if (cs->debug & L1_DEB_WARN) {
+                               sprintf(tmp, "amd7930_l1cmd unknown %4x", msg);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+}
+
+static void init_amd7930(struct IsdnCardState *cs)
+{
+       Bchan_init(&cs->bcs[0]);
+       Bchan_init(&cs->bcs[1]);
+       cs->bcs[0].BC_SetStack = setstack_amd7930;
+       cs->bcs[1].BC_SetStack = setstack_amd7930;
+       cs->bcs[0].BC_Close = Bchan_close;
+       cs->bcs[1].BC_Close = Bchan_close;
+       Bchan_mode(cs->bcs, 0, 0);
+       Bchan_mode(cs->bcs + 1, 0, 0);
+}
+
+void
+release_amd7930(struct IsdnCardState *cs)
+{
+}
+
+static int
+amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       return(0);
+               case CARD_RELEASE:
+                       release_amd7930(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(0);
+               case CARD_INIT:
+                       cs->l1cmd = amd7930_l1cmd;
+                       amd7930_liu_init(0, &amd7930_liu_callback, (void *)cs);
+                       init_amd7930(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_amd7930(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, amd7930_revision);
+       printk(KERN_INFO "HiSax: AMD7930 driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_AMD7930)
+               return (0);
+
+        cs->irq = amd7930_get_irqnum(0);
+        if (cs->irq == 0)
+               return (0);
+
+       cs->cardmsg = &amd7930_card_msg;
+
+       return (1);
+}
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
new file mode 100644 (file)
index 0000000..dad1711
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: arcofi.c,v 1.1 1997/10/29 18:51:20 keil Exp $
+
+ * arcofi.h   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *
+ * $Log: arcofi.c,v $
+ * Revision 1.1  1997/10/29 18:51:20  keil
+ * New files
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+
+int
+send_arcofi(struct IsdnCardState *cs, const u_char *msg) {
+       u_char val;
+       char tmp[32];
+       long flags;
+       int cnt=2;
+       
+       cs->mon_txp = 0;
+       cs->mon_txc = msg[0];
+       memcpy(cs->mon_tx, &msg[1], cs->mon_txc);
+       cs->mocr &= 0x0f;
+       cs->mocr |= 0xa0;
+       test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags);
+       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+       val = cs->readisac(cs, ISAC_MOSR);
+       cs->writeisac(cs, ISAC_MOX1, cs->mon_tx[cs->mon_txp++]);
+       cs->mocr |= 0x10;
+       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+       save_flags(flags);
+       sti();
+       while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
+               cnt--;
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+       }
+       restore_flags(flags);
+       sprintf(tmp, "arcofi tout %d", cnt);
+       debugl1(cs, tmp);
+       return(cnt);    
+}
+
diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h
new file mode 100644 (file)
index 0000000..5e1bb9e
--- /dev/null
@@ -0,0 +1,17 @@
+/* $Id: arcofi.h,v 1.1 1997/10/29 18:51:20 keil Exp $
+
+ * arcofi.h   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *
+ * $Log: arcofi.h,v $
+ * Revision 1.1  1997/10/29 18:51:20  keil
+ * New files
+ *
+ */
+#define ARCOFI_USE     1
+
+extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
new file mode 100644 (file)
index 0000000..c849174
--- /dev/null
@@ -0,0 +1,292 @@
+/* $Id: asuscom.c,v 1.2 1998/02/02 13:27:06 keil Exp $
+
+ * asuscom.c     low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to  ASUSCOM NETWORK INC. Taiwan and  Dynalink NL for informations
+ *
+ *
+ * $Log: asuscom.c,v $
+ * Revision 1.2  1998/02/02 13:27:06  keil
+ * New
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *Asuscom_revision = "$Revision: 1.2 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ASUS_ISAC      0
+#define ASUS_HSCX      1
+#define ASUS_ADR       2
+#define ASUS_CTRL_U7   3
+#define ASUS_CTRL_POTS 5
+
+/* CARD_ADR (Write) */
+#define ASUS_RESET      0x80   /* Bit 7 Reset-Leitung */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo read without cli because it's allready done  */
+
+       byteout(ale, off);
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readreg(cs->hw.asus.adr,
+                       cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.asus.adr,
+                cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
+               cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
+               cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
+               cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
+               cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n");
+               return;
+       }
+       val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
+       if (val) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (stat & 1) {
+               writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
+               writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_asuscom(struct IsdnCardState *cs)
+{
+       int bytecnt = 8;
+
+       if (cs->hw.asus.cfg_reg)
+               release_region(cs->hw.asus.cfg_reg, bytecnt);
+}
+
+static void
+reset_asuscom(struct IsdnCardState *cs)
+{
+       long flags;
+
+       byteout(cs->hw.asus.adr, ASUS_RESET);   /* Reset On */
+       save_flags(flags);
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       byteout(cs->hw.asus.adr, 0);    /* Reset Off */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       restore_flags(flags);
+}
+
+static int
+Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_asuscom(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_asuscom(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &asuscom_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_asuscom(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Asuscom_revision);
+       printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_ASUSCOM)
+               return (0);
+
+       bytecnt = 8;
+       cs->hw.asus.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+       cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
+       cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
+       cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
+       cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
+       cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
+
+       if (check_region((cs->hw.asus.cfg_reg), bytecnt)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.asus.cfg_reg,
+                      cs->hw.asus.cfg_reg + bytecnt);
+               return (0);
+       } else {
+               request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn");
+       }
+
+       printk(KERN_INFO
+              "ISDNLink: defined at 0x%x IRQ %d\n",
+              cs->hw.asus.cfg_reg,
+              cs->irq);
+       printk(KERN_INFO "ISDNLink: resetting card\n");
+       reset_asuscom(cs);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Asus_card_msg;
+       ISACVersion(cs, "ISDNLink:");
+       if (HscxVersion(cs, "ISDNLink:")) {
+               printk(KERN_WARNING
+                    "ISDNLink: wrong HSCX versions check IO address\n");
+               release_io_asuscom(cs);
+               return (0);
+       }
+       return (1);
+}
index e6c7755462cb4802703760a6766f583f5fbcfeb2..464bc33fd4dc1502dc41377da5dcaf2ee80b1d42 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: avm_a1.c,v 1.6 1997/04/13 19:54:07 keil Exp $
+/* $Id: avm_a1.c,v 2.7 1998/02/02 13:29:37 keil Exp $
 
  * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
  *
@@ -6,6 +6,30 @@
  *
  *
  * $Log: avm_a1.c,v $
+ * Revision 2.7  1998/02/02 13:29:37  keil
+ * fast io
+ *
+ * Revision 2.6  1998/01/13 23:09:46  keil
+ * really disable timer
+ *
+ * Revision 2.5  1998/01/02 06:50:29  calle
+ * Perodic timer of A1 now disabled, no need for linux driver.
+ *
+ * Revision 2.4  1997/11/08 21:35:42  keil
+ * new l1 init
+ *
+ * Revision 2.3  1997/11/06 17:13:32  keil
+ * New 2.1 init code
+ *
+ * Revision 2.2  1997/10/29 18:55:48  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1  1997/07/27 21:47:13  keil
+ * new interface structures
+ *
+ * Revision 2.0  1997/06/26 11:02:48  keil
+ * New Layer and card interface
+ *
  * Revision 1.6  1997/04/13 19:54:07  keil
  * Change in IRQ check delay for SMP
  *
  *
  */
 #define __NO_VERSION__
-#include "siemens.h"
 #include "hisax.h"
-#include "avm_a1.h"
+#include "isac.h"
+#include "hscx.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
 
 extern const char *CardType[];
-const char *avm_revision = "$Revision: 1.6 $";
+const char *avm_revision = "$Revision: 2.7 $";
+
+#define         AVM_A1_STAT_ISAC       0x01
+#define         AVM_A1_STAT_HSCX       0x02
+#define         AVM_A1_STAT_TIMER      0x04
 
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
 
 static inline u_char
 readreg(unsigned int adr, u_char off)
@@ -55,906 +82,303 @@ writereg(unsigned int adr, u_char off, u_char data)
 static inline void
 read_fifo(unsigned int adr, u_char * data, int size)
 {
-       insb(adr - 0x400, data, size);
+       insb(adr, 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");
+       outsb(adr, data, size);
 }
 
+/* Interface functions */
 
-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)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       waitforCEC(adr);
-       writereg(adr, HSCX_CMDR, data);
-       restore_flags(flags);
+       return (readreg(cs->hw.avm.isac, offset));
 }
 
-/*
- * fast interrupt here
- */
-
 static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       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));
+       writereg(cs->hw.avm.isac, offset, value);
 }
 
-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)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       read_fifo(cs->hw.avm.isacfifo, data, size);
 }
 
 static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       write_fifo(cs->hw.avm.isacfifo, data, size);
 }
 
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       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 {
-                               SET_SKB_FREE(hsp->tx_skb);
-                               dev_kfree_skb(hsp->tx_skb);
-                               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);
-       }
+       return (readreg(cs->hw.avm.hscx[hscx], offset));
 }
 
-/*
- * ISAC stuff goes here
- */
-
 static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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);
-       }
+       writereg(cs->hw.avm.hscx[hscx], offset, value);
 }
 
-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 {
-                                       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 {
-                               SET_SKB_FREE(sp->tx_skb);
-                               dev_kfree_skb(sp->tx_skb);
-                               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];
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
+#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
 
-       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);
-       }
-}
+#include "hscx_irq.c"
 
 static void
 avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs = dev_id;
        u_char val, sval, stat = 0;
        char tmp[32];
 
-       sp = (struct IsdnCardState *) dev_id;
-
-       if (!sp) {
+       if (!cs) {
                printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
                return;
        }
-       while (((sval = bytein(sp->cfg_reg)) & 0xf) != 0x7) {
+       while (((sval = bytein(cs->hw.avm.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) {
+                       byteout(cs->hw.avm.cfg_reg, 0x1E);
+                       sval = bytein(cs->hw.avm.cfg_reg);
+               } else if (cs->debug & L1_DEB_INTSTAT) {
                        sprintf(tmp, "avm IntStatus %x", sval);
-                       debugl1(sp, tmp);
+                       debugl1(cs, tmp);
                }
                if (!(sval & AVM_A1_STAT_HSCX)) {
-                       val = readreg(sp->hscx[1], HSCX_ISTA);
+                       val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
                        if (val) {
-                               hscx_int_main(sp, val);
+                               hscx_int_main(cs, val);
                                stat |= 1;
                        }
                }
                if (!(sval & AVM_A1_STAT_ISAC)) {
-                       val = readreg(sp->isac, ISAC_ISTA);
+                       val = readreg(cs->hw.avm.isac, ISAC_ISTA);
                        if (val) {
-                               isac_interrupt(sp, val);
+                               isac_interrupt(cs, 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);
+               writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
+               writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
+               writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
+               writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
        }
        if (stat & 2) {
-               writereg(sp->isac, ISAC_MASK, 0xFF);
-               writereg(sp->isac, ISAC_MASK, 0x0);
+               writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.avm.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_ioregs(struct IsdnCardState *cs, int mask)
 {
-       release_region(card->sp->cfg_reg, 8);
+       release_region(cs->hw.avm.cfg_reg, 8);
        if (mask & 1)
-               release_region(card->sp->isac, 32);
+               release_region(cs->hw.avm.isac + 32, 32);
        if (mask & 2)
-               release_region(card->sp->isac - 0x400, 1);
+               release_region(cs->hw.avm.isacfifo, 1);
        if (mask & 4)
-               release_region(card->sp->hscx[0], 32);
+               release_region(cs->hw.avm.hscx[0] + 32, 32);
        if (mask & 8)
-               release_region(card->sp->hscx[0] - 0x400, 1);
+               release_region(cs->hw.avm.hscxfifo[0], 1);
        if (mask & 0x10)
-               release_region(card->sp->hscx[1], 32);
+               release_region(cs->hw.avm.hscx[1] + 32, 32);
        if (mask & 0x20)
-               release_region(card->sp->hscx[1] - 0x400, 1);
+               release_region(cs->hw.avm.hscxfifo[1], 1);
 }
 
-void
-release_io_avm_a1(struct IsdnCard *card)
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-       release_ioregs(card, 0x3f);
+       switch (mt) {
+               case CARD_RESET:
+                       return(0);
+               case CARD_RELEASE:
+                       release_ioregs(cs, 0x3f);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &avm_a1_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
 }
 
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+__initfunc(int
+setup_avm_a1(struct IsdnCard *card))
 {
-       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_irqs(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_irqs(sp->irq) > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat_irqs(sp->irq));
-               debugl1(sp, tmp);
-               if (kstat_irqs(sp->irq) == sp->counter) {
-                       printk(KERN_WARNING
-                              "AVM A1: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       free_irq(sp->irq, sp);
-                       return (0);
-               }
-       }
-       return (ret);
-}
-
-int
-setup_avm_a1(struct IsdnCard *card)
-{
-       u_char val, verA, verB;
-       struct IsdnCardState *sp = card->sp;
+       u_char val;
+       struct IsdnCardState *cs = card->cs;
        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)
+       printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->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)) {
+       cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
+       cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
+       cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
+       cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
+       cs->hw.avm.isacfifo = card->para[1] + 0x1000;
+       cs->hw.avm.hscxfifo[0] = card->para[1];
+       cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
+       cs->irq = card->para[0];
+       if (check_region((cs->hw.avm.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);
+                      cs->hw.avm.cfg_reg,
+                      cs->hw.avm.cfg_reg + 8);
                return (0);
        } else {
-               request_region(sp->cfg_reg, 8, "avm cfg");
+               request_region(cs->hw.avm.cfg_reg, 8, "avm cfg");
        }
-       if (check_region((sp->isac), 32)) {
+       if (check_region((cs->hw.avm.isac + 32), 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);
+                      CardType[cs->typ],
+                      cs->hw.avm.isac + 32,
+                      cs->hw.avm.isac + 64);
+               release_ioregs(cs, 0);
                return (0);
        } else {
-               request_region(sp->isac, 32, "HiSax isac");
+               request_region(cs->hw.avm.isac + 32, 32, "HiSax isac");
        }
-       if (check_region((sp->isac - 0x400), 1)) {
+       if (check_region((cs->hw.avm.isacfifo), 1)) {
                printk(KERN_WARNING
                       "HiSax: %s isac fifo port %x already in use\n",
-                      CardType[sp->typ],
-                      sp->isac - 0x400);
-               release_ioregs(card, 1);
+                      CardType[cs->typ],
+                      cs->hw.avm.isacfifo);
+               release_ioregs(cs, 1);
                return (0);
        } else {
-               request_region(sp->isac - 0x400, 1, "HiSax isac fifo");
+               request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo");
        }
-       if (check_region((sp->hscx[0]), 32)) {
+       if (check_region((cs->hw.avm.hscx[0]) + 32, 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);
+                      CardType[cs->typ],
+                      cs->hw.avm.hscx[0] + 32,
+                      cs->hw.avm.hscx[0] + 64);
+               release_ioregs(cs, 3);
                return (0);
        } else {
-               request_region(sp->hscx[0], 32, "HiSax hscx A");
+               request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A");
        }
-       if (check_region((sp->hscx[0] - 0x400), 1)) {
+       if (check_region(cs->hw.avm.hscxfifo[0], 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);
+                      CardType[cs->typ],
+                      cs->hw.avm.hscxfifo[0]);
+               release_ioregs(cs, 7);
                return (0);
        } else {
-               request_region(sp->hscx[0] - 0x400, 1, "HiSax hscx A fifo");
+               request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo");
        }
-       if (check_region((sp->hscx[1]), 32)) {
+       if (check_region(cs->hw.avm.hscx[1] + 32, 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);
+                      CardType[cs->typ],
+                      cs->hw.avm.hscx[1] + 32,
+                      cs->hw.avm.hscx[1] + 64);
+               release_ioregs(cs, 0xf);
                return (0);
        } else {
-               request_region(sp->hscx[1], 32, "HiSax hscx B");
+               request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B");
        }
-       if (check_region((sp->hscx[1] - 0x400), 1)) {
+       if (check_region(cs->hw.avm.hscxfifo[1], 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);
+                      CardType[cs->typ],
+                      cs->hw.avm.hscxfifo[1]);
+               release_ioregs(cs, 0x1f);
                return (0);
        } else {
-               request_region(sp->hscx[1] - 0x400, 1, "HiSax hscx B fifo");
+               request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo");
        }
        save_flags(flags);
-       byteout(sp->cfg_reg, 0x0);
+       byteout(cs->hw.avm.cfg_reg, 0x0);
        sti();
        HZDELAY(HZ / 5 + 1);
-       byteout(sp->cfg_reg, 0x1);
+       byteout(cs->hw.avm.cfg_reg, 0x1);
        HZDELAY(HZ / 5 + 1);
-       byteout(sp->cfg_reg, 0x0);
+       byteout(cs->hw.avm.cfg_reg, 0x0);
        HZDELAY(HZ / 5 + 1);
-       val = sp->irq;
+       val = cs->irq;
        if (val == 9)
                val = 2;
-       byteout(sp->cfg_reg + 1, val);
+       byteout(cs->hw.avm.cfg_reg + 1, val);
        HZDELAY(HZ / 5 + 1);
-       byteout(sp->cfg_reg, 0x0);
+       byteout(cs->hw.avm.cfg_reg, 0x0);
        HZDELAY(HZ / 5 + 1);
        restore_flags(flags);
 
-       val = bytein(sp->cfg_reg);
+       val = bytein(cs->hw.avm.cfg_reg);
        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
-              sp->cfg_reg, val);
-       val = bytein(sp->cfg_reg + 3);
+              cs->hw.avm.cfg_reg, val);
+       val = bytein(cs->hw.avm.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);
+              cs->hw.avm.cfg_reg + 3, val);
+       val = bytein(cs->hw.avm.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);
+              cs->hw.avm.cfg_reg + 2, val);
+       byteout(cs->hw.avm.cfg_reg, 0x1E);
+       val = bytein(cs->hw.avm.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)) {
+              cs->hw.avm.cfg_reg, val);
+
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d cfg:0x%X\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.avm.cfg_reg);
+       printk(KERN_INFO
+              "HiSax: isac:0x%X/0x%X\n",
+              cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
+       printk(KERN_INFO
+              "HiSax: hscx A:0x%X/0x%X  hscx B:0x%X/0x%X\n",
+              cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
+              cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
+
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &AVM_card_msg;
+       ISACVersion(cs, "AVM A1:");
+       if (HscxVersion(cs, "AVM A1:")) {
                printk(KERN_WARNING
                       "AVM A1: wrong HSCX versions check IO address\n");
-               release_io_avm_a1(card);
+               release_ioregs(cs, 0x3f);
                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
deleted file mode 100644 (file)
index 85f4467..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* $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/buffers.c b/drivers/isdn/hisax/buffers.c
deleted file mode 100644 (file)
index 6213854..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/* $Id: buffers.c,v 1.1 1996/10/13 20:04:49 keil Exp $
- *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
- *              based on the teles driver from Jan den Ouden
- *
- * Thanks to    Jan den Ouden
- *              Fritz Elfert
- *
- * $Log: buffers.c,v $
- * Revision 1.1  1996/10/13 20:04:49  keil
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "hisax.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-#undef SMALLOC_DEBUG
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
-           int maxpages)
-{
-#ifdef DEBUG_MAGIC
-       generateerror
-           bp->magic = 010167;
-#endif
-
-#if 0
-       printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
-       bp->freelist = NULL;
-       bp->pageslist = NULL;
-       bp->pageorder = order;
-       bp->pagescount = 0;
-       bp->bpps = bpps;
-       bp->bufsize = BUFFER_SIZE(order, bpps);
-       bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
-       struct Pages   *ptr;
-       byte           *bptr;
-       int             i;
-       struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
-       printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
-       ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder);
-       if (!ptr) {
-               printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
-               return (-1);
-       }
-#if 0
-       printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
-       ptr->next = bp->pageslist;
-       bp->pageslist = ptr;
-       bp->pagescount++;
-
-       bptr = (byte *) ptr + sizeof(struct Pages *);
-
-       i = bp->bpps;
-       first = (struct BufHeader *) bptr;
-       prev = NULL;
-       while (i--) {
-               bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
-               bh->magic = 020167;
-#endif
-               bh->next = prev;
-               prev = bh;
-               bh->bp = bp;
-               bptr += PART_SIZE(bp->pageorder, bp->bpps);
-       }
-
-       first->next = bp->freelist;
-       bp->freelist = bh;
-       return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
-       struct Pages   *p;
-
-#if 0
-       printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
-       while (bp->pagescount--) {
-               p = bp->pageslist->next;
-               free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
-               printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
-               bp->pageslist = p;
-       }
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
-          struct BufPool *bp, int priority, void *heldby, int where)
-{
-       long            flags;
-       int             i;
-
-#ifdef DEBUG_MAGIC
-       if (bp->magic != 010167) {
-               printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
-               return (-1);
-       }
-#endif
-
-       save_flags(flags);
-       cli();
-       i = 0;
-       while (!0) {
-               if (bp->freelist) {
-                       *bh = bp->freelist;
-                       bp->freelist = bp->freelist->next;
-                       (*bh)->heldby = heldby;
-                       (*bh)->where = where;
-                       restore_flags(flags);
-                       return (0);
-               }
-               if ((i == 0) && (bp->pagescount < bp->maxpages)) {
-                        if (BufPoolAdd(bp, priority)) {
-                                restore_flags(flags);
-                                return -1;
-                        }
-                       i++;
-               } else {
-                       *bh = NULL;
-                       restore_flags(flags);
-                       return (-1);
-               }
-       }
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
-       struct BufPool *bp;
-       long            flags;
-
-#ifdef DEBUG_MAGIC
-       if (bh->magic != 020167) {
-               printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
-               printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
-               return;
-       }
-#endif
-
-       bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
-       if (bp->magic != 010167) {
-               printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
-               return;
-       }
-#endif
-
-       save_flags(flags);
-       cli();
-       bh->next = bp->freelist;
-       bp->freelist = bh;
-       restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
-            struct BufHeader *bh)
-{
-       unsigned long   flags;
-
-       save_flags(flags);
-       cli();
-       if (!bq->head)
-               bq->head = bh;
-       if (bq->tail)
-               bq->tail->next = bh;
-       bq->tail = bh;
-       bh->next = NULL;
-       restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
-                 struct BufHeader *bh)
-{
-       unsigned long   flags;
-
-       save_flags(flags);
-       cli();
-       bh->next = bq->head;
-       bq->head = bh;
-       if (!bq->tail)
-               bq->tail = bh;
-       restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
-       long            flags;
-
-       save_flags(flags);
-       cli();
-
-       if (bq->head) {
-               if (bq->tail == bq->head)
-                       bq->tail = NULL;
-               *bh = bq->head;
-               bq->head = (*bh)->next;
-               restore_flags(flags);
-               return (0);
-       } else {
-               restore_flags(flags);
-               return (-1);
-       }
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
-       bq->magic = 030167;
-#endif
-       bq->head = NULL;
-       bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
-       struct BufHeader *bh;
-
-       while (bq->head) {
-               BufQueueUnlink(&bh, bq);
-               BufPoolRelease(bh);
-       }
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
-       int             i = 0;
-       struct BufHeader *bh;
-
-       bh = bq->head;
-       while (bh) {
-               i++;
-               bh = bh->next;
-       }
-       return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
-               int releasetoo)
-{
-       long            flags;
-       struct BufHeader *sp;
-
-       save_flags(flags);
-       cli();
-
-       while (!0) {
-               sp = q->head;
-               if (!sp)
-                       break;
-               if ((sp->primitive == pr) && (sp->heldby == heldby)) {
-                       q->head = sp->next;
-                       if (q->tail == sp)
-                               q->tail = NULL;
-                       if (releasetoo)
-                               BufPoolRelease(sp);
-               } else
-                       break;
-       }
-
-       sp = q->head;
-       if (sp)
-               while (sp->next) {
-                       if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
-                               if (q->tail == sp->next)
-                                       q->tail = sp;
-                               if (releasetoo)
-                                       BufPoolRelease(sp->next);
-                               sp->next = sp->next->next;
-                       } else
-                               sp = sp->next;
-               }
-       restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#ifdef SMALLOC_DEBUG
-       printk(KERN_DEBUG "Sfree %x\n", (unsigned int)ptr);
-#endif
-       kfree(ptr);
-}
-
-byte           *
-Smalloc(int size, int pr, char *why)
-{
-       byte           *p;
-
-       p = (byte *) kmalloc(size, pr);
-#ifdef SMALLOC_DEBUG
-       printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, (unsigned int)p);
-#endif
-       return (p);
-}
index fbf04557477475390a8e9d32c761a619dd2032bf..6924e3f9e5475d7132d6c615d7f27dfb5c7dbe4a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
+/* $Id: callc.c,v 2.13 1998/02/12 23:07:16 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,96 +7,54 @@
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
- * Revision 1.30  1997/05/29 10:40:43  keil
- * chanp->impair was uninitialised
+ * Revision 2.13  1998/02/12 23:07:16  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.29  1997/04/23 20:09:49  fritz
- * Removed tmp, used by removed debugging code.
+ * Revision 2.12  1998/02/09 10:55:54  keil
+ * New leased line mode
  *
- * Revision 1.28  1997/04/21 13:42:25  keil
- * Remove unneeded debug
+ * Revision 2.11  1998/02/02 13:35:19  keil
+ * config B-channel delay
  *
- * Revision 1.27  1997/04/16 14:21:01  keil
- * remove unused variable
+ * Revision 2.10  1997/11/06 17:09:15  keil
+ * New 2.1 init code
  *
- * Revision 1.26  1997/04/13 19:55:21  keil
- * Changes in debugging code
+ * Revision 2.9  1997/10/29 19:01:58  keil
+ * new LL interface
  *
- * Revision 1.25  1997/04/06 22:54:08  keil
- * Using SKB's
+ * Revision 2.8  1997/10/10 20:56:44  fritz
+ * New HL interface.
  *
- * Revision 1.24  1997/03/05 11:28:03  keil
- * fixed undefined l2tei procedure
- * a layer1 release delete now the drel timer
+ * Revision 2.7  1997/10/01 09:21:28  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
  *
- * Revision 1.23  1997/03/04 23:07:42  keil
- * bugfix dial parameter
+ * Revision 2.6  1997/09/11 17:26:58  keil
+ * Open B-channel if here are incomming packets
  *
- * Revision 1.22  1997/02/27 13:51:55  keil
- * Reset B-channel (dlc) statemachine in every release
+ * Revision 2.5  1997/08/07 17:46:05  keil
+ * Fix Incomming Call without broadcast
  *
- * Revision 1.21  1997/02/19 09:24:27  keil
- * Bugfix: Hangup to LL if a ttyI rings
+ * Revision 2.4  1997/08/03 14:37:58  keil
+ * Activate Layer2 in PtP mode
  *
- * Revision 1.20  1997/02/17 00:32:47  keil
- * Bugfix: No Busy reported to LL
+ * Revision 2.3  1997/07/31 19:23:40  keil
+ * LAYER2_WATCHING for PtP
  *
- * Revision 1.19  1997/02/14 12:23:10  fritz
- * Added support for new insmod parameter handling.
+ * Revision 2.2  1997/07/31 11:48:18  keil
+ * experimental REJECT after ALERTING
  *
- * Revision 1.18  1997/02/11 01:36:58  keil
- * Changed setup-interface (incoming and outgoing), cause reporting
+ * Revision 2.1  1997/07/30 17:12:59  keil
+ * more changes for 'One TEI per card'
  *
- * 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 2.0  1997/07/27 21:12:21  keil
+ * CRef based L3; new channel handling; many other stuff
  *
- * Revision 1.16  1997/01/27 23:17:03  keil
- * delete timers while unloading
+ * Revision 1.31  1997/06/26 11:09:23  keil
+ * New managment and minor changes
  *
- * 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
+ * old logs removed /KKe
  *
  */
 
 #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 $";
+const char *lli_revision = "$Revision: 2.13 $";
 
 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 int init_b_st(struct Channel *chanp, int incoming);
+static void release_b_st(struct Channel *chanp);
 
 static struct Fsm callcfsm =
-{NULL, 0, 0};
+{NULL, 0, 0, NULL, NULL};
 static struct Fsm lcfsm =
-{NULL, 0, 0};
+{NULL, 0, 0, NULL, NULL};
 
 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)
+/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ 
+#define ALERT_REJECT 1
+
+/* Value to delay the sending of the first B-channel paket after CONNECT
+ * here is no value given by ITU, but experience shows that 300 ms will
+ * work on many networks, if you or your other side is behind local exchanges
+ * a greater value may be recommented. If the delay is to short the first paket
+ * will be lost and autodetect on many comercial routers goes wrong !
+ * You can adjust this value on runtime with 
+ * hisaxctrl <id> 2 <value>
+ * value is in milliseconds
+ */
+#define DEFAULT_B_DELAY        300
+
+/* Flags for remembering action done in lli */
+
+#define  FLG_START_D   0
+#define  FLG_ESTAB_D   1
+#define  FLG_CALL_SEND 2
+#define  FLG_CALL_REC   3
+#define  FLG_CALL_ALERT        4
+#define  FLG_START_B   5
+#define  FLG_CONNECT_B 6
+#define  FLG_LL_DCONN  7
+#define  FLG_LL_BCONN  8
+#define  FLG_DISC_SEND 9
+#define  FLG_DISC_REC  10
+#define  FLG_REL_REC   11
+#define  FLG_DO_ALERT  12
+#define  FLG_DO_HANGUP 13
+#define  FLG_DO_CONNECT        14
+#define  FLG_DO_ESTAB  15
 
 /*
  * Because of callback it's a good idea to delay the shutdown of the d-channel
  */
-#define        DREL_TIMER_VALUE 30000
+#define        DREL_TIMER_VALUE 10000
 
 /*
  * Find card with given driverId
@@ -162,9 +130,9 @@ 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);
+               if (cards[i].cs)
+                       if (cards[i].cs->myid == driverid)
+                               return (cards[i].cs);
        return (struct IsdnCardState *) 0;
 }
 
@@ -176,7 +144,7 @@ link_debug(struct Channel *chanp, char *s, int direction)
        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);
+       HiSax_putstatus(chanp->cs, tmp);
 }
 
 
@@ -233,7 +201,7 @@ enum {
        EV_SETUP_CMPL_IND,      /* 10 */
        EV_BC_EST,              /* 11 */
        EV_WRITEBUF,            /* 12 */
-       EV_DATAIN,              /* 13 */
+       EV_ESTABLISH,           /* 13 */
        EV_HANGUP,              /* 14 */
        EV_BC_REL,              /* 15 */
        EV_CINF,                /* 16 */
@@ -263,7 +231,7 @@ static char *strEvent[] =
        "EV_SETUP_CMPL_IND",
        "EV_BC_EST",
        "EV_WRITEBUF",
-       "EV_DATAIN",
+       "EV_ESTABLISH",
        "EV_HANGUP",
        "EV_BC_REL",
        "EV_CINF",
@@ -283,7 +251,6 @@ enum {
        ST_LC_ESTABLISH_WAIT,
        ST_LC_CONNECTED,
        ST_LC_FLUSH_WAIT,
-       ST_LC_FLUSH_DELAY,
        ST_LC_RELEASE_WAIT,
 };
 
@@ -297,7 +264,6 @@ static char *strLcState[] =
        "ST_LC_ESTABLISH_WAIT",
        "ST_LC_CONNECTED",
        "ST_LC_FLUSH_WAIT",
-       "ST_LC_FLUSH_DELAY",
        "ST_LC_RELEASE_WAIT",
 };
 
@@ -307,9 +273,7 @@ enum {
        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,
 };
 
@@ -322,9 +286,7 @@ static char *strLcEvent[] =
        "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",
 };
 
@@ -332,788 +294,962 @@ static char *strLcEvent[] =
 #define LC_B  1
 
 static inline void
-l4_deliver_cause(struct Channel *chanp)
+lli_deliver_cause(struct Channel *chanp)
 {
        isdn_ctrl ic;
 
-       if (chanp->para.cause < 0)
+       if (chanp->proc->para.cause < 0)
                return;
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->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);
+       if (chanp->cs->protocol == ISDN_PTYPE_EURO)
+               sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
+                       chanp->proc->para.cause & 0x7f);
        else
-               sprintf(ic.parm.num, "%02X%02X", chanp->para.loc & 0x7f,
-                       chanp->para.cause & 0x7f);
-       chanp->sp->iif.statcallb(&ic);
+               sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
+                       chanp->proc->para.cause & 0x7f);
+       chanp->cs->iif.statcallb(&ic);
+}
+
+static void
+lli_d_established(struct FsmInst *fi, int event, void *arg)
+{
+       struct Channel *chanp = fi->userdata;
+
+       test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+       if (chanp->leased) {
+               isdn_ctrl ic;
+               int ret;
+               char txt[32];
+
+               chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
+               FsmChangeState(fi, ST_IN_WAIT_LL);
+               test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
+               if (chanp->debug & 1)
+                       link_debug(chanp, "STAT_ICALL_LEASED", 0);
+               ic.driver = chanp->cs->myid;
+               ic.command = ISDN_STAT_ICALL;
+               ic.arg = chanp->chan;
+               ic.parm.setup.si1 = 7;
+               ic.parm.setup.si2 = 0;
+               ic.parm.setup.plan = 0;
+               ic.parm.setup.screen = 0;
+               sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); 
+               sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid);
+               ret = chanp->cs->iif.statcallb(&ic);
+               if (chanp->debug & 1) {
+                       sprintf(txt, "statcallb ret=%d", ret);
+                       link_debug(chanp, txt, 1);
+               }
+               if (!ret) {
+                       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+                       FsmChangeState(fi, ST_NULL);
+               }
+       } else if (fi->state == ST_WAIT_DSHUTDOWN)
+               FsmChangeState(fi, ST_NULL);
+}
+
+static void
+lli_d_released(struct FsmInst *fi, int event, void *arg)
+{
+       struct Channel *chanp = fi->userdata;
+
+       test_and_clear_bit(FLG_START_D, &chanp->Flags);
 }
 
 /*
  * Dial out
  */
 static void
-l4_prep_dialout(struct FsmInst *fi, int event, void *arg)
+lli_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;
+       chanp->lc_b->l2_start = !0;
        switch (chanp->l2_active_protocol) {
                case (ISDN_PROTO_L2_X75I):
-                       chanp->lc_b.l2_establish = !0;
+                       chanp->lc_b->l2_establish = !0;
                        break;
                case (ISDN_PROTO_L2_HDLC):
                case (ISDN_PROTO_L2_TRANS):
-                       chanp->lc_b.l2_establish = 0;
+                       chanp->lc_b->l2_establish = 0;
                        break;
                default:
-                       printk(KERN_WARNING "l4_prep_dialout unknown protocol\n");
+                       printk(KERN_WARNING "lli_prep_dialout unknown protocol\n");
                        break;
        }
-       if (chanp->Flags & FLG_ESTAB_D) {
+       if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
                FsmEvent(fi, EV_DLEST, NULL);
        } else {
-               chanp->Flags = FLG_START_D;
+               chanp->Flags = 0;
+               test_and_set_bit(FLG_START_D, &chanp->Flags);
                if (chanp->leased) {
-                       chanp->lc_d.l2_establish = 0;
+                       chanp->lc_d->l2_establish = 0;
                }
-               FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+               FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
        }
 }
 
 static void
-l4_do_dialout(struct FsmInst *fi, int event, void *arg)
+lli_do_dialout(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
 
        FsmChangeState(fi, ST_OUT_DIAL);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
        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);
+               test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_REQ, chanp);
+               test_and_set_bit(FLG_CALL_SEND, &chanp->Flags);
        }
 }
 
 static void
-l4_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
        if (chanp->debug & 1)
                link_debug(chanp, "STAT_DCONN", 0);
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->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);
+       chanp->cs->iif.statcallb(&ic);
+       init_b_st(chanp, 0);
+       test_and_set_bit(FLG_START_B, &chanp->Flags);
+       FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL);
 }
 
 static void
-l4_go_active(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       test_and_set_bit(FLG_CONNECT_B, &chanp->Flags);
        if (chanp->debug & 1)
                link_debug(chanp, "STAT_BCONN", 0);
-       SETBIT(chanp->Flags, FLG_LL_BCONN);
-       ic.driver = chanp->sp->myid;
+       test_and_set_bit(FLG_LL_BCONN, &chanp->Flags);
+       ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_BCONN;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(&ic);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) chanp->chan);
 }
 
 /* incomming call */
 
 static void
-l4_start_dchan(struct FsmInst *fi, int event, void *arg)
+lli_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) {
+       if (event == EV_ACCEPTD)
+               test_and_set_bit(FLG_DO_CONNECT, &chanp->Flags);
+       else if (event == EV_HANGUP) {
+               test_and_set_bit(FLG_DO_HANGUP, &chanp->Flags);
+#ifdef ALERT_REJECT            
+               test_and_set_bit(FLG_DO_ALERT, &chanp->Flags);
+#endif
+       } 
+       if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
                FsmEvent(fi, EV_DLEST, NULL);
-       } else {
-               chanp->Flags = FLG_START_D;
-               FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-       }
+       } else if (!test_and_set_bit(FLG_START_D, &chanp->Flags))
+               FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
 }
 
 static void
-l4_deliver_call(struct FsmInst *fi, int event, void *arg)
+lli_deliver_call(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
        isdn_ctrl ic;
        int ret;
        char txt[32];
 
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
        /*
         * 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)) {
+       if (1) { /* for only one TEI */
                FsmChangeState(fi, ST_IN_WAIT_LL);
-               SETBIT(chanp->Flags, FLG_ESTAB_D);
-               SETBIT(chanp->Flags, FLG_CALL_REC);
+               test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_ICALL", 0);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->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);
+               ic.parm.setup = chanp->proc->para.setup;
+               ret = chanp->cs->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);
+                               FsmDelTimer(&chanp->drel_timer, 61);
+                               if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
+                                       FsmChangeState(fi, ST_IN_ALERT_SEND);
+                                       test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags);
+                                       chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc);
+                               } else {
+                                       test_and_set_bit(FLG_DO_ALERT, &chanp->Flags);
+                                       FsmChangeState(fi, ST_IN_WAIT_D);
+                                       test_and_set_bit(FLG_START_D, &chanp->Flags);
+                                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+                               }
                                break;
                        case 2: /* Rejecting Call */
-                               RESBIT(chanp->Flags, FLG_CALL_REC);
+                               test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
                                break;
                        case 0: /* OK, nobody likes this call */
                        default:        /* statcallb problems */
-                               chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+                               chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
+                               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
                                FsmChangeState(fi, ST_NULL);
-                               chanp->Flags = FLG_ESTAB_D;
-                               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+#ifndef LAYER2_WATCHING
+                               if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+                                       FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+#endif
                                break;
                }
        } else {
-               chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
+               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+               FsmChangeState(fi, ST_NULL);
+#ifndef LAYER2_WATCHING
+               if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+                       FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+#endif
+       }
+}
+
+static void
+lli_establish_d(struct FsmInst *fi, int event, void *arg)
+{
+       /* This establish the D-channel for pending L3 messages 
+        * without blocking th channel
+        */
+       struct Channel *chanp = fi->userdata;
+
+       test_and_set_bit(FLG_DO_ESTAB, &chanp->Flags);
+       FsmChangeState(fi, ST_IN_WAIT_D);
+       test_and_set_bit(FLG_START_D, &chanp->Flags);
+       FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+lli_do_action(struct FsmInst *fi, int event, void *arg)
+{
+       struct Channel *chanp = fi->userdata;
+
+       test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+       if (chanp->leased) {
+               FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+               test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags);
+               test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags);
+               FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
+       } else if (test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags) &&
+               !test_bit(FLG_DO_HANGUP, &chanp->Flags)) {
+               FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+               test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
+       } else if (test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags)) {
+               if (test_bit(FLG_DO_HANGUP, &chanp->Flags))
+                       FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63);
+               FsmChangeState(fi, ST_IN_ALERT_SEND);
+               test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc);
+       } else if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) {
+               FsmChangeState(fi, ST_WAIT_DRELEASE);
+               chanp->proc->para.cause = 0x15;         /* Call Rejected */
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT_REQ, chanp->proc);
+               test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
+       } else if (test_and_clear_bit(FLG_DO_ESTAB, &chanp->Flags)) {
                FsmChangeState(fi, ST_NULL);
-               chanp->Flags = FLG_ESTAB_D;
-               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+               chanp->Flags = 0;
+               test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_ESTABLISH, chanp->proc);
+               chanp->proc = NULL;
+#ifndef LAYER2_WATCHING
+               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+#endif
        }
 }
 
 static void
-l4_send_dconnect(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
 }
 
 static void
-l4_init_bchan_in(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
        if (chanp->debug & 1)
                link_debug(chanp, "STAT_DCONN", 0);
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DCONN;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(&ic);
        chanp->l2_active_protocol = chanp->l2_protocol;
        chanp->incoming = !0;
-       chanp->lc_b.l2_start = 0;
+       chanp->lc_b->l2_start = 0;
        switch (chanp->l2_active_protocol) {
                case (ISDN_PROTO_L2_X75I):
-                       chanp->lc_b.l2_establish = !0;
+                       chanp->lc_b->l2_establish = !0;
                        break;
                case (ISDN_PROTO_L2_HDLC):
                case (ISDN_PROTO_L2_TRANS):
-                       chanp->lc_b.l2_establish = 0;
+                       chanp->lc_b->l2_establish = 0;
                        break;
                default:
-                       printk(KERN_WARNING "r9 unknown protocol\n");
+                       printk(KERN_WARNING "bchannel unknown protocol\n");
                        break;
        }
-       init_ds(chanp, !0);
-       SETBIT(chanp->Flags, FLG_START_B);
-       FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+       init_b_st(chanp, !0);
+       test_and_set_bit(FLG_START_B, &chanp->Flags);
+       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)
+lli_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 (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               RESBIT(chanp->Flags, FLG_LL_BCONN);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->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->cs->iif.statcallb(&ic);
        }
-       chanp->para.cause = 0x10;       /* Normal Call Clearing */
-       chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-       SETBIT(chanp->Flags, FLG_DISC_SEND);
+       if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       chanp->proc->para.cause = 0x10;         /* Normal Call Clearing */
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc);
+       test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
 }
 
 static void
-l4_shutdown_d(struct FsmInst *fi, int event, void *arg)
+lli_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);
+#ifdef LAYER2_WATCHING
+       FsmChangeState(fi, ST_NULL);
+#else
+       if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) {
+               if (chanp->chan) {
+                       if (chanp->cs->channel[0].fi.state != ST_NULL)
+                               return;
+               } else {
+                       if (chanp->cs->channel[1].fi.state != ST_NULL)
+                               return;
+               }
+       }
+       FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+       test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
+       FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+#endif
 }
 
 static void
-l4_timeout_d(struct FsmInst *fi, int event, void *arg)
+lli_timeout_d(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
        isdn_ctrl ic;
 
-       if (chanp->Flags & FLG_LL_DCONN) {
+       if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
                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;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
        }
        FsmChangeState(fi, ST_NULL);
-       chanp->Flags = FLG_ESTAB_D;
+       chanp->Flags = 0;
+       test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
+#ifndef LAYER2_WATCHING
        FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+#endif
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
 }
 
 static void
-l4_go_null(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
 }
 
 static void
-l4_disconn_bchan(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
+       FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
 }
 
 static void
-l4_send_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_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))
+       if (test_bit(FLG_DISC_REC, &chanp->Flags) ||
+               test_bit(FLG_REL_REC, &chanp->Flags))
                return;
        FsmChangeState(fi, ST_WAIT_DRELEASE);
-       if (chanp->Flags & FLG_LL_BCONN) {
+       if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               RESBIT(chanp->Flags, FLG_LL_BCONN);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
        }
-       if (chanp->Flags & FLG_START_B) {
-               release_ds(chanp);
-               RESBIT(chanp->Flags, FLG_START_B);
+       if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       if (chanp->leased) {
+               ic.command = ISDN_STAT_CAUSE;
+               ic.arg = chanp->chan;
+               sprintf(ic.parm.num, "L0010");
+               chanp->cs->iif.statcallb(&ic);
+               if (chanp->debug & 1)
+                       link_debug(chanp, "STAT_DHUP", 0);
+               ic.driver = chanp->cs->myid;
+               ic.command = ISDN_STAT_DHUP;
+               ic.arg = chanp->chan;
+               chanp->cs->iif.statcallb(&ic);
+               FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+               test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
+               FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+       } else {
+               if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags))
+                       chanp->proc->para.cause = 0x15;         /* Call Reject */
+               else
+                       chanp->proc->para.cause = 0x10;         /* Normal Call Clearing */
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc);
+               test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
        }
-       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)
+lli_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 (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               RESBIT(chanp->Flags, FLG_LL_BCONN);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
        }
-       release_ds(chanp);
-       RESBIT(chanp->Flags, FLG_START_B);
+       release_b_st(chanp);
+       test_and_clear_bit(FLG_START_B, &chanp->Flags);
 }
 
 
 static void
-l4_release_bchan(struct FsmInst *fi, int event, void *arg)
+lli_release_bchan(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
 
        chanp->data_open = 0;
-       SETBIT(chanp->Flags, FLG_DISC_REC);
+       test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
        FsmChangeState(fi, ST_WAIT_BREL_DISC);
-       RESBIT(chanp->Flags, FLG_CONNECT_B);
-       FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+       test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
+       FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
 }
 
 static void
-l4_received_d_rel(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       FsmChangeState(fi, ST_NULL);
+       test_and_set_bit(FLG_REL_REC, &chanp->Flags);
+       if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
+               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
        }
-       if (chanp->Flags & FLG_LL_BCONN) {
+       if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->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);
+               chanp->cs->iif.statcallb(&ic);
        }
-       if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+       if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+               test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+               test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_DHUP", 0);
-               l4_deliver_cause(chanp);
-               ic.driver = chanp->sp->myid;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->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);
+       test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+       lli_timeout_d(fi, event, arg);
 }
 
 static void
-l4_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       FsmChangeState(fi, ST_NULL);
+       if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
+               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
        }
-       if (chanp->Flags & FLG_LL_BCONN) {
+       if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
-               RESBIT(chanp->Flags, FLG_LL_BCONN);
+               chanp->cs->iif.statcallb(&ic);
        }
-       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 (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+               test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+               test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_DHUP", 0);
-               l4_deliver_cause(chanp);
-               ic.driver = chanp->sp->myid;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->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);
+       test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_REC, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+       lli_timeout_d(fi, event, arg);
 }
 
 static void
-l4_received_d_disc(struct FsmInst *fi, int event, void *arg)
+lli_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) {
+       test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
+       if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->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);
+               chanp->cs->iif.statcallb(&ic);
        }
-       if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+       if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       if (test_bit(FLG_LL_DCONN, &chanp->Flags) ||
+               test_bit(FLG_CALL_SEND, &chanp->Flags) ||
+               test_bit(FLG_CALL_ALERT, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_DHUP", 0);
-               l4_deliver_cause(chanp);
-               ic.driver = chanp->sp->myid;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->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);
+       test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE_REQ, chanp->proc);
 }
 
 /* processing charge info */
 static void
-l4_charge_info(struct FsmInst *fi, int event, void *arg)
+lli_charge_info(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
        isdn_ctrl ic;
 
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_CINF;
        ic.arg = chanp->chan;
-       sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
-       chanp->sp->iif.statcallb(&ic);
+       sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo);
+       chanp->cs->iif.statcallb(&ic);
 }
 
 /* error procedures */
 
 static void
-l4_no_dchan(struct FsmInst *fi, int event, void *arg)
+lli_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.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_NODCH;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(&ic);
        chanp->Flags = 0;
        FsmChangeState(fi, ST_NULL);
-       FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+       FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
 }
 
 static void
-l4_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
+lli_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.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DHUP;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(&ic);
 }
 
 static void
-l4_no_dchan_in(struct FsmInst *fi, int event, void *arg)
+lli_no_dchan_in(struct FsmInst *fi, int event, void *arg)
 {
        struct Channel *chanp = fi->userdata;
+       isdn_ctrl ic;
 
-       chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+       if (chanp->debug & 1)
+               link_debug(chanp, "STAT_DHUP", 0);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
        chanp->Flags = 0;
        FsmChangeState(fi, ST_NULL);
-       FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+       FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
 }
 
 static void
-l4_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
+lli_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);
+       test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
        if (chanp->debug & 1)
                link_debug(chanp, "STAT_DHUP", 0);
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DHUP;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(&ic);
+       lli_shutdown_d(fi, event, arg);
 }
 
 static void
-l4_setup_err(struct FsmInst *fi, int event, void *arg)
+lli_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 (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
                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;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
        }
-       SETBIT(chanp->Flags, FLG_DISC_SEND);    /* DISCONN was sent from L3 */
+       test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
 }
 
 static void
-l4_connect_err(struct FsmInst *fi, int event, void *arg)
+lli_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 (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
                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;
+               lli_deliver_cause(chanp);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
        }
-       SETBIT(chanp->Flags, FLG_DISC_SEND);    /* DISCONN was sent from L3 */
+       test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
 }
 
 static void
-l4_active_dlrl(struct FsmInst *fi, int event, void *arg)
+lli_got_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 (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
+               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
+               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
        }
-       if (chanp->Flags & FLG_LL_BCONN) {
+       if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
                        link_debug(chanp, "STAT_BHUP", 0);
-               ic.driver = chanp->sp->myid;
+               ic.driver = chanp->cs->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);
+               chanp->cs->iif.statcallb(&ic);
        }
-       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;
+       if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
+               release_b_st(chanp);
+       if (chanp->leased) {
+               ic.driver = chanp->cs->myid;
+               ic.command = ISDN_STAT_CAUSE;
+               ic.arg = chanp->chan;
+               sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f);
+               chanp->cs->iif.statcallb(&ic);
+               ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
-               chanp->sp->iif.statcallb(&ic);
+               chanp->cs->iif.statcallb(&ic);
+               chanp->Flags = 0;
+       } else {
+               if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
+                       if (chanp->debug & 1)
+                               link_debug(chanp, "STAT_DHUP", 0);
+                       if (chanp->cs->protocol == ISDN_PTYPE_EURO) {
+                               chanp->proc->para.cause = 0x2f;
+                               chanp->proc->para.loc = 0;
+                       } else {
+                               chanp->proc->para.cause = 0x70;
+                               chanp->proc->para.loc = 0;
+                       }
+                       lli_deliver_cause(chanp);
+                       ic.driver = chanp->cs->myid;
+                       ic.command = ISDN_STAT_DHUP;
+                       ic.arg = chanp->chan;
+                       chanp->cs->iif.statcallb(&ic);
+               }
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
+               chanp->Flags = 0;
+               FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
        }
-       chanp->Flags = 0;
-       chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
-       FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
 }
+
 /* *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},
+static struct FsmNode fnlist[] HISAX_INITDATA =
+{
+       {ST_NULL,               EV_DIAL,                lli_prep_dialout},
+       {ST_NULL,               EV_SETUP_IND,           lli_deliver_call},
+       {ST_NULL,               EV_SHUTDOWN_D,          lli_shutdown_d},
+       {ST_NULL,               EV_DLRL,                lli_go_null},
+       {ST_NULL,               EV_DLEST,               lli_d_established},
+       {ST_NULL,               EV_ESTABLISH,           lli_establish_d},
+       {ST_OUT_WAIT_D,         EV_DLEST,               lli_do_dialout},
+       {ST_OUT_WAIT_D,         EV_DLRL,                lli_no_dchan},
+       {ST_OUT_WAIT_D,         EV_HANGUP,              lli_no_dchan},
+       {ST_IN_WAIT_D,          EV_DLEST,               lli_do_action},
+       {ST_IN_WAIT_D,          EV_DLRL,                lli_no_dchan_in},
+       {ST_IN_WAIT_D,          EV_ACCEPTD,             lli_start_dchan},
+       {ST_IN_WAIT_D,          EV_HANGUP,              lli_start_dchan},
+       {ST_OUT_DIAL,           EV_SETUP_CNF,           lli_init_bchan_out},
+       {ST_OUT_DIAL,           EV_HANGUP,              lli_cancel_call},
+       {ST_OUT_DIAL,           EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_OUT_DIAL,           EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_OUT_DIAL,           EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_OUT_DIAL,           EV_NOSETUP_RSP,         lli_no_setup_rsp},
+       {ST_OUT_DIAL,           EV_SETUP_ERR,           lli_setup_err},
+       {ST_OUT_DIAL,           EV_DLRL,                lli_got_dlrl},
+       {ST_IN_WAIT_LL,         EV_DLEST,               lli_d_established},
+       {ST_IN_WAIT_LL,         EV_DLRL,                lli_d_released},
+       {ST_IN_WAIT_LL,         EV_ACCEPTD,             lli_start_dchan},
+       {ST_IN_WAIT_LL,         EV_HANGUP,              lli_start_dchan},
+       {ST_IN_WAIT_LL,         EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_IN_WAIT_LL,         EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_IN_WAIT_LL,         EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_IN_ALERT_SEND,      EV_SETUP_CMPL_IND,      lli_init_bchan_in},
+       {ST_IN_ALERT_SEND,      EV_ACCEPTD,             lli_send_dconnect},
+       {ST_IN_ALERT_SEND,      EV_HANGUP,              lli_send_d_disc},
+       {ST_IN_ALERT_SEND,      EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_IN_ALERT_SEND,      EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_IN_ALERT_SEND,      EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_IN_ALERT_SEND,      EV_DLRL,                lli_got_dlrl},
+       {ST_IN_WAIT_CONN_ACK,   EV_SETUP_CMPL_IND,      lli_init_bchan_in},
+       {ST_IN_WAIT_CONN_ACK,   EV_HANGUP,              lli_send_d_disc},
+       {ST_IN_WAIT_CONN_ACK,   EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_IN_WAIT_CONN_ACK,   EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_IN_WAIT_CONN_ACK,   EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_IN_WAIT_CONN_ACK,   EV_CONNECT_ERR,         lli_connect_err},
+       {ST_IN_WAIT_CONN_ACK,   EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_BCONN,         EV_BC_EST,              lli_go_active},
+       {ST_WAIT_BCONN,         EV_BC_REL,              lli_send_d_disc},
+       {ST_WAIT_BCONN,         EV_HANGUP,              lli_send_d_disc},
+       {ST_WAIT_BCONN,         EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_WAIT_BCONN,         EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_WAIT_BCONN,         EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_WAIT_BCONN,         EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_BCONN,         EV_CINF,                lli_charge_info},
+       {ST_ACTIVE,             EV_CINF,                lli_charge_info},
+       {ST_ACTIVE,             EV_BC_REL,              lli_released_bchan},
+       {ST_ACTIVE,             EV_HANGUP,              lli_disconn_bchan},
+       {ST_ACTIVE,             EV_DISCONNECT_IND,      lli_release_bchan},
+       {ST_ACTIVE,             EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_ACTIVE,             EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_ACTIVE,             EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_BRELEASE,      EV_BC_REL,              lli_send_d_disc},
+       {ST_WAIT_BRELEASE,      EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_WAIT_BRELEASE,      EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_WAIT_BRELEASE,      EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_WAIT_BRELEASE,      EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_BREL_DISC,     EV_BC_REL,              lli_received_d_disc},
+       {ST_WAIT_BREL_DISC,     EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_WAIT_BREL_DISC,     EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_WAIT_BREL_DISC,     EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_DCOMMAND,      EV_HANGUP,              lli_send_d_disc},
+       {ST_WAIT_DCOMMAND,      EV_DISCONNECT_IND,      lli_received_d_disc},
+       {ST_WAIT_DCOMMAND,      EV_RELEASE_CNF,         lli_received_d_relcnf},
+       {ST_WAIT_DCOMMAND,      EV_RELEASE_IND,         lli_received_d_rel},
+       {ST_WAIT_DCOMMAND,      EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_DRELEASE,      EV_RELEASE_IND,         lli_timeout_d},
+       {ST_WAIT_DRELEASE,      EV_RELEASE_CNF,         lli_timeout_d},
+       {ST_WAIT_DRELEASE,      EV_RELEASE_ERR,         lli_timeout_d},
+       {ST_WAIT_DRELEASE,      EV_DIAL,                lli_no_dchan_ready},
+       {ST_WAIT_DRELEASE,      EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_D_REL_CNF,     EV_RELEASE_CNF,         lli_timeout_d},
+       {ST_WAIT_D_REL_CNF,     EV_RELEASE_ERR,         lli_timeout_d},
+/* ETS 300-104 16.1 */
+       {ST_WAIT_D_REL_CNF,     EV_RELEASE_IND,         lli_timeout_d},
+       {ST_WAIT_D_REL_CNF,     EV_DIAL,                lli_no_dchan_ready},
+       {ST_WAIT_D_REL_CNF,     EV_DLRL,                lli_got_dlrl},
+       {ST_WAIT_DSHUTDOWN,     EV_DLRL,                lli_go_null},
+       {ST_WAIT_DSHUTDOWN,     EV_DLEST,               lli_d_established},
+       {ST_WAIT_DSHUTDOWN,     EV_DIAL,                lli_prep_dialout},
+       {ST_WAIT_DSHUTDOWN,     EV_SETUP_IND,           lli_deliver_call},
 };
 /* *INDENT-ON* */
 
 
-
-
 #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
 static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
+lc_activate_l1(struct FsmInst *fi, int event, void *arg)
 {
        struct LcFsm *lf = fi->userdata;
 
+       FsmDelTimer(&lf->act_timer, 50);
        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);
+       /* This timeout is to avoid a hang if no L1 activation is possible */
+       FsmAddTimer(&lf->act_timer, 30000, EV_LC_TIMER, NULL, 50);
+       lf->st->ma.manl1(lf->st, PH_ACTIVATE_REQ, NULL);
+}
 
+static void
+lc_activated_from_l1(struct FsmInst *fi, int event, void *arg)
+{
+       struct LcFsm *lf = fi->userdata;
+
+       if (lf->l2_establish)
+               FsmChangeState(fi, ST_LC_DELAY);
+       else {
+               FsmChangeState(fi, ST_LC_CONNECTED);
+               lf->lccall(lf, LC_ESTABLISH, NULL);
+       }
 }
 
 static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
+lc_l1_activated(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);
+       /* This timer is needed for delay the first paket on a channel
+          to be shure that the other side is ready too */
+       if (lf->delay)
+               FsmAddTimer(&lf->act_timer, lf->delay, EV_LC_TIMER, NULL, 51);
+       else
+               FsmEvent(fi, EV_LC_TIMER, NULL);
 }
 
 static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
+lc_start_l2(struct FsmInst *fi, int event, void *arg)
 {
        struct LcFsm *lf = fi->userdata;
 
-       if (lf->l2_establish) {
+/*     if (!lf->st->l1.act_state)
+               lf->st->l1.act_state = 2;
+*/     if (lf->l2_establish) {
                FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
                if (lf->l2_start)
                        lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
@@ -1124,107 +1260,97 @@ lc_r2(struct FsmInst *fi, int event, void *arg)
 }
 
 static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
+lc_connected(struct FsmInst *fi, int event, void *arg)
 {
        struct LcFsm *lf = fi->userdata;
 
+       FsmDelTimer(&lf->act_timer, 50);
        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)
+lc_release_l2(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->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL);
                lf->lccall(lf, LC_RELEASE, NULL);
        }
 }
 
 static void
-lc_r4_1(struct FsmInst *fi, int event, void *arg)
+lc_l2_released(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);
+       FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+       FsmDelTimer(&lf->act_timer, 51);
+       /* This delay is needed for send out the UA frame before
+        * PH_DEACTIVATE the interface
+        */
+       FsmAddTimer(&lf->act_timer, 20, EV_LC_TIMER, NULL, 54);
 }
 
 static void
-lc_r5_1(struct FsmInst *fi, int event, void *arg)
+lc_release_l1(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);
+       FsmDelTimer(&lf->act_timer, 54);
+       FsmChangeState(fi, ST_LC_NULL);
+       lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL);
+       lf->lccall(lf, LC_RELEASE, NULL);
 }
 
 static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
+lc_l1_deactivated(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},
+static struct FsmNode LcFnList[] HISAX_INITDATA =
+{
+       {ST_LC_NULL,            EV_LC_ESTABLISH,        lc_activate_l1},
+       {ST_LC_NULL,            EV_LC_PH_ACTIVATE,      lc_activated_from_l1},
+       {ST_LC_NULL,            EV_LC_DL_ESTABLISH,     lc_connected},
+       {ST_LC_ACTIVATE_WAIT,   EV_LC_PH_ACTIVATE,      lc_l1_activated},
+       {ST_LC_ACTIVATE_WAIT,   EV_LC_TIMER,            lc_release_l1},
+       {ST_LC_ACTIVATE_WAIT,   EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
+       {ST_LC_DELAY,           EV_LC_ESTABLISH,        lc_start_l2},
+       {ST_LC_DELAY,           EV_LC_TIMER,            lc_start_l2},
+       {ST_LC_DELAY,           EV_LC_DL_ESTABLISH,     lc_connected},
+       {ST_LC_DELAY,           EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
+       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_ESTABLISH,     lc_connected},
+       {ST_LC_ESTABLISH_WAIT,  EV_LC_RELEASE,          lc_release_l1},
+       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_RELEASE,       lc_release_l1},
+       {ST_LC_ESTABLISH_WAIT,  EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
+       {ST_LC_CONNECTED,       EV_LC_ESTABLISH,        lc_connected},
+       {ST_LC_CONNECTED,       EV_LC_RELEASE,          lc_release_l2},
+       {ST_LC_CONNECTED,       EV_LC_DL_RELEASE,       lc_l2_released},
+       {ST_LC_CONNECTED,       EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
+       {ST_LC_FLUSH_WAIT,      EV_LC_TIMER,            lc_release_l2},
+       {ST_LC_FLUSH_WAIT,      EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
+       {ST_LC_RELEASE_WAIT,    EV_LC_DL_RELEASE,       lc_release_l1},
+       {ST_LC_RELEASE_WAIT,    EV_LC_TIMER,            lc_release_l1},
+       {ST_LC_FLUSH_WAIT,      EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
 };
 /* *INDENT-ON* */
 
 
-
-
-
-
-
-
-
-
 #define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
 
-void
-CallcNew(void)
+HISAX_INITFUNC(void
+CallcNew(void))
 {
        callcfsm.state_count = STATE_COUNT;
        callcfsm.event_count = EVENT_COUNT;
@@ -1247,17 +1373,11 @@ CallcFree(void)
 }
 
 static void
-release_ds(struct Channel *chanp)
+release_b_st(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);
+       struct PStack *st = chanp->b_st;
 
+       chanp->bcs->BC_Close(chanp->bcs);
        switch (chanp->l2_active_protocol) {
                case (ISDN_PROTO_L2_X75I):
                        releasestack_isdnl2(st);
@@ -1268,90 +1388,145 @@ release_ds(struct Channel *chanp)
                        break;
        }
        /* Reset B-Channel Statemachine */
-       FsmDelTimer(&chanp->lc_b.act_timer, 79);
-       FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL);
+       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)
+dc_l1man(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp;
 
+       chanp = (struct Channel *) st->lli.userdata;
        switch (pr) {
-               case (PH_ACTIVATE):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
+               case (PH_ACTIVATE_CNF):
+               case (PH_ACTIVATE_IND):
+                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_ACTIVATE, NULL);
                        break;
-               case (PH_DEACTIVATE):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+               case (PH_DEACTIVATE_IND):
+                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_DEACTIVATE, NULL);
                        break;
        }
 }
 
 static void
-cc_l2man(struct PStack *st, int pr, void *arg)
+dc_l2man(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
 
        switch (pr) {
                case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
+                       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);
+                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_RELEASE, NULL);
                        break;
        }
 }
 
 static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
+bc_l1man(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
 
        switch (pr) {
-               case (PH_ACTIVATE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
+               case (PH_ACTIVATE_IND):
+               case (PH_ACTIVATE_CNF):
+                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_ACTIVATE, NULL);
                        break;
-               case (PH_DEACTIVATE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+               case (PH_DEACTIVATE_IND):
+                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_DEACTIVATE, NULL);
                        break;
        }
 }
 
 static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
+bc_l2man(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
 
        switch (pr) {
                case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
                        break;
                case (DL_RELEASE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_RELEASE, NULL);
                        break;
        }
 }
 
-static void
-l2tei_dummy(struct PStack *st, int pr, void *arg)
+struct Channel
+*selectfreechannel(struct PStack *st)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
-       char tmp[64], tm[32];
+       struct IsdnCardState *cs = st->l1.hardware;
+       struct Channel *chanp = st->lli.userdata;
+       int i;
 
-       jiftime(tm, jiffies);
-       sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr);
-       HiSax_putstatus(chanp->sp, tmp);
+       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+               i=1;
+       else
+               i=0;
+       while (i<2) {
+               if (chanp->fi.state == ST_NULL)
+                       return (chanp);
+               chanp++;
+               i++;
+       }               
+       return (NULL);
+}
+
+int
+is_activ(struct PStack *st)
+{
+       struct IsdnCardState *cs = st->l1.hardware;
+       struct Channel *chanp = st->lli.userdata;
+       int i;
+
+       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+               i=1;
+       else
+               i=0;
+       while (i<2) {
+               if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+                       return (1);
+               chanp++;
+               i++;
+       }               
+       return (0);
 }
 
 static void
-ll_handler(struct PStack *st, int pr, void *arg)
+ll_handler(struct l3_process *pc, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp;
        char tmp[64], tm[32];
 
+       if (pr == CC_SETUP_IND) {
+               if (!(chanp = selectfreechannel(pc->st))) {
+                       pc->st->lli.l4l3(pc->st, CC_DLRL, pc);
+                       return;
+               } else {
+                       chanp->proc = pc;
+                       pc->chan = chanp;
+                       FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+                       return;
+               }
+       } else if (pr == CC_ESTABLISH) {
+               if (is_activ(pc->st)) {
+                       pc->st->lli.l4l3(pc->st, CC_ESTABLISH, pc);
+                       return;
+               } else if (!(chanp = selectfreechannel(pc->st))) {
+                       pc->st->lli.l4l3(pc->st, CC_DLRL, pc);
+                       return;
+               } else {
+                       chanp->proc = pc;
+                       FsmEvent(&chanp->fi, EV_ESTABLISH, NULL);
+                       return;
+               }
+
+                       
+       }
+       chanp = pc->chan;
        switch (pr) {
                case (CC_DISCONNECT_IND):
                        FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
@@ -1359,9 +1534,6 @@ ll_handler(struct PStack *st, int pr, void *arg)
                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;
@@ -1386,49 +1558,51 @@ ll_handler(struct PStack *st, int pr, void *arg)
                case (CC_RELEASE_ERR):
                        FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
                        break;
+               case (CC_PROCEEDING_IND):
+               case (CC_ALERTING_IND):
+                       break;
                default:
-                       if (chanp->debug & 2048) {
+                       if (chanp->debug & 0x800) {
                                jiftime(tm, jiffies);
                                sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n",
                                        tm, chanp->chan, pr);
-                               HiSax_putstatus(chanp->sp, tmp);
+                               HiSax_putstatus(chanp->cs, tmp);
                        }
        }
 }
 
 static void
-init_is(struct Channel *chanp, unsigned int ces)
+init_d_st(struct Channel *chanp)
 {
-       struct PStack *st = &chanp->is;
-       struct IsdnCardState *sp = chanp->sp;
+       struct PStack *st = chanp->d_st;
+       struct IsdnCardState *cs = chanp->cs;
        char tmp[128];
 
-       setstack_HiSax(st, sp);
+       HiSax_addlist(cs, st);
+       setstack_HiSax(st, cs);
        st->l2.sap = 0;
-       st->l2.tei = 255;
-       st->l2.ces = ces;
-       st->l2.extended = !0;
-       st->l2.laptype = LAPD;
+       st->l2.tei = -1;
+       st->l2.flag = 0;
+       test_and_set_bit(FLG_MOD128, &st->l2.flag);
+       test_and_set_bit(FLG_LAPD, &st->l2.flag);
+       test_and_set_bit(FLG_ORIG, &st->l2.flag);
+       st->l2.maxlen = MAX_DFRAME_LEN;
        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  */
-       }
+       st->l2.T200 = 1000;     /* 1000 milliseconds  */
+       st->l2.N200 = 3;        /* try 3 times        */
+       if (st->protocol == ISDN_PTYPE_1TR6)
+               st->l2.T203 = 10000;    /* 10000 milliseconds */
+       else
+               st->l2.T203 = 10000;    /* 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->lli.userdata = chanp;
+       st->lli.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);
+       st->l1.l1man = dc_l1man;
+       st->l2.l2man = dc_l2man;
 }
 
 static void
@@ -1439,7 +1613,7 @@ callc_debug(struct FsmInst *fi, char *s)
 
        jiftime(tm, jiffies);
        sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
-       HiSax_putstatus(chanp->sp, str);
+       HiSax_putstatus(chanp->cs, str);
 }
 
 static void
@@ -1449,8 +1623,8 @@ lc_debug(struct FsmInst *fi, char *s)
        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);
+       sprintf(str, "%s Channel %d dc %s\n", tm, lf->ch->chan, s);
+       HiSax_putstatus(lf->ch->cs, str);
 }
 
 static void
@@ -1460,22 +1634,35 @@ dlc_debug(struct FsmInst *fi, char *s)
        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);
+       sprintf(str, "%s Channel %d bc %s\n", tm, lf->ch->chan, s);
+       HiSax_putstatus(lf->ch->cs, str);
 }
 
 static void
 lccall_d(struct LcFsm *lf, int pr, void *arg)
 {
-       struct Channel *chanp = lf->ch;
+       struct IsdnCardState *cs = lf->st->l1.hardware;
+       struct Channel *chanp;
+       int i;
 
-       switch (pr) {
-               case (LC_ESTABLISH):
-                       FsmEvent(&chanp->fi, EV_DLEST, NULL);
-                       break;
-               case (LC_RELEASE):
-                       FsmEvent(&chanp->fi, EV_DLRL, NULL);
-                       break;
+       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) {
+               chanp = lf->ch;
+               i = 1;
+       } else {
+               chanp = cs->channel;
+               i = 0;
+       }
+       while (i < 2) {
+               switch (pr) {
+                       case (LC_ESTABLISH):
+                               FsmEvent(&chanp->fi, EV_DLEST, NULL);
+                               break;
+                       case (LC_RELEASE):
+                               FsmEvent(&chanp->fi, EV_DLRL, NULL);
+                               break;
+               }
+               chanp++;
+               i++;
        }
 }
 
@@ -1495,20 +1682,19 @@ lccall_b(struct LcFsm *lf, int pr, void *arg)
 }
 
 static void
-init_chan(int chan, struct IsdnCardState *csta, int hscx,
-         unsigned int ces)
+init_chan(int chan, struct IsdnCardState *csta)
 {
        struct Channel *chanp = csta->channel + chan;
 
-       chanp->sp = csta;
-       chanp->hscx = hscx;
+       chanp->cs = csta;
+       chanp->bcs = csta->bcs + chan;
        chanp->chan = chan;
        chanp->incoming = 0;
        chanp->debug = 0;
        chanp->Flags = 0;
        chanp->leased = 0;
-       chanp->impair = 0;
-       init_is(chanp, ces);
+       chanp->b_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+       chanp->b_st->next = NULL;
 
        chanp->fi.fsm = &callcfsm;
        chanp->fi.state = ST_NULL;
@@ -1517,58 +1703,72 @@ init_chan(int chan, struct IsdnCardState *csta, int hscx,
        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;
+       if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+               chanp->d_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+               chanp->d_st->next = NULL;
+               init_d_st(chanp);
+               chanp->lc_d = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
+               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->delay = 0;
+               chanp->lc_d->ch = chanp;
+               chanp->lc_d->st = chanp->d_st;
+               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);
+       } else {
+               chanp->d_st = csta->channel->d_st;
+               chanp->lc_d = csta->channel->lc_d;
+       }
+       chanp->lc_b = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
+       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->delay = DEFAULT_B_DELAY;
+       chanp->lc_b->ch = chanp;
+       chanp->lc_b->st = chanp->b_st;
+       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->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++);
+       init_chan(0, csta);
+       init_chan(1, csta);
        printk(KERN_INFO "HiSax: 2 channels added\n");
+#ifdef LAYER2_WATCHING
+       printk(KERN_INFO "LAYER2 ESTABLISH\n");
+       test_and_set_bit(FLG_START_D, &csta->channel->Flags);
+       FsmEvent(&csta->channel->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+#endif
        return (2);
 }
 
 static void
-release_is(struct Channel *chanp)
+release_d_st(struct Channel *chanp)
 {
-       struct PStack *st = &chanp->is;
+       struct PStack *st = chanp->d_st;
 
+       if (!st)
+               return;
        releasestack_isdnl2(st);
        releasestack_isdnl3(st);
        HiSax_rmlist(st->l1.hardware, st);
+       kfree(st);
+       chanp->d_st = NULL;
 }
 
 void
@@ -1579,27 +1779,45 @@ CallcFreeChan(struct IsdnCardState *csta)
        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);
+               FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77);
+               FsmDelTimer(&csta->channel[i].lc_b->act_timer, 76);
+               if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
+                       release_d_st(csta->channel + i);
+               if (csta->channel[i].b_st) {
+                       if (test_and_clear_bit(FLG_START_B, &csta->channel[i].Flags))
+                               release_b_st(csta->channel + i);
+                       kfree(csta->channel[i].b_st);
+                       csta->channel[i].b_st = NULL;
+               } else
+                       printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
+               if (csta->channel[i].lc_b) {
+                       kfree(csta->channel[i].lc_b);
+                       csta->channel[i].b_st = NULL;
                }
-               release_is(csta->channel + i);
+               if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+                       release_d_st(csta->channel + i);
+                       FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77);
+                       if (csta->channel[i].lc_d) {
+                               kfree(csta->channel[i].lc_d);
+                               csta->channel[i].d_st = NULL;
+                       } else
+                               printk(KERN_WARNING "CallcFreeChan lc_d ch%d allready freed\n", i);
+               } else
+                       csta->channel[i].d_st = NULL;
        }
 }
 
 static void
 lldata_handler(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp = (struct Channel *) st->lli.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);
+                               chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
                        else {
-                               SET_SKB_FREE(skb);
                                dev_kfree_skb(skb);
                        }
                        break;
@@ -1613,16 +1831,22 @@ lldata_handler(struct PStack *st, int pr, void *arg)
 static void
 lltrans_handler(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
        struct sk_buff *skb = arg;
 
        switch (pr) {
-               case (PH_DATA):
+               case (PH_DATA_IND):
                        if (chanp->data_open)
-                               chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+                               chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
                        else {
-                               SET_SKB_FREE(skb);
-                               dev_kfree_skb(skb);
+                               if (chanp->lc_b->lcfi.state == ST_LC_DELAY)
+                                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
+                               if (chanp->data_open) {
+                                       link_debug(chanp, "channel now open", 0);
+                                       chanp->cs->iif.rcvcallb_skb(chanp->cs->myid,
+                                               chanp->chan, skb);
+                               } else
+                                       dev_kfree_skb(skb);
                        }
                        break;
                default:
@@ -1633,73 +1857,79 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
 }
 
 static void
-ll_writewakeup(struct PStack *st)
+ll_writewakeup(struct PStack *st, int len)
 {
-       struct Channel *chanp = st->l4.userdata;
+       struct Channel *chanp = st->lli.userdata;
        isdn_ctrl ic;
 
-       ic.driver = chanp->sp->myid;
+       ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_BSENT;
        ic.arg = chanp->chan;
-       chanp->sp->iif.statcallb(&ic);
+       ic.parm.length = len;
+       chanp->cs->iif.statcallb(&ic);
 }
 
 static int
-init_ds(struct Channel *chanp, int incoming)
+init_b_st(struct Channel *chanp, int incoming)
 {
-       struct PStack *st = &chanp->ds;
-       struct IsdnCardState *sp = chanp->sp;
-       struct HscxState *hsp = sp->hs + chanp->hscx;
+       struct PStack *st = chanp->b_st;
+       struct IsdnCardState *cs = chanp->cs;
        char tmp[128];
 
-       st->l1.hardware = sp;
-
-       hsp->mode = 2;
-
-       if (setstack_hscx(st, hsp))
+       st->l1.hardware = cs;
+       chanp->bcs->mode = 2;
+       if (chanp->bcs->BC_SetStack(st, chanp->bcs))
                return (-1);
-
-       st->l2.extended = 0;
-       st->l2.laptype = LAPB;
-       st->l2.orig = !incoming;
-       st->l2.t200 = 1000;     /* 1000 milliseconds */
+       st->l2.flag = 0;
+       test_and_set_bit(FLG_LAPB, &st->l2.flag);
+       st->l2.maxlen = MAX_DATA_SIZE;
+       if (!incoming)
+               test_and_set_bit(FLG_ORIG, &st->l2.flag);
+       st->l2.T200 = 1000;     /* 1000 milliseconds */
        st->l2.window = 7;
-       st->l2.n200 = 4;        /* try 4 times       */
-       st->l2.t203 = 5000;     /* 5000 milliseconds */
-
+       st->l2.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->l1.l1man = bc_l1man;
+                       st->l2.l2man = bc_l2man;
+                       st->lli.userdata = chanp;
+                       st->lli.l1writewakeup = NULL;
+                       st->lli.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;
+                       st->l1.mode = L1_MODE_HDLC;
+                       if (chanp->leased)
+                               st->l1.bc = chanp->chan & 1;
+                       else
+                               st->l1.bc = chanp->proc->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;
+                       st->l1.l1man = bc_l1man;
+                       st->lli.userdata = chanp;
+                       st->lli.l1writewakeup = ll_writewakeup;
+                       st->l1.mode = L1_MODE_HDLC;
+                       if (chanp->leased)
+                               st->l1.bc = chanp->chan & 1;
+                       else
+                               st->l1.bc = chanp->proc->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;
+                       st->l1.l1man = bc_l1man;
+                       st->lli.userdata = chanp;
+                       st->lli.l1writewakeup = ll_writewakeup;
+                       st->l1.mode = L1_MODE_TRANS;
+                       if (chanp->leased)
+                               st->l1.bc = chanp->chan & 1;
+                       else
+                               st->l1.bc = chanp->proc->para.bchannel - 1;
                        break;
        }
        return (0);
@@ -1719,15 +1949,17 @@ distr_debug(struct IsdnCardState *csta, int debugflags)
        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;
+               chanp[i].d_st->l2.l2m.debug = debugflags & 8;
+               chanp[i].b_st->l2.l2m.debug = debugflags & 0x10;
+               chanp[i].d_st->l2.debug = debugflags & 0x20;
+               chanp[i].b_st->l2.debug = debugflags & 0x40;
+               chanp[i].lc_d->lcfi.debug = debugflags & 0x80;
+               chanp[i].lc_b->lcfi.debug = debugflags & 0x100;
+               chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200;
+               chanp[i].b_st->ma.debug = debugflags & 0x200;
+               chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000;
        }
        csta->dlogflag = debugflags & 4;
-       csta->teistack->l2.l2m.debug = debugflags & 512;
 }
 
 int
@@ -1748,8 +1980,11 @@ HiSax_command(isdn_ctrl * ic)
        switch (ic->command) {
                case (ISDN_CMD_SETEAZ):
                        chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1)
-                               link_debug(chanp, "SETEAZ", 1);
+                       if (chanp->debug & 1) {
+                               sprintf(tmp, "SETEAZ card %d %s", csta->cardnr + 1,
+                                       ic->parm.num);
+                               link_debug(chanp, tmp, 1);
+                       }
                        break;
                case (ISDN_CMD_SETL2):
                        chanp = csta->channel + (ic->arg & 0xff);
@@ -1768,9 +2003,9 @@ HiSax_command(isdn_ctrl * ic)
                                 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';
+                       chanp->setup = ic->parm.setup;
+                       if (!strcmp(chanp->setup.eazmsn, "0"))
+                               chanp->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) {
@@ -1817,7 +2052,7 @@ HiSax_command(isdn_ctrl * ic)
                case (ISDN_CMD_LOCK):
                        HiSax_mod_inc_use_count();
 #ifdef MODULE
-                       if (csta->channel[0].debug & 1024) {
+                       if (csta->channel[0].debug & 0x400) {
                                jiftime(tmp, jiffies);
                                i = strlen(tmp);
                                sprintf(tmp + i, "   LOCK modcnt %lx\n", MOD_USE_COUNT);
@@ -1828,7 +2063,7 @@ HiSax_command(isdn_ctrl * ic)
                case (ISDN_CMD_UNLOCK):
                        HiSax_mod_dec_use_count();
 #ifdef MODULE
-                       if (csta->channel[0].debug & 1024) {
+                       if (csta->channel[0].debug & 0x400) {
                                jiftime(tmp, jiffies);
                                i = strlen(tmp);
                                sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT);
@@ -1852,16 +2087,13 @@ HiSax_command(isdn_ctrl * ic)
                                        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);
-                                       }
+                                       num = *(unsigned int *) ic->parm.num; 
+                                       csta->channel[0].lc_b->delay = num;
+                                       csta->channel[1].lc_b->delay = num;
+                                       sprintf(tmp, "delay card %d set to %d ms\n",
+                                               csta->cardnr + 1, num);
+                                       HiSax_putstatus(csta, tmp);
+                                       printk(KERN_DEBUG "HiSax: %s", tmp);
                                        break;
                                case (3):
                                        for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
@@ -1872,35 +2104,47 @@ HiSax_command(isdn_ctrl * ic)
                                                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);
+                                       num = *(unsigned int *) ic->parm.num;
+                                       if ((num <1) || (num > 2)) {
+                                               sprintf(tmp, "Set LEASED wrong channel %d\n",
+                                                       num);
+                                               HiSax_putstatus(csta, tmp);
+                                               printk(KERN_WARNING "HiSax: %s", tmp);
+                                       } else {
+                                               num--;
+                                               csta->channel[num].leased = 1;
+                                               csta->channel[num].lc_d->l2_establish = 0;
+                                               sprintf(tmp, "card %d channel %d set leased mode\n",
+                                                       csta->cardnr + 1, num + 1);
+                                               HiSax_putstatus(csta, tmp);
+                                               FsmEvent(&csta->channel[num].lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+                                       }
+                                       break;
+                               case (6):       /* set B-channel test loop */
+                                       num = *(unsigned int *) ic->parm.num;
+                                       if (csta->stlist)
+                                               csta->stlist->ma.manl1(csta->stlist,
+                                                       PH_TESTLOOP_REQ, (void *) num);
                                        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);
+                                               csta->cardnr + 1, csta->debug);
+                                       HiSax_putstatus(cards[0].cs, 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;
+                                       csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num;
+                                       csta->channel[1].d_st->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);
+                                       HiSax_putstatus(cards[0].cs, tmp);
                                        printk(KERN_DEBUG "HiSax: %s", tmp);
                                        break;
                                default:
@@ -1917,7 +2161,7 @@ HiSax_command(isdn_ctrl * ic)
 }
 
 int
-HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
+HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
 {
        struct IsdnCardState *csta = hisax_findcard(id);
        struct Channel *chanp;
@@ -1933,7 +2177,7 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
                return -ENODEV;
        }
        chanp = csta->channel + chan;
-       st = &chanp->ds;
+       st = chanp->b_st;
        if (!chanp->data_open) {
                link_debug(chanp, "writebuf: channel not open", 1);
                return -EIO;
@@ -1945,11 +2189,11 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
                return -EINVAL;
        }
        if (len) {
-               if ((len + csta->hs[chanp->hscx].tx_cnt) > MAX_DATA_MEM) {
+               if ((len + chanp->bcs->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) {
+                       if (chanp->debug & 0x800) {
                                sprintf(tmp, "writebuf: no buffers for %d bytes", len);
                                link_debug(chanp, tmp, 1);
                        }
@@ -1959,12 +2203,13 @@ HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
                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);
+                       if (!ack)
+                               nskb->pkt_type = PACKET_NOACK;
+                       if (chanp->lc_b->l2_establish)
+                               st->l3.l3l2(st, DL_DATA, nskb);
+                       else {
+                               chanp->bcs->tx_cnt += len;
+                               st->l2.l2l1(st, PH_DATA_REQ, nskb);
                        }
                        dev_kfree_skb(skb);
                } else
index 7379c8a779e5caef87f1309290312031a2058cbd..67e308e43d1bc4a4f3cbe0508d1abefcf2156212 100644 (file)
@@ -1,58 +1,53 @@
-/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $
+/* $Id: config.c,v 2.12 1998/02/11 17:28:02 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 2.12  1998/02/11 17:28:02  keil
+ * Niccy PnP/PCI support
  *
- * Revision 1.14  1997/03/25 23:11:22  keil
- * US NI-1 protocol
+ * Revision 2.11  1998/02/09 21:26:13  keil
+ * fix export module for 2.1
  *
- * Revision 1.13  1997/03/23 21:45:49  keil
- * Add support for ELSA PCMCIA
+ * Revision 2.10  1998/02/09 18:46:05  keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
  *
- * Revision 1.12  1997/03/11 21:01:43  keil
- * nzproto is only used with modules
+ * Revision 2.9  1998/02/03 23:31:28  keil
+ * add AMD7930 support
  *
- * Revision 1.11  1997/02/14 12:23:12  fritz
- * Added support for new insmod parameter handling.
+ * Revision 2.8  1998/02/02 13:32:59  keil
+ * New card support
  *
- * Revision 1.10  1997/02/14 09:22:09  keil
- * Final 2.0 version
+ * Revision 2.7  1998/01/31 21:41:44  keil
+ * changes for newer 2.1 kernels
  *
- * Revision 1.9  1997/02/10 11:45:09  fritz
- * More changes for Kernel 2.1.X compatibility.
+ * Revision 2.6  1997/11/08 21:35:43  keil
+ * new l1 init
  *
- * Revision 1.8  1997/02/09 00:28:05  keil
- * new interface handling, one interface per card
- * default protocol now works again
+ * Revision 2.5  1997/11/06 17:15:08  keil
+ * New 2.1 init; PCMCIA wrapper changes
  *
- * Revision 1.7  1997/01/27 15:56:57  keil
- * Teles PCMCIA ITK ix1 micro added
+ * Revision 2.4  1997/10/29 19:07:52  keil
+ * changes for 2.1
  *
- * Revision 1.6  1997/01/21 22:17:56  keil
- * new module load syntax
+ * Revision 2.3  1997/10/01 09:21:33  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
  *
- * Revision 1.5  1997/01/09 18:28:20  keil
- * cosmetic cleanups
+ * Revision 2.2  1997/09/11 17:24:46  keil
+ * Add new cards
  *
- * 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
+ * Revision 2.1  1997/07/27 21:41:35  keil
+ * version change
  *
+ * Revision 2.0  1997/06/26 11:06:28  keil
+ * New card and L1 interface.
+ * Eicon.Diehl Diva and Dynalink IS64PH support
  *
+ * old changes removed /KKe
  *
  */
 #include <linux/types.h>
  * { 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
+ *    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
+ *    8 Teles PCMCIA     p0=irq p1=iobase
+ *    9 ITK ix1-micro    p0=irq p1=iobase
+ *   10 ELSA PCMCIA      p0=irq p1=iobase
+ *   11 Eicon.Diehl Diva p0=irq p1=iobase
+ *   12 Asuscom ISDNLink p0=irq p1=iobase
+ *   13 Teleint          p0=irq p1=iobase
+ *   14 Teles 16.3c      p0=irq p1=iobase
+ *   15 Sedlbauer speed  p0=irq p1=iobase
+ *   16 USR Sportster internal  p0=irq  p1=iobase
+ *   17 MIC card                p0=irq  p1=iobase
+ *   18 ELSA Quickstep 1000PCI  no parameter
+ *   19 Compaq ISDN S0 ISA card p0=irq  p1=IO0 (HSCX)  p2=IO1 (ISAC) p3=IO2
+ *   20 Travers Technologies NETjet PCI card
+ *   21 reserved TELES PCI
+ *   22 Sedlbauer Speed Star    p0=irq p1=iobase
+ *   23 reserved
+ *   24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only)
  *
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
  */
 
-#ifdef CONFIG_HISAX_ELSA_PCC
+#ifdef CONFIG_HISAX_ELSA
 #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}
+#define DEFAULT_CFG {0,0,0,0}
+int elsa_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(elsa_init_pcmcia);
 #endif
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1
-#define DEFAULT_CFG {10,0x340,0}
+#define DEFAULT_CFG {10,0x340,0,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}
+#define DEFAULT_CFG {15,0x180,0,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}
+#define DEFAULT_CFG {15,0xd0000,0xd80,0}
 #endif
 
 #ifdef CONFIG_HISAX_IX1MICROR2
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
-#define DEFAULT_CFG {5,0x390,0}
+#define DEFAULT_CFG {5,0x390,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_DIEHLDIVA
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA
+#define DEFAULT_CFG {0,0x0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_ASUSCOM
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM
+#define DEFAULT_CFG {5,0x200,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_TELEINT
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELEINT
+#define DEFAULT_CFG {5,0x300,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_SEDLBAUER
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
+#define DEFAULT_CFG {11,0x270,0,0}
+int sedl_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(sedl_init_pcmcia);
+#endif
+
+#ifdef CONFIG_HISAX_SPORTSTER
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER
+#define DEFAULT_CFG {7,0x268,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_MIC
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_MIC
+#define DEFAULT_CFG {12,0x3e0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_NETJET
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NETJET
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_TELES3C
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELES3C
+#define DEFAULT_CFG {5,0x500,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_AMD7930
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_AMD7930
+#define DEFAULT_CFG {12,0x3e0,0,0}
+#endif
+
+#ifdef CONFIG_HISAX_NICCY
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NICCY
+#define DEFAULT_CFG {0,0x0,0,0}
 #endif
 
 #ifdef CONFIG_HISAX_1TR6
   NULL, \
 }
 
-#define EMPTY_CARD     {0, DEFAULT_PROTO, {0, 0, 0}, NULL}
+#define EMPTY_CARD     {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
 
 struct IsdnCard cards[] =
 {
@@ -172,55 +251,63 @@ struct IsdnCard cards[] =
        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" \
+static char HiSaxID[96] HISAX_INITDATA = "\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;
+char *HiSax_id HISAX_INITDATA = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-static int type[] =
+static int type[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int protocol[] =
+static int protocol[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int io[] =
+static int io[] HISAX_INITDATA =
 {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 */
-static int io0[] =
+#undef IO0_IO1
+#ifdef CONFIG_HISAX_16_3
+#define IO0_IO1
+#endif
+#ifdef CONFIG_HISAX_NICCY
+#undef IO0_IO1
+#define IO0_IO1
+#endif
+#ifdef IO0_IO1
+static int io0[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int io1[] =
+static int io1[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #endif
-static int irq[] =
+static int irq[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static int mem[] =
+static int mem[] HISAX_INITDATA =
 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static char *id = HiSaxID;
+static char *id HISAX_INITDATA = 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(type, "1-3i");
+MODULE_PARM(protocol, "1-2i");
+MODULE_PARM(io, "1-8i");
+MODULE_PARM(irq, "1-2i");
+MODULE_PARM(mem, "1-12i");
 MODULE_PARM(id, "s");
 #ifdef CONFIG_HISAX_16_3       /* For Creatix/Teles PnP */
-MODULE_PARM(io0, "1-16i");
-MODULE_PARM(io1, "1-16i");
-#endif
+MODULE_PARM(io0, "1-8i");
+MODULE_PARM(io1, "1-8i");
 #endif
 
 #endif
 
+int nrcards;
+
 extern char *l1_revision;
 extern char *l2_revision;
 extern char *l3_revision;
-extern char *l4_revision;
+extern char *lli_revision;
 extern char *tei_revision;
 
-char *
-HiSax_getrev(const char *revision)
+HISAX_INITFUNC(char *
+HiSax_getrev(const char *revision))
 {
        char *rev;
        char *p;
@@ -234,7 +321,27 @@ HiSax_getrev(const char *revision)
        return rev;
 }
 
-int nrcards;
+HISAX_INITFUNC(void
+HiSaxVersion(void))
+{
+       char tmp[64], rev[64];
+       char *r = rev;
+
+       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, lli_revision);
+       r += sprintf(r, "%s/", HiSax_getrev(tmp));
+       strcpy(tmp, tei_revision);
+       r += sprintf(r, "%s", HiSax_getrev(tmp));
+
+       printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n");
+       printk(KERN_INFO "HiSax: Version 2.8\n");
+       printk(KERN_INFO "HiSax: Revisions %s\n", rev);
+}
 
 void
 HiSax_mod_dec_use_count(void)
@@ -251,8 +358,8 @@ HiSax_mod_inc_use_count(void)
 #ifdef MODULE
 #define HiSax_init init_module
 #else
-void
-HiSax_setup(char *str, int *ints)
+__initfunc(void
+HiSax_setup(char *str, int *ints))
 {
        int i, j, argc;
 
@@ -297,31 +404,28 @@ HiSax_setup(char *str, int *ints)
 }
 #endif
 
-int
-HiSax_init(void)
+__initfunc(int
+HiSax_init(void))
 {
        int i;
-       char tmp[64], rev[64];
-       char *r = rev;
+       
 #ifdef MODULE
        int nzproto = 0;
+#ifdef CONFIG_HISAX_ELSA
+       if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
+               /* we have exported  and return in this case */
+               return 0;
+       }
+#endif
+#ifdef CONFIG_HISAX_SEDLBAUER
+       if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
+               /* we have to export  and return in this case */
+               return 0;
+       }
+#endif
 #endif
+       HiSaxVersion();
        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;
@@ -343,37 +447,44 @@ HiSax_init(void)
                                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 */
+#ifdef IO0_IO1
                        case ISDN_CTYPE_PNP:
+                       case ISDN_CTYPE_NICCY:
                                cards[i].para[0] = irq[i];
                                cards[i].para[1] = io0[i];
                                cards[i].para[2] = io1[i];
                                break;
-#endif
-                       case ISDN_CTYPE_A1:
+                       case ISDN_CTYPE_COMPAQ_ISA:
                                cards[i].para[0] = irq[i];
-                               cards[i].para[1] = io[i];
+                               cards[i].para[1] = io0[i];
+                               cards[i].para[2] = io1[i];
+                               cards[i].para[3] = io[i];
                                break;
-
+#endif
                        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_16_3:
+                       case ISDN_CTYPE_TELESPCMCIA:
+                       case ISDN_CTYPE_A1:
+                       case ISDN_CTYPE_ELSA_PNP:
+                       case ISDN_CTYPE_ELSA_PCMCIA:
                        case ISDN_CTYPE_IX1MICROR2:
+                       case ISDN_CTYPE_DIEHLDIVA:
+                       case ISDN_CTYPE_ASUSCOM:
+                       case ISDN_CTYPE_TELEINT:
+                       case ISDN_CTYPE_SEDLBAUER:
+                       case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+                       case ISDN_CTYPE_SPORTSTER:
+                       case ISDN_CTYPE_MIC:
+                       case ISDN_CTYPE_TELES3C:
                                cards[i].para[0] = irq[i];
                                cards[i].para[1] = io[i];
                                break;
-
+                       case ISDN_CTYPE_ELSA_PCI:
+                       case ISDN_CTYPE_NETJET:
+                       case ISDN_CTYPE_AMD7930:
+                               break;
                }
        }
        if (!nzproto) {
@@ -394,20 +505,20 @@ HiSax_init(void)
 
        CallcNew();
        Isdnl2New();
-       if (HiSax_inithardware()) {
+       TeiNew();
+       Isdnl1New();
+       if (HiSax_inithardware(NULL)) {
                /* 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");
+               printk(KERN_INFO "HiSax: module installed\n");
 #endif
                return (0);
        } else {
+               Isdnl1Free();
+               TeiFree();
                Isdnl2Free();
                CallcFree();
                return -EIO;
@@ -419,7 +530,101 @@ void
 cleanup_module(void)
 {
        HiSax_closehardware();
-       printk(KERN_NOTICE "HiSax module removed\n");
+       printk(KERN_INFO "HiSax module removed\n");
 }
 
+#ifdef CONFIG_HISAX_ELSA
+int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+       int i;
+       int nzproto = 0;
+
+       nrcards = 0;
+       HiSaxVersion();
+       if (id)                 /* If id= string used */
+               HiSax_id = id;
+       /* Initialize all 16 structs, even though we only accept
+          two pcmcia cards
+          */
+       for (i = 0; i < 16; i++) {
+               cards[i].para[0] = irq[i];
+               cards[i].para[1] = io[i];
+               cards[i].typ = type[i];
+               if (protocol[i]) {
+                       cards[i].protocol = protocol[i];
+                       nzproto++;
+               }
+       }
+       cards[0].para[0] = pcm_irq;
+       cards[0].para[1] = (int)pcm_iob;
+       cards[0].protocol = prot;
+       cards[0].typ = 10;
+       nzproto = 1;
+
+       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" : "");
+
+       Isdnl1New();
+       CallcNew();
+       Isdnl2New();
+       TeiNew();
+       HiSax_inithardware(busy_flag);
+       printk(KERN_NOTICE "HiSax: module installed\n");
+       return (0);
+}
+#endif
+#ifdef CONFIG_HISAX_SEDLBAUER
+int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+       int i;
+       int nzproto = 0;
+
+       nrcards = 0;
+       HiSaxVersion();
+       if (id)                 /* If id= string used */
+               HiSax_id = id;
+       /* Initialize all 16 structs, even though we only accept
+          two pcmcia cards
+          */
+       for (i = 0; i < 16; i++) {
+               cards[i].para[0] = irq[i];
+               cards[i].para[1] = io[i];
+               cards[i].typ = type[i];
+               if (protocol[i]) {
+                       cards[i].protocol = protocol[i];
+                       nzproto++;
+               }
+       }
+       cards[0].para[0] = pcm_irq;
+       cards[0].para[1] = (int)pcm_iob;
+       cards[0].protocol = prot;
+       cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+       nzproto = 1;
+
+       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" : "");
+
+       Isdnl1New();
+       CallcNew();
+       Isdnl2New();
+       TeiNew();
+       HiSax_inithardware(busy_flag);
+       printk(KERN_NOTICE "HiSax: module installed\n");
+       return (0);
+}
 #endif
+#endif 
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
new file mode 100644 (file)
index 0000000..fa3a45b
--- /dev/null
@@ -0,0 +1,465 @@
+/* $Id: diva.c,v 1.5 1998/02/02 13:29:38 keil Exp $
+
+ * diva.c     low level stuff for Eicon.Diehl Diva Family ISDN cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations
+ *
+ *
+ * $Log: diva.c,v $
+ * Revision 1.5  1998/02/02 13:29:38  keil
+ * fast io
+ *
+ * Revision 1.4  1997/11/08 21:35:44  keil
+ * new l1 init
+ *
+ * Revision 1.3  1997/11/06 17:13:33  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 18:55:55  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1  1997/09/18 17:11:20  keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+extern const char *CardType[];
+
+const char *Diva_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define DIVA_HSCX_DATA         0
+#define DIVA_HSCX_ADR          4
+#define DIVA_ISA_ISAC_DATA     2
+#define DIVA_ISA_ISAC_ADR      6
+#define DIVA_ISA_CTRL          7
+
+#define DIVA_PCI_ISAC_DATA     8
+#define DIVA_PCI_ISAC_ADR      0xc
+#define DIVA_PCI_CTRL          0x10
+
+/* SUB Types */
+#define DIVA_ISA       1
+#define DIVA_PCI       2
+
+/* PCI stuff */
+#define PCI_VENDOR_EICON_DIEHL 0x1133
+#define PCI_DIVA20PRO_ID       0xe001
+#define PCI_DIVA20_ID          0xe002
+#define PCI_DIVA20PRO_U_ID     0xe003
+#define PCI_DIVA20_U_ID                0xe004
+
+/* CTRL (Read) */
+#define DIVA_IRQ_STAT  0x01
+#define DIVA_EEPROM_SDA        0x02
+/* CTRL (Write) */
+#define DIVA_IRQ_REQ   0x01
+#define DIVA_RESET     0x08
+#define DIVA_EEPROM_CLK        0x40
+#define DIVA_PCI_LED_A 0x10
+#define DIVA_PCI_LED_B 0x20
+#define DIVA_ISA_LED_A 0x20
+#define DIVA_ISA_LED_B 0x40
+#define DIVA_IRQ_CLR   0x80
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo read without cli because it's allready done  */
+
+       byteout(ale, off);
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
+{
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+       readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
+}
+
+static void 
+WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+       writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return(readreg(cs->hw.diva.hscx_adr,
+               cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.diva.hscx_adr,
+               cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \
+               cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \
+                cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)
+                
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \
+               cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+               
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \
+               cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)
+               
+#include "hscx_irq.c"
+
+static void
+diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, sval, stat = 0;
+       int cnt=8;
+
+       if (!cs) {
+               printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+               return;
+       }
+       while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) {
+               val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40);
+               if (val) {
+                       hscx_int_main(cs, val);
+                       stat |= 1;
+               }
+               val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA);
+               if (val) {
+                       isac_interrupt(cs, val);
+                       stat |= 2;
+               }
+               cnt--;
+       }
+       if (!cnt)
+               printk(KERN_WARNING "Diva: IRQ LOOP\n");
+       if (stat & 1) {
+               writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0);
+               writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_diva(struct IsdnCardState *cs)
+{
+       int bytecnt;
+       
+       del_timer(&cs->hw.diva.tl);
+       if (cs->subtyp == DIVA_ISA)
+               bytecnt = 8;
+       else
+               bytecnt = 32;
+       if (cs->hw.diva.cfg_reg) {
+               byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
+               release_region(cs->hw.diva.cfg_reg, bytecnt);
+       }
+}
+
+static void
+reset_diva(struct IsdnCardState *cs)
+{
+       long flags;
+
+       save_flags(flags);
+       sti();
+       cs->hw.diva.ctrl_reg = 0;        /* Reset On */
+       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+       schedule();
+       cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
+       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+       schedule();
+       if (cs->subtyp == DIVA_ISA)
+               cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
+       else
+               cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A;
+       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+}
+
+#define DIVA_ASSIGN 1
+
+static void
+diva_led_handler(struct IsdnCardState *cs)
+{
+       int blink = 0;
+
+       del_timer(&cs->hw.diva.tl);
+       if (cs->hw.diva.status & DIVA_ASSIGN)
+               cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
+                       DIVA_ISA_LED_A : DIVA_PCI_LED_A;
+       else {
+               cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
+                       DIVA_ISA_LED_A : DIVA_PCI_LED_A;
+               blink = 250;
+       }
+       if (cs->hw.diva.status & 0xf000)
+               cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ?
+                       DIVA_ISA_LED_B : DIVA_PCI_LED_B;
+       else if (cs->hw.diva.status & 0x0f00) { 
+               cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ?
+                       DIVA_ISA_LED_B : DIVA_PCI_LED_B;
+               blink = 500;
+       } else
+               cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ?
+                       DIVA_ISA_LED_B : DIVA_PCI_LED_B);
+       
+       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+       if (blink) {
+               init_timer(&cs->hw.diva.tl);
+               cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000);
+               add_timer(&cs->hw.diva.tl);
+       }
+}
+
+static int
+Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_diva(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_diva(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &diva_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+               case MDL_REMOVE_REQ:
+                       cs->hw.diva.status = 0;
+                       break;
+               case MDL_ASSIGN_REQ:
+                       cs->hw.diva.status |= DIVA_ASSIGN;
+                       break;
+               case MDL_INFO_SETUP:
+                       if ((int)arg) 
+                               cs->hw.diva.status |=  0x0200;
+                       else
+                               cs->hw.diva.status |=  0x0100;
+                       break;
+               case MDL_INFO_CONN:
+                       if ((int)arg) 
+                               cs->hw.diva.status |=  0x2000;
+                       else
+                               cs->hw.diva.status |=  0x1000;
+                       break;
+               case MDL_INFO_REL:
+                       if ((int)arg) {
+                               cs->hw.diva.status &=  ~0x2000;
+                               cs->hw.diva.status &=  ~0x0200;
+                       } else {
+                               cs->hw.diva.status &=  ~0x1000;
+                               cs->hw.diva.status &=  ~0x0100;
+                       }
+                       break;
+       }
+       diva_led_handler(cs);
+       return(0);
+}
+
+
+
+static         int pci_index __initdata = 0;
+
+__initfunc(int
+setup_diva(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Diva_revision);
+       printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+               return(0);
+       cs->hw.diva.status = 0;
+       if (card->para[1]) {
+               cs->subtyp = DIVA_ISA;
+               cs->hw.diva.ctrl_reg = 0;
+               cs->hw.diva.cfg_reg = card->para[1];
+               cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+               cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+               cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+               cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+               cs->irq = card->para[0];
+               bytecnt = 8;
+       } else {
+#if CONFIG_PCI
+               u_char pci_bus, pci_device_fn, pci_irq;
+               u_int pci_ioaddr;
+
+               cs->subtyp = 0;
+               for (; pci_index < 0xff; pci_index++) {
+                       if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL,
+                          PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn)
+                          == PCIBIOS_SUCCESSFUL)
+                               cs->subtyp = DIVA_PCI;
+                       else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL,
+                          PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn)
+                          == PCIBIOS_SUCCESSFUL)
+                               cs->subtyp = DIVA_PCI;
+                       else
+                               break;
+                       /* get IRQ */
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                               PCI_INTERRUPT_LINE, &pci_irq);
+
+                       /* get IO address */
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_2, &pci_ioaddr);
+                       if (cs->subtyp)
+                               break;
+               }
+               if (!cs->subtyp) {
+                       printk(KERN_WARNING "Diva: No PCI card found\n");
+                       return(0);
+               }
+               if (!pci_irq) {
+                       printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+                       return(0);
+               }
+
+               if (!pci_ioaddr) {
+                       printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+                       return(0);
+               }
+               pci_ioaddr &= ~3; /* remove io/mem flag */
+               cs->hw.diva.cfg_reg = pci_ioaddr; 
+               cs->hw.diva.ctrl = pci_ioaddr + DIVA_PCI_CTRL;
+               cs->hw.diva.isac = pci_ioaddr + DIVA_PCI_ISAC_DATA;
+               cs->hw.diva.hscx = pci_ioaddr + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = pci_ioaddr + DIVA_PCI_ISAC_ADR;
+               cs->hw.diva.hscx_adr = pci_ioaddr + DIVA_HSCX_ADR;
+               cs->irq = pci_irq;
+               bytecnt = 32;
+#else
+               printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
+               printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
+               return (0);
+#endif /* CONFIG_PCI */
+       }
+
+       printk(KERN_INFO
+               "Diva: %s card configured at 0x%x IRQ %d\n",
+               (cs->subtyp == DIVA_ISA) ? "ISA" : "PCI",
+               cs->hw.diva.cfg_reg, cs->irq);
+       if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.diva.cfg_reg,
+                      cs->hw.diva.cfg_reg + bytecnt);
+               return (0);
+       } else {
+               request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn");
+       }
+
+       reset_diva(cs);
+       cs->hw.diva.tl.function = (void *) diva_led_handler;
+       cs->hw.diva.tl.data = (long) cs;
+       init_timer(&cs->hw.diva.tl);
+       cs->readisac  = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo  = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg  = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Diva_card_msg;
+
+       ISACVersion(cs, "Diva:");
+       if (HscxVersion(cs, "Diva:")) {
+               printk(KERN_WARNING
+                      "Diva: wrong HSCX versions check IO address\n");
+               release_io_diva(cs);
+               return (0);
+       }
+       return (1);
+}
index 5cea59d9dd93a5f45dd8a6482b2c40a34467575d..6a9966431637a13664f47c9eb0c58a78456e7c94 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+/* $Id: elsa.c,v 2.6 1998/02/02 13:29:40 keil Exp $
 
  * elsa.c     low level stuff for Elsa isdn cards
  *
  *
  *
  * $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 2.6  1998/02/02 13:29:40  keil
+ * fast io
  *
- * 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 2.5  1998/01/31 21:41:45  keil
+ * changes for newer 2.1 kernels
  *
- * Revision 1.11  1997/03/23 21:45:46  keil
- * Add support for ELSA PCMCIA
+ * Revision 2.4  1997/11/08 21:35:46  keil
+ * new l1 init
  *
- * Revision 1.10  1997/03/12 21:42:19  keil
- * Bugfix: IRQ hangs with QS1000
+ * Revision 2.3  1997/11/06 17:15:09  keil
+ * New 2.1 init; PCMCIA wrapper changes
  *
- * Revision 1.9  1997/03/04 15:57:39  keil
- * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ * Revision 2.2  1997/10/29 18:57:09  keil
+ * changes for 2.1.60, arcofi support
  *
- * Revision 1.8  1997/01/27 15:51:48  keil
- * SMP proof,cosmetics
+ * Revision 2.1  1997/07/27 21:47:08  keil
+ * new interface structures
  *
- * Revision 1.7  1997/01/21 22:20:48  keil
- * Elsa Quickstep support
+ * Revision 2.0  1997/06/26 11:02:40  keil
+ * New Layer and card interface
  *
- * 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.14  1997/04/13 19:53:25  keil
+ * Fixed QS1000 init, change in IRQ check delay for SMP
  *
- * Revision 1.2  1996/10/27 22:08:03  keil
- * cosmetic changes
+ * Revision 1.13  1997/04/07 22:58:07  keil
+ * need include config.h
  *
- * Revision 1.1  1996/10/13 20:04:52  keil
- * Initial revision
+ * Revision 1.12  1997/04/06 22:54:14  keil
+ * Using SKB's
  *
+ * old changes removed KKe
  *
  */
 
-#define ARCOFI_USE     0
-
 #define __NO_VERSION__
 #include <linux/config.h>
-#include "siemens.h"
 #include "hisax.h"
-#include "elsa.h"
+#include "arcofi.h"
+#include "isac.h"
+#include "ipac.h"
+#include "hscx.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_revision = "$Revision: 2.6 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000"};
+ "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI"};
 
 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)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ELSA_ISAC      0
+#define ELSA_ISAC_PCM  1
+#define ELSA_ITAC      1
+#define ELSA_HSCX      2
+#define ELSA_ALE       3
+#define ELSA_ALE_PCM   4
+#define ELSA_CONTROL   4
+#define ELSA_CONFIG    5
+#define ELSA_START_TIMER 6
+#define ELSA_TRIG_IRQ  7
+
+#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
+#define ELSA_QS1000PCI 9
+
+/* PCI stuff */
+#define PCI_VENDOR_ELSA        0x1048
+#define PCI_QS1000_ID  0x1000
+
+
+/* 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 ELSA_TIMER_RUN       0x02      /* Bit 1 des Config-Reg     */
+#define ELSA_TIMER_RUN_PCC8  0x01      /* Bit 0 des Config-Reg  bei PCC */
+#define ELSA_IRQ_IDX       0x38        /* Bit 3,4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PCC8  0x30        /* Bit 4,5 des Config-Reg */
+#define ELSA_IRQ_IDX_PC    0x0c        /* Bit 2,3 des Config-Reg */
+
+/* Control-Register (Write) */
+#define ELSA_LINE_LED        0x02      /* Bit 1 Gelbe LED */
+#define ELSA_STAT_LED        0x08      /* Bit 3 Gruene LED */
+#define ELSA_ISDN_RESET      0x20      /* Bit 5 Reset-Leitung */
+#define ELSA_ENA_TIMER_INT   0x80      /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define ELSA_HW_RELEASE      0x07      /* Bit 0-2 Hardwarerkennung */
+#define ELSA_S0_POWER_BAD    0x08      /* Bit 3 S0-Bus Spannung fehlt */
+
+/* Status Flags */
+#define ELSA_TIMER_AKTIV 1
+#define ELSA_BAD_PWR     2
+#define ELSA_ASSIGN      4
 
 static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readreg(unsigned int ale, unsigned int adr, 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);
+       byteout(ale, off);
+       ret = bytein(adr);
        restore_flags(flags);
        return (ret);
 }
 
 static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+readfifo(unsigned int ale, unsigned int adr, u_char off, 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);
+       byteout(ale, off);
+       insb(adr, data, size);
 }
 
 
 static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writereg(unsigned int ale, unsigned int adr, 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);
+       byteout(ale, off);
+       byteout(adr, data);
        restore_flags(flags);
 }
 
 static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+writefifo(unsigned int ale, unsigned int adr, u_char off, 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);
+       byteout(ale, off);
+       outsb(adr, data, size);
 }
 
-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;
+/* Interface functions */
 
-       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)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       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);
+       return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
 }
 
-static inline void
-writeitac(unsigned int adr, u_char off, u_char data)
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       byteout(adr + CARD_ALE, off);
-       byteout(adr + CARD_ITAC, data);
-       restore_flags(flags);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
 }
 
-static inline int
-TimerRun(struct IsdnCardState *sp)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
+       readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
 
-static inline void
-elsa_led_handler(struct IsdnCardState *sp)
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-
-       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);
+       writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
-#endif
 
-static inline void
-waitforCEC(int adr, int hscx)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-       int to = 50;
-
-       while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+       return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
 }
 
-
-static inline void
-waitforXFW(int adr, int hscx)
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       int to = 50;
-
-       while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
 }
 
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       waitforCEC(adr, hscx);
-       writehscx(adr, hscx, HSCX_CMDR, data);
-       restore_flags(flags);
+       readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
-/*
- * fast interrupt here
- */
-
-
 static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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));
+       writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
-void
-elsa_report(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       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);
+       return (readreg(cs->hw.elsa.ale,
+                       cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-/*
- * HSCX stuff goes here
- */
-
 static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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);
-       }
+       writereg(cs->hw.elsa.ale,
+                cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-static void
-hscx_fill_fifo(struct HscxState *hsp)
+static inline u_char
+readitac(struct IsdnCardState *cs, u_char off)
 {
-       struct IsdnCardState *sp = hsp->sp;
-       int more, count;
-       u_char *ptr;
+       register u_char ret;
        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);
+       byteout(cs->hw.elsa.ale, off);
+       ret = bytein(cs->hw.elsa.itac);
        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);
-       }
+       return (ret);
 }
 
 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 {
-                               SET_SKB_FREE(hsp->tx_skb);
-                               dev_kfree_skb(hsp->tx_skb);
-                               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)
+writeitac(struct IsdnCardState *cs, u_char off, u_char data)
 {
-       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);
+       byteout(cs->hw.elsa.ale, off);
+       byteout(cs->hw.elsa.itac, data);
        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)
+static inline int
+TimerRun(struct IsdnCardState *cs)
 {
-       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);
+       register u_char v;
+
+       v = bytein(cs->hw.elsa.cfg);
+       if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
+               return (0 == (v & ELSA_TIMER_RUN));
+       else if (cs->subtyp == ELSA_PCC8)
+               return (v & ELSA_TIMER_RUN_PCC8);
+       return (v & ELSA_TIMER_RUN);
 }
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-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
+#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data)
 
-       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 {
-                                       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 {
-                               SET_SKB_FREE(sp->tx_skb);
-                               dev_kfree_skb(sp->tx_skb);
-                               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
-               }
-       }
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-       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);
-       }
-}
+#include "hscx_irq.c"
 
 static void
 elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs = dev_id;
        u_char val;
+       int icnt=20;
 
-       sp = (struct IsdnCardState *) dev_id;
-
-       if (!sp) {
+       if (!cs) {
                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);
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
       Start_HSCX:
        if (val) {
-               hscx_int_main(sp, val);
+               hscx_int_main(cs, val);
        }
-       val = readisac(sp->cfg_reg, ISAC_ISTA);
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
       Start_ISAC:
        if (val) {
-               isac_interrupt(sp, val);
+               isac_interrupt(cs, 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");
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+       if (val && icnt) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               icnt--;
                goto Start_HSCX;
        }
-       val = readisac(sp->cfg_reg, ISAC_ISTA);
-       if (val) {
-               if (sp->debug & L1_DEB_ISAC)
-                       debugl1(sp, "ISAC IntStat after IntRoutine");
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+       if (val && icnt) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               icnt--;
                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);
+       if (!icnt)
+               printk(KERN_WARNING"ELSA IRQ LOOP\n");
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
+       if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
+               if (!TimerRun(cs)) {
+                       /* Timer Restart */
+                       byteout(cs->hw.elsa.timer, 0);
+                       cs->hw.elsa.counter++;
+               }
        }
-#endif
-       writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
-       writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
-       writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+       if (cs->hw.elsa.trig)
+               byteout(cs->hw.elsa.trig, 0x00);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0);
 }
 
-
 static void
-initisac(struct IsdnCardState *sp)
+elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
 {
-       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);
-}
+       struct IsdnCardState *cs = dev_id;
+       u_char ista,val;
+       char   tmp[64];
+       int icnt=20;
 
-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);
+       if (!cs) {
+               printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+               return;
        }
-       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;
+       if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) {
+         /* The card tends to generate interrupts while being removed
+            causing us to just crash the kernel. bad. */
+         printk(KERN_WARNING "Elsa: card not available!\n");
+         return;
+       }
+       ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+Start_IPAC:
+       if (cs->debug & L1_DEB_IPAC) {
+               sprintf(tmp, "IPAC ISTA %02X", ista);
+               debugl1(cs, tmp);
+       }
+       if (ista & 0x0f) {
+               val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+               if (ista & 0x01)
+                       val |= 0x01;
+               if (ista & 0x04)
+                       val |= 0x02;
+               if (ista & 0x08)
+                       val |= 0x04;
+               if (val)
+                       hscx_int_main(cs, val);
+       }
+       if (ista & 0x20) {
+               val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
+               if (val) {
+                       isac_interrupt(cs, val);
+               }
+       }
+       if (ista & 0x10) {
+               val = 0x01;
+               isac_interrupt(cs, val);
        }
-       writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+       ista  = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+       if ((ista & 0x3f) && icnt) {
+               icnt--;
+               goto Start_IPAC;
+       }
+       if (!icnt)
+               printk(KERN_WARNING "ELSA IRQ LOOP\n");
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0);
 }
 
 void
-release_io_elsa(struct IsdnCard *card)
+release_io_elsa(struct IsdnCardState *cs)
 {
        int bytecnt = 8;
 
-       if (card->sp->subtyp == ELSA_PCFPRO)
+       del_timer(&cs->hw.elsa.tl);
+       if (cs->hw.elsa.ctrl)
+               byteout(cs->hw.elsa.ctrl, 0);   /* LEDs Out */
+       if ((cs->subtyp == ELSA_PCFPRO) || 
+               (cs->subtyp == ELSA_QS3000) ||
+               (cs->subtyp == ELSA_PCF))
                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
+       if (cs->subtyp == ELSA_QS1000PCI) {
+               byteout(cs->hw.elsa.cfg + 0x4c, 0x01);  /* disable IRQ */
+               bytecnt = 2;
+               release_region(cs->hw.elsa.cfg, 0x80);
+       }
+       if (cs->hw.elsa.base)
+               release_region(cs->hw.elsa.base, bytecnt);
 }
 
 static void
-clear_pending_ints(struct IsdnCardState *sp)
+reset_elsa(struct IsdnCardState *cs)
 {
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
-       int val;
-       char tmp[64];
+       long flags;
 
-       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);
+       if (cs->hw.elsa.timer) {
+               /* Wait 1 Timer */
+               byteout(cs->hw.elsa.timer, 0);
+               while (TimerRun(cs));
+               cs->hw.elsa.ctrl_reg |= 0x50;
+               cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET;       /* Reset On */
+               byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+               /* Wait 1 Timer */
+               byteout(cs->hw.elsa.timer, 0);
+               while (TimerRun(cs));
+               cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET;        /* Reset Off */
+               byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+               /* Wait 1 Timer */
+               byteout(cs->hw.elsa.timer, 0);
+               while (TimerRun(cs));
+               if (cs->hw.elsa.trig)
+                       byteout(cs->hw.elsa.trig, 0xff);
        }
-       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);
+       if (cs->subtyp == ELSA_QS1000PCI) {
+               save_flags(flags);
+               sti();
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
+               schedule();
+               restore_flags(flags);
+               byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
        }
-#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);
+}
+
+const u_char ARCOFI_VERSION[] = {2,0xa0,0};
+const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */
+const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */
+const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */
+const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */
+const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0x9e,0x88,0x00,0xc8,0xd8,0x80}; /* RX */
+const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */
+const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR Down */
+const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* PWR Down */
+const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
+static void
+init_arcofi(struct IsdnCardState *cs) {
+       send_arcofi(cs, ARCOFI_COP_5);
+       send_arcofi(cs, ARCOFI_COP_6);
+       send_arcofi(cs, ARCOFI_COP_7);
+       send_arcofi(cs, ARCOFI_COP_8);
+       send_arcofi(cs, ARCOFI_COP_9);
+       send_arcofi(cs, ARCOFI_SOP_F);
+       send_arcofi(cs, ARCOFI_XOP_F);
 }
 
 static void
-check_arcofi(struct IsdnCardState *sp)
+check_arcofi(struct IsdnCardState *cs)
 {
-#if 0
-       u_char val;
+#if ARCOFI_USE
+       int arcofi_present = 0;
        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);
+       if (!cs->mon_tx)
+               if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "ISAC MON TX out of buffers!");
+                       return;
+               }
+       send_arcofi(cs, ARCOFI_VERSION);
+       if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
+               if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
+                       sprintf(tmp, "Arcofi response received %d bytes", cs->mon_rxp);
+                       debugl1(cs, tmp);
+                       p = cs->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;
+                       QuickHex(t, p, cs->mon_rxp);
+                       debugl1(cs, tmp);
+                       if ((cs->mon_rxp == 2) && (cs->mon_rx[0] == 0xa0)) {
+                               switch(cs->mon_rx[1]) {
+                                       case 0x80:
+                                               debugl1(cs, "Arcofi 2160 detected");
+                                               arcofi_present = 1;
+                                               break;
+                                       case 0x82:
+                                               debugl1(cs, "Arcofi 2165 detected");
+                                               arcofi_present = 2;
+                                               break;
+                                       case 0x84:
+                                               debugl1(cs, "Arcofi 2163 detected");
+                                               arcofi_present = 3;
+                                               break;
+                                       default:
+                                               debugl1(cs, "unknown Arcofi response");
+                                               break;
+                               }
+                       } else
+                               debugl1(cs, "undefined Monitor response");
+                       cs->mon_rxp = 0;
                }
-       } else if (sp->mon_tx) {
-               BufPoolRelease(sp->mon_tx);
-               sp->mon_tx = NULL;
-               sp->mon_txp = 0;
+       } else if (cs->mon_tx) {
                sprintf(tmp, "Arcofi not detected");
-               debugl1(sp, tmp);
+               debugl1(cs, tmp);
+       }
+       if (arcofi_present) {
+               if (cs->subtyp==ELSA_QS1000) {
+                       cs->subtyp = ELSA_QS3000;
+                       printk(KERN_INFO
+                               "Elsa: %s detected modem at 0x%x\n",
+                               Elsa_Types[cs->subtyp],
+                               cs->hw.elsa.base+8);
+                       release_region(cs->hw.elsa.base, 8);
+                       if (check_region(cs->hw.elsa.base, 16)) {
+                               printk(KERN_WARNING
+                               "HiSax: %s config port %x-%x already in use\n",
+                               Elsa_Types[cs->subtyp],
+                               cs->hw.elsa.base + 8,
+                               cs->hw.elsa.base + 16);
+                       } else
+                               request_region(cs->hw.elsa.base, 16,
+                                       "elsa isdn modem");
+               } else if (cs->subtyp==ELSA_PCC16) {
+                       cs->subtyp = ELSA_PCF;
+                       printk(KERN_INFO
+                               "Elsa: %s detected modem at 0x%x\n",
+                               Elsa_Types[cs->subtyp],
+                               cs->hw.elsa.base+8);
+                       release_region(cs->hw.elsa.base, 8);
+                       if (check_region(cs->hw.elsa.base, 16)) {
+                               printk(KERN_WARNING
+                               "HiSax: %s config port %x-%x already in use\n",
+                               Elsa_Types[cs->subtyp],
+                               cs->hw.elsa.base + 8,
+                               cs->hw.elsa.base + 16);
+                       } else
+                               request_region(cs->hw.elsa.base, 16,
+                                       "elsa isdn modem");
+               } else
+                       printk(KERN_INFO
+                               "Elsa: %s detected modem at 0x%x\n",
+                               Elsa_Types[cs->subtyp],
+                               cs->hw.elsa.base+8);
+               init_arcofi(cs);
        }
-       sp->mon_flg = 0;
 #endif
 }
 
-int
-initelsa(struct IsdnCardState *sp)
+static void
+elsa_led_handler(struct IsdnCardState *cs)
 {
-       int ret, irq_cnt, cnt = 3;
-       long flags;
+       int blink = 0;
 
-       irq_cnt = kstat_irqs(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_irqs(sp->irq));
-               if (kstat_irqs(sp->irq) == irq_cnt) {
-                       printk(KERN_WARNING
-                              "Elsa: IRQ(%d) getting no interrupts during init %d\n",
-                              sp->irq, 4 - cnt);
-                       if (cnt == 1) {
-                               free_irq(sp->irq, sp);
-                               return (0);
+       if ((cs->subtyp == ELSA_PCMCIA) &&
+               (cs->subtyp == ELSA_QS1000PCI))
+               return;
+       del_timer(&cs->hw.elsa.tl);
+       if (cs->hw.elsa.status & ELSA_ASSIGN)
+               cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED;
+       else if (cs->hw.elsa.status & ELSA_BAD_PWR)
+               cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED;
+       else {
+               cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED;
+               blink = 250;
+       }
+       if (cs->hw.elsa.status & 0xf000)
+               cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED;
+       else if (cs->hw.elsa.status & 0x0f00) {
+               cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED;
+               blink = 500;
+       } else
+               cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
+
+       byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+       if (blink) {
+               init_timer(&cs->hw.elsa.tl);
+               cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000);
+               add_timer(&cs->hw.elsa.tl);
+       }
+}
+
+static int
+Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       int pwr, ret = 0;
+       long flags;     
+
+       switch (mt) {
+               case CARD_RESET:
+                       reset_elsa(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_elsa(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       if (cs->subtyp == ELSA_QS1000PCI)
+                               ret = request_irq(cs->irq, &elsa_interrupt_ipac,
+                                       I4L_IRQ_FLAG, "HiSax", cs);
+                       else
+                               ret = request_irq(cs->irq, &elsa_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs);
+                       return(ret);
+               case CARD_INIT:
+                       if (cs->hw.elsa.trig)
+                               byteout(cs->hw.elsa.trig, 0xff);
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       if (cs->subtyp == ELSA_QS1000) {
+                               byteout(cs->hw.elsa.timer, 0);
+                               byteout(cs->hw.elsa.trig, 0xff);
+                       }
+                       return(0);
+               case CARD_TEST:
+                       if ((cs->subtyp != ELSA_PCMCIA) &&
+                               (cs->subtyp != ELSA_QS1000PCI)) {
+                               save_flags(flags);
+                               cs->hw.elsa.counter = 0;
+                               sti();
+                               cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
+                               cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
+                               byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+                               byteout(cs->hw.elsa.timer, 0);
+                       } else
+                               return(0);
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + (110 * HZ) / 1000;         /* Timeout 110ms */
+                       schedule();
+                       restore_flags(flags);
+                       cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
+                       byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+                       cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
+                       printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
+                              cs->hw.elsa.counter);
+                       if (abs(cs->hw.elsa.counter - 13) < 3) {
+                               printk(KERN_INFO "Elsa: timer and irq OK\n");
+                               ret = 0;
                        } else {
-                               reset_elsa(sp);
-                               cnt--;
+                               printk(KERN_WARNING
+                                      "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+                                      cs->hw.elsa.counter, cs->irq);
+                               ret = 1;
                        }
-               } else {
-                       check_arcofi(sp);
-                       cnt = 0;
-               }
+                       check_arcofi(cs);
+                       elsa_led_handler(cs);
+                       return(ret);
+               case MDL_REMOVE_REQ:
+                       cs->hw.elsa.status &= 0;
+                       break;
+               case MDL_ASSIGN_REQ:
+                       cs->hw.elsa.status |= ELSA_ASSIGN;
+                       break;
+               case MDL_INFO_SETUP:
+                       if ((int) arg)
+                               cs->hw.elsa.status |= 0x0200;
+                       else
+                               cs->hw.elsa.status |= 0x0100;
+                       break;
+               case MDL_INFO_CONN:
+                       if ((int) arg)
+                               cs->hw.elsa.status |= 0x2000;
+                       else
+                               cs->hw.elsa.status |= 0x1000;
+                       break;
+               case MDL_INFO_REL:
+                       if ((int) arg) {
+                               cs->hw.elsa.status &= ~0x2000;
+                               cs->hw.elsa.status &= ~0x0200;
+                       } else {
+                               cs->hw.elsa.status &= ~0x1000;
+                               cs->hw.elsa.status &= ~0x0100;
+                       }
+                       break;
+               case CARD_AUX_IND:
+                       break;
        }
-       sp->counter = 0;
-       return (ret);
+       pwr = bytein(cs->hw.elsa.ale);
+       if (pwr & 0x08)
+               cs->hw.elsa.status |= ELSA_BAD_PWR;
+       else
+               cs->hw.elsa.status &= ~ELSA_BAD_PWR;
+       elsa_led_handler(cs);
+       return(ret);
 }
 
-#ifdef CONFIG_HISAX_ELSA_PCC
 static unsigned char
-probe_elsa_adr(unsigned int adr)
+probe_elsa_adr(unsigned int adr, int typ)
 {
        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)) {
+       /* In case of the elsa pcmcia card, this region is in use,
+          reserved for us by the card manager. So we do not check it
+          here, it would fail. */
+       if (typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(adr, 8)) {
                printk(KERN_WARNING
                       "Elsa: Probing Port 0x%x: already in use\n",
                       adr);
@@ -1251,8 +736,8 @@ probe_elsa_adr(unsigned int adr)
        save_flags(flags);
        cli();
        for (i = 0; i < 16; i++) {
-               in1 = inb(adr + CARD_CONFIG);   /* 'toggelt' bei */
-               in2 = inb(adr + CARD_CONFIG);   /* jedem Zugriff */
+               in1 = inb(adr + ELSA_CONFIG);   /* 'toggelt' bei */
+               in2 = inb(adr + ELSA_CONFIG);   /* jedem Zugriff */
                p16_1 += 0x04 & in1;
                p16_2 += 0x04 & in2;
                p8_1 += 0x02 & in1;
@@ -1283,205 +768,295 @@ probe_elsa_adr(unsigned int adr)
 }
 
 static unsigned int
-probe_elsa(struct IsdnCardState *sp)
+probe_elsa(struct IsdnCardState *cs)
 {
        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])))
+               if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ)))
                        break;
        }
        return (CARD_portlist[i]);
 }
-#endif
+
+static         int pci_index __initdata = 0;
 
 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;
+       u_char val;
+       struct IsdnCardState *cs = card->cs;
        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 "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+       cs->hw.elsa.ctrl_reg = 0;
+       cs->hw.elsa.status = 0;
+       if (cs->typ == ISDN_CTYPE_ELSA) {
+               cs->hw.elsa.base = card->para[0];
                printk(KERN_INFO "Elsa: Microlink IO probing\n");
-               if (sp->cfg_reg) {
-                       if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+               if (cs->hw.elsa.base) {
+                       if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+                                                         cs->typ))) {
                                printk(KERN_WARNING
                                     "Elsa: no Elsa Microlink at 0x%x\n",
-                                      sp->cfg_reg);
+                                      cs->hw.elsa.base);
                                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) {
+                       cs->hw.elsa.base = probe_elsa(cs);
+               if (cs->hw.elsa.base) {
+                       cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+                       cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+                       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+                       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+                       cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+                       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+                       cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+                       cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+                       val = bytein(cs->hw.elsa.cfg);
+                       if (cs->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) {
+                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+                       } else if (cs->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];
+                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_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];
+                               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
                        }
-                       val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+                       val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
                        if (val < 3)
                                val |= 8;
                        val += 'A' - 3;
                        if (val == 'B' || val == 'C')
                                val ^= 1;
-                       if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G'))
+                       if ((cs->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)
+                              Elsa_Types[cs->subtyp],
+                              cs->hw.elsa.base,
+                              val, cs->irq);
+                       val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+                       if (val) {
                                printk(KERN_WARNING
                                   "Elsa: Microlink S0 bus power bad\n");
+                               cs->hw.elsa.status |= ELSA_BAD_PWR;
+                       }
                } 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;
+       } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+               cs->hw.elsa.base = card->para[1];
+               cs->irq = card->para[0];
+               cs->subtyp = ELSA_QS1000;
+               cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+               cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+               cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+               cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+               cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+               cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+               cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
                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;
+                      "Elsa: %s defined at 0x%x IRQ %d\n",
+                      Elsa_Types[cs->subtyp],
+                      cs->hw.elsa.base,
+                      cs->irq);
+       } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+               cs->hw.elsa.base = card->para[1];
+               cs->irq = card->para[0];
+               cs->subtyp = ELSA_PCMCIA;
+               cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+               cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+               cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+               cs->hw.elsa.timer = 0;
+               cs->hw.elsa.trig = 0;
+               cs->hw.elsa.ctrl = 0;
                printk(KERN_INFO
-                      "Elsa: %s found at 0x%x IRQ %d\n",
-                      Elsa_Types[sp->subtyp],
-                      sp->cfg_reg,
-                      sp->irq);
-       } else
+                      "Elsa: %s defined at 0x%x IRQ %d\n",
+                      Elsa_Types[cs->subtyp],
+                      cs->hw.elsa.base,
+                      cs->irq);
+       } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+#if CONFIG_PCI
+               u_char pci_bus, pci_device_fn, pci_irq;
+               u_int pci_ioaddr;
+
+               cs->subtyp = 0;
+               for (; pci_index < 0xff; pci_index++) {
+                       if (pcibios_find_device(PCI_VENDOR_ELSA,
+                          PCI_QS1000_ID, pci_index, &pci_bus, &pci_device_fn)
+                          == PCIBIOS_SUCCESSFUL)
+                               cs->subtyp = ELSA_QS1000PCI;
+                       else
+                               break;
+                       /* get IRQ */
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                               PCI_INTERRUPT_LINE, &pci_irq);
+
+                       /* get IO address */
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_1, &pci_ioaddr);
+                       pci_ioaddr &= ~3; /* remove io/mem flag */
+                       cs->hw.elsa.cfg = pci_ioaddr;
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_3, &pci_ioaddr);
+                       if (cs->subtyp)
+                               break;
+               }
+               if (!cs->subtyp) {
+                       printk(KERN_WARNING "Elsa: No PCI card found\n");
+                       return(0);
+               }
+               if (!pci_irq) {
+                       printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+                       return(0);
+               }
+
+               if (!pci_ioaddr) {
+                       printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+                       return(0);
+               }
+               pci_ioaddr &= ~3; /* remove io/mem flag */
+               cs->hw.elsa.base = pci_ioaddr;
+               cs->hw.elsa.ale  = pci_ioaddr;
+               cs->hw.elsa.isac = pci_ioaddr +1;
+               cs->hw.elsa.hscx = pci_ioaddr +1; 
+               cs->irq = pci_irq;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+               cs->hw.elsa.timer = 0;
+               cs->hw.elsa.trig  = 0;
+               printk(KERN_INFO
+                      "Elsa: %s defined at 0x%x/0x%x IRQ %d\n",
+                      Elsa_Types[cs->subtyp],
+                      cs->hw.elsa.base,
+                      cs->hw.elsa.cfg,
+                      cs->irq);
+#else
+               printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
+               printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
+               return (0);
+#endif /* CONFIG_PCI */
+       } else 
                return (0);
-#endif
 
-       switch (sp->subtyp) {
+       switch (cs->subtyp) {
                case ELSA_PC:
-                       bytecnt = 8;
-                       break;
                case ELSA_PCC8:
-                       bytecnt = 8;
-                       break;
-               case ELSA_PCFPRO:
-                       bytecnt = 16;
-                       break;
                case ELSA_PCC16:
+               case ELSA_QS1000:
+               case ELSA_PCMCIA:
                        bytecnt = 8;
                        break;
+               case ELSA_PCFPRO:
                case ELSA_PCF:
                        bytecnt = 16;
                        break;
-               case ELSA_QS1000:
-                       bytecnt = 8;
-                       break;
-               case ELSA_PCMCIA:
-                       bytecnt = 8;
+               case ELSA_QS1000PCI:
+                       bytecnt = 2;
                        break;
                default:
                        printk(KERN_WARNING
-                              "Unknown ELSA subtype %d\n", sp->subtyp);
+                              "Unknown ELSA subtype %d\n", cs->subtyp);
                        return (0);
        }
-
-       if (check_region((sp->cfg_reg), bytecnt)) {
+       /* In case of the elsa pcmcia card, this region is in use,
+          reserved for us by the card manager. So we do not check it
+          here, it would fail. */
+       if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(cs->hw.elsa.base, bytecnt)) {
                printk(KERN_WARNING
                       "HiSax: %s config port %x-%x already in use\n",
                       CardType[card->typ],
-                      sp->cfg_reg,
-                      sp->cfg_reg + bytecnt);
+                      cs->hw.elsa.base,
+                      cs->hw.elsa.base + bytecnt);
                return (0);
        } else {
-               request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+               request_region(cs->hw.elsa.base, 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)) {
+       if (cs->subtyp == ELSA_QS1000PCI) {
+               if (check_region(cs->hw.elsa.cfg, 0x80)) {
                        printk(KERN_WARNING
-                              "Elsa: timer do not start\n");
-                       release_io_elsa(card);
+                              "HiSax: %s pci port %x-%x already in use\n",
+                               CardType[card->typ],
+                               cs->hw.elsa.cfg,
+                               cs->hw.elsa.cfg + 0x80);
+                       release_region(cs->hw.elsa.base, bytecnt);
                        return (0);
+               } else {
+                       request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci");
                }
        }
-       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);
+       cs->hw.elsa.tl.function = (void *) elsa_led_handler;
+       cs->hw.elsa.tl.data = (long) cs;
+       init_timer(&cs->hw.elsa.tl);
+       /* Teste Timer */
+       if (cs->hw.elsa.timer) {
+               byteout(cs->hw.elsa.trig, 0xff);
+               byteout(cs->hw.elsa.timer, 0);
+               if (!TimerRun(cs)) {
+                       byteout(cs->hw.elsa.timer, 0);  /* 2. Versuch */
+                       if (!TimerRun(cs)) {
+                               printk(KERN_WARNING
+                                      "Elsa: timer do not start\n");
+                               release_io_elsa(cs);
+                               return (0);
+                       }
+               }
+               save_flags(flags);
+               sti();
+               HZDELAY(1);     /* wait >=10 ms */
+               restore_flags(flags);
+               if (TimerRun(cs)) {
+                       printk(KERN_WARNING "Elsa: timer do not run down\n");
+                       release_io_elsa(cs);
+                       return (0);
+               }
+               printk(KERN_INFO "Elsa: timer OK; resetting card\n");
        }
-       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);
+       reset_elsa(cs);
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Elsa_card_msg;
+       if (cs->subtyp == ELSA_QS1000PCI) {
+               cs->readisac = &ReadISAC_IPAC;
+               cs->writeisac = &WriteISAC_IPAC;
+               cs->readisacfifo = &ReadISACfifo_IPAC;
+               cs->writeisacfifo = &WriteISACfifo_IPAC;
+               val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID);
+               printk(KERN_INFO "Elsa: IPAC version %x\n", val);
+       } else {
+               cs->readisac = &ReadISAC;
+               cs->writeisac = &WriteISAC;
+               cs->readisacfifo = &ReadISACfifo;
+               cs->writeisacfifo = &WriteISACfifo;
+               ISACVersion(cs, "Elsa:");
+               if (HscxVersion(cs, "Elsa:")) {
+                       printk(KERN_WARNING
+                               "Elsa: wrong HSCX versions check IO address\n");
+                       release_io_elsa(cs);
+                       return (0);
+               }
        }
-#endif
-
-#ifdef CONFIG_HISAX_ELSA_PCC
-       if (sp->subtyp == ELSA_PC) {
-               val = readitac(sp->cfg_reg, ITAC_SYS);
+       if (cs->subtyp == ELSA_PC) {
+               val = readitac(cs, 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);
+               writeitac(cs, ITAC_ISEN, 0);
+               writeitac(cs, ITAC_RFIE, 0);
+               writeitac(cs, ITAC_XFIE, 0);
+               writeitac(cs, ITAC_SCIE, 0);
+               writeitac(cs, 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
deleted file mode 100644 (file)
index 5187e6a..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* $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);
index d0bb2f14f0ead971671b1482f435cbf9253de4a4..ae0662f3f561ccc573a31dbcdb606cefb35cd2c7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.4 1997/04/06 22:56:42 keil Exp $
+/* $Id: fsm.c,v 1.7 1997/11/06 17:09:13 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,6 +7,15 @@
  *              Fritz Elfert
  *
  * $Log: fsm.c,v $
+ * Revision 1.7  1997/11/06 17:09:13  keil
+ * New 2.1 init code
+ *
+ * Revision 1.6  1997/07/27 21:42:25  keil
+ * proof Fsm routines
+ *
+ * Revision 1.5  1997/06/26 11:10:05  keil
+ * Restart timer function added
+ *
  * Revision 1.4  1997/04/06 22:56:42  keil
  * Some cosmetic changes
  *
@@ -26,9 +35,9 @@
 
 #define FSM_TIMER_DEBUG 0
 
-void
+HISAX_INITFUNC(void
 FsmNew(struct Fsm *fsm,
-       struct FsmNode *fnlist, int fncount)
+       struct FsmNode *fnlist, int fncount))
 {
        int i;
 
@@ -36,9 +45,14 @@ FsmNew(struct Fsm *fsm,
            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;
+       for (i = 0; i < fncount; i++) 
+               if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
+                       printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n",
+                               i,fnlist[i].state,fsm->state_count,
+                               fnlist[i].event,fsm->event_count);
+               } else          
+                       fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+                               fnlist[i].state] = (int) fnlist[i].routine;
 }
 
 void
@@ -53,6 +67,11 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
        void (*r) (struct FsmInst *, int, void *);
        char str[80];
 
+       if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
+               printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n",
+                       fi->state,fi->fsm->state_count,event,fi->fsm->event_count);
+               return(1);
+       }
        r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
        if (r) {
                if (fi->debug) {
@@ -155,10 +174,26 @@ FsmAddTimer(struct FsmTimer *ft,
        return 0;
 }
 
-int
-FsmTimerRunning(struct FsmTimer *ft)
+void
+FsmRestartTimer(struct FsmTimer *ft,
+           int millisec, int event, void *arg, int where)
 {
-       return (ft->tl.next != NULL);
+
+#if FSM_TIMER_DEBUG
+       if (ft->fi->debug) {
+               char str[40];
+               sprintf(str, "FsmRestartTimer %lx %d %d", (long) ft, millisec, where);
+               ft->fi->printdebug(ft->fi, str);
+       }
+#endif
+
+       if (ft->tl.next || ft->tl.prev)
+               del_timer(&ft->tl);
+       init_timer(&ft->tl);
+       ft->event = event;
+       ft->arg = arg;
+       ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+       add_timer(&ft->tl);
 }
 
 void
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
new file mode 100644 (file)
index 0000000..734ec8b
--- /dev/null
@@ -0,0 +1,1297 @@
+/* $Id: hfc_2bds0.c,v 1.3 1998/02/12 23:07:22 keil Exp $
+ *
+ *  specific routines for CCD's HFC 2BDS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.c,v $
+ * Revision 1.3  1998/02/12 23:07:22  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.2  1998/02/02 13:26:13  keil
+ * New
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+/*
+#define KDEBUG_DEF
+#include "kdebug.h"
+*/
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static void
+dummyf(struct IsdnCardState *cs, u_char * data, int size)
+{
+       printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");
+}
+
+static inline u_char
+ReadReg(struct IsdnCardState *cs, int data, u_char reg)
+{
+       register u_char ret;
+
+       if (data) {
+               if (cs->hw.hfcD.cip != reg) { 
+                       cs->hw.hfcD.cip = reg;
+                       byteout(cs->hw.hfcD.addr | 1, reg);
+               }
+               ret = bytein(cs->hw.hfcD.addr);
+#if HFC_REG_DEBUG
+               if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+                       char tmp[32];
+                       sprintf(tmp, "t3c RD %02x %02x", reg, ret);
+                       debugl1(cs, tmp);
+               }
+#endif
+       } else
+               ret = bytein(cs->hw.hfcD.addr | 1);
+       return (ret);
+}
+
+static inline void
+WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
+{
+       if (cs->hw.hfcD.cip != reg) { 
+               cs->hw.hfcD.cip = reg;
+               byteout(cs->hw.hfcD.addr | 1, reg);
+       }
+       if (data)
+               byteout(cs->hw.hfcD.addr, value);
+#if HFC_REG_DEBUG
+       if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) {
+               char tmp[16];
+               sprintf(tmp, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);
+               debugl1(cs, tmp);
+       }
+#endif
+}
+
+/* Interface functions */
+
+static u_char
+readreghfcd(struct IsdnCardState *cs, u_char offset)
+{
+       return(ReadReg(cs, HFCD_DATA, offset));
+}
+
+static void
+writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       WriteReg(cs, HFCD_DATA, offset, value);
+}
+
+void
+set_cs_func(struct IsdnCardState *cs)
+{
+       cs->readisac = &readreghfcd;
+       cs->writeisac = &writereghfcd;
+       cs->readisacfifo = &dummyf;
+       cs->writeisacfifo = &dummyf;
+       cs->BC_Read_Reg = &ReadReg;
+       cs->BC_Write_Reg = &WriteReg;
+}
+
+static inline int
+WaitForBusy(struct IsdnCardState *cs)
+{
+       int to = 130;
+
+       while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) {
+               udelay(1);
+               to--;
+       }
+       if (!to)
+               printk(KERN_WARNING "HiSax: WaitForBusy timeout\n");
+       return (to);
+}
+
+static inline int
+WaitNoBusy(struct IsdnCardState *cs)
+{
+       long flags;
+       int to = 130;
+
+       while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) {
+               save_flags(flags);
+               sti();
+               udelay(1);
+               to--;
+               restore_flags(flags);
+       }
+       if (!to) 
+               printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n");
+       return (to);
+}
+
+static int
+SelFiFo(struct IsdnCardState *cs, u_char FiFo)
+{
+       u_char cip;
+       long flags;
+
+
+       if (cs->hw.hfcD.fifo == FiFo)
+               return(1);
+       save_flags(flags);
+       cli();
+       switch(FiFo) {
+               case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;
+                       break;
+               case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1;
+                       break;
+               case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2;
+                       break;
+               case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2;
+                       break;
+               case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND;
+                       break;
+               case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC;
+                       break;
+               default:
+                       restore_flags(flags);
+                       debugl1(cs, "SelFiFo Error");
+                       return(0);
+       }
+       cs->hw.hfcD.fifo = FiFo;
+       WaitNoBusy(cs);
+       cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);
+       sti();
+       WaitForBusy(cs);
+       restore_flags(flags);
+       return(2);
+}
+static int
+GetFreeFifoBytes_B(struct BCState *bcs)
+{
+       int s;
+
+       if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
+               return (bcs->cs->hw.hfcD.bfifosize);
+       s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
+       if (s <= 0)
+               s += bcs->cs->hw.hfcD.bfifosize;
+       s = bcs->cs->hw.hfcD.bfifosize - s;
+       return (s);
+}
+
+static int
+GetFreeFifoBytes_D(struct IsdnCardState *cs)
+{
+       int s;
+
+       if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2)
+               return (cs->hw.hfcD.dfifosize);
+       s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2];
+       if (s <= 0)
+               s += cs->hw.hfcD.dfifosize;
+       s = cs->hw.hfcD.dfifosize - s;
+       return (s);
+}
+
+static int
+ReadZReg(struct IsdnCardState *cs, u_char reg)
+{
+       int val;
+
+       WaitNoBusy(cs);
+       val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH);
+       WaitNoBusy(cs);
+       val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW);
+       return (val);
+}
+
+static void
+hfc_sched_event(struct BCState *bcs, int event)
+{
+       bcs->event |= 1 << event;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static struct sk_buff
+*hfc_empty_fifo(struct BCState *bcs, int count)
+{
+       u_char *ptr;
+       struct sk_buff *skb;
+       struct IsdnCardState *cs = bcs->cs;
+       int idx;
+       int chksum;
+       long flags;
+       u_char stat, cip;
+       char tmp[64];
+       
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hfc_empty_fifo");
+       idx = 0;
+       save_flags(flags);
+       if (count > HSCX_BUFMAX + 3) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hfc_empty_fifo: incoming packet too large");
+               cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+               while (idx++ < count) {
+                       cli();
+                       WaitNoBusy(cs);
+                       ReadReg(cs, HFCD_DATA_NODEB, cip);
+                       sti();
+               }
+               skb = NULL;
+       } else if (count < 4) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hfc_empty_fifo: incoming packet too small");
+               cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+               cli();
+               while ((idx++ < count) && WaitNoBusy(cs))
+                       ReadReg(cs, HFCD_DATA_NODEB, cip);
+               skb = NULL;
+       } else if (!(skb = dev_alloc_skb(count - 3)))
+               printk(KERN_WARNING "HFC: receive out of memory\n");
+       else {
+               ptr = skb_put(skb, count - 3);
+               idx = 0;
+               cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+               cli();
+               while (idx < (count - 3)) {
+                       cli();
+                       if (!WaitNoBusy(cs))
+                               break;
+                       *ptr = ReadReg(cs,  HFCD_DATA_NODEB, cip);
+                       sti();
+                       ptr++;
+                       idx++;
+               }
+               if (idx != count - 3) {
+                       sti();
+                       debugl1(cs, "RFIFO BUSY error");
+                       printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
+                       dev_kfree_skb(skb);
+                       skb = NULL;
+               } else {
+                       cli();
+                       WaitNoBusy(cs);
+                       chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
+                       WaitNoBusy(cs);
+                       chksum += ReadReg(cs, HFCD_DATA, cip);
+                       WaitNoBusy(cs);
+                       stat = ReadReg(cs, HFCD_DATA, cip);
+                       sti();
+                       if (cs->debug & L1_DEB_HSCX) {
+                               sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x",
+                                       bcs->channel, chksum, stat);
+                               debugl1(cs, tmp);
+                       }
+                       if (stat) {
+                               debugl1(cs, "FIFO CRC error");
+                               dev_kfree_skb(skb);
+                               skb = NULL;
+                       }
+               }
+       }
+       sti();
+       WaitForBusy(cs);
+       cli();
+       WaitNoBusy(cs);
+       stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC |
+               HFCB_REC | HFCB_CHANNEL(bcs->channel));
+       sti();
+       WaitForBusy(cs);
+       restore_flags(flags);
+       return (skb);
+}
+
+static void
+hfc_fill_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       long flags;
+       int idx, fcnt;
+       int count;
+       u_char cip;
+       char tmp[64];
+       
+
+       if (!bcs->hw.hfc.tx_skb)
+               return;
+       if (bcs->hw.hfc.tx_skb->len <= 0)
+               return;
+
+       save_flags(flags);
+       cli();
+       SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); 
+       cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip);
+       WaitNoBusy(cs);
+       cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip);
+       bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
+       sti();
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+                       bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+                       bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+               debugl1(cs, tmp);
+       }
+       fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+       if (fcnt < 0)
+               fcnt += 32;
+       if (fcnt > 30) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfc_fill_fifo more as 30 frames");
+               restore_flags(flags);
+               return;
+       }
+       count = GetFreeFifoBytes_B(bcs);
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "hfc_fill_fifo %d count(%d/%d),%lx",
+                       bcs->channel, bcs->hw.hfc.tx_skb->len,
+                       count, current->state);
+               debugl1(cs, tmp);
+       }
+       if (count < bcs->hw.hfc.tx_skb->len) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfc_fill_fifo no fifo mem");
+               restore_flags(flags);
+               return;
+       }
+       cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel);
+       idx = 0;
+       cli();
+       WaitForBusy(cs);
+       WaitNoBusy(cs);
+       WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]);
+       while (idx < bcs->hw.hfc.tx_skb->len) {
+               cli();
+               if (!WaitNoBusy(cs))
+                       break;
+               WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx]);
+               sti();
+               idx++;
+       }
+       if (idx != bcs->hw.hfc.tx_skb->len) {
+               sti();
+               debugl1(cs, "FIFO Send BUSY error");
+               printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
+       } else {
+               bcs->tx_cnt -= bcs->hw.hfc.tx_skb->len;
+               if (bcs->st->lli.l1writewakeup &&
+                       (PACKET_NOACK != bcs->hw.hfc.tx_skb->pkt_type))
+                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hfc.tx_skb->len);
+               dev_kfree_skb(bcs->hw.hfc.tx_skb);
+               bcs->hw.hfc.tx_skb = NULL;
+       }
+       WaitForBusy(cs);
+       cli();
+       WaitNoBusy(cs);
+       ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel));
+       sti();
+       WaitForBusy(cs);
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       restore_flags(flags);
+       return;
+}
+
+static void
+hfc_send_data(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       char tmp[32];
+       
+       if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+               hfc_fill_fifo(bcs);
+               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+       } else {
+               sprintf(tmp,"send_data %d blocked", bcs->channel);
+               debugl1(cs, tmp);
+       }
+}
+
+void
+main_rec_2bds0(struct BCState *bcs)
+{
+       long flags;
+       struct IsdnCardState *cs = bcs->cs;
+       int z1, z2, rcnt;
+       u_char f1, f2, cip;
+       int receive, count = 5;
+       struct sk_buff *skb;
+       char tmp[64];
+
+       save_flags(flags);
+    Begin:
+       count--;
+       cli();
+       if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+               sprintf(tmp,"rec_data %d blocked", bcs->channel);
+               debugl1(cs, tmp);
+               restore_flags(flags);
+               return;
+       }
+       SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));
+       cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       f1 = ReadReg(cs, HFCD_DATA, cip);
+       cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       f2 = ReadReg(cs, HFCD_DATA, cip);
+       sti();
+       if (f1 != f2) {
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc rec %d f1(%d) f2(%d)",
+                               bcs->channel, f1, f2);
+                       debugl1(cs, tmp);
+               }
+               cli();
+               z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
+               z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel));
+               sti();
+               rcnt = z1 - z2;
+               if (rcnt < 0)
+                       rcnt += cs->hw.hfcD.bfifosize;
+               rcnt++;
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+                               bcs->channel, z1, z2, rcnt);
+                       debugl1(cs, tmp);
+               }
+               if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+                       cli();
+                       skb_queue_tail(&bcs->rqueue, skb);
+                       sti();
+                       hfc_sched_event(bcs, B_RCVBUFREADY);
+               }
+               rcnt = f1 -f2;
+               if (rcnt<0)
+                       rcnt += 32;
+               if (rcnt>1)
+                       receive = 1;
+               else
+                       receive = 0;
+       } else
+               receive = 0;
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+       if (count && receive)
+               goto Begin;     
+       restore_flags(flags);
+       return;
+}
+
+void
+mode_2bs0(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+
+       if (cs->debug & L1_DEB_HSCX) {
+               char tmp[40];
+               sprintf(tmp, "HFCD bchannel mode %d bchan %d/%d",
+                       mode, bc, bcs->channel);
+               debugl1(cs, tmp);
+       }
+       bcs->mode = mode;
+       bcs->channel = bc;
+       switch (mode) {
+               case (L1_MODE_NULL):
+                       if (bc) {
+                               cs->hw.hfcD.conn |= 0x18;
+                               cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA;
+                       } else {
+                               cs->hw.hfcD.conn |= 0x3;
+                               cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA;
+                       }
+                       break;
+               case (L1_MODE_TRANS):
+                       if (bc) {
+                               cs->hw.hfcD.ctmt |= 2;
+                               cs->hw.hfcD.conn &= ~0x18;
+                               cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
+                       } else {
+                               cs->hw.hfcD.ctmt |= 1;
+                               cs->hw.hfcD.conn &= ~0x3;
+                               cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
+                       }
+                       break;
+               case (L1_MODE_HDLC):
+                       if (bc) {
+                               cs->hw.hfcD.ctmt &= ~2;
+                               cs->hw.hfcD.conn &= ~0x18;
+                               cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;
+                       } else {
+                               cs->hw.hfcD.ctmt &= ~1;
+                               cs->hw.hfcD.conn &= ~0x3;
+                               cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;
+                       }
+                       break;
+       }
+       WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
+       WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+       WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn);
+}
+
+static void
+hfc_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->hw.hfc.tx_skb = skb;
+/*                             test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+*/                             st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                               restore_flags(flags);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                               printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       save_flags(flags);
+                       cli();
+/*                     test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+*/                     st->l1.bcs->hw.hfc.tx_skb = skb;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       restore_flags(flags);
+                       break;
+               case (PH_PULL_REQ):
+                       if (!st->l1.bcs->hw.hfc.tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+void
+close_2bs0(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       mode_2bs0(bcs, 0, 0);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+               if (bcs->hw.hfc.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hfc.tx_skb);
+                       bcs->hw.hfc.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+static int
+open_hfcstate(struct IsdnCardState *cs,
+             int bc)
+{
+       struct BCState *bcs = cs->bcs + bc;
+
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->hw.hfc.tx_skb = NULL;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       bcs->event = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+static void
+hfc_manl1(struct PStack *st, int pr,
+         void *arg)
+{
+       switch (pr) {
+               case (PH_ACTIVATE_REQ):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       break;
+               case (PH_DEACTIVATE_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+                               mode_2bs0(st->l1.bcs, 0, 0);
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       break;
+       }
+}
+
+int
+setstack_2b(struct PStack *st, struct BCState *bcs)
+{
+       if (open_hfcstate(st->l1.hardware, bcs->channel))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = hfc_l2l1;
+       st->ma.manl1 = hfc_manl1;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+       struct PStack *st;
+
+       st = cs->stlist;
+       while (st) {
+               st->ma.manl1(st, msg, arg);
+               st = st->next;
+       }
+}
+
+static void
+hfcd_bh(struct IsdnCardState *cs)
+{
+/*     struct PStack *stptr;
+*/
+       if (!cs)
+               return;
+#if 0  
+       if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+               if (cs->debug)
+                       debugl1(cs, "D-Channel Busy cleared");
+               stptr = cs->stlist;
+               while (stptr != NULL) {
+                       stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL);
+                       stptr = stptr->next;
+               }
+       }
+#endif
+       if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+               switch (cs->ph_state) {
+                       case (0):
+                               manl1_msg(cs, PH_RESET_IND, NULL);
+                               break;
+                       case (3):
+                               manl1_msg(cs, PH_DEACT_IND, NULL);
+                               break;
+                       case (8):
+                               manl1_msg(cs, PH_RSYNC_IND, NULL);
+                               break;
+                       case (6):
+                               manl1_msg(cs, PH_INFO2_IND, NULL);
+                               break;
+                       case (7):
+                               manl1_msg(cs, PH_I4_P8_IND, NULL);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+               DChannel_proc_rcv(cs);
+       if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+               DChannel_proc_xmt(cs);
+}
+
+void
+sched_event_D(struct IsdnCardState *cs, int event)
+{
+       test_and_set_bit(event, &cs->event);
+       queue_task(&cs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static
+int receive_dmsg(struct IsdnCardState *cs)
+{
+       struct sk_buff *skb;
+       long flags;
+       int idx;
+       int rcnt, z1, z2;
+       u_char stat, cip, f1, f2;
+       int chksum;
+       int count=5;
+       u_char *ptr;
+       char tmp[64];
+
+       save_flags(flags);
+       cli();
+       if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+               debugl1(cs, "rec_dmsg blocked");
+               restore_flags(flags);
+               return(1);
+       }
+       SelFiFo(cs, 4 | HFCD_REC);
+       cip = HFCD_FIFO | HFCD_F1 | HFCD_REC;
+       WaitNoBusy(cs);
+       f1 = cs->readisac(cs, cip) & 0xf;
+       cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
+       WaitNoBusy(cs);
+       f2 = cs->readisac(cs, cip) & 0xf;
+       while ((f1 != f2) && count--) {
+               z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC);
+               z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC);
+               rcnt = z1 - z2;
+               if (rcnt < 0)
+                       rcnt += cs->hw.hfcD.dfifosize;
+               rcnt++;
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",
+                               f1, f2, z1, z2, rcnt);
+                       debugl1(cs, tmp);
+               }
+               sti();
+               idx = 0;
+               cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC;
+               if (rcnt > MAX_DFRAME_LEN + 3) {
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "empty_fifo d: incoming packet too large");
+                       while (idx < rcnt) {
+                               cli();
+                               if (!(WaitNoBusy(cs)))
+                                       break;
+                               ReadReg(cs, HFCD_DATA_NODEB, cip);
+                               sti();
+                               idx++;
+                       }
+               } else if (rcnt < 4) {
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "empty_fifo d: incoming packet too small");
+                       cli();
+                       while ((idx++ < rcnt) && WaitNoBusy(cs))
+                               ReadReg(cs, HFCD_DATA_NODEB, cip);
+               } else if ((skb = dev_alloc_skb(rcnt - 3))) {
+                       ptr = skb_put(skb, rcnt - 3);
+                       while (idx < (rcnt - 3)) {
+                               cli();
+                               if (!(WaitNoBusy(cs)))
+                                       break;
+                               *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip);
+                               sti();
+                               idx++;
+                               ptr++;
+                       }
+                       if (idx != (rcnt - 3)) {
+                               sti();
+                               debugl1(cs, "RFIFO D BUSY error");
+                               printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
+                               dev_kfree_skb(skb);
+                               skb = NULL;
+                       } else {
+                               cli();
+                               WaitNoBusy(cs);
+                               chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);
+                               WaitNoBusy(cs);
+                               chksum += ReadReg(cs, HFCD_DATA, cip);
+                               WaitNoBusy(cs);
+                               stat = ReadReg(cs, HFCD_DATA, cip);
+                               sti();
+                               if (cs->debug & L1_DEB_ISAC) {
+                                       sprintf(tmp, "empty_dfifo chksum %x stat %x",
+                                               chksum, stat);
+                                       debugl1(cs, tmp);
+                               }
+                               if (stat) {
+                                       debugl1(cs, "FIFO CRC error");
+                                       dev_kfree_skb(skb);
+                                       skb = NULL;
+                               } else {
+                                       skb_queue_tail(&cs->rq, skb);
+                                       sched_event_D(cs, D_RCVBUFREADY);
+                               }
+                       }
+               } else
+                       printk(KERN_WARNING "HFC: D receive out of memory\n");
+               sti();
+               WaitForBusy(cs);
+               cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC;
+               cli();
+               WaitNoBusy(cs);
+               stat = ReadReg(cs, HFCD_DATA, cip);
+               sti();
+               WaitForBusy(cs);
+               cip = HFCD_FIFO | HFCD_F2 | HFCD_REC;
+               cli();
+               WaitNoBusy(cs);
+               f2 = cs->readisac(cs, cip) & 0xf;
+       }
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+       restore_flags(flags);
+       return(1);
+} 
+
+static void
+hfc_fill_dfifo(struct IsdnCardState *cs)
+{
+       long flags;
+       int idx, fcnt;
+       int count;
+       u_char cip;
+       char tmp[64];
+
+       if (!cs->tx_skb)
+               return;
+       if (cs->tx_skb->len <= 0)
+               return;
+
+       save_flags(flags);
+       cli();
+       SelFiFo(cs, 4 | HFCD_SEND);
+       cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND;
+       WaitNoBusy(cs);
+       cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
+       WaitNoBusy(cs);
+       cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND;
+       cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf;
+       cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND);
+       sti();
+       if (cs->debug & L1_DEB_ISAC) {
+               sprintf(tmp, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)",
+                       cs->hw.hfcD.f1, cs->hw.hfcD.f2,
+                       cs->hw.hfcD.send[cs->hw.hfcD.f1]);
+               debugl1(cs, tmp);
+       }
+       fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2;
+       if (fcnt < 0)
+               fcnt += 16;
+       if (fcnt > 14) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfc_fill_Dfifo more as 14 frames");
+               restore_flags(flags);
+               return;
+       }
+       count = GetFreeFifoBytes_D(cs);
+       if (cs->debug & L1_DEB_ISAC) {
+               sprintf(tmp, "hfc_fill_Dfifo count(%d/%d)",
+                       cs->tx_skb->len, count);
+               debugl1(cs, tmp);
+       }
+       if (count < cs->tx_skb->len) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "hfc_fill_Dfifo no fifo mem");
+               restore_flags(flags);
+               return;
+       }
+       cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND;
+       idx = 0;
+       cli();
+       WaitForBusy(cs);
+       WaitNoBusy(cs);
+       WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]);
+       while (idx < cs->tx_skb->len) {
+               cli();
+               if (!(WaitNoBusy(cs)))
+                       break;
+               WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]);
+               sti();
+               idx++;
+       }
+       if (idx != cs->tx_skb->len) {
+               sti();
+               debugl1(cs, "DFIFO Send BUSY error");
+               printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n");
+       }
+       WaitForBusy(cs);
+       cli();
+       WaitNoBusy(cs);
+       ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
+       dev_kfree_skb(cs->tx_skb);
+       cs->tx_skb = NULL;
+       sti();
+       WaitForBusy(cs);
+       restore_flags(flags);
+       return;
+}
+
+static 
+struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
+{
+       if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
+               return(&cs->bcs[0]);
+       else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
+               return(&cs->bcs[1]);
+       else
+               return(NULL);
+}
+
+void
+hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
+{
+               u_char exval;
+               struct BCState *bcs;
+       char tmp[32];
+       int count=15;
+       long flags;
+
+       if (cs->debug & L1_DEB_ISAC) {
+               sprintf(tmp, "HFCD irq %x %s", val,
+                       test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
+                       "locked" : "unlocked");
+               debugl1(cs, tmp);
+       }
+       val &= cs->hw.hfcD.int_m1;
+       if (val & 0x40) { /* TE state machine irq */
+               exval = cs->readisac(cs, HFCD_STATES) & 0xf;
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "ph_state chg %d->%d", cs->ph_state,
+                               exval);
+                       debugl1(cs, tmp);
+               }
+               cs->ph_state = exval;
+               sched_event_D(cs, D_L1STATECHANGE);
+               val &= ~0x40;
+       }
+       while (val) {
+               save_flags(flags);
+               cli();
+               if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                       cs->hw.hfcD.int_s1 |= val;
+                       restore_flags(flags);
+                       return;
+               }
+               if (cs->hw.hfcD.int_s1 & 0x18) {
+                       exval = val;
+                       val =  cs->hw.hfcD.int_s1;
+                       cs->hw.hfcD.int_s1 = exval;
+               }       
+               if (val & 0x08) {
+                       if (!(bcs=Sel_BCS(cs, 0))) {
+                               if (cs->debug)
+                                       debugl1(cs, "hfcd spurious 0x08 IRQ");
+                       } else 
+                               main_rec_2bds0(bcs);
+               }
+               if (val & 0x10) {
+                       if (!(bcs=Sel_BCS(cs, 1))) {
+                               if (cs->debug)
+                                       debugl1(cs, "hfcd spurious 0x10 IRQ");
+                       } else 
+                               main_rec_2bds0(bcs);
+               }
+               if (val & 0x01) {
+                       if (!(bcs=Sel_BCS(cs, 0))) {
+                               if (cs->debug)
+                                       debugl1(cs, "hfcd spurious 0x01 IRQ");
+                       } else {
+                               if (bcs->hw.hfc.tx_skb) {
+                                       if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                               hfc_fill_fifo(bcs);
+                                               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                                       } else {
+                                               sprintf(tmp,"fill_data %d blocked", bcs->channel);
+                                               debugl1(cs, tmp);
+                                       }
+                               } else {
+                                       if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+                                               if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                                       hfc_fill_fifo(bcs);
+                                                       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                                               } else {
+                                                       sprintf(tmp,"fill_data %d blocked", bcs->channel);
+                                                       debugl1(cs, tmp);
+                                               }
+                                       } else {
+                                               hfc_sched_event(bcs, B_XMTBUFREADY);
+                                       }
+                               }
+                       }
+               }
+               if (val & 0x02) {
+                       if (!(bcs=Sel_BCS(cs, 1))) {
+                               if (cs->debug)
+                                       debugl1(cs, "hfcd spurious 0x02 IRQ");
+                       } else {
+                               if (bcs->hw.hfc.tx_skb) {
+                                       if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                               hfc_fill_fifo(bcs);
+                                               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                                       } else {
+                                               sprintf(tmp,"fill_data %d blocked", bcs->channel);
+                                               debugl1(cs, tmp);
+                                       }
+                               } else {
+                                       if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+                                               if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                                       hfc_fill_fifo(bcs);
+                                                       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                                               } else {
+                                                       sprintf(tmp,"fill_data %d blocked", bcs->channel);
+                                                       debugl1(cs, tmp);
+                                               }
+                                       } else {
+                                               hfc_sched_event(bcs, B_XMTBUFREADY);
+                                       }
+                               }
+                       }
+               }
+               if (val & 0x20) {       /* receive dframe */
+                       receive_dmsg(cs);
+               }
+               if (val & 0x04) {       /* dframe transmitted */
+                       if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+                               del_timer(&cs->dbusytimer);
+                       if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+                               sched_event_D(cs, D_CLEARBUSY);
+                       if (cs->tx_skb)
+                               if (cs->tx_skb->len) {
+                                       if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                               hfc_fill_dfifo(cs);
+                                               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                                       } else {
+                                               debugl1(cs, "hfc_fill_dfifo irq blocked");
+                                       }
+                                       goto afterXPR;
+                               } else {
+                                       dev_kfree_skb(cs->tx_skb);
+                                       cs->tx_cnt = 0;
+                                       cs->tx_skb = NULL;
+                               }
+                       if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+                               cs->tx_cnt = 0;
+                               if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                       hfc_fill_dfifo(cs);
+                                       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                               } else {
+                                       debugl1(cs, "hfc_fill_dfifo irq blocked");
+                               }
+                       } else
+                               sched_event_D(cs, D_XMTBUFREADY);
+               }
+      afterXPR:
+               if (cs->hw.hfcD.int_s1 && count--) {
+                       val = cs->hw.hfcD.int_s1;
+                       cs->hw.hfcD.int_s1 = 0;
+                       if (cs->debug & L1_DEB_ISAC) {
+                               sprintf(tmp, "HFCD irq %x loop %d", val, 15-count);
+                               debugl1(cs, tmp);
+                       }
+               } else
+                       val = 0;
+               restore_flags(flags);
+       }
+}
+
+static void
+HFCD_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       struct sk_buff *skb = arg;
+       char str[64];
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       if (cs->tx_skb) {
+                               skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+                       } else {
+                               if ((cs->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
+                                       LogFrame(cs, skb->data, skb->len);
+                                       sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                                       dlogframe(cs, skb->data + 4, skb->len - 4,
+                                                 str);
+                               }
+                               cs->tx_skb = skb;
+                               cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+                               if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                                       hfc_fill_dfifo(cs);
+                                       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                               } else
+                                       debugl1(cs, "hfc_fill_dfifo blocked");
+
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (cs->tx_skb) {
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+                               skb_queue_tail(&cs->sq, skb);
+                               break;
+                       }
+                       if ((cs->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
+                               LogFrame(cs, skb->data, skb->len);
+                               sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                               dlogframe(cs, skb->data + 4, skb->len - 4,
+                                         str);
+                       }
+                       cs->tx_skb = skb;
+                       cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+                       if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                               hfc_fill_dfifo(cs);
+                               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+                       } else
+                               debugl1(cs, "hfc_fill_dfifo blocked");
+                       break;
+               case (PH_PULL_REQ):
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+                       if (!cs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+void
+hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+       char tmp[32];
+       switch(msg) {
+               case PH_RESET_REQ:
+                       cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */
+                       udelay(6);
+                       cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */
+                       cs->hw.hfcD.mst_m |= HFCD_MASTER;
+                       cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+                       manl1_msg(cs, PH_POWERUP_CNF, NULL);
+                       break;
+               case PH_ENABLE_REQ:
+                       cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+                       break;
+               case PH_DEACT_ACK:
+                       cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
+                       cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       break;
+               case PH_INFO3_REQ:
+                       cs->hw.hfcD.mst_m |= HFCD_MASTER;
+                       cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       break;
+#if 0
+               case PH_TESTLOOP_REQ:
+                       u_char val = 0;
+                       if (1 & (int) arg)
+                               val |= 0x0c;
+                       if (2 & (int) arg)
+                               val |= 0x3;
+                       if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+                               /* IOM 1 Mode */
+                               if (!val) {
+                                       cs->writeisac(cs, ISAC_SPCR, 0xa);
+                                       cs->writeisac(cs, ISAC_ADF1, 0x2);
+                               } else {
+                                       cs->writeisac(cs, ISAC_SPCR, val);
+                                       cs->writeisac(cs, ISAC_ADF1, 0xa);
+                               }
+                       } else {
+                               /* IOM 2 Mode */
+                               cs->writeisac(cs, ISAC_SPCR, val);
+                               if (val)
+                                       cs->writeisac(cs, ISAC_ADF1, 0x8);
+                               else
+                                       cs->writeisac(cs, ISAC_ADF1, 0x0);
+                       }
+                       break;
+#endif
+               default:
+                       if (cs->debug & L1_DEB_WARN) {
+                               sprintf(tmp, "hfcd_l1cmd unknown %4x", msg);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+}
+
+void
+setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l2.l2l1 = HFCD_l2l1;
+}
+
+static void
+hfc_dbusy_timer(struct IsdnCardState *cs)
+{
+#if 0
+       struct PStack *stptr;
+       if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+               if (cs->debug)
+                       debugl1(cs, "D-Channel Busy");
+               test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+               stptr = cs->stlist;
+               
+               while (stptr != NULL) {
+                       stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL);
+                       stptr = stptr->next;
+               }
+       }
+#endif
+}
+
+__initfunc(unsigned int
+*init_send_hfcd(int cnt))
+{
+       int i, *send;
+
+       if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for hfcd.send\n");
+               return(NULL);
+       }
+       for (i = 0; i < cnt; i++)
+               send[i] = 0x1fff;
+       return(send);
+}
+
+__initfunc(void
+init2bds0(struct IsdnCardState *cs))
+{
+       cs->setstack_d = setstack_hfcd;
+       cs->l1cmd = hfcd_l1cmd;
+       cs->dbusytimer.function = (void *) hfc_dbusy_timer;
+       cs->dbusytimer.data = (long) cs;
+       init_timer(&cs->dbusytimer);
+       cs->tqueue.routine = (void *) (void *) hfcd_bh;
+       if (!cs->hw.hfcD.send)
+               cs->hw.hfcD.send = init_send_hfcd(16);
+       if (!cs->bcs[0].hw.hfc.send)
+               cs->bcs[0].hw.hfc.send = init_send_hfcd(32);
+       if (!cs->bcs[1].hw.hfc.send)
+               cs->bcs[1].hw.hfc.send = init_send_hfcd(32);
+       cs->BC_Send_Data = &hfc_send_data;
+       cs->bcs[0].BC_SetStack = setstack_2b;
+       cs->bcs[1].BC_SetStack = setstack_2b;
+       cs->bcs[0].BC_Close = close_2bs0;
+       cs->bcs[1].BC_Close = close_2bs0;
+       mode_2bs0(cs->bcs, 0, 0);
+       mode_2bs0(cs->bcs + 1, 0, 1);
+}
+
+void
+release2bds0(struct IsdnCardState *cs)
+{
+       if (cs->bcs[0].hw.hfc.send) {
+               kfree(cs->bcs[0].hw.hfc.send);
+               cs->bcs[0].hw.hfc.send = NULL;
+       }
+       if (cs->bcs[1].hw.hfc.send) {
+               kfree(cs->bcs[1].hw.hfc.send);
+               cs->bcs[1].hw.hfc.send = NULL;
+       }
+       if (cs->hw.hfcD.send) {
+               kfree(cs->hw.hfcD.send);
+               cs->hw.hfcD.send = NULL;
+       }
+}
diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h
new file mode 100644 (file)
index 0000000..d11e8b5
--- /dev/null
@@ -0,0 +1,131 @@
+/* $Id: hfc_2bds0.h,v 1.2 1998/02/02 13:26:15 keil Exp $
+
+ *  specific defines for CCD's HFC 2BDS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.h,v $
+ * Revision 1.2  1998/02/02 13:26:15  keil
+ * New
+ *
+ *
+ *
+ */
+
+#define HFCD_CIRM      0x18
+#define HFCD_CTMT      0x19
+#define HFCD_INT_M1    0x1A
+#define HFCD_INT_M2    0x1B
+#define HFCD_INT_S1    0x1E
+#define HFCD_STAT      0x1C
+#define HFCD_STAT_DISB  0x1D
+#define HFCD_STATES    0x30
+#define HFCD_SCTRL     0x31
+#define HFCD_TEST      0x32
+#define HFCD_SQ        0x34
+#define HFCD_CLKDEL    0x37
+#define HFCD_MST_MODE  0x2E
+#define HFCD_CONN      0x2F
+
+#define HFCD_FIFO      0x80
+#define HFCD_Z1                0x10
+#define HFCD_Z2                0x18
+#define HFCD_Z_LOW     0x00
+#define HFCD_Z_HIGH    0x04
+#define HFCD_F1_INC    0x12
+#define HFCD_FIFO_IN   0x16
+#define HFCD_F1                0x1a
+#define HFCD_F2                0x1e
+#define HFCD_F2_INC    0x22
+#define HFCD_FIFO_OUT  0x26
+#define HFCD_REC       0x01
+#define HFCD_SEND      0x00
+
+#define HFCB_FIFO      0x80
+#define HFCB_Z1                0x00
+#define HFCB_Z2                0x08
+#define HFCB_Z_LOW     0x00
+#define HFCB_Z_HIGH    0x04
+#define HFCB_F1_INC    0x28
+#define HFCB_FIFO_IN   0x2c
+#define HFCB_F1                0x30
+#define HFCB_F2                0x34
+#define HFCB_F2_INC    0x38
+#define HFCB_FIFO_OUT  0x3c
+#define HFCB_REC       0x01
+#define HFCB_SEND      0x00
+#define HFCB_B1                0x00
+#define HFCB_B2                0x02
+#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
+
+#define HFCD_STATUS    0
+#define HFCD_DATA      1
+#define HFCD_DATA_NODEB        2
+
+/* Status (READ) */
+#define HFCD_BUSY      0x01
+#define HFCD_BUSY_NBUSY        0x04
+#define HFCD_TIMER_ELAP        0x10
+#define HFCD_STATINT   0x20
+#define HFCD_FRAMEINT  0x40
+#define HFCD_ANYINT    0x80
+
+/* CTMT (Write) */
+#define HFCD_CLTIMER 0x80
+#define HFCD_TIM25  0x00
+#define HFCD_TIM50  0x08
+#define HFCD_TIM400 0x10
+#define HFCD_TIM800 0x18
+#define HFCD_AUTO_TIMER 0x20
+#define HFCD_TRANSB2 0x02
+#define HFCD_TRANSB1 0x01
+
+/* CIRM (Write) */
+#define HFCD_RESET     0x08
+#define HFCD_MEM8K     0x10
+#define HFCD_INTA      0x01
+#define HFCD_INTB      0x02
+#define HFCD_INTC      0x03
+#define HFCD_INTD      0x04
+#define HFCD_INTE      0x05
+#define HFCD_INTF      0x06
+
+/* INT_M1;INT_S1 */
+#define HFCD_INTS_B1TRANS      0x01
+#define HFCD_INTS_B2TRANS      0x02
+#define HFCD_INTS_DTRANS       0x04
+#define HFCD_INTS_B1REC                0x08
+#define HFCD_INTS_B2REC                0x10
+#define HFCD_INTS_DREC         0x20
+#define HFCD_INTS_L1STATE      0x40
+#define HFCD_INTS_TIMER                0x80
+
+/* INT_M2 */
+#define HFCD_IRQ_ENABLE                0x08
+
+/* STATES */
+#define HFCD_LOAD_STATE                0x10
+#define HFCD_ACTIVATE          0x20
+#define HFCD_DO_ACTION         0x40
+
+/* HFCD_MST_MODE */
+#define HFCD_MASTER            0x01
+
+/* HFCD_SCTRL */
+#define SCTRL_B1_ENA           0x01
+#define SCTRL_B2_ENA           0x02
+#define SCTRL_LOW_PRIO         0x08
+#define SCTRL_SQ_ENA           0x10
+#define SCTRL_TEST             0x20
+#define SCTRL_NONE_CAP         0x40
+#define SCTRL_PWR_DOWN         0x80
+
+/* HFCD_TEST */
+#define HFCD_AUTO_AWAKE                0x01
+
+extern void main_irq_2bds0(struct BCState *bcs);
+extern void init2bds0(struct IsdnCardState *cs);
+extern void release2bds0(struct IsdnCardState *cs);
+extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
+extern void set_cs_func(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
new file mode 100644 (file)
index 0000000..2d9ce5b
--- /dev/null
@@ -0,0 +1,615 @@
+/* $Id: hfc_2bs0.c,v 1.4 1998/02/12 23:07:29 keil Exp $
+
+ *  specific routines for CCD's HFC 2BS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bs0.c,v $
+ * Revision 1.4  1998/02/12 23:07:29  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.3  1997/11/06 17:13:35  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 19:04:47  keil
+ * changes for 2.1
+ *
+ * Revision 1.1  1997/09/11 17:31:33  keil
+ * Common part for HFC 2BS0 based cards
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bs0.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+static inline int
+WaitForBusy(struct IsdnCardState *cs)
+{
+       int to = 130;
+       long flags;
+       u_char val;
+
+       save_flags(flags);
+       cli();
+       while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+               val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
+                                     (cs->hw.hfc.cip & 3));
+               udelay(1);
+               to--;
+       }
+       restore_flags(flags);
+       if (!to) {
+               printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
+               return (0);
+       } else
+               return (to);
+}
+
+static inline int
+WaitNoBusy(struct IsdnCardState *cs)
+{
+       int to = 125;
+
+       while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
+               udelay(1);
+               to--;
+       }
+       if (!to) {
+               printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
+               return (0);
+       } else
+               return (to);
+}
+
+int
+GetFreeFifoBytes(struct BCState *bcs)
+{
+       int s;
+
+       if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
+               return (bcs->cs->hw.hfc.fifosize);
+       s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
+       if (s <= 0)
+               s += bcs->cs->hw.hfc.fifosize;
+       s = bcs->cs->hw.hfc.fifosize - s;
+       return (s);
+}
+
+int
+ReadZReg(struct BCState *bcs, u_char reg)
+{
+       int val;
+
+       WaitNoBusy(bcs->cs);
+       val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
+       WaitNoBusy(bcs->cs);
+       val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
+       return (val);
+}
+
+void
+hfc_sched_event(struct BCState *bcs, int event)
+{
+       bcs->event |= 1 << event;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static void
+hfc_clear_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       long flags;
+       int idx, cnt;
+       int rcnt, z1, z2;
+       u_char cip, f1, f2;
+       char tmp[64];
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hfc_clear_fifo");
+       save_flags(flags);
+       cli();
+       cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+       if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+               cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+               WaitForBusy(cs);
+       }
+       WaitNoBusy(cs);
+       f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+       z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+       cnt = 32;
+       while (((f1 != f2) || (z1 != z2)) && cnt--) {
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc clear %d f1(%d) f2(%d)",
+                               bcs->channel, f1, f2);
+                       debugl1(cs, tmp);
+               }
+               rcnt = z1 - z2;
+               if (rcnt < 0)
+                       rcnt += cs->hw.hfc.fifosize;
+               if (rcnt)
+                       rcnt++;
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
+                               bcs->channel, z1, z2, rcnt);
+                       debugl1(cs, tmp);
+               }
+               cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+               idx = 0;
+               while ((idx < rcnt) && WaitNoBusy(cs)) {
+                       cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+                       idx++;
+               }
+               if (f1 != f2) {
+                       WaitNoBusy(cs);
+                       cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+                                       HFC_CHANNEL(bcs->channel));
+                       WaitForBusy(cs);
+               }
+               cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+               WaitNoBusy(cs);
+               f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+               cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+               WaitNoBusy(cs);
+               f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+               z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+               z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+       }
+       restore_flags(flags);
+       return;
+}
+
+
+static struct sk_buff
+*
+hfc_empty_fifo(struct BCState *bcs, int count)
+{
+       u_char *ptr;
+       struct sk_buff *skb;
+       struct IsdnCardState *cs = bcs->cs;
+       int idx;
+       int chksum;
+       u_char stat, cip;
+       char tmp[64];
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hfc_empty_fifo");
+       idx = 0;
+       if (count > HSCX_BUFMAX + 3) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hfc_empty_fifo: incoming packet too large");
+               cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+               while ((idx++ < count) && WaitNoBusy(cs))
+                       cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+               WaitNoBusy(cs);
+               stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+                                      HFC_CHANNEL(bcs->channel));
+               WaitForBusy(cs);
+               return (NULL);
+       }
+       if (count < 4) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hfc_empty_fifo: incoming packet too small");
+               cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+               while ((idx++ < count) && WaitNoBusy(cs))
+                       cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+               WaitNoBusy(cs);
+               stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+                                      HFC_CHANNEL(bcs->channel));
+               WaitForBusy(cs);
+               return (NULL);
+       }
+       if (!(skb = dev_alloc_skb(count - 3)))
+               printk(KERN_WARNING "HFC: receive out of memory\n");
+       else {
+               ptr = skb_put(skb, count - 3);
+               idx = 0;
+               cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
+               while ((idx < count - 3) && WaitNoBusy(cs)) {
+                       *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
+                       idx++;
+               }
+               if (idx != count - 3) {
+                       debugl1(cs, "RFIFO BUSY error");
+                       printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
+                       dev_kfree_skb(skb);
+                       WaitNoBusy(cs);
+                       stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+                                              HFC_CHANNEL(bcs->channel));
+                       WaitForBusy(cs);
+                       return (NULL);
+               }
+               WaitNoBusy(cs);
+               chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
+               WaitNoBusy(cs);
+               chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
+               WaitNoBusy(cs);
+               stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x",
+                               bcs->channel, chksum, stat);
+                       debugl1(cs, tmp);
+               }
+               if (stat) {
+                       debugl1(cs, "FIFO CRC error");
+                       dev_kfree_skb(skb);
+                       skb = NULL;
+               }
+               WaitNoBusy(cs);
+               stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
+                                      HFC_CHANNEL(bcs->channel));
+               WaitForBusy(cs);
+       }
+       return (skb);
+}
+
+static void
+hfc_fill_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       long flags;
+       int idx, fcnt;
+       int count;
+       u_char cip;
+       char tmp[64];
+
+       if (!bcs->hw.hfc.tx_skb)
+               return;
+       if (bcs->hw.hfc.tx_skb->len <= 0)
+               return;
+
+       save_flags(flags);
+       cli();
+       cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+       if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+               cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+               WaitForBusy(cs);
+       }
+       WaitNoBusy(cs);
+       bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
+                       bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
+                       bcs->hw.hfc.send[bcs->hw.hfc.f1]);
+               debugl1(cs, tmp);
+       }
+       fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
+       if (fcnt < 0)
+               fcnt += 32;
+       if (fcnt > 30) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfc_fill_fifo more as 30 frames");
+               restore_flags(flags);
+               return;
+       }
+       count = GetFreeFifoBytes(bcs);
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "hfc_fill_fifo %d count(%d/%d)",
+                       bcs->channel, bcs->hw.hfc.tx_skb->len,
+                       count);
+               debugl1(cs, tmp);
+       }
+       if (count < bcs->hw.hfc.tx_skb->len) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfc_fill_fifo no fifo mem");
+               restore_flags(flags);
+               return;
+       }
+       cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
+       idx = 0;
+       while ((idx < bcs->hw.hfc.tx_skb->len) && WaitNoBusy(cs))
+               cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]);
+       if (idx != bcs->hw.hfc.tx_skb->len) {
+               debugl1(cs, "FIFO Send BUSY error");
+               printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
+       } else {
+               count =  bcs->hw.hfc.tx_skb->len;
+               bcs->tx_cnt -= count;
+               if (PACKET_NOACK == bcs->hw.hfc.tx_skb->pkt_type)
+                       count = -1;
+               dev_kfree_skb(bcs->hw.hfc.tx_skb);
+               bcs->hw.hfc.tx_skb = NULL;
+               WaitForBusy(cs);
+               WaitNoBusy(cs);
+               cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
+               if (bcs->st->lli.l1writewakeup && (count >= 0))
+                       bcs->st->lli.l1writewakeup(bcs->st, count);
+               test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       }
+       restore_flags(flags);
+       return;
+}
+
+void
+main_irq_hfc(struct BCState *bcs)
+{
+       long flags;
+       struct IsdnCardState *cs = bcs->cs;
+       int z1, z2, rcnt;
+       u_char f1, f2, cip;
+       int receive, transmit, count = 5;
+       struct sk_buff *skb;
+       char tmp[64];
+
+       save_flags(flags);
+      Begin:
+       cli();
+       count--;
+       cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
+       if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
+               cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
+               WaitForBusy(cs);
+       }
+       WaitNoBusy(cs);
+       f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
+       WaitNoBusy(cs);
+       f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
+       if (f1 != f2) {
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc rec %d f1(%d) f2(%d)",
+                               bcs->channel, f1, f2);
+                       debugl1(cs, tmp);
+               }
+               WaitForBusy(cs);
+               z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
+               z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
+               rcnt = z1 - z2;
+               if (rcnt < 0)
+                       rcnt += cs->hw.hfc.fifosize;
+               rcnt++;
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
+                               bcs->channel, z1, z2, rcnt);
+                       debugl1(cs, tmp);
+               }
+/*              sti(); */
+               if ((skb = hfc_empty_fifo(bcs, rcnt))) {
+                       skb_queue_tail(&bcs->rqueue, skb);
+                       hfc_sched_event(bcs, B_RCVBUFREADY);
+               }
+               receive = 1;
+       } else
+               receive = 0;
+       restore_flags(flags);
+       udelay(1);
+       cli();
+       if (bcs->hw.hfc.tx_skb) {
+               transmit = 1;
+               test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+               hfc_fill_fifo(bcs);
+               if (test_bit(BC_FLG_BUSY, &bcs->Flag))
+                       transmit = 0;
+       } else {
+               if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+                       transmit = 1;
+                       test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+                       hfc_fill_fifo(bcs);
+                       if (test_bit(BC_FLG_BUSY, &bcs->Flag))
+                               transmit = 0;
+               } else {
+                       transmit = 0;
+                       hfc_sched_event(bcs, B_XMTBUFREADY);
+               }
+       }
+       restore_flags(flags);
+       if ((receive || transmit) && count)
+               goto Begin;
+       return;
+}
+
+void
+mode_hfc(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+
+       if (cs->debug & L1_DEB_HSCX) {
+               char tmp[40];
+               sprintf(tmp, "HFC 2BS0 mode %d bchan %d/%d",
+                       mode, bc, bcs->channel);
+               debugl1(cs, tmp);
+       }
+       bcs->mode = mode;
+
+       switch (mode) {
+               case (L1_MODE_NULL):
+                       if (bc)
+                               cs->hw.hfc.isac_spcr &= ~0x03;
+                       else
+                               cs->hw.hfc.isac_spcr &= ~0x0c;
+                       break;
+               case (L1_MODE_TRANS):
+                       if (bc) {
+                               cs->hw.hfc.ctmt |= 1;
+                               cs->hw.hfc.isac_spcr &= ~0x03;
+                               cs->hw.hfc.isac_spcr |= 0x02;
+                       } else {
+                               cs->hw.hfc.ctmt |= 2;
+                               cs->hw.hfc.isac_spcr &= ~0x0c;
+                               cs->hw.hfc.isac_spcr |= 0x08;
+                       }
+                       break;
+               case (L1_MODE_HDLC):
+                       if (bc) {
+                               cs->hw.hfc.ctmt &= ~1;
+                               cs->hw.hfc.isac_spcr &= ~0x03;
+                               cs->hw.hfc.isac_spcr |= 0x02;
+                       } else {
+                               cs->hw.hfc.ctmt &= ~2;
+                               cs->hw.hfc.isac_spcr &= ~0x0c;
+                               cs->hw.hfc.isac_spcr |= 0x08;
+                       }
+                       break;
+       }
+       cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
+       cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
+       if (mode)
+               hfc_clear_fifo(bcs);
+}
+
+static void
+hfc_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->hw.hfc.tx_skb = skb;
+                               test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                               st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                               restore_flags(flags);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                               printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       save_flags(flags);
+                       cli();
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       st->l1.bcs->hw.hfc.tx_skb = skb;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       restore_flags(flags);
+                       break;
+               case (PH_PULL_REQ):
+                       if (!st->l1.bcs->hw.hfc.tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+void
+close_hfcstate(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       mode_hfc(bcs, 0, 0);
+       if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+               if (bcs->hw.hfc.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hfc.tx_skb);
+                       bcs->hw.hfc.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+       test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+}
+
+static int
+open_hfcstate(struct IsdnCardState *cs,
+             int bc)
+{
+       struct BCState *bcs = cs->bcs + bc;
+
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->hw.hfc.tx_skb = NULL;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       bcs->event = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+static void
+hfc_manl1(struct PStack *st, int pr,
+         void *arg)
+{
+       switch (pr) {
+               case (PH_ACTIVATE_REQ):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       break;
+               case (PH_DEACTIVATE_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+                               mode_hfc(st->l1.bcs, 0, 0);
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       break;
+       }
+}
+
+int
+setstack_hfc(struct PStack *st, struct BCState *bcs)
+{
+       if (open_hfcstate(st->l1.hardware, bcs->channel))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = hfc_l2l1;
+       st->ma.manl1 = hfc_manl1;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+__initfunc(void
+init_send(struct BCState *bcs))
+{
+       int i;
+
+       if (!(bcs->hw.hfc.send = kmalloc(32 * sizeof(unsigned int), GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for hfc.send\n");
+               return;
+       }
+       for (i = 0; i < 32; i++)
+               bcs->hw.hfc.send[i] = 0x1fff;
+}
+
+__initfunc(void
+inithfc(struct IsdnCardState *cs))
+{
+       init_send(&cs->bcs[0]);
+       init_send(&cs->bcs[1]);
+       cs->BC_Send_Data = &hfc_fill_fifo;
+       cs->bcs[0].BC_SetStack = setstack_hfc;
+       cs->bcs[1].BC_SetStack = setstack_hfc;
+       cs->bcs[0].BC_Close = close_hfcstate;
+       cs->bcs[1].BC_Close = close_hfcstate;
+       mode_hfc(cs->bcs, 0, 0);
+       mode_hfc(cs->bcs + 1, 0, 0);
+}
+
+void
+releasehfc(struct IsdnCardState *cs)
+{
+       if (cs->bcs[0].hw.hfc.send) {
+               kfree(cs->bcs[0].hw.hfc.send);
+               cs->bcs[0].hw.hfc.send = NULL;
+       }
+       if (cs->bcs[1].hw.hfc.send) {
+               kfree(cs->bcs[1].hw.hfc.send);
+               cs->bcs[1].hw.hfc.send = NULL;
+       }
+}
diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h
new file mode 100644 (file)
index 0000000..cce8e4a
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id: hfc_2bs0.h,v 1.1 1997/09/11 17:31:34 keil Exp $
+
+ *  specific defines for CCD's HFC 2BS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bs0.h,v $
+ * Revision 1.1  1997/09/11 17:31:34  keil
+ * Common part for HFC 2BS0 based cards
+ *
+ *
+ */
+
+#define HFC_CTMT       0xe0
+#define HFC_CIRM       0xc0
+#define HFC_CIP                0x80
+#define HFC_Z1         0x00
+#define HFC_Z2         0x08
+#define HFC_Z_LOW      0x00
+#define HFC_Z_HIGH     0x04
+#define HFC_F1_INC     0x28
+#define HFC_FIFO_IN    0x2c
+#define HFC_F1         0x30
+#define HFC_F2         0x34
+#define HFC_F2_INC     0x38
+#define HFC_FIFO_OUT   0x3c
+#define HFC_B1          0x00
+#define HFC_B2         0x02
+#define HFC_REC                0x01
+#define HFC_SEND       0x00
+#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
+
+#define HFC_STATUS     0
+#define HFC_DATA       1
+#define HFC_DATA_NODEB 2
+
+/* Status (READ) */
+#define HFC_BUSY       0x01
+#define HFC_TIMINT     0x02
+#define HFC_EXTINT     0x04
+
+/* CTMT (Write) */
+#define HFC_CLTIMER 0x10
+#define HFC_TIM50MS 0x08
+#define HFC_TIMIRQE 0x04
+#define HFC_TRANSB2 0x02
+#define HFC_TRANSB1 0x01
+
+/* CIRM (Write) */
+#define HFC_RESET      0x08
+#define HFC_MEM8K      0x10
+#define HFC_INTA       0x01
+#define HFC_INTB       0x02
+#define HFC_INTC       0x03
+#define HFC_INTD       0x04
+#define HFC_INTE       0x05
+#define HFC_INTF       0x06
+
+extern void main_irq_hfc(struct BCState *bcs);
+extern void inithfc(struct IsdnCardState *cs);
+extern void releasehfc(struct IsdnCardState *cs);
index efe7d53290dfa7427232500b27c36be6cd1a8317..f5b15e2bf59eb3d56b9a167fb72fa87aecd9b0c1 100644 (file)
@@ -1,52 +1,59 @@
-/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $
+/* $Id: hisax.h,v 2.14 1998/02/11 17:28:04 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 2.14  1998/02/11 17:28:04  keil
+ * Niccy PnP/PCI support
  *
- * Revision 1.12  1997/03/23 21:45:45  keil
- * Add support for ELSA PCMCIA
+ * Revision 2.13  1998/02/09 18:46:02  keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
  *
- * Revision 1.11  1997/02/11 01:36:02  keil
- * New Param structure
+ * Revision 2.12  1998/02/03 23:31:30  keil
+ * add AMD7930 support
  *
- * Revision 1.10  1997/02/09 00:23:52  keil
- * new interface handling, one interface per card
+ * Revision 2.11  1998/02/02 13:33:00  keil
+ * New card support
  *
- * Revision 1.9  1997/01/27 23:18:44  keil
- * prototype for releasestack_isdnl3
+ * Revision 2.10  1997/11/08 21:37:52  keil
+ * new l1 init;new Compaq card
  *
- * Revision 1.8  1997/01/27 16:02:37  keil
- * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype
+ * Revision 2.9  1997/11/06 17:09:09  keil
+ * New 2.1 init code
  *
- * Revision 1.7  1997/01/21 22:22:14  keil
- * changes for 2.0; Elsa Quickstep support
+ * Revision 2.8  1997/10/29 19:04:13  keil
+ * new L1; changes for 2.1
  *
- * Revision 1.6  1997/01/04 13:48:28  keil
- * primitiv for MDL_REMOVE added
+ * Revision 2.7  1997/10/10 20:56:47  fritz
+ * New HL interface.
  *
- * Revision 1.5  1996/12/08 19:49:19  keil
- * Monitor channel support
+ * Revision 2.6  1997/09/11 17:25:51  keil
+ * Add new cards
  *
- * Revision 1.4  1996/11/18 15:35:39  keil
- * some changes for ELSA cards
+ * Revision 2.5  1997/08/03 14:36:31  keil
+ * Implement RESTART procedure
  *
- * Revision 1.3  1996/11/05 19:37:23  keil
- * using config.h
+ * Revision 2.4  1997/07/31 19:25:20  keil
+ * PTP_DATA_LINK support
  *
- * Revision 1.2  1996/10/27 22:21:52  keil
- * CallFlags for broadcast messages
+ * Revision 2.3  1997/07/31 11:50:17  keil
+ * ONE TEI and FIXED TEI handling
  *
- * Revision 1.1  1996/10/13 20:03:46  keil
- * Initial revision
+ * Revision 2.2  1997/07/30 17:13:02  keil
+ * more changes for 'One TEI per card'
  *
+ * Revision 2.1  1997/07/27 21:45:13  keil
+ * new main structures
  *
+ * Revision 2.0  1997/06/26 11:06:27  keil
+ * New card and L1 interface.
+ * Eicon.Diehl Diva and Dynalink IS64PH support
+ *
+ * old changes removed KKe
  *
  */
-#include <linux/module.h>
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/fs.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;
-};
+#include <linux/init.h>
+
+#define PH_ACTIVATE_REQ        0x0010
+#define PH_ACTIVATE_CNF        0x0011
+#define PH_ACTIVATE_IND        0x0012
+#define PH_DEACTIVATE_REQ 0x0020
+#define PH_DEACTIVATE_CNF 0x0021
+#define PH_DEACTIVATE_IND 0x0022
+#define PH_DEACT_REQ   0x0024
+#define PH_DEACT_CNF   0x0025
+#define PH_DEACT_IND   0x0026
+#define PH_DEACT_ACK   0x0027
+#define PH_TESTLOOP_REQ        0x0030
+#define PH_PAUSE_CNF   0x0035
+#define PH_PAUSE_IND   0x0036
+#define PH_PULL_REQ    0x0038
+#define PH_PULL_CNF    0x0039
+#define        PH_PULL_IND     0x003A
+#define PH_DATA_REQ    0x0040
+#define PH_DATA_IND    0x0042
+
+#define PH_INFO3_REQ   0x0008
+#define PH_INFO2_IND   0x000A
+#define PH_ENABLE_REQ  0x0004
+#define PH_RSYNC_IND   0x0006
+#define PH_RESET_REQ   0x0000
+#define PH_RESET_IND   0x0002
+#define PH_POWERUP_CNF 0x0003
+#define PH_ACTIV_REQ   0x000C
+#define PH_I4_P8_IND   0x000D
+#define PH_I4_P10_IND  0x000F
+
+#define MDL_ASSIGN_REQ 0x0050
+#define MDL_ASSIGN_IND 0x0052
+#define MDL_REMOVE_REQ 0x0054
+#define MDL_ERROR_REQ  0x0058
+#define MDL_ERROR_IND  0x005A
+#define CARD_AUX_IND   0x005E
+
+#define DL_UNIT_DATA   6
+#define CC_ESTABLISH   7
+#define DL_ESTABLISH   8
+#define DL_DATA                9
+
+#define CC_CONNECT     15
+#define DL_RELEASE     20
+#define DL_FLUSH       21
+
+#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_INFO_SETUP 42
+#define MDL_INFO_CONN  43
+#define MDL_INFO_REL   44
+#define MDL_NOTEIPROC  46
+
+#define LC_ESTABLISH   47
+#define LC_RELEASE     48
+
+#define CC_INFO_CHARGE 52
+
+#define CC_MORE_INFO   53
+#define CC_IGNORE      54
+#define CC_RESTART     55
+
+
+#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
+
+#define CARD_RESET     0x1001
+#define CARD_SETIRQ    0x1002
+#define CARD_INIT      0x1003
+#define CARD_RELEASE   0x1004
+#define CARD_TEST      0x1005
 
 #ifdef __KERNEL__
 
-#undef DEBUG_MAGIC
-
-#define MAX_DFRAME_LEN 3072
+#define MAX_DFRAME_LEN 260
 #define HSCX_BUFMAX    4096
 #define MAX_DATA_SIZE  (HSCX_BUFMAX - 4)
-#define MAX_DATA_MEM    (HSCX_BUFMAX * 2)
+#define MAX_DATA_MEM   (HSCX_BUFMAX + 64)
+#define RAW_BUFMAX     (((HSCX_BUFMAX*6)/5) + 5)
 #define MAX_HEADER_LEN 4
 #define MAX_WINDOW     8
+#define MAX_MON_FRAME  32
+
+/* #define I4L_IRQ_FLAG SA_INTERRUPT */
+#define I4L_IRQ_FLAG    0
 
 /*
  * Statemachine
  */
+
 struct Fsm {
        int *jumpmatrix;
        int state_count, event_count;
@@ -226,73 +229,107 @@ struct FsmTimer {
 };
 
 struct L3Timer {
-       struct PStack *st;
+       struct l3_process *pc;
        struct timer_list tl;
        int event;
 };
 
+#define FLG_L1_ACTIVATING      1
+#define FLG_L1_ACTIVATED       2
+#define FLG_L1_DEACTTIMER      3
+#define FLG_L1_ACTTIMER                4
+#define FLG_L1_T3RUN           5
+#define FLG_L1_PULL_REQ                6
+
 struct Layer1 {
        void *hardware;
-       int hscx;
+       struct BCState *bcs;
        struct PStack **stlistp;
-       int act_state;
+       int Flags;
+       struct FsmInst l1m;
+       struct FsmTimer timer;
        void (*l1l2) (struct PStack *, int, void *);
        void (*l1man) (struct PStack *, int, void *);
-       int hscxmode, hscxchannel, requestpull;
+       void (*l1tei) (struct PStack *, int, void *);
+       int mode, bc;
 };
 
+#define GROUP_TEI      127
+#define TEI_SAPI       63
+#define CTRL_SAPI      0
+#define PACKET_NOACK   250
+
+/* Layer2 Flags */
+
+#define FLG_LAPB       0
+#define FLG_LAPD       1
+#define FLG_ORIG       2
+#define FLG_MOD128     3
+#define FLG_PEND_REL   4
+#define FLG_L3_INIT    5 
+#define FLG_T200_RUN   6 
+#define FLG_ACK_PEND   7
+#define FLG_REJEXC     8
+#define FLG_OWN_BUSY   9
+#define FLG_PEER_BUSY  10
+#define FLG_DCHAN_BUSY 11
+
 struct Layer2 {
-       int sap, tei, ces;
-       int extended, laptype;
-       int uihsize, ihsize;
+       int tei;
+       int tei_wanted;
+       int sap;
+       int maxlen;
+       unsigned int flag;
        int vs, va, vr;
-       struct sk_buff_head i_queue;
-       int window, orig;
-       int rejexp;
-       int debug;
-       struct sk_buff *windowar[MAX_WINDOW];
+       int rc;
+       int window;
        int sow;
-       struct FsmInst l2m;
+       struct sk_buff *windowar[MAX_WINDOW];
+       struct sk_buff_head i_queue;
+       struct sk_buff_head ui_queue;
        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;
+       struct FsmInst l2m;
+       struct FsmTimer t200, t203;
+       int T200, N200, T203;
+       int debug;
        char debug_id[32];
 };
 
 struct Layer3 {
-       void (*l3l4) (struct PStack *, int, void *);
+       void (*l3l4) (struct l3_process *, 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;
+       struct l3_process *proc;
+       struct l3_process *global;
+       int N303;
        int debug;
-       int channr;
 };
 
-struct Layer4 {
+struct LLInterface {
        void (*l4l3) (struct PStack *, int, void *);
        void *userdata;
-       void (*l1writewakeup) (struct PStack *);
-       void (*l2writewakeup) (struct PStack *);
+       void (*l1writewakeup) (struct PStack *, int);
+       void (*l2writewakeup) (struct PStack *, int);
 };
 
+
 struct Management {
+       int     ri;
+       struct FsmInst tei_m;
+       struct FsmTimer t202;
+       int T202, N202, debug;
+       void (*layer) (struct PStack *, int, void *);
        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
@@ -300,39 +337,114 @@ struct Param {
        int spv;                /* SPV Flag */
 };
 
+
 struct PStack {
        struct PStack *next;
        struct Layer1 l1;
        struct Layer2 l2;
        struct Layer3 l3;
-       struct Layer4 l4;
+       struct LLInterface lli; 
        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 */
+struct l3_process {
+       int callref;
+       int state;
+       struct L3Timer timer;
+       int N303;
+       int debug;
+       struct Param para;
+       struct Channel *chan;
+       struct PStack *st;
+       struct l3_process *next;
+};
+
+struct hscx_hw {
+       int rcvidx;
+       int count;              /* Current skb sent count */
+       u_char *rcvbuf;         /* B-Channel receive Buffer */
+       struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+struct hfcB_hw {
+       unsigned int *send;
+       int f1;
+       int f2;
+       struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+struct tiger_hw {
+       struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+       u_int *send;
+       u_int *s_irq;
+       u_int *s_end;
+       u_int *sendp;
+       u_int *rec;
+       int free;
+       u_char *rcvbuf;
+       u_char *sendbuf;
+       u_char *sp;
+       int sendcnt;
+       u_int s_tot;
+       u_int r_bitcnt;
+       u_int r_tot;
+       u_int r_err;
+       u_int r_fcs;
+       u_char r_state;
+       u_char r_one;
+       u_char r_val;
+       u_char s_state;
+};
+
+struct amd7930_hw {
+       u_char *tx_buff;
+       u_char *rv_buff;
+       int rv_buff_in;
+       int rv_buff_out;
+       struct sk_buff *rv_skb;
+       struct hdlc_state *hdlc_state;
+       struct tq_struct tq_rcv;
+       struct tq_struct tq_xmt;
+       struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+#define BC_FLG_INIT    1
+#define BC_FLG_ACTIV   2
+#define BC_FLG_BUSY    3
+#define BC_FLG_NOFRAME 4
+#define BC_FLG_HALF    5
+#define BC_FLG_EMPTY   6
+
+#define L1_MODE_NULL   0
+#define L1_MODE_TRANS  1
+#define L1_MODE_HDLC   2
+
+struct BCState {
+       int channel;
+       int mode;
+       int Flag;
+       struct IsdnCardState *cs;
        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 sk_buff_head squeue;     /* B-Channel send Queue */
        struct PStack *st;
        struct tq_struct tqueue;
        int event;
-#ifdef DEBUG_MAGIC
-       int magic;              /* 301270 */
-#endif
+       int  (*BC_SetStack) (struct PStack *, struct BCState *);
+       void (*BC_Close) (struct BCState *);
+       union {
+               struct hscx_hw hscx;
+               struct hfcB_hw hfc;
+               struct tiger_hw tiger;
+               struct amd7930_hw  amd7930;
+       } hw;
 };
 
 struct LcFsm {
-       struct FsmInst lcfi;
        int type;
+       int delay;
+       struct FsmInst lcfi;
        struct Channel *ch;
        void (*lccall) (struct LcFsm *, int, void *);
        struct PStack *st;
@@ -343,52 +455,209 @@ struct LcFsm {
 };
 
 struct Channel {
-       struct PStack ds, is;
-       struct IsdnCardState *sp;
-       int hscx;
+       struct PStack *b_st, *d_st;
+       struct IsdnCardState *cs;
+       struct BCState *bcs;
        int chan;
        int incoming;
        struct FsmInst fi;
-       struct LcFsm lc_d, lc_b;
-       struct Param para;
+       struct LcFsm *lc_d;
+       struct LcFsm *lc_b;
        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;
+       struct l3_process *proc;
+       setup_parm setup;       /* from isdnif.h numbers and Serviceindicator */
        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;
+struct elsa_hw {
+       unsigned int base;
+       unsigned int cfg;
+       unsigned int ctrl;
+       unsigned int ale;
+       unsigned int isac;
+       unsigned int itac;
+       unsigned int hscx;
+       unsigned int trig;
+       unsigned int timer;
+       unsigned int counter;
+       unsigned int status;
+       struct timer_list tl;
+       u_char ctrl_reg;
+};     
+
+struct teles3_hw {
+       unsigned int cfg_reg;
+       unsigned int isac;
+       unsigned int hscx[2];
+       unsigned int isacfifo;
+       unsigned int hscxfifo[2];
+};     
+
+struct teles0_hw {
        unsigned int cfg_reg;
        unsigned int membase;
+};     
+
+struct avm_hw {
+       unsigned int cfg_reg;
        unsigned int isac;
        unsigned int hscx[2];
+       unsigned int isacfifo;
+       unsigned int hscxfifo[2];
        unsigned int counter;
+};     
+
+struct ix1_hw {
+       unsigned int cfg_reg;
+       unsigned int isac_ale;
+       unsigned int isac;
+       unsigned int hscx_ale;
+       unsigned int hscx;
+};
+
+struct diva_hw {
+       unsigned int cfg_reg;
+       unsigned int ctrl;
+       unsigned int isac_adr;
+       unsigned int isac;
+       unsigned int hscx_adr;
+       unsigned int hscx;
+       unsigned int status;
+       struct timer_list tl;
+       u_char ctrl_reg;
+};     
+
+struct asus_hw {
+       unsigned int cfg_reg;
+       unsigned int adr;
+       unsigned int isac;
+       unsigned int hscx;
+       unsigned int u7;
+       unsigned int pots;
+};
+
+
+struct hfc_hw {
+       unsigned int addr;
+       unsigned int fifosize;
+       unsigned char cirm;
+       unsigned char ctmt;
+       unsigned char cip;
+       u_char isac_spcr;
+       struct timer_list timer;
+};
+
+struct sedl_hw {
+       unsigned int cfg_reg;
+       unsigned int adr;
+       unsigned int isac;
+       unsigned int hscx;
+       unsigned int reset_on;
+       unsigned int reset_off;
+};
+
+struct spt_hw {
+       unsigned int cfg_reg;
+       unsigned int isac;
+       unsigned int hscx[2];
+       unsigned char res_irq;
+};     
+
+struct mic_hw {
+       unsigned int cfg_reg;
+       unsigned int adr;
+       unsigned int isac;
+       unsigned int hscx;
+};
+
+struct njet_hw {
+       unsigned int base;
+       unsigned int isac;
+       unsigned int auxa;
+       unsigned char auxd;
+       unsigned char dmactrl;
+       unsigned char ctrl_reg;
+       unsigned char irqmask0;
+       unsigned char irqstat0;
+       unsigned char last_is0;
+};
+
+struct hfcD_hw {
+       unsigned int addr;
+       unsigned int bfifosize;
+       unsigned int dfifosize;
+       unsigned char cirm;
+       unsigned char ctmt;
+       unsigned char cip;
+       unsigned char conn;
+       unsigned char mst_m;
+       unsigned char int_m1;
+       unsigned char int_m2;
+       unsigned char int_s1;
+       unsigned char sctrl;
+       unsigned char stat;
+       unsigned char fifo;
+       unsigned char f1;
+       unsigned char f2;
+       unsigned int *send;
+       struct timer_list timer;
+};
+
+#define HW_IOM1                0
+#define HW_IPAC                1
+#define FLG_TWO_DCHAN  4
+#define FLG_L1_DBUSY   5
+#define FLG_DBUSY_TIMER 6
+#define FLG_LOCK_ATOMIC 7
+#define HW_MON0_RX_END 8
+#define HW_MON1_RX_END 9
+#define HW_MON0_TX_END 10
+#define HW_MON1_TX_END 11
+
+struct IsdnCardState {
+       unsigned char typ;
+       unsigned char subtyp;
+       int protocol;
+       unsigned int irq;
+       int HW_Flags; 
+       int *busy_flag;
+       union {
+               struct elsa_hw elsa;
+               struct teles0_hw teles0;
+               struct teles3_hw teles3;
+               struct avm_hw avm;
+               struct ix1_hw ix1;
+               struct diva_hw diva;
+               struct asus_hw asus;
+               struct hfc_hw hfc;
+               struct sedl_hw sedl;
+               struct spt_hw spt;
+               struct mic_hw mic;
+               struct njet_hw njet;
+               struct hfcD_hw hfcD;
+               struct ix1_hw niccy;
+       } hw;
        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 *);
+       u_char (*readisac) (struct IsdnCardState *, u_char);
+       void   (*writeisac) (struct IsdnCardState *, u_char, u_char);
+       void   (*readisacfifo) (struct IsdnCardState *, u_char *, int);
+       void   (*writeisacfifo) (struct IsdnCardState *, u_char *, int);
+       u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char);
+       void   (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
+       void   (*BC_Send_Data) (struct BCState *);
+       int    (*cardmsg) (struct IsdnCardState *, int, void *);
+       void   (*l1cmd) (struct IsdnCardState *, int, void *);
        struct Channel channel[2];
+       struct BCState bcs[2];
        struct PStack *stlist;
        u_char *rcvbuf;
        int rcvidx;
@@ -396,16 +665,20 @@ struct IsdnCardState {
        int tx_cnt;
        int event;
        struct tq_struct tqueue;
-       int ph_active;
+       struct timer_list dbusytimer;
        struct sk_buff_head rq, sq; /* D-channel queues */
-       int cardnr;
        int ph_state;
-       struct PStack *teistack;
-       struct HscxState hs[2];
+       int cardnr;
        int dlogflag;
        char *dlogspace;
        int debug;
-       unsigned int CallFlags;
+       u_char *mon_tx;
+       u_char *mon_rx;
+       int mon_txp;
+       int mon_txc;
+       int mon_rxp;
+       u_char mocr;
+       void   (*setstack_d) (struct PStack *, struct IsdnCardState *);
 };
 
 #define  MON0_RX       1
@@ -419,99 +692,246 @@ struct IsdnCardState {
 #define  ISDN_CTYPE_PNP                4
 #define  ISDN_CTYPE_A1         5
 #define  ISDN_CTYPE_ELSA       6
-#define  ISDN_CTYPE_ELSA_QS1000        7
+#define  ISDN_CTYPE_ELSA_PNP   7
 #define  ISDN_CTYPE_TELESPCMCIA        8
 #define  ISDN_CTYPE_IX1MICROR2 9
+#define  ISDN_CTYPE_ELSA_PCMCIA        10
+#define  ISDN_CTYPE_DIEHLDIVA  11
+#define  ISDN_CTYPE_ASUSCOM    12
+#define  ISDN_CTYPE_TELEINT    13
+#define  ISDN_CTYPE_TELES3C    14
+#define  ISDN_CTYPE_SEDLBAUER  15
+#define  ISDN_CTYPE_SPORTSTER  16
+#define  ISDN_CTYPE_MIC                17
+#define  ISDN_CTYPE_ELSA_PCI   18
+#define  ISDN_CTYPE_COMPAQ_ISA 19
+#define  ISDN_CTYPE_NETJET     20
+#define  ISDN_CTYPE_TELESPCI   21
+#define  ISDN_CTYPE_SEDLBAUER_PCMCIA   22
+#define  ISDN_CTYPE_AMD7930    23
+#define  ISDN_CTYPE_NICCY      24
+
+#define  ISDN_CTYPE_COUNT      24
+
+#ifdef ISDN_CHIP_ISAC
+#undef ISDN_CHIP_ISAC
+#endif
 
-#define  ISDN_CTYPE_COUNT      9
+#define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
+#define HISAX_INITDATA __initdata
 
 #ifdef CONFIG_HISAX_16_0
 #define  CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
 #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)
+                    (1<< ISDN_CTYPE_TELESPCMCIA) | (1<< ISDN_CTYPE_COMPAQ_ISA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
 #else
 #define  CARD_TELES3  0
 #endif
 
 #ifdef CONFIG_HISAX_AVM_A1
 #define  CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#ifndef ISDN_CHIP_ISAC 
+#define ISDN_CHIP_ISAC 1
+#endif
 #else
 #define  CARD_AVM_A1  0
 #endif
 
-#ifdef CONFIG_HISAX_ELSA_PCC
-#define  CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_QS1000)
+#ifdef CONFIG_HISAX_ELSA
+#define  CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_PNP) | \
+                  (1<< ISDN_CTYPE_ELSA_PCMCIA) | (1<< ISDN_CTYPE_ELSA_PCI)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#undef HISAX_INITFUNC
+#define HISAX_INITFUNC(__arginit) __arginit
+#undef HISAX_INITDATA
+#define HISAX_INITDATA
 #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)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
 #else
 #define CARD_IX1MICROR2 0
 #endif
 
+#ifdef  CONFIG_HISAX_DIEHLDIVA
+#define CARD_DIEHLDIVA (1 << ISDN_CTYPE_DIEHLDIVA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_DIEHLDIVA 0
+#endif
+
+#ifdef  CONFIG_HISAX_ASUSCOM
+#define CARD_ASUSCOM (1 << ISDN_CTYPE_ASUSCOM)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_ASUSCOM 0
+#endif
+
+#ifdef  CONFIG_HISAX_TELEINT
+#define CARD_TELEINT (1 << ISDN_CTYPE_TELEINT)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_TELEINT 0
+#endif
+
+#ifdef  CONFIG_HISAX_SEDLBAUER
+#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SEDLBAUER 0
+#endif
+
+#ifdef  CONFIG_HISAX_SPORTSTER
+#define CARD_SPORTSTER (1 << ISDN_CTYPE_SPORTSTER)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_SPORTSTER 0
+#endif
+
+#ifdef  CONFIG_HISAX_MIC
+#define CARD_MIC (1 << ISDN_CTYPE_MIC)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_MIC 0
+#endif
+
+#ifdef  CONFIG_HISAX_NETJET
+#define CARD_NETJET (1 << ISDN_CTYPE_NETJET)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NETJET 0
+#endif
+
+#ifdef CONFIG_HISAX_TELES3C
+#define  CARD_TELES3C (1<< ISDN_CTYPE_TELES3C)
+#else
+#define  CARD_TELES3C  0
+#endif
+
+#ifdef  CONFIG_HISAX_AMD7930
+#define CARD_AMD7930 (1 << ISDN_CTYPE_AMD7930)
+#else
+#define CARD_AMD7930 0
+#endif
+
+#ifdef CONFIG_HISAX_NICCY
+#define        CARD_NICCY (1 << ISDN_CTYPE_NICCY)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_NICCY 0
+#endif
+
+
 #define  SUPORTED_CARDS  (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
-                        | CARD_IX1MICROR2)
+                        | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \
+                        | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \
+                        | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \
+                        | CARD_NICCY)
+
+#define TEI_PER_CARD 0
+
+#ifdef CONFIG_HISAX_1TR6
+#undef TEI_PER_CARD
+#define TEI_PER_CARD 1
+#endif
+
+#ifdef CONFIG_HISAX_EURO
+#undef TEI_PER_CARD
+#define TEI_PER_CARD 1
+#define HISAX_EURO_SENDCOMPLETE 1
+#ifdef CONFIG_HISAX_ML
+#undef HISAX_EURO_SENDCOMPLETE
+#endif
+#undef HISAX_DE_AOC
+#ifdef CONFIG_DE_AOC
+#define HISAX_DE_AOC 1
+#endif
+#endif
+
+#if TEI_PER_CARD
+#undef TEI_FIXED
+#endif
+
+#undef PTP_DATA_LINK
+
+#ifdef PTP_DATA_LINK
+#undef TEI_FIXED
+#define TEI_FIXED 0
+#define LAYER2_WATCHING
+#endif
 
 struct IsdnCard {
        int typ;
        int protocol;           /* EDSS1 or 1TR6 */
-       unsigned int para[3];
-       struct IsdnCardState *sp;
+       unsigned int para[4];
+       struct IsdnCardState *cs;
 };
 
-
-#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);
+int HiSax_inithardware(int *);
 void HiSax_closehardware(void);
 
-void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
+void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
+unsigned int random_ri(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);
+int newcallref(void);
 
 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);
+int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
+       void *arg, int where);
+void FsmRestartTimer(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);
+int HiSax_writebuf_skb(int id, int chan, int ack, 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);
@@ -520,10 +940,12 @@ 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__ */
+void setstack_manager(struct PStack *st);
+#ifdef ISDN_CHIP_ISAC
+void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
+#endif /* ISDN_CHIP_ISAC */
+#endif /* __KERNEL__ */
 
 #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
 
@@ -533,8 +955,12 @@ void CallcNew(void);
 void CallcFree(void);
 int CallcNewChan(struct IsdnCardState *csta);
 void CallcFreeChan(struct IsdnCardState *csta);
+void Isdnl1New(void);
+void Isdnl1Free(void);
 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);
+void TeiNew(void);
+void TeiFree(void);
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
new file mode 100644 (file)
index 0000000..c44cc54
--- /dev/null
@@ -0,0 +1,280 @@
+/* $Id: hscx.c,v 1.7 1998/02/12 23:07:36 keil Exp $
+
+ * hscx.c   HSCX specific routines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.c,v $
+ * Revision 1.7  1998/02/12 23:07:36  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6  1998/02/02 13:41:12  keil
+ * new init
+ *
+ * Revision 1.5  1997/11/06 17:09:34  keil
+ * New 2.1 init code
+ *
+ * Revision 1.4  1997/10/29 19:01:06  keil
+ * changes for 2.1
+ *
+ * Revision 1.3  1997/07/27 21:38:34  keil
+ * new B-channel interface
+ *
+ * Revision 1.2  1997/06/26 11:16:17  keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+static char *HSCXVer[] HISAX_INITDATA =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+HISAX_INITFUNC(int
+HscxVersion(struct IsdnCardState *cs, char *s))
+{
+       int verA, verB;
+
+       verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
+       verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
+       printk(KERN_INFO "%s HSCX version A: %s  B: %s\n", s,
+              HSCXVer[verA], HSCXVer[verB]);
+       if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
+               return (1);
+       else
+               return (0);
+}
+
+void
+modehscx(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int hscx = bcs->channel;
+
+       if (cs->debug & L1_DEB_HSCX) {
+               char tmp[40];
+               sprintf(tmp, "hscx %c mode %d ichan %d",
+                       'A' + hscx, mode, bc);
+               debugl1(cs, tmp);
+       }
+       bcs->mode = mode;
+       cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, 0x85);
+       cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
+       cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
+       cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
+       cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
+       cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
+       cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
+       cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
+       cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
+
+       /* Switch IOM 1 SSI */
+       if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
+               bc = 1 - bc;
+
+       if (bc == 0) {
+               cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
+                             test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+               cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
+                             test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f);
+       } else {
+               cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x3);
+               cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x3);
+       }
+       switch (mode) {
+               case (L1_MODE_NULL):
+                       cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0xff);
+                       cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0xff);
+                       cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
+                       break;
+               case (L1_MODE_TRANS):
+                       cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
+                       break;
+               case (L1_MODE_HDLC):
+                       cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
+                       break;
+       }
+       if (mode)
+               cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
+       cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+hscx_sched_event(struct BCState *bcs, int event)
+{
+       bcs->event |= 1 << event;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static void
+hscx_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->hw.hscx.tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->hw.hscx.tx_skb = skb;
+                               test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                               st->l1.bcs->hw.hscx.count = 0;
+                               restore_flags(flags);
+                               st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (st->l1.bcs->hw.hscx.tx_skb) {
+                               printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       st->l1.bcs->hw.hscx.tx_skb = skb;
+                       st->l1.bcs->hw.hscx.count = 0;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       break;
+               case (PH_PULL_REQ):
+                       if (!st->l1.bcs->hw.hscx.tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+
+}
+
+void
+close_hscxstate(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       modehscx(bcs, 0, 0);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (bcs->hw.hscx.rcvbuf) {
+                       kfree(bcs->hw.hscx.rcvbuf);
+                       bcs->hw.hscx.rcvbuf = NULL;
+               }
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+               if (bcs->hw.hscx.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hscx.tx_skb);
+                       bcs->hw.hscx.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+static int
+open_hscxstate(struct IsdnCardState *cs,
+              int bc)
+{
+       struct BCState *bcs = cs->bcs + bc;
+
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+                       printk(KERN_WARNING
+                              "HiSax: No memory for hscx.rcvbuf\n");
+                       return (1);
+               }
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->hw.hscx.tx_skb = NULL;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       bcs->event = 0;
+       bcs->hw.hscx.rcvidx = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+static void
+hscx_manl1(struct PStack *st, int pr,
+          void *arg)
+{
+       switch (pr) {
+               case (PH_ACTIVATE_REQ):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       modehscx(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       break;
+               case (PH_DEACTIVATE_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+                               modehscx(st->l1.bcs, 0, 0);
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       break;
+       }
+}
+
+int
+setstack_hscx(struct PStack *st, struct BCState *bcs)
+{
+       if (open_hscxstate(st->l1.hardware, bcs->channel))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = hscx_l2l1;
+       st->ma.manl1 = hscx_manl1;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_hscx_ints(struct IsdnCardState *cs))
+{
+       int val;
+       char tmp[64];
+
+       val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
+       sprintf(tmp, "HSCX B ISTA %x", val);
+       debugl1(cs, tmp);
+       if (val & 0x01) {
+               val = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
+               sprintf(tmp, "HSCX B EXIR %x", val);
+               debugl1(cs, tmp);
+       } else if (val & 0x02) {
+               val = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
+               sprintf(tmp, "HSCX A EXIR %x", val);
+               debugl1(cs, tmp);
+       }
+       val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
+       sprintf(tmp, "HSCX A ISTA %x", val);
+       debugl1(cs, tmp);
+       val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
+       sprintf(tmp, "HSCX B STAR %x", val);
+       debugl1(cs, tmp);
+       val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
+       sprintf(tmp, "HSCX A STAR %x", val);
+       debugl1(cs, tmp);
+       cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
+       cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
+       cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
+       cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
+}
+
+HISAX_INITFUNC(void 
+inithscx(struct IsdnCardState *cs))
+{
+       cs->bcs[0].BC_SetStack = setstack_hscx;
+       cs->bcs[1].BC_SetStack = setstack_hscx;
+       cs->bcs[0].BC_Close = close_hscxstate;
+       cs->bcs[1].BC_Close = close_hscxstate;
+       modehscx(cs->bcs, 0, 0);
+       modehscx(cs->bcs + 1, 0, 0);
+}
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
new file mode 100644 (file)
index 0000000..ac2d380
--- /dev/null
@@ -0,0 +1,46 @@
+/* $Id: hscx.h,v 1.3 1997/07/27 21:38:35 keil Exp $
+
+ * hscx.h   HSCX specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.h,v $
+ * Revision 1.3  1997/07/27 21:38:35  keil
+ * new B-channel interface
+ *
+ * Revision 1.2  1997/06/26 11:16:18  keil
+ * first version
+ *
+ *
+ */
+
+/* All Registers original Siemens Spec  */
+
+#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
+
+extern int HscxVersion(struct IsdnCardState *cs, char *s);
+extern void hscx_sched_event(struct BCState *bcs, int event);
+extern void modehscx(struct BCState *bcs, int mode, int bc);
+extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
+extern void inithscx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
new file mode 100644 (file)
index 0000000..64e80e7
--- /dev/null
@@ -0,0 +1,320 @@
+/* $Id: hscx_irq.c,v 1.7 1998/02/12 23:07:37 keil Exp $
+
+ * hscx_irq.c     low level b-channel stuff for Siemens HSCX
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * This is an include file for fast inline IRQ stuff
+ *
+ * $Log: hscx_irq.c,v $
+ * Revision 1.7  1998/02/12 23:07:37  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.6  1997/10/29 19:01:07  keil
+ * changes for 2.1
+ *
+ * Revision 1.5  1997/10/01 09:21:35  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.4  1997/08/15 17:48:02  keil
+ * cosmetic
+ *
+ * Revision 1.3  1997/07/27 21:38:36  keil
+ * new B-channel interface
+ *
+ * Revision 1.2  1997/06/26 11:16:19  keil
+ * first version
+ *
+ *
+ */
+
+
+static inline void
+waitforCEC(struct IsdnCardState *cs, int hscx)
+{
+       int to = 50;
+
+       while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
+               udelay(1);
+               to--;
+       }
+       if (!to)
+               printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(struct IsdnCardState *cs, int hscx)
+{
+       int to = 50;
+
+       while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+               udelay(1);
+               to--;
+       }
+       if (!to)
+               printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
+}
+
+static inline void
+WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       waitforCEC(cs, hscx);
+       WRITEHSCX(cs, hscx, HSCX_CMDR, data);
+       restore_flags(flags);
+}
+
+
+
+static void
+hscx_empty_fifo(struct BCState *bcs, int count)
+{
+       u_char *ptr;
+       struct IsdnCardState *cs = bcs->cs;
+       long flags;
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hscx_empty_fifo");
+
+       if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hscx_empty_fifo: incoming packet too large");
+               WriteHSCXCMDR(cs, bcs->channel, 0x80);
+               bcs->hw.hscx.rcvidx = 0;
+               return;
+       }
+       ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+       bcs->hw.hscx.rcvidx += count;
+       save_flags(flags);
+       cli();
+       READHSCXFIFO(cs, bcs->channel, ptr, count);
+       WriteHSCXCMDR(cs, bcs->channel, 0x80);
+       restore_flags(flags);
+       if (cs->debug & L1_DEB_HSCX_FIFO) {
+               char tmp[256];
+               char *t = tmp;
+
+               t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+                            bcs->channel ? 'B' : 'A', count);
+               QuickHex(t, ptr, count);
+               debugl1(cs, tmp);
+       }
+}
+
+static void
+hscx_fill_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int more, count;
+       int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+       u_char *ptr;
+       long flags;
+
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hscx_fill_fifo");
+
+       if (!bcs->hw.hscx.tx_skb)
+               return;
+       if (bcs->hw.hscx.tx_skb->len <= 0)
+               return;
+
+       more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+       if (bcs->hw.hscx.tx_skb->len > fifo_size) {
+               more = !0;
+               count = fifo_size;
+       } else
+               count = bcs->hw.hscx.tx_skb->len;
+
+       waitforXFW(cs, bcs->channel);
+       save_flags(flags);
+       cli();
+       ptr = bcs->hw.hscx.tx_skb->data;
+       skb_pull(bcs->hw.hscx.tx_skb, count);
+       bcs->tx_cnt -= count;
+       bcs->hw.hscx.count += count;
+       WRITEHSCXFIFO(cs, bcs->channel, ptr, count);
+       WriteHSCXCMDR(cs, bcs->channel, more ? 0x8 : 0xa);
+       restore_flags(flags);
+       if (cs->debug & L1_DEB_HSCX_FIFO) {
+               char tmp[256];
+               char *t = tmp;
+
+               t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+                            bcs->channel ? 'B' : 'A', count);
+               QuickHex(t, ptr, count);
+               debugl1(cs, tmp);
+       }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
+{
+       u_char r;
+       struct BCState *bcs = cs->bcs + hscx;
+       struct sk_buff *skb;
+       int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
+       int count;
+       char tmp[32];
+
+       if (!test_bit(BC_FLG_INIT, &bcs->Flag))
+               return;
+
+       if (val & 0x80) {       /* RME */
+               r = READHSCX(cs, hscx, HSCX_RSTA);
+               if ((r & 0xf0) != 0xa0) {
+                       if (!(r & 0x80))
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "HSCX invalid frame");
+                       if ((r & 0x40) && bcs->mode)
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "HSCX RDO mode=%d",
+                                               bcs->mode);
+                                       debugl1(cs, tmp);
+                               }
+                       if (!(r & 0x20))
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "HSCX CRC error");
+                       WriteHSCXCMDR(cs, hscx, 0x80);
+               } else {
+                       count = READHSCX(cs, hscx, HSCX_RBCL) & (
+                               test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
+                       if (count == 0)
+                               count = fifo_size;
+                       hscx_empty_fifo(bcs, count);
+                       if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+                               if (cs->debug & L1_DEB_HSCX_FIFO) {
+                                       sprintf(tmp, "HX Frame %d", count);
+                                       debugl1(cs, tmp);
+                               }
+                               if (!(skb = dev_alloc_skb(count)))
+                                       printk(KERN_WARNING "HSCX: receive out of memory\n");
+                               else {
+                                       memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+                                       skb_queue_tail(&bcs->rqueue, skb);
+                               }
+                       }
+               }
+               bcs->hw.hscx.rcvidx = 0;
+               hscx_sched_event(bcs, B_RCVBUFREADY);
+       }
+       if (val & 0x40) {       /* RPF */
+               hscx_empty_fifo(bcs, fifo_size);
+               if (bcs->mode == L1_MODE_TRANS) {
+                       /* receive audio data */
+                       if (!(skb = dev_alloc_skb(fifo_size)))
+                               printk(KERN_WARNING "HiSax: receive out of memory\n");
+                       else {
+                               memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
+                               skb_queue_tail(&bcs->rqueue, skb);
+                       }
+                       bcs->hw.hscx.rcvidx = 0;
+                       hscx_sched_event(bcs, B_RCVBUFREADY);
+               }
+       }
+       if (val & 0x10) {       /* XPR */
+               if (bcs->hw.hscx.tx_skb)
+                       if (bcs->hw.hscx.tx_skb->len) {
+                               hscx_fill_fifo(bcs);
+                               return;
+                       } else {
+                               if (bcs->st->lli.l1writewakeup &&
+                                       (PACKET_NOACK != bcs->hw.hscx.tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+                               dev_kfree_skb(bcs->hw.hscx.tx_skb);
+                               bcs->hw.hscx.count = 0; 
+                               bcs->hw.hscx.tx_skb = NULL;
+                       }
+               if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) {
+                       bcs->hw.hscx.count = 0;
+                       test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+                       hscx_fill_fifo(bcs);
+               } else {
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+                       hscx_sched_event(bcs, B_XMTBUFREADY);
+               }
+       }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *cs, u_char val)
+{
+
+       u_char exval;
+       struct BCState *bcs;
+       char tmp[32];
+
+       if (val & 0x01) {
+               bcs = cs->bcs + 1;
+               exval = READHSCX(cs, 1, HSCX_EXIR);
+               if (exval == 0x40) {
+                       if (bcs->mode == 1)
+                               hscx_fill_fifo(bcs);
+                       else {
+                               /* Here we lost an TX interrupt, so
+                                  * restart transmitting the whole frame.
+                                */
+                               if (bcs->hw.hscx.tx_skb) {
+                                       skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count);
+                                       bcs->tx_cnt += bcs->hw.hscx.count;
+                                       bcs->hw.hscx.count = 0;
+                               }
+                               WriteHSCXCMDR(cs, bcs->channel, 0x01);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+               } else if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "HSCX B EXIR %x", exval);
+                       debugl1(cs, tmp);
+               }
+       }
+       if (val & 0xf8) {
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "HSCX B interrupt %x", val);
+                       debugl1(cs, tmp);
+               }
+               hscx_interrupt(cs, val, 1);
+       }
+       if (val & 0x02) {
+               bcs = cs->bcs;
+               exval = READHSCX(cs, 0, HSCX_EXIR);
+               if (exval == 0x40) {
+                       if (bcs->mode == L1_MODE_TRANS)
+                               hscx_fill_fifo(bcs);
+                       else {
+                               /* Here we lost an TX interrupt, so
+                                  * restart transmitting the whole frame.
+                                */
+                               if (bcs->hw.hscx.tx_skb) {
+                                       skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count);
+                                       bcs->tx_cnt += bcs->hw.hscx.count;
+                                       bcs->hw.hscx.count = 0;
+                               }
+                               WriteHSCXCMDR(cs, bcs->channel, 0x01);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+               } else if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "HSCX A EXIR %x", exval);
+                       debugl1(cs, tmp);
+               }
+       }
+       if (val & 0x04) {
+               exval = READHSCX(cs, 0, HSCX_ISTA);
+               if (cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp, "HSCX A interrupt %x", exval);
+                       debugl1(cs, tmp);
+               }
+               hscx_interrupt(cs, exval, 0);
+       }
+}
diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h
new file mode 100644 (file)
index 0000000..6d856ec
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: ipac.h,v 1.2 1997/10/29 18:51:21 keil Exp $
+
+ * ipac.h   IPAC specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: ipac.h,v $
+ * Revision 1.2  1997/10/29 18:51:21  keil
+ * New files
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:48  keil
+ * new files on 2.0
+ *
+ *
+ *
+ */
+
+
+/* All Registers original Siemens Spec  */
+
+#define IPAC_CONF      0xC0
+#define IPAC_MASK      0xC1
+#define IPAC_ISTA      0xC1
+#define IPAC_ID                0xC2
+#define IPAC_ACFG      0xC3
+#define IPAC_AOE       0xC4
+#define IPAC_ARX       0xC5
+#define IPAC_PITA1     0xC6
+#define IPAC_PITA2     0xC7
+#define IPAC_POTA1     0xC8
+#define IPAC_POTA2     0xC9
+#define IPAC_PCFG      0xCA
+#define IPAC_SCFG      0xCB
+#define IPAC_TIMR2     0xCC
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
new file mode 100644 (file)
index 0000000..9a2624e
--- /dev/null
@@ -0,0 +1,679 @@
+/* $Id: isac.c,v 1.12 1998/02/12 23:07:40 keil Exp $
+
+ * isac.c   ISAC specific routines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.c,v $
+ * Revision 1.12  1998/02/12 23:07:40  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.11  1998/02/09 10:54:49  keil
+ * fixes for leased mode
+ *
+ * Revision 1.10  1998/02/02 13:37:37  keil
+ * new init
+ *
+ * Revision 1.9  1997/11/06 17:09:07  keil
+ * New 2.1 init code
+ *
+ * Revision 1.8  1997/10/29 19:00:03  keil
+ * new layer1,changes for 2.1
+ *
+ * Revision 1.7  1997/10/01 09:21:37  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.6  1997/08/15 17:47:08  keil
+ * avoid oops because a uninitialised timer
+ *
+ * Revision 1.5  1997/08/07 17:48:49  keil
+ * fix wrong parenthesis
+ *
+ * Revision 1.4  1997/07/30 17:11:59  keil
+ * fixed Timer3
+ *
+ * Revision 1.3  1997/07/27 21:37:40  keil
+ * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
+ *
+ * Revision 1.2  1997/06/26 11:16:15  keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 1
+
+static char *ISACVer[] HISAX_INITDATA =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+void
+ISACVersion(struct IsdnCardState *cs, char *s)
+{
+       int val;
+
+       val = cs->readisac(cs, ISAC_RBCH);
+       printk(KERN_INFO "%s ISAC version : %s\n", s, ISACVer[(val >> 5) & 3]);
+}
+
+static void
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+       if (cs->debug & L1_DEB_ISAC) {
+               char tmp[32];
+               sprintf(tmp, "ph_command %x", command);
+               debugl1(cs, tmp);
+       }
+       cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
+}
+
+static void
+manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
+       struct PStack *st;
+
+       st = cs->stlist;
+       while (st) {
+               st->ma.manl1(st, msg, arg);
+               st = st->next;
+       }
+}
+
+static void
+isac_new_ph(struct IsdnCardState *cs)
+{
+       switch (cs->ph_state) {
+               case (ISAC_IND_RS):
+               case (ISAC_IND_EI):
+                       ph_command(cs, ISAC_CMD_DUI);
+                       manl1_msg(cs, PH_RESET_IND, NULL);
+                       break;
+               case (ISAC_IND_DID):
+                       manl1_msg(cs, PH_DEACT_CNF, NULL);
+                       break;
+               case (ISAC_IND_DR):
+                       manl1_msg(cs, PH_DEACT_IND, NULL);
+                       break;
+               case (ISAC_IND_PU):
+                       manl1_msg(cs, PH_POWERUP_CNF, NULL);
+                       break;
+               case (ISAC_IND_RSY):
+                       manl1_msg(cs, PH_RSYNC_IND, NULL);
+                       break;
+               case (ISAC_IND_ARD):
+                       manl1_msg(cs, PH_INFO2_IND, NULL);
+                       break;
+               case (ISAC_IND_AI8):
+                       manl1_msg(cs, PH_I4_P8_IND, NULL);
+                       break;
+               case (ISAC_IND_AI10):
+                       manl1_msg(cs, PH_I4_P10_IND, NULL);
+                       break;
+               default:
+                       break;
+       }
+}
+
+static void
+isac_bh(struct IsdnCardState *cs)
+{
+       struct PStack *stptr;
+       
+       if (!cs)
+               return;
+
+       if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+               if (cs->debug)
+                       debugl1(cs, "D-Channel Busy cleared");
+               stptr = cs->stlist;
+               while (stptr != NULL) {
+                       stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL);
+                       stptr = stptr->next;
+               }
+       }
+       if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
+               isac_new_ph(cs);                
+       if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+               DChannel_proc_rcv(cs);
+       if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+               DChannel_proc_xmt(cs);
+       if (test_and_clear_bit(D_RX_MON0, &cs->event))
+               test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_RX_MON1, &cs->event))
+               test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_TX_MON0, &cs->event))
+               test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_TX_MON1, &cs->event))
+               test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
+}
+
+void
+isac_empty_fifo(struct IsdnCardState *cs, int count)
+{
+       u_char *ptr;
+       long flags;
+
+       if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+               debugl1(cs, "isac_empty_fifo");
+
+       if ((cs->rcvidx + count) >= MAX_DFRAME_LEN) {
+               if (cs->debug & L1_DEB_WARN) {
+                       char tmp[40];
+                       sprintf(tmp, "isac_empty_fifo overrun %d",
+                               cs->rcvidx + count);
+                       debugl1(cs, tmp);
+               }
+               cs->writeisac(cs, ISAC_CMDR, 0x80);
+               cs->rcvidx = 0;
+               return;
+       }
+       ptr = cs->rcvbuf + cs->rcvidx;
+       cs->rcvidx += count;
+       save_flags(flags);
+       cli();
+       cs->readisacfifo(cs, ptr, count);
+       cs->writeisac(cs, ISAC_CMDR, 0x80);
+       restore_flags(flags);
+       if (cs->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(cs, tmp);
+       }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *cs)
+{
+       int count, more;
+       u_char *ptr;
+       long flags;
+
+       if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+               debugl1(cs, "isac_fill_fifo");
+
+       if (!cs->tx_skb)
+               return;
+
+       count = cs->tx_skb->len;
+       if (count <= 0)
+               return;
+
+       more = 0;
+       if (count > 32) {
+               more = !0;
+               count = 32;
+       }
+       save_flags(flags);
+       cli();
+       ptr = cs->tx_skb->data;
+       skb_pull(cs->tx_skb, count);
+       cs->tx_cnt += count;
+       cs->writeisacfifo(cs, ptr, count);
+       cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
+       restore_flags(flags);
+       if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+               debugl1(cs, "isac_fill_fifo dbusytimer running");
+               del_timer(&cs->dbusytimer);
+       }
+       init_timer(&cs->dbusytimer);
+       cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+       add_timer(&cs->dbusytimer);
+       if (cs->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(cs, tmp);
+       }
+}
+
+void
+isac_sched_event(struct IsdnCardState *cs, int event)
+{
+       test_and_set_bit(event, &cs->event);
+       queue_task(&cs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+void
+isac_interrupt(struct IsdnCardState *cs, u_char val)
+{
+       u_char exval, v1;
+       struct sk_buff *skb;
+       unsigned int count;
+       long flags;
+       char tmp[32];
+
+       if (cs->debug & L1_DEB_ISAC) {
+               sprintf(tmp, "ISAC interrupt %x", val);
+               debugl1(cs, tmp);
+       }
+       if (val & 0x80) {       /* RME */
+               exval = cs->readisac(cs, ISAC_RSTA);
+               if ((exval & 0x70) != 0x20) {
+                       if (exval & 0x40)
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "ISAC RDO");
+                       if (!(exval & 0x20))
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "ISAC CRC error");
+                       cs->writeisac(cs, ISAC_CMDR, 0x80);
+               } else {
+                       count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
+                       if (count == 0)
+                               count = 32;
+                       isac_empty_fifo(cs, count);
+                       save_flags(flags);
+                       cli();
+                       if ((count = cs->rcvidx) > 0) {
+                               cs->rcvidx = 0;
+                               if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+                                       printk(KERN_WARNING "HiSax: D receive out of memory\n");
+                               else {
+                                       memcpy(skb_put(skb, count), cs->rcvbuf, count);
+                                       skb_queue_tail(&cs->rq, skb);
+                               }
+                       }
+                       restore_flags(flags);
+               }
+               cs->rcvidx = 0;
+               isac_sched_event(cs, D_RCVBUFREADY);
+       }
+       if (val & 0x40) {       /* RPF */
+               isac_empty_fifo(cs, 32);
+       }
+       if (val & 0x20) {       /* RSC */
+               /* never */
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "ISAC RSC interrupt");
+       }
+       if (val & 0x10) {       /* XPR */
+               if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+                       del_timer(&cs->dbusytimer);
+               if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+                       isac_sched_event(cs, D_CLEARBUSY);
+               if (cs->tx_skb)
+                       if (cs->tx_skb->len) {
+                               isac_fill_fifo(cs);
+                               goto afterXPR;
+                       } else {
+                               dev_kfree_skb(cs->tx_skb);
+                               cs->tx_cnt = 0;
+                               cs->tx_skb = NULL;
+                       }
+               if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+                       cs->tx_cnt = 0;
+                       isac_fill_fifo(cs);
+               } else
+                       isac_sched_event(cs, D_XMTBUFREADY);
+       }
+      afterXPR:
+       if (val & 0x04) {       /* CISQ */
+               cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "ph_state change %x", cs->ph_state);
+                       debugl1(cs, tmp);
+               }
+               isac_sched_event(cs, D_L1STATECHANGE);
+       }
+       if (val & 0x02) {       /* SIN */
+               /* never */
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "ISAC SIN interrupt");
+       }
+       if (val & 0x01) {       /* EXI */
+               exval = cs->readisac(cs, ISAC_EXIR);
+               if (cs->debug & L1_DEB_WARN) {
+                       sprintf(tmp, "ISAC EXIR %02x", exval);
+                       debugl1(cs, tmp);
+               }
+               if (exval & 0x04) {
+                       v1 = cs->readisac(cs, ISAC_MOSR);
+                       if (cs->debug & L1_DEB_WARN) {
+                               sprintf(tmp, "ISAC MOSR %02x", v1);
+                               debugl1(cs, tmp);
+                       }
+#if ARCOFI_USE
+                       if (v1 & 0x08) {
+                               if (!cs->mon_rx)
+                                       if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+                                               if (cs->debug & L1_DEB_WARN)
+                                                       debugl1(cs, "ISAC MON RX out of memory!");
+                                               cs->mocr &= 0xf0;
+                                               cs->mocr |= 0x0a;
+                                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                               goto afterMONR0;
+                                       } else
+                                               cs->mon_rxp = 0;
+                               if (cs->mon_rxp >= MAX_MON_FRAME) {
+                                       cs->mocr &= 0xf0;
+                                       cs->mocr |= 0x0a;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       cs->mon_rxp = 0;
+                                       if (cs->debug & L1_DEB_WARN)
+                                               debugl1(cs, "ISAC MON RX overflow!");
+                                       goto afterMONR0;
+                               }
+                               cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                               if (cs->mon_rxp == 1) {
+                                       cs->mocr |= 0x04;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               }
+                       }
+                     afterMONR0:
+                       if (v1 & 0x80) {
+                               if (!cs->mon_rx)
+                                       if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+                                               if (cs->debug & L1_DEB_WARN)
+                                                       debugl1(cs, "ISAC MON RX out of memory!");
+                                               cs->mocr &= 0x0f;
+                                               cs->mocr |= 0xa0;
+                                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                               goto afterMONR1;
+                                       } else
+                                               cs->mon_rxp = 0;
+                               if (cs->mon_rxp >= MAX_MON_FRAME) {
+                                       cs->mocr &= 0x0f;
+                                       cs->mocr |= 0xa0;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       cs->mon_rxp = 0;
+                                       if (cs->debug & L1_DEB_WARN)
+                                               debugl1(cs, "ISAC MON RX overflow!");
+                                       goto afterMONR1;
+                               }
+                               cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                               if (cs->mon_rxp == 1) {
+                                       cs->mocr |= 0x40;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               }
+                       }
+                     afterMONR1:
+                       if (v1 & 0x04) {
+                               cs->mocr &= 0xf0;
+                               cs->mocr |= 0x0a;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               isac_sched_event(cs, D_RX_MON0);
+                       }
+                       if (v1 & 0x40) {
+                               cs->mocr &= 0x0f;
+                               cs->mocr |= 0xa0;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               isac_sched_event(cs, D_RX_MON1);
+                       }
+                       if (v1 & 0x02) {
+                               if (!cs->mon_tx) {
+                                       cs->mocr &= 0xf0;
+                                       cs->mocr |= 0x0a;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       goto AfterMOX0;
+                               }
+                               if (cs->mon_txp >= cs->mon_txc) {
+                                       if (cs->mon_txc)
+                                               isac_sched_event(cs, D_TX_MON0);
+                                       goto AfterMOX0;
+                               }
+                               cs->writeisac(cs, ISAC_MOX0,
+                                       cs->mon_tx[cs->mon_txp++]);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+                     AfterMOX0:
+                       if (v1 & 0x20) {
+                               if (!cs->mon_tx) {
+                                       cs->mocr &= 0x0f;
+                                       cs->mocr |= 0xa0;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       goto AfterMOX1;
+                               }
+                               if (cs->mon_txp >= cs->mon_txc) {
+                                       if (cs->mon_txc)
+                                               isac_sched_event(cs, D_TX_MON1);
+                                       goto AfterMOX1;
+                               }
+                               cs->writeisac(cs, ISAC_MOX1,
+                                       cs->mon_tx[cs->mon_txp++]);
+                               if (cs->debug & L1_DEB_WARN) {
+                                       sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+                     AfterMOX1:
+#endif
+               }
+       }
+}
+
+static void
+ISAC_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       struct sk_buff *skb = arg;
+       char str[64];
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       if (cs->tx_skb) {
+                               skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+                       } else {
+                               if ((cs->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
+                                       LogFrame(cs, skb->data, skb->len);
+                                       sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                                       dlogframe(cs, skb->data + 4, skb->len - 4,
+                                                 str);
+                               }
+                               cs->tx_skb = skb;
+                               cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                               if (cs->debug & L1_DEB_LAPD)
+                                       Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+                               isac_fill_fifo(cs);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (cs->tx_skb) {
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+                               skb_queue_tail(&cs->sq, skb);
+                               break;
+                       }
+                       if ((cs->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
+                               LogFrame(cs, skb->data, skb->len);
+                               sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+                               dlogframe(cs, skb->data + 4, skb->len - 4,
+                                         str);
+                       }
+                       cs->tx_skb = skb;
+                       cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+                       isac_fill_fifo(cs);
+                       break;
+               case (PH_PULL_REQ):
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+                       if (!cs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+void
+isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
+{
+       u_char val;
+       char tmp[32];
+       
+       switch(msg) {
+               case PH_RESET_REQ:
+                       if ((cs->ph_state == ISAC_IND_EI) ||
+                               (cs->ph_state == ISAC_IND_DR) ||
+                               (cs->ph_state == ISAC_IND_RS))
+                               ph_command(cs, ISAC_CMD_TIM);
+                       else
+                               ph_command(cs, ISAC_CMD_RS);
+                       break;
+               case PH_ENABLE_REQ:
+                       ph_command(cs, ISAC_CMD_TIM);
+                       break;
+               case PH_INFO3_REQ:
+                       ph_command(cs, ISAC_CMD_AR8);
+                       break;
+               case PH_TESTLOOP_REQ:
+                       val = 0;
+                       if (1 & (int) arg)
+                               val |= 0x0c;
+                       if (2 & (int) arg)
+                               val |= 0x3;
+                       if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+                               /* IOM 1 Mode */
+                               if (!val) {
+                                       cs->writeisac(cs, ISAC_SPCR, 0xa);
+                                       cs->writeisac(cs, ISAC_ADF1, 0x2);
+                               } else {
+                                       cs->writeisac(cs, ISAC_SPCR, val);
+                                       cs->writeisac(cs, ISAC_ADF1, 0xa);
+                               }
+                       } else {
+                               /* IOM 2 Mode */
+                               cs->writeisac(cs, ISAC_SPCR, val);
+                               if (val)
+                                       cs->writeisac(cs, ISAC_ADF1, 0x8);
+                               else
+                                       cs->writeisac(cs, ISAC_ADF1, 0x0);
+                       }
+                       break;
+               default:
+                       if (cs->debug & L1_DEB_WARN) {
+                               sprintf(tmp, "isac_l1cmd unknown %4x", msg);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+}
+
+void
+setstack_isac(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l2.l2l1 = ISAC_l2l1;
+}
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+       struct PStack *stptr;
+
+       if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+               if (cs->debug)
+                       debugl1(cs, "D-Channel Busy");
+               test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+               stptr = cs->stlist;
+               
+               while (stptr != NULL) {
+                       stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL);
+                       stptr = stptr->next;
+               }
+       }
+}
+
+HISAX_INITFUNC(void
+initisac(struct IsdnCardState *cs))
+{
+       cs->tqueue.routine = (void *) (void *) isac_bh;
+       cs->l1cmd = isac_l1cmd;
+       cs->setstack_d = setstack_isac;
+       cs->dbusytimer.function = (void *) dbusy_timer_handler;
+       cs->dbusytimer.data = (long) cs;
+       init_timer(&cs->dbusytimer);
+       cs->writeisac(cs, ISAC_MASK, 0xff);
+       cs->mocr = 0xaa;
+       if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+               /* IOM 1 Mode */
+               cs->writeisac(cs, ISAC_ADF2, 0x0);
+               cs->writeisac(cs, ISAC_SPCR, 0xa);
+               cs->writeisac(cs, ISAC_ADF1, 0x2);
+               cs->writeisac(cs, ISAC_STCR, 0x70);
+               cs->writeisac(cs, ISAC_MODE, 0xc9);
+       } else {
+               /* IOM 2 Mode */
+               cs->writeisac(cs, ISAC_ADF2, 0x80);
+               cs->writeisac(cs, ISAC_SQXR, 0x2f);
+               cs->writeisac(cs, ISAC_SPCR, 0x00);
+               cs->writeisac(cs, ISAC_STCR, 0x70);
+               cs->writeisac(cs, ISAC_MODE, 0xc9);
+               cs->writeisac(cs, ISAC_TIMR, 0x00);
+               cs->writeisac(cs, ISAC_ADF1, 0x00);
+       }
+       ph_command(cs, ISAC_CMD_RS);
+       cs->writeisac(cs, ISAC_MASK, 0x0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_isac_ints(struct IsdnCardState *cs))
+{
+       int val;
+       char tmp[64];
+
+       val = cs->readisac(cs, ISAC_STAR);
+       sprintf(tmp, "ISAC STAR %x", val);
+       debugl1(cs, tmp);
+       val = cs->readisac(cs, ISAC_MODE);
+       sprintf(tmp, "ISAC MODE %x", val);
+       debugl1(cs, tmp);
+       val = cs->readisac(cs, ISAC_ADF2);
+       sprintf(tmp, "ISAC ADF2 %x", val);
+       debugl1(cs, tmp);
+       val = cs->readisac(cs, ISAC_ISTA);
+       sprintf(tmp, "ISAC ISTA %x", val);
+       debugl1(cs, tmp);
+       if (val & 0x01) {
+               val = cs->readisac(cs, ISAC_EXIR);
+               sprintf(tmp, "ISAC EXIR %x", val);
+               debugl1(cs, tmp);
+       } else if (val & 0x04) {
+               val = cs->readisac(cs, ISAC_CIR0);
+               sprintf(tmp, "ISAC CIR0 %x", val);
+               debugl1(cs, tmp);
+               cs->ph_state = (val >> 2) & 0xf;
+       } else {
+               cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
+       }
+       isac_sched_event(cs, D_L1STATECHANGE);
+       cs->writeisac(cs, ISAC_MASK, 0xFF);
+       cs->writeisac(cs, ISAC_MASK, 0);
+       cs->writeisac(cs, ISAC_CMDR, 0x41);
+}
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
new file mode 100644 (file)
index 0000000..ac4d556
--- /dev/null
@@ -0,0 +1,74 @@
+/* $Id: isac.h,v 1.4 1997/10/29 19:09:34 keil Exp $
+
+ * isac.h   ISAC specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.h,v $
+ * Revision 1.4  1997/10/29 19:09:34  keil
+ * new L1
+ *
+ * Revision 1.3  1997/07/27 21:37:41  keil
+ * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
+ *
+ * Revision 1.2  1997/06/26 11:16:16  keil
+ * first version
+ *
+ *
+ */
+
+
+/* All Registers original Siemens Spec  */
+
+#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_CIR0 0x31
+#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 ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_CMD_TIM   0x0
+#define ISAC_CMD_RS    0x1
+#define ISAC_CMD_SCZ   0x4
+#define ISAC_CMD_SSZ   0x2
+#define ISAC_CMD_AR8   0x8
+#define ISAC_CMD_AR10  0x9
+#define ISAC_CMD_ARL   0xA
+#define ISAC_CMD_DUI   0xF
+
+#define ISAC_IND_RS    0x1
+#define ISAC_IND_PU    0x7
+#define ISAC_IND_DR    0x0
+#define ISAC_IND_SD    0x2
+#define ISAC_IND_DIS   0x3
+#define ISAC_IND_EI    0x6
+#define ISAC_IND_RSY   0x4
+#define ISAC_IND_ARD   0x8
+#define ISAC_IND_TI    0xA
+#define ISAC_IND_ATI   0xB
+#define ISAC_IND_AI8   0xC
+#define ISAC_IND_AI10  0xD
+#define ISAC_IND_DID   0xF
+
+extern void ISACVersion(struct IsdnCardState *cs, char *s);
+extern void initisac(struct IsdnCardState *cs);
+extern void isac_interrupt(struct IsdnCardState *cs, u_char val);
+extern void clear_pending_isac_ints(struct IsdnCardState *cs);
index 655e6a41788046b7f9d69f802b99d1736b9b5adf..8c4431b04f1cddd5f062e68d708fdbbf9f528adc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 1.15 1997/05/27 15:17:55 fritz Exp $
+/* $Id: isdnl1.c,v 2.18 1998/02/12 23:07:42 keil Exp $
 
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $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 2.18  1998/02/12 23:07:42  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 2.17  1998/02/11 17:28:07  keil
+ * Niccy PnP/PCI support
+ *
+ * Revision 2.16  1998/02/09 18:46:08  keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
  *
- * Revision 1.14  1997/04/07 23:00:08  keil
- * GFP_KERNEL ---> GFP_ATOMIC
+ * Revision 2.15  1998/02/09 10:54:51  keil
+ * fixes for leased mode
  *
- * Revision 1.13  1997/04/06 22:55:50  keil
- * Using SKB's
+ * Revision 2.14  1998/02/03 23:31:31  keil
+ * add AMD7930 support
  *
- * Revision 1.12  1997/03/26 13:43:57  keil
- * small cosmetics
+ * Revision 2.13  1998/02/02 13:33:02  keil
+ * New card support
  *
- * Revision 1.11  1997/03/25 23:11:23  keil
- * US NI-1 protocol
+ * Revision 2.12  1998/01/31 21:41:48  keil
+ * changes for newer 2.1 kernels
  *
- * Revision 1.10  1997/03/13 14:45:05  keil
- * using IRQ proof queue_task
+ * Revision 2.11  1997/11/12 15:01:23  keil
+ * COMPAQ_ISA changes
  *
- * Revision 1.9  1997/03/12 21:44:21  keil
- * change Interrupt routine from atomic quick to normal
+ * Revision 2.10  1997/11/08 21:35:48  keil
+ * new l1 init
  *
- * Revision 1.8  1997/02/09 00:24:31  keil
- * new interface handling, one interface per card
+ * Revision 2.9  1997/11/06 17:09:18  keil
+ * New 2.1 init code
  *
- * Revision 1.7  1997/01/27 15:56:03  keil
- * PCMCIA Teles card and ITK ix1 micro added
+ * Revision 2.8  1997/10/29 19:00:05  keil
+ * new layer1,changes for 2.1
  *
- * Revision 1.6  1997/01/21 22:20:00  keil
- * changes for D-channel log; Elsa Quickstep support
+ * Revision 2.7  1997/10/10 20:56:50  fritz
+ * New HL interface.
  *
- * Revision 1.5  1997/01/10 12:51:19  keil
- * cleanup; set newversion
+ * Revision 2.6  1997/09/12 10:05:16  keil
+ * ISDN_CTRL_DEBUG define
  *
- * Revision 1.4  1996/12/08 19:44:53  keil
- * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ * Revision 2.5  1997/09/11 17:24:45  keil
+ * Add new cards
  *
- * Revision 1.3  1996/11/18 15:34:47  keil
- * fix HSCX version code
+ * Revision 2.4  1997/08/15 17:47:09  keil
+ * avoid oops because a uninitialised timer
  *
- * Revision 1.2  1996/10/27 22:16:54  keil
- * ISAC/HSCX version lookup
+ * Revision 2.3  1997/08/01 11:16:40  keil
+ * cosmetics
  *
- * Revision 1.1  1996/10/13 20:04:53  keil
- * Initial revision
+ * Revision 2.2  1997/07/30 17:11:08  keil
+ * L1deactivated exported
  *
+ * Revision 2.1  1997/07/27 21:35:38  keil
+ * new layer1 interface
+ *
+ * Revision 2.0  1997/06/26 11:02:53  keil
+ * New Layer and card interface
+ *
+ * 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.
  *
+ * old changes removed KKe
  *
  */
 
-const char *l1_revision = "$Revision: 1.15 $";
+const char *l1_revision = "$Revision: 2.18 $";
 
 #define __NO_VERSION__
 #include <linux/config.h>
 #include "hisax.h"
 #include "isdnl1.h"
+#include <linux/kernel_stat.h>
+#if (LINUX_VERSION_CODE < 0x020150) /* 2.1.80 */
+#define kstat_irqs( PAR ) kstat.interrupts( (PAR) )
+#endif
+
+
 
 #if CARD_TELES0
-#include "teles0.h"
+extern int setup_teles0(struct IsdnCard *card);
 #endif
 
 #if CARD_TELES3
-#include "teles3.h"
+extern int setup_teles3(struct IsdnCard *card);
 #endif
 
 #if CARD_AVM_A1
-#include "avm_a1.h"
+extern int setup_avm_a1(struct IsdnCard *card);
 #endif
 
 #if CARD_ELSA
-#include "elsa.h"
+extern int setup_elsa(struct IsdnCard *card);
 #endif
 
 #if CARD_IX1MICROR2
-#include "ix1_micro.h"
+extern int setup_ix1micro(struct IsdnCard *card);
 #endif
 
-/* #define I4L_IRQ_FLAG SA_INTERRUPT */
-#define I4L_IRQ_FLAG    0
+#if CARD_DIEHLDIVA
+extern int  setup_diva(struct IsdnCard *card);
+#endif
 
-#define HISAX_STATUS_BUFSIZE 4096
+#if CARD_ASUSCOM
+extern int setup_asuscom(struct IsdnCard *card);
+#endif
 
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
+#if CARD_TELEINT
+extern int setup_TeleInt(struct IsdnCard *card);
+#endif
 
-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",
+#if CARD_SEDLBAUER
+extern int setup_sedlbauer(struct IsdnCard *card);
+#endif
+
+#if CARD_SPORTSTER
+extern int setup_sportster(struct IsdnCard *card);
+#endif
+
+#if CARD_MIC
+extern int setup_mic(struct IsdnCard *card);
 #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", "???"};
+#if CARD_NETJET
+extern int setup_netjet(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3C
+extern int setup_t163c(struct IsdnCard *card);
+#endif
+
+#if CARD_AMD7930
+extern int setup_amd7930(struct IsdnCard *card);
+#endif
+
+#if CARD_NICCY
+extern int setup_niccy(struct IsdnCard *card);
+#endif
 
-static char *ISACVer[] =
-{"2086/2186 V1.1", "2085 B1", "2085 B2",
- "2085 V2.3"};
+#define HISAX_STATUS_BUFSIZE 4096
+#define ISDN_CTRL_DEBUG 1
+#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", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
+ "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", 
+ "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
+ "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
+ "AMD 7930", "NICCY"
+};
 
 extern struct IsdnCard cards[];
 extern int nrcards;
 extern char *HiSax_id;
+extern struct IsdnBuffers *tracebuf;
+
+#define TIMER3_VALUE 7
+
+static
+struct Fsm l1fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+       ST_L1_F2,
+       ST_L1_F3,
+       ST_L1_F4,
+       ST_L1_F5,
+       ST_L1_F6,
+       ST_L1_F7,
+       ST_L1_F8,
+};
+
+#define L1_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1State[] =
+{
+       "ST_L1_F2",
+       "ST_L1_F3",
+       "ST_L1_F4",
+       "ST_L1_F5",
+       "ST_L1_F6",
+       "ST_L1_F7",
+       "ST_L1_F8",
+};
+
+enum {
+       EV_PH_ACTIVATE,
+       EV_RESET_IND,
+       EV_DEACT_CNF,
+       EV_DEACT_IND,
+       EV_POWER_UP,
+       EV_RSYNC_IND, 
+       EV_INFO2_IND,
+       EV_INFO4_IND,
+       EV_TIMER_DEACT,
+       EV_TIMER_ACT,
+       EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+static char *strL1Event[] =
+{
+       "EV_PH_ACTIVATE",
+       "EV_RESET_IND",
+       "EV_DEACT_CNF",
+       "EV_DEACT_IND",
+       "EV_POWER_UP",
+       "EV_RSYNC_IND", 
+       "EV_INFO2_IND",
+       "EV_INFO4_IND",
+       "EV_TIMER_DEACT",
+       "EV_TIMER_ACT",
+       "EV_TIMER3",
+};
 
 /*
  * Find card with given driverId
  */
 static inline struct IsdnCardState
-*
-hisax_findcard(int driverid)
+*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;
+               if (cards[i].cs)
+                       if (cards[i].cs->myid == driverid)
+                               return (cards[i].cs);
+       return (NULL);
 }
 
 int
@@ -162,6 +270,7 @@ HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
        }
 }
 
+#if ISDN_CTRL_DEBUG
 void
 HiSax_putstatus(struct IsdnCardState *csta, char *buf)
 {
@@ -194,6 +303,23 @@ HiSax_putstatus(struct IsdnCardState *csta, char *buf)
                csta->iif.statcallb(&ic);
        }
 }
+#else
+#define KDEBUG_DEF
+#include "../kdebug.h"
+
+static int DbgLineNr=0,DbgSequenzNr=1;
+
+void
+HiSax_putstatus(struct IsdnCardState *csta, char *buf)
+{
+       char tmp[512];
+       
+       if (DbgLineNr==23)
+               DbgLineNr=0;
+       sprintf(tmp, "%5d %s",DbgSequenzNr++,buf);
+       gput_str(tmp,0,DbgLineNr++);
+}      
+#endif
 
 int
 ll_run(struct IsdnCardState *csta)
@@ -238,228 +364,119 @@ ll_unload(struct IsdnCardState *csta)
 }
 
 void
-debugl1(struct IsdnCardState *sp, char *msg)
+debugl1(struct IsdnCardState *cs, 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);
+       sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg);
+       HiSax_putstatus(cs, tmp);
 }
 
-/*
- * ISAC stuff goes here
- */
-
-char *
-ISACVersion(u_char v)
+static void
+l1m_debug(struct FsmInst *fi, char *s)
 {
-       return (ISACVer[(v >> 5) & 3]);
+       struct PStack *st = fi->userdata;
+       
+       debugl1(st->l1.hardware, s);
 }
 
 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)
+L1activated(struct IsdnCardState *cs)
 {
        struct PStack *st;
 
-       st = sp->stlist;
-       while (st)
-               if (st->l1.act_state)
-                       return (!0);
+       st = cs->stlist;
+       while (st) {
+               if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
                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;
+                       st->l1.l1man(st, PH_ACTIVATE_IND, NULL);
+               st = st->next;
        }
 }
 
-
-static void
-act_ivated(struct IsdnCardState *sp)
+void
+L1deactivated(struct IsdnCardState *cs)
 {
        struct PStack *st;
 
-       st = sp->stlist;
+       st = cs->stlist;
        while (st) {
-               if (st->l1.act_state == 1) {
-                       st->l1.act_state = 2;
-                       st->l1.l1man(st, PH_ACTIVATE, NULL);
-               }
+               if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+                       st->l1.l1l2(st, PH_PAUSE_CNF, NULL);
+               st->l1.l1man(st, PH_DEACTIVATE_IND, NULL);
                st = st->next;
        }
+       test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 }
 
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
-       if (sp->ph_active == 5)
-               act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
+void
+DChannel_proc_xmt(struct IsdnCardState *cs)
 {
        struct PStack *stptr;
 
-       if (sp->tx_skb)
+       if (cs->tx_skb)
                return;
 
-       stptr = sp->stlist;
+       stptr = cs->stlist;
        while (stptr != NULL)
-               if (stptr->l1.requestpull) {
-                       stptr->l1.requestpull = 0;
-                       stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
+               if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
+                       stptr->l1.l1l2(stptr, PH_PULL_CNF, NULL);
                        break;
                } else
                        stptr = stptr->next;
 }
 
-static void
-process_rcv(struct IsdnCardState *sp)
+void
+DChannel_proc_rcv(struct IsdnCardState *cs)
 {
        struct sk_buff *skb, *nskb;
-       struct PStack *stptr;
-       int found, broadc;
+       struct PStack *stptr = cs->stlist;
+       int found, tei, sapi;
        char tmp[64];
 
-       while ((skb = skb_dequeue(&sp->rq))) {
+       if (stptr)
+               if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
+                       FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL);   
+       while ((skb = skb_dequeue(&cs->rq))) {
 #ifdef L2FRAME_DEBUG           /* psa */
-               if (sp->debug & L1_DEB_LAPD)
-                       Logl2Frame(sp, skb, "PH_DATA", 1);
+               if (cs->debug & L1_DEB_LAPD)
+                       Logl2Frame(cs, 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,
+               stptr = cs->stlist;
+               sapi = skb->data[0] >> 2;
+               tei = skb->data[1] >> 1;
+
+               if (tei == GROUP_TEI) {
+                       if (sapi == CTRL_SAPI) {        /* sapi 0 */
+                               if (cs->dlogflag) {
+                                       LogFrame(cs, skb->data, skb->len);
+                                       dlogframe(cs, skb->data + 3, skb->len - 3,
                                                  "Q.931 frame network->user broadcast");
                                }
-                       }
-                       while (stptr != NULL) {
-                               if ((skb->data[0] >> 2) == stptr->l2.sap)
+                               while (stptr != NULL) {
                                        if ((nskb = skb_clone(skb, GFP_ATOMIC)))
-                                               stptr->l1.l1l2(stptr, PH_DATA, nskb);
+                                               stptr->l1.l1l2(stptr, PH_DATA_IND, nskb);
                                        else
                                                printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
-                               stptr = stptr->next;
+                                       stptr = stptr->next;
+                               }
+                       } else if (sapi == TEI_SAPI) {
+                               while (stptr != NULL) {
+                                       if ((nskb = skb_clone(skb, GFP_ATOMIC)))
+                                               stptr->l1.l1tei(stptr, PH_DATA_IND, nskb);
+                                       else
+                                               printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
+                                       stptr = stptr->next;
+                               }
                        }
-                       SET_SKB_FREE(skb);
                        dev_kfree_skb(skb);
-               } else {
+               } else if (sapi == CTRL_SAPI) {
                        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);
+                               if (tei == stptr->l2.tei) {
+                                       stptr->l1.l1l2(stptr, PH_DATA_IND, skb);
                                        found = !0;
                                        break;
                                } else
@@ -474,167 +491,70 @@ process_rcv(struct IsdnCardState *sp)
                                        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);
+                                       LogFrame(cs, skb->data, skb->len);
+                                       dlogframe(cs, skb->data + 4, skb->len - 4, tmp);
                                }
-                               SET_SKB_FREE(skb);
                                dev_kfree_skb(skb);
                        }
                }
-
-       }
-
-}
-
-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)
+BChannel_proc_xmt(struct BCState *bcs)
 {
-       struct PStack *st = hsp->st;
+       struct PStack *st = bcs->st;
 
-       if (hsp->tx_skb)
+       if (test_bit(BC_FLG_BUSY, &bcs->Flag))
                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);
+       if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
+               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+       if (!test_bit(BC_FLG_ACTIV, &bcs->Flag))
+               if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue)))
+                       st->ma.manl1(st, PH_DEACTIVATE_CNF, 0);
 }
 
 static void
-hscx_process_rcv(struct HscxState *hsp)
+BChannel_proc_rcv(struct BCState *bcs)
 {
        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);
+       while ((skb = skb_dequeue(&bcs->rqueue))) {
+               bcs->st->l1.l1l2(bcs->st, PH_DATA_IND, skb);
        }
 }
 
 static void
-hscx_bh(struct HscxState *hsp)
+BChannel_bh(struct BCState *bcs)
 {
-
-       if (!hsp)
+       if (!bcs)
                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);
-
+       if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
+               BChannel_proc_rcv(bcs);
+       if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
+               BChannel_proc_xmt(bcs);
 }
 
-/*
- * interrupt stuff ends here
- */
-
 void
-HiSax_addlist(struct IsdnCardState *sp,
+HiSax_addlist(struct IsdnCardState *cs,
              struct PStack *st)
 {
-       st->next = sp->stlist;
-       sp->stlist = st;
+       st->next = cs->stlist;
+       cs->stlist = st;
 }
 
 void
-HiSax_rmlist(struct IsdnCardState *sp,
+HiSax_rmlist(struct IsdnCardState *cs,
             struct PStack *st)
 {
        struct PStack *p;
 
-       if (sp->stlist == st)
-               sp->stlist = st->next;
+       FsmDelTimer(&st->l1.timer, 0);
+       if (cs->stlist == st)
+               cs->stlist = st->next;
        else {
-               p = sp->stlist;
+               p = cs->stlist;
                while (p)
                        if (p->next == st) {
                                p->next = st->next;
@@ -644,248 +564,117 @@ HiSax_rmlist(struct IsdnCardState *sp,
        }
 }
 
-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))) {
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb);
-       }
-}
-
 void
-setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
+init_bcstate(struct IsdnCardState *cs,
+            int bc)
 {
-       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", card->sp)) {
-               printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
-                      card->sp->irq);
-               restore_flags(flags);
-               return (0);
-       }
-       restore_flags(flags);
-       return (1);
-}
-
-static void
-release_irq(int cardnr)
-{
-       struct IsdnCard *card = cards + cardnr;
-
-       free_irq(card->sp->irq, card->sp);
-}
-
-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);
-               }
-               while ((skb = skb_dequeue(&hs->squeue))) {
-                       SET_SKB_FREE(skb);
-                       dev_kfree_skb(skb);
-               }
-               if (hs->tx_skb) {
-                       SET_SKB_FREE(hs->tx_skb);
-                       dev_kfree_skb(hs->tx_skb);
-                       hs->tx_skb = NULL;
-               }
-       }
-       hs->init = 0;
+       struct BCState *bcs = cs->bcs + bc;
+
+       bcs->cs = cs;
+       bcs->channel = bc;
+       bcs->tqueue.next = 0;
+       bcs->tqueue.sync = 0;
+       bcs->tqueue.routine = (void *) (void *) BChannel_bh;
+       bcs->tqueue.data = bcs;
+       bcs->BC_SetStack = NULL;
+       bcs->BC_Close = NULL;
+       bcs->Flag = 0;
 }
 
 static void
 closecard(int cardnr)
 {
-       struct IsdnCardState *csta = cards[cardnr].sp;
+       struct IsdnCardState *csta = cards[cardnr].cs;
        struct sk_buff *skb;
-
-       close_hscxstate(csta->hs + 1);
-       close_hscxstate(csta->hs);
+       
+       if (csta->bcs->BC_Close != NULL) { 
+               csta->bcs->BC_Close(csta->bcs + 1);
+               csta->bcs->BC_Close(csta->bcs);
+       }
 
        if (csta->rcvbuf) {
                kfree(csta->rcvbuf);
                csta->rcvbuf = NULL;
        }
        while ((skb = skb_dequeue(&csta->rq))) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
        }
        while ((skb = skb_dequeue(&csta->sq))) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
        }
        if (csta->tx_skb) {
-               SET_SKB_FREE(csta->tx_skb);
                dev_kfree_skb(csta->tx_skb);
                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;
+       if (csta->mon_rx) {
+               kfree(csta->mon_rx);
+               csta->mon_rx = NULL;
        }
+       if (csta->mon_tx) {
+               kfree(csta->mon_tx);
+               csta->mon_tx = NULL;
+       }
+       csta->cardmsg(csta, CARD_RELEASE, NULL);
+       del_timer(&csta->dbusytimer);
        ll_unload(csta);
 }
 
-static int
-checkcard(int cardnr, char *id)
+HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+{
+       int irq_cnt, cnt = 3;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       irq_cnt = kstat_irqs(cs->irq);
+       printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
+               irq_cnt);
+       if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) {
+               printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+                       cs->irq);
+               return(1);
+       }
+       while (cnt) {
+               cs->cardmsg(cs, CARD_INIT, NULL);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               /* Timeout 10ms */
+               current->timeout = jiffies + (10 * HZ) / 1000;
+               schedule();
+               restore_flags(flags);
+               printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+                       cs->irq, kstat_irqs(cs->irq));
+               if (kstat_irqs(cs->irq) == irq_cnt) {
+                       printk(KERN_WARNING
+                              "%s: IRQ(%d) getting no interrupts during init %d\n",
+                              CardType[cs->typ], cs->irq, 4 - cnt);
+                       if (cnt == 1) {
+                               free_irq(cs->irq, cs);
+                               return (2);
+                       } else {
+                               cs->cardmsg(cs, CARD_RESET, NULL);
+                               cnt--;
+                       }
+               } else {
+                       cs->cardmsg(cs, CARD_TEST, NULL);
+                       return(0);
+               }
+       }
+       restore_flags(flags);
+       return(3);
+}
+
+HISAX_INITFUNC(static int
+checkcard(int cardnr, char *id, int *busy_flag))
 {
        long flags;
        int ret = 0;
        struct IsdnCard *card = cards + cardnr;
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs;
 
        save_flags(flags);
        cli();
-       if (!(sp = (struct IsdnCardState *)
+       if (!(cs = (struct IsdnCardState *)
              kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
                printk(KERN_WARNING
                       "HiSax: No memory for IsdnCardState(card %d)\n",
@@ -893,10 +682,16 @@ checkcard(int cardnr, char *id)
                restore_flags(flags);
                return (0);
        }
-       card->sp = sp;
-       sp->cardnr = cardnr;
-       sp->cfg_reg = 0;
-       sp->protocol = card->protocol;
+       card->cs = cs;
+       cs->cardnr = cardnr;
+       cs->debug = L1_DEB_WARN;
+       cs->HW_Flags = 0;
+       cs->busy_flag = busy_flag;
+#if TEI_PER_CARD
+#else
+       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+       cs->protocol = card->protocol;
 
        if ((card->typ > 0) && (card->typ < 31)) {
                if (!((1 << card->typ) & SUPORTED_CARDS)) {
@@ -913,31 +708,34 @@ checkcard(int cardnr, char *id)
                restore_flags(flags);
                return (0);
        }
-       if (!(sp->dlogspace = kmalloc(4096, GFP_ATOMIC))) {
+       if (!(cs->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))) {
+       if (!(cs->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);
+               kfree(cs->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 =
+       cs->stlist = NULL;
+       cs->dlogflag = 0;
+       cs->mon_tx = NULL;
+       cs->mon_rx = NULL;
+       cs->status_read = cs->status_buf;
+       cs->status_write = cs->status_buf;
+       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+       cs->typ = card->typ;
+       strcpy(cs->iif.id, id);
+       cs->iif.channels = 2;
+       cs->iif.maxbufsize = MAX_DATA_SIZE;
+       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+       cs->iif.features =
            ISDN_FEATURE_L2_X75I |
            ISDN_FEATURE_L2_HDLC |
            ISDN_FEATURE_L2_TRANS |
@@ -953,21 +751,19 @@ checkcard(int cardnr, char *id)
 #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
+       cs->iif.command = HiSax_command;
+       cs->iif.writecmd = NULL;
+       cs->iif.writebuf_skb = HiSax_writebuf_skb;
+       cs->iif.readstat = HiSax_readstatus;
+       register_isdn(&cs->iif);
+       cs->myid = cs->iif.channels;
+       printk(KERN_INFO
               "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);
+              "NONE", cs->iif.id, cs->myid);
        switch (card->typ) {
 #if CARD_TELES0
                case ISDN_CTYPE_16_0:
@@ -979,6 +775,7 @@ checkcard(int cardnr, char *id)
                case ISDN_CTYPE_16_3:
                case ISDN_CTYPE_PNP:
                case ISDN_CTYPE_TELESPCMCIA:
+               case ISDN_CTYPE_COMPAQ_ISA:
                        ret = setup_teles3(card);
                        break;
 #endif
@@ -989,7 +786,9 @@ checkcard(int cardnr, char *id)
 #endif
 #if CARD_ELSA
                case ISDN_CTYPE_ELSA:
-               case ISDN_CTYPE_ELSA_QS1000:
+               case ISDN_CTYPE_ELSA_PNP:
+               case ISDN_CTYPE_ELSA_PCMCIA:
+               case ISDN_CTYPE_ELSA_PCI:
                        ret = setup_elsa(card);
                        break;
 #endif
@@ -998,90 +797,103 @@ checkcard(int cardnr, char *id)
                        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;
+#if CARD_DIEHLDIVA
+               case ISDN_CTYPE_DIEHLDIVA:
+                       ret = setup_diva(card);
+                       break;
 #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);
+#if CARD_ASUSCOM
+               case ISDN_CTYPE_ASUSCOM:
+                       ret = setup_asuscom(card);
                        break;
 #endif
-#if CARD_TELES3
-               case ISDN_CTYPE_16_3:
-               case ISDN_CTYPE_PNP:
-               case ISDN_CTYPE_TELESPCMCIA:
-                       ret = initteles3(sp);
+#if CARD_TELEINT
+               case ISDN_CTYPE_TELEINT:
+                       ret = setup_TeleInt(card);
                        break;
 #endif
-#if CARD_AVM_A1
-               case ISDN_CTYPE_A1:
-                       ret = initavm_a1(sp);
+#if CARD_SEDLBAUER
+               case ISDN_CTYPE_SEDLBAUER:
+               case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+                       ret = setup_sedlbauer(card);
                        break;
 #endif
-#if CARD_ELSA
-               case ISDN_CTYPE_ELSA:
-               case ISDN_CTYPE_ELSA_QS1000:
-                       ret = initelsa(sp);
+#if CARD_SPORTSTER
+               case ISDN_CTYPE_SPORTSTER:
+                       ret = setup_sportster(card);
                        break;
 #endif
-#if CARD_IX1MICROR2
-               case ISDN_CTYPE_IX1MICROR2:
-                       ret = initix1micro(sp);
+#if CARD_MIC
+               case ISDN_CTYPE_MIC:
+                       ret = setup_mic(card);
                        break;
 #endif
-               default:
-                       ret = 0;
+#if CARD_NETJET
+               case ISDN_CTYPE_NETJET:
+                       ret = setup_netjet(card);
+                       break;
+#endif
+#if CARD_TELES3C
+               case ISDN_CTYPE_TELES3C:
+                       ret = setup_t163c(card);
+                       break;
+#endif
+#if CARD_NICCY
+               case ISDN_CTYPE_NICCY:
+                       ret = setup_niccy(card);
+                       break;
+#endif
+#if CARD_AMD7930
+               case ISDN_CTYPE_AMD7930:
+                       ret = setup_amd7930(card);
                        break;
+#endif
+               default:
+                       printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
+                              card->typ);
+                       ll_unload(cs);
+                       restore_flags(flags);
+                       return (0);
        }
        if (!ret) {
+               ll_unload(cs);
+               restore_flags(flags);
+               return (0);
+       }
+       if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for isac rcvbuf\n");
+               return (1);
+       }
+       cs->rcvidx = 0;
+       cs->tx_skb = NULL;
+       cs->tx_cnt = 0;
+       cs->event = 0;
+       cs->tqueue.next = 0;
+       cs->tqueue.sync = 0;
+       cs->tqueue.data = cs;
+
+       skb_queue_head_init(&cs->rq);
+       skb_queue_head_init(&cs->sq);
+
+       init_bcstate(cs, 0);
+       init_bcstate(cs, 1);
+       ret = init_card(cs);
+       if (ret) {
                closecard(cardnr);
+               restore_flags(flags);
                return (0);
        }
-       init_tei(sp, sp->protocol);
-       CallcNewChan(sp);
-       ll_run(sp);
+       init_tei(cs, cs->protocol);
+       CallcNewChan(cs);
+       ll_run(cs);
+       cs->l1cmd(cs, PH_RESET_REQ, NULL);
+       restore_flags(flags);
        return (1);
 }
 
-void
-HiSax_shiftcards(int idx)
+HISAX_INITFUNC(void
+HiSax_shiftcards(int idx))
 {
        int i;
 
@@ -1089,8 +901,8 @@ HiSax_shiftcards(int idx)
                memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-int
-HiSax_inithardware(void)
+HISAX_INITFUNC(int
+HiSax_inithardware(int *busy_flag))
 {
        int foundcards = 0;
        int i = 0;
@@ -1120,15 +932,15 @@ HiSax_inithardware(void)
                        else
                                sprintf(ids, "%s%d", id, i);
                }
-               if (checkcard(i, ids)) {
+               if (checkcard(i, ids, busy_flag)) {
                        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;
+                       if (cards[i].cs)
+                               kfree((void *) cards[i].cs);
+                       cards[i].cs = NULL;
                        HiSax_shiftcards(i);
                }
        }
@@ -1144,159 +956,66 @@ HiSax_closehardware(void)
        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);
+               if (cards[i].cs) {
+                       ll_stop(cards[i].cs);
+                       release_tei(cards[i].cs);
                        closecard(i);
-                       kfree((void *) cards[i].sp);
-                       cards[i].sp = NULL;
+                       free_irq(cards[i].cs->irq, cards[i].cs);
+                       kfree((void *) cards[i].cs);
+                       cards[i].cs = NULL;
                }
+       Isdnl1Free();
+       TeiFree();
        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))) {
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb);
-       }
-}
-
-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;
+       struct IsdnCardState *cs = cards[cardnr].cs;
+       struct PStack *stptr;
+       struct l3_process *pc;
+       int j, i = 1;
 
        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: Type %s\n", CardType[cs->typ]);
+       printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
        printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
               (ulong) & HiSax_reportcard);
+       printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
+       printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist));
+       stptr = cs->stlist;
+       while (stptr != NULL) {
+               printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr);
+               printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp);
+               printk(KERN_DEBUG "HiSax:   tei %d sapi %d\n",
+                      stptr->l2.tei, stptr->l2.sap);
+               printk(KERN_DEBUG "HiSax:      man 0x%lX\n", (ulong) stptr->ma.layer);
+               pc = stptr->l3.proc;
+               while (pc) {
+                       printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref,
+                              (ulong) pc);
+                       printk(KERN_DEBUG "HiSax:    state %d  st 0x%lX chan 0x%lX\n",
+                           pc->state, (ulong) pc->st, (ulong) pc->chan);
+                       pc = pc->next;
+               }
+               stptr = stptr->next;
+               i++;
+       }
+       for (j = 0; j < 2; j++) {
+               printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j,
+                      (ulong) & cs->channel[j]);
+               stptr = cs->channel[j].b_st;
+               i = 1;
+               while (stptr != NULL) {
+                       printk(KERN_DEBUG "HiSax:  b_st%d 0x%lX\n", i, (ulong) stptr);
+                       printk(KERN_DEBUG "HiSax:    man 0x%lX\n", (ulong) stptr->ma.layer);
+                       stptr = stptr->next;
+                       i++;
+               }
+       }
 }
 
 #ifdef L2FRAME_DEBUG           /* psa */
@@ -1366,7 +1085,7 @@ l2frames(u_char * ptr)
 }
 
 void
-Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
+Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
 {
        char tmp[132];
        u_char *ptr;
@@ -1374,13 +1093,293 @@ Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
        ptr = skb->data;
 
        if (ptr[0] & 1 || !(ptr[1] & 1))
-               debugl1(sp, "Addres not LAPD");
+               debugl1(cs, "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);
+               debugl1(cs, tmp);
        }
 }
-
 #endif
+
+static void
+l1_reset(struct FsmInst *fi, int event, void *arg)
+{
+       FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+
+       FsmChangeState(fi, ST_L1_F3);
+       if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+               cs->l1cmd(cs, PH_ENABLE_REQ, NULL);
+}
+
+static void
+l1_deact_req(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_F3);
+       if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
+               FsmDelTimer(&st->l1.timer, 1);
+               FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+               test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+       }
+}
+
+static void
+l1_power_up(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+
+       if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
+               FsmChangeState(fi, ST_L1_F4);
+               cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+               FsmDelTimer(&st->l1.timer, 1);
+               FsmAddTimer(&st->l1.timer, TIMER3_VALUE * HZ, EV_TIMER3, NULL, 2);
+               test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
+       } else
+               FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_go_F5(struct FsmInst *fi, int event, void *arg)
+{
+       FsmChangeState(fi, ST_L1_F5);
+}
+
+static void
+l1_go_F8(struct FsmInst *fi, int event, void *arg)
+{
+       FsmChangeState(fi, ST_L1_F8);
+}
+
+static void
+l1_info2_ind(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+
+       FsmChangeState(fi, ST_L1_F6);
+       cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+}
+
+static void
+l1_info4_ind(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+
+       FsmChangeState(fi, ST_L1_F7);
+       cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+       if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
+               FsmDelTimer(&st->l1.timer, 4);
+       if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
+               if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
+                       FsmDelTimer(&st->l1.timer, 3);
+               FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
+               test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
+       }
+}
+
+static void
+l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       
+       test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);        
+        if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+               L1deactivated(cs);
+        if (st->l1.l1m.state != ST_L1_F6)
+               FsmChangeState(fi, ST_L1_F3);
+}
+
+static void
+l1_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       
+       test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
+       test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+       L1activated(cs);
+}
+
+static void
+l1_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       
+       test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+       test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+       L1deactivated(cs);
+       cs->l1cmd(cs, PH_DEACT_ACK, NULL);
+}
+
+static void
+l1_activate(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+                
+       cs->l1cmd(cs, PH_RESET_REQ, NULL);
+}
+
+static struct FsmNode L1FnList[] HISAX_INITDATA =
+{
+       {ST_L1_F3, EV_PH_ACTIVATE, l1_activate},
+       {ST_L1_F3, EV_RESET_IND, l1_reset},
+       {ST_L1_F4, EV_RESET_IND, l1_reset},
+       {ST_L1_F5, EV_RESET_IND, l1_reset},
+       {ST_L1_F6, EV_RESET_IND, l1_reset},
+       {ST_L1_F7, EV_RESET_IND, l1_reset},
+       {ST_L1_F8, EV_RESET_IND, l1_reset},
+       {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
+       {ST_L1_F6, EV_DEACT_IND, l1_deact_req},
+       {ST_L1_F7, EV_DEACT_IND, l1_deact_req},
+       {ST_L1_F8, EV_DEACT_IND, l1_deact_req},
+       {ST_L1_F3, EV_POWER_UP, l1_power_up},
+       {ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
+       {ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
+       {ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
+       {ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
+       {ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
+       {ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
+       {ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
+       {ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
+       {ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
+       {ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
+       {ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
+       {ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
+       {ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
+       {ST_L1_F3, EV_TIMER3, l1_timer3},
+       {ST_L1_F4, EV_TIMER3, l1_timer3},
+       {ST_L1_F5, EV_TIMER3, l1_timer3},
+       {ST_L1_F6, EV_TIMER3, l1_timer3},
+       {ST_L1_F8, EV_TIMER3, l1_timer3},
+       {ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
+       {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
+       {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
+       {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
+       {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
+       {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
+       {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1_FN_COUNT (sizeof(L1FnList)/sizeof(struct FsmNode))
+
+HISAX_INITFUNC(void Isdnl1New(void))
+{
+       l1fsm.state_count = L1_STATE_COUNT;
+       l1fsm.event_count = L1_EVENT_COUNT;
+       l1fsm.strEvent = strL1Event;
+       l1fsm.strState = strL1State;
+       FsmNew(&l1fsm, L1FnList, L1_FN_COUNT);
+}
+
+void Isdnl1Free(void)
+{
+       FsmFree(&l1fsm);
+}
+
+static void
+dch_manl1(struct PStack *st, int pr,
+          void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       char tmp[32];
+
+       switch (pr) {
+               case PH_ACTIVATE_REQ:
+                       if (cs->debug) {
+                               sprintf(tmp, "PH_ACTIVATE_REQ %s",
+                                       strL1State[st->l1.l1m.state]);
+                               debugl1(cs, tmp);
+                       }
+                       if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
+                               st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       else {
+                               test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
+                               FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
+                       }
+                       break;
+               case PH_DEACTIVATE_REQ:
+                       if (cs->debug) {
+                               sprintf(tmp, "PH_DEACTIVATE_REQ %s",
+                                       strL1State[st->l1.l1m.state]);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+               case PH_TESTLOOP_REQ:
+                       if (1 & (int) arg)
+                               debugl1(cs, "PH_TEST_LOOP B1");
+                       if (2 & (int) arg)
+                               debugl1(cs, "PH_TEST_LOOP B2");
+                       if (!(3 & (int) arg))
+                               debugl1(cs, "PH_TEST_LOOP DISABLED");
+                       cs->l1cmd(cs, PH_TESTLOOP_REQ, arg);
+                       break;
+               case PH_RESET_IND:
+                       FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
+                       break;
+               case PH_DEACT_CNF:
+                       FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
+                       break;
+               case PH_DEACT_IND:
+                       FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
+                       break;
+               case PH_POWERUP_CNF:
+                       FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
+                       break;
+               case PH_RSYNC_IND:
+                       FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
+                       break;
+               case PH_INFO2_IND:
+                       FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
+                       break;
+               case PH_I4_P8_IND:
+               case PH_I4_P10_IND:
+                       FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
+                       break;
+               default:
+                       if (cs->debug) {
+                               sprintf(tmp, "dch_manl1 msg %04X unhandled", pr);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l1.hardware = cs;
+       st->protocol = cs->protocol;
+       st->l1.l1m.fsm = &l1fsm;
+       st->l1.l1m.state = ST_L1_F3;
+       st->l1.l1m.debug = cs->debug;
+       st->l1.l1m.userdata = st;
+       st->l1.l1m.userint = 0;
+       st->l1.l1m.printdebug = l1m_debug;
+       FsmInitTimer(&st->l1.l1m, &st->l1.timer);
+       setstack_tei(st);
+       setstack_manager(st);
+       st->l1.stlistp = &(cs->stlist);
+       st->ma.manl1 = dch_manl1;
+       st->l1.Flags = 0;
+       cs->setstack_d(st, cs);
+}
index d01d7012302a0f134fc3df5a301af829b71b6290..71f081a07ed9ab2c5276aff8f7fc0c76b99deec3 100644 (file)
@@ -1,18 +1,23 @@
-/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $
- *
+/* $Id: isdnl1.h,v 2.5 1998/02/02 13:36:58 keil Exp $
+
  * $Log: isdnl1.h,v $
- * Revision 1.4  1997/04/06 22:55:52  keil
- * Using SKB's
+ * Revision 2.5  1998/02/02 13:36:58  keil
+ * more debug
+ *
+ * Revision 2.4  1997/11/08 21:35:49  keil
+ * new l1 init
  *
- * Revision 1.3  1996/12/08 19:41:55  keil
- * L2FRAME_DEBUG
+ * Revision 2.3  1997/10/29 19:07:53  keil
+ * changes for 2.1
  *
- * Revision 1.2  1996/10/27 22:26:27  keil
- * ISAC/HSCX version functions
+ * Revision 2.2  1997/07/30 17:11:09  keil
+ * L1deactivated exported
  *
- * Revision 1.1  1996/10/13 20:03:47  keil
- * Initial revision
+ * Revision 2.1  1997/07/27 21:43:58  keil
+ * new l1 interface
  *
+ * Revision 2.0  1997/06/26 11:02:55  keil
+ * New Layer and card interface
  *
  *
  */
 #define        L1_DEB_HSCX             0x10
 #define        L1_DEB_HSCX_FIFO        0x20
 #define        L1_DEB_LAPD             0x40
+#define        L1_DEB_IPAC             0x80
+#define        L1_DEB_RECEIVE_FRAME    0x100
 
+#define D_RCVBUFREADY  0
+#define D_XMTBUFREADY  1
+#define D_L1STATECHANGE        2
+#define D_CLEARBUSY    3
+#define D_RX_MON0      4
+#define D_RX_MON1      5
+#define D_TX_MON0      6
+#define D_TX_MON1      7
 
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE    2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
+#define B_RCVBUFREADY 0
+#define B_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 int get_irq(int cardnr, void *routine);
+extern void DChannel_proc_xmt(struct IsdnCardState *cs);
+extern void DChannel_proc_rcv(struct IsdnCardState *cs);
+
 
 #ifdef L2FRAME_DEBUG
 extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir);
index 9c58eef90f16c979e903b07a8da73fa7d2712c74..eadfa4c8a32a2a458f4f5417091dc52a3bd3b90c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $
+/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,56 +7,51 @@
  *              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 2.7  1998/02/12 23:07:47  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.9  1997/04/07 23:02:11  keil
- * missing braces
+ * Revision 2.6  1998/02/02 13:36:15  keil
+ * bugfix X.75 win calculation
  *
- * Revision 1.8  1997/04/06 22:59:59  keil
- * Using SKB's; changing function names; some minor changes
+ * Revision 2.5  1997/11/06 17:09:22  keil
+ * New 2.1 init code
  *
- * Revision 1.7  1997/02/09 00:25:44  keil
- * new interface handling, one interface per card
+ * Revision 2.4  1997/10/29 19:02:01  keil
+ * new LL interface
  *
- * Revision 1.6  1997/01/21 22:23:42  keil
- * D-channel log changed
+ * Revision 2.3  1997/10/01 09:21:39  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
  *
- * Revision 1.5  1997/01/04 13:47:06  keil
- * handling of MDL_REMOVE added (Thanks to Sim Yskes)
+ * Revision 2.2  1997/07/31 11:49:05  keil
+ * Eroor handling for no TEI assign
  *
- * Revision 1.4  1996/12/08 19:51:51  keil
- * many fixes from Pekka Sarnila
+ * Revision 2.1  1997/07/27 21:34:38  keil
+ * cosmetics
  *
- * 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
+ * Revision 2.0  1997/06/26 11:07:29  keil
+ * New q.921 and X.75 Layer2
  *
  *
+ *  Old log removed KKe
  *
  */
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 1.10 $";
+const char *l2_revision = "$Revision: 2.7 $";
 
 static void l2m_debug(struct FsmInst *fi, char *s);
 
+static
 struct Fsm l2fsm =
 {NULL, 0, 0, NULL, NULL};
 
 enum {
        ST_L2_1,
+       ST_L2_2,
        ST_L2_3,
        ST_L2_4,
        ST_L2_5,
@@ -70,6 +65,7 @@ enum {
 static char *strL2State[] =
 {
        "ST_L2_1",
+       "ST_L2_2",
        "ST_L2_3",
        "ST_L2_4",
        "ST_L2_5",
@@ -81,53 +77,53 @@ static char *strL2State[] =
 enum {
        EV_L2_UI,
        EV_L2_SABMX,
-       EV_L2_UA,
        EV_L2_DISC,
-       EV_L2_I,
-       EV_L2_RR,
-       EV_L2_REJ,
+       EV_L2_DM,
+       EV_L2_UA,
        EV_L2_FRMR,
+       EV_L2_SUPER,
+       EV_L2_I,
        EV_L2_DL_DATA,
+       EV_L2_ACK_PULL,
+       EV_L2_DL_UNIT_DATA,
        EV_L2_DL_ESTABLISH,
+       EV_L2_DL_RELEASE,
        EV_L2_MDL_ASSIGN,
        EV_L2_MDL_REMOVE,
-       EV_L2_DL_UNIT_DATA,
-       EV_L2_DL_RELEASE,
+       EV_L2_MDL_ERROR,
        EV_L2_MDL_NOTEIPROC,
+       EV_L1_DEACTIVATE,
        EV_L2_T200,
-       EV_L2_ACK_PULL,
        EV_L2_T203,
-       EV_L2_RNR,
 };
 
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
+#define L2_EVENT_COUNT (EV_L2_T203+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_DM",
+       "EV_L2_UA",
        "EV_L2_FRMR",
+       "EV_L2_SUPER",
+       "EV_L2_I",
        "EV_L2_DL_DATA",
+       "EV_L2_ACK_PULL",
+       "EV_L2_DL_UNIT_DATA",
        "EV_L2_DL_ESTABLISH",
+       "EV_L2_DL_RELEASE",
        "EV_L2_MDL_ASSIGN",
        "EV_L2_MDL_REMOVE",
-       "EV_L2_DL_UNIT_DATA",
-       "EV_L2_DL_RELEASE",
+       "EV_L2_MDL_ERROR",
        "EV_L2_MDL_NOTEIPROC",
+       "EV_L1_DEACTIVATE",
        "EV_L2_T200",
-       "EV_L2_ACK_PULL",
        "EV_L2_T203",
-       "EV_L2_RNR",
 };
 
-int errcount = 0;
-
-static int l2addrsize(struct Layer2 *tsp);
+static int l2addrsize(struct Layer2 *l2);
 
 static void
 InitWin(struct Layer2 *l2)
@@ -143,11 +139,9 @@ ReleaseWin(struct Layer2 *l2)
 {
        int i, cnt = 0;
 
-
        for (i = 0; i < MAX_WINDOW; i++) {
                if (l2->windowar[i]) {
                        cnt++;
-                       SET_SKB_FREE(l2->windowar[i]);
                        dev_kfree_skb(l2->windowar[i]);
                        l2->windowar[i] = NULL;
                }
@@ -156,13 +150,15 @@ ReleaseWin(struct Layer2 *l2)
                printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
 }
 
-static int
+inline int
 cansend(struct PStack *st)
 {
        int p1;
 
-       p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
-       return (st->l2.vs != p1);
+       p1 = st->l2.vs - st->l2.va;
+       if (p1 < 0)
+               p1 += (test_bit(FLG_MOD128, &st->l2.flag) ? 128 : 8);
+       return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
 }
 
 static void
@@ -171,40 +167,54 @@ 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);
        }
 }
 
-int
-l2headersize(struct Layer2 *tsp, int ui)
+static void
+discard_ui_queue(struct PStack *st)
 {
-       return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&st->l2.ui_queue))) {
+               dev_kfree_skb(skb);
+       }
 }
 
-int
-l2addrsize(struct Layer2 *tsp)
+inline void
+clear_exception(struct Layer2 *l2)
 {
-       return (tsp->laptype == LAPD ? 2 : 1);
+       test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+       test_and_clear_bit(FLG_REJEXC, &l2->flag);
+       test_and_clear_bit(FLG_OWN_BUSY, &l2->flag);
+       test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+}
+
+inline int
+l2headersize(struct Layer2 *l2, int ui)
+{
+       return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
+               (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
+}
+
+inline int
+l2addrsize(struct Layer2 *l2)
+{
+       return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1);
 }
 
 static int
-sethdraddr(struct Layer2 *tsp,
-          u_char * header, int rsp)
+sethdraddr(struct Layer2 *l2, u_char * header, int rsp)
 {
        u_char *ptr = header;
-       int crbit;
+       int crbit = rsp;
 
-       if (tsp->laptype == LAPD) {
-               crbit = rsp;
-               if (!tsp->orig)
-                       crbit = !crbit;
-               *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
-               *ptr++ = (tsp->tei << 1) | 1;
+       if (test_bit(FLG_LAPD, &l2->flag)) {
+               *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0);
+               *ptr++ = (l2->tei << 1) | 1;
                return (2);
        } else {
-               crbit = rsp;
-               if (tsp->orig)
+               if (test_bit(FLG_ORIG, &l2->flag))
                        crbit = !crbit;
                if (crbit)
                        *ptr++ = 1;
@@ -218,79 +228,107 @@ static void
 enqueue_ui(struct PStack *st,
           struct sk_buff *skb)
 {
-       st->l2.l2l1(st, PH_DATA, skb);
+       st->l2.l2l1(st, PH_DATA_REQ, skb);
 }
 
 static void
 enqueue_super(struct PStack *st,
              struct sk_buff *skb)
 {
-       st->l2.l2l1(st, PH_DATA, skb);
+       st->l2.l2l1(st, PH_DATA_REQ, skb);
 }
 
-static int
-legalnr(struct PStack *st, int nr)
+inline int
+IsUI(u_char * data, int ext)
 {
-       struct Layer2 *l2 = &st->l2;
-       int lnr, lvs;
+       return ((data[0] & 0xef) == UI);
+}
 
-       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);
+inline int
+IsUA(u_char * data, int ext)
+{
+       return ((data[0] & 0xef) == UA);
 }
 
-static void
-setva(struct PStack *st, int nr)
+inline int
+IsDM(u_char * data, int ext)
 {
-       struct Layer2 *l2 = &st->l2;
+       return ((data[0] & 0xef) == DM);
+}
 
-       if (l2->va != nr) {
-               while (l2->va != nr) {
-                       l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
-                       SET_SKB_FREE(l2->windowar[l2->sow]);
-                       dev_kfree_skb(l2->windowar[l2->sow]);
-                       l2->windowar[l2->sow] = NULL;
-                       l2->sow = (l2->sow + 1) % l2->window;
-                       if (st->l4.l2writewakeup)
-                               st->l4.l2writewakeup(st);
-               }
-       }
+inline int
+IsDISC(u_char * data, int ext)
+{
+       return ((data[0] & 0xef) == DISC);
 }
 
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
+inline int
+IsRR(u_char * data, int ext)
 {
-       struct PStack *st = fi->userdata;
+       if (ext)
+               return (data[0] == RR);
+       else
+               return ((data[0] & 0xf) == 1);
+}
 
-       st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces);
-       FsmChangeState(fi, ST_L2_3);
+inline int
+IsSABMX(u_char * data, int ext)
+{
+       u_char d = data[0] & ~0x10;
+
+       return (ext ? d == SABME : d == SABM);
 }
 
-static void
-l2_send_ui(struct FsmInst *fi, int event, void *arg)
+inline int
+IsREJ(u_char * data, int ext)
 {
-       struct PStack *st = fi->userdata;
-       struct sk_buff *skb = arg;
-       u_char header[MAX_HEADER_LEN];
-       int i;
+       return (ext ? data[0] == REJ : (data[0] & 0xf) == REJ);
+}
 
-       i = sethdraddr(&(st->l2), header, CMD);
-       header[i++] = UI;
-       memcpy(skb_push(skb, i), header, i);
-       enqueue_ui(st, skb);
+inline int
+IsFRMR(u_char * data, int ext)
+{
+       return ((data[0] & 0xef) == FRMR);
 }
 
-static void
-l2_receive_ui(struct FsmInst *fi, int event, void *arg)
+inline int
+IsRNR(u_char * data, int ext)
 {
-       struct PStack *st = fi->userdata;
-       struct sk_buff *skb = arg;
+       return (ext ? data[0] == RNR : (data[0] & 0xf) == RNR);
+}
 
-       skb_pull(skb, l2headersize(&st->l2, 1));
-       st->l2.l2l3(st, DL_UNIT_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 + (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8));
+       lnr = (nr >= l2->va) ? nr : (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+       return (lnr <= lvs);
 }
 
-inline void
+static void
+setva(struct PStack *st, int nr)
+{
+       struct Layer2 *l2 = &st->l2;
+       int len;
+
+       while (l2->va != nr) {
+               l2->va = (l2->va + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+               len = l2->windowar[l2->sow]->len;
+               if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type)
+                       len = -1;
+               dev_kfree_skb(l2->windowar[l2->sow]);
+               l2->windowar[l2->sow] = NULL;
+               l2->sow = (l2->sow + 1) % l2->window;
+               if (st->lli.l2writewakeup && (len >=0))
+                       st->lli.l2writewakeup(st, len);
+       }
+}
+
+static void
 send_uframe(struct PStack *st, u_char cmd, u_char cr)
 {
        struct sk_buff *skb;
@@ -307,53 +345,156 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr)
        enqueue_super(st, skb);
 }
 
+inline u_char
+get_PollFlag(struct PStack * st, struct sk_buff * skb)
+{
+       return (skb->data[l2addrsize(&(st->l2))] & 0x10);
+}
+
+inline void
+FreeSkb(struct sk_buff *skb)
+{
+       dev_kfree_skb(skb);
+}
+
+
+inline u_char
+get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
+{
+       u_char PF;
+
+       PF = get_PollFlag(st, skb);
+       FreeSkb(skb);
+       return (PF);
+}
+
 static void
 establishlink(struct FsmInst *fi)
 {
        struct PStack *st = fi->userdata;
        u_char cmd;
 
-       FsmChangeState(fi, ST_L2_5);
+       clear_exception(&st->l2);
        st->l2.rc = 0;
+       cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10;
+       send_uframe(st, cmd, CMD);
+       FsmDelTimer(&st->l2.t203, 1);
+       FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 1);
+       test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+       FsmChangeState(fi, ST_L2_5);
+}
+
+static void
+l2_mdl_error(struct FsmInst *fi, int event, void *arg)
+{
+       struct sk_buff *skb = arg;
+       struct PStack *st = fi->userdata;
 
-       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");
+       switch (event) {
+               case EV_L2_UA:
+                       if (get_PollFlagFree(st, skb))
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'C');
+                       else
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'D');
+                       break;
+               case EV_L2_DM:
+                       if (get_PollFlagFree(st, skb))
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'B');
+                       else {
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'E');
+                               establishlink(fi);
+                               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+                       }
+                       break;
+       }
+}
 
+static void
+l2_dl_establish(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       int state = fi->state;
 
-       cmd = (st->l2.extended ? SABME : SABM) | 0x10; 
-       send_uframe(st, cmd, CMD);
+       FsmChangeState(fi, ST_L2_3); 
+       if (state == ST_L2_1)
+               st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
 }
 
 static void
-l2_establish(struct FsmInst *fi, int event, void *arg)
+l2_send_ui(struct PStack *st)
 {
-       establishlink(fi);
+       struct sk_buff *skb;
+       u_char header[MAX_HEADER_LEN];
+       int i;
+
+       i = sethdraddr(&(st->l2), header, CMD);
+       header[i++] = UI;
+       while ((skb = skb_dequeue(&st->l2.ui_queue))) {
+               memcpy(skb_push(skb, i), header, i);
+               enqueue_ui(st, skb);
+       }
 }
 
 static void
-l2_send_disconn(struct FsmInst *fi, int event, void *arg)
+l2_put_ui(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct Channel *chanp = st->l4.userdata;
-
-       FsmChangeState(fi, ST_L2_6);
+       struct sk_buff *skb = arg;
 
-       FsmDelTimer(&st->l2.t203_timer, 1);
-       if (st->l2.t200_running) {
-               FsmDelTimer(&st->l2.t200_timer, 2);
-               st->l2.t200_running = 0;
+       skb_queue_tail(&st->l2.ui_queue, skb);
+       if (fi->state == ST_L2_1) {
+               FsmChangeState(fi, ST_L2_2);
+               st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
        }
-       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 (fi->state > ST_L2_3)
+               l2_send_ui(st);
+}
 
+static void
+l2_got_ui(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
 
-       if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
-               send_uframe(st, DISC | 0x10, CMD);
+       skb_pull(skb, l2headersize(&st->l2, 1));
+       if (skb->len > st->l2.maxlen) { 
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+               FreeSkb(skb);
+       } else
+               st->l2.l2l3(st, DL_UNIT_DATA, skb);
+}
 
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       if (fi->state != ST_L2_4)
+               discard_i_queue(st);
+       if (fi->state != ST_L2_5)
+               establishlink(fi);
+       test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+}
+
+static void
+l2_dl_release(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       if (fi->state == ST_L2_4) {
+               st->l2.l2man(st, DL_RELEASE, NULL);
+               return;
+       } else if (fi->state == ST_L2_5) {
+               test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
+               return;
+       }
        discard_i_queue(st);
+       FsmChangeState(fi, ST_L2_6);
+       st->l2.rc = 0;
+       send_uframe(st, DISC | 0x10, CMD);
+       FsmDelTimer(&st->l2.t203, 1);
+       FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 2);
+       test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 }
 
 static void
@@ -361,46 +502,59 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       int est = 1, state;
+       int est = 1, state, rsp;
        u_char PollFlag;
 
        state = fi->state;
-
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       PollFlag = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
-
-       if (ST_L2_4 != state)
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
+       if (rsp) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }       
+       if (skb->len != (l2addrsize(&st->l2) + 1)) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }
+       PollFlag = get_PollFlagFree(st, skb);
+       if (ST_L2_6 == state) {
+               send_uframe(st, DM | PollFlag, RSP);
+               return;
+       } else
+               send_uframe(st, UA | PollFlag, RSP);
+       if (ST_L2_5 == state)
+               return;
+       if (ST_L2_4 != state) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'F');
                if (st->l2.vs != st->l2.va) {
                        discard_i_queue(st);
                        est = 1;
                } else
                        est = 0;
-
+       }
+       clear_exception(&st->l2);
        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");
+       FsmChangeState(fi, ST_L2_7);
+       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+               FsmDelTimer(&st->l2.t200, 2);
+       FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 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);
+                       st->l2.l2l1(st, PH_PULL_REQ, NULL);
 }
 
 static void
@@ -408,87 +562,152 @@ 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);
+       u_char PollFlag, cmd = UA;
+       int state, rel = 1, cst = 1, rsp;
 
-       FsmChangeState(fi, ST_L2_4);
+       state = fi->state;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
 
-       FsmDelTimer(&st->l2.t203_timer, 3);
-       if (st->l2.t200_running) {
-               FsmDelTimer(&st->l2.t200_timer, 4);
-               st->l2.t200_running = 0;
+       if (rsp) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }       
+       if (skb->len != (l2addrsize(&st->l2) + 1)) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
        }
-       if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
-               send_uframe(st, UA | PollFlag, RSP);
-
-       st->l2.l2man(st, DL_RELEASE, NULL);
+       PollFlag = get_PollFlagFree(st, skb);
+       if ((state == ST_L2_4) || (state == ST_L2_5)) {
+               rel = 0;
+               cst = 0;
+               cmd = DM;
+       } else if (state == ST_L2_6) {
+               rel = 0;
+               cst = 0;
+       }
+       if (cst) {
+               FsmChangeState(fi, ST_L2_4);
+               FsmDelTimer(&st->l2.t203, 3);
+               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) 
+                       FsmDelTimer(&st->l2.t200, 2);
+       }
+       send_uframe(st, cmd | PollFlag, RSP);
+       if (rel)
+               st->l2.l2man(st, DL_RELEASE, NULL);
 }
 
+
 static void
-l2_got_st4_disc(struct FsmInst *fi, int event, void *arg)
+l2_got_ua(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;
+       u_char PollFlag, est = 1;
+       int state,rsp;
 
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       PollFlag = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
+       state = fi->state;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
 
-       if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
-               send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP);
+       if (!rsp) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }       
+       if (skb->len != (l2addrsize(&st->l2) + 1)) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               FreeSkb(skb);
+               if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }
+       PollFlag = get_PollFlag(st, skb);
+       if (!PollFlag) {
+               l2_mdl_error(fi, event, arg);
+               return;
+       }
+       FreeSkb(skb);
 
+       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+               FsmDelTimer(&st->l2.t200, 2);
+       if (fi->state == ST_L2_5) {
+               if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) {
+                       discard_i_queue(st);
+                       st->l2.rc = 0;
+                       send_uframe(st, DISC | 0x10, CMD);
+                       FsmChangeState(fi, ST_L2_6);
+                       FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4);
+                       test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+               } else {
+                       if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag))
+                               if (st->l2.vs != st->l2.va)
+                                       discard_i_queue(st);
+                               else
+                                       est = 0;
+                       st->l2.vs = 0;
+                       st->l2.va = 0;
+                       st->l2.vr = 0;
+                       st->l2.sow = 0;
+                       FsmChangeState(fi, ST_L2_7);
+                       FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
+                       if (est)
+                               st->l2.l2man(st, DL_ESTABLISH, NULL);
+               }
+       } else {                /* ST_L2_6 */
+               st->l2.l2man(st, DL_RELEASE, NULL);
+               FsmChangeState(fi, ST_L2_4);
+       }
 }
 
 static void
-l2_got_ua_establish(struct FsmInst *fi, int event, void *arg)
+l2_got_dm(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       u_char f;
+       u_char PollFlag;
+       int state,rsp;
 
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       f = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
-       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");
+       state = fi->state;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
 
-               st->l2.l2man(st, DL_ESTABLISH, NULL);
+       if (!rsp) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }       
+       if (skb->len != (l2addrsize(&st->l2) + 1)) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               FreeSkb(skb);
+               if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
+                       establishlink(fi);
+               return;
        }
-}
-
-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);
-       if (f) {
-               FsmDelTimer(&st->l2.t200_timer, 6);
-               FsmChangeState(fi, ST_L2_4);
+       PollFlag = get_PollFlagFree(st, skb);
+       if (!PollFlag) {
+               establishlink(fi);
+               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+       } else {
+               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                       FsmDelTimer(&st->l2.t200, 2);
+               if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag))
+                       discard_i_queue(st);
                st->l2.l2man(st, DL_RELEASE, NULL);
+               FsmChangeState(fi, ST_L2_4);
        }
 }
 
@@ -502,7 +721,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
 
        l2 = &st->l2;
        i = sethdraddr(l2, tmp, cr);
-       if (l2->extended) {
+       if (test_bit(FLG_MOD128, &l2->flag)) {
                tmp[i++] = typ;
                tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
        } else
@@ -516,279 +735,279 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
 }
 
 inline void
-enquiry_response(struct PStack *st, u_char typ, u_char final)
+enquiry_response(struct PStack *st)
 {
-       enquiry_cr(st, typ, RSP, final);
+       if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
+               enquiry_cr(st, RNR, RSP, 1);
+       else
+               enquiry_cr(st, RR, RSP, 1);
+       test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
 }
 
 inline void
-enquiry_command(struct PStack *st, u_char typ, u_char poll)
+transmit_enquiry(struct PStack *st)
 {
-       enquiry_cr(st, typ, CMD, poll);
+       if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
+               enquiry_cr(st, RNR, CMD, 1);
+       else
+               enquiry_cr(st, RR, CMD, 1);
+       test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
+       FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 12);
+       test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
 }
 
+
 static void
 nrerrorrecovery(struct FsmInst *fi)
 {
-       /* should log error here */
+       struct PStack *st = fi->userdata;
+
+       st->ma.layer(st, MDL_ERROR_IND, (void *) 'J');
        establishlink(fi);
 }
 
 static void
-l2_got_st7_RR(struct FsmInst *fi, int event, void *arg)
+invoke_retransmission(struct PStack *st, int nr)
 {
-       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);
+       struct Layer2 *l2 = &st->l2;
+       int p1;
+       long flags;
 
-       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);
+       if (l2->vs != nr) {
+               save_flags(flags);
+               cli();
+               while (l2->vs != nr) {
+                       l2->vs = l2->vs - 1;
+                       if (l2->vs < 0)
+                               l2->vs += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+                       p1 = l2->vs - l2->va;
+                       if (p1 < 0)
+                               p1 += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+                       p1 = (p1 + l2->sow) % l2->window;
+                       skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+                       l2->windowar[p1] = 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);
+               restore_flags(flags);
+               st->l2.l2l1(st, PH_PULL_REQ, 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)
+l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
 {
        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;
+       int PollFlag, nr, rsp, typ = RR;
+       struct Layer2 *l2 = &st->l2;
 
-               l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
-               l2->rejexp = 0;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &l2->flag))
+               rsp = !rsp;
 
-               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));
+       skb_pull(skb, l2addrsize(l2));
+       if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
+               test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+               typ = RNR;
+       } else
+               test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+       if (IsREJ(skb->data, test_bit(FLG_MOD128, &l2->flag)))
+               typ = REJ;
+       if (test_bit(FLG_MOD128, &l2->flag)) {
+               if (skb->len == 2) {
+                       PollFlag = (skb->data[1] & 0x1) == 0x1;
+                       nr = skb->data[1] >> 1;
+               } else {
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
        } else {
-               /* n(s)!=v(r) */
-               wasok = 0;
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb);
-               if (st->l2.rejexp) {
-                       if (p)
-                               if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
-                                       enquiry_response(st, RR, p);
+               if (skb->len == 1) {
+                       PollFlag = (skb->data[0] & 0x10);
+                       nr = (skb->data[0] >> 5) & 0x7;
                } else {
-                       st->l2.rejexp = !0;
-                       enquiry_command(st, REJ, 1);
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
                }
        }
-       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);
+       FreeSkb(skb);
 
+       if ((!rsp) && PollFlag)
+               enquiry_response(st);
+       if (rsp && PollFlag)
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'A');
        if (legalnr(st, nr)) {
-               if (nr == st->l2.vs) {
+               if (typ == REJ) {
                        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) {
+                       invoke_retransmission(st, nr);
+                       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                               FsmDelTimer(&st->l2.t200, 9);
+                       if (FsmAddTimer(&st->l2.t203, st->l2.T203,
+                                       EV_L2_T203, NULL, 6))
+                               l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ");
+               } else if ((nr == l2->vs) && (typ == RR)) {
                        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);
+                       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                               FsmDelTimer(&st->l2.t200, 9);
+                       FsmRestartTimer(&st->l2.t203, st->l2.T203,
+                                       EV_L2_T203, NULL, 7);
+               } else if ((l2->va != nr) || (typ == RNR)) {
+                       setva(st, nr);
+                       FsmDelTimer(&st->l2.t203, 9);
+                       FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 6);
+                       test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
                }
+               if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
+                       st->l2.l2l1(st, PH_PULL_REQ, 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;
+       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);
+       }
+}
 
-                       p1 = l2->vs - l2->va;
-                       if (p1 < 0)
-                               p1 += l2->extended ? 128 : 8;
-                       p1 = (p1 + l2->sow) % l2->window;
+static void
+l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
 
-                       skb_queue_head(&l2->i_queue, l2->windowar[p1]);
-                       l2->windowar[p1] = NULL;
-               }
-               st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-       }
+       if (test_bit(FLG_LAPB, &st->l2.flag))
+               st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0);
+       if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag)))
+               skb_queue_tail(&st->l2.i_queue, skb);
+       if (fi->state == ST_L2_7)
+               st->l2.l2l1(st, PH_PULL_REQ, NULL);
 }
 
 static void
-l2_got_st7_rej(struct FsmInst *fi, int event, void *arg)
+l2_got_iframe(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       int PollFlag, seq, rsp;
-       struct Layer2 *l2;
+       struct IsdnCardState *sp = st->l1.hardware;
+       struct Layer2 *l2 = &(st->l2);
+       int PollFlag, ns, nr, i, hs, rsp;
+       char str[64];
 
-       l2 = &st->l2;
-       if (l2->laptype == LAPD)
-               rsp = *skb->data & 0x2;
-       else
-               rsp = *skb->data == 0x3;
-       if (l2->orig)
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &l2->flag))
                rsp = !rsp;
 
-       skb_pull(skb, l2addrsize(l2));
-       if (l2->extended) {
-               PollFlag = (skb->data[1] & 0x1) == 0x1;
-               seq = skb->data[1] >> 1;
+       if (rsp) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               FreeSkb(skb);
+               establishlink(fi);
+               return;
+       }       
+       i = l2addrsize(l2);
+       if (test_bit(FLG_MOD128, &l2->flag)) {
+               if (skb->len <= (i + 1)) {
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               } else if ((skb->len - i - 1) > l2->maxlen) { 
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
+               PollFlag = ((skb->data[i + 1] & 0x1) == 0x1);
+               ns = skb->data[i] >> 1;
+               nr = (skb->data[i + 1] >> 1) & 0x7f;
        } else {
-               PollFlag = (skb->data[0] & 0x10);
-               seq = (skb->data[0] >> 5) & 0x7;
+               if (skb->len <= i) {
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               } else if ((skb->len - i) > l2->maxlen) { 
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
+               PollFlag = (skb->data[i] & 0x10);
+               ns = (skb->data[i] >> 1) & 0x7;
+               nr = (skb->data[i] >> 5) & 0x7;
+       }
+       if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
+               FreeSkb(skb);
+               enquiry_response(st);
+       } else if (l2->vr == ns) {
+               l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
+               test_and_clear_bit(FLG_REJEXC, &l2->flag);
+               if (test_bit(FLG_LAPD, &l2->flag))
+                       if (sp->dlogflag) {
+                               hs = l2headersize(l2, 0);
+                               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 + hs,
+                                         skb->len - hs, str);
+                       }
+               if (PollFlag)
+                       enquiry_response(st);
+               else
+                       test_and_set_bit(FLG_ACK_PEND, &l2->flag);
+               skb_pull(skb, l2headersize(l2, 0));
+               st->l2.l2l3(st, DL_DATA, skb);
+       } else {
+               /* n(s)!=v(r) */
+               FreeSkb(skb);
+               if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
+                       if (PollFlag)
+                               enquiry_response(st);
+               } else {
+                       enquiry_cr(st, REJ, RSP, PollFlag);
+                       test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
+               }
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
-
-       if ((!rsp) && PollFlag)
-               enquiry_response(st, RR, PollFlag);
 
-       if (!legalnr(st, seq))
+       if (legalnr(st, nr)) {
+               setva(st, nr);
+               if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) {
+                       if (nr == st->l2.vs) {
+                               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                                       FsmDelTimer(&st->l2.t200, 10);
+                               FsmRestartTimer(&st->l2.t203, st->l2.T203,
+                                               EV_L2_T203, NULL, 7);
+                       } else if (nr != st->l2.va) {
+                               FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
+                                               NULL, 8);
+                               test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+                       }
+               }
+       } else {
+               nrerrorrecovery(fi);
                return;
+       }
+
+       if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
+               st->l2.l2l1(st, PH_PULL_REQ, NULL);
+       if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
+               enquiry_cr(st, RR, RSP, 0);
+}
+
+static void
+l2_got_tei(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
 
-       setva(st, seq);
-       invoke_retransmission(st, seq);
+       st->l2.tei = (int) arg;
+
+       if (fi->state == ST_L2_3) {
+               establishlink(fi);
+               test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+       } else
+               FsmChangeState(fi, ST_L2_4);
+       if (skb_queue_len(&st->l2.ui_queue))
+               l2_send_ui(st);
 }
 
 static void
@@ -801,21 +1020,21 @@ 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) {
+       if (test_bit(FLG_LAPD, &st->l2.flag) &&
+               test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+       } else if (st->l2.rc == st->l2.N200) {
                FsmChangeState(fi, ST_L2_4);
-               st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei);
+               test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
+               discard_i_queue(st);
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'G');
                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);
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+               send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM)
+                           | 0x10, CMD);
        }
 }
 
@@ -823,30 +1042,65 @@ 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) {
+       if (test_bit(FLG_LAPD, &st->l2.flag) &&
+               test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+       } else if (st->l2.rc == st->l2.N200) {
                FsmChangeState(fi, ST_L2_4);
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'H');
                st->l2.l2man(st, DL_RELEASE, NULL);
        } else {
                st->l2.rc++;
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
+                           NULL, 9);
+               send_uframe(st, DISC | 0x10, CMD);
+       }
+}
 
-               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");
+static void
+l2_st78_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
 
+       if (test_bit(FLG_LAPD, &st->l2.flag) &&
+               test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
+               return;
+       }
+       test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
+       if (fi->state == ST_L2_7) {
+               st->l2.rc = 0;
+               FsmChangeState(fi, ST_L2_8);
+       }
+       if (st->l2.rc == st->l2.N200) {
+               establishlink(fi);
+       } else {
+               transmit_enquiry(st);
+               st->l2.rc++;
+       }
+}
 
-               if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
-                       send_uframe(st, DISC | 0x10, CMD);
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
 
+       if (test_bit(FLG_LAPD, &st->l2.flag) &&
+               test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) {
+               FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9);
+               return;
        }
+       FsmChangeState(fi, ST_L2_8);
+       transmit_enquiry(st);
+       st->l2.rc = 0;
 }
 
 static void
 l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *oskb;
        struct Layer2 *l2 = &st->l2;
        u_char header[MAX_HEADER_LEN];
        int p1, i;
@@ -860,19 +1114,18 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 
        p1 = l2->vs - l2->va;
        if (p1 < 0)
-               p1 += l2->extended ? 128 : 8;
+               p1 += test_bit(FLG_MOD128, &l2->flag) ? 128 : 8;
        p1 = (p1 + l2->sow) % l2->window;
        if (l2->windowar[p1]) {
                printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
                       p1);
-               SET_SKB_FREE(l2->windowar[p1]);
                dev_kfree_skb(l2->windowar[p1]);
        }
        l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
 
        i = sethdraddr(&st->l2, header, CMD);
 
-       if (l2->extended) {
+       if (test_bit(FLG_MOD128, &l2->flag)) {
                header[i++] = l2->vs << 1;
                header[i++] = l2->vr << 1;
                l2->vs = (l2->vs + 1) % 128;
@@ -880,88 +1133,86 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
                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;
+       p1 = skb->data - skb->head;
+       if (p1 >= i)
+               memcpy(skb_push(skb, i), header, i);
+       else {
+               printk(KERN_WARNING
+               "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
+               oskb = skb;
+               skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
+               memcpy(skb_put(skb, i), header, i);
+               memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
+               FreeSkb(oskb);
+       }
+       st->l2.l2l1(st, PH_PULL_IND, skb);
+       test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
+       if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
+               FsmDelTimer(&st->l2.t203, 13);
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
        }
        if (skb_queue_len(&l2->i_queue) && cansend(st))
-               st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+               st->l2.l2l1(st, PH_PULL_REQ, 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)
+l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       int PollFlag, seq, rsp;
-       struct Layer2 *l2;
+       int PollFlag, nr, rsp, rnr = 0;
+       struct Layer2 *l2 = &st->l2;
 
-       l2 = &st->l2;
-       if (l2->laptype == LAPD)
-               rsp = *skb->data & 0x2;
-       else
-               rsp = *skb->data == 0x3;
-       if (l2->orig)
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &l2->flag))
                rsp = !rsp;
-
        skb_pull(skb, l2addrsize(l2));
-       if (l2->extended) {
-               PollFlag = (skb->data[1] & 0x1) == 0x1;
-               seq = skb->data[1] >> 1;
+
+       if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) {
+               test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
+               rnr = 1;
+       } else
+               test_and_clear_bit(FLG_PEER_BUSY, &l2->flag);
+       if (test_bit(FLG_MOD128, &l2->flag)) {
+               if (skb->len == 2) {
+                       PollFlag = (skb->data[1] & 0x1) == 0x1;
+                       nr = skb->data[1] >> 1;
+               } else {
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
        } else {
-               PollFlag = (skb->data[0] & 0x10);
-               seq = (skb->data[0] >> 5) & 0x7;
+               if (skb->len == 1) {
+                       PollFlag = (skb->data[0] & 0x10);
+                       nr = (skb->data[0] >> 5) & 0x7;
+               } else {
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
+       FreeSkb(skb);
 
        if (rsp && PollFlag) {
-               if (legalnr(st, seq)) {
+               if (legalnr(st, nr)) {
+                       setva(st, nr);
+                       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                               FsmDelTimer(&st->l2.t200, 7);
+                       FsmDelTimer(&l2->t203, 8);
+                       if (rnr) {
+                               FsmRestartTimer(&l2->t200, l2->T200,
+                                               EV_L2_T200, NULL, 14);
+                               test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
+                       } else
+                               FsmAddTimer(&l2->t203, l2->T203,
+                                           EV_L2_T203, NULL, 5);
+                       invoke_retransmission(st, nr);
                        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);
+                               st->l2.l2l1(st, PH_PULL_REQ, NULL);
                        else if (fi->userint & LC_FLUSH_WAIT) {
                                fi->userint &= ~LC_FLUSH_WAIT;
                                st->l2.l2man(st, DL_FLUSH, NULL);
@@ -969,36 +1220,13 @@ l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg)
                }
        } else {
                if (!rsp && PollFlag)
-                       enquiry_response(st, RR, PollFlag);
-               if (legalnr(st, seq)) {
-                       setva(st, seq);
+                       enquiry_response(st);
+               if (legalnr(st, nr)) {
+                       setva(st, nr);
                }
        }
 }
 
-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)
 {
@@ -1006,20 +1234,32 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
        struct sk_buff *skb = arg;
        char tmp[64];
 
-       skb_pull(skb, l2addrsize(&st->l2));
-       if (st->l2.l2m.debug) {
-               if (st->l2.extended)
+       skb_pull(skb, l2addrsize(&st->l2) + 1);
+       if (test_bit(FLG_MOD128, &st->l2.flag)) {
+               if (skb->len < 5)
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               else {
                        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
+                       l2m_debug(&st->l2.l2m, tmp);
+               }
+       } else {
+               if (skb->len < 3)
+                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+               else {
                        sprintf(tmp, "FRMR information %2x %2x %2x",
                                skb->data[0], skb->data[1], skb->data[2]);
-
-               l2m_debug(&st->l2.l2m, tmp);
+                       l2m_debug(&st->l2.l2m, tmp);
+               }
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb);
+       if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) ||         /* I or S */
+           (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) {
+               st->ma.layer(st, MDL_ERROR_IND, (void *) 'K');
+               establishlink(fi);
+               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+       }
+       FreeSkb(skb);
 }
 
 static void
@@ -1027,135 +1267,126 @@ 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 */
+       discard_i_queue(st);
+       discard_ui_queue(st);
+       st->l2.tei = -1;
+       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+               FsmDelTimer(&st->l2.t200, 18);
+       FsmDelTimer(&st->l2.t203, 19);
+       if (fi->state != ST_L2_4)
+               st->l2.l2man(st, DL_RELEASE, NULL);
        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)
+static void
+l2_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
-       u_char d = data[0] & ~0x10;
+       struct PStack *st = fi->userdata;
        
-       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);
+       discard_i_queue(st);
+       discard_ui_queue(st);
+       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+               FsmDelTimer(&st->l2.t200, 18);
+       FsmDelTimer(&st->l2.t203, 19);
+       test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+       clear_exception(&st->l2);
+       switch (fi->state) {
+               case ST_L2_3:
+                       st->l2.l2man(st, DL_RELEASE, NULL);
+               case ST_L2_2:
+                       FsmChangeState(fi, ST_L2_1);
+                       break;
+               case ST_L2_5:
+               case ST_L2_6:
+               case ST_L2_7:
+               case ST_L2_8:
+                       st->l2.l2man(st, DL_RELEASE, NULL);
+                       FsmChangeState(fi, ST_L2_4);
+                       break;
+       }
 }
 
-static struct FsmNode L2FnList[] =
+static struct FsmNode L2FnList[] HISAX_INITDATA =
 {
-       {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_1, EV_L2_DL_ESTABLISH, l2_dl_establish},
+       {ST_L2_2, EV_L2_DL_ESTABLISH, l2_dl_establish},
        {ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish},
-       {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
+       {ST_L2_5, EV_L2_DL_ESTABLISH, l2_establish},
+       {ST_L2_7, EV_L2_DL_ESTABLISH, l2_establish},
+       {ST_L2_8, EV_L2_DL_ESTABLISH, l2_establish},
+       {ST_L2_4, EV_L2_DL_RELEASE, l2_dl_release},
+       {ST_L2_5, EV_L2_DL_RELEASE, l2_dl_release},
+       {ST_L2_7, EV_L2_DL_RELEASE, l2_dl_release},
+       {ST_L2_8, EV_L2_DL_RELEASE, l2_dl_release},
+       {ST_L2_5, EV_L2_DL_DATA, l2_feed_iqueue},
        {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_1, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_put_ui},
+       {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei},
+       {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei},
+       {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+       {ST_L2_2, EV_L2_MDL_ERROR, l2_tei_remove},
+       {ST_L2_3, EV_L2_MDL_ERROR, 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},
        {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_5, EV_L2_SABMX, l2_got_SABMX},
+       {ST_L2_6, EV_L2_SABMX, l2_got_SABMX},
        {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_4, EV_L2_DISC, l2_got_disconn},
+       {ST_L2_5, EV_L2_DISC, l2_got_disconn},
+       {ST_L2_6, EV_L2_DISC, l2_got_disconn},
+       {ST_L2_7, EV_L2_DISC, l2_got_disconn},
        {ST_L2_8, EV_L2_DISC, l2_got_disconn},
+       {ST_L2_4, EV_L2_UA, l2_mdl_error},
+       {ST_L2_5, EV_L2_UA, l2_got_ua},
+       {ST_L2_6, EV_L2_UA, l2_got_ua},
+       {ST_L2_7, EV_L2_UA, l2_mdl_error},
+       {ST_L2_8, EV_L2_UA, l2_mdl_error},
+       {ST_L2_4, EV_L2_DM, l2_got_dm},
+       {ST_L2_5, EV_L2_DM, l2_got_dm},
+       {ST_L2_6, EV_L2_DM, l2_got_dm},
+       {ST_L2_7, EV_L2_DM, l2_mdl_error},
+       {ST_L2_8, EV_L2_DM, l2_mdl_error},
+       {ST_L2_1, EV_L2_UI, l2_got_ui},
+       {ST_L2_2, EV_L2_UI, l2_got_ui},
+       {ST_L2_3, EV_L2_UI, l2_got_ui},
+       {ST_L2_4, EV_L2_UI, l2_got_ui},
+       {ST_L2_5, EV_L2_UI, l2_got_ui},
+       {ST_L2_6, EV_L2_UI, l2_got_ui},
+       {ST_L2_7, EV_L2_UI, l2_got_ui},
+       {ST_L2_8, EV_L2_UI, l2_got_ui},
+       {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
        {ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
-       {ST_L2_8, EV_L2_I, l2_got_st8_data},
-
+       {ST_L2_7, EV_L2_SUPER, l2_got_st7_super},
+       {ST_L2_8, EV_L2_SUPER, l2_got_st8_super},
+       {ST_L2_7, EV_L2_I, l2_got_iframe},
+       {ST_L2_8, EV_L2_I, l2_got_iframe},
        {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_T200, l2_st78_tout_200},
+       {ST_L2_8, EV_L2_T200, l2_st78_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},
+       {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+       {ST_L2_2, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_3, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_4, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_5, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_6, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
+       {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
 };
 
 #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
@@ -1165,40 +1396,53 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
        u_char *datap;
-       int ret = !0;
+       int ret = 1, len;
 
        switch (pr) {
-               case (PH_DATA):
+               case (PH_DATA_IND):
                        datap = skb->data;
-                       datap += l2addrsize(&st->l2);
-
-                       if (IsI(datap, st->l2.extended))
+                       len = l2addrsize(&st->l2);
+                       if (skb->len > len)
+                               datap += len;
+                       else {
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                               FreeSkb(skb);
+                               return;
+                       }
+                       if (!(*datap & 1))      /* I-Frame */
                                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))
+                       else if ((*datap & 3) == 1)     /* S-Frame */
+                               ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb);
+                       else if (IsUI(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
-                       else if (IsSABMX(datap, st->l2.extended))
+                       else if (IsSABMX(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb);
-                       else if (IsUA(datap, st->l2.extended))
+                       else if (IsUA(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
-                       else if (IsDISC(datap, st->l2.extended))
+                       else if (IsDISC(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                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))
+                       else if (IsDM(datap, test_bit(FLG_MOD128, &st->l2.flag)))
+                               ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb);
+                       else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                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);
-
+                       else {
+                               ret = 0;
+                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+                               FreeSkb(skb);
+                       }
                        if (ret) {
-                               SET_SKB_FREE(skb);
-                               dev_kfree_skb(skb);
+                               FreeSkb(skb);
                        }
                        break;
-               case (PH_PULL_ACK):
+               case (PH_PULL_CNF):
                        FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
                        break;
+               case (PH_PAUSE_IND):
+                       test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+                       break;
+               case (PH_PAUSE_CNF):
+                       test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+                       break;
        }
 }
 
@@ -1208,13 +1452,11 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg)
        switch (pr) {
                case (DL_DATA):
                        if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
-                               SET_SKB_FREE(((struct sk_buff *) arg));
                                dev_kfree_skb((struct sk_buff *) arg);
                        }
                        break;
                case (DL_UNIT_DATA):
                        if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
-                               SET_SKB_FREE(((struct sk_buff *) arg));
                                dev_kfree_skb((struct sk_buff *) arg);
                        }
                        break;
@@ -1237,28 +1479,28 @@ isdnl2_manl2(struct PStack *st, int pr, void *arg)
                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):
+               case (PH_DEACTIVATE_IND):
+                       FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
+                       break;
+               case (MDL_ASSIGN_REQ):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
                        break;
-               case (MDL_REMOVE):
+               case (MDL_REMOVE_REQ):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
                        break;
+               case (MDL_ERROR_REQ):
+                       FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
+                       break;
        }
 }
 
 void
 releasestack_isdnl2(struct PStack *st)
 {
-       FsmDelTimer(&st->l2.t200_timer, 15);
-       FsmDelTimer(&st->l2.t203_timer, 16);
+       FsmDelTimer(&st->l2.t200, 15);
+       FsmDelTimer(&st->l2.t203, 16);
        discard_i_queue(st);
+       discard_ui_queue(st);
        ReleaseWin(&st->l2);
 }
 
@@ -1279,13 +1521,10 @@ 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);
+       skb_queue_head_init(&st->l2.ui_queue);
        InitWin(&st->l2);
-       st->l2.rejexp = 0;
        st->l2.debug = 0;
 
        st->l2.l2m.fsm = &l2fsm;
@@ -1296,9 +1535,8 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
        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;
+       FsmInitTimer(&st->l2.l2m, &st->l2.t200);
+       FsmInitTimer(&st->l2.l2m, &st->l2.t203);
 }
 
 void
@@ -1311,8 +1549,8 @@ releasestack_transl2(struct PStack *st)
 {
 }
 
-void
-Isdnl2New(void)
+HISAX_INITFUNC(void
+Isdnl2New(void))
 {
        l2fsm.state_count = L2_STATE_COUNT;
        l2fsm.event_count = L2_EVENT_COUNT;
index 73b66c73b6b2e54ef4efbd8e235b26af985e1ff4..026d8eb760f068e7a8bd1a35198d11b27d5cc3c0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+/* $Id: isdnl3.c,v 2.5 1998/02/12 23:07:52 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,38 +7,39 @@
  *              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 2.5  1998/02/12 23:07:52  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.8  1997/03/21 18:53:44  keil
- * Report no protocol error to syslog too
+ * Revision 2.4  1997/11/06 17:09:25  keil
+ * New 2.1 init code
  *
- * Revision 1.7  1997/03/17 18:34:38  keil
- * fixed oops if no protocol selected during config
+ * Revision 2.3  1997/10/29 19:07:53  keil
+ * changes for 2.1
  *
- * Revision 1.6  1997/02/16 01:04:08  fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
+ * Revision 2.2  1997/10/01 09:21:41  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
  *
- * Revision 1.5  1997/02/09 00:26:27  keil
- * new interface handling, one interface per card
- * leased line changes
+ * Revision 2.1  1997/08/03 14:36:32  keil
+ * Implement RESTART procedure
  *
- * Revision 1.4  1997/01/27 23:17:44  keil
- * delete timers while unloading
+ * Revision 2.0  1997/07/27 21:15:42  keil
+ * New Callref based layer3
  *
- * Revision 1.3  1997/01/21 22:31:12  keil
- * new statemachine; L3 timers
+ * Revision 1.11  1997/06/26 11:11:44  keil
+ * SET_SKBFREE now on creation of a SKB
  *
- * Revision 1.2  1996/11/05 19:42:04  keil
- * using config.h
+ * Revision 1.10  1997/04/06 22:54:16  keil
+ * Using SKB's
  *
- * Revision 1.1  1996/10/13 20:04:54  keil
- * Initial revision
+ * 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
  *
+ * Remove old logs /KKe
  *
  */
 #define __NO_VERSION__
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 1.10 $";
+const char *l3_revision = "$Revision: 2.5 $";
+
+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);
+}
+
+int
+getcallref(u_char * p)
+{
+       int l, m = 1, cr = 0;
+       p++;                    /* prot discr */
+       l = 0xf & *p++;         /* callref length */
+       if (!l)                 /* dummy CallRef */
+               return(-1);
+       while (l--) {
+               cr += m * (*p++);
+               m *= 8;
+       }
+       return (cr);
+}
+
+static int OrigCallRef = 0;
+
+int
+newcallref(void)
+{
+       if (OrigCallRef == 127)
+               OrigCallRef = 1;
+       else
+               OrigCallRef++;
+       return (OrigCallRef);
+}
 
 void
 l3_debug(struct PStack *st, char *s)
@@ -54,34 +120,33 @@ 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);
+       sprintf(str, "%s l3 %s\n", tm, s);
        HiSax_putstatus(st->l1.hardware, str);
 }
 
-
-
 void
-newl3state(struct PStack *st, int state)
+newl3state(struct l3_process *pc, 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);
+       if (pc->debug & L3_DEB_STATE) {
+               sprintf(tmp, "newstate cr %d %d --> %d", pc->callref,
+                       pc->state, state);
+               l3_debug(pc->st, tmp);
        }
-       st->l3.state = state;
+       pc->state = state;
 }
 
 static void
 L3ExpireTimer(struct L3Timer *t)
 {
-       t->st->l4.l4l3(t->st, t->event, NULL);
+       t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
 }
 
 void
-L3InitTimer(struct PStack *st, struct L3Timer *t)
+L3InitTimer(struct l3_process *pc, struct L3Timer *t)
 {
-       t->st = st;
+       t->pc = pc;
        t->tl.function = (void *) L3ExpireTimer;
        t->tl.data = (long) t;
        init_timer(&t->tl);
@@ -109,9 +174,9 @@ L3AddTimer(struct L3Timer *t,
 }
 
 void
-StopAllL3Timer(struct PStack *st)
+StopAllL3Timer(struct l3_process *pc)
 {
-       L3DelTimer(&st->l3.timer);
+       L3DelTimer(&pc->timer);
 }
 
 struct sk_buff *
@@ -132,9 +197,8 @@ no_l3_proto(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       l3_debug(st, "no protocol");
+       HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n");
        if (skb) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
        }
 }
@@ -151,14 +215,78 @@ extern void setstack_ni1(struct PStack *st);
 extern void setstack_1tr6(struct PStack *st);
 #endif
 
+struct l3_process
+*getl3proc(struct PStack *st, int cr)
+{
+       struct l3_process *p = st->l3.proc;
+
+       while (p)
+               if (p->callref == cr)
+                       return (p);
+               else
+                       p = p->next;
+       return (NULL);
+}
+
+struct l3_process
+*new_l3_process(struct PStack *st, int cr)
+{
+       struct l3_process *p, *np;
+
+       if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+               printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
+               return (NULL);
+       }
+       if (!st->l3.proc)
+               st->l3.proc = p;
+       else {
+               np = st->l3.proc;
+               while (np->next)
+                       np = np->next;
+               np->next = p;
+       }
+       p->next = NULL;
+       p->debug = L3_DEB_WARN;
+       p->callref = cr;
+       p->state = 0;
+       p->chan = NULL;
+       p->st = st;
+       p->N303 = st->l3.N303;
+       L3InitTimer(p, &p->timer);
+       return (p);
+};
+
+void
+release_l3_process(struct l3_process *p)
+{
+       struct l3_process *np, *pp = NULL;
+
+       if (!p)
+               return;
+       np = p->st->l3.proc;
+       while (np) {
+               if (np == p) {
+                       StopAllL3Timer(p);
+                       if (pp)
+                               pp->next = np->next;
+                       else
+                               p->st->l3.proc = np->next;
+                       kfree(p);
+                       return;
+               }
+               pp = np;
+               np = np->next;
+       }
+       printk(KERN_ERR "HiSax internal L3 error CR not in list\n");
+};
+
 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);
+       st->l3.proc   = NULL;
+       st->l3.global = NULL;
 
 #ifdef CONFIG_HISAX_EURO
        if (st->protocol == ISDN_PTYPE_EURO) {
@@ -176,11 +304,11 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp)
        } else
 #endif
        if (st->protocol == ISDN_PTYPE_LEASED) {
-               st->l4.l4l3 = no_l3_proto;
+               st->lli.l4l3 = no_l3_proto;
                st->l2.l2l3 = no_l3_proto;
-               printk(KERN_NOTICE "HiSax: Leased line mode\n");
+               printk(KERN_INFO "HiSax: Leased line mode\n");
        } else {
-               st->l4.l4l3 = no_l3_proto;
+               st->lli.l4l3 = no_l3_proto;
                st->l2.l2l3 = no_l3_proto;
                sprintf(tmp, "protocol %s not supported",
                        (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
@@ -188,15 +316,18 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp)
                        (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);
+       while (st->l3.proc)
+               release_l3_process(st->l3.proc);
+       if (st->l3.global) {
+               StopAllL3Timer(st->l3.global);
+               kfree(st->l3.global);
+               st->l3.global = NULL;
+       }
 }
index bed989a18613091a13fff3dad33087b31c5c6227..2ff582b4a4dc7f2b45b2d2c7beb9447e50e2cd09 100644 (file)
@@ -1,6 +1,12 @@
-/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $
- *
+/* $Id: isdnl3.h,v 2.0 1997/07/27 21:15:42 keil Exp $
+
  * $Log: isdnl3.h,v $
+ * Revision 2.0  1997/07/27 21:15:42  keil
+ * New Callref based layer3
+ *
+ * Revision 1.4  1997/06/26 11:20:57  keil
+ * ?
+ *
  * Revision 1.3  1997/04/06 22:54:17  keil
  * Using SKB's
  *
 #define        L3_DEB_CHARGE   0x08
 
 struct stateentry {
-       int     state;
-       u_char  primitive;
-       void    (*rout) (struct PStack *, u_char, void *);
+       int state;
+       u_char primitive;
+       void (*rout) (struct l3_process *, 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 newl3state(struct l3_process *pc, int state);
+extern void L3InitTimer(struct l3_process *pc, 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 int L3AddTimer(struct L3Timer *t, int millisec, int event);
+extern void StopAllL3Timer(struct l3_process *pc);
 extern struct sk_buff *l3_alloc_skb(int len);
+extern struct l3_process *new_l3_process(struct PStack *st, int cr);
+extern void release_l3_process(struct l3_process *p);
+extern struct l3_process *getl3proc(struct PStack *st, int cr);
index f5f5e857a0a0f3d7551daa1ddea5c90ed7df2fb3..0c075546b4220cd98c2eacad8cb7a9c4eb81dadd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 1.3 1997/04/13 19:54:02 keil Exp $
+/* $Id: ix1_micro.c,v 2.6 1998/02/11 17:28:09 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
  *              Beat Doebeli
  *
  * $Log: ix1_micro.c,v $
+ * Revision 2.6  1998/02/11 17:28:09  keil
+ * Niccy PnP/PCI support
+ *
+ * Revision 2.5  1998/02/02 13:29:42  keil
+ * fast io
+ *
+ * Revision 2.4  1997/11/08 21:35:50  keil
+ * new l1 init
+ *
+ * Revision 2.3  1997/11/06 17:09:35  keil
+ * New 2.1 init code
+ *
+ * Revision 2.2  1997/10/29 18:55:51  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1  1997/07/27 21:47:09  keil
+ * new interface structures
+ *
+ * Revision 2.0  1997/06/26 11:02:50  keil
+ * New Layer and card interface
+ *
  * Revision 1.3  1997/04/13 19:54:02  keil
  * Change in IRQ check delay for SMP
  *
 
 
 #define __NO_VERSION__
-#include "siemens.h"
 #include "hisax.h"
-#include "teles3.h"
+#include "isac.h"
+#include "hscx.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 1.3 $";
+const char *ix1_revision = "$Revision: 2.6 $";
 
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
 
 #define SPECIAL_PORT_OFFSET 3
 
@@ -73,865 +93,250 @@ const char *ix1_revision = "$Revision: 1.3 $";
 #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)
+readreg(unsigned int ale, unsigned int adr, 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);
-}
+       register u_char ret;
+       long flags;
 
-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++;
-       }
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
 }
 
 static inline void
-waitforCEC(int adr, int WhichHscx)
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-       int to = TIMEOUT;
+       /* fifo read without cli because it's allready done  */
 
-       while ((HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x04) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "ix1-Micro: waitforCEC timeout\n");
+       byteout(ale, off);
+       insb(adr, data, size);
 }
 
 
 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)
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
 {
        long flags;
 
        save_flags(flags);
        cli();
-       waitforCEC(adr, WhichHscx);
-       HscxWriteReg(adr, WhichHscx, HSCX_CMDR, data);
+       byteout(ale, off);
+       byteout(adr, 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)
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
-       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);
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
 }
 
-/*
- * HSCX stuff goes here
- */
+/* Interface functions */
 
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       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);
-       }
+       return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
 }
 
 static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       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);
-       }
+       writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
 }
 
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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 {
-                               SET_SKB_FREE(hsp->tx_skb);
-                               dev_kfree_skb(hsp->tx_skb);
-                               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);
-       }
+       readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
 }
 
-/*
- * ISAC stuff goes here
- */
-
 static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
 }
 
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       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);
-       }
+       return (readreg(cs->hw.ix1.hscx_ale,
+                       cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
 static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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);
+       writereg(cs->hw.ix1.hscx_ale,
+                cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
+#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
+               cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
+               cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
 
-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 {
-                                       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 {
-                               SET_SKB_FREE(sp->tx_skb);
-                               dev_kfree_skb(sp->tx_skb);
-                               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);
-               }
-       }
-}
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
+               cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
+               cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-       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);
-       }
-}
+#include "hscx_irq.c"
 
 static void
 ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs = dev_id;
        u_char val, stat = 0;
 
-       sp = (struct IsdnCardState *) dev_id;
-
-       if (!sp) {
-               printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+       if (!cs) {
+               printk(KERN_WARNING "IX1: Spurious interrupt!\n");
                return;
        }
-       val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+       val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
       Start_HSCX:
        if (val) {
-               hscx_int_main(sp, val);
+               hscx_int_main(cs, val);
                stat |= 1;
        }
-       val = IsacReadReg(sp->isac, ISAC_ISTA);
+       val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
       Start_ISAC:
        if (val) {
-               isac_interrupt(sp, val);
+               isac_interrupt(cs, val);
                stat |= 2;
        }
-       val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+       val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
        if (val) {
-               if (sp->debug & L1_DEB_HSCX)
-                       debugl1(sp, "HSCX IntStat after IntRoutine");
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
                goto Start_HSCX;
        }
-       val = IsacReadReg(sp->isac, ISAC_ISTA);
+       val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
        if (val) {
-               if (sp->debug & L1_DEB_ISAC)
-                       debugl1(sp, "ISAC IntStat after IntRoutine");
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "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);
+               writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
+               writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
        }
        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);
+               writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
        }
-       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)
+release_io_ix1micro(struct IsdnCardState *cs)
 {
-       if (card->sp->cfg_reg)
-               release_region(card->sp->cfg_reg, 4);
+       if (cs->hw.ix1.cfg_reg)
+               release_region(cs->hw.ix1.cfg_reg, 4);
 }
 
 static void
-clear_pending_ints(struct IsdnCardState *sp)
+ix1_reset(struct IsdnCardState *cs)
 {
-       int val;
-       char tmp[64];
+       long flags;
+       int cnt;
 
-       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);
+       /* reset isac */
+       save_flags(flags);
+       cnt = 3 * (HZ / 10) + 1;
+       sti();
+       while (cnt--) {
+               byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
+               HZDELAY(1);     /* wait >=10 ms */
        }
-       IsacWriteReg(sp->isac, ISAC_MASK, 0);
-       IsacWriteReg(sp->isac, ISAC_CMDR, 0x41);
+       byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
+       restore_flags(flags);
 }
 
-int
-initix1micro(struct IsdnCardState *sp)
+static int
+ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-       int ret;
-       int loop = 0;
-       char tmp[40];
-
-       sp->counter = kstat_irqs(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_irqs(sp->irq) > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat_irqs(sp->irq));
-               debugl1(sp, tmp);
-               if (kstat_irqs(sp->irq) == sp->counter) {
-                       printk(KERN_WARNING
-                              "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       free_irq(sp->irq, sp);
-                       return (0);
-               }
-       }
-       return (ret);
+       switch (mt) {
+               case CARD_RESET:
+                       ix1_reset(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_ix1micro(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &ix1micro_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
 }
 
-int
-setup_ix1micro(struct IsdnCard *card)
+
+__initfunc(int
+setup_ix1micro(struct IsdnCard *card))
 {
-       u_char val, verA, verB;
-       struct IsdnCardState *sp = card->sp;
-       long flags;
+       struct IsdnCardState *cs = card->cs;
        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)
+       printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->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)) {
+       cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
+       cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
+       cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
+       cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
+       cs->hw.ix1.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+       if (cs->hw.ix1.cfg_reg) {
+               if (check_region((cs->hw.ix1.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);
+                              cs->hw.ix1.cfg_reg,
+                              cs->hw.ix1.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)) {
+                       request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg");
+       }
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d io:0x%X\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.ix1.cfg_reg);
+       ix1_reset(cs);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &ix1_card_msg;
+       ISACVersion(cs, "ix1-Micro:");
+       if (HscxVersion(cs, "ix1-Micro:")) {
                printk(KERN_WARNING
                    "ix1-Micro: wrong HSCX versions check IO address\n");
-               release_io_ix1micro(card);
+               release_io_ix1micro(cs);
                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
deleted file mode 100644 (file)
index b180097..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* $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);
index c3ee6a73fa5ba1c439b72a3bd0b2697100466f5a..d60a5da66b809eeeeb22d81de15e40443f06c19c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: l3_1tr6.c,v 1.11 1997/04/06 22:54:18 keil Exp $
+/* $Id: l3_1tr6.c,v 2.4 1998/02/12 23:07:57 keil Exp $
 
  *  German 1TR6 D-channel protocol
  *
@@ -6,39 +6,28 @@
  *
  *
  * $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 2.4  1998/02/12 23:07:57  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.6  1996/12/14 21:07:20  keil
- * additional states for CC_REJECT
+ * Revision 2.3  1997/11/06 17:12:24  keil
+ * KERN_NOTICE --> KERN_INFO
  *
- * Revision 1.5  1996/12/08 19:55:17  keil
- * change CC_REJECT_REQ routine
+ * Revision 2.2  1997/10/29 19:03:00  keil
+ * changes for 2.1
  *
- * Revision 1.4  1996/10/30 10:18:01  keil
- * bugfixes in debugging output
+ * Revision 2.1  1997/08/03 15:28:09  keil
+ * release L3 empty processes
  *
- * Revision 1.3  1996/10/27 22:15:37  keil
- * bugfix reject handling
+ * Revision 2.0  1997/07/27 21:15:45  keil
+ * New Callref based layer3
  *
- * Revision 1.2  1996/10/13 23:08:56  keil
- * added missing state for callback reject
+ * Revision 1.12  1997/06/26 11:11:45  keil
+ * SET_SKBFREE now on creation of a SKB
  *
- * Revision 1.1  1996/10/13 20:04:55  keil
- * Initial revision
+ * Revision 1.11  1997/04/06 22:54:18  keil
+ * Using SKB's
  *
+ * Old Log removed /KKe
  *
  */
 
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 1.11 $";
+const char *l3_1tr6_revision = "$Revision: 2.4 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
        *ptr++ = dis; \
        *ptr++ = 0x1; \
-       *ptr++ = cref; \
+       *ptr++ = cref ^ 0x80; \
        *ptr++ = mty
 
 static void
-l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
+l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
 {
        struct sk_buff *skb;
        u_char *p;
@@ -66,12 +55,71 @@ l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
        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);
+       MsgHead(p, pc->callref, mt, pd);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+}
+
+static int
+l31tr6_check_messagetype_validity(int mt, int pd) {
+/* verify if a message type exists */
+
+       if (pd == PROTO_DIS_N0)
+               switch(mt) {
+                  case MT_N0_REG_IND:
+                  case MT_N0_CANC_IND:
+                  case MT_N0_FAC_STA:
+                  case MT_N0_STA_ACK:
+                  case MT_N0_STA_REJ:
+                  case MT_N0_FAC_INF:
+                  case MT_N0_INF_ACK:
+                  case MT_N0_INF_REJ:
+                  case MT_N0_CLOSE:
+                  case MT_N0_CLO_ACK:
+                       return(1);
+                  default:
+                       return(0);
+               }
+       else if (pd == PROTO_DIS_N1)
+               switch(mt) {
+                  case MT_N1_ESC:
+                  case MT_N1_ALERT:
+                  case MT_N1_CALL_SENT:
+                  case MT_N1_CONN:
+                  case MT_N1_CONN_ACK:
+                  case MT_N1_SETUP:
+                  case MT_N1_SETUP_ACK:
+                  case MT_N1_RES:
+                  case MT_N1_RES_ACK:
+                  case MT_N1_RES_REJ:
+                  case MT_N1_SUSP:
+                  case MT_N1_SUSP_ACK:
+                  case MT_N1_SUSP_REJ:
+                  case MT_N1_USER_INFO:
+                  case MT_N1_DET:
+                  case MT_N1_DISC:
+                  case MT_N1_REL:
+                  case MT_N1_REL_ACK:
+                  case MT_N1_CANC_ACK:
+                  case MT_N1_CANC_REJ:
+                  case MT_N1_CON_CON:
+                  case MT_N1_FAC:
+                  case MT_N1_FAC_ACK:
+                  case MT_N1_FAC_CAN:
+                  case MT_N1_FAC_REG:
+                  case MT_N1_FAC_REJ:
+                  case MT_N1_INFO:
+                  case MT_N1_REG_ACK:
+                  case MT_N1_REG_REJ:
+                  case MT_N1_STAT:
+                       return (1);
+                  default:
+                       return(0);
+               }
+       return(0);
 }
 
 static void
-l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[128];
@@ -81,16 +129,13 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
        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;
+       MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
+       teln = pc->para.setup.phone;
+       pc->para.spv = 0;
        if (!isdigit(*teln)) {
                switch (0x5f & *teln) {
                        case 'S':
-                               st->pa->spv = 1;
+                               pc->para.spv = 1;
                                break;
                        case 'C':
                                channel = 0x08;
@@ -103,8 +148,8 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
                                        channel |= 0x02;
                                break;
                        default:
-                               if (st->l3.debug & L3_DEB_WARN)
-                                       l3_debug(st, "Wrong MSN Code");
+                               if (pc->st->l3.debug & L3_DEB_WARN)
+                                       l3_debug(pc->st, "Wrong MSN Code");
                                break;
                }
                teln++;
@@ -114,22 +159,22 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
                *p++ = 1;
                *p++ = channel;
        }
-       if (st->pa->spv) {      /* SPV ? */
+       if (pc->para.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++ = pc->para.setup.si1;      /* 0 for all Services */
+               *p++ = pc->para.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 */
+               *p++ = pc->para.setup.si1;      /* 0 for all Services */
+               *p++ = pc->para.setup.si2;      /* 0 for all Services */
        }
-       eaz = st->pa->setup.eazmsn;
+       eaz = pc->para.setup.eazmsn;
        if (*eaz) {
                *p++ = WE0_origAddr;
                *p++ = strlen(eaz) + 1;
@@ -149,22 +194,21 @@ l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
        /* Codesatz 6 fuer Service */
        *p++ = WE6_serviceInd;
        *p++ = 2;               /* len=2 info,info2 */
-       *p++ = st->pa->setup.si1;
-       *p++ = st->pa->setup.si2;
+       *p++ = pc->para.setup.si1;
+       *p++ = pc->para.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);
-
+       L3DelTimer(&pc->timer);
+       L3AddTimer(&pc->timer, T303, CC_T303);
+       newl3state(pc, 1);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
 }
 
 static void
-l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        int bcfound = 0;
@@ -172,110 +216,105 @@ l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
        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;
+               pc->para.bchannel = p[2] & 0x3;
                bcfound++;
-       } else if (st->l3.debug & L3_DEB_WARN)
-               l3_debug(st, "setup without bchannel");
+       } else if (pc->st->l3.debug & L3_DEB_WARN)
+               l3_debug(pc->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");
+               pc->para.setup.si1 = p[2];
+               pc->para.setup.si2 = p[3];
+       } else if (pc->st->l3.debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup without service indicator");
 
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_destAddr, 0)))
-               iecpy(st->pa->setup.eazmsn, p, 1);
+               iecpy(pc->para.setup.eazmsn, p, 1);
        else
-               st->pa->setup.eazmsn[0] = 0;
+               pc->para.setup.eazmsn[0] = 0;
 
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
-               iecpy(st->pa->setup.phone, p, 1);
+               iecpy(pc->para.setup.phone, p, 1);
        } else
-               st->pa->setup.phone[0] = 0;
+               pc->para.setup.phone[0] = 0;
 
        p = skb->data;
-       st->pa->spv = 0;
+       pc->para.spv = 0;
        if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
                if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
-                       st->pa->spv = 1;
+                       pc->para.spv = 1;
        }
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
 
        /* Signal all services, linklevel takes care of Service-Indicator */
        if (bcfound) {
-               if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+               if ((pc->para.setup.si1 != 7) && (pc->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);
+                               pc->para.setup.phone,
+                               pc->para.setup.eazmsn);
+                       l3_debug(pc->st, tmp);
                }
-               newl3state(st, 6);
-               st->l3.l3l4(st, CC_SETUP_IND, NULL);
-       }
+               newl3state(pc, 6);
+               pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL);
+       } else
+               release_l3_process(pc);
 }
 
 static void
-l3_1tr6_setup_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
 
-       L3DelTimer(&st->l3.timer);
+       L3DelTimer(&pc->timer);
        p = skb->data;
-       newl3state(st, 2);
+       newl3state(pc, 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);
+               pc->para.bchannel = p[2] & 0x3;
+       } else if (pc->st->l3.debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup answer without bchannel");
        dev_kfree_skb(skb);
-       L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
-       st->l3.l3l4(st, CC_MORE_INFO, NULL);
+       L3AddTimer(&pc->timer, T304, CC_T304);
+       pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
 }
 
 static void
-l3_1tr6_call_sent(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
 
-       L3DelTimer(&st->l3.timer);
+       L3DelTimer(&pc->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);
+               pc->para.bchannel = p[2] & 0x3;
+       } else if (pc->st->l3.debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup answer without bchannel");
        dev_kfree_skb(skb);
-       L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
-       newl3state(st, 3);
-       st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+       L3AddTimer(&pc->timer, T310, CC_T310);
+       newl3state(pc, 3);
+       pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
 }
 
 static void
-l3_1tr6_alert(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       L3DelTimer(&st->l3.timer);      /* T304 */
-       newl3state(st, 4);
-       st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+       L3DelTimer(&pc->timer); /* T304 */
+       newl3state(pc, 4);
+       pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
 }
 
 static void
-l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        int i, tmpcharge = 0;
@@ -289,45 +328,42 @@ l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
                        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 (tmpcharge > pc->para.chargeinfo) {
+                       pc->para.chargeinfo = tmpcharge;
+                       pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
                }
-               if (st->l3.debug & L3_DEB_CHARGE) {
-                       sprintf(tmp, "charging info %d", st->pa->chargeinfo);
-                       l3_debug(st, tmp);
+               if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                       sprintf(tmp, "charging info %d", pc->para.chargeinfo);
+                       l3_debug(pc->st, tmp);
                }
-       } else if (st->l3.debug & L3_DEB_CHARGE)
-               l3_debug(st, "charging info not found");
-       SET_SKB_FREE(skb);
+       } else if (pc->st->l3.debug & L3_DEB_CHARGE)
+               l3_debug(pc->st, "charging info not found");
        dev_kfree_skb(skb);
 
 }
 
 static void
-l3_1tr6_info_s2(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
 }
 
 static void
-l3_1tr6_connect(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       L3DelTimer(&st->l3.timer);      /* T310 */
-       newl3state(st, 10);
-       SET_SKB_FREE(skb);
+       L3DelTimer(&pc->timer); /* T310 */
+       newl3state(pc, 10);
        dev_kfree_skb(skb);
-       st->pa->chargeinfo = 0;
-       st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+       pc->para.chargeinfo = 0;
+       pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
 }
 
 static void
-l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
        u_char *p;
@@ -335,47 +371,47 @@ l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_cause, 0))) {
                if (p[1] > 0) {
-                       st->pa->cause = p[2];
+                       pc->para.cause = p[2];
                        if (p[1] > 1)
-                               st->pa->loc = p[3];
+                               pc->para.loc = p[3];
                        else
-                               st->pa->loc = 0;
+                               pc->para.loc = 0;
                } else {
-                       st->pa->cause = 0;
-                       st->pa->loc = 0;
+                       pc->para.cause = 0;
+                       pc->para.loc = 0;
                }
        } else
-               st->pa->cause = -1;
-       SET_SKB_FREE(skb);
+               pc->para.cause = -1;
        dev_kfree_skb(skb);
-       StopAllL3Timer(st);
-       newl3state(st, 0);
-       l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
-       st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+       StopAllL3Timer(pc);
+       newl3state(pc, 0);
+       l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
+       pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+       release_l3_process(pc);
 }
 
 static void
-l3_1tr6_rel_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       StopAllL3Timer(st);
-       newl3state(st, 0);
-       st->pa->cause = -1;
-       st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+       StopAllL3Timer(pc);
+       newl3state(pc, 0);
+       pc->para.cause = -1;
+       pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+       release_l3_process(pc);
 }
 
 static void
-l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_disc(struct l3_process *pc, 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);
+       StopAllL3Timer(pc);
        p = skb->data;
        if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
                iecpy(a_charge, p, 1);
@@ -383,104 +419,102 @@ l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
                        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 (tmpcharge > pc->para.chargeinfo) {
+                       pc->para.chargeinfo = tmpcharge;
+                       pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
                }
-               if (st->l3.debug & L3_DEB_CHARGE) {
-                       sprintf(tmp, "charging info %d", st->pa->chargeinfo);
-                       l3_debug(st, tmp);
+               if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                       sprintf(tmp, "charging info %d", pc->para.chargeinfo);
+                       l3_debug(pc->st, tmp);
                }
-       } else if (st->l3.debug & L3_DEB_CHARGE)
-               l3_debug(st, "charging info not found");
+       } else if (pc->st->l3.debug & L3_DEB_CHARGE)
+               l3_debug(pc->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];
+                       pc->para.cause = p[2];
                        if (p[1] > 1)
-                               st->pa->loc = p[3];
+                               pc->para.loc = p[3];
                        else
-                               st->pa->loc = 0;
+                               pc->para.loc = 0;
                } else {
-                       st->pa->cause = 0;
-                       st->pa->loc = 0;
+                       pc->para.cause = 0;
+                       pc->para.loc = 0;
                }
        } else {
-               if (st->l3.debug & L3_DEB_WARN)
-                       l3_debug(st, "cause not found");
-               st->pa->cause = -1;
+               if (pc->st->l3.debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "cause not found");
+               pc->para.cause = -1;
        }
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       newl3state(st, 12);
-       st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+       newl3state(pc, 12);
+       pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
 }
 
 
 static void
-l3_1tr6_connect_ack(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       newl3state(st, 10);
-       st->pa->chargeinfo = 0;
-       L3DelTimer(&st->l3.timer);
-       st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+       newl3state(pc, 10);
+       pc->para.chargeinfo = 0;
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
 }
 
 static void
-l3_1tr6_alert_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
 {
-       newl3state(st, 7);
-       l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
+       newl3state(pc, 7);
+       l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
 }
 
 static void
-l3_1tr6_setup_rsp(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_setup_rsp(struct l3_process *pc, 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 ? */
+       MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
+       if (pc->para.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++ = pc->para.setup.si1;
+               *p++ = pc->para.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;
+               *p++ = pc->para.setup.si1;
+               *p++ = pc->para.setup.si2;
        }
-       newl3state(st, 8);
+       newl3state(pc, 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);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       L3DelTimer(&pc->timer);
+       L3AddTimer(&pc->timer, T313, CC_T313);
 }
 
 static void
-l3_1tr6_reset(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
 {
-       newl3state(st, 0);
+       release_l3_process(pc);
 }
 
 static void
-l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[16];
@@ -489,8 +523,8 @@ l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
        u_char cause = 0x10;
        u_char clen = 1;
 
-       if (st->pa->cause > 0)
-               cause = st->pa->cause;
+       if (pc->para.cause > 0)
+               cause = pc->para.cause;
        /* Map DSS1 causes */
        switch (cause & 0x7f) {
                case 0x10:
@@ -500,57 +534,55 @@ l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
                        cause = CAUSE_CallRejected;
                        break;
        }
-       StopAllL3Timer(st);
-       MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
+       StopAllL3Timer(pc);
+       MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
        *p++ = WE0_cause;
        *p++ = clen;            /* Laenge */
        if (clen)
                *p++ = cause | 0x80;
-       newl3state(st, 11);
+       newl3state(pc, 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);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       L3AddTimer(&pc->timer, T305, CC_T305);
 }
 
 static void
-l3_1tr6_release_req(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_release_req(struct l3_process *pc, 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);
+       StopAllL3Timer(pc);
+       newl3state(pc, 19);
+       l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
+       L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3_1tr6_t303(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t303(struct l3_process *pc, 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);
+       if (pc->N303 > 0) {
+               pc->N303--;
+               L3DelTimer(&pc->timer);
+               l3_1tr6_setup_req(pc, pr, arg);
        } else {
-               L3DelTimer(&st->l3.timer);
-               st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
-               st->l3.n_t303 = 1;
-               newl3state(st, 0);
+               L3DelTimer(&pc->timer);
+               pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
+               release_l3_process(pc);
        }
 }
 
 static void
-l3_1tr6_t304(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t304(struct l3_process *pc, 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);
-
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3_1tr6_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
 }
 
 static void
-l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[16];
@@ -559,9 +591,9 @@ l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
        u_char cause = 0x90;
        u_char clen = 1;
 
-       L3DelTimer(&st->l3.timer);
-       if (st->pa->cause > 0)
-               cause = st->pa->cause;
+       L3DelTimer(&pc->timer);
+       if (pc->para.cause > 0)
+               cause = pc->para.cause;
        /* Map DSS1 causes */
        switch (cause & 0x7f) {
                case 0x10:
@@ -571,53 +603,53 @@ l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
                        cause = CAUSE_CallRejected;
                        break;
        }
-       MsgHead(p, st->l3.callref, MT_N1_REL, PROTO_DIS_N1);
+       MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
        *p++ = WE0_cause;
        *p++ = clen;            /* Laenge */
        if (clen)
                *p++ = cause;
-       newl3state(st, 19);
+       newl3state(pc, 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);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3_1tr6_t310(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t310(struct l3_process *pc, 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);
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3_1tr6_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
 }
 
 static void
-l3_1tr6_t313(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t313(struct l3_process *pc, 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);
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3_1tr6_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
 }
 
 static void
-l3_1tr6_t308_1(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t308_1(struct l3_process *pc, 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);
+       L3DelTimer(&pc->timer);
+       l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
+       L3AddTimer(&pc->timer, T308, CC_T308_2);
+       newl3state(pc, 19);
 }
 
 static void
-l3_1tr6_t308_2(struct PStack *st, u_char pr, void *arg)
+l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
-       L3DelTimer(&st->l3.timer);
-       st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
-       newl3state(st, 0);
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+       release_l3_process(pc);
 }
 /* *INDENT-OFF* */
 static struct stateentry downstl[] =
@@ -688,49 +720,79 @@ static struct stateentry datastln1[] =
 
 
 
+
 static int datastln1_len = sizeof(datastln1) /
 sizeof(struct stateentry);
 
 static void
 up1tr6(struct PStack *st, int pr, void *arg)
 {
-       int i, mt;
+       int i, mt, cr;
+       struct l3_process *proc;
        struct sk_buff *skb = arg;
        char tmp[80];
 
+       if (skb->len < 4) {
+               if (st->l3.debug & L3_DEB_PROTERR) {
+                       sprintf(tmp, "up1tr6 len only %d", skb->len);
+                       l3_debug(st, tmp);
+               }
+               dev_kfree_skb(skb);
+               return;
+       }
        if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d",
+                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
                                (pr == DL_DATA) ? " " : "(broadcast) ",
-                               skb->data[0], skb->len, st->l3.state);
+                               skb->data[0], skb->len);
+                       l3_debug(st, tmp);
+               }
+               dev_kfree_skb(skb);
+               return;
+       }
+       if (skb->data[1] != 1) {
+               if (st->l3.debug & L3_DEB_PROTERR) {
+                       sprintf(tmp, "up1tr6 CR len not 1");
                        l3_debug(st, tmp);
                }
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                return;
        }
-       mt = skb->data[skb->data[1] + 2];
+       cr = skb->data[2];
+       mt = skb->data[3];
        if (skb->data[0] == PROTO_DIS_N0) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                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);
+                       sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
+                            (pr == DL_DATA) ? " " : "(broadcast) ", mt);
                        l3_debug(st, tmp);
                }
        } else if (skb->data[0] == PROTO_DIS_N1) {
+               if (!(proc = getl3proc(st, cr))) {
+                       if ((mt == MT_N1_SETUP) && (cr < 128)) {
+                               if (!(proc = new_l3_process(st, cr))) {
+                                       if (st->l3.debug & L3_DEB_PROTERR) {
+                                               sprintf(tmp, "up1tr6 no roc mem");
+                                               l3_debug(st, tmp);
+                                       }
+                                       dev_kfree_skb(skb);
+                                       return;
+                               }
+                       } else {
+                               dev_kfree_skb(skb);
+                               return;
+                       }
+               }
                for (i = 0; i < datastln1_len; i++)
                        if ((mt == datastln1[i].primitive) &&
-                           ((1 << st->l3.state) & datastln1[i].state))
+                           ((1 << proc->state) & datastln1[i].state))
                                break;
                if (i == datastln1_len) {
-                       SET_SKB_FREE(skb);
                        dev_kfree_skb(skb);
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
                                  (pr == DL_DATA) ? " " : "(broadcast) ",
-                                       st->l3.state, mt);
+                                       proc->state, mt);
                                l3_debug(st, tmp);
                        }
                        return;
@@ -738,10 +800,10 @@ up1tr6(struct PStack *st, int pr, void *arg)
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x",
                                  (pr == DL_DATA) ? " " : "(broadcast) ",
-                                       st->l3.state, mt);
+                                       proc->state, mt);
                                l3_debug(st, tmp);
                        }
-                       datastln1[i].rout(st, pr, skb);
+                       datastln1[i].rout(proc, pr, skb);
                }
        }
 }
@@ -749,26 +811,44 @@ up1tr6(struct PStack *st, int pr, void *arg)
 static void
 down1tr6(struct PStack *st, int pr, void *arg)
 {
-       int i;
+       int i, cr;
+       struct l3_process *proc;
+       struct Channel *chan;
        char tmp[80];
 
+       if (CC_SETUP_REQ == pr) {
+               chan = arg;
+               cr = newcallref();
+               cr |= 0x80;
+               if (!(proc = new_l3_process(st, cr))) {
+                       return;
+               } else {
+                       proc->chan = chan;
+                       chan->proc = proc;
+                       proc->para.setup = chan->setup;
+                       proc->callref = cr;
+               }
+       } else {
+               proc = arg;
+       }
+
        for (i = 0; i < downstl_len; i++)
                if ((pr == downstl[i].primitive) &&
-                   ((1 << st->l3.state) & downstl[i].state))
+                   ((1 << proc->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);
+                               proc->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);
+                               proc->state, pr);
                        l3_debug(st, tmp);
                }
-               downstl[i].rout(st, pr, arg);
+               downstl[i].rout(proc, pr, arg);
        }
 }
 
@@ -777,20 +857,10 @@ setstack_1tr6(struct PStack *st)
 {
        char tmp[64];
 
-       st->l4.l4l3 = down1tr6;
+       st->lli.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));
-       }
+       st->l3.N303 = 0;
+
+       strcpy(tmp, l3_1tr6_revision);
+       printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
 }
index 6e2fee72f4b5f51b8e68f342c7ad4459f57f57a6..90d08793e3ddf0e468f735ea80b5110b285567e2 100644 (file)
@@ -1,13 +1,14 @@
-/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+/* $Id: l3_1tr6.h,v 2.0 1997/07/27 21:15:47 keil Exp $
  *
  *  German 1TR6 D-channel protocol defines
  *
  * $Log: l3_1tr6.h,v $
+ * Revision 2.0  1997/07/27 21:15:47  keil
+ * New Callref based layer3
+ *
  * Revision 1.1  1996/10/13 20:03:48  keil
  * Initial revision
  *
- *
- *
  */
 #ifndef l3_1tr6
 #define l3_1tr6
@@ -29,7 +30,6 @@
 #define MT_N0_CLOSE   0x75
 #define MT_N0_CLO_ACK 0x77
 
-
 /*
  * MsgType N1
  */
@@ -65,8 +65,6 @@
 #define MT_N1_REG_REJ 0x6F
 #define MT_N1_STAT 0x63
 
-
-
 /*
  * W Elemente
  */
 #define CAUSE_RemoteUserResumed 0x73
 #define CAUSE_UserInfoDiscarded 0x7F
 
+#define T303   4000
+#define T304   20000
+#define T305   4000
+#define T308   4000
+#define T310   120000
+#define T313   4000
+#define T318   4000
+#define T319   4000
 
 #endif
index d6089873464fe59c5e4d0fff95ac0a4fc0e4f303..f8b97fd73135b1f834bed1ddd69dba34ffbef48e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 1.15 1997/04/17 11:50:48 keil Exp $
+/* $Id: l3dss1.c,v 2.7 1998/02/12 23:08:01 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
- * 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 2.7  1998/02/12 23:08:01  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.8  1997/01/21 22:29:41  keil
- * new statemachine; L3 timers
+ * Revision 2.6  1998/02/03 23:26:35  keil
+ * V110 extensions from Thomas Pfeiffer
  *
- * Revision 1.7  1996/12/14 21:06:59  keil
- * additional states for CC_REJECT
+ * Revision 2.5  1998/02/02 13:34:28  keil
+ * Support australian Microlink net and german AOCD
  *
- * Revision 1.6  1996/12/08 22:59:16  keil
- * fixed calling party number without octet 3a
+ * Revision 2.4  1997/11/06 17:12:25  keil
+ * KERN_NOTICE --> KERN_INFO
  *
- * Revision 1.5  1996/12/08 19:53:31  keil
- * fixes from Pekka Sarnila
+ * Revision 2.3  1997/10/29 19:03:01  keil
+ * changes for 2.1
  *
- * Revision 1.4  1996/11/05 19:44:36  keil
- * some fixes from Henner Eisen
+ * Revision 2.2  1997/08/07 17:44:36  keil
+ * Fix RESTART
  *
- * Revision 1.3  1996/10/30 10:18:01  keil
- * bugfixes in debugging output
+ * Revision 2.1  1997/08/03 14:36:33  keil
+ * Implement RESTART procedure
  *
- * Revision 1.2  1996/10/27 22:15:16  keil
- * bugfix reject handling
+ * Revision 2.0  1997/07/27 21:15:43  keil
+ * New Callref based layer3
  *
- * Revision 1.1  1996/10/13 20:04:55  keil
- * Initial revision
+ * Revision 1.17  1997/06/26 11:11:46  keil
+ * SET_SKBFREE now on creation of a SKB
  *
+ * Revision 1.15  1997/04/17 11:50:48  keil
+ * pa->loc was undefined, if it was not send by the exchange
  *
+ * Old log removed /KKe
  *
  */
 
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isdnl3.h"
+#include "l3dss1.h"
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 1.15 $";
+const char *dss1_revision = "$Revision: 2.7 $";
+
+#define EXT_BEARER_CAPS 1
 
 #define        MsgHead(ptr, cref, mty) \
        *ptr++ = 0x8; \
        *ptr++ = 0x1; \
-       *ptr++ = cref; \
+       *ptr++ = cref^0x80; \
        *ptr++ = mty
 
+
+#ifdef HISAX_DE_AOC
 static void
-l3dss1_message(struct PStack *st, u_char mt)
+l3dss1_parse_facility(struct l3_process *pc, u_char *p)
+{
+       int qd_len = 0;
+       char tmp[32];
+
+       p++;
+       qd_len = *p++;
+       if (qd_len == 0) {
+               l3_debug(pc->st, "qd_len == 0");
+               return;
+       }
+       if((*p & 0x1F) != 0x11) {       /* Service discriminator, supplementary service */
+               l3_debug(pc->st, "supplementary service != 0x11");
+               return;
+       }
+       while(qd_len > 0 && !(*p & 0x80)) {     /* extension ? */
+               p++; qd_len--;
+       } 
+       if(qd_len < 2) {
+               l3_debug(pc->st, "qd_len < 2");
+               return;
+       }
+       p++; qd_len--;
+       if((*p & 0xE0) != 0xA0) {       /* class and form */
+               l3_debug(pc->st, "class and form != 0xA0");
+               return;
+       }
+       switch(*p & 0x1F) {             /* component tag */
+           case 1: /* invoke */
+               {
+                   unsigned char nlen, ilen;
+                   int ident;
+    
+                   p++; qd_len--;
+                   if(qd_len < 1) {
+                           l3_debug(pc->st, "qd_len < 1");
+                           break;
+                   }
+                   if(*p & 0x80) { /* length format */
+                           l3_debug(pc->st, "*p & 0x80 length format");
+                           break;
+                   }
+                   nlen = *p++; qd_len--;
+                   if(qd_len < nlen) {
+                           l3_debug(pc->st, "qd_len < nlen");
+                           return;
+                   }
+                   qd_len -= nlen;
+    
+                   if(nlen < 2) {
+                           l3_debug(pc->st, "nlen < 2");
+                           return;
+                   }
+                   if(*p != 0x02) {    /* invoke identifier tag */
+                           l3_debug(pc->st, "invoke identifier tag !=0x02");
+                           return;
+                   }
+                   p++; nlen--;
+                   if(*p & 0x80) { /* length format */
+                           l3_debug(pc->st, "*p & 0x80 length format 2");
+                           break;
+                   }
+                   ilen = *p++; nlen--;
+                   if(ilen > nlen || ilen == 0) {
+                           l3_debug(pc->st, "ilen > nlen || ilen == 0");
+                           return;
+                   }
+                   nlen -= ilen;
+                   ident = 0;
+                   while(ilen > 0) {
+                           ident = (ident << 8) | (*p++ & 0xFF);       /* invoke identifier */
+                           ilen--;
+                   }
+    
+                   if(nlen < 2) {
+                           l3_debug(pc->st, "nlen < 2 22");
+                           return;
+                   }
+                   if(*p != 0x02)      {       /* operation value */ 
+                           l3_debug(pc->st, "operation value !=0x02");
+                           return;
+                   }
+                   p++; nlen--;
+                   ilen = *p++; nlen--;
+                   if(ilen > nlen || ilen == 0) {
+                           l3_debug(pc->st, "ilen > nlen || ilen == 0 22");
+                           return;
+                   }
+                   nlen -= ilen;
+                   ident = 0;
+                   while(ilen > 0) {
+                           ident = (ident << 8) | (*p++ & 0xFF);
+                           ilen--;
+                   }
+    
+    #define FOO1(s,a,b) \
+           while(nlen > 1) {           \
+                   int ilen = p[1];    \
+                   if(nlen < ilen+2) { \
+                           l3_debug(pc->st, "FOO1  nlen < ilen+2"); \
+                           return;             \
+                   }                   \
+                   nlen -= ilen+2;             \
+                   if((*p & 0xFF) == (a)) {    \
+                           int nlen = ilen;    \
+                           p += 2;             \
+                           b;          \
+                   } else {            \
+                           p += ilen+2;        \
+                   }                   \
+           }
+                           
+                   switch(ident) {
+                   default:
+                           break;
+                   case 0x22: /* during */
+                           FOO1("1A",0x30,FOO1("1C",0xA1,FOO1("1D",0x30,FOO1("1E",0x02,({
+                                   ident = 0;
+                                   while(ilen > 0) {
+                                           ident = (ident<<8) | *p++;
+                                           ilen--;
+                                   }
+                                   if (ident > pc->para.chargeinfo) {
+                                           pc->para.chargeinfo = ident;
+                                           pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+                                   }
+                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                                           if (*(p+2) == 0) {
+                                                   sprintf(tmp, "charging info during %d", pc->para.chargeinfo);
+                                                   l3_debug(pc->st, tmp);
+                                           }
+                                           else {
+                                           sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
+                                           l3_debug(pc->st, tmp);
+                                           }
+                                   }
+                           })))))
+                           break;
+                   case 0x24: /* final */
+                           FOO1("2A",0x30,FOO1("2B",0x30,FOO1("2C",0xA1,FOO1("2D",0x30,FOO1("2E",0x02,({
+                                   ident = 0;
+                                   while(ilen > 0) {
+                                           ident = (ident<<8) | *p++;
+                                           ilen--;
+                                   }
+                                   if (ident > pc->para.chargeinfo) {
+                                           pc->para.chargeinfo = ident;
+                                           pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+                                   }
+                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                                           sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
+                                           l3_debug(pc->st, tmp);
+                                   }
+                           }))))))
+                   break;
+                   }
+    #undef FOO1
+    
+               }
+           break;
+           case 2: /* return result */
+                   l3_debug(pc->st, "return result break");
+                   break;
+           case 3: /* return error */
+                   l3_debug(pc->st, "return error break");
+                   break;
+           default:
+                   l3_debug(pc->st, "default break");
+                   break;
+       }
+}
+#endif 
+
+static int 
+l3dss1_check_messagetype_validity(int mt) {
+/* verify if a message type exists */
+       switch(mt) {
+               case MT_ALERTING:
+               case MT_CALL_PROCEEDING:
+               case MT_CONNECT:
+               case MT_CONNECT_ACKNOWLEDGE:
+               case MT_PROGRESS:
+               case MT_SETUP:
+               case MT_SETUP_ACKNOWLEDGE:
+               case MT_RESUME:
+               case MT_RESUME_ACKNOWLEDGE:
+               case MT_RESUME_REJECT:
+               case MT_SUSPEND:
+               case MT_SUSPEND_ACKNOWLEDGE:
+               case MT_SUSPEND_REJECT:
+               case MT_USER_INFORMATION:
+               case MT_DISCONNECT:
+               case MT_RELEASE:
+               case MT_RELEASE_COMPLETE:
+               case MT_RESTART:
+               case MT_RESTART_ACKNOWLEDGE:
+               case MT_SEGMENT:
+               case MT_CONGESTION_CONTROL:
+               case MT_INFORMATION:
+               case MT_FACILITY:
+               case MT_NOTIFY:
+               case MT_STATUS:
+               case MT_STATUS_ENQUIRY:
+                       return(1);
+               default:
+                       return(0);
+       }
+       return(0);
+}
+
+static void
+l3dss1_message(struct l3_process *pc, u_char mt)
 {
        struct sk_buff *skb;
        u_char *p;
@@ -81,63 +282,226 @@ l3dss1_message(struct PStack *st, u_char mt)
        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);
+       MsgHead(p, pc->callref, mt);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
 }
 
 static void
-l3dss1_release_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_req(struct l3_process *pc, 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);
+       StopAllL3Timer(pc);
+       newl3state(pc, 19);
+       l3dss1_message(pc, MT_RELEASE);
+       L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3dss1_release_cmpl(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
        int cause = -1;
 
        p = skb->data;
-       st->pa->loc = 0;
+       pc->para.loc = 0;
        if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
                p++;
                if (*p++ == 2)
-                       st->pa->loc = *p++;
+                       pc->para.loc = *p++;
                cause = *p & 0x7f;
        }
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       StopAllL3Timer(st);
-       st->pa->cause = cause;
-       newl3state(st, 0);
-       st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+       StopAllL3Timer(pc);
+       pc->para.cause = cause;
+       newl3state(pc, 0);
+       pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+       release_l3_process(pc);
+}
+
+#ifdef EXT_BEARER_CAPS
+
+u_char *EncodeASyncParams(u_char *p, u_char si2)
+{ // 7c 06 88  90 21 42 00 bb
+
+  p[0] = p[1] = 0; p[2] = 0x80;
+  if (si2 & 32) // 7 data bits
+    p[2] += 16;
+  else          // 8 data bits
+    p[2] +=24;
+
+  if (si2 & 16) // 2 stop bits
+    p[2] += 96;
+  else          // 1 stop bit
+    p[2] = 32;
+
+  if (si2 & 8)  // even parity
+    p[2] += 2;
+  else          // no parity
+    p[2] += 3;
+
+  switch (si2 & 0x07)
+  {
+    case 0:     p[0] = 66;      // 1200 bit/s
+                break;
+    case 1:     p[0] = 88;      // 1200/75 bit/s
+                break;
+    case 2:     p[0] = 87;      // 75/1200 bit/s
+                break;
+    case 3:     p[0] = 67;      // 2400 bit/s
+                break;
+    case 4:     p[0] = 69;      // 4800 bit/s
+                break;
+    case 5:     p[0] = 72;      // 9600 bit/s
+                break;
+    case 6:     p[0] = 73;      // 14400 bit/s
+                break;
+    case 7:     p[0] = 75;      // 19200 bit/s
+                break;
+  }
+  return p+3;
+}
+
+u_char EncodeSyncParams(u_char si2, u_char ai)
+{
+
+  switch (si2)
+  {
+    case 0:     return ai + 2;  // 1200 bit/s
+    case 1:     return ai + 24; // 1200/75 bit/s
+    case 2:     return ai + 23; // 75/1200 bit/s
+    case 3:     return ai + 3;  // 2400 bit/s
+    case 4:     return ai + 5;  // 4800 bit/s
+    case 5:     return ai + 8;  // 9600 bit/s
+    case 6:     return ai + 9;  // 14400 bit/s
+    case 7:     return ai + 11; // 19200 bit/s
+    case 8:     return ai + 14; // 48000 bit/s
+    case 9:     return ai + 15; // 56000 bit/s
+    case 15:    return ai + 40; // negotiate bit/s
+    default:    break;
+  }
+  return ai;
+}
+
+
+static u_char DecodeASyncParams(u_char si2, u_char *p)
+{ u_char info;
+
+  switch (p[5])
+  {
+    case 66: // 1200 bit/s
+             break; // si2 bleibt gleich
+    case 88: // 1200/75 bit/s
+             si2 += 1;
+             break;
+    case 87: // 75/1200 bit/s
+             si2 += 2;
+             break;
+    case 67: // 2400 bit/s
+             si2 += 3;
+             break;
+    case 69: // 4800 bit/s
+             si2 += 4;
+             break;
+    case 72: // 9600 bit/s
+             si2 += 5;
+             break;
+    case 73: // 14400 bit/s
+             si2 += 6;
+             break;
+    case 75: // 19200 bit/s
+             si2 += 7;
+             break;
+  }
+
+  info = p[7] & 0x7f;
+  if ((info & 16) && (!(info & 8)))   // 7 data bits
+    si2 += 32;                        // else 8 data bits
+  if ((info & 96) == 96)              // 2 stop bits
+    si2 += 16;                        // else 1 stop bit
+  if ((info & 2) && (!(info & 1)))    // even parity
+    si2 += 8;                         // else no parity
+
+  return si2;
+}
+
+
+static u_char DecodeSyncParams(u_char si2, u_char info)
+{
+  info &= 0x7f;
+  switch (info)
+  {
+    case 40: // bit/s aushandeln  --- hat nicht geklappt, ai wird 165 statt 175!
+      return si2 + 15;
+    case 15: // 56000 bit/s --- hat nicht geklappt, ai wird 0 statt 169 !
+      return si2 + 9;
+    case 14: // 48000 bit/s
+      return si2 + 8;
+    case 11: // 19200 bit/s
+      return si2 + 7;
+    case 9:  // 14400 bit/s
+      return si2 + 6;
+    case 8:  // 9600  bit/s
+      return si2 + 5;
+    case 5:  // 4800  bit/s
+      return si2 + 4;
+    case 3:  // 2400  bit/s
+      return si2 + 3;
+    case 23: // 75/1200 bit/s
+      return si2 + 2;
+    case 24: // 1200/75 bit/s
+      return si2 + 1;
+    default: // 1200 bit/s
+      return si2;
+  }
 }
 
+static u_char DecodeSI2(struct sk_buff *skb)
+{ u_char *p; //, *pend=skb->data + skb->len;
+
+        if ((p = findie(skb->data, skb->len, 0x7c, 0)))
+        {
+          switch (p[4] & 0x0f)
+          {
+            case 0x01:  if (p[1] == 0x04) // sync. Bitratenadaption
+                          return DecodeSyncParams(160, p[5]); // V.110/X.30
+                        else if (p[1] == 0x06) // async. Bitratenadaption
+                          return DecodeASyncParams(192, p);   // V.110/X.30
+                        break;
+            case 0x08:  // if (p[5] == 0x02) // sync. Bitratenadaption
+                          return DecodeSyncParams(176, p[5]); // V.120
+                        break;
+          }
+        }
+        return 0;
+}
+
+#endif
+
+
 static void
-l3dss1_setup_req(struct PStack *st, u_char pr,
+l3dss1_setup_req(struct l3_process *pc, u_char pr,
                 void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[128];
        u_char *p = tmp;
        u_char channel = 0;
-       u_char screen = 0;
+       u_char screen = 0x80;
        u_char *teln;
        u_char *msn;
+       u_char *sub;
+       u_char *sp;
        int l;
 
-       st->l3.callref = st->pa->callref;
-       MsgHead(p, st->l3.callref, MT_SETUP);
+       MsgHead(p, pc->callref, MT_SETUP);
 
        /*
         * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
         */
+#ifdef HISAX_EURO_SENDCOMPLETE
        *p++ = 0xa1;            /* complete indicator */
-       switch (st->pa->setup.si1) {
+#endif
+       switch (pc->para.setup.si1) {
                case 1: /* Telephony                               */
                        *p++ = 0x4;     /* BC-IE-code                              */
                        *p++ = 0x3;     /* Length                                  */
@@ -157,7 +521,7 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
        /*
         * What about info2? Mapping to High-Layer-Compatibility?
         */
-       teln = st->pa->setup.phone;
+       teln = pc->para.setup.phone;
        if (*teln) {
                /* parse number for special things */
                if (!isdigit(*teln)) {
@@ -179,19 +543,28 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
                                        screen = 0x80;
                                        break;
                                default:
-                                       if (st->l3.debug & L3_DEB_WARN)
-                                               l3_debug(st, "Wrong MSN Code");
+                                       if (pc->debug & L3_DEB_WARN)
+                                               l3_debug(pc->st, "Wrong MSN Code");
                                        break;
                        }
                        teln++;
                }
        }
        if (channel) {
-               *p++ = 0x18;    /* channel indicator */
+               *p++ = IE_CHANNEL_ID;
                *p++ = 1;
                *p++ = channel;
        }
-       msn = st->pa->setup.eazmsn;
+       msn = pc->para.setup.eazmsn;
+       sub = NULL;
+       sp = msn;
+       while (*sp) { 
+               if ('.' == *sp) {
+                       sub = sp;
+                       *sp = 0;
+               } else 
+                       sp++;
+       }
        if (*msn) {
                *p++ = 0x6c;
                *p++ = strlen(msn) + (screen ? 2 : 1);
@@ -204,241 +577,372 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
                while (*msn)
                        *p++ = *msn++ & 0x7f;
        }
+       if (sub) {
+               *sub++ = '.';
+               *p++ = 0x6d; /* Calling party subaddress */
+               *p++ = strlen(sub) + 2;
+               *p++ = 0x80;    /* NSAP coded */
+               *p++ = 0x50;    /* local IDI format */
+               while (*sub)
+                       *p++ = *sub++ & 0x7f;
+       }
+       sub = NULL;
+       sp = teln;
+       while (*sp) { 
+               if ('.' == *sp) {
+                       sub = sp;
+                       *sp = 0;
+               } else 
+                       sp++;
+       }
        *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;
 
+       if (sub) {
+               *sub++ = '.';
+               *p++ = 0x71; /* Called party subaddress */
+               *p++ = strlen(sub) + 2;
+               *p++ = 0x80;    /* NSAP coded */
+               *p++ = 0x50;    /* local IDI format */
+               while (*sub)
+                       *p++ = *sub++ & 0x7f;
+       }
+
+#ifdef EXT_BEARER_CAPS
+        if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175))
+        { // sync. Bitratenadaption, V.110/X.30
+          *p++ = 0x7c; *p++ = 0x04; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21;
+          *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
+        }
+        else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191))
+        { // sync. Bitratenadaption, V.120
+          *p++ = 0x7c; *p++ = 0x05; *p++ = 0x88; *p++ = 0x90; *p++ = 0x28;
+          *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
+          *p++ = 0x82;
+        }
+        else if (pc->para.setup.si2 >= 192)
+        { // async. Bitratenadaption, V.110/X.30
+          *p++ = 0x7c; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21;
+          p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
+        }
+#endif
        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);
-
+       L3DelTimer(&pc->timer);
+       L3AddTimer(&pc->timer, T303, CC_T303);
+       newl3state(pc, 1);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
 }
 
 static void
-l3dss1_call_proc(struct PStack *st, u_char pr, void *arg)
+l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
 
-       L3DelTimer(&st->l3.timer);
+       L3DelTimer(&pc->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);
+       if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+               pc->para.bchannel = p[2] & 0x3;
+               if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN))
+                       l3_debug(pc->st, "setup answer without bchannel");
+       } else if (pc->debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup answer without bchannel");
        dev_kfree_skb(skb);
-       newl3state(st, 3);
-       L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
-       st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+       newl3state(pc, 3);
+       L3AddTimer(&pc->timer, T310, CC_T310);
+       pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
 }
 
 static void
-l3dss1_setup_ack(struct PStack *st, u_char pr, void *arg)
+l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
 
-       L3DelTimer(&st->l3.timer);
+       L3DelTimer(&pc->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);
+       if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+               pc->para.bchannel = p[2] & 0x3;
+               if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN))
+                       l3_debug(pc->st, "setup answer without bchannel");
+       } else if (pc->debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup answer without bchannel");
        dev_kfree_skb(skb);
-       newl3state(st, 2);
-       L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
-       st->l3.l3l4(st, CC_MORE_INFO, NULL);
+       newl3state(pc, 2);
+       L3AddTimer(&pc->timer, T304, CC_T304);
+       pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
 }
 
 static void
-l3dss1_disconnect(struct PStack *st, u_char pr, void *arg)
+l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
        int cause = -1;
 
-       StopAllL3Timer(st);
+       StopAllL3Timer(pc);
        p = skb->data;
-       st->pa->loc = 0;
+       pc->para.loc = 0;
        if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
                p++;
                if (*p++ == 2)
-                       st->pa->loc = *p++;
+                       pc->para.loc = *p++;
                cause = *p & 0x7f;
        }
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       newl3state(st, 12);
-       st->pa->cause = cause;
-       st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+       newl3state(pc, 12);
+       pc->para.cause = cause;
+       pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
 }
 
 static void
-l3dss1_connect(struct PStack *st, u_char pr, void *arg)
+l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       L3DelTimer(&st->l3.timer);      /* T310 */
-       newl3state(st, 10);
-       st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+       L3DelTimer(&pc->timer); /* T310 */
+       newl3state(pc, 10);
+       pc->para.chargeinfo = 0;
+       pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
 }
 
 static void
-l3dss1_alerting(struct PStack *st, u_char pr, void *arg)
+l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       L3DelTimer(&st->l3.timer);      /* T304 */
-       newl3state(st, 4);
-       st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+       L3DelTimer(&pc->timer); /* T304 */
+       newl3state(pc, 4);
+       pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
 }
 
 static void
-l3dss1_setup(struct PStack *st, u_char pr, void *arg)
+l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
 {
-       u_char *p;
+  /* This routine is called if here was no SETUP made (checks in dss1up and in
+   * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+   * It is called after it is veryfied that Layer2 is up.
+   * The cause value is allready in pc->para.cause
+   * MT_STATUS_ENQUIRE in the NULL state is handled too
+   */
+       u_char tmp[16];
+       u_char *p=tmp;
+       int l;
+       struct sk_buff *skb;
+
+       switch (pc->para.cause) {
+         case  81: /* 0x51 invalid callreference */
+         case  96: /* 0x60 mandory IE missing */
+         case 101: /* 0x65 incompatible Callstate */
+               MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+               *p++ = IE_CAUSE;
+               *p++ = 0x2;
+               *p++ = 0x80;
+               *p++ = pc->para.cause | 0x80;
+               break;
+         default:
+               printk(KERN_ERR "HiSax internal error l3dss1_msg_without_setup\n");
+               return;
+       }       
+       l = p - tmp;
+       if (!(skb = l3_alloc_skb(l)))
+               return;
+       memcpy(skb_put(skb, l), tmp, l);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       release_l3_process(pc);
+}
+
+static void
+l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+        u_char *p, *ptmp[8];
+       int i;
        int bcfound = 0;
        char tmp[80];
        struct sk_buff *skb = arg;
 
+       /* ETS 300-104 1.3.4 and 1.3.5
+        * we need to detect unknown inform. element from 0 to 7
+        */     
        p = skb->data;
-       st->pa->callref = getcallref(p);
-       st->l3.callref = 0x80 + st->pa->callref;
+       for(i = 0; i < 8; i++)
+               ptmp[i] = skb->data;
+       if (findie(ptmp[1], skb->len, 0x01, 0)
+           || findie(ptmp[2], skb->len, 0x02, 0)
+           || findie(ptmp[3], skb->len, 0x03, 0)
+           || findie(ptmp[5], skb->len, 0x05, 0)
+           || findie(ptmp[6], skb->len, 0x06, 0)
+           || findie(ptmp[7], skb->len, 0x07, 0)) {
+               /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE 
+                * cause 0x60
+                */
+               pc->para.cause = 0x60;
+               dev_kfree_skb(skb);
+               if (pc->state == 0)
+                       pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
+               else
+                       l3dss1_msg_without_setup(pc, pr, NULL);
+               return;
+       }
 
        /*
         * Channel Identification
         */
        p = skb->data;
-       if ((p = findie(p, skb->len, 0x18, 0))) {
-               st->pa->bchannel = p[2] & 0x3;
-               if (st->pa->bchannel)
+       if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+               pc->para.bchannel = p[2] & 0x3;
+               if (pc->para.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");
+               else if (pc->debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "setup without bchannel");
+       } else if (pc->debug & L3_DEB_WARN)
+               l3_debug(pc->st, "setup without bchannel");
 
        /*
           * Bearer Capabilities
         */
        p = skb->data;
        if ((p = findie(p, skb->len, 0x04, 0))) {
-               st->pa->setup.si2 = 0;
+               pc->para.setup.si2 = 0;
                switch (p[2] & 0x1f) {
                        case 0x00:
                                /* Speech */
                        case 0x10:
                                /* 3.1 Khz audio */
-                               st->pa->setup.si1 = 1;
+                               pc->para.setup.si1 = 1;
                                break;
                        case 0x08:
                                /* Unrestricted digital information */
-                               st->pa->setup.si1 = 7;
+                               pc->para.setup.si1 = 7;
+/* JIM, 05.11.97 I wanna set service indicator 2 */
+#ifdef EXT_BEARER_CAPS
+                                pc->para.setup.si2 = DecodeSI2(skb);
+                                printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n",
+                                       pc->para.setup.si1, pc->para.setup.si2);
+#endif
                                break;
                        case 0x09:
                                /* Restricted digital information */
-                               st->pa->setup.si1 = 2;
+                               pc->para.setup.si1 = 2;
                                break;
                        case 0x11:
                                /* Unrestr. digital information  with tones/announcements */
-                               st->pa->setup.si1 = 3;
+                               pc->para.setup.si1 = 3;
                                break;
                        case 0x18:
                                /* Video */
-                               st->pa->setup.si1 = 4;
+                               pc->para.setup.si1 = 4;
                                break;
                        default:
-                               st->pa->setup.si1 = 0;
+                               pc->para.setup.si1 = 0;
                }
-       } else if (st->l3.debug & L3_DEB_WARN)
-               l3_debug(st, "setup without bearer capabilities");
+       } else {
+               if (pc->debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "setup without bearer capabilities");
+               /* ETS 300-104 1.3.3 */
+               pc->para.cause = 0x60;
+               dev_kfree_skb(skb);
+               if (pc->state == 0)
+                       pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
+               else
+                       l3dss1_msg_without_setup(pc, pr, NULL);
+               return;
+       }
 
        p = skb->data;
        if ((p = findie(p, skb->len, 0x70, 0)))
-               iecpy(st->pa->setup.eazmsn, p, 1);
+               iecpy(pc->para.setup.eazmsn, p, 1);
        else
-               st->pa->setup.eazmsn[0] = 0;
+               pc->para.setup.eazmsn[0] = 0;
 
+       p = skb->data;
+       if ((p = findie(p, skb->len, 0x71, 0))) {
+               /* Called party subaddress */
+               if ((p[1]>=2) && (p[2]==0x80) && (p[3]==0x50)) {
+                       tmp[0]='.';
+                       iecpy(&tmp[1], p, 2);
+                       strcat(pc->para.setup.eazmsn, tmp);
+               } else if (pc->debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "wrong called subaddress");
+       }
        p = skb->data;
        if ((p = findie(p, skb->len, 0x6c, 0))) {
-               st->pa->setup.plan = p[2];
+               pc->para.setup.plan = p[2];
                if (p[2] & 0x80) {
-                       iecpy(st->pa->setup.phone, p, 1);
-                       st->pa->setup.screen = 0;
+                       iecpy(pc->para.setup.phone, p, 1);
+                       pc->para.setup.screen = 0;
                } else {
-                       iecpy(st->pa->setup.phone, p, 2);
-                       st->pa->setup.screen = p[3];
+                       iecpy(pc->para.setup.phone, p, 2);
+                       pc->para.setup.screen = p[3];
                }
        } else {
-               st->pa->setup.phone[0] = 0;
-               st->pa->setup.plan = 0;
-               st->pa->setup.screen = 0;
+               pc->para.setup.phone[0] = 0;
+               pc->para.setup.plan = 0;
+               pc->para.setup.screen = 0;
+       }
+       p = skb->data;
+       if ((p = findie(p, skb->len, 0x6d, 0))) {
+               /* Calling party subaddress */
+               if ((p[1]>=2) && (p[2]==0x80) && (p[3]==0x50)) {
+                       tmp[0]='.';
+                       iecpy(&tmp[1], p, 2);
+                       strcat(pc->para.setup.phone, tmp);
+               } else if (pc->debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "wrong calling subaddress");
        }
-       SET_SKB_FREE(skb);
+
        dev_kfree_skb(skb);
 
        if (bcfound) {
-               if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+               if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) {
                        sprintf(tmp, "non-digital call: %s -> %s",
-                               st->pa->setup.phone,
-                               st->pa->setup.eazmsn);
-                       l3_debug(st, tmp);
+                               pc->para.setup.phone, pc->para.setup.eazmsn);
+                       l3_debug(pc->st, tmp);
                }
-               newl3state(st, 6);
-               st->l3.l3l4(st, CC_SETUP_IND, NULL);
-       }
+               newl3state(pc, 6);
+               pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL);
+       } else
+               release_l3_process(pc);
 }
 
 static void
-l3dss1_reset(struct PStack *st, u_char pr, void *arg)
+l3dss1_reset(struct l3_process *pc, u_char pr, void *arg)
 {
-       StopAllL3Timer(st);
-       newl3state(st, 0);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_setup_rsp(struct PStack *st, u_char pr,
+l3dss1_setup_rsp(struct l3_process *pc, 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);
+       newl3state(pc, 8);
+       l3dss1_message(pc, MT_CONNECT);
+       L3DelTimer(&pc->timer);
+       L3AddTimer(&pc->timer, T313, CC_T313);
 }
 
 static void
-l3dss1_connect_ack(struct PStack *st, u_char pr, void *arg)
+l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       SET_SKB_FREE(skb);
        dev_kfree_skb(skb);
-       newl3state(st, 10);
-       L3DelTimer(&st->l3.timer);
-       st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+       newl3state(pc, 10);
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
 }
 
 static void
-l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[16];
@@ -446,12 +950,12 @@ l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
        int l;
        u_char cause = 0x10;
 
-       if (st->pa->cause > 0)
-               cause = st->pa->cause;
+       if (pc->para.cause > 0)
+               cause = pc->para.cause;
 
-       StopAllL3Timer(st);
+       StopAllL3Timer(pc);
 
-       MsgHead(p, st->l3.callref, MT_DISCONNECT);
+       MsgHead(p, pc->callref, MT_DISCONNECT);
 
        *p++ = IE_CAUSE;
        *p++ = 0x2;
@@ -462,13 +966,13 @@ l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
        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);
+       newl3state(pc, 11);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       L3AddTimer(&pc->timer, T305, CC_T305);
 }
 
 static void
-l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
+l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb;
        u_char tmp[16];
@@ -476,10 +980,10 @@ l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
        int l;
        u_char cause = 0x95;
 
-       if (st->pa->cause > 0)
-               cause = st->pa->cause;
+       if (pc->para.cause > 0)
+               cause = pc->para.cause;
 
-       MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE);
+       MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
 
        *p++ = IE_CAUSE;
        *p++ = 0x2;
@@ -490,13 +994,14 @@ l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
        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);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+       newl3state(pc, 0);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_release(struct PStack *st, u_char pr, void *arg)
+l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        struct sk_buff *skb = arg;
@@ -506,38 +1011,45 @@ l3dss1_release(struct PStack *st, u_char pr, void *arg)
        if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
                p++;
                if (*p++ == 2)
-                       st->pa->loc = *p++;
+                       pc->para.loc = *p++;
                cause = *p & 0x7f;
        }
-       SET_SKB_FREE(skb);
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
+#ifdef HISAX_DE_AOC
+           l3dss1_parse_facility(pc,p);
+#else
+               p = NULL;
+#endif
+       }
        dev_kfree_skb(skb);
-       StopAllL3Timer(st);
-       st->pa->cause = cause;
-       newl3state(st, 0);
-       l3dss1_message(st, MT_RELEASE_COMPLETE);
-       st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+       StopAllL3Timer(pc);
+       pc->para.cause = cause;
+       l3dss1_message(pc, MT_RELEASE_COMPLETE);
+       pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+       newl3state(pc, 0);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_alert_req(struct PStack *st, u_char pr,
+l3dss1_alert_req(struct l3_process *pc, u_char pr,
                 void *arg)
 {
-       newl3state(st, 7);
-       l3dss1_message(st, MT_ALERTING);
+       newl3state(pc, 7);
+       l3dss1_message(pc, MT_ALERTING);
 }
 
 static void
-l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
+l3dss1_status_enq(struct l3_process *pc, 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);
 
-       MsgHead(p, st->l3.callref, MT_STATUS);
+       MsgHead(p, pc->callref, MT_STATUS);
 
        *p++ = IE_CAUSE;
        *p++ = 0x2;
@@ -546,42 +1058,96 @@ l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
 
        *p++ = 0x14;            /* CallState */
        *p++ = 0x1;
-       *p++ = st->l3.state & 0x3f;
+       *p++ = pc->state & 0x3f;
+
+       l = p - tmp;
+       if (!(skb = l3_alloc_skb(l)))
+               return;
+       memcpy(skb_put(skb, l), tmp, l);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+}
+
+static void
+l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg)
+{
+  /* ETS 300-104 7.4.1, 8.4.1, 10.3.1, 11.4.1, 12.4.1, 13.4.1, 14.4.1...
+     if setup has been made and a non expected message type is received, we must send MT_STATUS cause 0x62  */
+        u_char tmp[16];
+       u_char *p = tmp;
+       int l;
+       struct sk_buff *skb = arg;
+
+       dev_kfree_skb(skb);
+
+       MsgHead(p, pc->callref, MT_STATUS);
+
+       *p++ = IE_CAUSE;
+       *p++ = 0x2;
+       *p++ = 0x80;
+       *p++ = 0x62 | 0x80;             /* status sending */
+
+       *p++ = 0x14;            /* CallState */
+       *p++ = 0x1;
+       *p++ = pc->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);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
 }
 
 static void
-l3dss1_t303(struct PStack *st, u_char pr, void *arg)
+l3dss1_release_ind(struct l3_process *pc, 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);
+       u_char *p;
+       struct sk_buff *skb = arg;
+       int callState = 0;
+       p = skb->data;
+
+       if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
+               p++;
+               if (1== *p++)
+                       callState = *p;
+       }
+       if(callState == 0) {
+               /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
+                * set down layer 3 without sending any message
+                */
+               pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+               newl3state(pc, 0);
+               release_l3_process(pc);
        } else {
-               newl3state(st, 0);
-               L3DelTimer(&st->l3.timer);
-               st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
-               st->l3.n_t303 = 1;
+               pc->st->l3.l3l4(pc, CC_IGNORE, NULL);
        }
 }
 
 static void
-l3dss1_t304(struct PStack *st, u_char pr, void *arg)
+l3dss1_t303(struct l3_process *pc, 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);
+       if (pc->N303 > 0) {
+               pc->N303--;
+               L3DelTimer(&pc->timer);
+               l3dss1_setup_req(pc, pr, arg);
+       } else {
+               L3DelTimer(&pc->timer);
+               pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
+               release_l3_process(pc);
+       }
+}
+
+static void
+l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
+{
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3dss1_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
 
 }
 
 static void
-l3dss1_t305(struct PStack *st, u_char pr, void *arg)
+l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char tmp[16];
        u_char *p = tmp;
@@ -589,11 +1155,11 @@ l3dss1_t305(struct PStack *st, u_char pr, void *arg)
        struct sk_buff *skb;
        u_char cause = 0x90;
 
-       L3DelTimer(&st->l3.timer);
-       if (st->pa->cause > 0)
-               cause = st->pa->cause;
+       L3DelTimer(&pc->timer);
+       if (pc->para.cause > 0)
+               cause = pc->para.cause | 0x80;
 
-       MsgHead(p, st->l3.callref, MT_RELEASE);
+       MsgHead(p, pc->callref, MT_RELEASE);
 
        *p++ = IE_CAUSE;
        *p++ = 0x2;
@@ -604,48 +1170,179 @@ l3dss1_t305(struct PStack *st, u_char pr, void *arg)
        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);
+       newl3state(pc, 19);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
+{
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3dss1_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
+{
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0xE6;
+       l3dss1_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg)
+{
+       newl3state(pc, 19);
+       L3DelTimer(&pc->timer);
+       l3dss1_message(pc, MT_RELEASE);
+       L3AddTimer(&pc->timer, T308, CC_T308_2);
+}
+
+static void
+l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
+{
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_t310(struct PStack *st, u_char pr, void *arg)
+l3dss1_restart(struct l3_process *pc, 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);
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc, CC_DLRL, NULL);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_t313(struct PStack *st, u_char pr, void *arg)
+l3dss1_status(struct l3_process *pc, 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);
+       u_char *p;
+       char tmp[64], *t;
+       int l;
+       struct sk_buff *skb = arg;
+       int cause, callState;
+
+       cause = callState = -1;
+       p = skb->data;
+       t = tmp;
+       if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+               p++;
+               l = *p++;
+               t += sprintf(t,"Status CR %x Cause:", pc->callref);
+               while (l--) {
+                       cause = *p;
+                       t += sprintf(t," %2x",*p++);
+               }
+       } else
+               sprintf(t,"Status CR %x no Cause", pc->callref);
+       l3_debug(pc->st, tmp);
+       p = skb->data;
+       t = tmp;
+       t += sprintf(t,"Status state %x ", pc->state);
+       if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
+               p++;
+               if (1== *p++) {
+                       callState = *p;
+                       t += sprintf(t,"peer state %x" , *p);
+               }
+               else
+                       t += sprintf(t,"peer state len error");
+       } else
+               sprintf(t,"no peer state");
+       l3_debug(pc->st, tmp);
+       if(((cause & 0x7f) == 0x6f) && (callState == 0)) {
+               /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... 
+                * if received MT_STATUS with cause == 0x6f and call 
+                * state == 0, then we must set down layer 3
+                */
+               l3dss1_release_ind(pc, pr, arg);
+       } else
+               dev_kfree_skb(skb);
 }
 
 static void
-l3dss1_t308_1(struct PStack *st, u_char pr, void *arg)
+l3dss1_facility(struct l3_process *pc, 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);
+        u_char *p;
+       struct sk_buff *skb = arg;
+
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
+#ifdef HISAX_DE_AOC
+           l3dss1_parse_facility(pc,p);
+#else
+               p = NULL;
+#endif
+       }
 }
 
+
+       
 static void
-l3dss1_t308_2(struct PStack *st, u_char pr, void *arg)
+l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
 {
-       newl3state(st, 0);
-       L3DelTimer(&st->l3.timer);
-       st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+       u_char tmp[32];
+       u_char *p;
+       u_char ri, chan=0;
+       int l;
+       struct sk_buff *skb = arg;
+       struct l3_process *up;
+       
+       newl3state(pc, 2);
+       L3DelTimer(&pc->timer);
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
+               ri = p[2];
+               sprintf(tmp, "Restart %x", ri);
+       } else {
+               sprintf(tmp, "Restart without restart IE");
+               ri = 0x86;
+       }
+       l3_debug(pc->st, tmp);
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+               chan = p[2] & 3;
+               sprintf(tmp, "Restart for channel %d", chan);
+               l3_debug(pc->st, tmp);
+       }
+       dev_kfree_skb(skb);
+       newl3state(pc, 2);
+       up = pc->st->l3.proc;
+       while (up) {
+               if ((ri & 7)==7)
+                       up->st->lli.l4l3(up->st, CC_RESTART, up);
+               else if (up->para.bchannel == chan)
+                               up->st->lli.l4l3(up->st, CC_RESTART, up);
+               up = up->next;
+       }
+       p = tmp;
+       MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
+       if (chan) {
+               *p++ = IE_CHANNEL_ID;
+               *p++ = 1;
+               *p++ = chan | 0x80;
+       }
+       *p++ = 0x79; /* RESTART Ind */
+       *p++ = 1;
+       *p++ = ri;
+       l = p - tmp;
+       if (!(skb = l3_alloc_skb(l)))
+               return;
+       memcpy(skb_put(skb, l), tmp, l);
+       newl3state(pc, 0);
+       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
 }
+
 /* *INDENT-OFF* */
 static struct stateentry downstatelist[] =
 {
+       {SBIT(0),
+        CC_ESTABLISH, l3dss1_msg_without_setup},
        {SBIT(0),
         CC_SETUP_REQ, l3dss1_setup_req},
        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
@@ -654,6 +1351,8 @@ static struct stateentry downstatelist[] =
         CC_RELEASE_REQ, l3dss1_release_req},
        {ALL_STATES,
         CC_DLRL, l3dss1_reset},
+       {ALL_STATES,
+        CC_RESTART, l3dss1_restart},
        {SBIT(6),
         CC_IGNORE, l3dss1_reset},
        {SBIT(6),
@@ -685,63 +1384,216 @@ static struct stateentry datastatelist[] =
 {
        {ALL_STATES,
         MT_STATUS_ENQUIRY, l3dss1_status_enq},
+       {ALL_STATES,
+        MT_FACILITY, l3dss1_facility},
+       {SBIT(19),
+        MT_STATUS, l3dss1_release_ind},
+       {ALL_STATES,
+        MT_STATUS, l3dss1_status},
        {SBIT(0) | SBIT(6),
         MT_SETUP, l3dss1_setup},
        {SBIT(1) | SBIT(2),
         MT_CALL_PROCEEDING, l3dss1_call_proc},
+       {SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+        MT_CALL_PROCEEDING, l3dss1_status_req},
        {SBIT(1),
         MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
+       {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+        MT_SETUP_ACKNOWLEDGE, l3dss1_status_req},
        {SBIT(1) | SBIT(2) | SBIT(3),
         MT_ALERTING, l3dss1_alerting},
+       {SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+        MT_ALERTING, l3dss1_status_req},
        {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),
+       {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(19),  MT_RELEASE, l3dss1_release_ind},
        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
         MT_DISCONNECT, l3dss1_disconnect},
+       {SBIT(11),
+        MT_DISCONNECT, l3dss1_release_req},
        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
         MT_CONNECT, l3dss1_connect},
+       {SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+        MT_CONNECT, l3dss1_status_req},
+       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(11) | SBIT(19),
+        MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req},
        {SBIT(8),
         MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
+       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+        MT_INVALID, l3dss1_status_req},
 };
-/* *INDENT-ON* */
 
+static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry);
 
-static int datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
+static struct stateentry globalmes_list[] =
+{
+       {ALL_STATES,
+         MT_STATUS, l3dss1_status},
+       {SBIT(0),
+        MT_RESTART, l3dss1_global_restart},
+/*     {SBIT(1),
+        MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},                                  
+*/
+};
+static int globalm_len = sizeof(globalmes_list) / sizeof(struct stateentry);
+
+#if 0
+static struct stateentry globalcmd_list[] =
+{
+       {ALL_STATES,
+         CC_STATUS, l3dss1_status_req},
+       {SBIT(0),
+        CC_RESTART, l3dss1_restart_req},
+};
+
+static int globalc_len = sizeof(globalcmd_list) / sizeof(struct stateentry);
+#endif
+/* *INDENT-ON* */
+
+static void
+global_handler(struct PStack *st, int mt, struct sk_buff *skb)
+{
+       int i;
+       char tmp[64];
+       struct l3_process *proc = st->l3.global;
+       
+       for (i = 0; i < globalm_len; i++)
+               if ((mt == globalmes_list[i].primitive) &&
+                   ((1 << proc->state) & globalmes_list[i].state))
+                       break;
+       if (i == globalm_len) {
+               dev_kfree_skb(skb);
+               if (st->l3.debug & L3_DEB_STATE) {
+                       sprintf(tmp, "dss1 global state %d mt %x unhandled",
+                               proc->state, mt);
+                       l3_debug(st, tmp);
+               }
+               return;
+       } else {
+               if (st->l3.debug & L3_DEB_STATE) {
+                       sprintf(tmp, "dss1 global %d mt %x",
+                               proc->state, mt);
+                       l3_debug(st, tmp);
+               }
+               globalmes_list[i].rout(proc, mt, skb);
+       }
+}
 
 static void
 dss1up(struct PStack *st, int pr, void *arg)
 {
-       int i, mt;
+       int i, mt, cr, cause, callState;
+       char *ptr;
        struct sk_buff *skb = arg;
+       struct l3_process *proc;
        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 %d state %d",
+                       sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d",
                                (pr == DL_DATA) ? " " : "(broadcast) ",
-                               skb->data[0], skb->len, st->l3.state);
+                               skb->data[0], skb->len);
                        l3_debug(st, tmp);
                }
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                return;
        }
+       cr = getcallref(skb->data);
        mt = skb->data[skb->data[1] + 2];
+       if (!cr) {                              /* Global CallRef */
+               global_handler(st, mt, skb);
+               return;
+       } else if (cr == -1) {                  /* Dummy Callref */
+               dev_kfree_skb(skb);
+               return;
+       } else if (!(proc = getl3proc(st, cr))) {
+               /* No transaction process exist, that means no call with
+                * this callreference is active
+                */
+               if (mt == MT_SETUP) {
+               /* Setup creates a new transaction process */
+                       if (!(proc = new_l3_process(st, cr))) {
+                               /* May be to answer with RELEASE_COMPLETE and
+                                * CAUSE 0x2f "Resource unavailable", but this
+                                * need a new_l3_process too ... arghh
+                                */
+                               dev_kfree_skb(skb);
+                               return;
+                       }
+               } else if (mt == MT_STATUS) {
+                       cause = 0;
+                       if((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
+                                 ptr++;
+                                 if (*ptr++ == 2)
+                                       ptr++;
+                                 cause = *ptr & 0x7f;
+                       }
+                       callState = 0;
+                       if((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
+                               ptr++;
+                               if (*ptr++ == 2)
+                                       ptr++;
+                               callState = *ptr;
+                       }
+                       if (callState == 0) {
+                               /* ETS 300-104 part 2.4.1
+                                * if setup has not been made and a message type
+                                * MT_STATUS is received with call state == 0,
+                                * we must send nothing
+                                */
+                               dev_kfree_skb(skb);
+                               return;
+                       } else {
+                               /* ETS 300-104 part 2.4.2
+                                * if setup has not been made and a message type 
+                                * MT_STATUS is received with call state != 0,
+                                * we must send MT_RELEASE_COMPLETE cause 101
+                                */
+                               dev_kfree_skb(skb);
+                               if ((proc = new_l3_process(st, cr))) {
+                                       proc->para.cause = 0x65; /* 101 */
+                                       proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+                               }
+                               return;
+                       }
+               } else if (mt == MT_RELEASE_COMPLETE){
+                       dev_kfree_skb(skb);
+                       return;
+               } else {
+                       /* ETS 300-104 part 2
+                        * if setup has not been made and a message type 
+                        * (except MT_SETUP and RELEASE_COMPLETE) is received,
+                        * we must send MT_RELEASE_COMPLETE cause 81 */
+                       dev_kfree_skb(skb);
+                       if ((proc = new_l3_process(st, cr))) {
+                               proc->para.cause = 0x51; /* 81 */
+                               proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+                       }
+                       return;
+               }
+       } else if (!l3dss1_check_messagetype_validity(mt)) {
+               /* ETS 300-104 7.4.2, 8.4.2, 10.3.2, 11.4.2, 12.4.2, 13.4.2,
+                * 14.4.2...
+                * if setup has been made and invalid message type is received,
+                * we must send MT_STATUS cause 0x62
+                */
+               mt = MT_INVALID;  /* sorry, not clean, but do the right thing ;-) */
+       }
+
        for (i = 0; i < datasllen; i++)
                if ((mt == datastatelist[i].primitive) &&
-                   ((1 << st->l3.state) & datastatelist[i].state))
+                   ((1 << proc->state) & datastatelist[i].state))
                        break;
        if (i == datasllen) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                if (st->l3.debug & L3_DEB_STATE) {
                        sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
                                (pr == DL_DATA) ? " " : "(broadcast) ",
-                               st->l3.state, mt);
+                               proc->state, mt);
                        l3_debug(st, tmp);
                }
                return;
@@ -749,36 +1601,55 @@ dss1up(struct PStack *st, int pr, void *arg)
                if (st->l3.debug & L3_DEB_STATE) {
                        sprintf(tmp, "dss1up%sstate %d mt %x",
                                (pr == DL_DATA) ? " " : "(broadcast) ",
-                               st->l3.state, mt);
+                               proc->state, mt);
                        l3_debug(st, tmp);
                }
-               datastatelist[i].rout(st, pr, skb);
+               datastatelist[i].rout(proc, pr, skb);
        }
 }
 
 static void
 dss1down(struct PStack *st, int pr, void *arg)
 {
-       int i;
+       int i, cr;
+       struct l3_process *proc;
+       struct Channel *chan;
        char tmp[80];
 
+       if (CC_SETUP_REQ == pr) {
+               chan = arg;
+               cr = newcallref();
+               cr |= 0x80;
+               if ((proc = new_l3_process(st, cr))) {
+                       proc->chan = chan;
+                       chan->proc = proc;
+                       proc->para.setup = chan->setup;
+                       proc->callref = cr;
+               }
+       } else {
+               proc = arg;
+       }
+       if (!proc) {
+               printk(KERN_ERR "HiSax internal error dss1down without proc\n");
+               return;
+       }
        for (i = 0; i < downsllen; i++)
                if ((pr == downstatelist[i].primitive) &&
-                   ((1 << st->l3.state) & downstatelist[i].state))
+                   ((1 << proc->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);
+                               proc->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);
+                               proc->state, pr);
                        l3_debug(st, tmp);
                }
-               downstatelist[i].rout(st, pr, arg);
+               downstatelist[i].rout(proc, pr, arg);
        }
 }
 
@@ -787,20 +1658,20 @@ setstack_dss1(struct PStack *st)
 {
        char tmp[64];
 
-       st->l4.l4l3 = dss1down;
+       st->lli.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));
+       st->l3.N303 = 1;
+       if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+               printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n");
+       } else {
+               st->l3.global->state = 0;
+               st->l3.global->callref = 0;
+               st->l3.global->next = NULL;
+               st->l3.global->debug = L3_DEB_WARN;
+               st->l3.global->st = st;
+               st->l3.global->N303 = 1;
+               L3InitTimer(st->l3.global, &st->l3.global->timer);
        }
+       strcpy(tmp, dss1_revision);
+       printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
 }
diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h
new file mode 100644 (file)
index 0000000..8508c31
--- /dev/null
@@ -0,0 +1,71 @@
+/* $Id: l3dss1.h,v 1.5 1998/02/02 13:34:30 keil Exp $
+ *
+ *  DSS1 (Euro) D-channel protocol defines
+ *
+ * $Log: l3dss1.h,v $
+ * Revision 1.5  1998/02/02 13:34:30  keil
+ * Support australian Microlink net and german AOCD
+ *
+ * Revision 1.4  1997/10/29 19:07:54  keil
+ * changes for 2.1
+ *
+ * Revision 1.3  1997/08/07 17:44:37  keil
+ * Fix RESTART
+ *
+ * Revision 1.2  1997/08/03 14:36:34  keil
+ * Implement RESTART procedure
+ *
+ * Revision 1.1  1997/07/27 21:08:38  keil
+ * new
+ *
+ *
+ *
+ */
+#define T303   4000
+#define T304   30000
+#define T305   30000
+#define T308   4000
+#define T310   30000
+#define T313   4000
+#define T318   4000
+#define T319   4000
+
+/*
+ * 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 MT_INVALID             0xff
+
+#define IE_CAUSE               0x08
+#define IE_BEARER              0x04
+#define IE_FACILITY            0x1c
+#define IE_CALL_STATE          0x14
+#define IE_CHANNEL_ID          0x18
+#define IE_RESTART_IND         0x79
diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c
new file mode 100644 (file)
index 0000000..b3e9819
--- /dev/null
@@ -0,0 +1,58 @@
+/* $Id: lmgr.c,v 1.2 1997/10/29 19:09:34 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *  Layermanagement module
+ *
+ * $Log: lmgr.c,v $
+ * Revision 1.2  1997/10/29 19:09:34  keil
+ * new L1
+ *
+ * Revision 1.1  1997/06/26 11:17:25  keil
+ * first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+
+static void
+error_handling_dchan(struct PStack *st, int Error)
+{
+       switch (Error) {
+               case 'C':
+               case 'D':
+               case 'G':
+               case 'H':
+                       st->l2.l2tei(st, MDL_ERROR_REQ, NULL);
+                       break;
+       }
+}
+
+static void
+hisax_manager(struct PStack *st, int pr, void *arg)
+{
+       char tm[32], str[256];
+       int Code;
+
+       switch (pr) {
+               case MDL_ERROR_IND:
+                       Code = (int) arg;
+                       jiftime(tm, jiffies);
+                       sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm,
+                               Code, test_bit(FLG_LAPD, &st->l2.flag) ?
+                               "D-channel" : "B-channel");
+                       HiSax_putstatus(st->l1.hardware, str);
+                       if (test_bit(FLG_LAPD, &st->l2.flag))
+                               error_handling_dchan(st, Code);
+                       break;
+       }
+}
+
+void
+setstack_manager(struct PStack *st)
+{
+       st->ma.layer = hisax_manager;
+}
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
new file mode 100644 (file)
index 0000000..8bf4757
--- /dev/null
@@ -0,0 +1,284 @@
+/* $Id: mic.c,v 1.6 1998/02/17 15:39:57 keil Exp $
+
+ * mic.c  low level stuff for mic cards
+ *
+ * Copyright (C) 1997 
+ *
+ * Author  Stephan von Krawczynski <skraw@ithnet.com>
+ *
+ *
+ * $Log: mic.c,v $
+ * Revision 1.6  1998/02/17 15:39:57  keil
+ * fix reset problem
+ *
+ * Revision 1.5  1998/02/02 13:29:43  keil
+ * fast io
+ *
+ * Revision 1.4  1997/11/08 21:35:51  keil
+ * new l1 init
+ *
+ * Revision 1.3  1997/11/06 17:09:11  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 18:51:17  keil
+ * New files
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:54  keil
+ * new files on 2.0
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *mic_revision = "$Revision: 1.6 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define MIC_ISAC       2
+#define MIC_HSCX       1
+#define MIC_ADR                7
+
+/* CARD_ADR (Write) */
+#define MIC_RESET      0x3     /* same as DOS driver */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo read without cli because it's allready done  */
+
+       byteout(ale, off);
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readreg(cs->hw.mic.adr,
+                       cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.mic.adr,
+                cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
+               cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
+               cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
+               cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
+               cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "mic: Spurious interrupt!\n");
+               return;
+       }
+       val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
+       if (val) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (stat & 1) {
+               writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
+               writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_mic(struct IsdnCardState *cs)
+{
+       int bytecnt = 8;
+
+       if (cs->hw.mic.cfg_reg)
+               release_region(cs->hw.mic.cfg_reg, bytecnt);
+}
+
+static int
+mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_mic(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &mic_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       inithscx(cs); /* /RTSA := ISAC RST */
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_mic(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, mic_revision);
+       printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_MIC)
+               return (0);
+
+       bytecnt = 8;
+       cs->hw.mic.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+       cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
+       cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
+       cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
+
+       if (check_region((cs->hw.mic.cfg_reg), bytecnt)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.mic.cfg_reg,
+                      cs->hw.mic.cfg_reg + bytecnt);
+               return (0);
+       } else {
+               request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn");
+       }
+
+       printk(KERN_INFO
+              "mic: defined at 0x%x IRQ %d\n",
+              cs->hw.mic.cfg_reg,
+              cs->irq);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &mic_card_msg;
+       ISACVersion(cs, "mic:");
+       if (HscxVersion(cs, "mic:")) {
+               printk(KERN_WARNING
+                   "mic: wrong HSCX versions check IO address\n");
+               release_io_mic(cs);
+               return (0);
+       }
+       return (1);
+}
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
new file mode 100644 (file)
index 0000000..0686598
--- /dev/null
@@ -0,0 +1,1108 @@
+/* $Id: netjet.c,v 1.3 1998/02/12 23:08:05 keil Exp $
+
+ * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Traverse Technologie Australia for documents and informations
+ *
+ *
+ * $Log: netjet.c,v $
+ * Revision 1.3  1998/02/12 23:08:05  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.2  1998/02/02 13:32:06  keil
+ * New
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/interrupt.h>
+#define fcstab  ppp_crc16_table
+#include <linux/ppp_defs.h>
+extern __u16 ppp_crc16_table[256]; /* from ppp code */
+
+extern const char *CardType[];
+
+const char *NETjet_revision = "$Revision: 1.3 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/* PCI stuff */
+#define PCI_VENDOR_TRAVERSE_TECH 0xe159
+#define PCI_NETJET_ID  0x0001
+
+#define NETJET_CTRL    0x00
+#define NETJET_DMACTRL 0x01
+#define NETJET_AUXCTRL 0x02
+#define NETJET_AUXDATA 0x03
+#define NETJET_IRQMASK0 0x04
+#define NETJET_IRQMASK1 0x05
+#define NETJET_IRQSTAT0 0x06
+#define NETJET_IRQSTAT1 0x07
+#define NETJET_DMA_READ_START  0x08
+#define NETJET_DMA_READ_IRQ    0x0c
+#define NETJET_DMA_READ_END    0x10
+#define NETJET_DMA_READ_ADR    0x14
+#define NETJET_DMA_WRITE_START 0x18
+#define NETJET_DMA_WRITE_IRQ   0x1c
+#define NETJET_DMA_WRITE_END   0x20
+#define NETJET_DMA_WRITE_ADR   0x24
+#define NETJET_PULSE_CNT       0x28
+
+#define NETJET_ISAC_OFF        0xc0
+#define NETJET_ISACIRQ 0x10
+
+#define NETJET_DMA_SIZE 512
+
+#define HDLC_ZERO_SEARCH 0
+#define HDLC_FLAG_SEARCH 1
+#define HDLC_FLAG_FOUND  2
+#define HDLC_FRAME_FOUND 3
+#define HDLC_NULL 4
+#define HDLC_PART 5
+#define HDLC_FULL 6
+
+#define HDLC_FLAG_VALUE        0x7e
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       long flags;
+       u_char ret;
+       
+       save_flags(flags);
+       cli();
+       cs->hw.njet.auxd &= 0xfc;
+       cs->hw.njet.auxd |= (offset>>4) & 3;
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2));
+       restore_flags(flags);
+       return(ret);
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       long flags;
+       
+       save_flags(flags);
+       cli();
+       cs->hw.njet.auxd &= 0xfc;
+       cs->hw.njet.auxd |= (offset>>4) & 3;
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value);
+       restore_flags(flags);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+       cs->hw.njet.auxd &= 0xfc;
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       insb(cs->hw.njet.isac, data, size);
+}
+
+static void 
+WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+{
+       cs->hw.njet.auxd &= 0xfc;
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+       outsb(cs->hw.njet.isac, data, size);
+}
+
+void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
+{
+       u_int mask=0x000000ff, val = 0, *p=pos;
+       u_int i;
+       
+       val |= fill;
+       if (chan) {
+               val  <<= 8;
+               mask <<= 8;
+       }
+       mask ^= 0xffffffff;
+       for (i=0; i<cnt; i++) {
+               *p   &= mask;
+               *p++ |= val;
+               if (p > bcs->hw.tiger.s_end)
+                       p = bcs->hw.tiger.send;
+       }
+}
+
+void
+mode_tiger(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       char tmp[64];
+
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "Tiger mode %d bchan %d/%d",
+                       mode, bc, bcs->channel);
+               debugl1(cs, tmp);
+       }
+       bcs->mode = mode;
+       bcs->channel = bc;
+       switch (mode) {
+               case (L1_MODE_NULL):
+                       fill_mem(bcs, bcs->hw.tiger.send,
+                               NETJET_DMA_SIZE, bc, 0xff);
+                       if (cs->debug & L1_DEB_HSCX) {
+                               sprintf(tmp, "Tiger stat rec %d/%d send %d",
+                                       bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
+                                       bcs->hw.tiger.s_tot); 
+                               debugl1(cs, tmp);
+                       }
+                       if ((cs->bcs[0].mode == L1_MODE_NULL) &&
+                               (cs->bcs[1].mode == L1_MODE_NULL)) {
+                               cs->hw.njet.dmactrl = 0;
+                               byteout(cs->hw.njet.base + NETJET_DMACTRL,
+                                       cs->hw.njet.dmactrl);
+                               byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+                       }
+                       break;
+               case (L1_MODE_TRANS):
+                       break;
+               case (L1_MODE_HDLC): 
+                       fill_mem(bcs, bcs->hw.tiger.send,
+                               NETJET_DMA_SIZE, bc, 0xff);
+                       bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
+                       bcs->hw.tiger.r_tot = 0;
+                       bcs->hw.tiger.r_bitcnt = 0;
+                       bcs->hw.tiger.r_one = 0;
+                       bcs->hw.tiger.r_err = 0;
+                       bcs->hw.tiger.s_tot = 0;
+                       if (! cs->hw.njet.dmactrl) {
+                               fill_mem(bcs, bcs->hw.tiger.send,
+                                       NETJET_DMA_SIZE, !bc, 0xff);
+                               cs->hw.njet.dmactrl = 1;
+                               byteout(cs->hw.njet.base + NETJET_DMACTRL,
+                                       cs->hw.njet.dmactrl);
+                               byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x3f);
+                       }
+                       bcs->hw.tiger.sendp = bcs->hw.tiger.send;
+                       bcs->hw.tiger.free = NETJET_DMA_SIZE;
+                       test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+                       break;
+       }
+       if (cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp, "tiger: set %x %x %x  %x/%x  pulse=%d",
+                       bytein(cs->hw.njet.base + NETJET_DMACTRL),
+                       bytein(cs->hw.njet.base + NETJET_IRQMASK0),
+                       bytein(cs->hw.njet.base + NETJET_IRQSTAT0),
+                       inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+                       inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+                       bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+               debugl1(cs, tmp);
+       }
+}
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+       return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
+
+static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
+       char tmp[128];
+       char *t = tmp;
+       int i=count,j;
+       u_char *p = buf;
+
+       t += sprintf(t, "tiger %s(%4d)", s, count);
+       while (i>0) {
+               if (i>16)
+                       j=16;
+               else
+                       j=i;
+               QuickHex(t, p, j);
+               debugl1(cs, tmp);
+               p += j;
+               i -= j;
+               t = tmp;
+               t += sprintf(t, "tiger %s      ", s);
+       }
+}
+
+#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
+                       bitcnt++;\
+                       s_val >>= 1;\
+                       if (val & 1) {\
+                               s_one++;\
+                               s_val |= 0x80;\
+                       } else {\
+                               s_one = 0;\
+                               s_val &= 0x7f;\
+                       }\
+                       if (bitcnt==8) {\
+                               bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+                               bitcnt = 0;\
+                       }\
+                       if (s_one == 5) {\
+                               s_val >>= 1;\
+                               s_val &= 0x7f;\
+                               bitcnt++;\
+                               s_one = 0;\
+                       }\
+                       if (bitcnt==8) {\
+                               bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+                               bitcnt = 0;\
+                       }\
+                       val >>= 1;\
+               }
+
+static void make_raw_data(struct BCState *bcs) {
+       register u_int i,s_cnt=0;
+       register u_char j;
+       register u_char val;
+       register u_char s_one = 0;
+       register u_char s_val = 0;
+       register u_char bitcnt = 0;
+       u_int fcs;
+       char tmp[64];
+       
+       
+       bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE;
+       fcs = PPP_INITFCS;
+       for (i=0; i<bcs->hw.tiger.tx_skb->len; i++) {
+               val = bcs->hw.tiger.tx_skb->data[i];
+               fcs = PPP_FCS (fcs, val);
+               MAKE_RAW_BYTE;
+       }
+       fcs ^= 0xffff;
+       val = fcs & 0xff;
+       MAKE_RAW_BYTE;
+       val = (fcs>>8) & 0xff;
+       MAKE_RAW_BYTE;
+       val = HDLC_FLAG_VALUE;
+       for (j=0; j<8; j++) { 
+               bitcnt++;
+               s_val >>= 1;
+               if (val & 1)
+                       s_val |= 0x80;
+               else
+                       s_val &= 0x7f;
+               if (bitcnt==8) {
+                       bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+                       bitcnt = 0;
+               }
+               val >>= 1;
+       }
+       if (bcs->cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp,"tiger make_raw: in %d out %d.%d",
+                       bcs->hw.tiger.tx_skb->len, s_cnt, bitcnt);
+               debugl1(bcs->cs,tmp);
+       }
+       if (bitcnt) {
+               while (8>bitcnt++) {
+                       s_val >>= 1;
+                       s_val |= 0x80;
+               }
+               bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+       }
+       bcs->hw.tiger.sendcnt = s_cnt;
+       bcs->tx_cnt -= bcs->hw.tiger.tx_skb->len;
+       bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
+}
+
+static void got_frame(struct BCState *bcs, int count) {
+       struct sk_buff *skb;
+               
+       if (!(skb = dev_alloc_skb(count)))
+               printk(KERN_WARNING "TIGER: receive out of memory\n");
+       else {
+               memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count);
+               skb_queue_tail(&bcs->rqueue, skb);
+       }
+       bcs->event |= 1 << B_RCVBUFREADY;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+       
+       if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
+               printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
+}
+
+
+
+static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
+       int i;
+       register u_char j;
+       register u_char val;
+       u_int  *pend = bcs->hw.tiger.rec +NETJET_DMA_SIZE -1;
+       register u_char state = bcs->hw.tiger.r_state;
+       register u_char r_one = bcs->hw.tiger.r_one;
+       register u_char r_val = bcs->hw.tiger.r_val;
+       register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
+       u_int *p = buf;
+       char tmp[64];
+        
+       for (i=0;i<cnt;i++) {
+               val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
+               p++;
+               if (p > pend)
+                       p = bcs->hw.tiger.rec;
+               if (val == 0xff) {
+                       state = HDLC_ZERO_SEARCH;
+                       bcs->hw.tiger.r_tot++;
+                       bitcnt = 0;
+                       r_one = 0;
+                       continue;
+               }
+               for (j=0;j<8;j++) {
+                       if (state == HDLC_ZERO_SEARCH) {
+                               if (val & 1) {
+                                       r_one++;
+                               } else {
+                                       r_one=0;
+                                       state= HDLC_FLAG_SEARCH;
+                                       if (bcs->cs->debug & L1_DEB_HSCX) {
+                                               sprintf(tmp,"tiger read_raw: zBit(%d,%d,%d) %x",
+                                                       bcs->hw.tiger.r_tot,i,j,val);
+                                               debugl1(bcs->cs,tmp);
+                                       }
+                               }
+                       } else if (state == HDLC_FLAG_SEARCH) { 
+                               if (val & 1) {
+                                       r_one++;
+                                       if (r_one>6) {
+                                               state=HDLC_ZERO_SEARCH;
+                                       }
+                               } else {
+                                       if (r_one==6) {
+                                               bitcnt=0;
+                                               r_val=0;
+                                               state=HDLC_FLAG_FOUND;
+                                               if (bcs->cs->debug & L1_DEB_HSCX) {
+                                                       sprintf(tmp,"tiger read_raw: flag(%d,%d,%d) %x",
+                                                               bcs->hw.tiger.r_tot,i,j,val);
+                                                       debugl1(bcs->cs,tmp);
+                                               }
+                                       }
+                                       r_one=0;
+                               }
+                       } else if (state ==  HDLC_FLAG_FOUND) {
+                               if (val & 1) {
+                                       r_one++;
+                                       if (r_one>6) {
+                                               state=HDLC_ZERO_SEARCH;
+                                       } else {
+                                               r_val >>= 1;
+                                               r_val |= 0x80;
+                                               bitcnt++;
+                                       }
+                               } else {
+                                       if (r_one==6) {
+                                               bitcnt=0;
+                                               r_val=0;
+                                               r_one=0;
+                                               val >>= 1;
+                                               continue;
+                                       } else if (r_one!=5) {
+                                               r_val >>= 1;
+                                               r_val &= 0x7f;
+                                               bitcnt++;
+                                       }
+                                       r_one=0;        
+                               }
+                               if ((state != HDLC_ZERO_SEARCH) &&
+                                       !(bitcnt & 7)) {
+                                       state=HDLC_FRAME_FOUND;
+                                       bcs->hw.tiger.r_fcs = PPP_INITFCS;
+                                       bcs->hw.tiger.rcvbuf[0] = r_val;
+                                       bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
+                                       if (bcs->cs->debug & L1_DEB_HSCX) {
+                                               sprintf(tmp,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x",
+                                                       bcs->hw.tiger.r_tot,i,j,r_val,val,
+                                                       bcs->cs->hw.njet.irqstat0);
+                                               debugl1(bcs->cs,tmp);
+                                       }
+                               }
+                       } else if (state ==  HDLC_FRAME_FOUND) {
+                               if (val & 1) {
+                                       r_one++;
+                                       if (r_one>6) {
+                                               state=HDLC_ZERO_SEARCH;
+                                               bitcnt=0;
+                                       } else {
+                                               r_val >>= 1;
+                                               r_val |= 0x80;
+                                               bitcnt++;
+                                       }
+                               } else {
+                                       if (r_one==6) {
+                                               r_val=0; 
+                                               r_one=0;
+                                               bitcnt++;
+                                               if (bitcnt & 7) {
+                                                       debugl1(bcs->cs, "tiger: frame not byte aligned");
+                                                       state=HDLC_FLAG_SEARCH;
+                                                       bcs->hw.tiger.r_err++;
+                                               } else {
+                                                       if (bcs->cs->debug & L1_DEB_HSCX) {
+                                                               sprintf(tmp,"tiger frame end(%d,%d): fcs(%x) i %x",
+                                                                       i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
+                                                               debugl1(bcs->cs, tmp);
+                                                       }
+                                                       if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
+                                                               got_frame(bcs, (bitcnt>>3)-3);
+                                                       } else
+                                                               if (bcs->cs->debug) {
+                                                                       debugl1(bcs->cs, "tiger FCS error");
+                                                                       printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
+                                                                               (bitcnt>>3)-1, "rec");
+                                                                       bcs->hw.tiger.r_err++;
+                                                               }
+                                                       state=HDLC_FLAG_FOUND;
+                                               }
+                                               bitcnt=0;
+                                       } else if (r_one==5) {
+                                               val >>= 1;
+                                               r_one=0;
+                                               continue;
+                                       } else {
+                                               r_val >>= 1;
+                                               r_val &= 0x7f;
+                                               bitcnt++;
+                                       }
+                                       r_one=0;        
+                               }
+                               if ((state == HDLC_FRAME_FOUND) &&
+                                       !(bitcnt & 7)) {
+                                       if ((bitcnt>>3)>=HSCX_BUFMAX) {
+                                               debugl1(bcs->cs, "tiger: frame to big");
+                                               r_val=0; 
+                                               state=HDLC_FLAG_SEARCH;
+                                               bcs->hw.tiger.r_err++;
+                                       } else {
+                                               bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val;
+                                               bcs->hw.tiger.r_fcs = 
+                                                       PPP_FCS (bcs->hw.tiger.r_fcs, r_val);
+                                       }
+                               }
+                       }
+                       val >>= 1;
+               }
+               bcs->hw.tiger.r_tot++;
+       }
+       bcs->hw.tiger.r_state = state;
+       bcs->hw.tiger.r_one = r_one;
+       bcs->hw.tiger.r_val = r_val;
+       bcs->hw.tiger.r_bitcnt = bitcnt;
+}
+
+static void read_tiger(struct IsdnCardState *cs) {
+       u_int *p;
+       int cnt = NETJET_DMA_SIZE/2;
+       
+       if (cs->hw.njet.irqstat0 & 4)
+               p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1;
+       else
+               p = cs->bcs[0].hw.tiger.rec + cnt - 1;
+       if (cs->bcs[0].mode == L1_MODE_HDLC)
+               read_raw(cs->bcs, p, cnt);
+       if (cs->bcs[1].mode == L1_MODE_HDLC)
+               read_raw(cs->bcs + 1, p, cnt);
+       cs->hw.njet.irqstat0 &= 0xf3;
+}
+
+static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
+
+static void fill_dma(struct BCState *bcs)
+{
+       char tmp[64];
+       register u_int *p, *sp;
+       register int cnt;
+
+       if (!bcs->hw.tiger.tx_skb)
+               return;
+       if (bcs->cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp,"tiger fill_dma1: c%d %4x", bcs->channel,
+                       bcs->Flag);
+                       debugl1(bcs->cs,tmp);
+       }
+       if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
+               return;
+       make_raw_data(bcs);
+       if (bcs->cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp,"tiger fill_dma2: c%d %4x", bcs->channel,
+                       bcs->Flag);
+                       debugl1(bcs->cs,tmp);
+       }
+       if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
+               write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
+       } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
+               p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
+               sp = bcs->hw.tiger.sendp;
+               if (p == bcs->hw.tiger.s_end)
+                       p = bcs->hw.tiger.send -1;
+               if (sp == bcs->hw.tiger.s_end)
+                       sp = bcs->hw.tiger.send -1;
+               cnt = p - sp;
+               if (cnt <0) {
+                       write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
+               } else {
+                       p++;
+                       cnt++;
+                       if (p > bcs->hw.tiger.s_end)
+                               p = bcs->hw.tiger.send;
+                       p++;
+                       cnt++;
+                       if (p > bcs->hw.tiger.s_end)
+                               p = bcs->hw.tiger.send;
+                       write_raw(bcs, p, bcs->hw.tiger.free - cnt);
+               }
+       } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
+               p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
+               cnt = bcs->hw.tiger.s_end - p;
+               if (cnt < 2) {
+                       p = bcs->hw.tiger.send + 1;
+                       cnt = NETJET_DMA_SIZE/2 - 2;
+               } else {
+                       p++;
+                       p++;
+                       if (cnt <= (NETJET_DMA_SIZE/2))
+                               cnt += NETJET_DMA_SIZE/2;
+                       cnt--;
+                       cnt--;
+               }
+               write_raw(bcs, p, cnt);
+       }
+       if (bcs->cs->debug & L1_DEB_HSCX) {
+               sprintf(tmp,"tiger fill_dma3: c%d %4x", bcs->channel,
+                       bcs->Flag);
+               debugl1(bcs->cs,tmp);
+       }
+}
+
+static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
+       u_int mask, val, *p=buf;
+       u_int i, s_cnt;
+       char tmp[64];
+        
+        if (cnt <= 0)
+               return;
+       if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
+               if (bcs->hw.tiger.sendcnt> cnt) {
+                       s_cnt = cnt;
+                       bcs->hw.tiger.sendcnt -= cnt;
+               } else {
+                       s_cnt = bcs->hw.tiger.sendcnt;
+                       bcs->hw.tiger.sendcnt = 0;
+               }
+               if (bcs->channel)
+                       mask = 0xffff00ff;
+               else
+                       mask = 0xffffff00;
+               for (i=0; i<s_cnt; i++) {
+                       val = bcs->channel ? ((bcs->hw.tiger.sp[i] <<8) & 0xff00) :
+                               (bcs->hw.tiger.sp[i]);
+                       *p   &= mask;
+                       *p++ |= val;
+                       if (p>bcs->hw.tiger.s_end)
+                               p = bcs->hw.tiger.send;
+               }
+               bcs->hw.tiger.s_tot += s_cnt;
+               if (bcs->cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel,
+                       (u_int)buf, (u_int)p, s_cnt, cnt, bcs->hw.tiger.sendcnt,
+                       bcs->cs->hw.njet.irqstat0);
+                       debugl1(bcs->cs,tmp);
+               }
+               if (bcs->cs->debug & L1_DEB_HSCX_FIFO)
+                       printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd");
+               bcs->hw.tiger.sp += s_cnt;
+               bcs->hw.tiger.sendp = p;
+               if (!bcs->hw.tiger.sendcnt) {
+                       if (!bcs->hw.tiger.tx_skb) {
+                               sprintf(tmp,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
+                               debugl1(bcs->cs, tmp);
+                       } else {
+                               if (bcs->st->lli.l1writewakeup &&
+                                       (PACKET_NOACK != bcs->hw.tiger.tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.tiger.tx_skb->len);
+                               dev_kfree_skb(bcs->hw.tiger.tx_skb);
+                               bcs->hw.tiger.tx_skb = NULL;
+                       }
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+                       bcs->hw.tiger.free = cnt - s_cnt;
+                       if (bcs->hw.tiger.free > (NETJET_DMA_SIZE/2))
+                               test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
+                       else {
+                               test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
+                               test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
+                       }
+                       if ((bcs->hw.tiger.tx_skb = skb_dequeue(&bcs->squeue))) {
+                               fill_dma(bcs);
+                       } else {
+                               mask ^= 0xffffffff;
+                               if (s_cnt < cnt) {
+                                       for (i=s_cnt; i<cnt;i++) {
+                                               *p++ |= mask;
+                                               if (p>bcs->hw.tiger.s_end)
+                                                       p = bcs->hw.tiger.send;
+                                       }
+                                       if (bcs->cs->debug & L1_DEB_HSCX) {
+                                               sprintf(tmp, "tiger write_raw: fill rest %d",
+                                                       cnt - s_cnt);
+                                               debugl1(bcs->cs,tmp);
+                                       }
+                               }
+                               bcs->event |= 1 << B_XMTBUFREADY;
+                               queue_task(&bcs->tqueue, &tq_immediate);
+                               mark_bh(IMMEDIATE_BH);
+                       }
+               }
+       } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
+               test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
+               fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
+               bcs->hw.tiger.free += cnt;
+               if (bcs->cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp,"tiger write_raw: fill half");
+                       debugl1(bcs->cs,tmp);
+               }
+       } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
+               test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+               fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
+               if (bcs->cs->debug & L1_DEB_HSCX) {
+                       sprintf(tmp,"tiger write_raw: fill full");
+                       debugl1(bcs->cs,tmp);
+               }
+       }
+}
+
+static void write_tiger(struct IsdnCardState *cs) {
+       u_int *p, cnt = NETJET_DMA_SIZE/2;
+       
+       if (cs->hw.njet.irqstat0  & 1)
+               p = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1;
+       else
+               p = cs->bcs[0].hw.tiger.send + cnt - 1;
+       if (cs->bcs[0].mode == L1_MODE_HDLC)
+               write_raw(cs->bcs, p, cnt);
+       if (cs->bcs[1].mode == L1_MODE_HDLC)
+               write_raw(cs->bcs + 1, p, cnt);
+       cs->hw.njet.irqstat0 &= 0xfc;
+}
+
+static void
+tiger_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA_REQ):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->hw.tiger.tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->hw.tiger.tx_skb = skb;
+                               st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                               restore_flags(flags);
+                       }
+                       break;
+               case (PH_PULL_IND):
+                       if (st->l1.bcs->hw.tiger.tx_skb) {
+                               printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       save_flags(flags);
+                       cli();
+                       st->l1.bcs->hw.tiger.tx_skb = skb;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       restore_flags(flags);
+                       break;
+               case (PH_PULL_REQ):
+                       if (!st->l1.bcs->hw.tiger.tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+       }
+}
+
+void
+close_tigerstate(struct BCState *bcs)
+{
+       struct sk_buff *skb;
+
+       mode_tiger(bcs, 0, 0);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (bcs->hw.tiger.rcvbuf) {
+                       kfree(bcs->hw.tiger.rcvbuf);
+                       bcs->hw.tiger.rcvbuf = NULL;
+               }
+               if (bcs->hw.tiger.sendbuf) {
+                       kfree(bcs->hw.tiger.sendbuf);
+                       bcs->hw.tiger.sendbuf = NULL;
+               }
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+               if (bcs->hw.tiger.tx_skb) {
+                       dev_kfree_skb(bcs->hw.tiger.tx_skb);
+                       bcs->hw.tiger.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+static int
+open_tigerstate(struct IsdnCardState *cs, int bc)
+{
+       struct BCState *bcs = cs->bcs + bc;
+
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_KERNEL))) {
+                       printk(KERN_WARNING
+                              "HiSax: No memory for tiger.rcvbuf\n");
+                       return (1);
+               }
+               if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_KERNEL))) {
+                       printk(KERN_WARNING
+                              "HiSax: No memory for tiger.sendbuf\n");
+                       return (1);
+               }
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->hw.tiger.tx_skb = NULL;
+       bcs->hw.tiger.sendcnt = 0;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       bcs->event = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+static void
+tiger_manl1(struct PStack *st, int pr,
+         void *arg)
+{
+       switch (pr) {
+               case (PH_ACTIVATE_REQ):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       break;
+               case (PH_DEACTIVATE_REQ):
+                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
+                               mode_tiger(st->l1.bcs, 0, 0);
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       break;
+       }
+}
+
+int
+setstack_tiger(struct PStack *st, struct BCState *bcs)
+{
+       if (open_tigerstate(st->l1.hardware, bcs->channel))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = tiger_l2l1;
+       st->ma.manl1 = tiger_manl1;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+__initfunc(void
+inittiger(struct IsdnCardState *cs))
+{
+       char tmp[128];
+
+       if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
+               GFP_KERNEL | GFP_DMA))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for tiger.send\n");
+               return;
+       }
+       cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE/2 - 1;
+       cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1;
+       cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
+       cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
+       cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
+       
+       memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int));
+       sprintf(tmp, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send,
+               (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1));
+       debugl1(cs, tmp);
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
+               cs->hw.njet.base + NETJET_DMA_READ_START);
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
+               cs->hw.njet.base + NETJET_DMA_READ_IRQ);
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
+               cs->hw.njet.base + NETJET_DMA_READ_END);
+       if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int),
+               GFP_KERNEL | GFP_DMA))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for tiger.rec\n");
+               return;
+       }
+       sprintf(tmp, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec,
+               (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1));
+       debugl1(cs, tmp);
+       cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
+       memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int));
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
+               cs->hw.njet.base + NETJET_DMA_WRITE_START);
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE/2 - 1),
+               cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
+       outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1),
+               cs->hw.njet.base + NETJET_DMA_WRITE_END);
+       sprintf(tmp, "tiger: dmacfg  %x/%x  pulse=%d",
+               inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+               inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+               bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+       debugl1(cs, tmp);
+       cs->hw.njet.last_is0 = 0;
+       cs->bcs[0].BC_SetStack = setstack_tiger;
+       cs->bcs[1].BC_SetStack = setstack_tiger;
+       cs->bcs[0].BC_Close = close_tigerstate;
+       cs->bcs[1].BC_Close = close_tigerstate;
+}
+
+void
+releasetiger(struct IsdnCardState *cs)
+{
+       if (cs->bcs[0].hw.tiger.send) {
+               kfree(cs->bcs[0].hw.tiger.send);
+               cs->bcs[0].hw.tiger.send = NULL;
+       }
+       if (cs->bcs[1].hw.tiger.send) {
+               cs->bcs[1].hw.tiger.send = NULL;
+       }
+       if (cs->bcs[0].hw.tiger.rec) {
+               kfree(cs->bcs[0].hw.tiger.rec);
+               cs->bcs[0].hw.tiger.rec = NULL;
+       }
+       if (cs->bcs[1].hw.tiger.rec) {
+               cs->bcs[1].hw.tiger.rec = NULL;
+       }
+}
+
+static void
+netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, sval, stat = 1;
+       char tmp[128];
+
+       if (!cs) {
+               printk(KERN_WARNING "NETjet: Spurious interrupt!\n");
+               return;
+       }
+       if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
+               NETJET_ISACIRQ)) {
+               val = ReadISAC(cs, ISAC_ISTA);
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "tiger: i1 %x %x", sval, val);
+                       debugl1(cs, tmp);
+               }
+               if (val) {
+                       isac_interrupt(cs, val);
+                       stat |= 2;
+               }
+       }
+       if ((cs->hw.njet.irqstat0 = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
+/*             sprintf(tmp, "tiger: ist0 %x  %x %x  %x/%x  pulse=%d",
+                       sval, 
+                       bytein(cs->hw.njet.base + NETJET_DMACTRL),
+                       bytein(cs->hw.njet.base + NETJET_IRQMASK0),
+                       inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
+                       inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
+                       bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
+               debugl1(cs, tmp);
+*/
+               if (cs->hw.njet.last_is0 & cs->hw.njet.irqstat0 & 0xf) {
+                       sprintf(tmp, "tiger: ist0 %x->%x irq lost",
+                               cs->hw.njet.last_is0, cs->hw.njet.irqstat0);
+                       debugl1(cs, tmp);
+               }
+               cs->hw.njet.last_is0 = cs->hw.njet.irqstat0;
+/*             cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
+*/             byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
+/*             byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
+*/             if (cs->hw.njet.irqstat0 & 0x0c)
+                       read_tiger(cs);
+               if (cs->hw.njet.irqstat0 & 0x03)
+                       write_tiger(cs);
+       }
+/*     if (!testcnt--) {
+               cs->hw.njet.dmactrl = 0;
+               byteout(cs->hw.njet.base + NETJET_DMACTRL,
+                       cs->hw.njet.dmactrl);
+               byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+       }
+*/     if (stat & 2) {
+               WriteISAC(cs, ISAC_MASK, 0xFF);
+               WriteISAC(cs, ISAC_MASK, 0x0);
+       }
+}
+
+static void
+reset_netjet(struct IsdnCardState *cs)
+{
+       long flags;
+
+       save_flags(flags);
+       sti();
+       cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+       schedule();
+       cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+       byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+       schedule();
+       restore_flags(flags);
+       cs->hw.njet.auxd = 0;
+       cs->hw.njet.dmactrl = 0;
+       byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+       byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+       byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+}
+
+void
+release_io_netjet(struct IsdnCardState *cs)
+{
+       byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+       byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
+       releasetiger(cs);
+       release_region(cs->hw.njet.base, 256);
+}
+
+
+static int
+NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_netjet(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_netjet(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &netjet_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       inittiger(cs);
+                       clear_pending_isac_ints(cs);
+                       initisac(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+
+
+static         int pci_index __initdata = 0;
+
+__initfunc(int
+setup_netjet(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+#if CONFIG_PCI
+       u_char pci_bus, pci_device_fn, pci_irq;
+       u_int pci_ioaddr, found;
+#endif
+
+       strcpy(tmp, NETjet_revision);
+       printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_NETJET)
+               return(0);
+#if CONFIG_PCI
+       found = 0;
+       for (; pci_index < 0xff; pci_index++) {
+               if (pcibios_find_device(PCI_VENDOR_TRAVERSE_TECH,
+                       PCI_NETJET_ID, pci_index, &pci_bus, &pci_device_fn)
+                       == PCIBIOS_SUCCESSFUL)
+                       found = 1;
+               else
+                       break;
+               /* get IRQ */
+               pcibios_read_config_byte(pci_bus, pci_device_fn,
+                       PCI_INTERRUPT_LINE, &pci_irq);
+
+               /* get IO address */
+               pcibios_read_config_dword(pci_bus, pci_device_fn,
+                       PCI_BASE_ADDRESS_0, &pci_ioaddr);
+               if (found)
+                       break;
+       }
+       if (!found) {
+               printk(KERN_WARNING "NETjet: No PCI card found\n");
+               return(0);
+       }
+       if (!pci_irq) {
+               printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
+               return(0);
+       }
+       if (!pci_ioaddr) {
+               printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
+               return(0);
+       }
+       pci_ioaddr &= ~3; /* remove io/mem flag */
+       cs->hw.njet.base = pci_ioaddr; 
+       cs->hw.njet.auxa = pci_ioaddr + NETJET_AUXDATA;
+       cs->hw.njet.isac = pci_ioaddr | NETJET_ISAC_OFF;
+       cs->irq = pci_irq;
+       bytecnt = 256;
+#else
+       printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n");
+       printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n");
+       return (0);
+#endif /* CONFIG_PCI */
+       printk(KERN_INFO
+               "NETjet: PCI card configured at 0x%x IRQ %d\n",
+               cs->hw.njet.base, cs->irq);
+       if (check_region(cs->hw.njet.base, bytecnt)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.njet.base,
+                      cs->hw.njet.base + bytecnt);
+               return (0);
+       } else {
+               request_region(cs->hw.njet.base, bytecnt, "netjet isdn");
+       }
+       reset_netjet(cs);
+       cs->readisac  = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo  = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg  = &dummyrr;
+       cs->BC_Write_Reg = &dummywr;
+       cs->BC_Send_Data = &fill_dma;
+       cs->cardmsg = &NETjet_card_msg;
+       ISACVersion(cs, "NETjet:");
+       return (1);
+}
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
new file mode 100644 (file)
index 0000000..1d7d7e5
--- /dev/null
@@ -0,0 +1,354 @@
+/* $Id: niccy.c,v 1.2 1998/02/11 17:31:04 keil Exp $
+
+ * niccy.c  low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
+ *          compatible (SAGEM cybermodem)
+ *
+ * Author   Karsten Keil
+ * 
+ * Thanks to Dr. Neuhaus and SAGEM for informations
+ *
+ * $Log: niccy.c,v $
+ * Revision 1.2  1998/02/11 17:31:04  keil
+ * new file
+ *
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+extern const char *CardType[];
+const char *niccy_revision = "$Revision: 1.2 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define ISAC_PCI_DATA  0
+#define HSCX_PCI_DATA  1
+#define ISAC_PCI_ADDR  2
+#define HSCX_PCI_ADDR  3
+#define ISAC_PNP       0
+#define HSCX_PNP       1
+
+/* SUB Types */
+#define NICCY_PNP      1
+#define NICCY_PCI      2
+
+/* PCI stuff */
+#define PCI_VENDOR_DR_NEUHAUS  0x1267
+#define PCI_NICCY_ID           0x1016
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo read without cli because it's allready done  */
+
+       byteout(ale, off);
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readreg(cs->hw.niccy.hscx_ale,
+                       cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.niccy.hscx_ale,
+                cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
+               cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
+               cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
+               cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
+               cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "Niccy: Spurious interrupt!\n");
+               return;
+       }
+       val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+       if (val) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (stat & 1) {
+               writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
+               writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
+       }
+}
+
+void
+release_io_niccy(struct IsdnCardState *cs)
+{
+       if (cs->subtyp == NICCY_PCI)
+               release_region(cs->hw.niccy.isac, 4);
+       else {
+               release_region(cs->hw.niccy.isac, 2);
+               release_region(cs->hw.niccy.isac_ale, 2);
+       }
+}
+
+static void
+niccy_reset(struct IsdnCardState *cs)
+{
+       // No reset procedure known
+}
+
+static int
+niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       niccy_reset(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_niccy(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &niccy_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+static         int pci_index __initdata = 0;
+
+__initfunc(int
+setup_niccy(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, niccy_revision);
+       printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_NICCY)
+               return (0);
+
+       if (card->para[1]) {
+               cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
+               cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
+               cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
+               cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
+               cs->hw.niccy.cfg_reg = 0;
+               cs->subtyp = NICCY_PNP;
+               cs->irq = card->para[0];
+               if (check_region((cs->hw.niccy.isac), 2)) {
+                       printk(KERN_WARNING
+                               "HiSax: %s data port %x-%x already in use\n",
+                               CardType[card->typ],
+                               cs->hw.niccy.isac,
+                               cs->hw.niccy.isac + 1);
+                       return (0);
+               } else
+                       request_region(cs->hw.niccy.isac, 2, "niccy data");
+               if (check_region((cs->hw.niccy.isac_ale), 2)) {
+                       printk(KERN_WARNING
+                               "HiSax: %s address port %x-%x already in use\n",
+                               CardType[card->typ],
+                               cs->hw.niccy.isac_ale,
+                               cs->hw.niccy.isac_ale + 1);
+                       release_region(cs->hw.niccy.isac, 2);
+                       return (0);
+               } else
+                       request_region(cs->hw.niccy.isac_ale, 2, "niccy addr");
+       } else {
+#if CONFIG_PCI
+               u_char pci_bus, pci_device_fn, pci_irq;
+               u_int pci_ioaddr;
+
+               cs->subtyp = 0;
+               for (; pci_index < 0xff; pci_index++) {
+                       if (pcibios_find_device(PCI_VENDOR_DR_NEUHAUS,
+                          PCI_NICCY_ID, pci_index, &pci_bus, &pci_device_fn)
+                          == PCIBIOS_SUCCESSFUL)
+                               cs->subtyp = NICCY_PCI;
+                       else
+                               break;
+                       /* get IRQ */
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                               PCI_INTERRUPT_LINE, &pci_irq);
+
+                       /* get IO address */
+                       /* if it won't work try the other PCI addresses
+                        * PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5
+                        */
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_2, &pci_ioaddr);
+                       if (cs->subtyp)
+                               break;
+               }
+               if (!cs->subtyp) {
+                       printk(KERN_WARNING "Niccy: No PCI card found\n");
+                       return(0);
+               }
+               if (!pci_irq) {
+                       printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+                       return(0);
+               }
+
+               if (!pci_ioaddr) {
+                       printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+                       return(0);
+               }
+               pci_ioaddr &= ~3; /* remove io/mem flag */
+               cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
+               cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
+               cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
+               cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
+               cs->irq = pci_irq;
+               if (check_region((cs->hw.niccy.isac), 4)) {
+                       printk(KERN_WARNING
+                               "HiSax: %s data port %x-%x already in use\n",
+                               CardType[card->typ],
+                               cs->hw.niccy.isac,
+                               cs->hw.niccy.isac + 4);
+                       return (0);
+               } else
+                       request_region(cs->hw.niccy.isac, 4, "niccy");
+#else
+               printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
+               printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
+               return (0);
+#endif /* CONFIG_PCI */
+       }
+       printk(KERN_INFO
+               "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
+               CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+               cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
+       niccy_reset(cs);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &niccy_card_msg;
+       ISACVersion(cs, "Niccy:");
+       if (HscxVersion(cs, "Niccy:")) {
+               printk(KERN_WARNING
+                   "Niccy: wrong HSCX versions check IO address\n");
+               release_io_niccy(cs);
+               return (0);
+       }
+       return (1);
+}
index 1e1ee47723c0b25b4da1ee8084e2ea0b5041ff18..a0ba3645a5cae01c9da20e7bc053cded3486d99d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.5 1997/04/06 22:56:43 keil Exp $
+/* $Id: q931.c,v 1.6 1997/07/27 21:09:44 keil Exp $
 
  * q931.c       code to decode ITU Q.931 call control messages
  *
@@ -14,6 +14,9 @@
  *
  *
  * $Log: q931.c,v $
+ * Revision 1.6  1997/07/27 21:09:44  keil
+ * move functions to isdnl3.c
+ *
  * Revision 1.5  1997/04/06 22:56:43  keil
  * Some cosmetic changes
  *
 #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)
 {
@@ -88,14 +53,6 @@ iecpy(u_char * dest, u_char * iestart, int ieoffset)
        *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
  */
diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c
new file mode 100644 (file)
index 0000000..16938bc
--- /dev/null
@@ -0,0 +1,539 @@
+/* $Id: rawhdlc.c,v 1.2 1998/02/09 10:53:51 keil Exp $
+
+ * rawhdlc.c     support routines for cards that don't support HDLC
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *            Brent Baccala <baccala@FreeSoft.org>
+ *
+ *
+ * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
+ * don't perform HDLC encapsulation over the B channel.  Drivers for
+ * such cards use support routines in this file to perform B channel HDLC.
+ *
+ * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
+ * over a continuously transmitting serial communications link.
+ * It looks like this:
+ *
+ *      11111111101111110...........0111111011111111111
+ *      iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
+ *
+ *      i = idle     f = flag     d = data
+ *
+ * When idle, the channel sends a continuous string of ones (mark
+ * idle; illustrated), or a continuous string of flag characters (flag
+ * idle).  The beginning of a data frame is marked by a flag character
+ * (01111110), then comes the actual data, followed by another flag
+ * character, after which another frame may be sent immediately (a
+ * single flag may serve as both the end of one frame and the start of
+ * the next), or the link may return to idle.  Obviously, the flag
+ * character can not appear anywhere in the data (or a false
+ * end-of-frame would occur), so the transmitter performs
+ * "bit-stuffing" - inserting a zero bit after every five one bits,
+ * irregardless of the original bit after the five ones.  Byte
+ * ordering is irrelevent at this point - the data is treated as a
+ * string of bits, not bytes.  Since no more than 5 ones may now occur
+ * in a row, the flag sequence, with its 6 ones, is unique.
+ *
+ * Upon reception, a zero bit that occur after 5 one bits is simply
+ * discarded.  A series of 6 one bits is end-of-frame, and a series of
+ * 7 one bits is an abort.  Once bit-stuffing has been corrected for,
+ * an integer number of bytes should now be present.  The last two
+ * of these bytes form the Frame Check Sequence, a CRC that is verified
+ * and then discarded.  Note that bit-stuffing is performed on the FCS
+ * just as if it were regular data.
+ *
+ *
+ *
+ * int make_raw_hdlc_data(u_char *src, u_int slen,
+ *                        u_char *dst, u_int dsize)
+ *
+ *   Used for transmission.  Copies slen bytes from src to dst, performing
+ *   HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
+ *   dsize is size of destination buffer, and should be at least
+ *   ((6*slen)/5)+5 bytes to ensure adequate space will be available.
+ *   Function returns length (in bytes) of valid destination buffer, or
+ *   0 upon destination overflow.
+ *
+ * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
+ *
+ *   Initializes hdlc_state structure before first call to read_raw_hdlc_data
+ *
+ *   mode = 0: Sane mode
+ *   mode = 1/2: 
+ *             Insane mode; NETJet use a shared unsigned int memory block (
+ *            with busmaster DMA), the bit pattern of every word is 
+ *            <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
+ *            according to Siemens IOM-2 interface, so we have to handle
+ *             the src buffer as unsigned int and have to shift/mask the
+ *             B-channel bytes.
+ *             mode 1 -> B1  mode 2  -> B2 data is used
+ *
+ * int read_raw_hdlc_data(struct hdlc_state *saved_state,
+ *                        u_char *src, u_int slen,
+ *                        u_char *dst, u_int dsize)
+ *
+ *   Used for reception.  Scans source buffer bit-by-bit looking for
+ *   valid HDLC frames, which are copied to destination buffer.  HDLC
+ *   state information is stored in a structure, which allows this
+ *   function to process frames spread across several blocks of raw
+ *   HDLC data.  Part of the state information is bit offsets into
+ *   the source and destination buffers.
+ *
+ *   A return value >0 indicates the length of a valid frame, now
+ *   stored in the destination buffer.  In this case, the source
+ *   buffer might not be completely processed, so this function should
+ *   be called again with the same source buffer, possibly with a
+ *   different destination buffer.
+ *
+ *   A return value of zero indicates that the source buffer was
+ *   completely processed without finding a valid end-of-packet;
+ *   however, we might be in the middle of packet reception, so
+ *   the function should be called again with the next block of
+ *   raw HDLC data and the same destination buffer.  It is NOT
+ *   permitted to change the destination buffer in this case,
+ *   since data may already have begun to be stored there.
+ *
+ *   A return value of -1 indicates some kind of error - destination
+ *   buffer overflow, CRC check failed, frame not a multiple of 8
+ *   bits.  Destination buffer probably contains invalid data, which
+ *   should be discarded.  Call function again with same source buffer
+ *   and a new (or same) destination buffer.
+ *
+ *   Suggested calling sequence:
+ *
+ *      init_hdlc_state(...);
+ *      for (EACH_RAW_DATA_BLOCK) {
+ *         while (len = read_raw_hdlc_data(...)) {
+ *             if (len == -1) DISCARD_FRAME;
+ *             else PROCESS_FRAME;
+ *         }
+ *      }
+ *
+ *
+ * Test the code in this file as follows:
+ *    gcc -DDEBUGME -o rawhdlctest rawhdlc.c
+ *    ./rawhdlctest < rawdata
+ *
+ * The file "rawdata" can be easily generated from a HISAX B-channel
+ * hex dump (CF CF CF 02 ...) using the following perl script:
+ *
+ * while(<>) {
+ *     @hexlist = split ' ';
+ *     while ($hexstr = shift(@hexlist)) {
+ *         printf "%c", hex($hexstr);
+ *     }
+ * }
+ *
+ */
+
+#ifdef DEBUGME
+#include <stdio.h>
+#endif
+
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include "rawhdlc.h"
+
+/* There's actually an identical copy of this table in the PPP code
+ * (ppp_crc16_table), but I don't want this code dependant on PPP
+ */
+
+// static 
+__u16 fcstab[256] =
+{
+       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define HDLC_ZERO_SEARCH 0
+#define HDLC_FLAG_SEARCH 1
+#define HDLC_FLAG_FOUND  2
+#define HDLC_FRAME_FOUND 3
+#define HDLC_NULL 4
+#define HDLC_PART 5
+#define HDLC_FULL 6
+
+#define HDLC_FLAG_VALUE        0x7e
+
+
+#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
+                       bitcnt++;\
+                       out_val >>= 1;\
+                       if (val & 1) {\
+                               s_one++;\
+                               out_val |= 0x80;\
+                       } else {\
+                               s_one = 0;\
+                               out_val &= 0x7f;\
+                       }\
+                       if (bitcnt==8) {\
+                               if (d_cnt == dsize) return 0;\
+                               dst[d_cnt++] = out_val;\
+                               bitcnt = 0;\
+                       }\
+                       if (s_one == 5) {\
+                               out_val >>= 1;\
+                               out_val &= 0x7f;\
+                               bitcnt++;\
+                               s_one = 0;\
+                       }\
+                       if (bitcnt==8) {\
+                               if (d_cnt == dsize) return 0;\
+                               dst[d_cnt++] = out_val;\
+                               bitcnt = 0;\
+                       }\
+                       val >>= 1;\
+               }
+
+/* Optimization suggestion: If needed, this function could be
+ * dramatically sped up using a state machine.  Each state would
+ * correspond to having seen N one bits, and being offset M bits into
+ * the current output byte.  N ranges from 0 to 4, M from 0 to 7, so
+ * we need 5*8 = 35 states.  Each state would have a table with 256
+ * entries, one for each input character.  Each entry would contain
+ * three output characters, an output state, an a byte increment
+ * that's either 1 or 2.  All this could fit in four bytes; so we need
+ * 4 bytes * 256 characters = 1 KB for each state (35 KB total).  Zero
+ * the output buffer before you start.  For each character in your
+ * input, you look it up in the current state's table and get three
+ * bytes to be or'ed into the output at the current byte offset, and
+ * an byte increment to move your pointer forward.  A simple Perl
+ * script could generate the tables.  Given HDLC semantics, probably
+ * would be better to set output to all 1s, then use ands instead of ors.
+ * A smaller state machine could operate on nibbles instead of bytes.
+ * A state machine for 32-bit architectures could use word offsets
+ * instead of byte offsets, requiring 5*32 = 160 states; probably
+ * best to work on nibbles in such a case.
+ */
+
+
+int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize)
+{
+       register u_int i,d_cnt=0;
+       register u_char j;
+       register u_char val;
+       register u_char s_one = 0;
+       register u_char out_val = 0;
+       register u_char bitcnt = 0;
+       u_int fcs;
+       
+       
+       dst[d_cnt++] = HDLC_FLAG_VALUE;
+       fcs = PPP_INITFCS;
+       for (i=0; i<slen; i++) {
+               val = src[i];
+               fcs = PPP_FCS (fcs, val);
+               MAKE_RAW_BYTE;
+       }
+       fcs ^= 0xffff;
+       val = fcs & 0xff;
+       MAKE_RAW_BYTE;
+       val = (fcs>>8) & 0xff;
+       MAKE_RAW_BYTE;
+       val = HDLC_FLAG_VALUE;
+       for (j=0; j<8; j++) { 
+               bitcnt++;
+               out_val >>= 1;
+               if (val & 1)
+                       out_val |= 0x80;
+               else
+                       out_val &= 0x7f;
+               if (bitcnt==8) {
+                       if (d_cnt == dsize) return 0;
+                       dst[d_cnt++] = out_val;
+                       bitcnt = 0;
+               }
+               val >>= 1;
+       }
+       if (bitcnt) {
+               while (8>bitcnt++) {
+                       out_val >>= 1;
+                       out_val |= 0x80;
+               }
+               if (d_cnt == dsize) return 0;
+               dst[d_cnt++] = out_val;
+       }
+
+       return d_cnt;
+}
+
+void init_hdlc_state(struct hdlc_state *stateptr, int mode)
+{
+       stateptr->state = HDLC_ZERO_SEARCH;
+       stateptr->r_one = 0;
+       stateptr->r_val = 0;
+       stateptr->o_bitcnt = 0;
+       stateptr->i_bitcnt = 0;
+       stateptr->insane_mode = mode;
+}
+
+/* Optimization suggestion: A similar state machine could surely
+ * be developed for this function as well.
+ */
+
+int read_raw_hdlc_data(struct hdlc_state *saved_state,
+                       u_char *src, u_int slen, u_char *dst, u_int dsize)
+{
+       int retval=0;
+       register u_char val;
+       register u_char state = saved_state->state;
+       register u_char r_one = saved_state->r_one;
+       register u_char r_val = saved_state->r_val;
+       register u_int o_bitcnt = saved_state->o_bitcnt;
+       register u_int i_bitcnt = saved_state->i_bitcnt;
+       register u_int fcs    = saved_state->fcs;
+       register u_int *isrc = (u_int *) src;
+        
+       /* Use i_bitcnt (bit offset into source buffer) to reload "val"
+        * in case we're starting up again partway through a source buffer
+        */
+
+       if ((i_bitcnt >> 3) < slen) {
+               if (saved_state->insane_mode==1) {
+                       val = isrc[(i_bitcnt >> 3)] & 0xff;
+               } else if (saved_state->insane_mode==2) {
+                       val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
+               } else {
+                       val = src[i_bitcnt >> 3];
+               }
+               val >>= i_bitcnt & 7;
+       }
+
+       /* One bit per loop.  Keep going until we've got something to
+        * report (retval != 0), or we exhaust the source buffer
+        */
+
+       while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
+               if ((i_bitcnt & 7) == 0) {
+                       if (saved_state->insane_mode==1) {
+                               val = isrc[(i_bitcnt >> 3)] & 0xff;
+                       } else if (saved_state->insane_mode==2) {
+                               val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
+                       } else {
+                               val = src[i_bitcnt >> 3];
+                       }
+#ifdef DEBUGME
+                       printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
+#endif
+                       if (val == 0xff) {
+                               state = HDLC_ZERO_SEARCH;
+                               o_bitcnt = 0;
+                               r_one = 0;
+                               i_bitcnt += 8;
+                               continue;
+                       }
+               }
+
+#ifdef DEBUGME
+               /* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
+#endif
+
+               if (state == HDLC_ZERO_SEARCH) {
+                       if (val & 1) {
+                               r_one++;
+                       } else {
+                               r_one=0;
+                               state= HDLC_FLAG_SEARCH;
+                       }
+               } else if (state == HDLC_FLAG_SEARCH) { 
+                       if (val & 1) {
+                               r_one++;
+                               if (r_one>6) {
+                                       state=HDLC_ZERO_SEARCH;
+                               }
+                       } else {
+                               if (r_one==6) {
+                                       o_bitcnt=0;
+                                       r_val=0;
+                                       state=HDLC_FLAG_FOUND;
+                               }
+                               r_one=0;
+                       }
+               } else if (state ==  HDLC_FLAG_FOUND) {
+                       if (val & 1) {
+                               r_one++;
+                               if (r_one>6) {
+                                       state=HDLC_ZERO_SEARCH;
+                               } else {
+                                       r_val >>= 1;
+                                       r_val |= 0x80;
+                                       o_bitcnt++;
+                               }
+                       } else {
+                               if (r_one==6) {
+                                       o_bitcnt=0;
+                                       r_val=0;
+                                       r_one=0;
+                                       i_bitcnt++;
+                                       val >>= 1;
+                                       continue;
+                               } else if (r_one!=5) {
+                                       r_val >>= 1;
+                                       r_val &= 0x7f;
+                                       o_bitcnt++;
+                               }
+                               r_one=0;        
+                       }
+                       if ((state != HDLC_ZERO_SEARCH) &&
+                               !(o_bitcnt & 7)) {
+#ifdef DEBUGME
+                               printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
+#endif
+                               state=HDLC_FRAME_FOUND;
+                               fcs = PPP_INITFCS;
+                               dst[0] = r_val;
+                               fcs = PPP_FCS (fcs, r_val);
+                       }
+               } else if (state ==  HDLC_FRAME_FOUND) {
+                       if (val & 1) {
+                               r_one++;
+                               if (r_one>6) {
+                                       state=HDLC_ZERO_SEARCH;
+                                       o_bitcnt=0;
+                               } else {
+                                       r_val >>= 1;
+                                       r_val |= 0x80;
+                                       o_bitcnt++;
+                               }
+                       } else {
+                               if (r_one==6) {
+                                       r_val=0; 
+                                       r_one=0;
+                                       o_bitcnt++;
+                                       if (o_bitcnt & 7) {
+                                               /* Alignment error */
+#ifdef DEBUGME
+                                               printf("Alignment error\n");
+#endif
+                                               state=HDLC_FLAG_SEARCH;
+                                               retval = -1;
+                                       } else if (fcs==PPP_GOODFCS) {
+                                               /* Valid frame */
+                                               state=HDLC_FLAG_FOUND;
+                                               retval = (o_bitcnt>>3)-3;
+                                       } else {
+                                               /* CRC error */
+#ifdef DEBUGME
+                                               printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
+#endif
+                                               state=HDLC_FLAG_FOUND;
+                                               retval = -1;
+                                       }
+                               } else if (r_one==5) {
+                                       r_one=0;
+                                       i_bitcnt++;
+                                       val >>= 1;
+                                       continue;
+                               } else {
+                                       r_val >>= 1;
+                                       r_val &= 0x7f;
+                                       o_bitcnt++;
+                               }
+                               r_one=0;        
+                       }
+                       if ((state == HDLC_FRAME_FOUND) &&
+                               !(o_bitcnt & 7)) {
+                               if ((o_bitcnt>>3)>=dsize) {
+                                       /* Buffer overflow error */
+#ifdef DEBUGME
+                                       printf("Buffer overflow error\n");
+#endif
+                                       r_val=0; 
+                                       state=HDLC_FLAG_SEARCH;
+                                       retval = -1;
+                               } else {
+                                       dst[(o_bitcnt>>3)-1] = r_val;
+                                       fcs = PPP_FCS (fcs, r_val);
+#ifdef DEBUGME
+                                       printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
+#endif
+                               }
+                       }
+               }
+               i_bitcnt ++;
+               val >>= 1;
+       }
+
+       /* We exhausted the source buffer before anything else happened
+        * (retval==0).  Reset i_bitcnt in expectation of a new source
+        * buffer.  Other, we either had an error or a valid frame, so
+        * reset o_bitcnt in expectation of a new destination buffer.
+        */
+
+       if (retval == 0) {
+               i_bitcnt = 0;
+       } else {
+               o_bitcnt = 0;
+       }
+
+       saved_state->state = state;
+       saved_state->r_one = r_one;
+       saved_state->r_val = r_val;
+       saved_state->fcs = fcs;
+       saved_state->o_bitcnt = o_bitcnt;
+       saved_state->i_bitcnt = i_bitcnt;
+
+       return (retval);
+}
+
+
+
+#ifdef DEBUGME
+
+char buffer[1024];
+char obuffer[1024];
+
+main()
+{
+  int buflen=0;
+  int len;
+  struct hdlc_state hdlc_state;
+
+  while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
+
+  printf("buflen = %d\n", buflen);
+
+  init_hdlc_state(&hdlc_state, 0);
+
+  while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
+    if (len == -1) printf("Error @ byte %d/bit %d\n",
+                         hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
+    else {
+      printf("Frame received: len %d\n", len);
+    }
+  }
+
+  printf("Done\n");
+}
+
+#endif
diff --git a/drivers/isdn/hisax/rawhdlc.h b/drivers/isdn/hisax/rawhdlc.h
new file mode 100644 (file)
index 0000000..d946fa0
--- /dev/null
@@ -0,0 +1,26 @@
+/* $Id: rawhdlc.h,v 1.2 1998/02/09 10:53:53 keil Exp $
+
+ * rawhdlc.h     support routines for cards that don't support HDLC
+ *
+ * Author     Brent Baccala <baccala@FreeSoft.org>
+ *
+ */
+
+#ifndef RAWHDLC_H
+struct hdlc_state {
+       char insane_mode;
+       u_char state;
+       u_char r_one;
+       u_char r_val;
+       u_int o_bitcnt;
+       u_int i_bitcnt;
+       u_int fcs;
+};
+
+
+int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize);
+void init_hdlc_state(struct hdlc_state *stateptr, int mode);
+int read_raw_hdlc_data(struct hdlc_state *saved_state,
+                       u_char *src, u_int slen, u_char *dst, u_int dsize);
+#define RAWHDLC_H
+#endif
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
new file mode 100644 (file)
index 0000000..40dc8e6
--- /dev/null
@@ -0,0 +1,356 @@
+/* $Id: sedlbauer.c,v 1.6 1998/02/09 18:46:06 keil Exp $
+
+ * sedlbauer.c  low level stuff for Sedlbauer cards
+ *              includes Support for the Sedlbauer Speed Star 
+ *              derived from the original file dynalink.c from Karsten Keil
+ *
+ * Copyright (C) 1997,1998 Marcus Niemann (for the modifications to
+ *                                         the original file dynalink.c)
+ *
+ * Author     Marcus Niemann (niemann@www-bib.fh-bielefeld.de)
+ *
+ * Thanks to  Karsten Keil
+ *            Sedlbauer AG for informations
+ *            Edgar Toernig
+ *
+ * $Log: sedlbauer.c,v $
+ * Revision 1.6  1998/02/09 18:46:06  keil
+ * Support for Sedlbauer PCMCIA (Marcus Niemann)
+ *
+ * Revision 1.5  1998/02/02 13:29:45  keil
+ * fast io
+ *
+ * Revision 1.4  1997/11/08 21:35:52  keil
+ * new l1 init
+ *
+ * Revision 1.3  1997/11/06 17:09:28  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 18:55:52  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1  1997/09/11 17:32:04  keil
+ * new
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *Sedlbauer_revision = "$Revision: 1.6 $";
+
+const char *Sedlbauer_Types[] =
+{"None", "Speed Card", "Speed Win", "Speed Star"};
+#define SEDL_SPEED_CARD 1
+#define SEDL_SPEED_WIN  2
+#define SEDL_SPEED_STAR 3
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define SEDL_RESET_ON  0
+#define SEDL_RESET_OFF 1
+#define SEDL_ISAC      2
+#define SEDL_HSCX      3
+#define SEDL_ADR       4
+
+#define SEDL_PCMCIA_RESET      0
+#define SEDL_PCMCIA_ISAC       1
+#define SEDL_PCMCIA_HSCX       2
+#define SEDL_PCMCIA_ADR                4
+
+#define SEDL_RESET      0x3    /* same as DOS driver */
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo read without cli because it's allready done  */
+
+       byteout(ale, off);
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readreg(cs->hw.sedl.adr,
+                       cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.sedl.adr,
+                cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
+               cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
+               cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
+
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
+               cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
+               cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
+               return;
+       }
+
+        if ((cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) && (*cs->busy_flag == 1)) {
+          /* The card tends to generate interrupts while being removed
+             causing us to just crash the kernel. bad. */
+          printk(KERN_WARNING "Sedlbauer: card not available!\n");
+          return;
+        }
+
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
+       if (val) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (stat & 1) {
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_sedlbauer(struct IsdnCardState *cs)
+{
+       int bytecnt = 8;
+
+       if (cs->hw.sedl.cfg_reg)
+               release_region(cs->hw.sedl.cfg_reg, bytecnt);
+}
+
+static void
+reset_sedlbauer(struct IsdnCardState *cs)
+{
+       long flags;
+
+       if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA) {
+               byteout(cs->hw.sedl.reset_on, SEDL_RESET);      /* Reset On */
+               save_flags(flags);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + 1;
+               schedule();
+               byteout(cs->hw.sedl.reset_off, 0);      /* Reset Off */
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + 1;
+               schedule();
+               restore_flags(flags);
+       }
+}
+
+static int
+Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_sedlbauer(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_sedlbauer(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &sedlbauer_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_sedlbauer(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Sedlbauer_revision);
+       printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
+               cs->subtyp = SEDL_SPEED_CARD;
+       } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {    
+               cs->subtyp = SEDL_SPEED_STAR;
+       } else
+               return (0);
+
+       bytecnt = 8;
+       cs->hw.sedl.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+       if (cs->subtyp == SEDL_SPEED_STAR) {
+               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ADR;
+               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ISAC;
+               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_HSCX;
+               cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET;
+               cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET;
+       } else {
+               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ADR;
+               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAC;
+               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX;
+               cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_RESET_ON;
+               cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_RESET_OFF;
+       }
+        
+       /* In case of the sedlbauer pcmcia card, this region is in use,
+           reserved for us by the card manager. So we do not check it
+           here, it would fail. */
+       if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA &&
+          check_region((cs->hw.sedl.cfg_reg), bytecnt)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.sedl.cfg_reg,
+                      cs->hw.sedl.cfg_reg + bytecnt);
+               return (0);
+       } else {
+               request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn");
+       }
+
+       printk(KERN_INFO
+              "Sedlbauer: defined at 0x%x IRQ %d\n",
+              cs->hw.sedl.cfg_reg,
+              cs->irq);
+       printk(KERN_WARNING
+                      "Sedlbauer %s uses ports 0x%x-0x%x\n",
+                      Sedlbauer_Types[cs->subtyp],
+                      cs->hw.sedl.cfg_reg,
+                      cs->hw.sedl.cfg_reg + bytecnt);
+
+       printk(KERN_INFO "Sedlbauer: resetting card\n");
+       reset_sedlbauer(cs);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Sedl_card_msg;
+       ISACVersion(cs, "Sedlbauer:");
+       if (HscxVersion(cs, "Sedlbauer:")) {
+               printk(KERN_WARNING
+                   "Sedlbauer: wrong HSCX versions check IO address\n");
+               release_io_sedlbauer(cs);
+               return (0);
+       }
+       return (1);
+}
diff --git a/drivers/isdn/hisax/siemens.h b/drivers/isdn/hisax/siemens.h
deleted file mode 100644 (file)
index f356a30..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* $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/sportster.c b/drivers/isdn/hisax/sportster.c
new file mode 100644 (file)
index 0000000..cb867a1
--- /dev/null
@@ -0,0 +1,291 @@
+/* $Id: sportster.c,v 1.5 1998/02/02 13:29:46 keil Exp $
+
+ * sportster.c     low level stuff for USR Sportster internal TA
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
+ *
+ * $Log: sportster.c,v $
+ * Revision 1.5  1998/02/02 13:29:46  keil
+ * fast io
+ *
+ * Revision 1.4  1997/11/08 21:35:52  keil
+ * new l1 init
+ *
+ * Revision 1.3  1997/11/06 17:09:29  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 18:51:18  keil
+ * New files
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:58  keil
+ * new files on 2.0
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+const char *sportster_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define         SPORTSTER_ISAC         0xC000
+#define         SPORTSTER_HSCXA        0x0000
+#define         SPORTSTER_HSCXB        0x4000
+#define         SPORTSTER_RES_IRQ      0x8000
+#define         SPORTSTER_RESET        0x80
+#define         SPORTSTER_INTE         0x40
+
+static inline int
+calc_off(unsigned int base, unsigned int off)
+{
+       return(base + ((off & 0xfc)<<8) + ((off & 3)<<1));
+}
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+       insb(adr, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (bytein(calc_off(cs->hw.spt.isac, offset)));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       byteout(calc_off(cs->hw.spt.isac, offset), value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       read_fifo(cs->hw.spt.isac, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       write_fifo(cs->hw.spt.isac, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
+#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val;
+
+       if (!cs) {
+               printk(KERN_WARNING "Sportster: Spurious interrupt!\n");
+               return;
+       }
+       val = READHSCX(cs, 1, HSCX_ISTA);
+      Start_HSCX:
+       if (val)
+               hscx_int_main(cs, val);
+       val = ReadISAC(cs, ISAC_ISTA);
+      Start_ISAC:
+       if (val)
+               isac_interrupt(cs, val);
+       val = READHSCX(cs, 1, HSCX_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = ReadISAC(cs, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       /* get a new irq impulse if there any pending */
+       bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
+}
+
+void
+release_io_sportster(struct IsdnCardState *cs)
+{
+       int i, adr;
+
+       byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
+       for (i=0; i<64; i++) {
+               adr = cs->hw.spt.cfg_reg + i *1024;
+               release_region(adr, 8);
+       }
+}
+
+void
+reset_sportster(struct IsdnCardState *cs)
+{
+       long flags;
+
+       cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
+       byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+       save_flags(flags);
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
+       byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       restore_flags(flags);
+}
+
+static int
+Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_sportster(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_sportster(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &sportster_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
+                       byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+get_io_range(struct IsdnCardState *cs))
+{
+       int i, j, adr;
+       
+       for (i=0;i<64;i++) {
+               adr = cs->hw.spt.cfg_reg + i *1024;
+               if (check_region(adr, 8)) {
+                       printk(KERN_WARNING
+                               "HiSax: %s config port %x-%x already in use\n",
+                               CardType[cs->typ], adr, adr + 8);
+                       break;
+               } else
+                       request_region(adr, 8, "sportster");
+       }
+       if (i==64)
+               return(1);
+       else {
+               for (j=0; j<i; j++) {
+                       adr = cs->hw.spt.cfg_reg + j *1024;
+                       release_region(adr, 8);
+               }
+               return(0);
+       }
+}
+
+__initfunc(int
+setup_sportster(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, sportster_revision);
+       printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_SPORTSTER)
+               return (0);
+
+       cs->hw.spt.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+       if (!get_io_range(cs))
+               return (0);
+       cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
+       cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
+       cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
+       
+       switch(cs->irq) {
+               case 5: cs->hw.spt.res_irq = 1;
+                       break;
+               case 7: cs->hw.spt.res_irq = 2;
+                       break;
+               case 10:cs->hw.spt.res_irq = 3;
+                       break;
+               case 11:cs->hw.spt.res_irq = 4;
+                       break;
+               case 12:cs->hw.spt.res_irq = 5;
+                       break;
+               case 14:cs->hw.spt.res_irq = 6;
+                       break;
+               case 15:cs->hw.spt.res_irq = 7;
+                       break;
+               default:release_io_sportster(cs);
+                       printk(KERN_WARNING "Sportster: wrong IRQ\n");
+                       return(0);
+       }
+       reset_sportster(cs);
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d cfg:0x%X\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.spt.cfg_reg);
+
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Sportster_card_msg;
+       ISACVersion(cs, "Sportster:");
+       if (HscxVersion(cs, "Sportster:")) {
+               printk(KERN_WARNING
+                      "Sportster: wrong HSCX versions check IO address\n");
+               release_io_sportster(cs);
+               return (0);
+       }
+       return (1);
+}
index d97595938536cee2df86e836980434c688222d38..a520787469aeb7c228b4b0cc77532fe3607ad594 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $
+/* $Id: tei.c,v 2.7 1998/02/12 23:08:11 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: tei.c,v $
- * Revision 1.8  1997/04/07 22:59:08  keil
- * GFP_KERNEL --> GFP_ATOMIC
+ * Revision 2.7  1998/02/12 23:08:11  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
- * Revision 1.7  1997/04/06 22:54:03  keil
- * Using SKB's
+ * Revision 2.6  1998/02/02 13:41:42  keil
+ * fix MDL_ASSIGN for PtP
  *
- * Revision 1.6  1997/02/09 00:25:12  keil
- * new interface handling, one interface per card
+ * Revision 2.5  1997/11/06 17:09:12  keil
+ * New 2.1 init code
  *
- * Revision 1.5  1997/01/27 15:57:51  keil
- * cosmetics
+ * Revision 2.4  1997/10/29 19:04:46  keil
+ * changes for 2.1
  *
- * Revision 1.4  1997/01/21 22:32:44  keil
- * Tei verify request
+ * Revision 2.3  1997/10/01 09:21:43  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
  *
- * Revision 1.3  1997/01/04 13:45:02  keil
- * cleanup,adding remove tei request (thanks to Sim Yskes)
+ * Revision 2.2  1997/07/31 19:24:39  keil
+ * fixed a warning
  *
- * Revision 1.2  1996/12/08 19:52:39  keil
- * minor debug fix
+ * Revision 2.1  1997/07/31 11:50:16  keil
+ * ONE TEI and FIXED TEI handling
  *
- * Revision 1.1  1996/10/13 20:04:57  keil
- * Initial revision
+ * Revision 2.0  1997/07/27 21:13:30  keil
+ * New TEI managment
  *
+ * Revision 1.9  1997/06/26 11:18:02  keil
+ * New managment
  *
+ * 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
+ *
+ * Old log removed/ KKe
  *
  */
 #define __NO_VERSION__
 #include "hisax.h"
+#include "isdnl2.h"
+#include <linux/random.h>
 
-extern struct IsdnCard cards[];
-extern int nrcards;
+const char *tei_revision = "$Revision: 2.7 $";
 
-const char *tei_revision = "$Revision: 1.8 $";
+#define ID_REQUEST     1
+#define ID_ASSIGNED    2
+#define ID_DENIED      3
+#define ID_CHK_REQ     4
+#define ID_CHK_RES     5
+#define ID_REMOVE      6
+#define ID_VERIFY      7
 
-static struct PStack *
-findces(struct PStack *st, int ces)
+#define TEI_ENTITY_ID  0xf
+
+static
+struct Fsm teifsm =
+{NULL, 0, 0, NULL, NULL};
+
+void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
+
+enum {
+       ST_TEI_NOP,
+       ST_TEI_IDREQ,
+       ST_TEI_IDVERIFY,
+};
+
+#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
+
+static char *strTeiState[] =
 {
-       struct PStack *ptr = *(st->l1.stlistp);
+       "ST_TEI_NOP",
+       "ST_TEI_IDREQ",
+       "ST_TEI_IDVERIFY",
+};
 
-       while (ptr)
-               if (ptr->l2.ces == ces)
-                       return (ptr);
-               else
-                       ptr = ptr->next;
-       return (NULL);
+enum {
+       EV_IDREQ,
+       EV_ASSIGN,
+       EV_DENIED,
+       EV_CHKREQ,
+       EV_REMOVE,
+       EV_VERIFY,
+       EV_T202,
+};
+
+#define TEI_EVENT_COUNT (EV_T202+1)
+
+static char *strTeiEvent[] =
+{
+       "EV_IDREQ",
+       "EV_ASSIGN",
+       "EV_DENIED",
+       "EV_CHKREQ",
+       "EV_REMOVE",
+       "EV_VERIFY",
+       "EV_T202",
+};
+
+unsigned int
+random_ri(void)
+{
+       unsigned int x;
+
+       get_random_bytes(&x, sizeof(x));
+       return (x & 0xffff);
 }
 
 static struct PStack *
@@ -72,246 +132,357 @@ findtei(struct PStack *st, int tei)
 }
 
 static void
-mdl_unit_data_res(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
 {
        struct sk_buff *skb;
        u_char *bp;
 
-       if (!(skb = alloc_skb(6 + MAX_HEADER_LEN, GFP_ATOMIC))) {
+       if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
                printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
                return;
        }
-       skb_reserve(skb, MAX_HEADER_LEN);
+       bp = skb_put(skb, 3);
+       bp[0] = (TEI_SAPI << 2);
+       bp[1] = (GROUP_TEI << 1) | 0x1;
+       bp[2] = UI;
        bp = skb_put(skb, 5);
-       bp[0] = 0xf;
+       bp[0] = TEI_ENTITY_ID;
        bp[1] = ri >> 8;
        bp[2] = ri & 0xff;
-       bp[3] = mt;
-       bp[4] = (ai << 1) | 1;
-       st->l3.l3l2(st, DL_UNIT_DATA, skb);
+       bp[3] = m_id;
+       bp[4] = (tei << 1) | 1;
+       st->l2.l2l1(st, PH_DATA_REQ, skb);
 }
 
 static void
-mdl_unit_data_ind(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+tei_id_request(struct FsmInst *fi, int event, void *arg)
 {
-       unsigned int tces;
-       struct PStack *otsp, *ptr;
+       struct PStack *st = fi->userdata;
        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);
-                       }
+       if (st->l2.tei != -1) {
+               sprintf(tmp, "assign request for allready asigned tei %d",
+                       st->l2.tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               return;
+       }
+       st->ma.ri = random_ri();
+       if (st->ma.debug) {
+               sprintf(tmp, "assign request ri %d", st->ma.ri);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
        }
+       put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
+       FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
+       FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
+       st->ma.N202 = 3;
 }
 
-void
-tei_handler(struct PStack *st,
-           u_char pr, struct sk_buff *skb)
+static void
+tei_id_assign(struct FsmInst *fi, int event, void *arg)
 {
-       u_char *bp;
-       unsigned int data;
-       char tmp[32];
+       struct PStack *ost, *st = fi->userdata;
+       struct sk_buff *skb = arg;
+       struct IsdnCardState *cs;
+       int ri, tei;
+       char tmp[64];
 
-       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);
-                       SET_SKB_FREE(skb);
-                       dev_kfree_skb(skb);
-                       break;
-               default:
-                       break;
+       ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
+       tei = skb->data[4] >> 1;
+       if (st->ma.debug) {
+               sprintf(tmp, "identity assign ri %d tei %d", ri, tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+       if ((ost = findtei(st, tei))) {         /* same tei is in use */
+               if (ri != ost->ma.ri) {
+                       sprintf(tmp, "possible duplicate assignment tei %d", tei);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       ost->l2.l2tei(ost, MDL_ERROR_REQ, NULL);
+               }
+       } else if (ri == st->ma.ri) {
+               FsmDelTimer(&st->ma.t202, 1);
+               FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+               st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) tei);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_ASSIGN_REQ, NULL);
        }
 }
 
-unsigned int
-randomces(void)
+static void
+tei_id_denied(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
+       int ri, tei;
+       char tmp[64];
+
+       ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
+       tei = skb->data[4] >> 1;
+       if (st->ma.debug) {
+               sprintf(tmp, "identity denied ri %d tei %d", ri, tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+}
+
+static void
+tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
+       int tei;
+       char tmp[64];
+
+       tei = skb->data[4] >> 1;
+       if (st->ma.debug) {
+               sprintf(tmp, "identity check req tei %d", tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+       if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
+               FsmDelTimer(&st->ma.t202, 4);
+               FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+               put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
+       }
+}
+
+static void
+tei_id_remove(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
+       struct IsdnCardState *cs;
+       int tei;
+       char tmp[64];
+
+       tei = skb->data[4] >> 1;
+       if (st->ma.debug) {
+               sprintf(tmp, "identity remove tei %d", tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+       if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
+               FsmDelTimer(&st->ma.t202, 5);
+               FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+               st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+       }
+}
+
+static void
+tei_id_verify(struct FsmInst *fi, int event, void *arg)
 {
-       int x = jiffies & 0xffff;
+       struct PStack *st = fi->userdata;
+       char tmp[64];
 
-       return (x);
+       if (st->ma.debug) {
+               sprintf(tmp, "id verify request for tei %d", st->l2.tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+       put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
+       FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
+       FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
+       st->ma.N202 = 2;
 }
 
 static void
-tei_man(struct PStack *sp, int i, void *v)
+tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
 {
+       struct PStack *st = fi->userdata;
+       char tmp[64];
+       struct IsdnCardState *cs;
 
-       printk(KERN_DEBUG "tei_man\n");
+       if (--st->ma.N202) {
+               st->ma.ri = random_ri();
+               if (st->ma.debug) {
+                       sprintf(tmp, "assign req(%d) ri %d",
+                               4 - st->ma.N202, st->ma.ri);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               }
+               put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
+               FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
+       } else {
+               sprintf(tmp, "assign req failed");
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               st->ma.manl2(st, MDL_ERROR_IND, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+               FsmChangeState(fi, ST_TEI_NOP);
+       }
+}
+
+static void
+tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       char tmp[64];
+       struct IsdnCardState *cs;
+
+       if (--st->ma.N202) {
+               if (st->ma.debug) {
+                       sprintf(tmp, "id verify req(%d) for tei %d",
+                               3 - st->ma.N202, st->l2.tei);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               }
+               put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
+               FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
+       } else {
+               sprintf(tmp, "verify req for tei %d failed", st->l2.tei);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+               FsmChangeState(fi, ST_TEI_NOP);
+       }
+}
+
+static void
+tei_l1l2(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       int mt;
+       char tmp[64];
+
+       if (pr == PH_DATA_IND) {
+               if (skb->len < 3) {
+                       sprintf(tmp, "short mgr frame %d/3", skb->len);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               } else if (((skb->data[0] >> 2) != TEI_SAPI) ||
+                          ((skb->data[1] >> 1) != GROUP_TEI)) {
+                       sprintf(tmp, "wrong mgr sapi/tei %x/%x",
+                               skb->data[0], skb->data[1]);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               } else if ((skb->data[2] & 0xef) != UI) {
+                       sprintf(tmp, "mgr frame is not ui %x",
+                               skb->data[2]);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               } else {
+                       skb_pull(skb, 3);
+                       if (skb->len < 5) {
+                               sprintf(tmp, "short mgr frame %d/5", skb->len);
+                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       } else if (skb->data[0] != TEI_ENTITY_ID) {
+                               /* wrong management entity identifier, ignore */
+                               sprintf(tmp, "tei handler wrong entity id %x\n",
+                                       skb->data[0]);
+                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       } else {
+                               mt = skb->data[3];
+                               if (mt == ID_ASSIGNED)
+                                       FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
+                               else if (mt == ID_DENIED)
+                                       FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
+                               else if (mt == ID_CHK_REQ)
+                                       FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
+                               else if (mt == ID_REMOVE)
+                                       FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
+                               else {
+                                       sprintf(tmp, "tei handler wrong mt %x\n",
+                                               mt);
+                                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                               }
+                       }
+               }
+       } else {
+               sprintf(tmp, "tei handler wrong pr %x\n", pr);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+       }
+       dev_kfree_skb(skb);
 }
 
 static void
 tei_l2tei(struct PStack *st, int pr, void *arg)
 {
-       struct IsdnCardState *sp = st->l1.hardware;
+       switch (pr) {
+               case (MDL_ASSIGN_IND):
+#ifdef TEI_FIXED
+                       if (st->ma.debug) {
+                               char tmp[64];
+                               sprintf(tmp, "fixed assign tei %d", TEI_FIXED);
+                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       }
+                       st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) TEI_FIXED);
+#else
+                       FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
+#endif
+                       break;
+               case (MDL_ERROR_REQ):
+                       FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
+                       break;
+               default:
+                       break;
+       }
+}
+
+static void
+tei_debug(struct FsmInst *fi, char *s)
+{
+       struct PStack *st = fi->userdata;
+       char tm[32], str[256];
 
-       tei_handler(sp->teistack, pr, arg);
+       jiftime(tm, jiffies);
+       sprintf(str, "%s Tei %s\n", tm, s);
+       HiSax_putstatus(st->l1.hardware, str);
 }
 
 void
 setstack_tei(struct PStack *st)
 {
        st->l2.l2tei = tei_l2tei;
+       st->ma.T202 = 2000;     /* T202  2000 milliseconds */
+       st->l1.l1tei = tei_l1l2;
+       st->ma.debug = 1;
+       st->ma.tei_m.fsm = &teifsm;
+       st->ma.tei_m.state = ST_TEI_NOP;
+       st->ma.tei_m.debug = 1;
+       st->ma.tei_m.userdata = st;
+       st->ma.tei_m.userint = 0;
+       st->ma.tei_m.printdebug = tei_debug;
+       FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
 }
 
 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;
+}
+
+void
+release_tei(struct IsdnCardState *cs)
+{
+       struct PStack *st = cs->stlist;
 
-       sprintf(tmp, "Card %d tei", sp->cardnr + 1);
-       setstack_isdnl2(st, tmp);
-       st->l2.debug = 0;
-       st->l3.debug = 0;
+       while (st) {
+               FsmDelTimer(&st->ma.t202, 1);
+               st = st->next;
+       }
+}
 
-       st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+static struct FsmNode TeiFnList[] HISAX_INITDATA =
+{
+       {ST_TEI_NOP, EV_IDREQ, tei_id_request},
+       {ST_TEI_NOP, EV_VERIFY, tei_id_verify},
+       {ST_TEI_NOP, EV_REMOVE, tei_id_remove},
+       {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
+       {ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
+       {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
+       {ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
+       {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
+       {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
+       {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
+};
 
-       st->l2.l2l3 = (void *) tei_handler;
-       st->l1.l1man = tei_man;
-       st->l2.l2man = tei_man;
-       st->l4.l2writewakeup = NULL;
+#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
 
-       HiSax_addlist(sp, st);
-       sp->teistack = st;
+HISAX_INITFUNC(void
+TeiNew(void))
+{
+       teifsm.state_count = TEI_STATE_COUNT;
+       teifsm.event_count = TEI_EVENT_COUNT;
+       teifsm.strEvent = strTeiEvent;
+       teifsm.strState = strTeiState;
+       FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
 }
 
 void
-release_tei(struct IsdnCardState *sp)
+TeiFree(void)
 {
-       struct PStack *st = sp->teistack;
-
-       HiSax_rmlist(sp, st);
-       kfree((void *) st);
+       FsmFree(&teifsm);
 }
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
new file mode 100644 (file)
index 0000000..d86dd79
--- /dev/null
@@ -0,0 +1,363 @@
+/* $Id: teleint.c,v 1.5 1998/02/02 13:40:47 keil Exp $
+
+ * teleint.c     low level stuff for TeleInt isdn cards
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teleint.c,v $
+ * Revision 1.5  1998/02/02 13:40:47  keil
+ * fast io
+ *
+ * Revision 1.4  1997/11/08 21:35:53  keil
+ * new l1 init
+ *
+ * Revision 1.3  1997/11/06 17:09:30  keil
+ * New 2.1 init code
+ *
+ * Revision 1.2  1997/10/29 18:55:53  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 1.1  1997/09/11 17:32:32  keil
+ * new
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hfc_2bs0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *TeleInt_revision = "$Revision: 1.5 $";
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static inline u_char
+readreg(unsigned int ale, unsigned int adr, u_char off)
+{
+       register u_char ret;
+       int max_delay = 2000;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = HFC_BUSY & bytein(ale);
+       while (ret && --max_delay)
+               ret = HFC_BUSY & bytein(ale);
+       if (!max_delay) {
+               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+               restore_flags(flags);
+               return (0);
+       }
+       ret = bytein(adr);
+       restore_flags(flags);
+       return (ret);
+}
+
+static inline void
+readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       register u_char ret;
+       int max_delay = 2000;
+       byteout(ale, off);
+
+       ret = HFC_BUSY & bytein(ale);
+       while (ret && --max_delay)
+               ret = HFC_BUSY & bytein(ale);
+       if (!max_delay) {
+               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+               return;
+       }
+       insb(adr, data, size);
+}
+
+
+static inline void
+writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+{
+       register u_char ret;
+       int max_delay = 2000;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(ale, off);
+       ret = HFC_BUSY & bytein(ale);
+       while (ret && --max_delay)
+               ret = HFC_BUSY & bytein(ale);
+       if (!max_delay) {
+               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+               restore_flags(flags);
+               return;
+       }
+       byteout(adr, data);
+       restore_flags(flags);
+}
+
+static inline void
+writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+{
+       register u_char ret;
+       int max_delay = 2000;
+
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       ret = HFC_BUSY & bytein(ale);
+       while (ret && --max_delay)
+               ret = HFC_BUSY & bytein(ale);
+       if (!max_delay) {
+               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
+               return;
+       }
+       outsb(adr, data, size);
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       cs->hw.hfc.cip = offset;
+       return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       cs->hw.hfc.cip = offset;
+       writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       cs->hw.hfc.cip = 0;
+       readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       cs->hw.hfc.cip = 0;
+       writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
+}
+
+static u_char
+ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
+{
+       register u_char ret;
+
+       if (data) {
+               cs->hw.hfc.cip = reg;
+               byteout(cs->hw.hfc.addr | 1, reg);
+               ret = bytein(cs->hw.hfc.addr);
+               if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+                       char tmp[32];
+                       sprintf(tmp, "hfc RD %02x %02x", reg, ret);
+                       debugl1(cs, tmp);
+               }
+       } else
+               ret = bytein(cs->hw.hfc.addr | 1);
+       return (ret);
+}
+
+static void
+WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
+{
+       byteout(cs->hw.hfc.addr | 1, reg);
+       cs->hw.hfc.cip = reg;
+       if (data)
+               byteout(cs->hw.hfc.addr, value);
+       if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) {
+               char tmp[32];
+               sprintf(tmp, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
+               debugl1(cs, tmp);
+       }
+}
+
+static void
+TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "TeleInt: Spurious interrupt!\n");
+               return;
+       }
+       val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
+       if (val) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (stat & 2) {
+               writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
+               writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
+       }
+}
+
+static void
+TeleInt_Timer(struct IsdnCardState *cs)
+{
+       int stat = 0;
+
+       if (cs->bcs[0].mode) {
+               stat |= 1;
+               main_irq_hfc(&cs->bcs[0]);
+       }
+       if (cs->bcs[1].mode) {
+               stat |= 2;
+               main_irq_hfc(&cs->bcs[1]);
+       }
+       cs->hw.hfc.timer.expires = jiffies + 1;
+       add_timer(&cs->hw.hfc.timer);
+}
+
+void
+release_io_TeleInt(struct IsdnCardState *cs)
+{
+       del_timer(&cs->hw.hfc.timer);
+       releasehfc(cs);
+       if (cs->hw.hfc.addr)
+               release_region(cs->hw.hfc.addr, 2);
+}
+
+static void
+reset_TeleInt(struct IsdnCardState *cs)
+{
+       long flags;
+
+       printk(KERN_INFO "TeleInt: resetting card\n");
+       cs->hw.hfc.cirm |= HFC_RESET;
+       byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);  /* Reset On */
+       save_flags(flags);
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 3;
+       schedule();
+       cs->hw.hfc.cirm &= ~HFC_RESET;
+       byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);  /* Reset Off */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       restore_flags(flags);
+}
+
+static int
+TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       reset_TeleInt(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_TeleInt(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &TeleInt_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       inithfc(cs);
+                       clear_pending_isac_ints(cs);
+                       initisac(cs);
+                       cs->hw.hfc.timer.expires = jiffies + 1;
+                       add_timer(&cs->hw.hfc.timer);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_TeleInt(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, TeleInt_revision);
+       printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_TELEINT)
+               return (0);
+
+       cs->hw.hfc.addr = card->para[1] & 0x3fe;
+       cs->irq = card->para[0];
+       cs->hw.hfc.cirm = HFC_CIRM;
+       cs->hw.hfc.isac_spcr = 0x00;
+       cs->hw.hfc.cip = 0;
+       cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
+       cs->bcs[0].hw.hfc.send = NULL;
+       cs->bcs[1].hw.hfc.send = NULL;
+       cs->hw.hfc.fifosize = 7 * 1024 + 512;
+       cs->hw.hfc.timer.function = (void *) TeleInt_Timer;
+       cs->hw.hfc.timer.data = (long) cs;
+       init_timer(&cs->hw.hfc.timer);
+       if (check_region((cs->hw.hfc.addr), 2)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.hfc.addr,
+                      cs->hw.hfc.addr + 2);
+               return (0);
+       } else {
+               request_region(cs->hw.hfc.addr, 2, "TeleInt isdn");
+       }
+       /* HW IO = IO */
+       byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
+       byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
+       switch (cs->irq) {
+               case 3:
+                       cs->hw.hfc.cirm |= HFC_INTA;
+                       break;
+               case 4:
+                       cs->hw.hfc.cirm |= HFC_INTB;
+                       break;
+               case 5:
+                       cs->hw.hfc.cirm |= HFC_INTC;
+                       break;
+               case 7:
+                       cs->hw.hfc.cirm |= HFC_INTD;
+                       break;
+               case 10:
+                       cs->hw.hfc.cirm |= HFC_INTE;
+                       break;
+               case 11:
+                       cs->hw.hfc.cirm |= HFC_INTF;
+                       break;
+               default:
+                       printk(KERN_WARNING "TeleInt: wrong IRQ\n");
+                       release_io_TeleInt(cs);
+                       return (0);
+       }
+       byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
+       byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
+
+       printk(KERN_INFO
+              "TeleInt: defined at 0x%x IRQ %d\n",
+              cs->hw.hfc.addr,
+              cs->irq);
+
+       reset_TeleInt(cs);
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHFC;
+       cs->BC_Write_Reg = &WriteHFC;
+       cs->cardmsg = &TeleInt_card_msg;
+       ISACVersion(cs, "TeleInt:");
+       return (1);
+}
index 6aaba70d3918130d2d708b004a9be920161fbc9c..7cd173154b3a153f6d700df4b65867daa6da534d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $
+/* $Id: teles0.c,v 2.6 1998/02/03 23:27:47 keil Exp $
 
  * teles0.c     low level stuff for Teles Memory IO isdn cards
  *              based on the teles driver from Jan den Ouden
  *              Beat Doebeli
  *
  * $Log: teles0.c,v $
- * Revision 1.8  1997/04/13 19:54:04  keil
- * Change in IRQ check delay for SMP
+ * Revision 2.6  1998/02/03 23:27:47  keil
+ * IRQ 9
  *
- * Revision 1.7  1997/04/06 22:54:04  keil
- * Using SKB's
+ * Revision 2.5  1998/02/02 13:29:47  keil
+ * fast io
  *
- * Revision 1.6  1997/01/27 15:52:18  keil
- * SMP proof,cosmetics
+ * Revision 2.4  1997/11/08 21:35:54  keil
+ * new l1 init
  *
- * Revision 1.5  1997/01/21 22:25:59  keil
- * cleanups
+ * Revision 2.3  1997/11/06 17:09:31  keil
+ * New 2.1 init code
  *
- * Revision 1.4  1996/11/05 19:41:27  keil
- * more changes for 2.1
+ * Revision 2.2  1997/10/29 18:55:57  keil
+ * changes for 2.1.60 (irq2dev_map)
  *
- * Revision 1.3  1996/10/30 10:22:58  keil
- * Changes for 2.1 kernels
+ * Revision 2.1  1997/07/27 21:47:10  keil
+ * new interface structures
  *
- * Revision 1.2  1996/10/27 22:08:34  keil
- * cosmetic changes
+ * Revision 2.0  1997/06/26 11:02:43  keil
+ * New Layer and card interface
  *
- * Revision 1.1  1996/10/13 20:04:58  keil
- * Initial revision
+ * 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
  *
+ * removed old log info /KKe
  *
  */
 #define __NO_VERSION__
-#include "siemens.h"
 #include "hisax.h"
-#include "teles0.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
+#include "isac.h"
+#include "hscx.h"
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 1.8 $";
+const char *teles0_revision = "$Revision: 2.6 $";
 
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
 
 static inline u_char
 readisac(unsigned int adr, u_char off)
 {
-       return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+       return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
 static inline void
 writeisac(unsigned int adr, u_char off, u_char data)
 {
-       writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+       writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
 
 static inline u_char
 readhscx(unsigned int adr, int hscx, u_char off)
 {
-       return readb(adr + (hscx ? 0x1e0 : 0x1a0) +
+       return readb(adr + (hscx ? 0x1c0 : 0x180) +
                     ((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) +
+       writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
               ((off & 1) ? 0x1ff : 0) + off);
 }
 
@@ -87,7 +89,7 @@ read_fifo_isac(unsigned int adr, u_char * data, int size)
                data[i] = readb(ad);
 }
 
-static void
+static inline void
 write_fifo_isac(unsigned int adr, u_char * data, int size)
 {
        register int i;
@@ -113,745 +115,204 @@ write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
        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");
-}
 
+/* Interface functions */
 
-static inline void
-waitforXFW(int adr, int hscx)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       int to = 50;
-
-       while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
+       return (readisac(cs->hw.teles0.membase, offset));
 }
 
-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)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       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);
+       writeisac(cs->hw.teles0.membase, offset, value);
 }
 
-/*
- * HSCX stuff goes here
- */
-
 static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       read_fifo_isac(cs->hw.teles0.membase, data, size);
 }
 
 static void
-hscx_fill_fifo(struct HscxState *hsp)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       write_fifo_isac(cs->hw.teles0.membase, data, size);
 }
 
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       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 "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 {
-                               SET_SKB_FREE(hsp->tx_skb);
-                               dev_kfree_skb(hsp->tx_skb);
-                               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);
-       }
+       return (readhscx(cs->hw.teles0.membase, hscx, offset));
 }
 
-/*
- * ISAC stuff goes here
- */
-
 static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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);
-       }
+       writehscx(cs->hw.teles0.membase, hscx, offset, value);
 }
 
-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 "AVM: D receive out of memory\n");
-                               else {
-                                       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 {
-                               SET_SKB_FREE(sp->tx_skb);
-                               dev_kfree_skb(sp->tx_skb);
-                               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);
-               }
-       }
-}
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
 
-       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);
-       }
-}
+#include "hscx_irq.c"
 
 static void
-telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs = dev_id;
        u_char val, stat = 0;
+       int count = 0;
 
-       sp = (struct IsdnCardState *) dev_id;
-
-       if (!sp) {
+       if (!cs) {
                printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
                return;
        }
-       val = readhscx(sp->membase, 1, HSCX_ISTA);
+       val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
       Start_HSCX:
        if (val) {
-               hscx_int_main(sp, val);
+               hscx_int_main(cs, val);
                stat |= 1;
        }
-       val = readisac(sp->membase, ISAC_ISTA);
+       val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
       Start_ISAC:
        if (val) {
-               isac_interrupt(sp, val);
+               isac_interrupt(cs, val);
                stat |= 2;
        }
-       val = readhscx(sp->membase, 1, HSCX_ISTA);
-       if (val) {
-               if (sp->debug & L1_DEB_HSCX)
-                       debugl1(sp, "HSCX IntStat after IntRoutine");
+       count++;
+       val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+       if (val && count < 20) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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");
+       val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+       if (val && count < 20) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "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);
+               writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
+               writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
+               writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
+               writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
        }
        if (stat & 2) {
-               writeisac(sp->membase, ISAC_MASK, 0xFF);
-               writeisac(sp->membase, ISAC_MASK, 0x0);
+               writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+               writeisac(cs->hw.teles0.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)
+release_io_teles0(struct IsdnCardState *cs)
 {
-       if (card->sp->cfg_reg)
-               release_region(card->sp->cfg_reg, 8);
+       if (cs->hw.teles0.cfg_reg)
+               release_region(cs->hw.teles0.cfg_reg, 8);
 }
 
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+static int
+reset_teles0(struct IsdnCardState *cs)
 {
-       int val;
-       char tmp[64];
+       u_char cfval;
+       long flags;
 
-       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);
+       save_flags(flags);
+       sti();
+       if (cs->hw.teles0.cfg_reg) {
+               switch (cs->irq) {
+                       case 2:
+                       case 9:
+                               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:
+                               return(1);
+               }
+               cfval |= ((cs->hw.teles0.membase >> 9) & 0xF0);
+               byteout(cs->hw.teles0.cfg_reg + 4, cfval);
+               HZDELAY(HZ / 10 + 1);
+               byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
+               HZDELAY(HZ / 10 + 1);
        }
-       writeisac(sp->membase, ISAC_MASK, 0);
-       writeisac(sp->membase, ISAC_CMDR, 0x41);
+       writeb(0, cs->hw.teles0.membase + 0x80);
+       HZDELAY(HZ / 5 + 1);
+       writeb(1, cs->hw.teles0.membase + 0x80);
+       HZDELAY(HZ / 5 + 1);
+       restore_flags(flags);
+       return(0);
 }
 
-int
-initteles0(struct IsdnCardState *sp)
+static int
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-       int ret;
-       int loop = 0;
-       char tmp[40];
-
-       sp->counter = kstat_irqs(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_irqs(sp->irq) > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat_irqs(sp->irq));
-               debugl1(sp, tmp);
-               if (kstat_irqs(sp->irq) == sp->counter) {
-                       printk(KERN_WARNING
-                              "Teles0: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       free_irq(sp->irq, sp);
-                       return (0);
-               }
-       }
-       return (ret);
+       switch (mt) {
+               case CARD_RESET:
+                       reset_teles0(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_teles0(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &teles0_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
 }
 
-int
-setup_teles0(struct IsdnCard *card)
+__initfunc(int
+setup_teles0(struct IsdnCard *card))
 {
-       u_char cfval, val, verA, verB;
-       struct IsdnCardState *sp = card->sp;
-       long flags;
+       u_char val;
+       struct IsdnCardState *cs = card->cs;
        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))
+       printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
+       if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
                return (0);
 
-       if (sp->typ == ISDN_CTYPE_16_0)
-               sp->cfg_reg = card->para[2];
+       if (cs->typ == ISDN_CTYPE_16_0)
+               cs->hw.teles0.cfg_reg = card->para[2];
        else                    /* 8.0 */
-               sp->cfg_reg = 0;
+               cs->hw.teles0.cfg_reg = 0;
 
        if (card->para[1] < 0x10000) {
                card->para[1] <<= 4;
@@ -859,110 +320,69 @@ setup_teles0(struct IsdnCard *card)
                   "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)) {
+       cs->hw.teles0.membase = card->para[1];
+       cs->irq = card->para[0];
+       if (cs->hw.teles0.cfg_reg) {
+               if (check_region((cs->hw.teles0.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);
+                              cs->hw.teles0.cfg_reg,
+                              cs->hw.teles0.cfg_reg + 8);
                        return (0);
                } else {
-                       request_region(sp->cfg_reg, 8, "teles cfg");
+                       request_region(cs->hw.teles0.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) {
+       if (cs->hw.teles0.cfg_reg) {
+               if ((val = bytein(cs->hw.teles0.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);
+                              cs->hw.teles0.cfg_reg + 0, val);
+                       release_region(cs->hw.teles0.cfg_reg, 8);
                        return (0);
                }
-               if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+               if ((val = bytein(cs->hw.teles0.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);
+                              cs->hw.teles0.cfg_reg + 1, val);
+                       release_region(cs->hw.teles0.cfg_reg, 8);
                        return (0);
                }
-               val = bytein(sp->cfg_reg + 2);  /* 0x1e=without AB
-                                                  * 0x1f=with AB
-                                                  * 0x1c 16.3 ???
-                                                */
+               val = bytein(cs->hw.teles0.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);
+                              cs->hw.teles0.cfg_reg + 2, val);
+                       release_region(cs->hw.teles0.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)) {
+       /* 16.0 and 8.0 designed for IOM1 */
+       test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d mem:0x%X cfg:0x%X\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
+       if (reset_teles0(cs)) {
+               printk(KERN_WARNING "Teles0: wrong IRQ\n");
+               release_io_teles0(cs);
+               return (0);
+       }
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Teles_card_msg;
+       ISACVersion(cs, "Teles0:");
+       if (HscxVersion(cs, "Teles0:")) {
                printk(KERN_WARNING
                 "Teles0: wrong HSCX versions check IO/MEM addresses\n");
-               release_io_teles0(card);
+               release_io_teles0(cs);
                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
deleted file mode 100644 (file)
index 3baaa5c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* $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);
index 4b92e5ab7b7fc2d56695f8c3103e467dbca1bf5e..261d054fb8a14384586352f5cbe7a337a565977b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $
+/* $Id: teles3.c,v 2.7 1998/02/02 13:29:48 keil Exp $
 
  * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
  *
  *              Beat Doebeli
  *
  * $Log: teles3.c,v $
+ * Revision 2.7  1998/02/02 13:29:48  keil
+ * fast io
+ *
+ * Revision 2.6  1997/11/13 16:22:44  keil
+ * COMPAQ_ISA reset
+ *
+ * Revision 2.5  1997/11/12 15:01:25  keil
+ * COMPAQ_ISA changes
+ *
+ * Revision 2.4  1997/11/08 21:35:56  keil
+ * new l1 init
+ *
+ * Revision 2.3  1997/11/06 17:09:33  keil
+ * New 2.1 init code
+ *
+ * Revision 2.2  1997/10/29 18:55:59  keil
+ * changes for 2.1.60 (irq2dev_map)
+ *
+ * Revision 2.1  1997/07/27 21:47:12  keil
+ * new interface structures
+ *
+ * Revision 2.0  1997/06/26 11:02:46  keil
+ * New Layer and card interface
+ *
  * Revision 1.11  1997/04/13 19:54:05  keil
  * Change in IRQ check delay for SMP
  *
  * 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
- *
- *
+ * removed old log info /KKe
  *
  */
 #define __NO_VERSION__
-#include "siemens.h"
 #include "hisax.h"
-#include "teles3.h"
+#include "isac.h"
+#include "hscx.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 1.11 $";
+const char *teles3_revision = "$Revision: 2.7 $";
 
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
 
 static inline u_char
 readreg(unsigned int adr, u_char off)
@@ -82,953 +90,410 @@ writereg(unsigned int adr, u_char off, u_char data)
 static inline void
 read_fifo(unsigned int adr, u_char * data, int size)
 {
-       insb(adr + 0x1e, data, size);
+       insb(adr, data, size);
 }
 
 static void
 write_fifo(unsigned int adr, u_char * data, int size)
 {
-       outsb(adr + 0x1e, data, size);
+       outsb(adr, data, size);
 }
 
-static inline void
-waitforCEC(int adr)
-{
-       int to = 50;
+/* Interface functions */
 
-       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)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       int to = 50;
-
-       while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
+       return (readreg(cs->hw.teles3.isac, offset));
 }
-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)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       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);
-       }
+       writereg(cs->hw.teles3.isac, offset, value);
 }
 
 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)
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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 {
-                               SET_SKB_FREE(hsp->tx_skb);
-                               dev_kfree_skb(hsp->tx_skb);
-                               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);
-       }
+       read_fifo(cs->hw.teles3.isacfifo, data, size);
 }
 
-/*
- * ISAC stuff goes here
- */
-
 static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
-       }
+       write_fifo(cs->hw.teles3.isacfifo, data, size);
 }
 
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       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);
-       }
+       return (readreg(cs->hw.teles3.hscx[hscx], offset));
 }
 
 static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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);
+       writereg(cs->hw.teles3.hscx[hscx], offset, value);
 }
 
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-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 {
-                                       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 {
-                               SET_SKB_FREE(sp->tx_skb);
-                               dev_kfree_skb(sp->tx_skb);
-                               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];
+#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
 
-
-       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);
-       }
-}
+#include "hscx_irq.c"
 
 static void
 teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 #define MAXCOUNT 20
-       struct IsdnCardState *sp;
+       struct IsdnCardState *cs = dev_id;
        u_char val, stat = 0;
        int count = 0;
 
-       sp = (struct IsdnCardState *) dev_id;
-
-       if (!sp) {
+       if (!cs) {
                printk(KERN_WARNING "Teles: Spurious interrupt!\n");
                return;
        }
-       val = readreg(sp->hscx[1], HSCX_ISTA);
+       val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
       Start_HSCX:
        if (val) {
-               hscx_int_main(sp, val);
+               hscx_int_main(cs, val);
                stat |= 1;
        }
-       val = readreg(sp->isac, ISAC_ISTA);
+       val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
       Start_ISAC:
        if (val) {
-               isac_interrupt(sp, val);
+               isac_interrupt(cs, val);
                stat |= 2;
        }
        count++;
-       val = readreg(sp->hscx[1], HSCX_ISTA);
+       val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
        if (val && count < MAXCOUNT) {
-               if (sp->debug & L1_DEB_HSCX)
-                       debugl1(sp, "HSCX IntStat after IntRoutine");
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
                goto Start_HSCX;
        }
-       val = readreg(sp->isac, ISAC_ISTA);
+       val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
        if (val && count < MAXCOUNT) {
-               if (sp->debug & L1_DEB_ISAC)
-                       debugl1(sp, "ISAC IntStat after IntRoutine");
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "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);
+               writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+               writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+               writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+               writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
        }
        if (stat & 2) {
-               writereg(sp->isac, ISAC_MASK, 0xFF);
-               writereg(sp->isac, ISAC_MASK, 0x0);
+               writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.teles3.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_ioregs(struct IsdnCardState *cs, int mask)
 {
        if (mask & 1)
-               release_region(card->sp->isac, 32);
+               release_region(cs->hw.teles3.isac + 32, 32);
        if (mask & 2)
-               release_region(card->sp->hscx[0], 32);
+               release_region(cs->hw.teles3.hscx[0] + 32, 32);
        if (mask & 4)
-               release_region(card->sp->hscx[1], 32);
+               release_region(cs->hw.teles3.hscx[1] + 32, 32);
 }
 
 void
-release_io_teles3(struct IsdnCard *card)
+release_io_teles3(struct IsdnCardState *cs)
 {
-       if (card->sp->typ == ISDN_CTYPE_TELESPCMCIA)
-               release_region(card->sp->hscx[0], 97);
+       if (cs->typ == ISDN_CTYPE_TELESPCMCIA)
+               release_region(cs->hw.teles3.cfg_reg, 97);
        else {
-               if (card->sp->cfg_reg)
-                       release_region(card->sp->cfg_reg, 8);
-               release_ioregs(card, 0x7);
+               if (cs->hw.teles3.cfg_reg)
+                       if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                               release_region(cs->hw.teles3.cfg_reg, 1);
+                       } else {
+                               release_region(cs->hw.teles3.cfg_reg, 8);
+                       }
+               release_ioregs(cs, 0x7);
        }
 }
 
-static void
-clear_pending_ints(struct IsdnCardState *sp)
+static int
+reset_teles3(struct IsdnCardState *cs)
 {
-       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);
+       long flags;
+       u_char irqcfg;
+
+       if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
+               if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
+                       switch (cs->irq) {
+                               case 2:
+                               case 9:
+                                       irqcfg = 0x00;
+                                       break;
+                               case 3:
+                                       irqcfg = 0x02;
+                                       break;
+                               case 4:
+                                       irqcfg = 0x04;
+                                       break;
+                               case 5:
+                                       irqcfg = 0x06;
+                                       break;
+                               case 10:
+                                       irqcfg = 0x08;
+                                       break;
+                               case 11:
+                                       irqcfg = 0x0A;
+                                       break;
+                               case 12:
+                                       irqcfg = 0x0C;
+                                       break;
+                               case 15:
+                                       irqcfg = 0x0E;
+                                       break;
+                               default:
+                                       return(1);
+                       }
+                       save_flags(flags);
+                       byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
+                       sti();
+                       HZDELAY(HZ / 10 + 1);
+                       byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
+                       HZDELAY(HZ / 10 + 1);
+                       restore_flags(flags);
+               } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                       save_flags(flags);
+                       byteout(cs->hw.teles3.cfg_reg, 0xff);
+                       HZDELAY(2);
+                       byteout(cs->hw.teles3.cfg_reg, 0x00);
+                       HZDELAY(2);
+                       restore_flags(flags);
+               } else {
+                       /* Reset off for 16.3 PnP , thanks to Georg Acher */
+                       save_flags(flags);
+                       byteout(cs->hw.teles3.isac + 0x3c, 0);
+                       HZDELAY(2);
+                       byteout(cs->hw.teles3.isac + 0x3c, 1);
+                       HZDELAY(2);
+                       restore_flags(flags);
+               }
        }
-       writereg(sp->isac, ISAC_MASK, 0);
-       writereg(sp->isac, ISAC_CMDR, 0x41);
+       return(0);
 }
 
-int
-initteles3(struct IsdnCardState *sp)
+static int
+Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-       int ret;
-       int loop = 0;
-       char tmp[40];
-
-       sp->counter = kstat_irqs(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_irqs(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_irqs(sp->irq), loop);
-               debugl1(sp, tmp);
-               if (kstat_irqs(sp->irq) <= sp->counter) {
-                       printk(KERN_WARNING
-                              "Teles3: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       free_irq(sp->irq, sp);
-                       return (0);
-               }
-       }
-       return (ret);
+       switch (mt) {
+               case CARD_RESET:
+                       reset_teles3(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_teles3(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &teles3_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       initisac(cs);
+                       inithscx(cs);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
 }
 
-int
-setup_teles3(struct IsdnCard *card)
+__initfunc(int
+setup_teles3(struct IsdnCard *card))
 {
-       u_char cfval = 0, val, verA, verB;
-       struct IsdnCardState *sp = card->sp;
-       long flags;
+       u_char val;
+       struct IsdnCardState *cs = card->cs;
        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))
+       printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
+       if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
+           && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
                return (0);
 
-       if (sp->typ == ISDN_CTYPE_16_3) {
-               sp->cfg_reg = card->para[1];
-               switch (sp->cfg_reg) {
+       if (cs->typ == ISDN_CTYPE_16_3) {
+               cs->hw.teles3.cfg_reg = card->para[1];
+               switch (cs->hw.teles3.cfg_reg) {
                        case 0x180:
                        case 0x280:
                        case 0x380:
-                               sp->cfg_reg |= 0xc00;
+                               cs->hw.teles3.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)) {
+               cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
+               cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
+               cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
+       } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+               cs->hw.teles3.cfg_reg = card->para[1];
+               cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
+               cs->hw.teles3.hscx[1] = card->para[1];
+               cs->hw.teles3.isac = card->para[1] + 0x20;
+       } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+               cs->hw.teles3.cfg_reg = card->para[3];
+               cs->hw.teles3.isac = card->para[2] - 32;
+               cs->hw.teles3.hscx[0] = card->para[1] - 32;
+               cs->hw.teles3.hscx[1] = card->para[1];
+       } else {        /* PNP */
+               cs->hw.teles3.cfg_reg = 0;
+               cs->hw.teles3.isac = card->para[1] - 32;
+               cs->hw.teles3.hscx[0] = card->para[2] - 32;
+               cs->hw.teles3.hscx[1] = card->para[2];
+       }
+       cs->irq = card->para[0];
+       cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
+       cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
+       cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
+       if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
+               if (check_region((cs->hw.teles3.cfg_reg), 97)) {
                        printk(KERN_WARNING
                               "HiSax: %s ports %x-%x already in use\n",
-                              CardType[sp->typ],
-                              sp->hscx[0],
-                              sp->hscx[0] + 96);
+                              CardType[cs->typ],
+                              cs->hw.teles3.cfg_reg,
+                              cs->hw.teles3.cfg_reg + 96);
                        return (0);
                } else
-                       request_region(sp->hscx[0], 97, "HiSax Teles PCMCIA");
+                       request_region(cs->hw.teles3.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);
+               if (cs->hw.teles3.cfg_reg) {
+                       if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                               if (check_region((cs->hw.teles3.cfg_reg), 1)) {
+                                       printk(KERN_WARNING
+                                               "HiSax: %s config port %x already in use\n",
+                                               CardType[card->typ],
+                                               cs->hw.teles3.cfg_reg);
+                                       return (0);
+                               } else
+                                       request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg");
                        } else {
-                               request_region(sp->cfg_reg, 8, "teles3 cfg");
+                               if (check_region((cs->hw.teles3.cfg_reg), 8)) {
+                                       printk(KERN_WARNING
+                                              "HiSax: %s config port %x-%x already in use\n",
+                                              CardType[card->typ],
+                                              cs->hw.teles3.cfg_reg,
+                                               cs->hw.teles3.cfg_reg + 8);
+                                       return (0);
+                               } else
+                                       request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg");
                        }
                }
-               if (check_region((sp->isac), 32)) {
+               if (check_region((cs->hw.teles3.isac + 32), 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);
-                       }
+                              CardType[cs->typ],
+                              cs->hw.teles3.isac + 32,
+                              cs->hw.teles3.isac + 64);
+                       if (cs->hw.teles3.cfg_reg)
+                               if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                                       release_region(cs->hw.teles3.cfg_reg, 1);
+                               } else {
+                                       release_region(cs->hw.teles3.cfg_reg, 8);
+                               }
                        return (0);
-               } else {
-                       request_region(sp->isac, 32, "HiSax isac");
-               }
-               if (check_region((sp->hscx[0]), 32)) {
+               } else
+                       request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac");
+               if (check_region((cs->hw.teles3.hscx[0] + 32), 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);
+                              CardType[cs->typ],
+                              cs->hw.teles3.hscx[0] + 32,
+                              cs->hw.teles3.hscx[0] + 64);
+                       if (cs->hw.teles3.cfg_reg)
+                               if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                                       release_region(cs->hw.teles3.cfg_reg, 1);
+                               } else {
+                                       release_region(cs->hw.teles3.cfg_reg, 8);
+                               }
+                       release_ioregs(cs, 1);
                        return (0);
-               } else {
-                       request_region(sp->hscx[0], 32, "HiSax hscx A");
-               }
-               if (check_region((sp->hscx[1]), 32)) {
+               } else
+                       request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A");
+               if (check_region((cs->hw.teles3.hscx[1] + 32), 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);
+                              CardType[cs->typ],
+                              cs->hw.teles3.hscx[1] + 32,
+                              cs->hw.teles3.hscx[1] + 64);
+                       if (cs->hw.teles3.cfg_reg)
+                               if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
+                                       release_region(cs->hw.teles3.cfg_reg, 1);
+                               } else {
+                                       release_region(cs->hw.teles3.cfg_reg, 8);
+                               }
+                       release_ioregs(cs, 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;
-               }
+               } else
+                       request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B");
        }
-       if (sp->cfg_reg) {
-               if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+       if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
+               if ((val = bytein(cs->hw.teles3.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);
+                              cs->hw.teles3.cfg_reg + 0, val);
+                       release_io_teles3(cs);
                        return (0);
                }
-               if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+               if ((val = bytein(cs->hw.teles3.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);
+                              cs->hw.teles3.cfg_reg + 1, val);
+                       release_io_teles3(cs);
                        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) {
+               val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
+                                                        * 0x1f=with AB
+                                                        * 0x1c 16.3 ???
+                                                        * 0x39 16.3 1.1
+                                                        * 0x46 16.3 with AB + Video (Teles-Vision)
+                                                        */
+               if (val != 0x46 && val != 0x39 && 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);
+                              cs->hw.teles3.cfg_reg + 2, val);
+                       release_io_teles3(cs);
                        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_INFO
+              "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
+       printk(KERN_INFO
+              "HiSax: hscx A:0x%X  hscx B:0x%X\n",
+              cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
+
+       if (reset_teles3(cs)) {
+               printk(KERN_WARNING "Teles3: wrong IRQ\n");
+               release_io_teles3(cs);
+               return (0);
+       }
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Teles_card_msg;
+       ISACVersion(cs, "Teles3:");
+       if (HscxVersion(cs, "Teles3:")) {
                printk(KERN_WARNING
                       "Teles3: wrong HSCX versions check IO address\n");
-               release_io_teles3(card);
+               release_io_teles3(cs);
                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
deleted file mode 100644 (file)
index 8f8dc80..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* $Id: teles3.h,v 1.2 1997/01/21 22:27:14 keil Exp $
- *
- * teles3.h   Header for Teles 16.3 PNP & compatible
- *
- * Author      Karsten Keil (keil@temic-ech.spacenet.de)
- *
- *
- * $Log: teles3.h,v $
- * Revision 1.2  1997/01/21 22:27:14  keil
- * cleanups
- *
- * Revision 1.1  1996/10/13 20:03:49  keil
- * Initial revision
- *
- *
-*/
-
-extern void teles3_report(struct IsdnCardState *sp);
-extern  void release_io_teles3(struct IsdnCard *card);
-extern int  setup_teles3(struct IsdnCard *card);
-extern  int  initteles3(struct IsdnCardState *sp);
diff --git a/drivers/isdn/hisax/teles3c.c b/drivers/isdn/hisax/teles3c.c
new file mode 100644 (file)
index 0000000..848c46b
--- /dev/null
@@ -0,0 +1,199 @@
+/* $Id: teles3c.c,v 1.2 1998/02/02 13:27:07 keil Exp $
+
+ * teles3c.c     low level stuff for teles 16.3c
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles3c.c,v $
+ * Revision 1.2  1998/02/02 13:27:07  keil
+ * New
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *teles163c_revision = "$Revision: 1.2 $";
+
+static void
+t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat;
+       char tmp[32];
+
+       if (!cs) {
+               printk(KERN_WARNING "teles3c: Spurious interrupt!\n");
+               return;
+       }
+       if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & 
+               (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
+               val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "teles3c: stat(%02x) s1(%02x)", stat, val);
+                       debugl1(cs, tmp);
+               }
+               hfc2bds0_interrupt(cs, val);
+       } else {
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "teles3c: irq_no_irq stat(%02x)", stat);
+                       debugl1(cs, tmp);
+               }
+       }
+}
+
+static void
+t163c_Timer(struct IsdnCardState *cs)
+{
+       cs->hw.hfcD.timer.expires = jiffies + 75;
+       /* WD RESET */
+/*     WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
+       add_timer(&cs->hw.hfcD.timer);
+*/
+}
+
+void
+release_io_t163c(struct IsdnCardState *cs)
+{
+       release2bds0(cs);
+       del_timer(&cs->hw.hfcD.timer);
+       if (cs->hw.hfcD.addr)
+               release_region(cs->hw.hfcD.addr, 2);
+}
+
+static void
+reset_t163c(struct IsdnCardState *cs)
+{
+       long flags;
+
+       printk(KERN_INFO "teles3c: resetting card\n");
+       cs->hw.hfcD.cirm = HFCD_RESET | HFCD_MEM8K;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);   /* Reset On */
+       save_flags(flags);
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 3;
+       schedule();
+       cs->hw.hfcD.cirm = HFCD_MEM8K;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);   /* Reset Off */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       cs->hw.hfcD.cirm |= HFCD_INTB;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);   /* INT B */
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
+       cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
+       cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
+       cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
+               HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
+               HFCD_INTS_DREC | HFCD_INTS_L1STATE;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
+       udelay(10);
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
+       cs->hw.hfcD.mst_m = 0;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, HFCD_MASTER); /* HFC Master */
+       cs->hw.hfcD.sctrl = 0;
+       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
+       restore_flags(flags);
+}
+
+static int
+t163c_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       long flags;
+       char tmp[32];
+
+       if (cs->debug & L1_DEB_ISAC) {
+               
+               sprintf(tmp, "teles3c: card_msg %x", mt);
+               debugl1(cs, tmp);
+       }
+       switch (mt) {
+               case CARD_RESET:
+                       reset_t163c(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_t163c(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       cs->hw.hfcD.timer.expires = jiffies + 75;
+                       add_timer(&cs->hw.hfcD.timer);
+                       return(request_irq(cs->irq, &t163c_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       init2bds0(cs);
+                       save_flags(flags);
+                       sti();
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + (80*HZ)/1000;
+                       schedule();
+                       cs->hw.hfcD.ctmt |= HFCD_TIM800;
+                       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
+                       cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       restore_flags(flags);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_t163c(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, teles163c_revision);
+       printk(KERN_INFO "HiSax: Teles 16.3c driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_TELES3C)
+               return (0);
+       cs->debug = 0xff;
+       cs->hw.hfcD.addr = card->para[1] & 0xfffe;
+       cs->irq = card->para[0];
+       cs->hw.hfcD.cip = 0;
+       cs->hw.hfcD.int_s1 = 0;
+       cs->hw.hfcD.send = NULL;
+       cs->bcs[0].hw.hfc.send = NULL;
+       cs->bcs[1].hw.hfc.send = NULL;
+       cs->hw.hfcD.bfifosize = 1024 + 512;
+       cs->hw.hfcD.dfifosize = 512;
+       cs->ph_state = 0;
+       cs->hw.hfcD.fifo = 255;
+       if (check_region((cs->hw.hfcD.addr), 2)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.hfcD.addr,
+                      cs->hw.hfcD.addr + 2);
+               return (0);
+       } else {
+               request_region(cs->hw.hfcD.addr, 2, "teles3c isdn");
+       }
+       /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
+       outb(0x00, cs->hw.hfcD.addr);
+       outb(0x56, cs->hw.hfcD.addr | 1);
+       printk(KERN_INFO
+              "teles3c: defined at 0x%x IRQ %d HZ %d\n",
+              cs->hw.hfcD.addr,
+              cs->irq, HZ);
+
+       set_cs_func(cs);
+       cs->hw.hfcD.timer.function = (void *) t163c_Timer;
+       cs->hw.hfcD.timer.data = (long) cs;
+       init_timer(&cs->hw.hfcD.timer);
+       reset_t163c(cs);
+       cs->cardmsg = &t163c_card_msg;
+       return (1);
+}
index 0d839512d00eb1e84535fbcedf74eb5ddf12ab7e..2cc0e17f401c4d805d95c9bac1adb95f64752e29 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.44 1997/03/30 16:51:26 calle Exp $
+/* $Id: icn.c,v 1.49 1998/02/13 11:14:15 keil Exp $
 
  * ISDN low-level module for the ICN active ISDN-Card.
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: icn.c,v $
+ * Revision 1.49  1998/02/13 11:14:15  keil
+ * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
+ *
+ * Revision 1.48  1997/10/10 15:56:14  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.47  1997/10/01 09:21:51  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.46  1997/08/21 22:38:33  fritz
+ * Fixed a typo.
+ *
+ * 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.
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.44 $";
+*revision = "$Revision: 1.49 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -205,10 +224,20 @@ icn_free_queue(icn_card * card, int channel)
 {
        struct sk_buff_head *queue = &card->spqueue[channel];
        struct sk_buff *skb;
+       unsigned long flags;
 
        while ((skb = skb_dequeue(queue)))
                dev_kfree_skb(skb);
+       save_flags(flags);
+       cli();
+       card->xlen[channel] = 0;
        card->sndcount[channel] = 0;
+       if (card->xskb[channel]) {
+               card->xskb[channel] = NULL;
+               restore_flags(flags);
+               dev_kfree_skb(card->xskb[channel]);
+       } else
+               restore_flags(flags);
 }
 
 /* Put a value into a shift-register, highest bit first.
@@ -440,12 +469,14 @@ icn_pollbchan_send(int channel, icn_card * card)
        struct sk_buff *skb;
        isdn_ctrl cmd;
 
-       if (!(card->sndcount[channel] ||
+       if (!(card->sndcount[channel] || card->xskb[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]))) {
+               while (sbfree && 
+                      (card->sndcount[channel] ||
+                       skb_queue_len(&card->spqueue[channel]) ||
+                       card->xskb[channel])) {
                        save_flags(flags);
                        cli();
                        if (card->xmit_lock[channel]) {
@@ -454,7 +485,19 @@ icn_pollbchan_send(int channel, icn_card * card)
                        }
                        card->xmit_lock[channel]++;
                        restore_flags(flags);
-                       skb = skb_dequeue(&card->spqueue[channel]);
+                       skb = card->xskb[channel];
+                       if (!skb) {
+                               skb = skb_dequeue(&card->spqueue[channel]);
+                               if (skb) {
+                                       /* Pop ACK-flag off skb.
+                                        * Store length to xlen.
+                                        */
+                                       if (*(skb_pull(skb,1)))
+                                               card->xlen[channel] = skb->len;
+                                       else
+                                               card->xlen[channel] = 0;
+                               }
+                       }
                        if (!skb)
                                break;
                        if (skb->len > ICN_FRAGSIZE) {
@@ -471,13 +514,22 @@ icn_pollbchan_send(int channel, icn_card * card)
                        sbnext; /* switch to next buffer        */
                        icn_maprelease_channel(card, mch & 2);
                        if (!skb->len) {
-                               dev_kfree_skb(skb);
-                               cmd.command = ISDN_STAT_BSENT;
-                               cmd.driver = card->myid;
-                               cmd.arg = channel;
-                               card->interface.statcallb(&cmd);
-                       } else
-                               skb_queue_head(&card->spqueue[channel], skb);
+                               save_flags(flags);
+                               cli();
+                               if (card->xskb[channel]) {
+                                       card->xskb[channel] = NULL;
+                                       restore_flags(flags);
+                                       dev_kfree_skb(skb);
+                               } else
+                                       restore_flags(flags);
+                               if (card->xlen[channel]) {
+                                       cmd.command = ISDN_STAT_BSENT;
+                                       cmd.driver = card->myid;
+                                       cmd.arg = channel;
+                                       cmd.parm.length = card->xlen[channel];
+                                       card->interface.statcallb(&cmd);
+                               }
+                       }
                        card->xmit_lock[channel] = 0;
                        if (!icn_trymaplock_channel(card, mch))
                                break;
@@ -557,12 +609,11 @@ static icn_stat icn_stat_table[] =
  * This routine is called periodically via timer.
  */
 
-static int
+static void
 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;
 
@@ -575,7 +626,7 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                s++;
        }
        if (action == -1)
-               return 0;
+               return;
        cmd.driver = card->myid;
        cmd.arg = channel;
        switch (action) {
@@ -591,7 +642,6 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                        cli();
                        card->rcvidx[channel] = 0;
                        restore_flags(flags);
-                       dflag |= (channel + 1);
                        break;
                case 3:
                        {
@@ -645,7 +695,6 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                                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);
@@ -675,7 +724,7 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                        break;
        }
        card->interface.statcallb(&cmd);
-       return dflag;
+       return;
 }
 
 static void
@@ -701,7 +750,6 @@ 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;
@@ -722,7 +770,7 @@ icn_polldchan(unsigned long data)
                                    card->imsg[1] <= '2' && card->imsg[2] == ';') {
                                        ch = (card->imsg[1] - '0') - 1;
                                        p = &card->imsg[3];
-                                       dflag |= icn_parse_status(p, ch, card);
+                                       icn_parse_status(p, ch, card);
                                } else {
                                        p = card->imsg;
                                        if (!strncmp(p, "DRV1.", 5)) {
@@ -771,10 +819,6 @@ icn_polldchan(unsigned long data)
                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 */
@@ -807,7 +851,7 @@ icn_polldchan(unsigned long data)
  */
 
 static int
-icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
+icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card * card)
 {
        int len = skb->len;
        unsigned long flags;
@@ -827,6 +871,10 @@ icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
                cli();
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (nskb) {
+                       /* Push ACK flag as one
+                        * byte in front of data.
+                        */
+                       *(skb_push(nskb, 1)) = ack?1:0;
                        skb_queue_tail(&card->spqueue[channel], nskb);
                        dev_kfree_skb(skb);
                } else
@@ -1382,7 +1430,8 @@ icn_command(isdn_ctrl * c, icn_card * card)
                                                        }
                                                        current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
                                                        schedule();
-                                                       sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
+                                                       sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;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",
@@ -1638,14 +1687,14 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
 }
 
 static int
-if_sendbuf(int id, int channel, struct sk_buff *skb)
+if_sendbuf(int id, int channel, int ack, 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));
+               return (icn_sendbuf(channel, ack, skb, card));
        }
        printk(KERN_ERR
               "icn: if_sendbuf called with invalid driverId!\n");
@@ -1669,6 +1718,7 @@ icn_initcard(int port, char *id)
        }
        memset((char *) card, 0, sizeof(icn_card));
        card->port = port;
+       card->interface.hl_hdrlen = 1;
        card->interface.channels = ICN_BCH;
        card->interface.maxbufsize = 4000;
        card->interface.command = if_command;
@@ -1781,11 +1831,7 @@ icn_init(void)
        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);
index 991d57e4ddee48dbf5710d72b665fd1e285d67a6..3bd2819cedb85b3d97c9f6acf81e795027a33aa5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.26 1997/02/14 12:23:16 fritz Exp $
+/* $Id: icn.h,v 1.28 1997/10/10 15:56:18 fritz Exp $
 
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: icn.h,v $
+ * Revision 1.28  1997/10/10 15:56:18  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *
+ * Revision 1.27  1997/10/01 09:21:56  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.26  1997/02/14 12:23:16  fritz
  * Added support for new insmod parameter handling.
  *
@@ -265,6 +275,9 @@ typedef struct icn_card {
        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     */
+       int xlen[ICN_BCH];      /* Byte-counters/Flags for sent-ACK */
+       struct sk_buff *xskb[ICN_BCH];
+                               /* Current transmitted skb          */
        struct sk_buff_head
         spqueue[ICN_BCH];      /* Sendqueue                        */
        char regname[35];       /* Name used for request_region     */
@@ -303,7 +316,6 @@ 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");
@@ -314,7 +326,6 @@ 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__ */
 
index 84da942941c559ecd453ab7526461ce09ae8e1f8..d097366ed5d9f427a9401698b04122ba5c4e5302 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_audio.c,v 1.8 1997/03/02 14:29:16 fritz Exp $
+/* $Id: isdn_audio.c,v 1.10 1998/02/20 17:09:40 fritz Exp $
 
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_audio.c,v $
+ * Revision 1.10  1998/02/20 17:09:40  fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.9  1997/10/01 09:20:25  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.8  1997/03/02 14:29:16  fritz
  * More ttyI related cleanup.
  *
@@ -53,7 +61,7 @@
 #include "isdn_audio.h"
 #include "isdn_common.h"
 
-char *isdn_audio_revision = "$Revision: 1.8 $";
+char *isdn_audio_revision = "$Revision: 1.10 $";
 
 /*
  * Misc. lookup-tables.
@@ -531,7 +539,6 @@ isdn_audio_goertzel(int *sample, modem_info * info)
                       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;
index c7f4e8b08c89b174aa8c13bc49f1b57f228ca66b..30a4a77033cea3048a7d8e2562bf79b39ac5fe7b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_cards.c,v 1.6 1997/04/23 18:56:03 fritz Exp $
+/* $Id: isdn_cards.c,v 1.7 1998/02/20 17:24:28 fritz Exp $
 
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_cards.c,v $
+ * Revision 1.7  1998/02/20 17:24:28  fritz
+ * Added ACT2000 init.
+ *
  * Revision 1.6  1997/04/23 18:56:03  fritz
  * Old Teles driver removed, Changed doc and scripts accordingly.
  *
@@ -82,4 +85,7 @@ isdn_cards_init(void)
        capi_init();
        capidrv_init();
 #endif
+#if CONFIG_ISDN_DRV_ACT2000
+       act2000_init();
+#endif
 }
index c97c7781c1143e790621b9b0ec6b2e421322f966..3f4953f06a7296f487975b8e7846944c9df3a8a3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.55  1998/02/23 23:35:32  fritz
+ * Eliminated some compiler warnings.
+ *
+ * Revision 1.54  1998/02/22 19:44:19  fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.53  1998/02/20 17:18:05  fritz
+ * Changes for recent kernels.
+ * Added common stub for sending commands to lowlevel.
+ * Added V.110.
+ *
+ * Revision 1.52  1998/01/31 22:05:57  keil
+ * Lots of changes for X.25 support:
+ * Added generic support for connection-controlling encapsulation protocols
+ * Added support of BHUP status message
+ * Added support for additional p_encap X25IFACE
+ * Added support for kernels >= 2.1.72
+ *
+ * Revision 1.51  1998/01/31 19:17:29  calle
+ * merged changes from and for 2.1.82
+ *
+ * Revision 1.50  1997/12/12 06:12:11  calle
+ * moved EXPORT_SYMBOL(register_isdn) from isdn_syms.c to isdn_common.c
+ *
+ * Revision 1.49  1997/11/06 17:16:52  keil
+ * Sync to 2.1.62 changes
+ *
+ * Revision 1.48  1997/11/02 23:55:50  keil
+ * Andi Kleen's changes for 2.1.60
+ * without it the isdninfo and isdnctrl devices won't work
+ *
+ * Revision 1.47  1997/10/09 21:28:46  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.46  1997/10/01 09:20:27  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.45  1997/08/21 23:11:41  fritz
+ * Added changes for kernels >= 2.1.45
+ *
  * Revision 1.44  1997/05/27 15:17:23  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
  */
 
 #include <linux/config.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/version.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
 #include <linux/poll.h>
-#endif
 #include <linux/isdn.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #ifdef CONFIG_ISDN_AUDIO
 #include "isdn_audio.h"
 #endif
+#include "isdn_v110.h"
 #include "isdn_cards.h"
 
 /* Debugflags */
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.44 $";
+static char *isdn_revision = "$Revision: 1.55 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -232,6 +279,7 @@ extern char *isdn_audio_revision;
 #else
 static char *isdn_audio_revision = ": none $";
 #endif
+extern char *isdn_v110_revision;
 
 static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 
@@ -260,13 +308,6 @@ isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 }
 #endif
 
-static __inline void
-isdn_trash_skb(struct sk_buff *skb)
-{
-       SET_SKB_FREE(skb);
-       kfree_skb(skb);
-}
-
 static void
 isdn_free_queue(struct sk_buff_head *queue)
 {
@@ -277,7 +318,7 @@ isdn_free_queue(struct sk_buff_head *queue)
        cli();
        if (skb_queue_len(queue))
                while ((skb = skb_dequeue(queue)))
-                       isdn_trash_skb(skb);
+                       dev_kfree_skb(skb);
        restore_flags(flags);
 }
 
@@ -294,6 +335,7 @@ 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 int isdn_timer_cnt4 = 0;
 
 static void
 isdn_timer_funct(ulong dummy)
@@ -323,6 +365,11 @@ isdn_timer_funct(ulong dummy)
                                if (tf & ISDN_TIMER_MODEMRING)
                                        isdn_tty_modem_ring();
                        }
+                       if (++isdn_timer_cnt4 > ISDN_TIMER_KEEPINT) {
+                               isdn_timer_cnt4 = 0;
+                               if (tf & ISDN_TIMER_KEEPALIVE)
+                                       isdn_net_slarp_out();
+                       }
 #if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
                        if (tf & ISDN_TIMER_IPPP)
                                isdn_ppp_timer_timeout();
@@ -374,22 +421,71 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
        int i;
 
        if ((i = isdn_dc2minor(di, channel)) == -1) {
-               isdn_trash_skb(skb);
+               dev_kfree_skb(skb);
                return;
        }
        /* Update statistics */
        dev->ibytes[i] += skb->len;
+       
        /* First, try to deliver data to network-device */
        if (isdn_net_rcv_skb(i, skb))
                return;
+
+       /* V.110 handling
+        * makes sense for async streams only, so it is
+        * called after possible net-device delivery.
+        */
+       if (dev->v110[i]) {
+               atomic_inc(&dev->v110use[i]);
+               skb = isdn_v110_decode(dev->v110[i], skb);
+               atomic_dec(&dev->v110use[i]);
+               if (!skb)
+                       return;
+       }
+
        /* No network-device found, deliver to tty or raw-channel */
-       SET_SKB_FREE(skb);
        if (skb->len) {
                if (isdn_tty_rcv_skb(i, di, channel, skb))
                        return;
                wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
        } else
-               isdn_trash_skb(skb);
+               dev_kfree_skb(skb);
+}
+
+/*
+ * Intercept command from Linklevel to Lowlevel.
+ * If layer 2 protocol is V.110 and this is not supported by current
+ * lowlevel-driver, use driver's transparent mode and handle V.110 in
+ * linklevel instead.
+ */
+int
+isdn_command(isdn_ctrl *cmd)
+{
+       if (cmd->command == ISDN_CMD_SETL2) {
+                       int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+                       unsigned long l2prot = (cmd->arg >> 8) & 255;
+                       unsigned long features = (dev->drv[cmd->driver]->interface->features
+                                                >> ISDN_FEATURE_L2_SHIFT) &
+                               ISDN_FEATURE_L2_MASK;
+                       unsigned long l2_feature = (1 << l2prot);
+
+                       switch (l2prot) {
+                               case ISDN_PROTO_L2_V11096:
+                               case ISDN_PROTO_L2_V11019:
+                               case ISDN_PROTO_L2_V11038:
+                                               /* If V.110 requested, but not supported by
+                                                * HL-driver, set emulator-flag and change
+                                                * Layer-2 to transparent
+                                                */
+                                       if (!(features & l2_feature)) {
+                                               dev->v110emu[idx] = l2prot;
+                                               cmd->arg = (cmd->arg & 255) |
+                                                                  (ISDN_PROTO_L2_TRANS << 8);
+                                       } else
+                                               dev->v110emu[idx] = 0;
+                       }
+       }
+       return dev->drv[cmd->driver]->interface->command(cmd);
 }
 
 void
@@ -403,7 +499,7 @@ isdn_all_eaz(int di, int ch)
        cmd.arg = ch;
        cmd.command = ISDN_CMD_SETEAZ;
        cmd.parm.num[0] = '\0';
-       (void) dev->drv[di]->interface->command(&cmd);
+       isdn_command(&cmd);
 }
 
 static int
@@ -424,7 +520,9 @@ isdn_status_callback(isdn_ctrl * c)
                                return -1;
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
-                       if (isdn_net_stat_callback(i, c->command))
+                       if (isdn_net_stat_callback(i, c))
+                               return 0;
+                       if (isdn_v110_stat_callback(i, c))
                                return 0;
                        if (isdn_tty_stat_callback(i, c))
                                return 0;
@@ -456,14 +554,14 @@ isdn_status_callback(isdn_ctrl * c)
                                cmd.driver = di;
                                cmd.arg = c->arg;
                                cmd.command = ISDN_CMD_HANGUP;
-                               dev->drv[di]->interface->command(&cmd);
+                               isdn_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);
+                       isdn_command(&cmd);
                        r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
                        switch (r) {
                                case 0:
@@ -476,7 +574,7 @@ isdn_status_callback(isdn_ctrl * c)
                                                cmd.driver = di;
                                                cmd.arg = c->arg;
                                                cmd.command = ISDN_CMD_HANGUP;
-                                               dev->drv[di]->interface->command(&cmd);
+                                               isdn_command(&cmd);
                                                retval = 2;
                                        }
                                        break;
@@ -486,7 +584,7 @@ isdn_status_callback(isdn_ctrl * c)
                                        cmd.driver = di;
                                        cmd.arg = c->arg;
                                        cmd.command = ISDN_CMD_ACCEPTD;
-                                       dev->drv[di]->interface->command(&cmd);
+                                       isdn_command(&cmd);
                                        retval = 1;
                                        break;
                                case 2: /* For calling back, first reject incoming call ... */
@@ -496,7 +594,7 @@ isdn_status_callback(isdn_ctrl * c)
                                        cmd.driver = di;
                                        cmd.arg = c->arg;
                                        cmd.command = ISDN_CMD_HANGUP;
-                                       dev->drv[di]->interface->command(&cmd);
+                                       isdn_command(&cmd);
                                        if (r == 3)
                                                break;
                                        /* Fall through */
@@ -509,7 +607,7 @@ isdn_status_callback(isdn_ctrl * c)
                                cmd.driver = di;
                                cmd.arg = c->arg;
                                cmd.command = ISDN_CMD_UNLOCK;
-                               dev->drv[di]->interface->command(&cmd);
+                               isdn_command(&cmd);
                        }
                        return retval;
                        break;
@@ -522,7 +620,8 @@ isdn_status_callback(isdn_ctrl * c)
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
                        if (strcmp(c->parm.num, "0"))
-                               isdn_net_stat_callback(i, c->command);
+                               isdn_net_stat_callback(i, c);
+                       isdn_tty_stat_callback(i, c);
                        break;
                case ISDN_STAT_CAUSE:
 #ifdef ISDN_DEBUG_STATCALLB
@@ -541,14 +640,15 @@ isdn_status_callback(isdn_ctrl * c)
                        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))
+                       if (isdn_net_stat_callback(i, c))
                                break;
+                       isdn_v110_stat_callback(i, c);
                        /* 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);
+                               isdn_command(&cmd);
                                break;
                        }
                        break;
@@ -563,8 +663,9 @@ isdn_status_callback(isdn_ctrl * c)
                        dev->drv[di]->flags &= ~(1 << (c->arg));
                        isdn_info_update();
                        /* Signal hangup to network-devices */
-                       if (isdn_net_stat_callback(i, c->command))
+                       if (isdn_net_stat_callback(i, c))
                                break;
+                       isdn_v110_stat_callback(i, c);
                        if (isdn_tty_stat_callback(i, c))
                                break;
                        break;
@@ -579,8 +680,9 @@ isdn_status_callback(isdn_ctrl * c)
                                return 0;
                        dev->drv[di]->flags |= (1 << (c->arg));
                        isdn_info_update();
-                       if (isdn_net_stat_callback(i, c->command))
+                       if (isdn_net_stat_callback(i, c))
                                break;
+                       isdn_v110_stat_callback(i, c);
                        if (isdn_tty_stat_callback(i, c))
                                break;
                        break;
@@ -594,6 +696,12 @@ isdn_status_callback(isdn_ctrl * c)
                                return 0;
                        dev->drv[di]->flags &= ~(1 << (c->arg));
                        isdn_info_update();
+#ifdef CONFIG_ISDN_X25
+                       /* Signal hangup to network-devices */
+                       if (isdn_net_stat_callback(i, c))
+                               break;
+#endif
+                       isdn_v110_stat_callback(i, c);
                        if (isdn_tty_stat_callback(i, c))
                                break;
                        break;
@@ -605,7 +713,7 @@ isdn_status_callback(isdn_ctrl * c)
 #endif
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
-                       if (isdn_net_stat_callback(i, c->command))
+                       if (isdn_net_stat_callback(i, c))
                                break;
                        if (isdn_tty_stat_callback(i, c))
                                break;
@@ -636,6 +744,8 @@ isdn_status_callback(isdn_ctrl * c)
                        isdn_info_update();
                        restore_flags(flags);
                        return 0;
+               case ISDN_STAT_L1ERR:
+                       break;
                default:
                        return -1;
        }
@@ -752,7 +862,7 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user
                        ISDN_AUDIO_SKB_LOCK(skb) = 0;
 #endif
                        skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
-                       isdn_trash_skb(skb);
+                       dev_kfree_skb(skb);
                } else {
                        /* Not yet emptied this buff, so it
                         * must stay in the queue, for further calls
@@ -848,8 +958,8 @@ isdn_info_update(void)
        wake_up_interruptible(&(dev->info_waitq));
 }
 
-static RWTYPE
-isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
        uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
        int len = 0;
@@ -857,6 +967,9 @@ isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
        int drvidx;
        int chidx;
 
+       if (off != &file->f_pos)
+               return -ESPIPE;
+
        if (minor == ISDN_MINOR_STATUS) {
                char *p;
                if (!file->private_data) {
@@ -922,18 +1035,22 @@ isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
        return -ENODEV;
 }
 
-static LSTYPE isdn_lseek(struct file *file, LSARG offset, int orig)
+static loff_t
+isdn_lseek(struct file *file, loff_t offset, int orig)
 {
        return -ESPIPE;
 }
 
-static RWTYPE
-isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
 {
        uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
        int drvidx;
        int chidx;
 
+       if (off != &file->f_pos)
+               return -ESPIPE;
+
        if (minor == ISDN_MINOR_STATUS)
                return -EPERM;
        if (!dev->drivers)
@@ -972,41 +1089,6 @@ isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
        return -ENODEV;
 }
 
-#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);
-
-       if (minor == ISDN_MINOR_STATUS) {
-               if (file->private_data)
-                       return 1;
-               else {
-                       if (st)
-                               select_wait(&(dev->info_waitq), st);
-                       return 0;
-               }
-       }
-       if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
-               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;
-       }
-#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)
 {
@@ -1041,7 +1123,6 @@ isdn_poll(struct file *file, poll_table * wait)
        printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
        return POLLERR;
 }
-#endif
 
 static int
 isdn_set_allcfg(char *src)
@@ -1055,7 +1136,7 @@ isdn_set_allcfg(char *src)
        if ((ret = isdn_net_rmall()))
                return ret;
        if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
-               return ret;
+                return ret;
        save_flags(flags);
        cli();
        src += sizeof(int);
@@ -1082,7 +1163,7 @@ isdn_set_allcfg(char *src)
                                restore_flags(flags);
                                return ret;
                        }
-                       GET_USER(phone.phone[phone_len], src++);
+                       get_user(phone.phone[phone_len], src++);
                        if ((phone.phone[phone_len] == ' ') ||
                            (phone.phone[phone_len] == '\0')) {
                                if (phone_len) {
@@ -1122,28 +1203,30 @@ isdn_get_allcfg(char *dest)
        cli();
        p = dev->netdev;
        while (p) {
+               isdn_net_local *lp = p->local;
+
                if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
                        restore_flags(flags);
                        return ret;
                }
-               strcpy(cfg.eaz, p->local.msn);
-               cfg.exclusive = p->local.exclusive;
-               if (p->local.pre_device >= 0) {
-                       sprintf(cfg.drvid, "%s,%d", dev->drvid[p->local.pre_device],
-                               p->local.pre_channel);
+               strcpy(cfg.eaz, lp->msn);
+               cfg.exclusive = lp->exclusive;
+               if (lp->pre_device >= 0) {
+                       sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device],
+                               lp->pre_channel);
                } else
                        cfg.drvid[0] = '\0';
-               cfg.onhtime = p->local.onhtime;
-               cfg.charge = p->local.charge;
-               cfg.l2_proto = p->local.l2_proto;
-               cfg.l3_proto = p->local.l3_proto;
-               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 & 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)) {
+               cfg.onhtime = lp->onhtime;
+               cfg.charge = lp->charge;
+               cfg.l2_proto = lp->l2_proto;
+               cfg.l3_proto = lp->l3_proto;
+               cfg.p_encap = lp->p_encap;
+               cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
+               cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0;
+               cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+               cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
+               cfg.chargeint = lp->chargeint;
+               if (copy_to_user(dest, lp->name, 10)) {
                        restore_flags(flags);
                        return -EFAULT;
                }
@@ -1153,14 +1236,14 @@ isdn_get_allcfg(char *dest)
                        return -EFAULT;
                }
                dest += sizeof(cfg);
-               strcpy(phone.name, p->local.name);
+               strcpy(phone.name, lp->name);
                phone.outgoing = 0;
                if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
                        restore_flags(flags);
                        return ret;
                } else
                        dest += ret;
-               strcpy(phone.name, p->local.name);
+               strcpy(phone.name, lp->name);
                phone.outgoing = 1;
                if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
                        restore_flags(flags);
@@ -1343,9 +1426,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                /* 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);
+                               if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+                                       return ret;
+                               return isdn_net_force_hangup(name);
                                break;
 #endif                          /* CONFIG_NETDEVICES */
                        case IIOCSETVER:
@@ -1366,7 +1449,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                        int i;
                                        char *p;
                                        if ((ret = copy_from_user((char *) &iocts, (char *) arg,
-                                             sizeof(isdn_ioctl_struct))))
+                                            sizeof(isdn_ioctl_struct))))
                                                return ret;
                                        if (strlen(iocts.drvid)) {
                                                if ((p = strchr(iocts.drvid, ',')))
@@ -1440,7 +1523,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 
                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
                                                if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
-                                                     ISDN_MODEM_ANZREG)))
+                                                    ISDN_MODEM_ANZREG)))
                                                        return ret;
                                                p += ISDN_MODEM_ANZREG;
                                                if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
@@ -1482,7 +1565,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                                        while (1) {
                                                                if ((ret = verify_area(VERIFY_READ, p, 1)))
                                                                        return ret;
-                                                               GET_USER(bname[j], p++);
+                                                               get_user(bname[j], p++);
                                                                switch (bname[j]) {
                                                                        case '\0':
                                                                                loop = 0;
@@ -1554,7 +1637,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                        c.command = ISDN_CMD_IOCTL;
                                        c.arg = cmd;
                                        memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-                                       ret = dev->drv[drvidx]->interface->command(&c);
+                                       ret = isdn_command(&c);
                                        memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
                                        if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
                                                return -EFAULT;
@@ -1616,7 +1699,7 @@ isdn_open(struct inode *ino, struct file *filep)
                        return -ENODEV;
                c.command = ISDN_CMD_LOCK;
                c.driver = drvidx;
-               (void) dev->drv[drvidx]->interface->command(&c);
+               isdn_command(&c);
                MOD_INC_USE_COUNT;
                return 0;
        }
@@ -1627,7 +1710,7 @@ isdn_open(struct inode *ino, struct file *filep)
                c.command = ISDN_CMD_LOCK;
                c.driver = drvidx;
                MOD_INC_USE_COUNT;
-               (void) dev->drv[drvidx]->interface->command(&c);
+               isdn_command(&c);
                return 0;
        }
 #ifdef CONFIG_ISDN_PPP
@@ -1641,7 +1724,7 @@ isdn_open(struct inode *ino, struct file *filep)
        return -ENODEV;
 }
 
-static CLOSETYPE
+static int
 isdn_close(struct inode *ino, struct file *filep)
 {
        uint minor = MINOR(ino->i_rdev);
@@ -1659,39 +1742,39 @@ isdn_close(struct inode *ino, struct file *filep)
                                else
                                        dev->infochain = (infostruct *) (p->next);
                                kfree(p);
-                               return CLOSEVAL;
+                               return 0;
                        }
                        q = p;
                        p = (infostruct *) (p->next);
                }
                printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-               return CLOSEVAL;
+               return 0;
        }
        if (minor < ISDN_MINOR_CTRL) {
                drvidx = isdn_minor2drv(minor);
                if (drvidx < 0)
-                       return CLOSEVAL;
+                       return 0;
                c.command = ISDN_CMD_UNLOCK;
                c.driver = drvidx;
-               (void) dev->drv[drvidx]->interface->command(&c);
-               return CLOSEVAL;
+               isdn_command(&c);
+               return 0;
        }
        if (minor <= ISDN_MINOR_CTRLMAX) {
                drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
                if (drvidx < 0)
-                       return CLOSEVAL;
+                       return 0;
                if (dev->profd == current)
                        dev->profd = NULL;
                c.command = ISDN_CMD_UNLOCK;
                c.driver = drvidx;
-               (void) dev->drv[drvidx]->interface->command(&c);
-               return CLOSEVAL;
+               isdn_command(&c);
+               return 0;
        }
 #ifdef CONFIG_ISDN_PPP
        if (minor <= ISDN_MINOR_PPPMAX)
                isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
 #endif
-       return CLOSEVAL;
+       return 0;
 }
 
 static struct file_operations isdn_fops =
@@ -1700,11 +1783,7 @@ static struct file_operations isdn_fops =
        isdn_read,
        isdn_write,
        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,
@@ -1731,6 +1810,8 @@ isdn_map_eaz2msn(char *msn, int di)
  * Find an unused ISDN-channel, whose feature-flags match the
  * given L2- and L3-protocols.
  */
+#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
+
 int
 isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                      ,int pre_chan)
@@ -1738,11 +1819,18 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
        int i;
        ulong flags;
        ulong features;
+       ulong vfeatures;
        isdn_ctrl cmd;
 
        save_flags(flags);
        cli();
-       features = (1 << l2_proto) | (0x100 << l3_proto);
+       features = ((1 << l2_proto) | (0x10000 << l3_proto));
+       vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
+                    ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
+       /* If Layer-2 protocol is V.110, accept drivers with
+        * transparent feature even if these don't support V.110
+        * because we can emulate this in linklevel.
+        */
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
                if (USG_NONE(dev->usage[i]) &&
                    (dev->drvmap[i] != -1)) {
@@ -1751,7 +1839,9 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                        ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
                                continue;
                        if ((dev->drv[d]->running)) {
-                               if ((dev->drv[d]->interface->features & features) == features) {
+                               if (((dev->drv[d]->interface->features & features) == features) ||
+                                   (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
+                                    (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
                                        if ((pre_dev < 0) || (pre_chan < 0)) {
                                                dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
                                                dev->usage[i] |= usage;
@@ -1759,7 +1849,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                cmd.driver = d;
                                                cmd.arg = 0;
                                                cmd.command = ISDN_CMD_LOCK;
-                                               (void) dev->drv[d]->interface->command(&cmd);
+                                               isdn_command(&cmd);
                                                restore_flags(flags);
                                                return i;
                                        } else {
@@ -1770,7 +1860,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                        cmd.driver = d;
                                                        cmd.arg = 0;
                                                        cmd.command = ISDN_CMD_LOCK;
-                                                       (void) dev->drv[d]->interface->command(&cmd);
+                                                       isdn_command(&cmd);
                                                        restore_flags(flags);
                                                        return i;
                                                }
@@ -1808,7 +1898,7 @@ isdn_free_channel(int di, int ch, int usage)
                        cmd.arg = ch;
                        cmd.command = ISDN_CMD_UNLOCK;
                        restore_flags(flags);
-                       (void) dev->drv[di]->interface->command(&cmd);
+                       isdn_command(&cmd);
                        return;
                }
        restore_flags(flags);
@@ -1836,31 +1926,6 @@ isdn_unexclusive_channel(int di, int ch)
        restore_flags(flags);
 }
 
-/*
- * receive callback handler for drivers not supporting sk_buff's.
- * Parameters:
- *
- * di      = Driver-Index.
- * channel = Number of B-Channel (0...)
- * buf     = pointer to packet-data
- * len     = Length of packet-data
- *
- */
-static void
-isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
-{
-       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");
-}
-
 /*
  *  writebuf replacement for SKB_ABLE drivers
  */
@@ -1869,60 +1934,69 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
                   int user)
 {
        int ret;
+       int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+       struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
 
-       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);
+       if (!skb)
+               return 0;
+       skb_reserve(skb, hl);
+       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);
-       }
+       ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
+       if (ret <= 0)
+               dev_kfree_skb(skb);
        if (ret > 0)
                dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
        return ret;
 }
 
 /*
- * writebuf_skb replacement for NON SKB_ABLE drivers
- * If lowlevel-device does not support supports skbufs, use
- * standard send-routine, else sind directly.
- *
  * Return: length of data on success, -ERRcode on failure.
  */
-
 int
-isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
+isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
 {
        int ret;
-       int len = skb->len;     /* skb pointer no longer valid after free */
-
-       if (dev->drv[drvidx]->interface->writebuf_skb)
-               ret = dev->drv[drvidx]->interface->
-                   writebuf_skb(drvidx, chan, skb);
-       else {
-               if ((ret = dev->drv[drvidx]->interface->
-                 writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+       struct sk_buff *nskb = NULL;
+       int v110_ret = skb->len;
+       int idx = isdn_dc2minor(drvidx, chan);
+
+       if (dev->v110[idx]) {
+               atomic_inc(&dev->v110use[idx]);
+               nskb = isdn_v110_encode(dev->v110[idx], skb);
+               atomic_dec(&dev->v110use[idx]);
+               if (!nskb)
+                       return 0;
+               v110_ret = *((int *)nskb->data);
+               skb_pull(nskb, sizeof(int));
+               if (!nskb->len) {
+                       dev_kfree_skb(nskb);
                        dev_kfree_skb(skb);
-       }
-       if (ret > 0)
-               dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+                       return v110_ret;
+               }
+               /* V.110 must always be acknowledged */
+               ack = 1;
+               ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
+       } else
+               ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+       if (ret > 0) {
+               dev->obytes[idx] += ret;
+               if (dev->v110[idx]) {
+                       atomic_inc(&dev->v110use[idx]);
+                       dev->v110[idx]->skbuser++;
+                       atomic_dec(&dev->v110use[idx]);
+                       dev_kfree_skb(skb);
+                       /* For V.110 return unencoded data length */
+                       ret = v110_ret;
+                       if (ret == skb->len)
+                               dev_kfree_skb(skb);
+               }
+       } else
+               if (dev->v110[idx])
+                       dev_kfree_skb(nskb);
        return ret;
 }
 
@@ -1930,6 +2004,8 @@ isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
  * Low-level-driver registration
  */
 
+EXPORT_SYMBOL(register_isdn);
+
 int
 register_isdn(isdn_if * i)
 {
@@ -1951,7 +2027,7 @@ register_isdn(isdn_if * i)
                       ISDN_MAX_CHANNELS);
                return 0;
        }
-       if ((!i->writebuf_skb) && (!i->writebuf)) {
+       if (!i->writebuf_skb) {
                printk(KERN_WARNING "register_isdn: No write routine given.\n");
                return 0;
        }
@@ -2019,7 +2095,6 @@ register_isdn(isdn_if * i)
        i->channels = drvidx;
 
        i->rcvcallb_skb = isdn_receive_skb_callback;
-       i->rcvcallb = isdn_receive_callback;
        i->statcallb = isdn_status_callback;
        if (!strlen(i->id))
                sprintf(i->id, "line%d", drvidx);
@@ -2078,11 +2153,7 @@ int
 isdn_init(void)
 {
        int i;
-       char irev[50];
-       char trev[50];
-       char nrev[50];
-       char prev[50];
-       char arev[50];
+       char tmprev[50];
 
        sti();
        if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
@@ -2126,18 +2197,18 @@ isdn_init(void)
        }
 #endif                          /* CONFIG_ISDN_PPP */
 
-       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);
-       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));
+       strcpy(tmprev, isdn_revision);
+       printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
+       strcpy(tmprev, isdn_tty_revision);
+       printk("%s/", isdn_getrev(tmprev));
+       strcpy(tmprev, isdn_net_revision);
+       printk("%s/", isdn_getrev(tmprev));
+       strcpy(tmprev, isdn_ppp_revision);
+       printk("%s/", isdn_getrev(tmprev));
+       strcpy(tmprev, isdn_audio_revision);
+       printk("%s/", isdn_getrev(tmprev));
+       strcpy(tmprev, isdn_v110_revision);
+       printk("%s", isdn_getrev(tmprev));
 
 #ifdef MODULE
        printk(" loaded\n");
index d0df7fe7965ae28d0c1a9d69a359e48abaa4a493..b9d5df7153e9dbed518f25a198167d2cb7b795d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.6 1997/02/28 02:32:44 fritz Exp $
+/* $Id: isdn_common.h,v 1.9 1998/02/20 17:19:01 fritz Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.9  1998/02/20 17:19:01  fritz
+ * Added common stub for sending commands to lowlevel.
+ *
+ * Revision 1.8  1997/10/09 21:28:49  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.7  1997/10/01 09:20:30  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.6  1997/02/28 02:32:44  fritz
  * Cleanup: Moved some tty related stuff from isdn_common.c
  *          to isdn_tty.c
@@ -61,6 +79,7 @@ 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_command(isdn_ctrl *);
 extern int isdn_dc2minor(int di, int ch);
 extern void isdn_info_update(void);
 extern char *isdn_map_eaz2msn(char *msn, int di);
@@ -69,13 +88,8 @@ 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 isdn_writebuf_skb_stub(int, 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);
 #endif
diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c
new file mode 100644 (file)
index 0000000..0d9abb2
--- /dev/null
@@ -0,0 +1,108 @@
+/* $Id: isdn_concap.c,v 1.2 1998/01/31 22:49:21 keil Exp $
+ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
+ * stuff goes here. Stuff that depends only on the concap protocol goes to
+ * another -- protocol specific -- source file.
+ *
+ * $Log: isdn_concap.c,v $
+ * Revision 1.2  1998/01/31 22:49:21  keil
+ * correct comments
+ *
+ * Revision 1.1  1998/01/31 22:27:57  keil
+ * New files from Henner Eisen for X.25 support
+ *
+ */
+
+
+#include <linux/isdn.h>
+#include "isdn_x25iface.h"
+#include "isdn_net.h"
+#include <linux/concap.h>
+#include "isdn_concap.h"
+
+/* The declaration of this (or a plublic variant thereof) should really go
+   in linux/isdn.h. But we really need it here (and isdn_ppp, like us, also
+   refers to that private function currently owned by isdn_net.c) */
+extern int isdn_net_force_dial_lp(isdn_net_local *);
+
+
+/* The following set of device service operations are for encapsulation
+   protocols that require for reliable datalink sematics. That means:
+
+   - before any data is to be submitted the connection must explicitly
+     be set up.
+   - after the successful set up of the connection is signalled the
+     connection is considered to be reliably up.
+
+   Auto-dialing ist not compatible with this requirements. Thus, auto-dialing 
+   is completely bypassed.
+
+   It might be possible to implement a (non standardized) datalink protocol
+   that provides a reliable data link service while using some auto dialing
+   mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
+   signaling on the D-channel) while the B-channel is down.
+   */
+
+
+int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+{
+       int tmp;
+       struct device *ndev = concap -> net_dev;
+       isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+
+       IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
+       lp->huptimer = 0;
+       tmp=isdn_net_send_skb(ndev, lp, skb);
+       IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
+       return tmp;
+}
+
+
+int isdn_concap_dl_connect_req(struct concap_proto *concap)
+{
+       struct device *ndev = concap -> net_dev;
+       isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+       int ret;
+       IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
+
+       /* dial ... */
+       ret = isdn_net_force_dial_lp( lp );
+       if ( ret ) IX25DEBUG("dialing failed\n");
+       return 0;
+}
+
+int isdn_concap_dl_disconn_req(struct concap_proto *concap)
+{
+       IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
+
+       isdn_net_hangup( concap -> net_dev );
+       return 0;
+}
+
+struct concap_device_ops isdn_concap_reliable_dl_dops = {
+       &isdn_concap_dl_data_req,
+       &isdn_concap_dl_connect_req,
+       &isdn_concap_dl_disconn_req
+};
+
+struct concap_device_ops isdn_concap_demand_dial_dops = {
+       NULL, /* set this first entry to something like &isdn_net_start_xmit,
+                but the entry part of the current isdn_net_start_xmit must be
+                separated first. */
+       /* no connection control for demand dial semantics */
+       NULL,
+       NULL,
+};
+
+/* The following should better go into a dedicated source file such that
+   this sourcefile does not need to include any protocol specific header
+   files. For now:
+   */
+struct concap_proto * isdn_concap_new( int encap )
+{
+       switch ( encap ) {
+       case ISDN_NET_ENCAP_X25IFACE:
+               return isdn_x25iface_proto_new();
+       }
+       return NULL;
+}
diff --git a/drivers/isdn/isdn_concap.h b/drivers/isdn/isdn_concap.h
new file mode 100644 (file)
index 0000000..722f8ee
--- /dev/null
@@ -0,0 +1,7 @@
+/* $Id: isdn_concap.h,v 1.2 1998/01/31 22:49:21 keil Exp $
+ */
+extern struct concap_device_ops isdn_concap_reliable_dl_dops;
+extern struct concap_device_ops isdn_concap_demand_dial_dops;
+extern struct concap_proto * isdn_concap_new( int );
+
+
index c44fcc74a7549d77b8c22f6f22af55b58ee4331d..46b460370803d1f952009e339c6c5d2d917bf2b7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.44 1997/05/27 15:17:26 fritz Exp $
+/* $Id: isdn_net.c,v 1.55 1998/02/23 19:38:22 fritz Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.55  1998/02/23 19:38:22  fritz
+ * Corrected check for modified feature-flags.
+ *
+ * Revision 1.54  1998/02/20 17:15:07  fritz
+ * Changes for recent kernels.
+ * Ugly workaround for adjusting Ethernet frames with recent kernels.
+ * replaced direct calls to lowlevel-driver command by common hook.
+ *
+ * Revision 1.53  1998/01/31 22:05:54  keil
+ * Lots of changes for X.25 support:
+ * Added generic support for connection-controlling encapsulation protocols
+ * Added support of BHUP status message
+ * Added support for additional p_encap X25IFACE
+ * Added support for kernels >= 2.1.72
+ *
+ * Revision 1.52  1998/01/31 19:29:51  calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.51  1997/10/09 21:28:50  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.50  1997/10/01 09:20:32  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.49  1997/08/21 14:38:13  fritz
+ * Bugfix: Did not compile without SyncPPP.
+ *
+ * Revision 1.48  1997/06/22 11:57:15  fritz
+ * Added ability to adjust slave triggerlevel.
+ *
+ * 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
 #include <linux/isdn.h>
 #include <net/arp.h>
 #include <net/icmp.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
-#include <linux/poll.h>
+#ifndef DEV_NUMBUFFS
+#include <net/pkt_sched.h>
 #endif
+#include <linux/inetdevice.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
 #ifdef CONFIG_ISDN_PPP
 #include "isdn_ppp.h"
 #endif
-#ifndef DEV_NUMBUFFS
-#include <net/pkt_sched.h>
+#ifdef CONFIG_ISDN_X25
+#include <linux/concap.h>
+#include "isdn_concap.h"
 #endif
 
 /* Prototypes */
@@ -218,7 +268,7 @@ static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
 static void dev_purge_queues(struct device *dev);      /* move this to net/core/dev.c */
 #endif
 
-char *isdn_net_revision = "$Revision: 1.44 $";
+char *isdn_net_revision = "$Revision: 1.55 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -229,22 +279,28 @@ 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
-           );
+       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 }
 
 static void
 isdn_net_reset(struct device *dev)
 {
+#ifdef CONFIG_ISDN_X25
+       struct concap_device_ops * dops = 
+               ( (isdn_net_local *) dev->priv ) -> dops;
+       struct concap_proto * cprot = 
+               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; 
+#endif
        ulong flags;
 
        save_flags(flags);
        cli();                  /* Avoid glitch on writes to CMD regs */
        dev->interrupt = 0;
        dev->tbusy = 0;
+#ifdef CONFIG_ISDN_X25
+       if( cprot && cprot -> pops && dops ) 
+               cprot -> pops -> restart ( cprot, dev, dops );
+#endif
        restore_flags(flags);
 }
 
@@ -254,14 +310,22 @@ isdn_net_open(struct device *dev)
 {
        int i;
        struct device *p;
+       struct in_device *in_dev;
 
        isdn_net_reset(dev);
        dev->start = 1;
-       /* Fill in the MAC-level header. */
+       /* Fill in the MAC-level header (not needed, but for compatibility... */
        for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
                dev->dev_addr[i] = 0xfc;
-       memset(&(dev->dev_addr[i]), 0, sizeof(u32));
-
+       if ((in_dev = dev->ip_ptr) != NULL) {
+               /*
+                *      Any address will do - we take the first
+                */
+               struct in_ifaddr *ifa = in_dev->ifa_list;
+               if (ifa != NULL)
+                       memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+       }
        /* If this interface has slaves, start them also */
 
        if ((p = (((isdn_net_local *) dev->priv)->slave))) {
@@ -356,7 +420,7 @@ isdn_net_autohup()
 
        anymore = 0;
        while (p) {
-               isdn_net_local *l = (isdn_net_local *) & (p->local);
+               isdn_net_local *l = p->local;
                if ((jiffies - last_jiffies) == 0)
                        l->cps = l->transcount;
                else
@@ -405,18 +469,24 @@ isdn_net_autohup()
  * Return: 1 = Event handled, 0 = not for us or unknown Event.
  */
 int
-isdn_net_stat_callback(int idx, int cmd)
+isdn_net_stat_callback(int idx, isdn_ctrl *c)
 {
        isdn_net_dev *p = dev->st_netdev[idx];
-
+       int cmd = c->command;
+       
        if (p) {
-               isdn_net_local *lp = &(p->local);
+               isdn_net_local *lp = p->local;
+#ifdef CONFIG_ISDN_X25
+               struct concap_proto *cprot = lp -> netdev -> cprot;
+               struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
                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++;
+                                       lp->stats.tx_bytes += c->parm.length;
                                        if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
                                                struct device *mdev;
                                                if (lp->master)
@@ -449,6 +519,16 @@ isdn_net_stat_callback(int idx, int cmd)
                                break;
                        case ISDN_STAT_DHUP:
                                /* Either D-Channel-hangup or error during dialout */
+#ifdef CONFIG_ISDN_X25
+                               /* If we are not connencted then dialing had
+                                  failed. If there are generic encap protocol
+                                  receiver routines signal the closure of
+                                  the link*/
+                               
+                               if( !(lp->flags & ISDN_NET_CONNECTED) 
+                                   && pops && pops -> disconn_ind )
+                                       pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
                                if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
                                        lp->flags &= ~ISDN_NET_CONNECTED;
                                        if (lp->first_skb) {
@@ -475,6 +555,18 @@ isdn_net_stat_callback(int idx, int cmd)
                                        return 1;
                                }
                                break;
+#ifdef CONFIG_ISDN_X25
+                       case ISDN_STAT_BHUP:
+                               /* B-Channel-hangup */
+                               /* try if there are generic encap protocol
+                                  receiver routines and signal the closure of
+                                  the link */
+                               if( pops  &&  pops -> disconn_ind ){
+                                               pops -> disconn_ind(cprot);
+                                               return 1;
+                                       }
+                               break;
+#endif /* CONFIG_ISDN_X25 */
                        case ISDN_STAT_BCONN:
                                /* B-Channel is up */
                                switch (lp->dialstate) {
@@ -492,6 +584,8 @@ isdn_net_stat_callback(int idx, int cmd)
                                                        dev->rx_netdev[idx] = p;
                                                lp->dialstate = 0;
                                                isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
+                                               if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
+                                                       isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
                                                printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
                                                /* If first Chargeinfo comes before B-Channel connect,
                                                 * we correct the timestamp here.
@@ -504,7 +598,15 @@ isdn_net_stat_callback(int idx, int cmd)
                                                if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
                                                        isdn_ppp_wakeup_daemon(lp);
 #endif
+#ifdef CONFIG_ISDN_X25
+                                               /* try if there are generic concap receiver routines */
+                                               if( pops )
+                                                       if( pops->connect_ind)
+                                                               pops->connect_ind(cprot);
+
+#endif /* CONFIG_ISDN_X25 */
                                                if (lp->first_skb) {
+                                                       
                                                        if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
                                                                lp->first_skb = NULL;
                                                }
@@ -573,11 +675,13 @@ isdn_net_dial(void)
        isdn_ctrl cmd;
 
        while (p) {
+               isdn_net_local *lp = p->local;
+
 #ifdef ISDN_DEBUG_NET_DIAL
-               if (p->local.dialstate)
-                       printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name, p->local.dialstate);
+               if (lp->dialstate)
+                       printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
 #endif
-               switch (p->local.dialstate) {
+               switch (lp->dialstate) {
                        case 0:
                                /* Nothing to do for this interface */
                                break;
@@ -587,132 +691,133 @@ isdn_net_dial(void)
                                 */
                                save_flags(flags);
                                cli();
-                               p->local.dial = p->local.phone[1];
+                               lp->dial = lp->phone[1];
                                restore_flags(flags);
-                               if (!p->local.dial) {
+                               if (!lp->dial) {
                                        printk(KERN_WARNING "%s: phone number deleted?\n",
-                                              p->local.name);
+                                              lp->name);
                                        isdn_net_hangup(&p->dev);
                                        break;
                                }
                                anymore = 1;
-                               p->local.dialstate++;
+                               lp->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.driver = lp->isdn_device;
+                               cmd.arg = lp->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));
+                               isdn_command(&cmd);
+                               sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
                                cmd.command = ISDN_CMD_SETEAZ;
-                               dev->drv[p->local.isdn_device]->interface->command(&cmd);
-                               p->local.dialretry = 0;
+                               isdn_command(&cmd);
+                               lp->dialretry = 0;
                                anymore = 1;
-                               p->local.dialstate++;
+                               lp->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.
                                 */
-                               cmd.driver = p->local.isdn_device;
+                               cmd.driver = lp->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.arg = lp->isdn_channel + (lp->l2_proto << 8);
+                               isdn_command(&cmd);
+                               cmd.driver = lp->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;
+                               cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+                               isdn_command(&cmd);
+                               cmd.driver = lp->isdn_device;
+                               cmd.arg = lp->isdn_channel;
                                save_flags(flags);
                                cli();
-                               if (!p->local.dial) {
+                               if (!lp->dial) {
                                        restore_flags(flags);
                                        printk(KERN_WARNING "%s: phone number deleted?\n",
-                                              p->local.name);
+                                              lp->name);
                                        isdn_net_hangup(&p->dev);
                                        break;
                                }
-                               if (!strcmp(p->local.dial->num, "LEASED")) {
+                               if (!strcmp(lp->dial->num, "LEASED")) {
                                        restore_flags(flags);
-                                       p->local.dialstate = 4;
-                                       printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
+                                       lp->dialstate = 4;
+                                       printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
                                } else {
-                                       sprintf(cmd.parm.setup.phone, "%s", p->local.dial->num);
+                                       sprintf(cmd.parm.setup.phone, "%s", lp->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++;
+                                       if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
+                                               lp->dial = lp->phone[1];
+                                               lp->dialretry++;
                                        }
                                        restore_flags(flags);
+                                       cmd.driver = lp->isdn_device;
                                        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);
+                                               isdn_map_eaz2msn(lp->msn, cmd.driver));
+                                       i = isdn_dc2minor(lp->isdn_device, lp->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;
+                                       printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
+                                              lp->dialretry - 1, cmd.parm.setup.phone);
+                                       lp->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", lp->isdn_device,
+                                              lp->isdn_channel);
 #endif
-                                       dev->drv[p->local.isdn_device]->interface->command(&cmd);
+                                       isdn_command(&cmd);
                                }
-                               p->local.huptimer = 0;
-                               p->local.outgoing = 1;
-                               if (p->local.chargeint) {
-                                       p->local.hupflags |= ISDN_HAVECHARGE;
-                                       p->local.hupflags &= ~ISDN_WAITCHARGE;
+                               lp->huptimer = 0;
+                               lp->outgoing = 1;
+                               if (lp->chargeint) {
+                                       lp->hupflags |= ISDN_HAVECHARGE;
+                                       lp->hupflags &= ~ISDN_WAITCHARGE;
                                } else {
-                                       p->local.hupflags |= ISDN_WAITCHARGE;
-                                       p->local.hupflags &= ~ISDN_HAVECHARGE;
+                                       lp->hupflags |= ISDN_WAITCHARGE;
+                                       lp->hupflags &= ~ISDN_HAVECHARGE;
                                }
                                anymore = 1;
-                               p->local.dialstate =
-                                   (p->local.cbdelay &&
-                                    (p->local.flags & ISDN_NET_CBOUT)) ? 12 : 4;
+                               lp->dialstate =
+                                   (lp->cbdelay &&
+                                    (lp->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;
+                               if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+                                       if (lp->dialretry < lp->dialmax) {
+                                               lp->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.driver = lp->isdn_device;
+                               cmd.arg = lp->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);
+                               lp->dtimer = 0;
+                               lp->dialstate++;
+                               isdn_command(&cmd);
                                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", lp->dtimer);
 #endif
-                               if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
-                                       p->local.dialstate = 3;
+                               if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+                                       lp->dialstate = 3;
                                anymore = 1;
                                break;
                        case 7:
@@ -720,69 +825,69 @@ isdn_net_dial(void)
                                 * 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", lp->dtimer);
 #endif
-                               cmd.driver = p->local.isdn_device;
+                               cmd.driver = lp->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.arg = lp->isdn_channel + (lp->l2_proto << 8);
+                               isdn_command(&cmd);
+                               cmd.driver = lp->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)
+                               cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
+                               isdn_command(&cmd);
+                               if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
                                        isdn_net_hangup(&p->dev);
                                else {
                                        anymore = 1;
-                                       p->local.dialstate++;
+                                       lp->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.driver = lp->isdn_device;
+                               cmd.arg = lp->isdn_channel;
                                cmd.command = ISDN_CMD_ACCEPTB;
-                               dev->drv[p->local.isdn_device]->interface->command(&cmd);
+                               isdn_command(&cmd);
                                anymore = 1;
-                               p->local.dtimer = 0;
-                               p->local.dialstate++;
+                               lp->dtimer = 0;
+                               lp->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", lp->dtimer);
 #endif
-                               if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+                               if (lp->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;
+                               if (lp->dtimer++ > lp->cbdelay)
+                                       lp->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;
+                               if (lp->dtimer++ > lp->cbdelay) {
+                                       printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
+                                       lp->dtimer = 0;
+                                       lp->dialstate = 4;
+                                       cmd.driver = lp->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);
+                                       cmd.arg = lp->isdn_channel;
+                                       isdn_command(&cmd);
+                                       isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
                                }
                                anymore = 1;
                                break;
                        default:
                                printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
-                                      p->local.dialstate, p->local.name);
+                                      lp->dialstate, lp->name);
                }
                p = (isdn_net_dev *) p->next;
        }
@@ -797,6 +902,10 @@ isdn_net_hangup(struct device *d)
 {
        isdn_net_local *lp = (isdn_net_local *) d->priv;
        isdn_ctrl cmd;
+#ifdef CONFIG_ISDN_X25
+       struct concap_proto *cprot = lp -> netdev -> cprot;
+       struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+#endif
 
        if (lp->flags & ISDN_NET_CONNECTED) {
                lp->flags &= ~ISDN_NET_CONNECTED;
@@ -804,10 +913,18 @@ isdn_net_hangup(struct device *d)
 #ifdef CONFIG_ISDN_PPP
                isdn_ppp_free(lp);
 #endif
+#ifdef CONFIG_ISDN_X25
+               /* try if there are generic encap protocol
+                  receiver routines and signal the closure of
+                  the link */          
+               if( pops && pops -> disconn_ind )
+                 pops -> disconn_ind(cprot);
+#endif /* CONFIG_ISDN_X25 */
+
                cmd.driver = lp->isdn_device;
                cmd.command = ISDN_CMD_HANGUP;
                cmd.arg = lp->isdn_channel;
-               (void) dev->drv[cmd.driver]->interface->command(&cmd);
+               isdn_command(&cmd);
                printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
                isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
        }
@@ -820,28 +937,43 @@ typedef struct {
 } ip_ports;
 
 static void
-isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
+isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
 {
-       u_char *p = buf;
-       unsigned short proto = ETH_P_IP;
+       u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+       unsigned short proto = ntohs(skb->protocol);
        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;
+       /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ 
+       if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
+               /* fall back to old isdn_net_log_packet method() */
+               char * buf = skb->data;
+
+               printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+               p = buf;
+               proto = ETH_P_IP;
+               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;
+#ifdef CONFIG_ISDN_PPP
+                       case ISDN_NET_ENCAP_SYNCPPP:
+                               proto = ntohs(skb->protocol);
+                               p = &buf[IPPP_MAX_HEADER];
+                               break;
+#endif
+               }
        }
        data_ofs = ((p[0] & 15) * 4);
        switch (proto) {
@@ -891,7 +1023,7 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
 
 /*
  * Generic routine to send out an skbuf.
- * If lowlevel-device does not support supports skbufs, use
+ * If lowlevel-device does not support support skbufs, use
  * standard send-routine, else send directly.
  *
  * Return: 0 on success, !0 on failure.
@@ -904,14 +1036,13 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
        int ret;
        int len = skb->len;     /* save len */
 
-       ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
+       ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
        if (ret == len) {
                lp->transcount += len;
                clear_bit(0, (void *) &(ndev->tbusy));
                return 0;
        }
        if (ret < 0) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                lp->stats.tx_errors++;
                clear_bit(0, (void *) &(ndev->tbusy));
@@ -945,7 +1076,7 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
 #endif
        /* Reset hangup-timeout */
        lp->huptimer = 0;
-       if (lp->cps > 7000) {
+       if (lp->cps > lp->triggercps) {
                /* Device overloaded */
 
                /*
@@ -988,35 +1119,64 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
        return ret;
 }
 
+static void
+isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev)
+{
+       isdn_net_local *lp = (isdn_net_local *) dev->priv;
+       if (!skb)
+               return;
+       if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+               ulong pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
+               if (pullsize)
+                       skb_pull(skb, pullsize);
+       }
+}
+
 /*
  * Try sending a packet.
  * If this interface isn't connected to a ISDN-Channel, find a free channel,
  * and start dialing.
  */
-int
+static int
 isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
 {
        isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+#ifdef CONFIG_ISDN_X25
+       struct concap_proto * cprot = lp -> netdev -> cprot; 
+#endif
 
        if (ndev->tbusy) {
                if (jiffies - ndev->trans_start < (2 * HZ))
                        return 1;
                if (!lp->dialstate)
                        lp->stats.tx_errors++;
-               ndev->tbusy = 0;
                ndev->trans_start = jiffies;
        }
-       if (skb == NULL) {
-               return 0;
-       }
-       /* Avoid timer-based retransmission conflicts. */
-       if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
-               printk(KERN_WARNING
-                      "%s: Transmitter access conflict.\n",
-                      ndev->name);
-       else {
-               u_char *buf = skb->data;
+       ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
+#ifdef CONFIG_ISDN_X25
+/* At this point hard_start_xmit() passes control to the encapsulation
+   protocol (if present). 
+   For X.25 auto-dialing is completly bypassed because:
+   - It does not conform with the semantics of a reliable datalink
+     service as needed by X.25 PLP.
+   - I don't want that the interface starts dialing when the network layer
+     sends a message which requests to disconnect the lapb link (or if it
+     sends any other message not resulting in data transmission).
+   Instead, dialing will be initiated by the encapsulation protocol entity
+   when a dl_establish request is received from the upper layer.
+*/
+       if( cprot ) {
+               return  cprot -> pops -> encap_and_xmit ( cprot , skb);
+       } else
+#endif
+       /* auto-dialing xmit function */
+       {
+#ifdef ISDN_DEBUG_NET_DUMP
+               u_char *buf;
+#endif
+               isdn_net_adjust_hdr(skb, ndev);
 #ifdef ISDN_DEBUG_NET_DUMP
+               buf = skb->data;
                isdn_dumppkt("S:", buf, skb->len, 40);
 #endif
                if (!(lp->flags & ISDN_NET_CONNECTED)) {
@@ -1033,24 +1193,15 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                                           lp->pre_device,
                                                 lp->pre_channel)) < 0) {
                                        restore_flags(flags);
-#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);
                                        ndev->tbusy = 0;
                                        return 0;
-#endif
                                }
                                /* Log packet, which triggered dialing */
                                if (dev->net_verbose)
-                                       isdn_net_log_packet(buf, lp);
+                                       isdn_net_log_skb(skb, lp);
                                lp->dialstate = 1;
                                lp->flags |= ISDN_NET_CONNECTED;
                                /* Connect interface with channel */
@@ -1114,12 +1265,26 @@ static int
 isdn_net_close(struct device *dev)
 {
        struct device *p;
+#ifdef CONFIG_ISDN_X25
+       struct concap_proto * cprot = 
+               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; 
+       /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
+#endif
 
+#ifdef CONFIG_ISDN_X25
+       if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
+#endif
        dev->tbusy = 1;
        dev->start = 0;
        if ((p = (((isdn_net_local *) dev->priv)->slave))) {
                /* If this interface has slaves, stop them also */
                while (p) {
+#ifdef CONFIG_ISDN_X25
+                       cprot = ( (isdn_net_local *) p->priv ) 
+                               -> netdev -> cprot; 
+                       if( cprot && cprot -> pops ) 
+                               cprot -> pops -> close( cprot );
+#endif
                        isdn_net_hangup(p);
                        p->tbusy = 1;
                        p->start = 0;
@@ -1156,6 +1321,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
        struct ethhdr *eth;
        unsigned char *rawp;
 
+       skb->mac.raw = skb->data;
        skb_pull(skb, ETH_HLEN);
        eth = skb->mac.ethernet;
 
@@ -1170,7 +1336,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
         *      so don't forget to remove it.
         */
 
-       else if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+       else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
                if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
                        skb->pkt_type = PACKET_OTHERHOST;
        }
@@ -1193,6 +1359,97 @@ isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
        return htons(ETH_P_802_2);
 }
 
+static void
+isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
+{
+       unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+       struct sk_buff *skb = dev_alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp));
+       unsigned long t = (jiffies / HZ * 1000000);
+       int len;
+       cisco_hdr *ch;
+       cisco_slarp *s;
+       
+       if (!skb) {
+               printk(KERN_WARNING
+                      "%s: Could not allocate SLARP reply\n", lp->name);
+               return;
+       }
+       skb_reserve(skb, hl);
+       ch = (cisco_hdr *)skb_put(skb, sizeof(cisco_hdr));
+       ch->addr = CISCO_ADDR_UNICAST;
+       ch->ctrl = 0;
+       ch->type = htons(CISCO_TYPE_SLARP);
+       s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp));
+       if (is_reply) {
+               s->code = htonl(CISCO_SLARP_REPLY);
+               memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32));
+               memset(&s->slarp.reply.netmask, 0, sizeof(__u32));
+       } else {
+               lp->cisco_myseq++;
+               s->code = htonl(CISCO_SLARP_KEEPALIVE);
+               s->slarp.keepalive.my_seq = htonl(lp->cisco_myseq);
+               s->slarp.keepalive.your_seq = htonl(lp->cisco_yourseq);
+       }
+       s->rel = 0xffff;
+       s->t1 = t >> 16;
+       s->t0 = t & 0xffff;
+       len = skb->len;
+       if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len)
+               dev_kfree_skb(skb);
+}
+
+static void
+isdn_net_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+{
+       cisco_slarp *s = (cisco_slarp *)skb->data;
+
+       switch (ntohl(s->code)) {
+               case CISCO_SLARP_REQUEST:
+                       isdn_net_slarp_send(lp, 1);
+                       break;
+               case CISCO_SLARP_REPLY:
+                       /* Ignore replies */
+                       break;
+               case CISCO_SLARP_KEEPALIVE:
+                       lp->cisco_yourseq = s->slarp.keepalive.my_seq;
+                       if (ntohl(s->slarp.keepalive.my_seq == lp->cisco_myseq)) {
+                               if (lp->cisco_loop++ == 2) {
+                                       printk(KERN_WARNING "%s: Keepalive Loop\n",
+                                              lp->name);
+                                       lp->cisco_myseq ^= jiffies;
+                               }
+                       } else
+                               lp->cisco_loop = 0;
+                       break;
+       }
+       kfree_skb(skb);
+}
+
+/*
+ * Called every 10 sec. via timer-interrupt if
+ * any network-interface has Cisco-Keepalive-Encapsulation
+ * and is online.
+ * Send Keepalive-Packet and re-schedule.
+ */
+void
+isdn_net_slarp_out(void)
+{
+       isdn_net_dev *p = dev->netdev;
+       int anymore = 0;
+
+       while (p) {
+               isdn_net_local *l = p->local;
+               if ((l->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) &&
+                   (l->flags & ISDN_NET_CONNECTED) &&
+                   (!l->dialstate)                           ) {
+                       anymore = 1;
+                       isdn_net_slarp_send(l, 0);
+               }
+               p = (isdn_net_dev *) p->next;
+       }
+       isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, anymore);
+}
+
 /*
  * Got a packet from ISDN-Channel.
  */
@@ -1200,23 +1457,19 @@ static void
 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' */
+#ifdef CONFIG_ISDN_PPP
        int proto = PPP_PROTOCOL(skb->data);
 #endif
+#ifdef CONFIG_ISDN_X25
+       struct concap_proto *cprot = lp -> netdev -> cprot;
+#endif
+       cisco_hdr *ch;
 
        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))
-#endif
-               lp->huptimer = 0;
 
+       lp->stats.rx_packets++;
+       lp->stats.rx_bytes += skb->len;
        if (lp->master) {
                /* Bundling: If device is a slave-device, deliver to master, also
                 * handle master's statistics and hangup-timeout
@@ -1224,16 +1477,9 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
                ndev = lp->master;
                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))
-#endif
-                       lp->huptimer = 0;
+               lp->stats.rx_bytes += skb->len;
        }
+
        skb->dev = ndev;
        skb->pkt_type = PACKET_HOST;
        skb->mac.raw = skb->data;
@@ -1243,22 +1489,61 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
        switch (lp->p_encap) {
                case ISDN_NET_ENCAP_ETHER:
                        /* Ethernet over ISDN */
+                       olp->huptimer = 0;
+                       lp->huptimer = 0;
                        skb->protocol = isdn_net_type_trans(skb, ndev);
                        break;
                case ISDN_NET_ENCAP_UIHDLC:
                        /* HDLC with UI-frame (for ispa with -h1 option) */
+                       olp->huptimer = 0;
+                       lp->huptimer = 0;
                        skb_pull(skb, 2);
                        /* Fall through */
                case ISDN_NET_ENCAP_RAWIP:
                        /* RAW-IP without MAC-Header */
+                       olp->huptimer = 0;
+                       lp->huptimer = 0;
                        skb->protocol = htons(ETH_P_IP);
                        break;
+               case ISDN_NET_ENCAP_CISCOHDLCK:
+                       ch = (cisco_hdr *)skb->data;
+                       if ((ch->addr != CISCO_ADDR_UNICAST) &&
+                           (ch->addr != CISCO_ADDR_BROADCAST)  ) {
+                               printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
+                                      lp->name, ch->addr);
+                               kfree_skb(skb);
+                               return;
+                       }
+                       if (ch->ctrl != 0) {
+                               printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
+                                      lp->name, ch->ctrl);
+                               kfree_skb(skb);
+                               return;
+                       }
+                       switch (ntohs(ch->type)) {
+                               case CISCO_TYPE_INET:
+                                       skb_pull(skb, 4);
+                                       skb->protocol = htons(ETH_P_IP);
+                                       break;
+                               case CISCO_TYPE_SLARP:
+                                       skb_pull(skb, 4);
+                                       isdn_net_slarp_in(olp, skb);
+                                       return;
+                               default:
+                                       printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
+                                              lp->name, ch->type);
+                                       kfree_skb(skb);
+                                       return;
+                       }
+                       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 */
+                       olp->huptimer = 0;
+                       lp->huptimer = 0;
                        skb->protocol = *(unsigned short *) &(skb->data[0]);
                        skb_pull(skb, 2);
                        if (*(unsigned short *) skb->data == 0xFFFF)
@@ -1266,10 +1551,26 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
                        break;
 #ifdef CONFIG_ISDN_PPP
                case ISDN_NET_ENCAP_SYNCPPP:
+                       /*
+                        * If encapsulation is syncppp, don't reset
+                        * huptimer on LCP packets.
+                        */
+                       if (proto != PPP_LCP) {
+                               olp->huptimer = 0;
+                               lp->huptimer = 0;
+                       }
                        isdn_ppp_receive(lp->netdev, olp, skb);
                        return;
 #endif
                default:
+#ifdef CONFIG_ISDN_X25
+                 /* try if there are generic sync_device receiver routines */
+                       if(cprot) if(cprot -> pops) 
+                               if( cprot -> pops -> data_ind){
+                                       cprot -> pops -> data_ind(cprot,skb);
+                                       return;
+                               };
+#endif /* CONFIG_ISDN_X25 */
                        printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
                               lp->name);
                        kfree_skb(skb);
@@ -1290,7 +1591,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
        isdn_net_dev *p = dev->rx_netdev[idx];
 
        if (p) {
-               isdn_net_local *lp = &p->local;
+               isdn_net_local *lp = p->local;
                if ((lp->flags & ISDN_NET_CONNECTED) &&
                    (!lp->dialstate)) {
                        isdn_net_receive(&p->dev, skb);
@@ -1329,15 +1630,15 @@ my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
         * Anyway, the loopback-device should never use this function...
         */
 
-       if (dev->flags & IFF_LOOPBACK) {
+       if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
                memset(eth->h_dest, 0, dev->addr_len);
-               return (dev->hard_header_len);
+               return ETH_HLEN /*(dev->hard_header_len)*/;
        }
        if (daddr) {
                memcpy(eth->h_dest, daddr, dev->addr_len);
-               return dev->hard_header_len;
+               return ETH_HLEN /*dev->hard_header_len*/;
        }
-       return -dev->hard_header_len;
+       return -ETH_HLEN /*dev->hard_header_len*/;
 }
 
 /*
@@ -1356,6 +1657,13 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
                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;
@@ -1377,43 +1685,21 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
                        *((ushort *) & skb->data[2]) = htons(type);
                        len = 4;
                        break;
+#ifdef CONFIG_ISDN_X25
+               default:
+                 /* try if there are generic concap protocol routines */
+                       if( lp-> netdev -> cprot ){
+                               printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
+                               len = 0;
+                               break;
+                       }
+                       break;
+#endif /* CONFIG_ISDN_X25 */
        }
        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)
-{
-       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
-       }
-       return ret;
-}
-#else
 static int
 isdn_net_rebuild_header(struct sk_buff *skb)
 {
@@ -1439,12 +1725,12 @@ isdn_net_rebuild_header(struct sk_buff *skb)
                 *      Try to get ARP to resolve the header.
                 */
 #ifdef CONFIG_INET
-               ret = arp_find(eth->h_dest, skb) ? 1 : 0;
+               ret = arp_find(eth->h_dest, skb);
 #endif
        }
        return ret;
 }
-#endif
+
 /*
  * Interface-setup. (called just after registering a new interface)
  */
@@ -1465,21 +1751,13 @@ isdn_net_init(struct device *ndev)
                return -ENODEV;
        }
        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;
-#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|IFF_POINTOPOINT;
@@ -1599,13 +1877,13 @@ isdn_net_swapbind(int drvidx)
 #endif
        p = dev->netdev;
        while (p) {
-               if (p->local.pre_device == drvidx)
-                       switch (p->local.pre_channel) {
+               if (p->local->pre_device == drvidx)
+                       switch (p->local->pre_channel) {
                                case 0:
-                                       p->local.pre_channel = 1;
+                                       p->local->pre_channel = 1;
                                        break;
                                case 1:
-                                       p->local.pre_channel = 0;
+                                       p->local->pre_channel = 0;
                                        break;
                        }
                p = (isdn_net_dev *) p->next;
@@ -1676,6 +1954,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
        /* Accept only calls with Si1 = 7 (Data-Transmission) */
        if (si1 != 7) {
+               restore_flags(flags);
                if (dev->net_verbose > 1)
                        printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
                return 0;
@@ -1689,6 +1968,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 #endif
        swapped = 0;
        while (p) {
+               isdn_net_local *lp = p->local;
+
                /* If last check has triggered as binding-swap, revert it */
                switch (swapped) {
                        case 2:
@@ -1699,25 +1980,25 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                break;
                }
                swapped = 0;
-               if (!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz))
+               if (!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz))
                        ematch = 1;
 #ifdef ISDN_DEBUG_NET_ICALL
                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);
+                      lp->name, lp->msn, lp->flags, lp->dialstate);
 #endif
-               if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) &&       /* EAZ is matching   */
-                   (((!(p->local.flags & ISDN_NET_CONNECTED)) &&       /* but not connected */
+               if ((!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) &&    /* EAZ is matching   */
+                   (((!(lp->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   */
+                    ((((lp->dialstate == 4) || (lp->dialstate == 12)) &&       /* if dialing        */
+                      (!(lp->flags & ISDN_NET_CALLBACK)))      /* but no callback   */
                     ))) {
 #ifdef ISDN_DEBUG_NET_ICALL
                        printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
-                              p->local.pre_device, p->local.pre_channel);
+                              lp->pre_device, lp->pre_channel);
 #endif
                        if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
-                               if ((p->local.pre_channel != ch) ||
-                                   (p->local.pre_device != di)) {
+                               if ((lp->pre_channel != ch) ||
+                                   (lp->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
@@ -1741,8 +2022,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 #endif
                                                                /* Yes, swap bindings only, if the original
                                                                 * binding is bound to channel 1 of this driver */
-                                                               if ((p->local.pre_device == di) &&
-                                                                   (p->local.pre_channel == 1)) {
+                                                               if ((lp->pre_device == di) &&
+                                                                   (lp->pre_channel == 1)) {
                                                                        isdn_net_swapbind(di);
                                                                        swapped = 1;
                                                                } else {
@@ -1764,8 +2045,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                                        printk(KERN_DEBUG "n_fi: final check\n");
 #endif
                                                        if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) &&
-                                                           ((p->local.pre_channel != ch) ||
-                                                            (p->local.pre_device != di))) {
+                                                           ((lp->pre_channel != ch) ||
+                                                            (lp->pre_device != di))) {
 #ifdef ISDN_DEBUG_NET_ICALL
                                                                printk(KERN_DEBUG "n_fi: final check failed\n");
 #endif
@@ -1786,16 +2067,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 #ifdef ISDN_DEBUG_NET_ICALL
                        printk(KERN_DEBUG "n_fi: match2\n");
 #endif
-                       n = p->local.phone[0];
-                       if (p->local.flags & ISDN_NET_SECURE) {
+                       n = lp->phone[0];
+                       if (lp->flags & ISDN_NET_SECURE) {
                                while (n) {
                                        if (isdn_net_wildmat(nr, n->num))
                                                break;
                                        n = (isdn_net_phone *) n->next;
                                }
                        }
-                       if (n || (!(p->local.flags & ISDN_NET_SECURE))) {
-                               isdn_net_local *lp = &(p->local);
+                       if (n || (!(lp->flags & ISDN_NET_SECURE))) {
 #ifdef ISDN_DEBUG_NET_ICALL
                                printk(KERN_DEBUG "n_fi: match3\n");
 #endif
@@ -1804,7 +2084,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                 */
                                if (!p->dev.start) {
                                        restore_flags(flags);
-                                       printk(KERN_INFO "%s: incoming call, if down -> rejected\n",
+                                       printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
                                               lp->name);
                                        return 3;
                                }
@@ -1872,12 +2152,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                               eaz);
                                        /* if this interface is dialing, it does it probably on a different
                                           device, so free this device */
-                                       if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) {
+                                       if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
 #ifdef CONFIG_ISDN_PPP
                                                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_free_channel(lp->isdn_device, lp->isdn_channel,
                                                         ISDN_USAGE_NET);
                                        }
                                        dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
@@ -1885,16 +2165,16 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                        strcpy(dev->num[idx], nr);
                                        isdn_info_update();
                                        dev->st_netdev[idx] = lp->netdev;
-                                       p->local.isdn_device = di;
-                                       p->local.isdn_channel = ch;
-                                       p->local.ppp_slot = -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 |= ISDN_WAITCHARGE;
-                                       p->local.hupflags &= ~ISDN_HAVECHARGE;
+                                       lp->isdn_device = di;
+                                       lp->isdn_channel = ch;
+                                       lp->ppp_slot = -1;
+                                       lp->flags |= ISDN_NET_CONNECTED;
+                                       lp->dialstate = 7;
+                                       lp->dtimer = 0;
+                                       lp->outgoing = 0;
+                                       lp->huptimer = 0;
+                                       lp->hupflags |= ISDN_WAITCHARGE;
+                                       lp->hupflags &= ~ISDN_HAVECHARGE;
 #ifdef CONFIG_ISDN_PPP
                                        if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
                                                if (isdn_ppp_bind(lp) < 0) {
@@ -1926,7 +2206,7 @@ isdn_net_findif(char *name)
        isdn_net_dev *p = dev->netdev;
 
        while (p) {
-               if (!strcmp(p->local.name, name))
+               if (!strcmp(p->local->name, name))
                        return p;
                p = (isdn_net_dev *) p->next;
        }
@@ -1989,7 +2269,7 @@ isdn_net_force_dial(char *name)
 
        if (!p)
                return -ENODEV;
-       return (isdn_net_force_dial_lp(&p->local));
+       return (isdn_net_force_dial_lp(p->local));
 }
 
 /*
@@ -2010,20 +2290,25 @@ isdn_net_new(char *name, struct device *master)
                return NULL;
        }
        memset(netdev, 0, sizeof(isdn_net_dev));
+       if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
+               printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+               return NULL;
+       }
+       memset(netdev->local, 0, sizeof(isdn_net_local));
        if (name == NULL)
-               strcpy(netdev->local.name, "         ");
+               strcpy(netdev->local->name, "         ");
        else
-               strcpy(netdev->local.name, name);
-       netdev->dev.name = netdev->local.name;
-       netdev->dev.priv = &netdev->local;
+               strcpy(netdev->local->name, name);
+       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;
+       netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
        if (master) {
                /* Device shall be a slave */
                struct device *p = (((isdn_net_local *) master->priv)->slave);
                struct device *q = master;
 
-               netdev->local.master = master;
+               netdev->local->master = master;
                /* Put device at end of slave-chain */
                while (p) {
                        q = p;
@@ -2037,41 +2322,43 @@ isdn_net_new(char *name, struct device *master)
                /* Device shall be a master */
                if (register_netdev(&netdev->dev) != 0) {
                        printk(KERN_WARNING "isdn_net: Could not register net-device\n");
+                       kfree(netdev->local);
                        kfree(netdev);
                        return NULL;
                }
        }
-       netdev->local.magic = ISDN_NET_MAGIC;
+       netdev->local->magic = ISDN_NET_MAGIC;
 
 #ifdef CONFIG_ISDN_PPP
        netdev->mp_last = NULL; /* mpqueue is empty */
        netdev->ib.next_num = 0;
        netdev->ib.last = NULL;
 #endif
-       netdev->queue = &netdev->local;
-       netdev->local.last = &netdev->local;
-       netdev->local.netdev = netdev;
-       netdev->local.next = &netdev->local;
-
-       netdev->local.isdn_device = -1;
-       netdev->local.isdn_channel = -1;
-       netdev->local.pre_device = -1;
-       netdev->local.pre_channel = -1;
-       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.l2_proto = ISDN_PROTO_L2_X75I;
-       netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
-       netdev->local.slavedelay = 10 * HZ;
-       netdev->local.srobin = &netdev->dev;
-       netdev->local.hupflags = ISDN_INHUP;    /* Do hangup even on incoming calls */
-       netdev->local.onhtime = 10;     /* Default hangup-time for saving costs
+       netdev->queue = netdev->local;
+       netdev->local->last = netdev->local;
+       netdev->local->netdev = netdev;
+       netdev->local->next = netdev->local;
+
+       netdev->local->isdn_device = -1;
+       netdev->local->isdn_channel = -1;
+       netdev->local->pre_device = -1;
+       netdev->local->pre_channel = -1;
+       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->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 = ISDN_INHUP;   /* Do hangup even on incoming calls */
+       netdev->local->onhtime = 10;    /* Default hangup-time for saving costs
           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->dialmax = 1;
+       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;
@@ -2095,7 +2382,7 @@ isdn_net_newslave(char *parm)
                if (!(n = isdn_net_findif(parm)))
                        return NULL;
                /* Master must be a real interface, not a slave */
-               if (n->local.master)
+               if (n->local->master)
                        return NULL;
                /* Master must not be started yet */
                if (n->dev.start)
@@ -2120,10 +2407,15 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
        int drvidx;
        int chidx;
        char drvid[25];
-
+#ifdef CONFIG_ISDN_X25
+       ulong flags;
+#endif
        if (p) {
+               isdn_net_local *lp = p->local;
+
                /* See if any registered driver supports the features we want */
-               features = (1 << cfg->l2_proto) | (256 << cfg->l3_proto);
+               features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
+                       ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
                        if (dev->drv[i])
                                if ((dev->drv[i]->interface->features & features) == features)
@@ -2132,22 +2424,68 @@ 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 (lp->p_encap != cfg->p_encap){
+#ifdef CONFIG_ISDN_X25
+                       struct concap_proto * cprot = p -> cprot;
+#endif
                        if (p->dev.start) {
                                printk(KERN_WARNING
                                "%s: cannot change encap when if is up\n",
-                                      p->local.name);
+                                      lp->name);
                                return -EBUSY;
                        }
-               if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+#ifdef CONFIG_ISDN_X25
+                       /* delete old encapsulation protocol if present ... */
+                       save_flags(flags);
+                       cli(); /* avoid races with incoming events trying to
+                                 call cprot->pops methods */
+                       if( cprot && cprot -> pops ) 
+                               cprot -> pops -> proto_del ( cprot );
+                       p -> cprot = NULL;
+                       lp -> dops = NULL;
+                       restore_flags(flags);
+                       /* ... ,  prepare for configuration of new one ... */
+                       switch ( cfg -> p_encap ){
+                       case ISDN_NET_ENCAP_X25IFACE:
+                               lp -> dops = &isdn_concap_reliable_dl_dops;
+                       }
+                       /* ... and allocate new one ... */
+                       p -> cprot = isdn_concap_new( cfg -> p_encap );
+                       /* p -> cprot == NULL now if p_encap is not supported
+                          by means of the concap_proto mechanism */
+                       /* the protocol is not configured yet; this will 
+                          happen later when isdn_net_reset() is called */
+#endif
+               }
+               switch ( cfg->p_encap ) {
+               case ISDN_NET_ENCAP_SYNCPPP:
 #ifndef CONFIG_ISDN_PPP
                        printk(KERN_WARNING "%s: SyncPPP support not configured\n",
-                              p->local.name);
+                              lp->name);
                        return -EINVAL;
 #else
                        p->dev.type = ARPHRD_PPP;       /* change ARP type */
                        p->dev.addr_len = 0;
 #endif
+                       break;
+               case ISDN_NET_ENCAP_X25IFACE:
+#ifndef CONFIG_ISDN_X25
+                       printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
+                              p->local->name);
+                       return -EINVAL;
+#else
+                       p->dev.type = ARPHRD_X25;       /* change ARP type */
+                       p->dev.addr_len = 0;
+#endif
+                       break;
+               default:
+                       if( cfg->p_encap >= 0 &&
+                           cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
+                               break;
+                       printk(KERN_WARNING 
+                              "%s: encapsulation protocol %d not supported\n",
+                              p->local->name, cfg->p_encap);
+                       return -EINVAL;
                }
                if (strlen(cfg->drvid)) {
                        /* A bind has been requested ... */
@@ -2175,20 +2513,20 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                                return -ENODEV;
                } else {
                        /* Parameters are valid, so get them */
-                       drvidx = p->local.pre_device;
-                       chidx = p->local.pre_channel;
+                       drvidx = lp->pre_device;
+                       chidx = lp->pre_channel;
                }
                if (cfg->exclusive > 0) {
                        int flags;
 
                        /* 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,
+                       if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
+                                                      lp->l3_proto,
                                                       drvidx,
                                                       chidx)) < 0) {
                                /* Grab failed, because desired channel is in use */
-                               p->local.exclusive = -1;
+                               lp->exclusive = -1;
                                restore_flags(flags);
                                return -EBUSY;
                        }
@@ -2196,93 +2534,82 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        dev->usage[i] = ISDN_USAGE_EXCLUSIVE;
                        isdn_info_update();
                        restore_flags(flags);
-                       p->local.exclusive = i;
+                       lp->exclusive = i;
                } else {
                        /* Non-exclusive binding or unbind. */
-                       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);
+                       lp->exclusive = -1;
+                       if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
+                               isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
+                               isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
                                drvidx = -1;
                                chidx = -1;
                        }
                }
-               strcpy(p->local.msn, cfg->eaz);
-               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;
+               strcpy(lp->msn, cfg->eaz);
+               lp->pre_device = drvidx;
+               lp->pre_channel = chidx;
+               lp->onhtime = cfg->onhtime;
+               lp->charge = cfg->charge;
+               lp->l2_proto = cfg->l2_proto;
+               lp->l3_proto = cfg->l3_proto;
+               lp->cbdelay = cfg->cbdelay;
+               lp->dialmax = cfg->dialmax;
+               lp->triggercps = cfg->triggercps;
+               lp->slavedelay = cfg->slavedelay * HZ;
+               lp->pppbind = cfg->pppbind;
                if (cfg->secure)
-                       p->local.flags |= ISDN_NET_SECURE;
+                       lp->flags |= ISDN_NET_SECURE;
                else
-                       p->local.flags &= ~ISDN_NET_SECURE;
+                       lp->flags &= ~ISDN_NET_SECURE;
                if (cfg->cbhup)
-                       p->local.flags |= ISDN_NET_CBHUP;
+                       lp->flags |= ISDN_NET_CBHUP;
                else
-                       p->local.flags &= ~ISDN_NET_CBHUP;
+                       lp->flags &= ~ISDN_NET_CBHUP;
                switch (cfg->callback) {
                        case 0:
-                               p->local.flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+                               lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
                                break;
                        case 1:
-                               p->local.flags |= ISDN_NET_CALLBACK;
-                               p->local.flags &= ~ISDN_NET_CBOUT;
+                               lp->flags |= ISDN_NET_CALLBACK;
+                               lp->flags &= ~ISDN_NET_CBOUT;
                                break;
                        case 2:
-                               p->local.flags |= ISDN_NET_CBOUT;
-                               p->local.flags &= ~ISDN_NET_CALLBACK;
+                               lp->flags |= ISDN_NET_CBOUT;
+                               lp->flags &= ~ISDN_NET_CALLBACK;
                                break;
                }
                if (cfg->chargehup)
-                       p->local.hupflags |= ISDN_CHARGEHUP;
+                       lp->hupflags |= ISDN_CHARGEHUP;
                else
-                       p->local.hupflags &= ~ISDN_CHARGEHUP;
+                       lp->hupflags &= ~ISDN_CHARGEHUP;
                if (cfg->ihup)
-                       p->local.hupflags |= ISDN_INHUP;
+                       lp->hupflags |= ISDN_INHUP;
                else
-                       p->local.hupflags &= ~ISDN_INHUP;
+                       lp->hupflags &= ~ISDN_INHUP;
                if (cfg->chargeint > 10) {
-                       p->local.hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
-                       p->local.chargeint = cfg->chargeint * HZ;
+                       lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+                       lp->chargeint = cfg->chargeint * HZ;
                }
-               if (cfg->p_encap != p->local.p_encap) {
+               if (cfg->p_encap != lp->p_encap) {
                        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|IFF_POINTOPOINT;
                        } 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.hard_header_cache = lp->org_hhc;
+                                       p->dev.header_cache_update = lp->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|IFF_POINTOPOINT;
                                }
                        }
                }
-               p->local.p_encap = cfg->p_encap;
+               lp->p_encap = cfg->p_encap;
                return 0;
        }
        return -ENODEV;
@@ -2297,39 +2624,42 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
        isdn_net_dev *p = isdn_net_findif(cfg->name);
 
        if (p) {
-               strcpy(cfg->eaz, p->local.msn);
-               cfg->exclusive = p->local.exclusive;
-               if (p->local.pre_device >= 0) {
-                       sprintf(cfg->drvid, "%s,%d", dev->drvid[p->local.pre_device],
-                               p->local.pre_channel);
+               isdn_net_local *lp = p->local;
+
+               strcpy(cfg->eaz, lp->msn);
+               cfg->exclusive = lp->exclusive;
+               if (lp->pre_device >= 0) {
+                       sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
+                               lp->pre_channel);
                } else
                        cfg->drvid[0] = '\0';
-               cfg->onhtime = p->local.onhtime;
-               cfg->charge = p->local.charge;
-               cfg->l2_proto = p->local.l2_proto;
-               cfg->l3_proto = p->local.l3_proto;
-               cfg->p_encap = p->local.p_encap;
-               cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
+               cfg->onhtime = lp->onhtime;
+               cfg->charge = lp->charge;
+               cfg->l2_proto = lp->l2_proto;
+               cfg->l3_proto = lp->l3_proto;
+               cfg->p_encap = lp->p_encap;
+               cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
                cfg->callback = 0;
-               if (p->local.flags & ISDN_NET_CALLBACK)
+               if (lp->flags & ISDN_NET_CALLBACK)
                        cfg->callback = 1;
-               if (p->local.flags & ISDN_NET_CBOUT)
+               if (lp->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->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);
+               cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+               cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
+               cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
+               cfg->cbdelay = lp->cbdelay;
+               cfg->dialmax = lp->dialmax;
+               cfg->triggercps = lp->triggercps;
+               cfg->slavedelay = lp->slavedelay / HZ;
+               cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
+                   (lp->chargeint / HZ) : 0;
+               cfg->pppbind = lp->pppbind;
+               if (lp->slave)
+                       strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
                else
                        cfg->slave[0] = '\0';
-               if (p->local.master)
-                       strcpy(cfg->master, ((isdn_net_local *) p->local.master->priv)->name);
+               if (lp->master)
+                       strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
                else
                        cfg->master[0] = '\0';
                return 0;
@@ -2352,8 +2682,8 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
                if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
                        return -ENOMEM;
                strcpy(n->num, phone->phone);
-               n->next = p->local.phone[phone->outgoing & 1];
-               p->local.phone[phone->outgoing & 1] = n;
+               n->next = p->local->phone[phone->outgoing & 1];
+               p->local->phone[phone->outgoing & 1] = n;
                return 0;
        }
        return -ENODEV;
@@ -2378,7 +2708,7 @@ 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++;
@@ -2413,16 +2743,16 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
        if (p) {
                save_flags(flags);
                cli();
-               n = p->local.phone[inout];
+               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 (p->local->dial == n)
+                                       p->local->dial = n->next;
                                if (m)
                                        m->next = n->next;
                                else
-                                       p->local.phone[inout] = n->next;
+                                       p->local->phone[inout] = n->next;
                                kfree(n);
                                return 0;
                        }
@@ -2449,15 +2779,15 @@ isdn_net_rmallphone(isdn_net_dev * p)
        save_flags(flags);
        cli();
        for (i = 0; i < 2; i++) {
-               n = p->local.phone[i];
+               n = p->local->phone[i];
                while (n) {
                        m = n->next;
                        kfree(n);
                        n = m;
                }
-               p->local.phone[i] = NULL;
+               p->local->phone[i] = NULL;
        }
-       p->local.dial = NULL;
+       p->local->dial = NULL;
        restore_flags(flags);
        return 0;
 }
@@ -2472,9 +2802,9 @@ isdn_net_force_hangup(char *name)
        struct device *q;
 
        if (p) {
-               if (p->local.isdn_device < 0)
+               if (p->local->isdn_device < 0)
                        return 1;
-               q = p->local.slave;
+               q = p->local->slave;
                /* If this interface has slaves, do a hangup for them also. */
                while (q) {
                        isdn_net_hangup(q);
@@ -2496,7 +2826,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
 
        save_flags(flags);
        cli();
-       if (p->local.master) {
+       if (p->local->master) {
                /* If it's a slave, it may be removed even if it is busy. However
                 * it has to be hung up first.
                 */
@@ -2507,30 +2837,37 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
                restore_flags(flags);
                return -EBUSY;
        }
+#ifdef CONFIG_ISDN_X25
+       if( p -> cprot && p -> cprot -> pops )
+               p -> cprot -> pops -> proto_del ( p -> cprot );
+#endif
        /* Free all phone-entries */
        isdn_net_rmallphone(p);
        /* If interface is bound exclusive, free channel-usage */
-       if (p->local.exclusive != -1)
-               isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
-       if (p->local.master) {
+       if (p->local->exclusive != -1)
+               isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
+       if (p->local->master) {
                /* It's a slave-device, so update master's slave-pointer if necessary */
-               if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
-                       ((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
-       } else
+               if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+                       ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
+       } else {
                /* Unregister only if it's a master-device */
+               p->dev.hard_header_cache = p->local->org_hhc;
+               p->dev.header_cache_update = p->local->org_hcu;
                unregister_netdev(&p->dev);
+       }
        /* Unlink device from chain */
        if (q)
                q->next = p->next;
        else
                dev->netdev = p->next;
-       if (p->local.slave) {
+       if (p->local->slave) {
                /* If this interface has a slave, remove it also */
-               char *slavename = ((isdn_net_local *) (p->local.slave->priv))->name;
+               char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
                isdn_net_dev *n = dev->netdev;
                q = NULL;
                while (n) {
-                       if (!strcmp(n->local.name, slavename)) {
+                       if (!strcmp(n->local->name, slavename)) {
                                isdn_net_realrm(n, q);
                                break;
                        }
@@ -2543,6 +2880,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
                isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
        restore_flags(flags);
 
+       kfree(p->local);
        kfree(p);
 
        return 0;
@@ -2561,7 +2899,7 @@ isdn_net_rm(char *name)
        p = dev->netdev;
        q = NULL;
        while (p) {
-               if (!strcmp(p->local.name, name))
+               if (!strcmp(p->local->name, name))
                        return (isdn_net_realrm(p, q));
                q = p;
                p = (isdn_net_dev *) p->next;
@@ -2585,7 +2923,7 @@ isdn_net_rmall(void)
        save_flags(flags);
        cli();
        while (dev->netdev) {
-               if (!dev->netdev->local.master) {
+               if (!dev->netdev->local->master) {
                        /* Remove master-devices only, slaves get removed with their master */
                        if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
                                restore_flags(flags);
index 56df21081e9c555c0e86500081cffcd7578418fe..19a084dd2189b97e8c2f7d2d731002b77f8a0629 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.5 1997/02/10 20:12:47 fritz Exp $
+/* $Id: isdn_net.h,v 1.6 1997/10/09 21:28:54 fritz Exp $
 
  * header for Linux ISDN subsystem, network related functions (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.h,v $
+ * Revision 1.6  1997/10/09 21:28:54  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
  * Revision 1.5  1997/02/10 20:12:47  fritz
  * Changed interface for reporting incoming calls.
  *
 #define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
 #define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
 
+/*
+ * Definitions for Cisco-HDLC header.
+ */
+
+typedef struct cisco_hdr {
+       __u8  addr; /* unicast/broadcast */
+       __u8  ctrl; /* Always 0          */
+       __u16 type; /* IP-typefield      */
+} cisco_hdr;
+
+typedef struct cisco_slarp {
+       __u32 code;                     /* SLREQ/SLREPLY/KEEPALIVE */
+       union {
+               struct {
+                       __u32 ifaddr;   /* My interface address     */
+                       __u32 netmask;  /* My interface netmask     */
+               } reply;
+               struct {
+                       __u32 my_seq;   /* Packet sequence number   */
+                       __u32 your_seq;
+               } keepalive;
+       } slarp;
+       __u16 rel;                      /* Always 0xffff            */
+       __u16 t1;                       /* Uptime in usec >> 16     */
+       __u16 t0;                       /* Uptime in usec & 0xffff  */
+} cisco_slarp;
+
+#define CISCO_ADDR_UNICAST    0x0f
+#define CISCO_ADDR_BROADCAST  0x8f
+#define CISCO_TYPE_INET       0x0800
+#define CISCO_TYPE_SLARP      0x8035
+#define CISCO_SLARP_REPLY     0
+#define CISCO_SLARP_REQUEST   1
+#define CISCO_SLARP_KEEPALIVE 2
+
 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_stat_callback(int, isdn_ctrl *);
 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 *);
@@ -65,3 +110,4 @@ 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 *);
+extern void isdn_net_slarp_out(void);
index 0f29e340afbe4adf8ef38058504e49b8279cb5ce..a4a45d9eac49cf72e79cae2ebf2e4c1d9bf5e666 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.27 1997/03/30 16:51:17 calle Exp $
+/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.33  1998/02/20 17:11:54  fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.32  1998/01/31 19:29:55  calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.31  1997/10/09 21:29:01  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.30  1997/10/01 09:20:38  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.29  1997/08/21 23:11:44  fritz
+ * Added changes for kernels >= 2.1.45
+ *
+ * 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.
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isdn.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
 #include <linux/poll.h>
-#endif
 #include "isdn_common.h"
 #include "isdn_ppp.h"
 #include "isdn_net.h"
@@ -148,6 +177,12 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
                                 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);
@@ -160,7 +195,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
 static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision = "$Revision: 1.27 $";
+char *isdn_ppp_revision = "$Revision: 1.33 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -267,7 +302,7 @@ isdn_ppp_bind(isdn_net_local * lp)
                char exclusive[ISDN_MAX_CHANNELS];      /* exclusive flags */
                memset(exclusive, 0, ISDN_MAX_CHANNELS);
                while (net_dev) {       /* step through net devices to find exclusive minors */
-                       isdn_net_local *lp = &net_dev->local;
+                       isdn_net_local *lp = net_dev->local;
                        if (lp->pppbind >= 0)
                                exclusive[lp->pppbind] = 1;
                        net_dev = net_dev->next;
@@ -382,7 +417,12 @@ isdn_ppp_open(int min, struct file *file)
        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 = NULL;
        is->mp_seqno = 0;       /* MP sequence number */
        is->pppcfg = 0;         /* ppp configuration */
@@ -644,50 +684,6 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
        return 0;
 }
 
-#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;
-       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->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);
-                               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;
-       }
-       return 1;
-}
-#else
 unsigned int
 isdn_ppp_poll(struct file *file, poll_table * wait)
 {
@@ -700,7 +696,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
        is = file->private_data;
 
        if (is->debug & 0x2)
-               printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev));
+               printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
+                               MINOR(file->f_dentry->d_inode->i_rdev));
 
        poll_wait(file, &is->wq, wait);
 
@@ -725,8 +722,6 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
        restore_flags(flags);
        return mask;
 }
-#endif
-
 
 /*
  *  fill up isdn_ppp_read() queue ..
@@ -798,31 +793,35 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
        struct ippp_buf_queue *b;
        int r;
        unsigned long flags;
+       unsigned char *save_buf;
 
        is = file->private_data;
 
        if (!(is->state & IPPP_OPEN))
                return 0;
 
+       if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
+               return r;
+
        save_flags(flags);
        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;
-       if ((r = copy_to_user(buf, b->buf, count))) {
-               restore_flags(flags);
-               return r;
-       }
-       kfree(b->buf);
        b->buf = NULL;
        is->first = b;
+
        restore_flags(flags);
 
+       copy_to_user(buf, save_buf, count);
+       kfree(save_buf);
+
        return count;
 }
 
@@ -872,14 +871,13 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                                printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
                                return count;
                        }
-                       SET_SKB_FREE(skb);
                        if (copy_from_user(skb_put(skb, count), buf, count))
                                return -EFAULT;
                        if (is->debug & 0x40) {
                                printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
                                isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
                        }
-                       if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+                       if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
                                if (lp->sav_skb) {
                                        dev_kfree_skb(lp->sav_skb);
                                        printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
@@ -934,46 +932,66 @@ isdn_ppp_cleanup(void)
                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)
+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: %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);
        else if (is->pppcfg & SC_REJ_COMP_AC) {
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                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;
+                       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,
@@ -987,6 +1005,10 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                                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 */
@@ -995,9 +1017,14 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                                        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)
@@ -1006,11 +1033,14 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                                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;
                                {
@@ -1064,7 +1094,6 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                                if (!q) {
                                        net_dev->ib.modify = 0;
                                        printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
-                                       SET_SKB_FREE(skb);
                                        dev_kfree_skb(skb);
                                        return; /* discard */
                                }
@@ -1093,7 +1122,8 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                                 * 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);
                        net_dev->ib.modify = 0;
@@ -1102,7 +1132,7 @@ isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *sk
                        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);
 }
 
 /*
@@ -1115,19 +1145,21 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
        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(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)
@@ -1140,10 +1172,9 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                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) {
+                       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++;
-                               SET_SKB_FREE(skb);
+                               net_dev->local->stats.rx_dropped++;
                                dev_kfree_skb(skb);
                                return;
                        }
@@ -1164,11 +1195,9 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                                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++;
+                                       net_dev->local->stats.rx_dropped++;
                                        dev_kfree_skb(skb_old);
                                        return;
                                }
@@ -1176,11 +1205,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                                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,
+                               pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
                                                skb->data, skb_old->len);
                                dev_kfree_skb(skb_old);
                                if (pkt_len < 0) {
-                                       SET_SKB_FREE(skb);
                                        dev_kfree_skb(skb);
                                        lp->stats.rx_dropped++;
                                        return;
@@ -1191,26 +1219,45 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
 #else
                        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);
                        return;
 #endif
                        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);
                        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;
 
        return;
 }
 
+/*
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
+ */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
+{
+       struct sk_buff *skb = *skb_p;
+
+       if(skb_headroom(skb) < len) {
+               printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+       return skb_push(skb,len);
+}
+
+
 /*
  * send ppp frame .. we expect a PIDCOMPressable proto --
  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
@@ -1223,12 +1270,10 @@ int
 isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */
-       isdn_net_local *lp,
-       *mlp;
+       isdn_net_local *lp,*mlp;
        isdn_net_dev *nd;
        unsigned int proto = PPP_IP;     /* 0x21 */
-       struct ippp_struct *ipt,
-       *ipts;
+       struct ippp_struct *ipt,*ipts;
 
        if (mdev)
                mlp = (isdn_net_local *) (mdev->priv);
@@ -1250,6 +1295,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
                        printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
                return 1;
        }
+
        switch (ntohs(skb->protocol)) {
                case ETH_P_IP:
                        proto = PPP_IP;
@@ -1297,11 +1343,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
         * after this line .. requeueing in the device queue is no longer allowed!!!
         */
 
+       /* 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);
@@ -1310,14 +1363,13 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
                        int pktlen;
 
                        new_skb->dev = skb->dev;
-                       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));
 
-                       if (buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
+                       if (buf != skb->data) { 
                                if (new_skb->data != buf)
                                        printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
                                dev_kfree_skb(skb);
@@ -1339,6 +1391,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        }
 #endif
 
+    /*
+     * 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);
 
@@ -1349,13 +1406,17 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
                ipts->mp_seqno++;
                nd->queue = nd->queue->next;
                if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
-                       unsigned char *data = skb_push(skb, 3);
+                       unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+                       if(!data)
+                               return 0;
                        mp_seqno &= 0xfff;
-                       data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8);        /* (B)egin & (E)ndbit .. */
+                       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 {
-                       unsigned char *data = skb_push(skb, 5);
+                       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;
@@ -1365,17 +1426,29 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
                proto = PPP_MP; /* MP Protocol, 0x003d */
        }
 #endif
+
+       /*
+        * 'link' compression 
+        */
+       skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
        if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
-               unsigned char *data = skb_push(skb,1);
+               unsigned char *data = isdn_ppp_skb_push(&skb,1);
+               if(!data)
+                       return 0;
                data[0] = proto & 0xff;
        }
        else {
-               unsigned char *data = skb_push(skb,2);
+               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 = skb_push(skb,2);
+               unsigned char *data = isdn_ppp_skb_push(&skb,2);
+               if(!data)
+                       return 0;
                data[0] = 0xff;    /* All Stations */
                data[1] = 0x03;    /* Unnumbered information */
        }
@@ -1406,10 +1479,8 @@ isdn_ppp_free_sqqueue(isdn_net_dev * p)
        p->ib.sq = NULL;
        while (q) {
                struct sqqueue *qn = q->next;
-               if (q->skb) {
-                       SET_SKB_FREE(q->skb);
+               if (q->skb)
                        dev_kfree_skb(q->skb);
-               }
                kfree(q);
                q = qn;
        }
@@ -1424,7 +1495,6 @@ isdn_ppp_free_mpqueue(isdn_net_dev * p)
 
        while (q) {
                struct mpqueue *ql = q->next;
-               SET_SKB_FREE(q->skb);
                dev_kfree_skb(q->skb);
                kfree(q);
                q = ql;
@@ -1599,7 +1669,6 @@ isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long
        if (!(*skb)) {
                while (q) {
                        struct mpqueue *ql = q->next;
-                       SET_SKB_FREE(q->skb);
                        dev_kfree_skb(q->skb);
                        kfree(q);
                        q = ql;
@@ -1612,7 +1681,6 @@ isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long
                struct mpqueue *ql = q->next;
                memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
                cnt += q->skb->len;
-               SET_SKB_FREE(q->skb);
                dev_kfree_skb(q->skb);
                kfree(q);
                q = ql;
@@ -1632,13 +1700,15 @@ isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_s
        struct sqqueue *q;
 
        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);
+                       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);
@@ -1663,32 +1733,30 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
 
        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;
-                                       SET_SKB_FREE(q->skb);
-                                       dev_kfree_skb(q->skb);
-                                       kfree(q);
+       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;
+                               printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+                               dev_kfree_skb(q->skb);
+                               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)
-               slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
+               slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp);
 #endif
 }
 
@@ -1708,7 +1776,7 @@ isdn_ppp_timer_timeout(void)
        *qn;
 
        while (net_dev) {
-               isdn_net_local *lp = &net_dev->local;
+               isdn_net_local *lp = net_dev->local;
                if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */
                        net_dev = net_dev->next;
                        continue;
@@ -1728,7 +1796,8 @@ 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;
@@ -1804,7 +1873,7 @@ 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 = 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);
@@ -1853,7 +1922,7 @@ isdn_ppp_dial_slave(char *name)
 
        if (!(ndev = isdn_net_findif(name)))
                return 1;
-       lp = &ndev->local;
+       lp = ndev->local;
        if (!(lp->flags & ISDN_NET_CONNECTED))
                return 5;
 
@@ -1884,7 +1953,7 @@ isdn_ppp_hangup_slave(char *name)
 
        if (!(ndev = isdn_net_findif(name)))
                return 1;
-       lp = &ndev->local;
+       lp = ndev->local;
        if (!(lp->flags & ISDN_NET_CONNECTED))
                return 5;
 
@@ -1905,6 +1974,128 @@ 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");
+       dev_kfree_skb(skb);
+       return NULL;
+#else
+       if(!master) {
+               /* 
+                * single link compression 
+                */
+               if(!is->link_compressor) {
+                       printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+                       dev_kfree_skb(skb);
+                       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");
+                       dev_kfree_skb(skb);
+                       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) {
+               dev_kfree_skb(skb_out);
+               return skb_in;
+       }
+       
+       dev_kfree_skb(skb_in);
+       *proto = new_proto;
+       return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame .. 
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+        struct sk_buff *skb)
+{
+#if 0
+       printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+               skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+               skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
 
 int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
@@ -1937,6 +2128,7 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
                if(ipc->num == num) {
                        return 0;       
                        is->compressor = ipc;
+                       is->link_compressor = ipc;
                }
                ipc = ipc->next;
        }
index 11184b8c0cfda712285a01b4ce2a93a08ab846ee..0e05af08b53509f45d568f729c1a543d02a7243c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.9 1997/02/11 18:32:59 fritz Exp $
+/* $Id: isdn_ppp.h,v 1.12 1998/01/31 22:07:48 keil Exp $
 
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.h,v $
+ * Revision 1.12  1998/01/31 22:07:48  keil
+ * changes for newer kernels
+ *
+ * Revision 1.11  1997/10/01 09:20:44  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * 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().
  *
@@ -63,11 +78,7 @@ 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);
-#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 unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
 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 *);
@@ -78,3 +89,7 @@ extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 #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
deleted file mode 100644 (file)
index 20cf9c6..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* $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/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 0929dbc26967307ff0ce66b1906d0ab2eca4db45..fd976ff50ca70b049e60f4444613d6b5974a3467 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $
+/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.47  1998/02/22 19:44:14  fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.46  1998/02/20 17:23:08  fritz
+ * Changes for recent kernels.
+ * Merged in contributions by Thomas Pfeiffer (V.110 T.70+ Extended FAX stuff)
+ * Added symbolic constants for Modem-Registers.
+ *
+ * Revision 1.45  1998/01/31 22:07:49  keil
+ * changes for newer kernels
+ *
+ * Revision 1.44  1998/01/31 19:30:02  calle
+ * Merged changes from and for 2.1.82, not tested only compiled ...
+ *
+ * Revision 1.43  1997/10/09 21:29:04  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.42  1997/10/01 09:20:49  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
  * Revision 1.41  1997/05/27 15:17:31  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
 #define VBUFX (VBUF/16)
 #endif
 
+#define FIX_FILE_TRANSFER
+
 /* Prototypes */
 
 static int isdn_tty_edit_at(const char *, int, modem_info *, int);
@@ -223,12 +254,63 @@ static int bit2si[8] =
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.41 $";
+char *isdn_tty_revision = "$Revision: 1.47 $";
 
 #define DLE 0x10
 #define ETX 0x03
 #define DC4 0x14
 
+/*
+ * Definition of some special Registers of AT-Emulator
+ */
+#define REG_RINGATA   0
+#define REG_RINGCNT   1
+#define REG_ESC       2
+#define REG_CR        3
+#define REG_LF        4
+#define REG_BS        5
+
+#define REG_RESP     12
+#define BIT_RESP      1
+#define REG_RESPNUM  12
+#define BIT_RESPNUM   2
+#define REG_ECHO     12
+#define BIT_ECHO      4
+#define REG_DCD      12
+#define BIT_DCD       8
+#define REG_CTS      12
+#define BIT_CTS      16
+#define REG_DTRR     12
+#define BIT_DTRR     32
+#define REG_DSR      12
+#define BIT_DSR      64
+#define REG_CPPP     12
+#define BIT_CPPP    128
+
+#define REG_DELXMT   13
+#define BIT_DELXMT    1
+#define REG_T70      13
+#define BIT_T70       2
+#define BIT_T70_EXT  32
+#define REG_DTRHUP   13
+#define BIT_DTRHUP    4
+#define REG_RESPXT   13
+#define BIT_RESPXT    8
+#define REG_CIDONCE  13
+#define BIT_CIDONCE  16
+#define REG_RUNG     13
+#define BIT_RUNG     64
+
+#define REG_L2PROT   14
+#define REG_L3PROT   15
+#define REG_PSIZE    16
+#define REG_WSIZE    17
+#define REG_SI1      18
+#define REG_SI2      19
+#define REG_SI1I     20
+#define REG_PLAN     21
+#define REG_SCREEN   22
+
 /* 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.
@@ -272,10 +354,9 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
 #ifdef CONFIG_ISDN_AUDIO
                                        }
 #endif
-                                       if (info->emu.mdmreg[12] & 128)
+                                       if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
                                                tty->flip.flag_buf_ptr[len - 1] = 0xff;
                                        queue_task(&tty->flip.tqueue, &tq_timer);
-                                       SET_SKB_FREE(skb);
                                        kfree_skb(skb);
                                        return 1;
                                }
@@ -319,7 +400,7 @@ isdn_tty_readmodem(void)
                                                                           tty->flip.char_buf_ptr,
                                                                           tty->flip.flag_buf_ptr, c, 0);
                                                        /* CISCO AsyncPPP Hack */
-                                                       if (!(info->emu.mdmreg[12] & 128))
+                                                       if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
                                                                memset(tty->flip.flag_buf_ptr, 0, r);
                                                        tty->flip.count += r;
                                                        tty->flip.flag_buf_ptr += r;
@@ -371,19 +452,26 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
 #endif
                ) {
                /* If Modem not listening, drop data */
-               SET_SKB_FREE(skb);
                kfree_skb(skb);
                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);
+       if (info->emu.mdmreg[REG_T70] & BIT_T70) {
+               if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
+                       /* T.70 decoding: throw away the T.70 header (2 or 4 bytes)   */
+                       if (skb->data[0] == 3) /* pure data packet -> 4 byte headers  */
+                               skb_pull(skb, 4);
+                       else
+                               if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr  */
+                                       skb_pull(skb, 2);
+               } else
+                       /* 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);
                return 1;
        }
@@ -454,16 +542,12 @@ isdn_tty_cleanup_xmit(modem_info * info)
        save_flags(flags);
        cli();
        if (skb_queue_len(&info->xmit_queue))
-               while ((skb = skb_dequeue(&info->xmit_queue))) {
-                       SET_SKB_FREE(skb);
+               while ((skb = skb_dequeue(&info->xmit_queue)))
                        kfree_skb(skb);
-               }
 #ifdef CONFIG_ISDN_AUDIO
        if (skb_queue_len(&info->dtmf_queue))
-               while ((skb = skb_dequeue(&info->dtmf_queue))) {
-                       SET_SKB_FREE(skb);
+               while ((skb = skb_dequeue(&info->dtmf_queue)))
                        kfree_skb(skb);
-               }
 #endif
        restore_flags(flags);
 }
@@ -479,7 +563,7 @@ isdn_tty_tint(modem_info * info)
                return;
        len = skb->len;
        if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
-                                          info->isdn_channel, skb)) == len) {
+                                          info->isdn_channel, 1, skb)) == len) {
                struct tty_struct *tty = info->tty;
                info->send_outstanding++;
                info->msr |= UART_MSR_CTS;
@@ -492,7 +576,6 @@ isdn_tty_tint(modem_info * info)
        }
        if (slen < 0) {
                /* Error: no channel, already shutdown, or wrong parameter */
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb);
                return;
        }
@@ -590,7 +673,7 @@ isdn_tty_end_vrx(const char *buf, int c, int from_user)
 
        while (c--) {
                if (from_user)
-                       GET_USER(ch, buf);
+                       get_user(ch, buf);
                else
                        ch = *buf;
                if ((ch != 0x11) && (ch != 0x13))
@@ -640,7 +723,7 @@ isdn_tty_senddown(modem_info * info)
                restore_flags(flags);
                return;
        }
-       if ((info->emu.mdmreg[12] & 0x10) != 0)
+       if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
                info->msr &= ~UART_MSR_CTS;
        info->lsr &= ~UART_LSR_TEMT;
        if (info->isdn_driver < 0) {
@@ -710,10 +793,13 @@ isdn_tty_senddown(modem_info * info)
                }
        }
 #endif                          /* CONFIG_ISDN_AUDIO */
-       SET_SKB_FREE(skb);
-       if (info->emu.mdmreg[13] & 2)
+       if (info->emu.mdmreg[REG_T70] & BIT_T70) {
                /* Add T.70 simplified header */
-               memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+               if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
+                       memcpy(skb_push(skb, 2), "\1\0", 2);
+               else
+                       memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+       }
        skb_queue_tail(&info->xmit_queue, skb);
 }
 
@@ -761,27 +847,27 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
 {
        int usg = ISDN_USAGE_MODEM;
        int si = 7;
-       int l2 = m->mdmreg[14];
+       int l2 = m->mdmreg[REG_L2PROT];
        isdn_ctrl cmd;
        ulong flags;
        int i;
        int j;
 
        for (j = 7; j >= 0; j--)
-               if (m->mdmreg[18] & (1 << j)) {
+               if (m->mdmreg[REG_SI1] & (1 << j)) {
                        si = bit2si[j];
                        break;
                }
 #ifdef CONFIG_ISDN_AUDIO
        if (si == 1) {
-               l2 = 4;
+               l2 = ISDN_PROTO_L2_TRANS;
                usg = ISDN_USAGE_VOICE;
        }
 #endif
-       m->mdmreg[20] = si2bit[si];
+       m->mdmreg[REG_SI1I] = si2bit[si];
        save_flags(flags);
        cli();
-       i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1);
+       i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
        if (i < 0) {
                restore_flags(flags);
                isdn_tty_modem_result(6, info);
@@ -798,32 +884,32 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
                cmd.driver = info->isdn_driver;
                cmd.arg = info->isdn_channel;
                cmd.command = ISDN_CMD_CLREAZ;
-               dev->drv[info->isdn_driver]->interface->command(&cmd);
+               isdn_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);
+               isdn_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);
+               isdn_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.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+               isdn_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.parm.setup.si2 = m->mdmreg[REG_SI2];
                cmd.command = ISDN_CMD_DIAL;
                info->dialing = 1;
                strcpy(dev->num[i], n);
                isdn_info_update();
-               dev->drv[info->isdn_driver]->interface->command(&cmd);
+               isdn_command(&cmd);
        }
 }
 
@@ -865,6 +951,9 @@ isdn_tty_modem_hup(modem_info * info, int local)
                info->adpcmr = NULL;
        }
 #endif
+       if ((info->msr & UART_MSR_RI) &&
+               (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
+               isdn_tty_modem_result(12, info);
        info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
        info->lsr |= UART_LSR_TEMT;
        if (info->isdn_driver >= 0) {
@@ -872,11 +961,11 @@ isdn_tty_modem_hup(modem_info * info, int 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_command(&cmd);
                }
                isdn_all_eaz(info->isdn_driver, info->isdn_channel);
-               info->emu.mdmreg[1] = 0;
-               usage = (info->emu.mdmreg[20] == 1) ?
+               info->emu.mdmreg[REG_RINGCNT] = 0;
+               usage = (info->emu.mdmreg[REG_SI1I] == 1) ?
                    ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
                isdn_free_channel(info->isdn_driver, info->isdn_channel,
                                  usage);
@@ -937,7 +1026,7 @@ isdn_tty_change_speed(modem_info * info)
                isdn_tty_modem_ncarrier(info);
        } else {
                info->mcr &= ~UART_MCR_DTR;
-               if (info->emu.mdmreg[13] & 4) {
+               if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
 #ifdef ISDN_DEBUG_MODEM_HUP
                        printk(KERN_DEBUG "Mhup in changespeed\n");
 #endif
@@ -1020,7 +1109,7 @@ isdn_tty_shutdown(modem_info * info)
        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) {
+               if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
                        isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                        printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
@@ -1047,8 +1136,8 @@ isdn_tty_shutdown(modem_info * info)
 static int
 isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
 {
-       int c,
-        total = 0;
+       int c;
+       int total = 0;
        ulong flags;
        modem_info *info = (modem_info *) tty->driver_data;
 
@@ -1074,7 +1163,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
 #ifdef CONFIG_ISDN_AUDIO
                        if (!info->vonline)
 #endif
-                               isdn_tty_check_esc(buf, m->mdmreg[2], c,
+                               isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
                                                   &(m->pluscount),
                                                   &(m->lastplus),
                                                   from_user);
@@ -1116,7 +1205,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
                        } else
 #endif
                                info->xmit_count += c;
-                       if (m->mdmreg[13] & 1) {
+                       if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) {
                                isdn_tty_senddown(info);
                                isdn_tty_tint(info);
                        }
@@ -1304,7 +1393,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
        uint arg;
        int pre_dtr;
 
-       GET_USER(arg, (uint *) value);
+       get_user(arg, (uint *) value);
        switch (cmd) {
                case TIOCMBIS:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1327,7 +1416,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
                        }
                        if (arg & TIOCM_DTR) {
                                info->mcr &= ~UART_MCR_DTR;
-                               if (info->emu.mdmreg[13] & 4) {
+                               if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
                                        isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                                        printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
@@ -1348,7 +1437,7 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
                               | ((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) {
+                                       if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
                                                isdn_tty_modem_reset_regs(info, 0);
 #ifdef ISDN_DEBUG_MODEM_HUP
                                                printk(KERN_DEBUG "Mhup in TIOCMSET\n");
@@ -1414,7 +1503,7 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
                        error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
                        if (error)
                                return error;
-                       GET_USER(arg, (ulong *) arg);
+                       get_user(arg, (ulong *) arg);
                        tty->termios->c_cflag =
                            ((tty->termios->c_cflag & ~CLOCAL) |
                             (arg ? CLOCAL : 0));
@@ -1443,7 +1532,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
                                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);
@@ -1823,10 +1911,10 @@ static void
 isdn_tty_modem_reset_regs(modem_info * info, int force)
 {
        atemu *m = &info->emu;
-       if ((m->mdmreg[12] & 32) || force) {
+       if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || 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[REG_PSIZE] * 16;
        }
 #ifdef CONFIG_ISDN_AUDIO
        isdn_tty_modem_reset_vpar(m);
@@ -1881,6 +1969,7 @@ isdn_tty_modem_init(void)
        m->tty_modem.stop = NULL;
        m->tty_modem.start = NULL;
        m->tty_modem.hangup = isdn_tty_hangup;
+       m->tty_modem.driver_name = "isdn_tty";
        /*
         * The callout device is just like normal device except for
         * major number and the subtype code.
@@ -1905,7 +1994,7 @@ isdn_tty_modem_init(void)
                sprintf(info->last_num, "none");
                info->last_dir = 0;
                info->last_lhup = 1;
-               info->last_l2 = 0;
+               info->last_l2 = -1;
                info->last_si = 0;
                isdn_tty_reset_profile(&info->emu);
                isdn_tty_modem_reset_regs(info, 1);
@@ -1927,7 +2016,7 @@ isdn_tty_modem_init(void)
 #ifdef CONFIG_ISDN_AUDIO
                skb_queue_head_init(&info->dtmf_queue);
 #endif
-               if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+               if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
                        printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
                        return -3;
                }
@@ -1977,12 +2066,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
 #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]);
+                      info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]);
 #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[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
+                   (info->emu.mdmreg[REG_SI2] == si2)) {         /* SI2 is matching */
                        idx = isdn_dc2minor(di, ch);
 #ifdef ISDN_DEBUG_MODEM_ICALL
                        printk(KERN_DEBUG "m_fi: match1\n");
@@ -1990,7 +2079,10 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
                               info->flags, info->isdn_driver, info->isdn_channel,
                               dev->usage[idx]);
 #endif
-                       if ((info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+                       if (
+#ifndef FIX_FILE_TRANSFER
+                               (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+#endif
                            (info->isdn_driver == -1) &&
                            (info->isdn_channel == -1) &&
                            (USG_NONE(dev->usage[idx]))) {
@@ -2001,9 +2093,9 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
                                dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
                                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[21] = setup.plan;
-                               info->emu.mdmreg[22] = setup.screen;
+                               info->emu.mdmreg[REG_SI1I] = si2bit[si1];
+                               info->emu.mdmreg[REG_PLAN] = setup.plan;
+                               info->emu.mdmreg[REG_SCREEN] = setup.screen;
                                isdn_info_update();
                                restore_flags(flags);
                                printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
@@ -2029,12 +2121,20 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
 {
        int mi;
        modem_info *info;
+       char *e;
 
        if (i < 0)
                return 0;
        if ((mi = dev->m_idx[i]) >= 0) {
                info = &dev->mdm.info[mi];
                switch (c->command) {
+                        case ISDN_STAT_CINF:
+                                printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
+                                info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
+                                if (e == c->parm.num)
+                                       info->emu.charge = 0;
+                               
+                                break;                 
                        case ISDN_STAT_BSENT:
 #ifdef ISDN_TTY_STAT_DEBUG
                                printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
@@ -2093,6 +2193,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
                                 */
                                if (TTY_IS_ACTIVE(info)) {
                                        info->msr |= UART_MSR_DCD;
+                                       info->emu.charge = 0;
                                        if (info->dialing) {
                                                info->dialing = 0;
                                                info->last_dir = 1;
@@ -2184,13 +2285,13 @@ isdn_tty_at_cout(char *msg, modem_info * info)
        for (p = msg; *p; p++) {
                switch (*p) {
                        case '\r':
-                               c = m->mdmreg[3];
+                               c = m->mdmreg[REG_CR];
                                break;
                        case '\n':
-                               c = m->mdmreg[4];
+                               c = m->mdmreg[REG_LF];
                                break;
                        case '\b':
-                               c = m->mdmreg[5];
+                               c = m->mdmreg[REG_BS];
                                break;
                        default:
                                c = *p;
@@ -2293,14 +2394,14 @@ isdn_tty_modem_result(int code, modem_info * info)
        static char *msg[] =
        {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
         "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
-        "RINGING", "NO MSN/EAZ", "VCON"};
+        "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
        ulong flags;
        char s[10];
 
        switch (code) {
                case 2:
-                       m->mdmreg[1]++; /* RING */
-                       if (m->mdmreg[1] == m->mdmreg[0])
+                       m->mdmreg[REG_RINGCNT]++;       /* RING */
+                       if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
                                /* Automatically accept incoming call */
                                isdn_tty_cmd_ATA(info);
                        break;
@@ -2313,7 +2414,7 @@ isdn_tty_modem_result(int code, modem_info * info)
 #endif
                        save_flags(flags);
                        cli();
-                       m->mdmreg[1] = 0;
+                       m->mdmreg[REG_RINGCNT] = 0;
                        del_timer(&info->nc_timer);
                        info->ncarrier = 0;
                        if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
@@ -2356,15 +2457,19 @@ isdn_tty_modem_result(int code, modem_info * info)
                                info->online = 1;
                        break;
        }
-       if (m->mdmreg[12] & 1) {
+       if (m->mdmreg[REG_RESP] & BIT_RESP) {
                /* Show results */
                isdn_tty_at_cout("\r\n", info);
-               if (m->mdmreg[12] & 2) {
+               if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
                        /* Show numeric results */
                        sprintf(s, "%d", code);
                        isdn_tty_at_cout(s, info);
                } else {
-                       if ((code == 2) && (!(m->mdmreg[13] & 16))) {
+                       if ((code == 2) &&
+                               (m->mdmreg[REG_RUNG] & BIT_RUNG) &&
+                               (m->mdmreg[REG_RINGCNT] > 1))
+                               return;
+                       if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) {
                                isdn_tty_at_cout("CALLER NUMBER: ", info);
                                isdn_tty_at_cout(dev->num[info->drv_index], info);
                                isdn_tty_at_cout("\r\n", info);
@@ -2373,7 +2478,8 @@ isdn_tty_modem_result(int code, modem_info * info)
                        switch (code) {
                                case 2:
                                        /* Print CID only once, _after_ 1.st RING */
-                                       if ((m->mdmreg[13] & 16) && (m->mdmreg[1] == 1)) {
+                                       if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
+                                           (m->mdmreg[REG_RINGCNT] == 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);
@@ -2383,18 +2489,39 @@ isdn_tty_modem_result(int code, modem_info * info)
                                case 6:
                                case 7:
                                case 8:
-                                       m->mdmreg[1] = 0;
+                                       m->mdmreg[REG_RINGCNT] = 0;
                                        /* Append Cause-Message if enabled */
-                                       if (m->mdmreg[13] & 8) {
+                                       if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
                                                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)
+                                       switch (m->mdmreg[REG_L2PROT]) {
+                                               case ISDN_PROTO_L2_X75I:
+                                               case ISDN_PROTO_L2_X75UI:
+                                               case ISDN_PROTO_L2_X75BUI:
+                                                       isdn_tty_at_cout("/X.75", info);
+                                                       break;
+                                               case ISDN_PROTO_L2_HDLC:
+                                                       isdn_tty_at_cout("/HDLC", info);
+                                                       break;
+                                               case ISDN_PROTO_L2_V11096:
+                                                       isdn_tty_at_cout("/V110/9600", info);
+                                                       break;
+                                               case ISDN_PROTO_L2_V11019:
+                                                       isdn_tty_at_cout("/V110/19200", info);
+                                                       break;
+                                               case ISDN_PROTO_L2_V11038:
+                                                       isdn_tty_at_cout("/V110/38400", info);
+                                                       break;
+                                       }
+                                       if (m->mdmreg[REG_T70] & BIT_T70) {
                                                isdn_tty_at_cout("/T.70", info);
+                                               if (m->mdmreg[REG_T70] & BIT_T70_EXT)
+                                                       isdn_tty_at_cout("+", info);
+                                       }
                                        break;
                        }
                }
@@ -2479,16 +2606,25 @@ isdn_tty_report(modem_info * info)
        isdn_tty_at_cout("    Layer-2 Protocol: ", info);
        switch (info->last_l2) {
                case ISDN_PROTO_L2_X75I:
-                       isdn_tty_at_cout("x75i", info);
+                       isdn_tty_at_cout("X.75i", info);
                        break;
                case ISDN_PROTO_L2_X75UI:
-                       isdn_tty_at_cout("x75ui", info);
+                       isdn_tty_at_cout("X.75ui", info);
                        break;
                case ISDN_PROTO_L2_X75BUI:
-                       isdn_tty_at_cout("x75bui", info);
+                       isdn_tty_at_cout("X.75bui", info);
                        break;
                case ISDN_PROTO_L2_HDLC:
-                       isdn_tty_at_cout("hdlc", info);
+                       isdn_tty_at_cout("HDLC", info);
+                       break;
+               case ISDN_PROTO_L2_V11096:
+                       isdn_tty_at_cout("V.110 9600 Baud", info);
+                       break;
+               case ISDN_PROTO_L2_V11019:
+                       isdn_tty_at_cout("V.110 19200 Baud", info);
+                       break;
+               case ISDN_PROTO_L2_V11038:
+                       isdn_tty_at_cout("V.110 38400 Baud", info);
                        break;
                case ISDN_PROTO_L2_TRANS:
                        isdn_tty_at_cout("transparent", info);
@@ -2497,7 +2633,12 @@ isdn_tty_report(modem_info * info)
                        isdn_tty_at_cout("unknown", info);
                        break;
        }
-       isdn_tty_at_cout((m->mdmreg[13] & 2) ? "/t.70\r\n" : "\r\n", info);
+       if (m->mdmreg[REG_T70] & BIT_T70) {
+               isdn_tty_at_cout("/T.70", info);
+               if (m->mdmreg[REG_T70] & BIT_T70_EXT)
+                       isdn_tty_at_cout("+", info);
+       }
+       isdn_tty_at_cout("\r\n", info);
        isdn_tty_at_cout("    Service:          ", info);
        switch (info->last_si) {
                case 1:
@@ -2535,30 +2676,36 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                        /* &B - Set Buffersize */
                        p[0]++;
                        i = isdn_getnum(p);
-                       if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
+                       if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
                                PARSE_ERROR1;
 #ifdef CONFIG_ISDN_AUDIO
-                       if ((m->mdmreg[18] & 1) && (i > VBUF))
+                       if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
                                PARSE_ERROR1;
 #endif
-                       m->mdmreg[16] = i / 16;
-                       info->xmit_size = m->mdmreg[16] * 16;
+                       m->mdmreg[REG_PSIZE] = i / 16;
+                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
+                       switch (m->mdmreg[REG_L2PROT]) {
+                               case ISDN_PROTO_L2_V11096:
+                               case ISDN_PROTO_L2_V11019:
+                               case ISDN_PROTO_L2_V11038:
+                                       info->xmit_size /= 10;          
+                       }
                        break;
                case 'D':
                        /* &D - Set DCD-Low-behavior */
                        p[0]++;
                        switch (isdn_getnum(p)) {
                                case 0:
-                                       m->mdmreg[13] &= ~4;
-                                       m->mdmreg[12] &= ~32;
+                                       m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
+                                       m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
                                        break;
                                case 2:
-                                       m->mdmreg[13] |= 4;
-                                       m->mdmreg[12] &= ~32;
+                                       m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
+                                       m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
                                        break;
                                case 3:
-                                       m->mdmreg[13] |= 4;
-                                       m->mdmreg[12] |= 32;
+                                       m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
+                                       m->mdmreg[REG_DTRR] |= BIT_DTRR;
                                        break;
                                default:
                                        PARSE_ERROR1
@@ -2575,12 +2722,46 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                        isdn_tty_reset_profile(m);
                        isdn_tty_modem_reset_regs(info, 1);
                        break;
+               case 'R':
+                       /* &R - Set V.110 bitrate adaption */
+                       p[0]++;
+                       i = isdn_getnum(p);
+                       switch (i) {
+                               case 0:
+                                       /* Switch off V.110, back to X.75 */
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+                                       m->mdmreg[REG_SI2] = 0;
+                                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
+                                       break;
+                               case 9600:
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
+                                       m->mdmreg[REG_SI2] = 197;
+                                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+                                       break;
+                               case 19200:
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
+                                       m->mdmreg[REG_SI2] = 199;
+                                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+                                       break;
+                               case 38400:
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
+                                       m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
+                                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
+                                       break;
+                               default:
+                                       PARSE_ERROR1;
+                       }
+                       /* Switch off T.70 */
+                       m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
+                       /* Set Service 7 */
+                       m->mdmreg[REG_SI1] |= 4;
+                       break;
                case 'S':
                        /* &S - Set Windowsize */
                        p[0]++;
                        i = isdn_getnum(p);
                        if ((i > 0) && (i < 9))
-                               m->mdmreg[17] = i;
+                               m->mdmreg[REG_WSIZE] = i;
                        else
                                PARSE_ERROR1;
                        break;
@@ -2610,19 +2791,27 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                        }
                        break;
                case 'X':
-                       /* &X - Switch to BTX-Mode */
+                       /* &X - Switch to BTX-Mode and T.70 */
                        p[0]++;
                        switch (isdn_getnum(p)) {
                                case 0:
-                                       m->mdmreg[13] &= ~2;
-                                       info->xmit_size = m->mdmreg[16] * 16;
+                                       m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
+                                       info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
                                        break;
                                case 1:
-                                       m->mdmreg[13] |= 2;
-                                       m->mdmreg[14] = 0;
+                                       m->mdmreg[REG_T70] |= BIT_T70;
+                                       m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
+                                       info->xmit_size = 112;
+                                       m->mdmreg[REG_SI1] = 4;
+                                       m->mdmreg[REG_SI2] = 0;
+                                       break;
+                               case 2:
+                                       m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
+                                       m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
                                        info->xmit_size = 112;
-                                       m->mdmreg[18] = 4;
-                                       m->mdmreg[19] = 0;
+                                       m->mdmreg[REG_SI1] = 4;
+                                       m->mdmreg[REG_SI2] = 0;
                                        break;
                                default:
                                        PARSE_ERROR1;
@@ -2639,22 +2828,28 @@ 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)
+               case REG_L2PROT:
+                       if (mval > ISDN_PROTO_L2_MAX)
                                return 1;
                        break;
-               case 16:
-                       if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+               case REG_PSIZE:
+                       if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
                                return 1;
 #ifdef CONFIG_ISDN_AUDIO
-                       if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+                       if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
                                return 1;
 #endif
                        info->xmit_size = mval * 16;
+                       switch (m->mdmreg[REG_L2PROT]) {
+                               case ISDN_PROTO_L2_V11096:
+                               case ISDN_PROTO_L2_V11019:
+                               case ISDN_PROTO_L2_V11038:
+                                       info->xmit_size /= 10;          
+                       }
                        break;
-               case 20:
-               case 21:
-               case 22:
+               case REG_SI1I:
+               case REG_PLAN:
+               case REG_SCREEN:
                        /* readonly registers */
                        return 1;
        }
@@ -2741,31 +2936,31 @@ isdn_tty_cmd_ATA(modem_info * info)
                /* Accept incoming call */
                info->last_dir = 0;
                strcpy(info->last_num, dev->num[info->drv_index]);
-               m->mdmreg[1] = 0;
+               m->mdmreg[REG_RINGCNT] = 0;
                info->msr &= ~UART_MSR_RI;
-               l2 = m->mdmreg[14];
+               l2 = m->mdmreg[REG_L2PROT];
 #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;
+               if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
+                       if (m->mdmreg[REG_SI1I] == 1)
+                               l2 = ISDN_PROTO_L2_TRANS;
                        else
-                               l2 = 0;
+                               l2 = ISDN_PROTO_L2_X75I;
                }
 #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);
+               isdn_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.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+               isdn_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);
+               isdn_command(&cmd);
        } else
                isdn_tty_modem_result(8, info);
 }
@@ -2787,7 +2982,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
                        case '?':
                                p[0]++;
                                sprintf(rs, "\r\n%d",
-                                       (m->mdmreg[18] & 1) ? 8 : 0);
+                                       (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
                                isdn_tty_at_cout(rs, info);
                                break;
                        case '=':
@@ -2795,18 +2990,22 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
                                switch (*p[0]) {
                                        case '0':
                                                p[0]++;
-                                               m->mdmreg[18] = 4;
+                                               m->mdmreg[REG_SI1] = 4;
                                                info->xmit_size =
-                                                   m->mdmreg[16] * 16;
+                                                   m->mdmreg[REG_PSIZE] * 16;
+                                               break;
+                                       case '2':
+                                               printk(KERN_DEBUG "isdn_tty: FCLASS=2\n");
+                                               p[0]++;
                                                break;
                                        case '8':
                                                p[0]++;
-                                               m->mdmreg[18] = 5;
+                                               m->mdmreg[REG_SI1] = 5;
                                                info->xmit_size = VBUF;
                                                break;
                                        case '?':
                                                p[0]++;
-                                               isdn_tty_at_cout("\r\n0,8",
+                                               isdn_tty_at_cout("\r\n0,2,8",
                                                                 info);
                                                break;
                                        default:
@@ -2824,7 +3023,7 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
                        case '?':
                                p[0]++;
                                sprintf(rs, "\r\n%d",
-                                       m->mdmreg[0]);
+                                       m->mdmreg[REG_RINGATA]);
                                isdn_tty_at_cout(rs, info);
                                break;
                        case '=':
@@ -2832,13 +3031,100 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info)
                                par = isdn_getnum(p);
                                if ((par < 0) || (par > 255))
                                        PARSE_ERROR1;
-                               m->mdmreg[0] = par;
+                               m->mdmreg[REG_RINGATA] = par;
                                break;
                        default:
                                PARSE_ERROR1;
                }
                return 0;
        }
+        if (!strncmp(p[0], "TBC=", 4)) { /* UNKLAR !! */
+                p[0] += 4;
+                printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
+                switch (*p[0]) {
+                        case '0':
+                                p[0]++;
+                                break;
+                        default:
+                                PARSE_ERROR1;
+                }
+                return 0;
+        }
+        if (!strncmp(p[0], "BOR=", 4)) { /* UNKLAR !! */
+                p[0] += 4;
+                printk(KERN_DEBUG "isdn_tty: Fax FBOR=%c\n", *p[0]);
+                switch (*p[0]) {
+                        case '0':
+                                p[0]++;
+                                break;
+                        default:
+                                PARSE_ERROR1;
+                }
+                return 0;
+        }
+        if (!strncmp(p[0], "DCC=", 4)) { /* SETUP irgendwie !! */
+               int i, val[]={0,0,0,0,0,0,0,0};
+
+                p[0] += 4;
+                if (*p[0] == '?') {
+                       isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0,1),(0),(0),(0-7)",info);
+                       p[0]++;
+                } else {
+                       for (i=0; (*p[0]>='0') && (*p[0]<='9'); i++) {
+                               val[i] = *p[0] - 48;
+                               p[0]++;
+                               if (*p[0] == ',')
+                                       p[0]++;
+                       }
+                       printk(KERN_DEBUG "isdn_tty: Fax Setup values=%d,%d,%d,%d,%d,%d,%d,%d\n",
+                              val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
+                }
+                return 0;
+        }
+        if (!strncmp(p[0], "LID=", 4)) { /* set sender ID !! */
+               char senderID[80];
+               int i;
+
+                p[0] += 4;
+                if (*p[0] =='"')
+                       p[0]++;
+                for(i=0; (*p[0]) && (*p[0] != '"'); i++)
+                       senderID[i] = *p[0]++;
+                senderID[i] = 0;
+                if (*p[0] =='"')
+                       p[0]++;
+                printk(KERN_DEBUG "isdn_tty: Fax sender=>%s<\n", senderID);
+                return 0;
+        }
+        if (!strncmp(p[0], "MFR?", 4)) {
+                p[0] += 4;
+                printk(KERN_DEBUG "isdn_tty: FMFR?\n");
+                isdn_tty_at_cout("\r\nISDNfax", info);
+                return 0;
+        }
+        if (!strncmp(p[0], "MDL?", 4)) {
+                p[0] += 4;
+                printk(KERN_DEBUG "isdn_tty: FMDL?\n");
+                isdn_tty_at_cout("\r\nAVM-B1", info);
+                return 0;
+        }
+        if (!strncmp(p[0], "AP=?", 4)) {
+                p[0] += 4;
+                printk(KERN_DEBUG "isdn_tty: FAP=?\n");
+                return 0;
+        }
+        if (!strncmp(p[0], "PHCTO=", 6)) {
+               /* beim trace mit dem zyxel folgt der wert 30 ;*/
+                p[0] += 6;
+                printk(KERN_DEBUG "isdn_tty: FPHCTO=%s\n", p[0]);
+                return 0;
+        }
+        if (!strncmp(p[0], "CR=", 3)) {
+                p[0] += 3;
+                printk(KERN_DEBUG "isdn_tty: FCR=%s\n", p[0]);
+                return 0;
+        }
+        printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
        PARSE_ERROR1;
 }
 
@@ -3110,10 +3396,10 @@ isdn_tty_parse_at(modem_info * info)
                                p++;
                                switch (isdn_getnum(&p)) {
                                        case 0:
-                                               m->mdmreg[12] &= ~4;
+                                               m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
                                                break;
                                        case 1:
-                                               m->mdmreg[12] |= 4;
+                                               m->mdmreg[REG_ECHO] |= BIT_ECHO;
                                                break;
                                        default:
                                                PARSE_ERROR;
@@ -3149,6 +3435,11 @@ isdn_tty_parse_at(modem_info * info)
                                                p++;
                                                isdn_tty_report(info);
                                                break;
+                                       case '3':
+                                                p++;
+                                                sprintf(ds, "\r\n%d", info->emu.charge);
+                                                isdn_tty_at_cout(ds, info);
+                                                break;
                                        default:
                                }
                                break;
@@ -3166,10 +3457,10 @@ isdn_tty_parse_at(modem_info * info)
                                p++;
                                switch (isdn_getnum(&p)) {
                                        case 0:
-                                               m->mdmreg[12] |= 1;
+                                               m->mdmreg[REG_RESP] |= BIT_RESP;
                                                break;
                                        case 1:
-                                               m->mdmreg[12] &= ~1;
+                                               m->mdmreg[REG_RESP] &= ~BIT_RESP;
                                                break;
                                        default:
                                                PARSE_ERROR;
@@ -3186,10 +3477,10 @@ isdn_tty_parse_at(modem_info * info)
                                p++;
                                switch (isdn_getnum(&p)) {
                                        case 0:
-                                               m->mdmreg[12] |= 2;
+                                               m->mdmreg[REG_RESP] |= BIT_RESPNUM;
                                                break;
                                        case 1:
-                                               m->mdmreg[12] &= ~2;
+                                               m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
                                                break;
                                        default:
                                                PARSE_ERROR;
@@ -3210,7 +3501,7 @@ isdn_tty_parse_at(modem_info * info)
                                                        return;
                                                break;
                                        case 'V':
-                                               if (!(m->mdmreg[18] & 1))
+                                               if (!(m->mdmreg[REG_SI1] & 1))
                                                        PARSE_ERROR;
                                                p++;
                                                if (isdn_tty_cmd_PLUSV(&p, info))
@@ -3261,14 +3552,14 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
 
        for (cnt = count; cnt > 0; p++, cnt--) {
                if (user)
-                       GET_USER(c, p);
+                       get_user(c, p);
                else
                        c = *p;
                total++;
-               if (c == m->mdmreg[3] || c == m->mdmreg[4]) {
+               if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
                        /* Separator (CR oder LF) */
                        m->mdmcmd[m->mdmcmdl] = 0;
-                       if (m->mdmreg[12] & 4) {
+                       if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
                                eb[0] = c;
                                eb[1] = 0;
                                isdn_tty_at_cout(eb, info);
@@ -3278,18 +3569,18 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
                        m->mdmcmdl = 0;
                        continue;
                }
-               if (c == m->mdmreg[5] && m->mdmreg[5] < 128) {
+               if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
                        /* Backspace-Funktion */
                        if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
                                if (m->mdmcmdl)
                                        m->mdmcmdl--;
-                               if (m->mdmreg[12] & 4)
+                               if (m->mdmreg[REG_ECHO] & BIT_ECHO)
                                        isdn_tty_at_cout("\b", info);
                        }
                        continue;
                }
                if (cmdchar(c)) {
-                       if (m->mdmreg[12] & 4) {
+                       if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
                                eb[0] = c;
                                eb[1] = 0;
                                isdn_tty_at_cout(eb, info);
diff --git a/drivers/isdn/isdn_v110.c b/drivers/isdn/isdn_v110.c
new file mode 100644 (file)
index 0000000..ae62378
--- /dev/null
@@ -0,0 +1,645 @@
+/* $Id: isdn_v110.c,v 1.2 1998/02/22 19:44:25 fritz Exp $
+
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+ * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdn_v110.c,v $
+ * Revision 1.2  1998/02/22 19:44:25  fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.1  1998/02/20 17:32:09  fritz
+ * First checkin (not yet completely functionable).
+ *
+ */
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <linux/isdn.h>
+#include "isdn_v110.h"
+
+#undef ISDN_V110_DEBUG
+
+char *isdn_v110_revision = "$Revision: 1.2 $";
+
+#define V110_38400 255
+#define V110_19200  15
+#define V110_9600    3
+
+/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
+   als online und offline matrix für 9600, 19200 und 38400
+ */
+static unsigned char V110_OnMatrix_9600[] =
+{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
+
+static unsigned char V110_OffMatrix_9600[] =
+{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char V110_OnMatrix_19200[] =
+{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
+ 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
+
+static unsigned char V110_OffMatrix_19200[] =
+{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+static unsigned char V110_OnMatrix_38400[] =
+{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
+
+static unsigned char V110_OffMatrix_38400[] =
+{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
+
+
+/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
+   Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
+   bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
+   auf der isdn-leitung falsch herum ist.
+ */
+
+static __inline unsigned char
+FlipBits(unsigned char c, int keylen)
+{
+       unsigned char b = c;
+       unsigned char bit = 128;
+       int i;
+       int j;
+       int hunks = (8 / keylen);
+
+       c = 0;
+       for (i = 0; i < hunks; i++) {
+               for (j = 0; j < keylen; j++) {
+                       if (b & (bit >> j))
+                               c |= bit >> (keylen - j - 1);
+               }
+               bit >>= keylen;
+       }
+       return c;
+}
+
+
+/* isdn_v110_open allocates and initializes private V.110 data
+ * structures and returns a pointer to these.
+ */
+static isdn_v110_stream *
+isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
+{
+       int i;
+       isdn_v110_stream *v;
+
+       if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL)
+               return NULL;
+       memset(v, 0, sizeof(isdn_v110_stream));
+       v->key = key;
+       v->nbits = 0;
+       for (i = 0; key & (1 << i); i++)
+               v->nbits++;
+
+       v->nbytes = 8 / v->nbits;
+       v->decodelen = 0;
+
+       switch (key) {
+               case V110_38400:
+                       v->OnlineFrame = V110_OnMatrix_38400;
+                       v->OfflineFrame = V110_OffMatrix_38400;
+                       break;
+               case V110_19200:
+                       v->OnlineFrame = V110_OnMatrix_19200;
+                       v->OfflineFrame = V110_OffMatrix_19200;
+                       break;
+               default:
+                       v->OnlineFrame = V110_OnMatrix_9600;
+                       v->OfflineFrame = V110_OffMatrix_9600;
+                       break;
+       }
+       v->framelen = v->nbytes * 10;
+       v->SyncInit = 5;
+       v->introducer = 0;
+       v->dbit = 1;
+       v->b = 0;
+       v->skbres = hdrlen;
+       v->maxsize = maxsize - hdrlen;
+       if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) {
+               kfree(v);
+               return NULL;
+       }
+       return v;
+}
+
+/* isdn_v110_close frees private V.110 data structures */
+static void
+isdn_v110_close(isdn_v110_stream * v)
+{
+       if (v == NULL)
+               return;
+#ifdef ISDN_V110_DEBUG
+       printk(KERN_DEBUG "v110 close\n");
+#if 0
+       printk(KERN_DEBUG "isdn_v110_close: nbytes=%d\n", v->nbytes);
+       printk(KERN_DEBUG "isdn_v110_close: nbits=%d\n", v->nbits);
+       printk(KERN_DEBUG "isdn_v110_close: key=%d\n", v->key);
+       printk(KERN_DEBUG "isdn_v110_close: SyncInit=%d\n", v->SyncInit);
+       printk(KERN_DEBUG "isdn_v110:close: decodelen=%d\n", v->decodelen);
+       printk(KERN_DEBUG "isdn_v110_close: framelen=%d\n", v->framelen);
+#endif
+#endif
+       kfree(v->encodebuf);
+       kfree(v);
+}
+
+
+/* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */
+
+static int
+ValidHeaderBytes(isdn_v110_stream * v)
+{
+       int i;
+       for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++)
+               if ((v->decodebuf[i] & v->key) != 0)
+                       break;
+       return i;
+}
+
+/* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */
+
+static void
+SyncHeader(isdn_v110_stream * v)
+{
+       unsigned char *rbuf = v->decodebuf;
+       int len = v->decodelen;
+
+       if (len == 0)
+               return;
+       for (rbuf++, len--; len > 0; len--, rbuf++)     /* such den SyncHeader in buf ! */
+               if ((*rbuf & v->key) == 0)      /* erstes byte gefunden ?       */
+                       break;  /* jupp!                        */
+       if (len)
+               memcpy(v->decodebuf, rbuf, len);
+
+       v->decodelen = len;
+#ifdef ISDN_V110_DEBUG
+       printk(KERN_DEBUG "isdn_v110: Header resync\n");
+#endif
+}
+
+/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
+   len is the number of matrix-lines. len must be a multiple of 10, i.e.
+   only complete matices must be given.
+   From these, netto data is extracted and returned in buf. The return-value
+   is the bytecount of the decoded data.
+ */
+static int
+DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf)
+{
+       int line = 0;
+       int buflen = 0;
+       int mbit = 64;
+       int introducer = v->introducer;
+       int dbit = v->dbit;
+       unsigned char b = v->b;
+
+       while (line < len) {    /* sind schon alle matrizenzeilen abgearbeitet? */
+               if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
+                       if (m[line] != 0x00) {  /* nicht 0 ? dann fehler! */
+#ifdef ISDN_V110_DEBUG
+                               printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
+#endif
+
+/*
+  dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
+  v->introducer = 0; v->dbit = 1; v->b = 0;
+  return buflen;                                                                                                     anzahl schon erzeugter daten zurückgeben!
+  */
+                       }
+                       line++; /* sonst die nächste matrixzeile nehmen */
+                       continue;
+               } else if ((line % 10) == 5) {  /* in zeile 5 stehen nur e-bits ! */
+                       if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
+#ifdef ISDN_V110_DEBUG
+                               printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
+#endif
+/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
+   v->introducer = 0; v->dbit = 1; v->b = 0;
+   return buflen;
+ */
+                       }
+                       line++; /* alles klar, nächste zeile */
+                       continue;
+               } else if (!introducer) {       /* every byte starts with 10 (stopbit, startbit) */
+                       introducer = (m[line] & mbit) ? 0 : 1;  /* aktuelles bit der matrix */
+                     next_byte:
+                       if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */
+                               mbit >>= 1;     /* nein, nimm das nächste in dieser zeile */
+                               continue;
+                       }       /* sonst links in der nächsten zeile anfangen */
+                       mbit = 64;
+                       line++;
+                       continue;
+               } else {        /* sonst müssen wir ein datenbit setzen */
+                       if (m[line] & mbit)     /* war das bit in der matrix gesetzt ? */
+                               b |= dbit;      /* ja, dann setz es auch im datenbyte  */
+                       else
+                               b &= dbit - 1;  /* nein, lösch bit im datenbyte */
+                       if (dbit < 128) /* haben wir schon ein ganzes byte voll ? */
+                               dbit <<= 1;     /* nein, auf zum nächsten datenbit */
+                       else {  /* ein ganzes datenbyte ist voll */
+                               buf[buflen++] = b;      /* byte in den output buffer kopieren */
+                               introducer = b = 0;     /* Init der Introsequenz und des datenbytes */
+                               dbit = 1;       /* als nächstes suchen wir das nullte bit */
+                       }
+                       goto next_byte; /* suche das nächste bit in der matrix */
+               }
+       }
+       v->introducer = introducer;
+       v->dbit = dbit;
+       v->b = b;
+       return buflen;          /* return anzahl der bytes im output buffer */
+}
+
+/* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den
+   V110 frames zusammengepackt werden müssen. Die Daten können an diese
+   Schnittstelle so Ã¼bergeben werden, wie sie von der Leitung kommen, ohne
+   darauf achten zu müssen, das frames usw. eingehalten werden.
+ */
+struct sk_buff *
+isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
+{
+       int i;
+       int j;
+       int len;
+       unsigned char *v110_buf;
+       unsigned char *rbuf;
+
+       if (!skb) {
+               printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n");
+               return NULL;
+       }
+       rbuf = skb->data;
+       len = skb->len;
+       if (v == NULL) {
+               /* invalid handle, no chance to proceed */
+               printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n");
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+       if (v->decodelen == 0)  /* cache empty?               */
+               for (; len > 0; len--, rbuf++)  /* scan for SyncHeader in buf */
+                       if ((*rbuf & v->key) == 0)
+                               break;  /* found first byte           */
+       if (len == 0) {
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+       /* copy new data to decode-buffer */
+       memcpy(&(v->decodebuf[v->decodelen]), rbuf, len);
+       v->decodelen += len;
+      ReSync:
+       if (v->decodelen < v->nbytes) { /* got a new header ? */
+               dev_kfree_skb(skb);
+               return NULL;    /* no, try later      */
+       }
+       if (ValidHeaderBytes(v) != v->nbytes) { /* ist es ein ungültiger header ? */
+               SyncHeader(v);  /* nein, such einen header */
+               goto ReSync;
+       }
+       len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
+       if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
+               printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+       for (i = 0; i < len; i++) {
+               v110_buf[i] = 0;
+               for (j = 0; j < v->nbytes; j++)
+                       v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
+               v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
+       }
+       v->decodelen = (v->decodelen % (10 * v->nbytes));
+       memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
+
+       skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
+       kfree(v110_buf);
+       if (skb->len)
+               return skb;
+       else {
+               kfree_skb(skb);
+               return NULL;
+       }
+}
+
+/* EncodeMatrix takes input data in buf, len is the bytecount.
+   Data is encoded into v110 frames in m. Return value is the number of
+   matrix-lines generated.
+ */
+static int
+EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
+{
+       int line = 0;
+       int i = 0;
+       int mbit = 128;
+       int dbit = 1;
+       int introducer = 3;
+       int ibit[] = {0, 1, 1};
+
+       while ((i < len) && (line < mlen)) {    /* solange noch input da ist */
+               switch (line % 10) {    /* in welcher matrixzeile sind wir ? */
+                       case 0:
+                               m[line++] = 0x00;       /* zeile 0 ist immer 0 */
+                               mbit = 128;     /* und es geht mit dem 7. bit weiter */
+                               break;
+                       case 5:
+                               m[line++] = 0xbf;       /* zeile 5 ist immer 10111111 */
+                               mbit = 128;     /* und es geht mit dem 7. bit weiter */
+                               break;
+               }
+               if (line >= mlen) {
+                       printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
+                       return line;
+               }
+       next_bit:
+               switch (mbit) { /* ganz linkes oder rechtes bit ? */
+                       case 1:
+                               line++; /* ganz rechts ! dann in die nächste */
+                               if (line >= mlen) {
+                                       printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
+                                       return line;
+                               }
+                       case 128:
+                               m[line] = 128;  /* ganz links byte auf 1000000 setzen */
+                               mbit = 64;      /* aktuelles bit in der matrixzeile */
+                               continue;
+               }
+               if (introducer) {       /* 110 sequenz setzen ? */
+                       introducer--;   /* ein digit weniger setzen */
+                       m[line] |= ibit[introducer] ? mbit : 0; /* entsprechendes bit setzen */
+                       mbit >>= 1;     /* bit der matrixzeile >> 1 */
+                       goto next_bit;  /* und dort weiter machen */
+               }               /* else datenbits in die matrix packen! */
+               m[line] |= (buf[i] & dbit) ? mbit : 0;  /* datenbit in matrix setzen */
+               if (dbit == 128) {      /* war es das letzte datenbit ? */
+                       dbit = 1;       /* dann mach beim nächsten weiter */
+                       i++;    /* nächste datenbyte des input buffers */
+                       if (i < len)    /* war es schon das letzte ? */
+                               introducer = 3; /* nein, schreib den introducer 110 */
+                       else {  /* war das letzte datenbyte ! */
+                               m[line] |= (mbit - 1) & 0xfe;   /* setz restliche bits der zeile auf 1 */
+                               break;
+                       }
+               } else          /* nicht das letzte datenbit */
+                       dbit <<= 1;     /* dann gehe zum nächsten datenbit */
+               mbit >>= 1;     /* und setz bit der matrix weiter */
+               goto next_bit;
+
+       }
+       /* evtl. noch restliche zeilen in der matrix generieren... */
+       if ((line) && ((line + 10) < mlen))
+               switch (++line % 10) {
+                       case 1:
+                               m[line++] = 0xfe;
+                       case 2:
+                               m[line++] = 0xfe;
+                       case 3:
+                               m[line++] = 0xfe;
+                       case 4:
+                               m[line++] = 0xfe;
+                       case 5:
+                               m[line++] = 0xbf;
+                       case 6:
+                               m[line++] = 0xfe;
+                       case 7:
+                               m[line++] = 0xfe;
+                       case 8:
+                               m[line++] = 0xfe;
+                       case 9:
+                               m[line++] = 0xfe;
+               }
+       return line;            /* soviele matrixzeilen sind es */
+}
+
+/*
+ * Build a sync frame.
+ */
+static struct sk_buff *
+isdn_v110_sync(isdn_v110_stream *v)
+{
+       struct sk_buff *skb;
+
+       if (v == NULL) {
+               /* invalid handle, no chance to proceed */
+               printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
+               return NULL;
+       }
+       if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
+               skb_reserve(skb, v->skbres);
+               memcpy(skb_put(skb, v->framelen), v->OfflineFrame, v->framelen);
+       }
+       return skb;
+}
+
+/*
+ * Build an idle frame.
+ */
+static struct sk_buff *
+isdn_v110_idle(isdn_v110_stream *v)
+{
+       struct sk_buff *skb;
+
+       if (v == NULL) {
+               /* invalid handle, no chance to proceed */
+               printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n");
+               return NULL;
+       }
+       if ((skb = dev_alloc_skb(v->framelen + v->skbres))) {
+               skb_reserve(skb, v->skbres);
+               memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen);
+       }
+       return skb;
+}
+
+struct sk_buff *
+isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
+{
+       int i;
+       int j;
+       int rlen;
+       int mlen;
+       int olen;
+       int size;
+       int sval1;
+       int sval2;
+       int nframes;
+       unsigned char *v110buf;
+       unsigned char *rbuf;
+       struct sk_buff *nskb;
+
+       if (v == NULL) {
+               /* invalid handle, no chance to proceed */
+               printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n");
+               return NULL;
+       }
+       if (!skb) {
+               /* invalid skb, no chance to proceed */
+               printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
+               return NULL;
+       }
+       rlen = skb->len;
+       nframes = (rlen + 3) / 4;
+       v110buf = v->encodebuf;
+       if ((nframes * 40) > v->maxsize) {
+               size = v->maxsize;
+               rlen = v->maxsize / 40;
+       } else
+               size = nframes * 40;
+       if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
+               printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
+               return NULL;
+       }
+       skb_reserve(nskb, v->skbres + sizeof(int));
+       if (skb->len == 0) {
+               memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen);
+               *((int *)skb_push(nskb, sizeof(int))) = 0;
+               return nskb;
+       }
+       mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
+       /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
+       rbuf = skb_put(nskb, size);
+       olen = 0;
+       sval1 = 8 - v->nbits;
+       sval2 = v->key << sval1;
+       for (i = 0; i < mlen; i++) {
+               v110buf[i] = FlipBits(v110buf[i], v->nbits);
+               for (j = 0; j < v->nbytes; j++) {
+                       if (size--)
+                               *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
+                       else {
+                               printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
+                               goto buffer_full;
+                       }
+                       olen++;
+               }
+       }
+buffer_full:
+       skb_trim(nskb, olen);
+       *((int *)skb_push(nskb, sizeof(int))) = rlen;
+       return nskb;
+}
+
+int
+isdn_v110_stat_callback(int idx, isdn_ctrl * c)
+{
+       isdn_v110_stream *v = NULL;
+       int i;
+       int ret;
+
+       if (idx < 0)
+               return 0;
+       switch (c->command) {
+               case ISDN_STAT_BSENT:
+                        /* Keep the send-queue of the driver filled
+                        * with frames:
+                        * If number of outstanding frames < 3,
+                        * send down an Idle-Frame (or an Sync-Frame, if
+                        * v->SyncInit != 0). 
+                        */
+                       if (!(v = dev->v110[idx]))
+                               return 0;
+                       atomic_inc(&dev->v110use[idx]);
+                       if (v->skbidle > 0) {
+                               v->skbidle--;
+                               ret = 1;
+                       } else {
+                               if (v->skbuser > 0)
+                                       v->skbuser--;
+                               ret = 0;
+                       }
+                       for (i = v->skbuser + v->skbidle; i < 2; i++) {
+                               struct sk_buff *skb;
+                               if (v->SyncInit > 0)
+                                       skb = isdn_v110_sync(v);
+                               else
+                                       skb = isdn_v110_idle(v);
+                               if (skb) {
+                                       if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+                                               dev_kfree_skb(skb);
+                                               break;
+                                       } else {
+                                               if (v->SyncInit)
+                                                       v->SyncInit--;
+                                               v->skbidle++;
+                                       }
+                               } else
+                                       break;
+                       }
+                       atomic_dec(&dev->v110use[idx]);
+                       return ret;
+               case ISDN_STAT_DHUP:
+               case ISDN_STAT_BHUP:
+                       while (1) {
+                               atomic_inc(&dev->v110use[idx]);
+                               if (atomic_dec_and_test(&dev->v110use[idx])) {
+                                       isdn_v110_close(dev->v110[idx]);
+                                       dev->v110[idx] = NULL;
+                                       break;
+                               }
+                               sti();
+                       }
+                       break;
+               case ISDN_STAT_BCONN:
+                       if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
+                               int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
+                               int maxsize = dev->drv[c->driver]->interface->maxbufsize;
+                               atomic_inc(&dev->v110use[idx]);
+                               switch (dev->v110emu[idx]) {
+                                       case ISDN_PROTO_L2_V11096:
+                                               dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
+                                               break;
+                                       case ISDN_PROTO_L2_V11019:
+                                               dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
+                                               break;
+                                       case ISDN_PROTO_L2_V11038:
+                                               dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
+                                               break;
+                                       default:
+                               }
+                               if ((v = dev->v110[idx])) {
+                                       while (v->SyncInit) {
+                                               struct sk_buff *skb = isdn_v110_sync(v);
+                                               if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
+                                                       dev_kfree_skb(skb);
+                                                       /* Unable to send, try later */
+                                                       break;
+                                               }
+                                               v->SyncInit--;
+                                               v->skbidle++;
+                                       }
+                               } else
+                                       printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
+                               atomic_dec(&dev->v110use[idx]);
+                       }
+                       break;
+               default:
+                       return 0;
+       }
+       return 0;
+}
diff --git a/drivers/isdn/isdn_v110.h b/drivers/isdn/isdn_v110.h
new file mode 100644 (file)
index 0000000..9ab5a93
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id: isdn_v110.h,v 1.1 1998/02/20 17:32:11 fritz Exp $
+
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+ * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Log: isdn_v110.h,v $
+ * Revision 1.1  1998/02/20 17:32:11  fritz
+ * First checkin (not yet completely functionable).
+ *
+ */
+#ifndef _isdn_v110_h_
+#define _isdn_v110_h_
+
+/* isdn_v110_encode erhält len Nettodaten in buf, kodiert diese und liefert
+   das Ergebnis wieder in buf. Wieviele Bytes kodiert wurden wird als
+   return zurück gegeben. Diese Daten können dann 1:1 auf die Leitung
+   gegeben werden.
+*/
+extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
+
+/* isdn_v110_decode erhält vom input stream V110 kodierte Daten, die zu den
+   V110 frames zusammengepackt werden müssen. Die Daten können an diese
+   Schnittstelle so Ã¼bergeben werden, wie sie von der Leitung kommen, ohne
+   darauf achten zu müssen, das frames usw. eingehalten werden.
+ */
+extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
+
+extern int isdn_v110_stat_callback(int, isdn_ctrl *);
+
+#endif
diff --git a/drivers/isdn/isdn_x25iface.c b/drivers/isdn/isdn_x25iface.c
new file mode 100644 (file)
index 0000000..17d291c
--- /dev/null
@@ -0,0 +1,340 @@
+/* $Id: isdn_x25iface.c,v 1.3 1998/02/20 17:25:20 fritz Exp $
+ * stuff needed to support the Linux X.25 PLP code on top of devices that
+ * can provide a lab_b service using the concap_proto mechanism.
+ * This module supports a network interface wich provides lapb_sematics
+ * -- as defined in ../../Documentation/networking/x25-iface.txt -- to
+ * the upper layer and assumes that the lower layer provides a reliable
+ * data link service by means of the the concap_device_ops callbacks.
+ *
+ * Only protocol specific stuff goes here. Device specific stuff
+ * goes to another -- device related -- concap_proto support source file.
+ *
+ * $Log: isdn_x25iface.c,v $
+ * Revision 1.3  1998/02/20 17:25:20  fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.2  1998/01/31 22:49:22  keil
+ * correct comments
+ *
+ * Revision 1.1  1998/01/31 22:27:58  keil
+ * New files from Henner Eisen for X.25 support
+ *
+ */
+
+/* #include <linux/isdn.h> */
+#include <linux/netdevice.h>
+#include <linux/concap.h>
+#include <linux/wanrouter.h>
+#include "isdn_x25iface.h"
+
+/* for debugging messages not to cause an oops when device pointer is NULL*/
+#define MY_DEVNAME(dev)  ( (dev) ? (dev)->name : "DEVICE UNSPECIFIED" )
+
+
+typedef struct isdn_x25iface_proto_data {
+       int magic;
+       enum wan_states state;
+       /* Private stuff, not to be accessed via proto_data. We provide the
+          other storage for the concap_proto instance here as well,
+          enabling us to allocate both with just one kmalloc(): */ 
+       struct concap_proto priv;
+} ix25_pdata_t;
+
+
+
+/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
+void isdn_x25iface_proto_del( struct concap_proto * );
+int isdn_x25iface_proto_close( struct concap_proto * );
+int isdn_x25iface_proto_restart( struct concap_proto *,
+                                struct device *,
+                                struct concap_device_ops *);
+int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
+int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
+int isdn_x25iface_connect_ind( struct concap_proto * );
+int isdn_x25iface_disconn_ind( struct concap_proto * );
+
+
+static struct concap_proto_ops ix25_pops = {
+       &isdn_x25iface_proto_new,
+       &isdn_x25iface_proto_del,
+       &isdn_x25iface_proto_restart,
+       &isdn_x25iface_proto_close,
+       &isdn_x25iface_xmit,
+       &isdn_x25iface_receive,
+       &isdn_x25iface_connect_ind,
+       &isdn_x25iface_disconn_ind
+};
+
+/* error message helper fuction */
+static void illegal_state_warn( unsigned state, unsigned char firstbyte) 
+{
+       printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
+               "current state %d\n",firstbyte, state );
+}
+
+/* check protocol data field for consistency */
+static int pdata_is_bad( ix25_pdata_t * pda ){
+
+       if( pda  &&  pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
+       printk( KERN_WARNING
+               "isdn_x25iface_xxx: illegal pointer to proto data\n" );
+       return 1;
+}
+
+/* create a new x25 interface protocol instance
+ */
+struct concap_proto * isdn_x25iface_proto_new()
+{
+       ix25_pdata_t * tmp = kmalloc(sizeof(ix25_pdata_t),GFP_KERNEL);
+       IX25DEBUG("isdn_x25iface_proto_new\n");
+       if( tmp ){
+               tmp -> magic = ISDN_X25IFACE_MAGIC;
+               tmp -> state = WAN_UNCONFIGURED;
+               /* private data space used to hold the concap_proto data.
+                  Only to be accessed via the returned pointer */
+               tmp -> priv.dops       = NULL;
+               tmp -> priv.net_dev    = NULL;
+               tmp -> priv.pops       = &ix25_pops;
+               tmp -> priv.flags      = 0;
+               tmp -> priv.proto_data = tmp;
+               return( &(tmp -> priv) );
+       }
+       return NULL;
+};
+
+/* close the x25iface encapsulation protocol 
+ */
+int isdn_x25iface_proto_close(struct concap_proto *cprot){
+
+       ix25_pdata_t *tmp;
+        int ret = 0;
+       ulong flags;
+
+       if( ! cprot ){
+               printk( KERN_ERR "isdn_x25iface_proto_close: "
+                       "invalid concap_proto pointer\n" );
+               return -1;
+       }
+       IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
+       save_flags(flags);
+       cli();  /* avoid races with incoming events calling pops methods while
+                cprot members are inconsistent */  
+       cprot -> dops    = NULL;
+       cprot -> net_dev = NULL;
+       tmp = cprot -> proto_data;
+       if( pdata_is_bad( tmp ) ){
+               ret = -1;
+       } else {
+               tmp -> state = WAN_UNCONFIGURED;
+       }
+       restore_flags(flags);
+
+       return ret;
+}
+
+/* Delete the x25iface encapsulation protocol instance
+ */
+void isdn_x25iface_proto_del(struct concap_proto *cprot){
+
+       ix25_pdata_t * tmp;
+       IX25DEBUG( "isdn_x25iface_proto_del \n" );
+       if( ! cprot ){
+               printk( KERN_ERR "isdn_x25iface_proto_del: "
+                       "concap_proto pointer is NULL\n" );
+               return;
+       }
+       tmp = cprot -> proto_data;
+       if( tmp == NULL ){ 
+               printk( KERN_ERR "isdn_x25iface_proto_del: inconsistent "
+                       "proto_data pointer (maybe already deleted?)\n"); 
+               return;
+       }
+       /* close if the protocol is still open */
+       if( cprot -> dops ) isdn_x25iface_proto_close(cprot);
+       /* freeing the storage should be sufficient now. But some additional
+          settings might help to catch wild pointer bugs */
+       tmp -> magic = 0;
+       cprot -> proto_data = NULL;
+
+       kfree( tmp );
+       return;
+}
+
+/* (re-)initialize the data structures for x25iface encapsulation
+ */
+int isdn_x25iface_proto_restart(struct concap_proto *cprot,
+                               struct device *ndev, 
+                               struct concap_device_ops *dops)
+{
+       ix25_pdata_t * pda = cprot -> proto_data ;
+       ulong flags;
+
+       IX25DEBUG( "isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev) );
+
+       if ( pdata_is_bad( pda ) ) return -1;
+
+       if( !( dops  && dops -> data_req && dops -> connect_req 
+              && dops -> disconn_req )  ){
+               printk( KERN_WARNING "isdn_x25iface_restart: required dops"
+                       " missing\n" );
+               isdn_x25iface_proto_close(cprot);
+               return -1;
+       }
+       save_flags(flags);
+       cli();  /* avoid races with incoming events calling pops methods while
+                cprot members are inconsistent */  
+       cprot -> net_dev = ndev;
+       cprot -> pops = &ix25_pops;
+       cprot -> dops = dops;
+       pda -> state = WAN_DISCONNECTED;
+       restore_flags(flags);
+       return 0;
+}
+
+/* deliver a dl_data frame received from i4l HL driver to the network layer 
+ */
+int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
+{
+       IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
+       if ( ( (ix25_pdata_t*) (cprot->proto_data) ) 
+            -> state == WAN_CONNECTED ){
+               skb -> dev = cprot -> net_dev;
+               skb -> protocol = htons(ETH_P_X25);
+               skb -> pkt_type = PACKET_HOST;
+               if( skb_push(skb, 1)){
+                       skb -> data[0]=0x00;
+                       skb -> mac.raw = skb -> data;
+                       netif_rx(skb);
+                       return 0;
+               }
+       }
+       printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev) );
+       dev_kfree_skb(skb);
+       return -1;
+}
+
+/* a connection set up is indicated by lower layer 
+ */
+int isdn_x25iface_connect_ind(struct concap_proto *cprot)
+{
+       struct sk_buff * skb = dev_alloc_skb(1);
+       enum wan_states *state_p 
+         = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
+       IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
+                  , MY_DEVNAME(cprot->net_dev) );
+       if( *state_p == WAN_UNCONFIGURED ){ 
+               printk(KERN_WARNING 
+                      "isdn_x25iface_connect_ind while unconfigured %s\n"
+                      , MY_DEVNAME(cprot->net_dev) );
+               return -1;
+       }
+       *state_p = WAN_CONNECTED;
+       if( skb ){
+               *( skb_put(skb, 1) ) = 0x01;
+               skb -> mac.raw = skb -> data;
+               skb -> dev  = cprot -> net_dev;
+               skb -> protocol = htons(ETH_P_X25);
+               skb -> pkt_type = PACKET_HOST;
+               netif_rx(skb);
+               return 0;
+       } else {
+               printk(KERN_WARNING "isdn_x25iface_connect_ind: "
+                      " out of memory -- disconnecting\n");
+               cprot -> dops -> disconn_req(cprot);
+               return -1;
+       }
+}
+       
+/* a disconnect is indicated by lower layer 
+ */
+int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
+{
+       struct sk_buff *skb;
+       enum wan_states *state_p 
+         = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
+       IX25DEBUG( "isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot -> net_dev) );
+       if( *state_p == WAN_UNCONFIGURED ){ 
+               printk(KERN_WARNING 
+                      "isdn_x25iface_disconn_ind while unconfigured\n");
+               return -1;
+       }
+       if(! cprot -> net_dev) return -1;
+       *state_p = WAN_DISCONNECTED;
+       skb = dev_alloc_skb(1);
+       if( skb ){
+               *( skb_put(skb, 1) ) = 0x02;
+               skb -> mac.raw = skb -> data;
+               skb -> dev  = cprot -> net_dev;
+               skb -> protocol = htons(ETH_P_X25);
+               skb -> pkt_type = PACKET_HOST;
+               netif_rx(skb);
+               return 0;
+       } else {
+               printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
+                      " out of memory\n");
+               return -1;
+       }
+}
+
+/* process a frame handed over to us from linux network layer. First byte
+   semantics as defined in ../../Documentation/networking/x25-iface.txt 
+   */
+int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
+{
+       unsigned char firstbyte = skb->data[0];
+       unsigned *state = 
+               &( ( (ix25_pdata_t*) (cprot -> proto_data) ) -> state  );
+       int ret = 0;
+       IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
+       switch ( firstbyte ){
+       case 0x00: /* dl_data request */
+               if( *state == WAN_CONNECTED ){
+                       skb_pull(skb, 1);
+                       cprot -> net_dev -> trans_start = jiffies;
+                       ret = ( cprot -> dops -> data_req(cprot, skb) );
+                       /* prepare for future retransmissions */
+                       if( ret ) skb_push(skb,1);
+                       return ret;
+               }
+               illegal_state_warn( *state, firstbyte ); 
+               break;
+       case 0x01: /* dl_connect request */
+               if( *state == WAN_DISCONNECTED ){
+                       *state = WAN_CONNECTING;
+                       cprot -> dops -> connect_req(cprot);
+               } else {
+                       illegal_state_warn( *state, firstbyte );
+               }
+               break;
+       case 0x02: /* dl_disconnect request */
+               switch ( *state ){
+               case WAN_DISCONNECTED: 
+                       /* Should not happen. However, give upper layer a
+                          chance to recover from inconstistency  but don't
+                          trust the lower layer sending the disconn_confirm
+                          when already disconnected */
+                       printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
+                              " requested while disconnected\n" );
+                       isdn_x25iface_disconn_ind(cprot);
+                       break; /* prevent infinite loops */
+               case WAN_CONNECTING:
+               case WAN_CONNECTED:
+                       *state = WAN_DISCONNECTED;
+                       cprot -> dops -> disconn_req(cprot);
+                       break;
+               default:
+                       illegal_state_warn( *state, firstbyte );
+               }
+               break;
+       case 0x03: /* changing lapb parameters requested */
+               printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
+                      " options not yet supported\n");
+               break;
+       default:
+               printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
+                      " first byte %x ignored:\n", firstbyte);
+       }
+       dev_kfree_skb(skb);
+       return 0;
+}
diff --git a/drivers/isdn/isdn_x25iface.h b/drivers/isdn/isdn_x25iface.h
new file mode 100644 (file)
index 0000000..146eeef
--- /dev/null
@@ -0,0 +1,32 @@
+/* $Id: isdn_x25iface.h,v 1.2 1998/01/31 22:49:23 keil Exp $
+ */
+#ifndef _LINUX_ISDN_X25IFACE_H
+#define _LINUX_ISDN_X25IFACE_H
+
+#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
+/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
+#ifdef DEBUG_ISDN_X25
+#   define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
+#else
+#   define IX25DEBUG(fmt,args...)
+#endif
+
+#include <linux/skbuff.h>
+#include <linux/wanrouter.h>
+#include <linux/isdn.h>
+#include <linux/concap.h>
+
+extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
+extern struct concap_proto     * isdn_x25iface_proto_new(void);
+
+
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile
new file mode 100644 (file)
index 0000000..588d807
--- /dev/null
@@ -0,0 +1,11 @@
+L_OBJS :=
+M_OBJS :=
+
+ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
+  L_OBJS += isdnloop.o
+else
+  M_OBJS += isdnloop.o
+endif
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
new file mode 100644 (file)
index 0000000..faf59ca
--- /dev/null
@@ -0,0 +1,1619 @@
+/* $Id: isdnloop.c,v 1.4 1998/02/24 21:39:05 he Exp $
+
+ * ISDN low-level module implementing a dummy loop driver.
+ *
+ * Copyright 1997 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)
+ * 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: isdnloop.c,v $
+ * Revision 1.4  1998/02/24 21:39:05  he
+ * L2_PROT_X25DTE / DCE
+ * additional state 17 and new internal signal messages "BCON_I"
+ * (for reliable connect confirmation primitive as needed by x.25 upper layer)
+ * Changes for new LL-HL interface
+ *
+ * Revision 1.3  1998/02/20 17:33:30  fritz
+ * Changes for recent kernels.
+ *
+ * Revision 1.2  1997/10/01 09:22:03  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.1  1997/03/24 23:02:04  fritz
+ * Added isdnloop driver.
+ *
+ */
+
+#include "isdnloop.h"
+
+static char
+*revision = "$Revision: 1.4 $";
+
+static int isdnloop_addcard(char *);
+
+/*
+ * Free queue completely.
+ *
+ * Parameter:
+ *   card    = pointer to card struct
+ *   channel = channel number
+ */
+static void
+isdnloop_free_queue(isdnloop_card * card, int channel)
+{
+       struct sk_buff_head *queue = &card->bqueue[channel];
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(queue)))
+               dev_kfree_skb(skb);
+       card->sndcount[channel] = 0;
+}
+
+/*
+ * Send B-Channel data to another virtual card.
+ * This routine is called via timer-callback from isdnloop_pollbchan().
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   ch   = channel number (0-based)
+ */
+static void
+isdnloop_bchan_send(isdnloop_card * card, int ch)
+{
+       isdnloop_card *rcard = card->rcard[ch];
+       int rch = card->rch[ch], len, ack;
+       struct sk_buff *skb;
+       isdn_ctrl cmd;
+
+       while (card->sndcount[ch]) {
+               if ((skb = skb_dequeue(&card->bqueue[ch]))) {
+                       len = skb->len;
+                       card->sndcount[ch] -= len;
+                       ack = *(skb->head); /* used as scratch area */
+                       cmd.driver = card->myid;
+                       cmd.arg = ch;
+                       if (rcard){
+                               rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
+                       } else {
+                               printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
+                               dev_kfree_skb(skb);
+
+                               cmd.command = ISDN_STAT_L1ERR;
+                               cmd.parm.errcode = ISDN_STAT_L1ERR_SEND;
+                               card->interface.statcallb(&cmd); 
+                       };
+                       cmd.command = ISDN_STAT_BSENT;
+                       cmd.parm.length = len;
+                       if ( ack ) card->interface.statcallb(&cmd);
+               } else
+                       card->sndcount[ch] = 0;
+       }
+}
+
+/*
+ * Send/Receive Data to/from the B-Channel.
+ * This routine is called via timer-callback.
+ * It schedules itself while any B-Channel is open.
+ *
+ * Parameter:
+ *   data = pointer to card struct, set by kernel timer.data
+ */
+static void
+isdnloop_pollbchan(unsigned long data)
+{
+       isdnloop_card *card = (isdnloop_card *) data;
+       unsigned long flags;
+
+       if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
+               isdnloop_bchan_send(card, 0);
+       if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
+               isdnloop_bchan_send(card, 1);
+       if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
+               /* schedule b-channel polling again */
+               save_flags(flags);
+               cli();
+               card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+               add_timer(&card->rb_timer);
+               card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+               restore_flags(flags);
+       } else
+               card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
+}
+
+/*
+ * Parse ICN-type setup string and fill fields of setup-struct
+ * with parsed data.
+ *
+ * Parameter:
+ *   setup = setup string, format: [caller-id],si1,si2,[called-id]
+ *   cmd   = pointer to struct to be filled.
+ */
+static void
+isdnloop_parse_setup(char *setup, isdn_ctrl * cmd)
+{
+       char *t = setup;
+       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;
+}
+
+typedef struct isdnloop_stat {
+       char *statstr;
+       int command;
+       int action;
+} isdnloop_stat;
+/* *INDENT-OFF* */
+static isdnloop_stat isdnloop_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* */
+
+
+/*
+ * Parse Status message-strings from virtual card.
+ * Depending on status, call statcallb for sending messages to upper
+ * levels. Also set/reset B-Channel active-flags.
+ *
+ * Parameter:
+ *   status  = status string to parse.
+ *   channel = channel where message comes from.
+ *   card    = card where message comes from.
+ */
+static void
+isdnloop_parse_status(u_char * status, int channel, isdnloop_card * card)
+{
+       isdnloop_stat *s = isdnloop_stat_table;
+       int action = -1;
+       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;
+       cmd.driver = card->myid;
+       cmd.arg = channel;
+       switch (action) {
+               case 1:
+                       /* BCON_x */
+                       card->flags |= (channel) ?
+                           ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
+                       break;
+               case 2:
+                       /* BDIS_x */
+                       card->flags &= ~((channel) ?
+                                        ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
+                       isdnloop_free_queue(card, channel);
+                       break;
+               case 3:
+                       /* DCAL_I and DSCA_I */
+                       isdnloop_parse_setup(status + 6, &cmd);
+                       break;
+               case 4:
+                       /* FCALL */
+                       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:
+                       /* CIF */
+                       strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1);
+                       break;
+               case 6:
+                       /* AOC */
+                       sprintf(cmd.parm.num, "%d",
+                            (int) simple_strtoul(status + 7, NULL, 16));
+                       break;
+               case 7:
+                       /* CAU */
+                       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:
+                       /* Misc Errors on L1 and L2 */
+                       card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
+                       isdnloop_free_queue(card, 0);
+                       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 &= ~ISDNLOOP_FLAGS_B2ACTIVE;
+                       isdnloop_free_queue(card, 1);
+                       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);
+}
+
+/*
+ * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   c    = char to store.
+ */
+static void
+isdnloop_putmsg(isdnloop_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);
+}
+
+/*
+ * Poll a virtual cards message queue.
+ * If there are new status-replies from the card, copy them to
+ * ringbuffer for reading on /dev/isdnctrl and call
+ * isdnloop_parse_status() for processing them. Watch for special
+ * Firmware bootmessage and parse it, to get the D-Channel protocol.
+ * If there are B-Channels open, initiate a timer-callback to
+ * isdnloop_pollbchan().
+ * This routine is called periodically via timer interrupt.
+ *
+ * Parameter:
+ *   data = pointer to card struct
+ */
+static void
+isdnloop_polldchan(unsigned long data)
+{
+       isdnloop_card *card = (isdnloop_card *) data;
+       struct sk_buff *skb;
+       int avail;
+       int left;
+       u_char c;
+       int ch;
+       int flags;
+       u_char *p;
+       isdn_ctrl cmd;
+
+       if ((skb = skb_dequeue(&card->dqueue)))
+               avail = skb->len;
+       else
+               avail = 0;
+       for (left = avail; left > 0; left--) {
+               c = *skb->data;
+               skb_pull(skb, 1);
+               isdnloop_putmsg(card, c);
+               card->imsg[card->iptr] = c;
+               if (card->iptr < 59)
+                       card->iptr++;
+               if (!skb->len) {
+                       avail++;
+                       isdnloop_putmsg(card, '\n');
+                       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];
+                               isdnloop_parse_status(p, ch, card);
+                       } else {
+                               p = card->imsg;
+                               if (!strncmp(p, "DRV1.", 5)) {
+                                       printk(KERN_INFO "isdnloop: (%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
+                                                      "isdnloop: (%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
+                                                      "isdnloop: (%s) Euro-Protocol loaded and running\n", CID);
+                                       }
+                                       continue;
+
+                               }
+                       }
+               }
+       }
+       if (avail) {
+               cmd.command = ISDN_STAT_STAVAIL;
+               cmd.driver = card->myid;
+               cmd.arg = avail;
+               card->interface.statcallb(&cmd);
+       }
+       if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
+               if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
+                       /* schedule b-channel polling */
+                       card->flags |= ISDNLOOP_FLAGS_RBTIMER;
+                       save_flags(flags);
+                       cli();
+                       del_timer(&card->rb_timer);
+                       card->rb_timer.function = isdnloop_pollbchan;
+                       card->rb_timer.data = (unsigned long) card;
+                       card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
+                       add_timer(&card->rb_timer);
+                       restore_flags(flags);
+               }
+       /* schedule again */
+       save_flags(flags);
+       cli();
+       card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
+       add_timer(&card->st_timer);
+       restore_flags(flags);
+}
+
+/*
+ * Append a packet to the transmit buffer-queue.
+ *
+ * Parameter:
+ *   channel = Number of B-channel
+ *   skb     = packet to send.
+ *   card    = pointer to card-struct
+ * Return:
+ *   Number of bytes transferred, -E??? on error
+ */
+static int
+isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
+{
+       int len = skb->len;
+       unsigned long flags;
+       struct sk_buff *nskb;
+
+       if (len > 4000) {
+               printk(KERN_WARNING
+                      "isdnloop: Send packet too large\n");
+               return -EINVAL;
+       }
+       if (len) {
+               if (!(card->flags & (channel) ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))
+                       return 0;
+               if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
+                       return 0;
+               save_flags(flags);
+               cli();
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (nskb) {
+                       skb_queue_tail(&card->bqueue[channel], nskb);
+                       dev_kfree_skb(skb);
+               } else
+                       len = 0;
+               card->sndcount[channel] += len;
+               restore_flags(flags);
+       }
+       return len;
+}
+
+/*
+ * Read the messages from the card's ringbuffer
+ *
+ * Parameter:
+ *   buf  = pointer to buffer.
+ *   len  = number of bytes to read.
+ *   user = flag, 1: called from userlevel 0: called from kernel.
+ *   card = pointer to card struct.
+ * Return:
+ *   number of bytes actually transferred.
+ */
+static int
+isdnloop_readstatus(u_char * buf, int len, int user, isdnloop_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;
+}
+
+/*
+ * Simulate a card's response by appending it to the cards
+ * message queue.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   s    = pointer to message-string.
+ *   ch   = channel: 0 = generic messages, 1 and 2 = D-channel messages.
+ * Return:
+ *   0 on success, 1 on memory squeeze.
+ */
+static int
+isdnloop_fake(isdnloop_card * card, char *s, int ch)
+{
+       struct sk_buff *skb;
+       int len = strlen(s) + ((ch >= 0) ? 3 : 0);
+
+       if (!(skb = dev_alloc_skb(len))) {
+               printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
+               return 1;
+       }
+       if (ch >= 0)
+               sprintf(skb_put(skb, 3), "%02d;", ch);
+       memcpy(skb_put(skb, strlen(s)), s, strlen(s));
+       skb_queue_tail(&card->dqueue, skb);
+       return 0;
+}
+/* *INDENT-OFF* */
+static isdnloop_stat isdnloop_cmd_table[] =
+{
+       {"BCON_R",         0,  1},      /* B-Channel connect        */
+       {"BCON_I",         0, 17},      /* B-Channel connect ind    */
+       {"BDIS_R",         0,  2},      /* B-Channel disconnect     */
+       {"DDIS_R",         0,  3},      /* D-Channel disconnect     */
+       {"DCON_R",         0, 16},      /* D-Channel connect        */
+       {"DSCA_R",         0,  4},      /* Dial 1TR6-SPV     */
+       {"DCAL_R",         0,  5},      /* Dial */
+       {"EAZC",           0,  6},      /* Clear EAZ listener */
+       {"EAZ",            0,  7},      /* Set EAZ listener */
+       {"SEEAZ",          0,  8},      /* Get EAZ listener */
+       {"MSN",            0,  9},      /* Set/Clear MSN listener */
+       {"MSALL",          0, 10},      /* Set multi MSN listeners */
+       {"SETSIL",         0, 11},      /* Set SI list     */
+       {"SEESIL",         0, 12},      /* Get SI list     */
+       {"SILC",           0, 13},      /* Clear SI list     */
+       {"LOCK",           0, -1},      /* LOCK channel     */
+       {"UNLOCK",         0, -1},      /* UNLOCK channel     */
+       {"FV2ON",          1, 14},      /* Leased mode on               */
+       {"FV2OFF",         1, 15},      /* Leased mode off              */
+       {NULL, 0, -1}
+};
+/* *INDENT-ON* */
+
+
+/*
+ * Simulate an error-response from a card.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ */
+static void
+isdnloop_fake_err(isdnloop_card * card)
+{
+       char buf[60];
+
+       sprintf(buf, "E%s", card->omsg);
+       isdnloop_fake(card, buf, -1);
+       isdnloop_fake(card, "NAK", -1);
+}
+
+static u_char ctable_eu[] =
+{0x00, 0x11, 0x01, 0x12};
+static u_char ctable_1t[] =
+{0x00, 0x3b, 0x01, 0x3a};
+
+/*
+ * Assemble a simplified cause message depending on the
+ * D-channel protocol used.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   loc  = location: 0 = local, 1 = remote.
+ *   cau  = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
+ * Return:
+ *   Pointer to buffer containing the assembled message.
+ */
+static char *
+isdnloop_unicause(isdnloop_card * card, int loc, int cau)
+{
+       static char buf[6];
+
+       switch (card->ptype) {
+               case ISDN_PTYPE_EURO:
+                       sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
+                       break;
+               case ISDN_PTYPE_1TR6:
+                       sprintf(buf, "%02X44", ctable_1t[cau]);
+                       break;
+               default:
+                       return ("0000");
+       }
+       return (buf);
+}
+
+/*
+ * Release a virtual connection. Called from timer interrupt, when
+ * called party did not respond.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   ch   = channel (0-based)
+ */
+static void
+isdnloop_atimeout(isdnloop_card * card, int ch)
+{
+       unsigned long flags;
+       char buf[60];
+
+       save_flags(flags);
+       cli();
+       if (card->rcard) {
+               isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
+               card->rcard[ch]->rcard[card->rch[ch]] = NULL;
+               card->rcard[ch] = NULL;
+       }
+       isdnloop_fake(card, "DDIS_I", ch + 1);
+       /* No user responding */
+       sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
+       isdnloop_fake(card, buf, ch + 1);
+       restore_flags(flags);
+}
+
+/*
+ * Wrapper for isdnloop_atimeout().
+ */
+static void
+isdnloop_atimeout0(unsigned long data)
+{
+       isdnloop_card *card = (isdnloop_card *) data;
+       isdnloop_atimeout(card, 0);
+}
+
+/*
+ * Wrapper for isdnloop_atimeout().
+ */
+static void
+isdnloop_atimeout1(unsigned long data)
+{
+       isdnloop_card *card = (isdnloop_card *) data;
+       isdnloop_atimeout(card, 1);
+}
+
+/*
+ * Install a watchdog for a user, not responding.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   ch   = channel to watch for.
+ */
+static void
+isdnloop_start_ctimer(isdnloop_card * card, int ch)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       init_timer(&card->c_timer[ch]);
+       card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
+       if (ch)
+               card->c_timer[ch].function = isdnloop_atimeout1;
+       else
+               card->c_timer[ch].function = isdnloop_atimeout0;
+       card->c_timer[ch].data = (unsigned long) card;
+       add_timer(&card->c_timer[ch]);
+       restore_flags(flags);
+}
+
+/*
+ * Kill a pending channel watchdog.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ *   ch   = channel (0-based).
+ */
+static void
+isdnloop_kill_ctimer(isdnloop_card * card, int ch)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       del_timer(&card->c_timer[ch]);
+       restore_flags(flags);
+}
+
+static u_char si2bit[] =
+{0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
+static u_char bit2si[] =
+{1, 5, 7};
+
+/*
+ * Try finding a listener for an outgoing call.
+ *
+ * Parameter:
+ *   card = pointer to calling card.
+ *   p    = pointer to ICN-type setup-string.
+ *   lch  = channel of calling card.
+ *   cmd  = pointer to struct to be filled when parsing setup.
+ * Return:
+ *   0 = found match, alerting should happen.
+ *   1 = found matching number but it is busy.
+ *   2 = no matching listener.
+ *   3 = found matching number but SI does not match.
+ */
+static int
+isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
+{
+       isdnloop_card *cc = cards;
+       unsigned long flags;
+       int ch;
+       int num_match;
+       int i;
+       char *e;
+       char nbuf[32];
+
+       isdnloop_parse_setup(p, cmd);
+       while (cc) {
+               for (ch = 0; ch < 2; ch++) {
+                       /* Exclude ourself */
+                       if ((cc == card) && (ch == lch))
+                               continue;
+                       num_match = 0;
+                       switch (cc->ptype) {
+                               case ISDN_PTYPE_EURO:
+                                       for (i = 0; i < 3; i++)
+                                               if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
+                                                       num_match = 1;
+                                       break;
+                               case ISDN_PTYPE_1TR6:
+                                       e = cc->eazlist[ch];
+                                       while (*e) {
+                                               sprintf(nbuf, "%s%c", cc->s0num[0], *e);
+                                               if (!(strcmp(nbuf, cmd->parm.setup.phone)))
+                                                       num_match = 1;
+                                               e++;
+                                       }
+                       }
+                       if (num_match) {
+                               save_flags(flags);
+                               cli();
+                               /* channel idle? */
+                               if (!(cc->rcard[ch])) {
+                                       /* Check SI */
+                                       if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
+                                               restore_flags(flags);
+                                               return 3;
+                                       }
+                                       /* ch is idle, si and number matches */
+                                       cc->rcard[ch] = card;
+                                       cc->rch[ch] = lch;
+                                       card->rcard[lch] = cc;
+                                       card->rch[lch] = ch;
+                                       restore_flags(flags);
+                                       return 0;
+                               } else {
+                                       restore_flags(flags);
+                                       /* num matches, but busy */
+                                       if (ch == 1)
+                                               return 1;
+                               }
+                       }
+               }
+               cc = cc->next;
+       }
+       return 2;
+}
+
+/*
+ * Depending on D-channel protocol and caller/called, modify
+ * phone number.
+ *
+ * Parameter:
+ *   card   = pointer to card struct.
+ *   phone  = pointer phone number.
+ *   caller = flag: 1 = caller, 0 = called.
+ * Return:
+ *   pointer to new phone number.
+ */
+static char *
+isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
+{
+       int i;
+       static char nphone[30];
+
+       switch (card->ptype) {
+               case ISDN_PTYPE_EURO:
+                       if (caller) {
+                               for (i = 0; i < 2; i++)
+                                       if (!(strcmp(card->s0num[i], phone)))
+                                               return (phone);
+                               return (card->s0num[0]);
+                       }
+                       return (phone);
+                       break;
+               case ISDN_PTYPE_1TR6:
+                       if (caller) {
+                               sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
+                               return (nphone);
+                       } else
+                               return (&phone[strlen(phone) - 1]);
+                       break;
+       }
+       return ("\0");
+}
+
+/*
+ * Parse an ICN-type command string sent to the 'card'.
+ * Perform misc. actions depending on the command.
+ *
+ * Parameter:
+ *   card = pointer to card struct.
+ */
+static void
+isdnloop_parse_cmd(isdnloop_card * card)
+{
+       char *p = card->omsg;
+       isdn_ctrl cmd;
+       char buf[60];
+       isdnloop_stat *s = isdnloop_cmd_table;
+       int action = -1;
+       int i;
+       int ch;
+
+       if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
+               isdnloop_fake_err(card);
+               return;
+       }
+       ch = card->omsg[1] - '0';
+       if ((ch < 0) || (ch > 2)) {
+               isdnloop_fake_err(card);
+               return;
+       }
+       p += 3;
+       while (s->statstr) {
+               if (!strncmp(p, s->statstr, strlen(s->statstr))) {
+                       action = s->action;
+                       if (s->command && (ch != 0)) {
+                               isdnloop_fake_err(card);
+                               return;
+                       }
+                       break;
+               }
+               s++;
+       }
+       if (action == -1)
+               return;
+       switch (action) {
+               case 1:
+                       /* 0x;BCON_R */
+                       if (card->rcard[ch - 1]) {
+                               isdnloop_fake(card->rcard[ch - 1], "BCON_I",
+                                             card->rch[ch - 1] + 1);
+                       }
+                       break;
+               case 17:
+                       /* 0x;BCON_I */
+                       if (card->rcard[ch - 1]) {
+                               isdnloop_fake(card->rcard[ch - 1], "BCON_C",
+                                             card->rch[ch - 1] + 1);
+                       }
+                       break;
+               case 2:
+                       /* 0x;BDIS_R */
+                       isdnloop_fake(card, "BDIS_C", ch);
+                       if (card->rcard[ch - 1]) {
+                               isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
+                                             card->rch[ch - 1] + 1);
+                       }
+                       break;
+               case 16:
+                       /* 0x;DCON_R */
+                       isdnloop_kill_ctimer(card, ch - 1);
+                       if (card->rcard[ch - 1]) {
+                               isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
+                               isdnloop_fake(card->rcard[ch - 1], "DCON_C",
+                                             card->rch[ch - 1] + 1);
+                               isdnloop_fake(card, "DCON_C", ch);
+                       }
+                       break;
+               case 3:
+                       /* 0x;DDIS_R */
+                       isdnloop_kill_ctimer(card, ch - 1);
+                       if (card->rcard[ch - 1]) {
+                               isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
+                               isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
+                                             card->rch[ch - 1] + 1);
+                               card->rcard[ch - 1] = NULL;
+                       }
+                       isdnloop_fake(card, "DDIS_C", ch);
+                       break;
+               case 4:
+                       /* 0x;DSCA_Rdd,yy,zz,oo */
+                       if (card->ptype != ISDN_PTYPE_1TR6) {
+                               isdnloop_fake_err(card);
+                               return;
+                       }
+                       /* Fall through */
+               case 5:
+                       /* 0x;DCAL_Rdd,yy,zz,oo */
+                       p += 6;
+                       switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
+                               case 0:
+                                       /* Alerting */
+                                       sprintf(buf, "D%s_I%s,%02d,%02d,%s",
+                                          (action == 4) ? "SCA" : "CAL",
+                                               isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
+                                               cmd.parm.setup.si1,
+                                               cmd.parm.setup.si2,
+                                       isdnloop_vstphone(card->rcard[ch],
+                                              cmd.parm.setup.phone, 0));
+                                       isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
+                                       /* Fall through */
+                               case 3:
+                                       /* si1 does not match, dont alert but start timer */
+                                       isdnloop_start_ctimer(card, ch - 1);
+                                       break;
+                               case 1:
+                                       /* Remote busy */
+                                       isdnloop_fake(card, "DDIS_I", ch);
+                                       sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
+                                       isdnloop_fake(card, buf, ch);
+                                       break;
+                               case 2:
+                                       /* No such user */
+                                       isdnloop_fake(card, "DDIS_I", ch);
+                                       sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
+                                       isdnloop_fake(card, buf, ch);
+                                       break;
+                       }
+                       break;
+               case 6:
+                       /* 0x;EAZC */
+                       card->eazlist[ch - 1][0] = '\0';
+                       break;
+               case 7:
+                       /* 0x;EAZ */
+                       p += 3;
+                       strcpy(card->eazlist[ch - 1], p);
+                       break;
+               case 8:
+                       /* 0x;SEEAZ */
+                       sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
+                       isdnloop_fake(card, buf, ch + 1);
+                       break;
+               case 9:
+                       /* 0x;MSN */
+                       break;
+               case 10:
+                       /* 0x;MSNALL */
+                       break;
+               case 11:
+                       /* 0x;SETSIL */
+                       p += 6;
+                       i = 0;
+                       while (strchr("0157", *p)) {
+                               if (i)
+                                       card->sil[ch - 1] |= si2bit[*p - '0'];
+                               i = (*p++ == '0');
+                       }
+                       if (*p)
+                               isdnloop_fake_err(card);
+                       break;
+               case 12:
+                       /* 0x;SEESIL */
+                       sprintf(buf, "SIN-LIST: ");
+                       p = buf + 10;
+                       for (i = 0; i < 3; i++)
+                               if (card->sil[ch - 1] & (1 << i))
+                                       p += sprintf(p, "%02d", bit2si[i]);
+                       isdnloop_fake(card, buf, ch + 1);
+                       break;
+               case 13:
+                       /* 0x;SILC */
+                       card->sil[ch - 1] = 0;
+                       break;
+               case 14:
+                       /* 00;FV2ON */
+                       break;
+               case 15:
+                       /* 00;FV2OFF */
+                       break;
+       }
+}
+
+/*
+ * Put command-strings into the of the 'card'. In reality, execute them
+ * right in place by calling isdnloop_parse_cmd(). Also copy every
+ * command to the read message ringbuffer, preceeding it with a '>'.
+ * These mesagges can be read at /dev/isdnctrl.
+ *
+ * Parameter:
+ *   buf  = pointer to command buffer.
+ *   len  = length of buffer data.
+ *   user = flag: 1 = called form userlevel, 0 called from kernel.
+ *   card = pointer to card struct.
+ * Return:
+ *   number of bytes transfered (currently always equals len).
+ */
+static int
+isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card)
+{
+       int xcount = 0;
+       int ocount = 1;
+       isdn_ctrl cmd;
+
+       while (len) {
+               int count = MIN(255, len);
+               u_char *p;
+               u_char msg[0x100];
+
+               if (user)
+                       copy_from_user(msg, buf, count);
+               else
+                       memcpy(msg, buf, count);
+               isdnloop_putmsg(card, '>');
+               for (p = msg; count > 0; count--, p++) {
+                       len--;
+                       xcount++;
+                       isdnloop_putmsg(card, *p);
+                       card->omsg[card->optr] = *p;
+                       if (*p == '\n') {
+                               card->omsg[card->optr] = '\0';
+                               card->optr = 0;
+                               isdnloop_parse_cmd(card);
+                               if (len) {
+                                       isdnloop_putmsg(card, '>');
+                                       ocount++;
+                               }
+                       } else {
+                               if (card->optr < 59)
+                                       card->optr++;
+                       }
+                       ocount++;
+               }
+       }
+       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
+isdnloop_stopcard(isdnloop_card * card)
+{
+       unsigned long flags;
+       isdn_ctrl cmd;
+
+       save_flags(flags);
+       cli();
+       if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
+               card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
+               del_timer(&card->st_timer);
+               del_timer(&card->rb_timer);
+               del_timer(&card->c_timer[0]);
+               del_timer(&card->c_timer[1]);
+               cmd.command = ISDN_STAT_STOP;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+       }
+       restore_flags(flags);
+}
+
+/*
+ * Stop all cards before unload.
+ */
+static void
+isdnloop_stopallcards(void)
+{
+       isdnloop_card *p = cards;
+
+       while (p) {
+               isdnloop_stopcard(p);
+               p = p->next;
+       }
+}
+
+/*
+ * Start a 'card'. Simulate card's boot message and set the phone
+ * number(s) of the virtual 'S0-Interface'. Install D-channel
+ * poll timer.
+ *
+ * Parameter:
+ *   card  = pointer to card struct.
+ *   sdefp = pointer to struct holding ioctl parameters.
+ * Return:
+ *   0 on success, -E??? otherwise.
+ */
+static int
+isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
+{
+       unsigned long flags;
+       isdnloop_sdef sdef;
+       int i;
+
+       if (card->flags & ISDNLOOP_FLAGS_RUNNING)
+               return -EBUSY;
+       copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef));
+       save_flags(flags);
+       cli();
+       switch (sdef.ptype) {
+               case ISDN_PTYPE_EURO:
+                       if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
+                                         -1)) {
+                               restore_flags(flags);
+                               return -ENOMEM;
+                       }
+                       card->sil[0] = card->sil[1] = 4;
+                       if (isdnloop_fake(card, "TEI OK", 0)) {
+                               restore_flags(flags);
+                               return -ENOMEM;
+                       }
+                       for (i = 0; i < 3; i++)
+                               strcpy(card->s0num[i], sdef.num[i]);
+                       break;
+               case ISDN_PTYPE_1TR6:
+                       if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
+                                         -1)) {
+                               restore_flags(flags);
+                               return -ENOMEM;
+                       }
+                       card->sil[0] = card->sil[1] = 4;
+                       if (isdnloop_fake(card, "TEI OK", 0)) {
+                               restore_flags(flags);
+                               return -ENOMEM;
+                       }
+                       strcpy(card->s0num[0], sdef.num[0]);
+                       card->s0num[1][0] = '\0';
+                       card->s0num[2][0] = '\0';
+                       break;
+               default:
+                       restore_flags(flags);
+                       printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
+                              sdef.ptype);
+                       return -EINVAL;
+       }
+       init_timer(&card->st_timer);
+       card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
+       card->st_timer.function = isdnloop_polldchan;
+       card->st_timer.data = (unsigned long) card;
+       add_timer(&card->st_timer);
+       card->flags |= ISDNLOOP_FLAGS_RUNNING;
+       restore_flags(flags);
+       return 0;
+}
+
+/*
+ * Main handler for commands sent by linklevel.
+ */
+static int
+isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
+{
+       ulong a;
+       int i;
+       char cbuf[60];
+       isdn_ctrl cmd;
+       isdnloop_cdef cdef;
+
+       switch (c->command) {
+               case ISDN_CMD_IOCTL:
+                       memcpy(&a, c->parm.num, sizeof(ulong));
+                       switch (c->arg) {
+                               case ISDNLOOP_IOCTL_DEBUGVAR:
+                                       return (ulong) card;
+                               case ISDNLOOP_IOCTL_STARTUP:
+                                       if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef))))
+                                               return i;
+                                       return (isdnloop_start(card, (isdnloop_sdef *) a));
+                                       break;
+                               case ISDNLOOP_IOCTL_ADDCARD:
+                                       if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_cdef))))
+                                               return i;
+                                       copy_from_user((char *) &cdef, (char *) a, sizeof(cdef));
+                                       return (isdnloop_addcard(cdef.id1));
+                                       break;
+                               case ISDNLOOP_IOCTL_LEASEDCFG:
+                                       if (a) {
+                                               if (!card->leased) {
+                                                       card->leased = 1;
+                                                       while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+                                                               current->timeout = jiffies + 10;
+                                                               schedule();
+                                                       }
+                                                       current->timeout = jiffies + 10;
+                                                       schedule();
+                                                       sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");
+                                                       i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                                                       printk(KERN_INFO
+                                                              "isdnloop: (%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 = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                                                       printk(KERN_INFO
+                                                              "isdnloop: (%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 & ISDNLOOP_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (card->leased)
+                               break;
+                       if ((c->arg & 255) < ISDNLOOP_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 = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                       }
+                       break;
+               case ISDN_CMD_ACCEPTD:
+                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (c->arg < ISDNLOOP_BCH) {
+                               a = c->arg + 1;
+                               cbuf[0] = 0;
+                               switch (card->l2_proto[a - 1]) {
+                                       case ISDN_PROTO_L2_X75I:
+                                               sprintf(cbuf, "%02d;BX75\n", (int) a);
+                                               break;
+#ifdef CONFIG_ISDN_X25
+                                       case ISDN_PROTO_L2_X25DTE:
+                                               sprintf(cbuf, "%02d;BX2T\n", (int) a);
+                                               break;
+                                       case ISDN_PROTO_L2_X25DCE:
+                                               sprintf(cbuf, "%02d;BX2C\n", (int) a);
+                                               break;
+#endif
+                                       case ISDN_PROTO_L2_HDLC:
+                                               sprintf(cbuf, "%02d;BTRA\n", (int) a);
+                                               break;
+                               }
+                               if (strlen(cbuf))
+                                       i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                               sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+                               i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                       }
+                       break;
+               case ISDN_CMD_ACCEPTB:
+                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (c->arg < ISDNLOOP_BCH) {
+                               a = c->arg + 1;
+                               switch (card->l2_proto[a - 1]) {
+                                       case ISDN_PROTO_L2_X75I:
+                                               sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+                                               break;
+#ifdef CONFIG_ISDN_X25
+                                       case ISDN_PROTO_L2_X25DTE:
+                                               sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);
+                                               break;
+                                       case ISDN_PROTO_L2_X25DCE:
+                                               sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);
+                                               break;
+#endif
+                                       case ISDN_PROTO_L2_HDLC:
+                                               sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+                                               break;
+                                       default:
+                                               sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+                               }
+                               printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);
+                               i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                               break;
+               case ISDN_CMD_HANGUP:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if (c->arg < ISDNLOOP_BCH) {
+                                       a = c->arg + 1;
+                                       sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+                                       i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                               }
+                               break;
+               case ISDN_CMD_SETEAZ:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if (card->leased)
+                                       break;
+                               if (c->arg < ISDNLOOP_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 = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                               }
+                               break;
+               case ISDN_CMD_CLREAZ:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if (card->leased)
+                                       break;
+                               if (c->arg < ISDNLOOP_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 = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                               }
+                               break;
+               case ISDN_CMD_SETL2:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if ((c->arg & 255) < ISDNLOOP_BCH) {
+                                       a = c->arg;
+                                       switch (a >> 8) {
+                                               case ISDN_PROTO_L2_X75I:
+                                                       sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+                                                       break;
+#ifdef CONFIG_ISDN_X25
+                                               case ISDN_PROTO_L2_X25DTE:
+                                                       sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);
+                                                       break;
+                                               case ISDN_PROTO_L2_X25DCE:
+                                                       sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);
+                                                       break;
+#endif
+                                               case ISDN_PROTO_L2_HDLC:
+                                                       sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+                                                       break;
+                                               default:
+                                                       return -EINVAL;
+                                       }
+                                       i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
+                                       card->l2_proto[a & 255] = (a >> 8);
+                               }
+                               break;
+               case ISDN_CMD_GETL2:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if ((c->arg & 255) < ISDNLOOP_BCH)
+                                       return card->l2_proto[c->arg & 255];
+                               else
+                                       return -ENODEV;
+               case ISDN_CMD_SETL3:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               return 0;
+               case ISDN_CMD_GETL3:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               if ((c->arg & 255) < ISDNLOOP_BCH)
+                                       return ISDN_PROTO_L3_TRANS;
+                               else
+                                       return -ENODEV;
+               case ISDN_CMD_GETEAZ:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               break;
+               case ISDN_CMD_SETSIL:
+                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                                       return -ENODEV;
+                               break;
+               case ISDN_CMD_GETSIL:
+                               if (!card->flags & ISDNLOOP_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 isdnloop_card *
+isdnloop_findcard(int driverid)
+{
+       isdnloop_card *p = cards;
+
+       while (p) {
+               if (p->myid == driverid)
+                       return p;
+               p = p->next;
+       }
+       return (isdnloop_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+       isdnloop_card *card = isdnloop_findcard(c->driver);
+
+       if (card)
+               return (isdnloop_command(c, card));
+       printk(KERN_ERR
+              "isdnloop: if_command called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+       isdnloop_card *card = isdnloop_findcard(id);
+
+       if (card) {
+               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       return -ENODEV;
+               return (isdnloop_writecmd(buf, len, user, card));
+       }
+       printk(KERN_ERR
+              "isdnloop: if_writecmd called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+       isdnloop_card *card = isdnloop_findcard(id);
+
+       if (card) {
+               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       return -ENODEV;
+               return (isdnloop_readstatus(buf, len, user, card));
+       }
+       printk(KERN_ERR
+              "isdnloop: if_readstatus called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+       isdnloop_card *card = isdnloop_findcard(id);
+
+       if (card) {
+               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       return -ENODEV;
+               /* ack request stored in skb scratch area */
+               *(skb->head) = ack;
+               return (isdnloop_sendbuf(channel, skb, card));
+       }
+       printk(KERN_ERR
+              "isdnloop: 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 isdnloop_card *
+isdnloop_initcard(char *id)
+{
+       isdnloop_card *card;
+       int i;
+
+       if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
+               printk(KERN_WARNING
+                "isdnloop: (%s) Could not allocate card-struct.\n", id);
+               return (isdnloop_card *) 0;
+       }
+       memset((char *) card, 0, sizeof(isdnloop_card));
+       card->interface.channels = ISDNLOOP_BCH;
+       card->interface.hl_hdrlen  = 1; /* scratch area for storing ack flag*/ 
+       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 |
+#ifdef CONFIG_ISDN_X25
+           ISDN_FEATURE_L2_X25DTE |
+           ISDN_FEATURE_L2_X25DCE |
+#endif
+           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 < ISDNLOOP_BCH; i++) {
+               card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+               skb_queue_head_init(&card->bqueue[i]);
+       }
+       skb_queue_head_init(&card->dqueue);
+       card->next = cards;
+       cards = card;
+       if (!register_isdn(&card->interface)) {
+               cards = cards->next;
+               printk(KERN_WARNING
+                      "isdnloop: Unable to register %s\n", id);
+               kfree(card);
+               return (isdnloop_card *) 0;
+       }
+       card->myid = card->interface.channels;
+       return card;
+}
+
+static int
+isdnloop_addcard(char *id1)
+{
+       ulong flags;
+       isdnloop_card *card;
+
+       save_flags(flags);
+       cli();
+       if (!(card = isdnloop_initcard(id1))) {
+               restore_flags(flags);
+               return -EIO;
+       }
+       restore_flags(flags);
+       printk(KERN_INFO
+              "isdnloop: (%s) virtual card added\n",
+              card->interface.id);
+       return 0;
+}
+
+#ifdef MODULE
+#define isdnloop_init init_module
+#else
+void
+isdnloop_setup(char *str, int *ints)
+{
+       static char sid[20];
+
+       if (strlen(str)) {
+               strcpy(sid, str);
+               isdnloop_id = sid;
+       }
+}
+#endif
+
+int
+isdnloop_init(void)
+{
+       char *p;
+       char rev[10];
+
+       /* No symbols to export, hide all symbols */
+       EXPORT_NO_SYMBOLS;
+
+       if ((p = strchr(revision, ':'))) {
+               strcpy(rev, p + 1);
+               p = strchr(rev, '$');
+               *p = 0;
+       } else
+               strcpy(rev, " ??? ");
+       printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
+       return (isdnloop_addcard(isdnloop_id));
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+       isdn_ctrl cmd;
+       isdnloop_card *card = cards;
+       isdnloop_card *last;
+       int i;
+
+       isdnloop_stopallcards();
+       while (card) {
+               cmd.command = ISDN_STAT_UNLOAD;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               for (i = 0; i < ISDNLOOP_BCH; i++)
+                       isdnloop_free_queue(card, i);
+               card = card->next;
+       }
+       card = cards;
+       while (card) {
+               struct sk_buff *skb;
+
+               last = card;
+               while ((skb = skb_dequeue(&card->dqueue)))
+                       dev_kfree_skb(skb);
+               card = card->next;
+               kfree(last);
+       }
+       printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
+}
+#endif
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
new file mode 100644 (file)
index 0000000..2eb8d25
--- /dev/null
@@ -0,0 +1,145 @@
+/* $Id: isdnloop.h,v 1.2 1997/10/01 09:22:07 fritz Exp $
+
+ * Loopback lowlevel module for testing of linklevel.
+ *
+ * Copyright 1997 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)
+ * 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: isdnloop.h,v $
+ * Revision 1.2  1997/10/01 09:22:07  fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.1  1997/03/24 23:02:05  fritz
+ * Added isdnloop driver.
+ *
+ */
+
+#ifndef isdnloop_h
+#define isdnloop_h
+
+#define ISDNLOOP_IOCTL_DEBUGVAR  0
+#define ISDNLOOP_IOCTL_ADDCARD   1
+#define ISDNLOOP_IOCTL_LEASEDCFG 2
+#define ISDNLOOP_IOCTL_STARTUP   3
+
+/* Struct for adding new cards */
+typedef struct isdnloop_cdef {
+       char id1[10];
+} isdnloop_cdef;
+
+/* Struct for configuring cards */
+typedef struct isdnloop_sdef {
+       int ptype;
+       char num[3][20];
+} isdnloop_sdef;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/config.h>
+#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/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>
+
+#endif                          /* __KERNEL__ */
+
+#define ISDNLOOP_FLAGS_B1ACTIVE 1      /* B-Channel-1 is open           */
+#define ISDNLOOP_FLAGS_B2ACTIVE 2      /* B-Channel-2 is open           */
+#define ISDNLOOP_FLAGS_RUNNING  4      /* Cards driver activated        */
+#define ISDNLOOP_FLAGS_RBTIMER  8      /* scheduling of B-Channel-poll  */
+#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle          */
+#define ISDNLOOP_TIMER_DCREAD (HZ/2)   /* D-Channel poll-cycle          */
+#define ISDNLOOP_TIMER_ALERTWAIT (10*HZ)       /* Alert timeout                 */
+#define ISDNLOOP_MAX_SQUEUE 65536      /* Max. outstanding send-data    */
+#define ISDNLOOP_BCH 2          /* channels per card             */
+
+/*
+ * Per card driver data
+ */
+typedef struct isdnloop_card {
+       struct isdnloop_card *next;     /* Pointer to next device struct    */
+       struct isdnloop_card
+       *rcard[ISDNLOOP_BCH];   /* Pointer to 'remote' card         */
+       int rch[ISDNLOOP_BCH];  /* 'remote' channel                 */
+       int myid;               /* Driver-Nr. assigned by linklevel */
+       int leased;             /* Flag: This Adapter is connected  */
+       /*       to a leased line           */
+       int sil[ISDNLOOP_BCH];  /* SI's to listen for               */
+       char eazlist[ISDNLOOP_BCH][11];
+       /* EAZ's to listen for              */
+       char s0num[3][20];      /* 1TR6 base-number or MSN's        */
+       unsigned short flags;   /* Statusflags                      */
+       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        */
+       struct timer_list
+        c_timer[ISDNLOOP_BCH]; /* Timer for Alerting               */
+       int l2_proto[ISDNLOOP_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  */
+       int optr;               /* Index to omsg-buffer             */
+       char omsg[60];          /* Internal buf for cmd-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[ISDNLOOP_BCH];     /* Byte-counters for B-Ch.-send     */
+       struct sk_buff_head
+        bqueue[ISDNLOOP_BCH];  /* B-Channel queues                 */
+       struct sk_buff_head dqueue;     /* D-Channel queue                  */
+} isdnloop_card;
+
+/*
+ * Main driver data
+ */
+#ifdef __KERNEL__
+static isdnloop_card *cards = (isdnloop_card *) 0;
+static char *isdnloop_id = "\0";
+
+#ifdef MODULE
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_PARM(isdnloop_id, "s");
+MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
+#endif
+
+#endif                          /* __KERNEL__ */
+
+/* Utility-Macros */
+
+#define CID (card->interface.id)
+#define MIN(a,b) ((a<b)?a:b)
+#define MAX(a,b) ((a>b)?a:b)
+
+#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif                          /* isdnloop_h */
index 790da879248db88f3364aeaae54046a8cb3441c7..ed681f375547f19d23b589287e6c574498596296 100644 (file)
@@ -147,9 +147,6 @@ int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
-
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
         *(skb_put(*skb, 1)) = 0x01;  /* ACCEPT_CALL */
         *(skb_put(*skb, 1)) = 0;
@@ -170,8 +167,6 @@ int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
 #ifdef DEBUG
@@ -200,8 +195,6 @@ int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
         return 2;
@@ -222,8 +215,6 @@ int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-  
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
         /* Layer2 protocol */
@@ -285,8 +276,6 @@ int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
         
@@ -338,8 +327,6 @@ int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2) ) = chan->callref;  
 
         *(skb_put(*skb, 1)) = chan->layer2link;
@@ -357,8 +344,6 @@ int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2) ) = callref;  
 
         *(skb_put(*skb, 1)) = 2;                  /* Cause.Length = 2; */
@@ -382,8 +367,6 @@ int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
                return -1;
        }
 
-        SET_SKB_FREE((*skb));
-
         *((ushort*) skb_put(*skb, 2)) = chan->callref;  
 
         return 2;
index cacb714bee82262f799aaac8ecabd662ca04be5f..43c36fa9ee2c7abfd96cca886c2858684f5f50ed 100644 (file)
@@ -61,7 +61,7 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = {
 
 int pcbit_command(isdn_ctrl* ctl);
 int pcbit_stat(u_char* buf, int len, int user, int, int);
-int pcbit_xmit(int driver, int chan, struct sk_buff *skb);
+int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
 int pcbit_writecmd(const u_char*, int, int, int, int);
 
 static int set_protocol_running(struct pcbit_dev * dev);
@@ -164,7 +164,6 @@ int pcbit_init_dev(int board, int mem_base, int irq)
                            ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );
 
        dev_if->writebuf_skb = pcbit_xmit;
-       dev_if->writebuf  = NULL;
        dev_if->hl_hdrlen = 10;
 
        dev_if->maxbufsize = MAXBUFSIZE;
@@ -330,7 +329,7 @@ static void pcbit_block_timer(unsigned long data)
 }
 #endif
 
-int pcbit_xmit(int driver, int chnum, struct sk_buff *skb)
+int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
 {
        ushort hdrlen;
        int refnum, len;
@@ -731,8 +730,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
 #endif
        }
 
-       SET_SKB_FREE(skb);
-
        kfree_skb(skb);
 
 }
index 0ccb2b7c90a71fd7eb9d563b3eed22195318010b..8283b7367033781131c4a9d1a7a0298722efc4fe 100644 (file)
@@ -380,10 +380,8 @@ pcbit_receive(struct pcbit_dev *dev)
                        return;
 #else
                        /* discard previous queued frame */
-                       if (dev->read_frame->skb) {
-                               SET_SKB_FREE(dev->read_frame->skb);
+                       if (dev->read_frame->skb)
                                kfree_skb(dev->read_frame->skb);
-                       }
                        kfree(dev->read_frame);
                        dev->read_frame = NULL;
 #endif
@@ -648,10 +646,8 @@ pcbit_l2_err_recover(unsigned long data)
        dev->w_busy = dev->r_busy = 1;
 
        if (dev->read_frame) {
-               if (dev->read_frame->skb) {
-                       SET_SKB_FREE(dev->read_frame->skb);
+               if (dev->read_frame->skb)
                        kfree_skb(dev->read_frame->skb);
-               }
                kfree(dev->read_frame);
                dev->read_frame = NULL;
        }
index 34f8fc1c54e604bc1bfe7c65c51a8f84f0bf9360..33aee3360eb3ca8416d0f82df59c4e860ce06e9f 100644 (file)
@@ -35,10 +35,8 @@ 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
 
@@ -87,11 +85,7 @@ 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;
 }
index 3a814de931bb9e2b7c11671adc83af4a92bdf553..c5312cd83e63e0532d760256fc797e62dac4999f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: debug.c,v 1.2 1996/11/20 17:49:50 fritz Exp $
+ *  $Id: debug.c,v 1.3 1997/10/01 09:22:20 fritz Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
 
 #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
+#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+#define FREE_IRQ(a,b) free_irq(a,b)
 
 inline char *strcpy(char *, const char *);
 
index 3452cbf36361cde2b2e8a77d5e1e389f3cc68077..23cd53f07f37ad0f0d7ffb5ec500eddbecfbc54d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: event.c,v 1.3 1997/02/11 22:53:41 fritz Exp $
+ *  $Id: event.c,v 1.4 1997/10/09 22:30:58 fritz Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -62,10 +62,16 @@ int indicate_status(int card, int event,ulong Channel,char *Data)
        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);
+               switch (event) {
+                       case ISDN_STAT_BSENT:
+                               memcpy(&cmd.parm.length, Data, sizeof(cmd.parm.length));
+                               break;
+                       case ISDN_STAT_ICALL:
+                               memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
+                               break;
+                       default:
+                               strcpy(cmd.parm.num, Data);
+               }
        }
 
        cmd.command = event;
index 4a769822567b2c5bcfccb3f83ebd26e6e3808805..b0f07ac3c9cda1cc8b4a7f51fe6b6fcda98d6526 100644 (file)
                                           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 */
index c9eb24035e658aca69b2b98d3e32a5144bbe69a8..d34dd03b9f8838439459cad4750cb7f112a5db00 100644 (file)
@@ -20,7 +20,7 @@ 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 sndpkt(int, int, int, struct sk_buff *);
 extern int command(isdn_ctrl *);
 extern int indicate_status(int, int, ulong, char*);
 extern int reset(int);
@@ -38,12 +38,10 @@ int irq_supported(int irq_x)
 }
 
 #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
 /*
index 6b5b369e363b6d4bbbbb10fa6e4aa1fd175cc1ac..25964752ba6956b07a1aa8df292f503e9e8b3793 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: interrupt.c,v 1.3 1997/02/11 22:53:43 fritz Exp $
+ *  $Id: interrupt.c,v 1.4 1998/01/31 22:10:52 keil Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
index e104fada64662a8c0fb659265fb9409a385dce42..2cbdcdae895edcc3bb82698abce490a47aae390e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: message.c,v 1.2 1996/11/20 17:49:54 fritz Exp $
+ *  $Id: message.c,v 1.3 1998/01/31 22:10:55 keil Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  message.c - functions for sending and receiving control messages
@@ -33,7 +33,6 @@
 #include "hardware.h"
 #include "message.h"
 #include "card.h"
-#include <asm/io.h>
 
 extern board *adapter[];
 extern unsigned int cinst;
@@ -203,7 +202,7 @@ int sendmessage(int card,
         * wait for an empty slot in the queue
         */
        while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
-               __SLOW_DOWN_IO;
+               udelay(1);
 
        /*
         * Disable interrupts and map in shared memory
index 563d1821db1518ece402c6d681d8cb5ff9c08e98..d75cb04d7f7b4fb43d11a57a68b1e50470d4ce7e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: packet.c,v 1.2 1996/11/20 17:49:55 fritz Exp $
+ *  $Id: packet.c,v 1.4 1998/02/12 23:08:50 keil Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@ extern board *adapter[];
 extern unsigned int cinst;
 
 extern int get_card_from_id(int);
-extern int indicate_status(int, int,ulong,char*);
+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,
@@ -47,6 +47,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
        LLData  ReqLnkWrite;
        int status;
        int card;
+       unsigned long len;
 
        card = get_card_from_id(devId);
 
@@ -89,6 +90,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
 
        status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
                                channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
+       len = data->len;
        if(status) {
                pr_debug("%s: Failed to send packet, status = %d\n", adapter[card]->devicename, status);
                return -1;
@@ -101,9 +103,9 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
                        adapter[card]->channel[channel].next_sendbuf;
                        pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename);
                dev_kfree_skb(data);
-               indicate_status(card,ISDN_STAT_BSENT,channel,NULL);
+               indicate_status(card,ISDN_STAT_BSENT,channel, (char *)&len);
        }
-       return data->len;
+       return len;
 }
 
 void rcvpkt(int card, RspMessage *rcvmsg)
index bd542b4fd7619314bf9d590a541f317cdaec62ba..012542b09446c23b47fad87f97487c6c3a8f68b8 100644 (file)
@@ -482,8 +482,9 @@ static int parport_SPP_supported(struct parport *pb)
  */
 static int parport_ECR_present(struct parport *pb)
 {
-       unsigned char r, octr = parport_pc_read_control(pb), 
-         oecr = parport_pc_read_econtrol(pb);
+       unsigned char r, octr = parport_pc_read_control(pb);
+       unsigned char oecr = parport_pc_read_econtrol(pb);
+       unsigned char tmp;
 
        r = parport_pc_read_control(pb);        
        if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
@@ -500,12 +501,14 @@ static int parport_ECR_present(struct parport *pb)
                return 0;
 
        parport_pc_write_econtrol(pb, 0x34);
-       if (parport_pc_read_econtrol(pb) != 0x35)
-               return 0;
+       tmp = parport_pc_read_econtrol(pb);
 
        parport_pc_write_econtrol(pb, oecr);
        parport_pc_write_control(pb, octr);
        
+       if (tmp != 0x35)
+               return 0;
+
        return PARPORT_MODE_PCECR;
 }
 
@@ -735,6 +738,7 @@ static int irq_probe_EPP(struct parport *pb)
 {
        int irqs;
        unsigned char octr = parport_pc_read_control(pb);
+       unsigned char oecr = parport_pc_read_econtrol(pb);
 
 #ifndef ADVANCED_DETECT
        return PARPORT_IRQ_NONE;
@@ -758,6 +762,7 @@ static int irq_probe_EPP(struct parport *pb)
        udelay(20);
 
        pb->irq = close_intr_election(irqs);
+       parport_pc_write_econtrol(pb, oecr);
        parport_pc_write_control(pb, octr);
        return pb->irq;
 }
@@ -766,6 +771,7 @@ static int irq_probe_SPP(struct parport *pb)
 {
        int irqs;
        unsigned char octr = parport_pc_read_control(pb);
+       unsigned char oecr = parport_pc_read_econtrol(pb);
 
 #ifndef ADVANCED_DETECT
        return PARPORT_IRQ_NONE;
@@ -794,6 +800,7 @@ static int irq_probe_SPP(struct parport *pb)
        if (pb->irq <= 0)
                pb->irq = PARPORT_IRQ_NONE;     /* No interrupt detected */
        
+       parport_pc_write_econtrol(pb, oecr);
        parport_pc_write_control(pb, octr);
        return pb->irq;
 }
@@ -815,7 +822,7 @@ static int parport_irq_probe(struct parport *pb)
                        
        if (pb->irq == PARPORT_IRQ_NONE && 
            (pb->modes & PARPORT_MODE_PCECPEPP)) {
-               int oecr = parport_pc_read_econtrol(pb);
+               unsigned char oecr = parport_pc_read_econtrol(pb);
                parport_pc_write_econtrol(pb, 0x80);
                pb->irq = irq_probe_EPP(pb);
                parport_pc_write_econtrol(pb, oecr);
index 7a4ceca36b6f894667533c501d1afcb727121333..79d6d8076853ab04e516792eb75beb71afa43908 100644 (file)
@@ -306,9 +306,9 @@ static int ultramca_close_card(struct device *dev)
 
 #define MAX_ULTRAMCA_CARDS  4   /* Max number of Ultra cards per module */
 #define NAMELEN     8   /* # of chars for storing dev->name */
-static char namelist[NAMELEN * MAX_ULTRA_CARDS] = { 0, };
+static char namelist[NAMELEN * MAX_ULTRAMCA_CARDS] = { 0, };
 
-static struct device dev_ultra[MAX_ULTRA_CARDS] =
+static struct device dev_ultra[MAX_ULTRAMCA_CARDS] =
 {
        {
                NULL,       /* assign a chunk of namelist[] below */
@@ -318,11 +318,11 @@ static struct device dev_ultra[MAX_ULTRA_CARDS] =
        },
 };
 
-static int io[MAX_ULTRA_CARDS] = { 0, };
-static int irq[MAX_ULTRA_CARDS]  = { 0, };
+static int io[MAX_ULTRAMCA_CARDS] = { 0, };
+static int irq[MAX_ULTRAMCA_CARDS]  = { 0, };
 
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -331,7 +331,7 @@ int init_module(void)
 {
        int this_dev, found = 0;
 
-       for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++)
+       for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++)
        {
                struct device *dev = &dev_ultra[this_dev];
                dev->name = namelist+(NAMELEN*this_dev);
@@ -360,7 +360,7 @@ void cleanup_module(void)
 {
        int this_dev;
 
-       for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++)
+       for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++)
        {
                struct device *dev = &dev_ultra[this_dev];
                if (dev->priv != NULL)
index 1d14136fb40cd52a6562240483c8cd91b4ef11ae..b5d76f7e52f4e84e65cdcaef4cf9d952ffb2a7df 100644 (file)
@@ -28,6 +28,8 @@
 #include <scsi/scsi_ioctl.h>
 #include <scsi/sg.h>
 
+int sg_big_buff = SG_BIG_BUFF;         /* for now, sg_big_buff is read-only through sysctl */
+
 static int sg_init(void);
 static int sg_attach(Scsi_Device *);
 static int sg_detect(Scsi_Device *);
index be58c11eddf6cc1d4e8b2fe574c77850075ff017..7da69373229dcf0efae9cd22a14eb36073b15355 100644 (file)
@@ -362,8 +362,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
 
        current->mm->rss = 0;
        current->mm->mmap = NULL;
-       current->suid = current->euid = current->fsuid = bprm->e_uid;
-       current->sgid = current->egid = current->fsgid = bprm->e_gid;
+       compute_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
 #ifdef __sparc__
        if (N_MAGIC(ex) == NMAGIC) {
index 50f071faf46d4229dea6769ec00f18540ad36ede..ff4f5971086d684a4d1422b6de0f209cb7526cd3 100644 (file)
@@ -705,8 +705,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 #ifndef VM_STACK_FLAGS
        current->executable = dget(bprm->dentry);
 #endif
-       current->suid = current->euid = current->fsuid = bprm->e_uid;
-       current->sgid = current->egid = current->fsgid = bprm->e_gid;
+       compute_creds(bprm);
        current->flags &= ~PF_FORKNOEXEC;
        bprm->p = (unsigned long)
          create_elf_tables((char *)bprm->p,
index 1d58146ae2a59b816c99f7faca2c83760b3755b8..9aefbe8f3ae0f2da9680d69643265a3829e6b21e 100644 (file)
@@ -1141,6 +1141,9 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
        return NULL;
 }
 
+/*
+ * Note: the caller should wake up the buffer_wait list if needed.
+ */
 static void put_unused_buffer_head(struct buffer_head * bh)
 {
        if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
@@ -1153,9 +1156,6 @@ static void put_unused_buffer_head(struct buffer_head * bh)
        nr_unused_buffer_heads++;
        bh->b_next_free = unused_list;
        unused_list = bh;
-       if (!waitqueue_active(&buffer_wait))
-               return;
-       wake_up(&buffer_wait);
 }
 
 /* 
@@ -1165,18 +1165,26 @@ static void put_unused_buffer_head(struct buffer_head * bh)
  * fields after the final unlock.  So, the device driver puts them on
  * the reuse_list instead once IO completes, and we recover these to
  * the unused_list here.
+ *
+ * Note that we don't do a wakeup here, but return a flag indicating
+ * whether we got any buffer heads. A task ready to sleep can check
+ * the returned value, and any tasks already sleeping will have been
+ * awakened when the buffer heads were added to the reuse list.
  */
-static inline void recover_reusable_buffer_heads(void)
+static inline int recover_reusable_buffer_heads(void)
 {
-       struct buffer_head *head;
-
-       head = xchg(&reuse_list, NULL);
+       struct buffer_head *head = xchg(&reuse_list, NULL);
+       int found = 0;
        
-       while (head) {
-               struct buffer_head *bh = head;
-               head = head->b_next_free;
-               put_unused_buffer_head(bh);
+       if (head) {
+               do {
+                       struct buffer_head *bh = head;
+                       head = head->b_next_free;
+                       put_unused_buffer_head(bh);
+               } while (head);
+               found = 1;
        }
+       return found;
 }
 
 /*
@@ -1275,11 +1283,15 @@ try_again:
  * In case anything failed, we just free everything we got.
  */
 no_grow:
-       bh = head;
-       while (bh) {
-               head = bh;
-               bh = bh->b_this_page;
-               put_unused_buffer_head(head);
+       if (head) {
+               do {
+                       bh = head;
+                       head = head->b_this_page;
+                       put_unused_buffer_head(bh);
+               } while (head);
+
+               /* Wake up any waiters ... */
+               wake_up(&buffer_wait);
        }
 
        /*
@@ -1305,8 +1317,8 @@ no_grow:
         */
        add_wait_queue(&buffer_wait, &wait);
        current->state = TASK_UNINTERRUPTIBLE;
-       recover_reusable_buffer_heads();
-       schedule();
+       if (!recover_reusable_buffer_heads())
+               schedule();
        remove_wait_queue(&buffer_wait, &wait);
        current->state = TASK_RUNNING;
        goto try_again;
@@ -1333,14 +1345,24 @@ static inline void after_unlock_page (struct page * page)
  */
 static inline void free_async_buffers (struct buffer_head * bh)
 {
-       struct buffer_head * tmp;
+       struct buffer_head *tmp, *tail;
 
-       tmp = bh;
-       do {
-               tmp->b_next_free = xchg(&reuse_list, NULL);
-               reuse_list = tmp;
-               tmp = tmp->b_this_page;
-       } while (tmp != bh);
+       /*
+        * Link all the buffers into the b_next_free list,
+        * so we only have to do one xchg() operation ...
+        */
+       tail = bh;
+       while ((tmp = tail->b_this_page) != bh) {
+               tail->b_next_free = tmp;
+               tail = tmp;
+       };
+
+       /* Update the reuse list */
+       tail->b_next_free = xchg(&reuse_list, NULL);
+       reuse_list = bh;
+
+       /* Wake up any waiters ... */
+       wake_up(&buffer_wait);
 }
 
 static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
@@ -1390,7 +1412,6 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
        clear_bit(PG_locked, &page->flags);
        wake_up(&page->wait);
        after_unlock_page(page);
-       wake_up(&buffer_wait);
        return;
 
 still_busy:
@@ -1636,6 +1657,7 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
                        return 0;
                tmp = tmp->b_this_page;
        } while (tmp != bh);
+
        tmp = bh;
        do {
                p = tmp;
@@ -1649,6 +1671,9 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
                remove_from_queues(p);
                put_unused_buffer_head(p);
        } while (tmp != bh);
+       /* Wake up anyone waiting for buffer heads */
+       wake_up(&buffer_wait);
+
        buffermem -= PAGE_SIZE;
        mem_map[MAP_NR(page)].buffers = NULL;
        free_page(page);
index 28cc277f5bfde9cdb16d639f1d48aa884f2e4743..801db79fb6a691612ecb7f6839b253e01862e9aa 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 
+#include <asm/uaccess.h>
+
 #define DCACHE_PARANOIA 1
 /* #define DCACHE_DEBUG 1 */
 
@@ -669,7 +671,7 @@ void d_add(struct dentry * entry, struct inode * inode)
        d_instantiate(entry, inode);
 }
 
-#define switch(x,y) do { \
+#define do_switch(x,y) do { \
        __typeof__ (x) __tmp = x; \
        x = y; y = __tmp; } while (0)
 
@@ -705,10 +707,10 @@ void d_move(struct dentry * dentry, struct dentry * target)
        list_del(&target->d_child);
 
        /* Switch the parents and the names.. */
-       switch(dentry->d_parent, target->d_parent);
-       switch(dentry->d_name.name, target->d_name.name);
-       switch(dentry->d_name.len, target->d_name.len);
-       switch(dentry->d_name.hash, target->d_name.hash);
+       do_switch(dentry->d_parent, target->d_parent);
+       do_switch(dentry->d_name.name, target->d_name.name);
+       do_switch(dentry->d_name.len, target->d_name.len);
+       do_switch(dentry->d_name.hash, target->d_name.hash);
        list_add(&target->d_child, &target->d_parent->d_subdirs);
        list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
 }
@@ -757,6 +759,41 @@ char * d_path(struct dentry *dentry, char *buffer, int buflen)
        return retval;
 }
 
+/*
+ * NOTE! The user-level library version returns a
+ * character pointer. The kernel system call just
+ * returns the length of the buffer filled (which
+ * includes the ending '\0' character), or a negative
+ * error value. So libc would do something like
+ *
+ *     char *getcwd(char * buf, size_t size)
+ *     {
+ *             int retval;
+ *
+ *             retval = sys_getcwd(buf, size);
+ *             if (retval >= 0)
+ *                     return buf;
+ *             errno = -retval;
+ *             return NULL;
+ *     }
+ */
+asmlinkage int sys_getcwd(char *buf, unsigned long size)
+{
+       int error;
+       unsigned long len;
+       char * page = (char *) __get_free_page(GFP_USER);
+       char * cwd = d_path(current->fs->pwd, page, PAGE_SIZE);
+
+       error = -ERANGE;
+       len = PAGE_SIZE + page - cwd;
+       if (len <= size) {
+               error = len;
+               if (copy_to_user(buf, cwd, len))
+                       error = -EFAULT;
+       }
+       return error;
+}
+
 /*
  * Test whether new_dentry is a subdirectory of old_dentry.
  *
index dfdd96826ee5428a61a46483865f26cb00027a0b..835e4e9fdb991418d278e638e195bbe4e3bfedae 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -605,6 +605,45 @@ int prepare_binprm(struct linux_binprm *bprm)
                        id_change = 1;
        }
 
+       /* We don't have VFS support for capabilities yet */
+       cap_clear(bprm->cap_inheritable);
+       cap_clear(bprm->cap_permitted);
+       cap_clear(bprm->cap_effective);
+
+       /*  To support inheritance of root-permissions and suid-root
+         *  executables under compatibility mode, we raise the
+         *  effective and inherited bitmasks of the executable file
+         *  (translation: we set the executable "capability dumb" and
+         *  set the allowed set to maximum). We don't set any forced
+         *  bits.
+         *
+         *  If only the real uid is 0, we only raise the inheritable
+         *  bitmask of the executable file (translation: we set the
+         *  allowed set to maximum and the application to "capability
+         *  smart"). 
+         */
+
+       if (!issecure(SECURE_NOROOT)) {
+               if (bprm->e_uid == 0 || current->uid == 0)
+                       cap_set_full(bprm->cap_inheritable);
+               if (bprm->e_uid == 0) 
+                       cap_set_full(bprm->cap_effective);
+       }
+
+        /* We use a conservative definition of suid for capabilities.
+         * The process is suid if the permitted set is not a subset of
+         * the current permitted set after the exec call.
+         *         new permitted set = forced | (allowed & inherited)
+         *                       pP' = fP     | (fI      & pI)
+         */
+
+        if ((bprm->cap_permitted.cap |
+            (current->cap_inheritable.cap &
+             bprm->cap_inheritable.cap)) &
+           ~current->cap_permitted.cap) {
+               id_change = 1;
+       }
+
        if (id_change) {
                /* We can't suid-execute if we're sharing parts of the executable */
                /* or if we're being traced (or if suid execs are not allowed)    */
@@ -623,6 +662,45 @@ int prepare_binprm(struct linux_binprm *bprm)
        return read_exec(bprm->dentry,0,bprm->buf,128,1);
 }
 
+/*
+ * This function is used to produce the new IDs and capabilities
+ * from the old ones and the file's capabilities.
+ *
+ * The formula used for evolving capabilities is:
+ *
+ *       pI' = pI
+ *       pP' = fP | (fI & pI)
+ *       pE' = pP' & fE          [NB. fE is 0 or ~0]
+ *
+ * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
+ * ' indicates post-exec().
+ */
+
+void compute_creds(struct linux_binprm *bprm) 
+{
+       int new_permitted = bprm->cap_permitted.cap |
+               (bprm->cap_inheritable.cap & current->cap_inheritable.cap);
+
+       current->cap_permitted.cap = new_permitted;
+       current->cap_effective.cap = new_permitted & bprm->cap_effective.cap;
+       
+        /* XXX - Audit candidate */
+        if (!cap_isclear(current->cap_effective)) {
+                printk(KERN_NOTICE
+                      "raising capabilities on `%s'(pid=%d) [%04x]:%lu\n",
+                      current->comm, current->pid,
+                      kdev_t_to_nr(bprm->dentry->d_inode->i_dev), 
+                      bprm->dentry->d_inode->i_ino);
+        }
+       
+        current->suid = current->euid = current->fsuid = bprm->e_uid;
+        current->sgid = current->egid = current->fsgid = bprm->e_gid;
+        if (current->euid != current->uid || current->egid != current->gid ||
+           !cap_isclear(current->cap_permitted))
+                current->dumpable = 0;
+}
+
+
 void remove_arg_zero(struct linux_binprm *bprm)
 {
        if (bprm->argc) {
index f752229ce6aba194a6034b8c757090982cacb455..8280d07365089292eb6acb9ae81b66a12988be39 100644 (file)
@@ -648,7 +648,7 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
             (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
            (inode->u.ext2_i.i_flags &
             (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
-               if (securelevel > 0 || !fsuser())
+               if (!fsuser())
                        goto out;
        } else if ((current->fsuid != inode->i_uid) && !fsuser())
                goto out;
index c0514c01e14e7202ea709b9cd83eabae4e8fd0d4..4ba722b8540bd84925708aedbceefc1c3f98f777 100644 (file)
@@ -37,7 +37,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                    (inode->u.ext2_i.i_flags &
                     (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
                        /* This test looks nicer. Thanks to Pauline Middelink */
-                       if (!fsuser() || securelevel > 0)
+                       if (!fsuser())
                                return -EPERM;
                } else
                        if ((current->fsuid != inode->i_uid) && !fsuser())
index ab9948a62c9153247b718487f77cb94d8bd575e7..04da4f4126ca2a79a851f4e869a80292b438abc9 100644 (file)
@@ -50,7 +50,7 @@ struct inode_operations proc_fd_inode_operations = {
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       proc_permission         /* permission */
 };
 
 /*
index 16ee84225581049dcd9b4451645a0f971ea2f27d..53ac522cb93552c5acb54af28e452227a7eeb7a9 100644 (file)
@@ -129,6 +129,108 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
        return 1;
 }
 
+/*
+ * The standard rules, copied from fs/namei.c:permission().
+ */
+static int standard_permission(struct inode *inode, int mask)
+{
+       int mode = inode->i_mode;
+
+       if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+           (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+               return -EROFS; /* Nobody gets write access to a read-only fs */
+       else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+               return -EACCES; /* Nobody gets write access to an immutable file */
+       else if (current->fsuid == inode->i_uid)
+               mode >>= 6;
+       else if (in_group_p(inode->i_gid))
+               mode >>= 3;
+       if (((mode & mask & 0007) == mask) || fsuser())
+               return 0;
+       return -EACCES;
+}
+
+/* 
+ * Set up permission rules for processes looking at other processes.
+ * You're not allowed to see a process unless it has the same or more
+ * restricted root than your own.  This prevents a chrooted processes
+ * from escaping through the /proc entries of less restricted
+ * processes, and thus allows /proc to be safely mounted in a chrooted
+ * area.
+ *
+ * Note that root (uid 0) doesn't get permission for this either,
+ * since chroot is stronger than root.
+ *
+ * XXX TODO: use the dentry mechanism to make off-limits procs simply
+ * invisible rather than denied?  Does each namespace root get its own
+ * dentry tree?
+ *
+ * This also applies the default permissions checks, as it only adds
+ * restrictions.
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au>
+ */
+int proc_permission(struct inode *inode, int mask)
+{
+       struct task_struct *p;
+       unsigned long ino = inode->i_ino;
+       unsigned long pid;
+       struct dentry *de, *base;
+
+       if (standard_permission(inode, mask) != 0)
+               return -EACCES;
+
+       /* 
+        * Find the root of the processes being examined (if any).
+        * XXX Surely there's a better way of doing this?
+        */
+       if (ino >= PROC_OPENPROM_FIRST && 
+           ino <  PROC_OPENPROM_FIRST + PROC_NOPENPROM)
+               return 0;               /* already allowed */
+
+       pid = ino >> 16;
+       if (pid == 0)
+               return 0;               /* already allowed */
+       
+       de = NULL;
+       base = current->fs->root;
+
+       read_lock(&tasklist_lock);
+       p = find_task_by_pid(pid);
+
+       if (p != NULL)
+               de = p->fs->root;
+       read_unlock(&tasklist_lock);
+
+       if (p == NULL)
+               return -EACCES;         /* ENOENT? */
+
+       if (de == NULL)
+       {
+               /* kswapd and bdflush don't have proper root or cwd... */
+               return -EACCES;
+       }
+       
+       /* XXX locking? */
+       for(;;)
+       {
+               struct dentry *parent;
+
+               if (de == base)
+                       return 0;       /* already allowed */
+
+               de = de->d_covers;
+               parent = de->d_parent;
+
+               if (de == parent)
+                       break;
+
+               de = parent;
+       }
+
+       return -EACCES;                 /* incompatible roots */
+}
+
 struct inode * proc_get_inode(struct super_block * sb, int ino,
                                struct proc_dir_entry * de)
 {
index 2f4abc9455430b8473a8e88a9eb7098c32e899b1..5ee0fd30a36c3d38ea2a07695fdf0ebe5c0e7600 100644 (file)
@@ -58,7 +58,7 @@ struct inode_operations proc_link_inode_operations = {
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       proc_permission         /* permission */
 };
 
 static struct dentry * proc_follow_link(struct dentry *dentry,
index 1cbdbad9aaf28023ebcbcddfa57164640b12a009..6478dab77a9ad0c74e574bf99816ab25db83a86b 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/proc_fs.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -336,5 +337,5 @@ struct inode_operations proc_mem_inode_operations = {
        NULL,                   /* writepage */
        NULL,                   /* bmap */
        NULL,                   /* truncate */
-       NULL                    /* permission */
+       proc_permission         /* permission */
 };
index 0a5c60bf532e79bdb791b6699ca13407352b81de..d947f77332cfc932b3ac3cc66b0ef2662a7821ed 100644 (file)
@@ -148,7 +148,7 @@ __initfunc(static void check_popad(void))
 }
 
 /*
- *     B step AMD K6 before B 9729AIJW have hardware bugs that can cause
+ *     B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  *     misexecution of code under Linux. Owners of such processors should
  *     contact AMD for precise details and a CPU swap.
  *
@@ -195,10 +195,10 @@ __initfunc(static void check_amd_k6(void))
                printk(KERN_INFO "AMD K6 stepping B detected - ");
                /* -- cut here -- */
                if (d > 20*K6_BUG_LOOP) 
-                       printk(KERN_INFO "system stability may be impaired when more than 32 MB are used.\n");
+                       printk("system stability may be impaired when more than 32 MB are used.\n");
                else 
-                       printk(KERN_INFO "probably OK (after B9730xxxx).\n");
-               printk(KERN_INFO "Please see http://www.chorus.com/bpc/k6bug.html\n");
+                       printk("probably OK (after B9730xxxx).\n");
+               printk(KERN_INFO "Please see http://www.chorus.com/poulot/k6bug.html\n");
        }
 }
 
index 068be0f2954762d23ef0fae612a836c846125022..6819f825b252047f4fadfb26642626f19aaecbf0 100644 (file)
 #define __NR_pread             180
 #define __NR_pwrite            181
 #define __NR_chown             182
+#define __NR_getcwd            183
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
 
index 401933c3f031a3dc4d0851b56424b3663b142998..f564ae89884dd3af26bef69a276a0a5e5b4f710d 100644 (file)
@@ -1,11 +1,25 @@
 /*
- * $Id: b1lli.h,v 1.1 1997/03/04 21:27:32 calle Exp $
+ * $Id: b1lli.h,v 1.3 1998/01/31 10:54:37 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.3  1998/01/31 10:54:37  calle
+ * include changes for PCMCIA cards from 2.0 version
+ *
+ * Revision 1.2  1997/12/10 19:38:42  calle
+ * get changes from 2.0 tree
+ *
+ * Revision 1.1.2.2  1997/11/26 16:57:26  calle
+ * more changes for B1/M1/T1.
+ *
+ * Revision 1.1.2.1  1997/11/26 10:47:01  calle
+ * prepared for M1 (Mobile) and T1 (PMX) cards.
+ * prepared to set configuration after load to support other D-channel
+ * protocols, point-to-point and leased lines.
+ *
  * Revision 1.1  1997/03/04 21:27:32  calle
  * First version in isdn4linux
  *
@@ -32,10 +46,22 @@ typedef struct avmb1_loaddef {
        avmb1_t4file t4file;
 } avmb1_loaddef;
 
+typedef struct avmb1_loadandconfigdef {
+       int contr;
+       avmb1_t4file t4file;
+        avmb1_t4file t4config; 
+} avmb1_loadandconfigdef;
+
 typedef struct avmb1_resetdef {
        int contr;
 } avmb1_resetdef;
 
+typedef struct avmb1_getdef {
+       int contr;
+       int cardtype;
+       int cardstate;
+} avmb1_getdef;
+
 /*
  * struct for adding new cards 
  */
@@ -44,25 +70,39 @@ typedef struct avmb1_carddef {
        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 */
+#define AVM_CARDTYPE_B1        0
+#define AVM_CARDTYPE_T1        1
+#define AVM_CARDTYPE_M1        2
+#define AVM_CARDTYPE_M2        3
 
+typedef struct avmb1_extcarddef {
+       int port;
+       int irq;
+        int cardtype;
+} avmb1_extcarddef;
+
+#define        AVMB1_LOAD              0       /* load image to card */
+#define AVMB1_ADDCARD          1       /* add a new card */
+#define AVMB1_RESETCARD                2       /* reset a card */
+#define        AVMB1_LOAD_AND_CONFIG   3       /* load image and config to card */
+#define        AVMB1_ADDCARD_WITH_TYPE 4       /* add a new card, with cardtype */
+#define AVMB1_GET_CARDINFO     5       /* get cardtype */
 
 
-#ifdef __KERNEL__
 
 /*
  * card states for startup
  */
 
-#define CARD_NONE      0
+#define CARD_FREE      0
 #define CARD_DETECTED  1
 #define CARD_LOADING   2
 #define CARD_INITSTATE 4
 #define CARD_RUNNING   5
 #define CARD_ACTIVE    6
 
+#ifdef __KERNEL__
+
 #define        AVMB1_PORTLEN   0x1f
 
 #define AVM_MAXVERSION 8
@@ -81,6 +121,7 @@ typedef struct avmb1_card {
        int cnr;
        unsigned short port;
        unsigned irq;
+       int cardtype;
        volatile unsigned short cardstate;
        int interrupt;
        int blocked;
@@ -108,14 +149,15 @@ typedef struct avmb1_card {
 
 
 /* b1lli.c */
-int B1_detect(unsigned short base);
+int B1_detect(unsigned short base, int cardtype);
 void B1_reset(unsigned short base);
 int B1_load_t4file(unsigned short base, avmb1_t4file * t4file);
+int B1_load_config(unsigned short base, avmb1_t4file * config);
 int B1_loaded(unsigned short base);
-unsigned char B1_assign_irq(unsigned short base, unsigned irq);
+unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype);
 unsigned char B1_enable_irq(unsigned short base);
 unsigned char B1_disable_irq(unsigned short base);
-int B1_valid_irq(unsigned irq);
+int B1_valid_irq(unsigned irq, int cardtype);
 void B1_handle_interrupt(avmb1_card * card);
 void B1_send_init(unsigned short port,
            unsigned int napps, unsigned int nncci, unsigned int cardnr);
@@ -133,8 +175,17 @@ void avmb1_handle_free_ncci(avmb1_card * card,
 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);
+/* standard calls, with check and allocation of resources */
+int avmb1_addcard(int port, int irq, int cardtype);
+int avmb1_probecard(int port, int irq, int cardtype);
+
+
+int avmb1_resetcard(int cardnr);
+
+/* calls for pcmcia driver */
+int avmb1_detectcard(int port, int irq, int cardtype);
+int avmb1_registercard(int port, int irq, int cardtype, int allocio);
+int avmb1_unregistercard(int cnr, int freeio);
 
 #endif                         /* __KERNEL__ */
 
index c6a15bb34fca9679d3a72a8f7ff77d3a5b12e4a9..4d90c2eefae2087b95c2f9925b31a12ea170839c 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_BINFMTS_H
 
 #include <linux/ptrace.h>
+#include <linux/capability.h>
 
 /*
  * MAX_ARG_PAGES defines the number of pages allocated for arguments
@@ -21,6 +22,7 @@ struct linux_binprm{
        int java;               /* Java binary, prevent recursive invocation */
        struct dentry * dentry;
        int e_uid, e_gid;
+       kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
        int argc, envc;
        char * filename;        /* Name of binary */
        unsigned long loader, exec;
@@ -63,6 +65,8 @@ extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm
 extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
                unsigned long p, int from_kmem);
 
+extern void compute_creds(struct linux_binprm *binprm);
+
 /* this eventually goes away */
 #define change_ldt(a,b) setup_arg_pages(a,b)
 
diff --git a/include/linux/capability.h b/include/linux/capability.h
new file mode 100644 (file)
index 0000000..a702a6e
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * This is <linux/capability.h>
+ *
+ * Andrew G. Morgan <morgan@parc.power.net>
+ * Alexander Kjeldaas <astor@guardian.no>
+ * with help from Aleph1, Roland Buresund and Andrew Main.
+ */ 
+
+#ifndef _LINUX_CAPABILITY_H
+#define _LINUX_CAPABILITY_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+/* User-level do most of the mapping between kernel and user
+   capabilities based on the version tag given by the kernel. The
+   kernel might be somewhat backwards compatible, but don't bet on
+   it. */
+
+#define _LINUX_CAPABILITY_VERSION  0x19980330
+
+typedef struct _user_cap_struct {
+       __u32 version;
+       __u32 size;
+       __u8  cap[1];
+} *cap_t;
+
+#ifdef __KERNEL__
+
+typedef struct kernel_cap_struct {
+       int cap;
+} kernel_cap_t;
+
+#endif
+
+
+/**
+ ** POSIX-draft defined capabilities. 
+ **/
+
+/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
+   overrides the restriction of changing file ownership and group
+   ownership. */
+
+#define CAP_CHOWN            0
+
+/* Override all DAC access, including ACL execute access if
+   [_POSIX_ACL] is defined. Excluding DAC access covered by
+   CAP_LINUX_IMMUTABLE */
+
+#define CAP_DAC_OVERRIDE     1
+
+/* Overrides all DAC restrictions regarding read and search on files
+   and directories, including ACL restrictions if [_POSIX_ACL] is
+   defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE */
+
+#define CAP_DAC_READ_SEARCH  2
+    
+/* Overrides all restrictions about allowed operations on files, where
+   file owner ID must be equal to the user ID, except where CAP_FSETID
+   is applicable. It doesn't override MAC and DAC restrictions. */
+
+#define CAP_FOWNER           3
+
+/* Overrides the following restrictions that the effective user ID
+   shall match the file owner ID when setting the S_ISUID and S_ISGID
+   bits on that file; that the effective group ID (or one of the
+   supplementary group IDs shall match the file owner ID when setting
+   the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
+   cleared on successful return from chown(2). */
+
+#define CAP_FSETID           4
+
+/* Used to decide between falling back on the old suser() or fsuser(). */
+
+#define CAP_FS_MASK          0x1f
+
+/* Overrides the restriction that the real or effective user ID of a
+   process sending a signal must match the real or effective user ID
+   of the process receiving the signal. */
+
+#define CAP_KILL             5
+
+/* Allows setgid(2) manipulation */
+
+#define CAP_SETGID           6
+
+/* Allows setuid(2) manipulation */
+
+#define CAP_SETUID           7
+
+
+/**
+ ** Linux-specific capabilities
+ **/
+
+/* Transfer any capability in your permitted set to any pid,
+   remove any capability in your permitted set from any pid */
+
+#define CAP_SETPCAP          8
+
+/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */
+
+#define CAP_LINUX_IMMUTABLE  9
+
+/* Allows binding to TCP/UDP sockets below 1024 */
+
+#define CAP_NET_BIND_SERVICE 10
+
+/* Allow broadcasting, listen to multicast */
+
+#define CAP_NET_BROADCAST    11
+
+/* Allow interface configuration */
+/* Allow configuring of firewall stuff */
+/* Allow setting debug option on sockets */
+/* Allow modification of routing tables */
+
+#define CAP_NET_ADMIN        12
+
+/* Allow use of RAW sockets */
+/* Allow use of PACKET sockets */
+
+#define CAP_NET_RAW          13
+
+/* Allow locking of segments in memory */
+
+#define CAP_IPC_LOCK         14
+
+/* Override IPC ownership checks */
+
+#define CAP_IPC_OWNER        15
+
+/* Insert and remove kernel modules */
+
+#define CAP_SYS_MODULE       16
+
+/* Allow ioperm/iopl access */
+
+#define CAP_SYS_RAWIO        17
+
+/* Allow use of chroot() */
+
+#define CAP_SYS_CHROOT       18
+
+/* Allow ptrace() of any process */
+
+#define CAP_SYS_PTRACE       19
+
+/* Allow configuration of process accounting */
+
+#define CAP_SYS_PACCT        20
+
+/* Allow configuration of the secure attention key */
+/* Allow administration of the random device */
+/* Allow device administration */
+/* Allow examination and configuration of disk quotas */
+/* System Admin functions: mount et al */
+
+#define CAP_SYS_ADMIN        21
+
+/* Allow use of reboot() */
+
+#define CAP_SYS_BOOT         22
+
+/* Allow use of renice() on others, and raising of priority */
+
+#define CAP_SYS_NICE         23
+
+/* Override resource limits */
+
+#define CAP_SYS_RESOURCE     24
+
+/* Allow manipulation of system clock */
+
+#define CAP_SYS_TIME         25
+
+/* Allow configuration of tty devices */
+
+#define CAP_SYS_TTY_CONFIG   26
+
+#ifdef __KERNEL__
+
+/*
+ * Internal kernel functions only
+ */
+
+#define CAP_EMPTY_SET       {  0 }
+#define CAP_FULL_SET        { ~0 }
+
+#define CAP_TO_MASK(x) (1 << (x))
+#define cap_raise(c, flag)   (c.cap |=  CAP_TO_MASK(flag))
+#define cap_lower(c, flag)   (c.cap &= ~CAP_TO_MASK(flag))
+#define cap_raised(c, flag)  (c.cap &   CAP_TO_MASK(flag))
+
+#define cap_isclear(c) (!c.cap)
+
+#define cap_copy(dest,src) do { (dest).cap = (src).cap; } while(0)
+#define cap_clear(c)       do {  c.cap =  0; } while(0)
+#define cap_set_full(c)    do {  c.cap = ~0; } while(0)
+
+#define cap_is_fs_cap(c)     ((c) & CAP_FS_MASK)
+
+#endif /* __KERNEL__ */
+
+#endif /* !_LINUX_CAPABILITY_H */
diff --git a/include/linux/concap.h b/include/linux/concap.h
new file mode 100644 (file)
index 0000000..05f74d8
--- /dev/null
@@ -0,0 +1,113 @@
+/* $Id: concap.h,v 1.1 1998/02/01 00:15:11 keil Exp $
+*/
+#ifndef _LINUX_CONCAP_H
+#define _LINUX_CONCAP_H
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+/* Stuff to support encapsulation protocols genericly. The encapsulation
+   protocol is processed at the uppermost layer of the network interface.
+
+   (c) 1997 by Henner Eisen <eis@baty.hanse.de>
+   This software is subject to the GNU General Public License.
+
+   Based on a ideas developed in a 'synchronous device' thread in the
+   linux-x25 mailing list contributed by Alan Cox, Thomasz Motylewski
+   and Jonathan Naylor.
+
+   For more documetation on this refer to Documentation/isdn/README.concap
+   */
+
+struct concap_proto_ops;
+struct concap_device_ops;
+
+/* this manages all data needed by the encapsulation protocol
+ */
+struct concap_proto{
+       struct device *net_dev;         /* net device using our service  */
+       struct concap_device_ops *dops; /* callbacks provided by device */
+       struct concap_proto_ops  *pops; /* callbacks provided by us */
+       int flags;
+       void *proto_data;               /* protocol specific private data, to
+                                          be accessed via *pops methods only*/
+       /*
+         :
+         whatever 
+         :
+         */
+};
+
+/* Operations to be supported by the net device. Called by the encapsulation
+ * protocol entity. No receive method is offered because the encapsulation
+ * protocol directly calls netif_rx().
+ */
+struct concap_device_ops{
+
+       /* to request data is submitted by device*/ 
+       int (*data_req)(struct concap_proto *, struct sk_buff *);
+
+       /* Control methods must be set to NULL by devices which do not
+          support connection control.*/
+       /* to request a connection is set up */ 
+       int (*connect_req)(struct concap_proto *);
+
+       /* to request a connection is released */
+       int (*disconn_req)(struct concap_proto *);      
+};
+
+/* Operations to be supported by the encapsulation protocol. Called by
+ * device driver.
+ */
+struct concap_proto_ops{
+
+       /* create a new encapsulation protocol instance of same type */
+       struct concap_proto *  (*proto_new) (void);
+
+       /* delete encapsulation protocol instance and free all its resources.
+          cprot may no loger be referenced after calling this */
+       void (*proto_del)(struct concap_proto *cprot);
+
+       /* initialize the protocol's data. To be called at interface startup
+          or when the device driver resets the interface. All services of the
+          encapsulation protocol may be used after this*/
+       int (*restart)(struct concap_proto *cprot, 
+                      struct device *ndev,
+                      struct concap_device_ops *dops);
+
+       /* inactivate an encapsulation protocol instance. The encapsulation
+          protocol may not call any *dops methods after this. */
+       int (*close)(struct concap_proto *cprot);
+
+       /* process a frame handed down to us by upper layer */
+       int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
+
+       /* to be called for each data entity received from lower layer*/ 
+       int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
+
+       /* to be called when a connection was set up/down.
+          Protocols that don't process these primitives might fill in
+          dummy methods here */
+       int (*connect_ind)(struct concap_proto *cprot);
+       int (*disconn_ind)(struct concap_proto *cprot);
+  /*
+    Some network device support functions, like net_header(), rebuild_header(),
+    and others, that depend solely on the encapsulation protocol, might
+    be provided here, too. The net device would just fill them in its
+    corresponding fields when it is opened.
+    */
+};
+
+/* dummy restart/close/connect/reset/disconn methods
+ */
+extern int concap_nop(struct concap_proto *cprot); 
+
+/* dummy submit method
+ */
+extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb);
+#endif
+#endif
+
+
+
+
index 8c0854b0b854dca1f5634e85792b788a8f77b1e7..e287e64d5fe93b4d5bfcf18c92977a313589816c 100644 (file)
@@ -80,7 +80,7 @@ extern struct console_cmdline console_list[MAX_CMDLINECONSOLES];
  */
 
 #define CON_PRINTBUFFER        (1)
-#define CON_FIRST      (2)
+#define CON_CONSDEV    (2) /* Last on the command line */
 #define CON_ENABLED    (4)
 
 struct console
index 6c55c89f19500eddff8de75409e0ae680073cbf0..35eb83fa264e51ff1d46cd460eb0a2f924a67bdb 100644 (file)
@@ -65,6 +65,7 @@
 #define SC_REJ_COMP_TCP        0x00000020      /* reject TCP (VJ) comp. on input */
 #define SC_CCP_OPEN    0x00000040      /* Look at CCP packets */
 #define SC_CCP_UP      0x00000080      /* May send/recv compressed packets */
+#define SC_ENABLE_IP   0x00000100      /* IP packets may be exchanged */
 #define SC_COMP_RUN    0x00001000      /* compressor has been inited */
 #define SC_DECOMP_RUN  0x00002000      /* decompressor has been inited */
 #define SC_DEBUG       0x00010000      /* enable debug messages */
index f7b4747d38a0e8307ba9f48a0fb5477af54a3aa5..e061cabaa13cbafbea8d15d4a3feb43024f9d4b4 100644 (file)
@@ -1,4 +1,10 @@
-/* $Id: isdn.h,v 1.29 1997/05/27 15:18:02 fritz Exp $
+/* Changes for X.25 support:
+   Added ISDN_NET_ENCAP_X25IFACE macro.
+   Additional field in isdn_net_dev_s and isdn_net_local to support
+   generic encapsulation protocols. 
+*/
+
+/* $Id: isdn.h,v 1.37 1998/02/22 19:45:24 fritz Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.37  1998/02/22 19:45:24  fritz
+ * Some changes regarding V.110
+ *
+ * Revision 1.36  1998/02/20 17:35:55  fritz
+ * Added V.110 stuff.
+ *
+ * Revision 1.35  1998/01/31 22:14:14  keil
+ * changes for 2.1.82
+ *
+ * Revision 1.34  1997/10/09 21:28:11  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.33  1997/08/21 14:44:22  fritz
+ * Moved triggercps to end of struct for backwards-compatibility.
+ *
+ * Revision 1.32  1997/08/21 09:49:46  fritz
+ * Increased NET_DV
+ *
+ * Revision 1.31  1997/06/22 11:57:07  fritz
+ * Added ability to adjust slave triggerlevel.
+ *
+ * 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
 #define IIOCDRVCTL  _IO('I',128)
 
 /* Packet encapsulations for net-interfaces */
-#define ISDN_NET_ENCAP_ETHER     0
-#define ISDN_NET_ENCAP_RAWIP     1
-#define ISDN_NET_ENCAP_IPTYP     2
-#define ISDN_NET_ENCAP_CISCOHDLC 3
-#define ISDN_NET_ENCAP_SYNCPPP   4
-#define ISDN_NET_ENCAP_UIHDLC    5
-
+#define ISDN_NET_ENCAP_ETHER      0
+#define ISDN_NET_ENCAP_RAWIP      1
+#define ISDN_NET_ENCAP_IPTYP      2
+#define ISDN_NET_ENCAP_CISCOHDLC  3 /* Without SLARP and keepalive */
+#define ISDN_NET_ENCAP_SYNCPPP    4
+#define ISDN_NET_ENCAP_UIHDLC     5
+#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive    */
+#define ISDN_NET_ENCAP_X25IFACE   7 /* Documentation/networking/x25-iface.txt*/
+#define ISDN_NET_ENCAP_MAX_ENCAP  ISDN_NET_ENCAP_X25IFACE
 /* Facility which currently uses an ISDN-channel */
 #define ISDN_USAGE_NONE       0
 #define ISDN_USAGE_RAW        1
@@ -219,7 +258,7 @@ typedef struct {
   int  outgoing;
 } isdn_net_ioctl_phone;
 
-#define NET_DV 0x02 /* Data version for net_cfg     */
+#define NET_DV 0x04 /* Data version for net_cfg     */
 #define TTY_DV 0x04 /* Data version for iprofd etc. */
 
 typedef struct {
@@ -244,6 +283,7 @@ typedef struct {
   int  cbhup;        /* Flag: Reject Call before Callback     */
   int  pppbind;      /* ippp device for bindings              */
   int  chargeint;    /* Use fixed charge interval length      */
+  int  triggercps;   /* BogoCPS needed for triggering slave   */
 } isdn_net_ioctl_cfg;
 
 #ifdef __KERNEL__
@@ -287,6 +327,10 @@ typedef struct {
 #include <linux/isdn_ppp.h>
 #endif
 
+#ifdef CONFIG_ISDN_X25
+#  include <linux/concap.h>
+#endif
+
 #include <linux/isdnif.h>
 
 #define ISDN_DRVIOCTL_MASK       0x7f  /* Mask for Device-ioctl */
@@ -317,21 +361,23 @@ typedef struct {
                              ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)     )
 
 /* Timer-delays and scheduling-flags */
-#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
-#define ISDN_TIMER_MODEMXMIT 8
-#define ISDN_TIMER_NETDIAL   16
-#define ISDN_TIMER_NETHANGUP 32
-#define ISDN_TIMER_IPPP      64
+#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_KEEPINT    10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
+#define ISDN_TIMER_MODEMREAD   1
+#define ISDN_TIMER_MODEMPLUS   2
+#define ISDN_TIMER_MODEMRING   4
+#define ISDN_TIMER_MODEMXMIT   8
+#define ISDN_TIMER_NETDIAL    16 
+#define ISDN_TIMER_NETHANGUP  32
+#define ISDN_TIMER_IPPP       64 
+#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
 #define ISDN_TIMER_FAST      (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
                               ISDN_TIMER_MODEMXMIT)
 #define ISDN_TIMER_SLOW      (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
-                              ISDN_TIMER_NETDIAL)
+                              ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE)
 
 /* Timeout-Values for isdn_net_dial() */
 #define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
@@ -362,6 +408,15 @@ typedef struct {
   char num[ISDN_MSNLEN];
 } isdn_net_phone;
 
+/*
+   Principles when extending structures for generic encapsulation protocol
+   ("concap") support:
+   - Stuff which is hardware specific (here i4l-specific) goes in 
+     the netdev -> local structure (here: isdn_net_local)
+   - Stuff which is encapsulation protocol specific goes in the structure
+     which holds the linux device structure (here: isdn_net_device)
+*/
+
 /* Local interface-data */
 typedef struct isdn_net_local_s {
   ulong                  magic;
@@ -413,6 +468,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      */
@@ -425,16 +481,21 @@ 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*/
-
                                        /* Ptr to orig. hard_header_cache   */
-  int                    (*org_hhc)(struct neighbour *neigh,
+  int                    (*org_hhc)(
+                                   struct neighbour *neigh,
                                    struct hh_cache *hh);
-
                                        /* Ptr to orig. header_cache_update */
   void                   (*org_hcu)(struct hh_cache *,
                                    struct device *,
                                     unsigned char *);
   int  pppbind;                        /* ippp device for bindings         */
+#ifdef CONFIG_ISDN_X25
+  struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
+#endif
+  int  cisco_loop;                     /* Loop counter for Cisco-SLARP     */
+  ulong cisco_myseq;                   /* Local keepalive seq. for Cisco   */
+  ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
 } isdn_net_local;
 
 #ifdef CONFIG_ISDN_PPP
@@ -451,14 +512,18 @@ struct ippp_bundle {
 
 /* the interface itself */
 typedef struct isdn_net_dev_s {
-  isdn_net_local  local;
+  isdn_net_local *local;
   isdn_net_local *queue;
   void           *next;                /* Pointer to next isdn-interface   */
-  struct device   dev;                /* interface to upper levels        */
+  struct device   dev;        /* interface to upper levels        */
 #ifdef CONFIG_ISDN_PPP
   struct mpqueue *mp_last; 
   struct ippp_bundle ib;
 #endif
+#ifdef CONFIG_ISDN_X25
+  struct concap_proto  *cprot; /* connection oriented encapsulation protocol */
+#endif
+
 } isdn_net_dev;
 
 /*===================== End of ip-over-ISDN stuff ===========================*/
@@ -477,7 +542,8 @@ typedef struct isdn_net_dev_s {
 #define ISDN_ASYNC_PGRP_LOCKOUT       0x0200 /* Lock cua opens on pgrp       */
 #define ISDN_ASYNC_CALLOUT_NOHUP      0x0400 /* No hangup for cui            */
 #define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
-#define ISDN_SERIAL_XMIT_SIZE           4000 /* Maximum bufsize for write    */
+#define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
+#define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
 #define ISDN_SERIAL_TYPE_NORMAL            1
 #define ISDN_SERIAL_TYPE_CALLOUT           2
 
@@ -499,18 +565,19 @@ typedef struct isdn_audio_skb {
 
 /* 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                          */
+       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  */
+       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 +              */
-  char                mdmcmd[255];     /* Modem-Commandbuffer              */
+       int          mdmcmdl;                    /* Length of Modem-Commandbuffer      */
+       int          pluscount;                  /* Counter for +++ sequence           */
+       int          lastplus;                   /* Timestamp of last +                */
+       char         mdmcmd[255];                /* Modem-Commandbuffer                */
+       unsigned int charge;                     /* Charge units of current connection */
 } atemu;
 
 /* Private data (similar to async_struct in <linux/serial.h>) */
@@ -590,8 +657,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;
 };
@@ -599,7 +666,7 @@ struct sqqueue {
 struct mpqueue {
   struct mpqueue *next;
   struct mpqueue *last;
-  int    sqno;
+  long sqno;
   struct sk_buff *skb;
   int BEbyte;
   unsigned long time;
@@ -638,18 +705,44 @@ struct ippp_struct {
   struct slcompress *slcomp;
 #endif
   unsigned long debug;
-  struct isdn_ppp_compressor *compressor;
+  struct isdn_ppp_compressor *compressor,*link_compressor;
+  void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
 };
 
 #endif
 
 /*======================== End of sync-ppp stuff ===========================*/
 
+/*======================== Start of V.110 stuff ============================*/
+#define V110_BUFSIZE 1024
+
+typedef struct {
+       int nbytes;                    /* 1 Matrixbyte -> nbytes in stream     */
+       int nbits;                     /* Number of used bits in streambyte    */
+       unsigned char key;             /* Bitmask in stream eg. 11 (nbits=2)   */
+       int decodelen;                 /* Amount of data in decodebuf          */
+       int SyncInit;                  /* Number of sync frames to send        */
+       unsigned char *OnlineFrame;    /* Precalculated V110 idle frame        */
+       unsigned char *OfflineFrame;   /* Precalculated V110 sync Frame        */
+       int framelen;                  /* Length of frames                     */
+       int skbuser;                   /* Number of unacked userdata skbs      */
+       int skbidle;                   /* Number of unacked idle/sync skbs     */
+       int introducer;                /* Local vars for decoder               */
+       int dbit;
+       unsigned char b;
+       int skbres;                    /* space to reserve in outgoing skb     */
+       int maxsize;                   /* maxbufsize of lowlevel driver        */
+       unsigned char *encodebuf;      /* temporary buffer for encoding        */
+       unsigned char decodebuf[V110_BUFSIZE]; /* incomplete V110 matrices     */
+} isdn_v110_stream;
+
+/*========================= End of V.110 stuff =============================*/
+
 /*======================= Start of general stuff ===========================*/
 
 typedef struct {
-  char *next;
-  char *private;
+       char *next;
+       char *private;
 } infostruct;
 
 /* Description of hardware-level-driver */
@@ -704,6 +797,9 @@ typedef struct isdn_devt {
   isdn_net_dev      *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers   */
   ulong             ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes  */
   ulong             obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes  */
+  int               v110emu[ISDN_MAX_CHANNELS];/* V.110 emulator-mode 0=none */
+  atomic_t          v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
+  isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
 } isdn_dev;
 
 extern isdn_dev *dev;
index 71bbc557a917735a86e88749705b322467b1d81e..177646520470eea38c33e9c4da7021f7365b4319 100644 (file)
@@ -1,23 +1,8 @@
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
-struct isdn_ppp_compressor
-{
-    struct isdn_ppp_compressor *next,*prev;
-    int num;    /* proto num */
-    void *priv; /* private data for compressor */
-       int (*open)(struct isdn_ppp_compressor *);
-       int (*close)(struct isdn_ppp_compressor *);
-       int (*reset)(struct isdn_ppp_compressor *,int type);
-       int (*config)(struct isdn_ppp_compressor *,void *data,int data_len);
-       struct sk_buff *(*compress)(struct isdn_ppp_compressor *,struct sk_buff *);
-       struct sk_buff *(*uncompress)(struct isdn_ppp_compressor *,struct sk_buff *);
-};
-
 extern int isdn_ppp_dial_slave(char *);
 extern int isdn_ppp_hangup_slave(char *);
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
 
 #define CALLTYPE_INCOMING 0x1
 #define CALLTYPE_OUTGOING 0x2
@@ -31,18 +16,17 @@ struct pppcallinfo
        int charge_units;
 };
 
 #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 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
@@ -52,4 +36,36 @@ struct pppcallinfo
 #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 a3f6773a46dd311599136d833bc7097aa51d3d2e..e7a7f247c08668122c322b0dcaacc62f3fdb6652 100644 (file)
@@ -1,4 +1,8 @@
-/* $Id: isdnif.h,v 1.20 1997/05/27 15:18:06 fritz Exp $
+/* X25 changes:
+   Added constants ISDN_PROTO_L2_X25DTE/DCE and corresponding ISDN_FEATURE_..
+   */
+
+/* $Id: isdnif.h,v 1.23 1998/02/20 17:36:52 fritz Exp $
  *
  * Linux ISDN subsystem
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.23  1998/02/20 17:36:52  fritz
+ * Added L2-protocols for V.110, changed FEATURE-Flag-constants.
+ *
+ * Revision 1.22  1998/01/31 22:14:12  keil
+ * changes for 2.1.82
+ *
+ * Revision 1.21  1997/10/09 21:28:13  fritz
+ * New HL<->LL interface:
+ *   New BSENT callback with nr. of bytes included.
+ *   Sending without ACK.
+ *   New L1 error status (not yet in use).
+ *   Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
  * Revision 1.20  1997/05/27 15:18:06  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
 #define ISDN_PTYPE_EURO      2   /* EDSS1-protocol       */
 #define ISDN_PTYPE_LEASED    3   /* for leased lines     */
 #define ISDN_PTYPE_NI1       4   /* US NI-1 protocol     */
+#define ISDN_PTYPE_MAX       7   /* Max. 8 Protocols     */
 
 /*
  * Values for Layer-2-protocol-selection
  */
-#define ISDN_PROTO_L2_X75I   0   /* X75/LAPB with I-Frames      */
-#define ISDN_PROTO_L2_X75UI  1   /* X75/LAPB with UI-Frames     */
-#define ISDN_PROTO_L2_X75BUI 2   /* X75/LAPB with UI-Frames     */
-#define ISDN_PROTO_L2_HDLC   3   /* HDLC                        */
-#define ISDN_PROTO_L2_TRANS  4   /* Transparent (Voice)         */
+#define ISDN_PROTO_L2_X75I   0   /* X75/LAPB with I-Frames            */
+#define ISDN_PROTO_L2_X75UI  1   /* X75/LAPB with UI-Frames           */
+#define ISDN_PROTO_L2_X75BUI 2   /* X75/LAPB with UI-Frames           */
+#define ISDN_PROTO_L2_HDLC   3   /* HDLC                              */
+#define ISDN_PROTO_L2_TRANS  4   /* Transparent (Voice)               */
+#define ISDN_PROTO_L2_X25DTE 5   /* X25/LAPB DTE mode                 */
+#define ISDN_PROTO_L2_X25DCE 6   /* X25/LAPB DCE mode                 */
+#define ISDN_PROTO_L2_V11096 7   /* V.110 bitrate adaption 9600 Baud  */
+#define ISDN_PROTO_L2_V11019 8   /* V.110 bitrate adaption 19200 Baud */
+#define ISDN_PROTO_L2_V11038 9   /* V.110 bitrate adaption 38400 Baud */
+#define ISDN_PROTO_L2_MAX    15  /* Max. 16 Protocols                 */
 
 /*
  * Values for Layer-3-protocol-selection
  */
 #define ISDN_PROTO_L3_TRANS  0   /* Transparent                 */
+#define ISDN_PROTO_L3_MAX    7   /* Max. 8 Protocols            */
 
 #ifdef __KERNEL__
 
  * Commands from linklevel to lowlevel
  *
  */
-#define ISDN_CMD_IOCTL   0       /* Perform ioctl                         */
+#define ISDN_CMD_IOCTL    0       /* Perform ioctl                         */
 #define ISDN_CMD_DIAL     1       /* Dial out                              */
 #define ISDN_CMD_ACCEPTD  2       /* Accept an incoming call on D-Chan.    */
 #define ISDN_CMD_ACCEPTB  3       /* Request B-Channel connect.            */
 #define ISDN_STAT_NODCH   268    /* Signal no D-Channel                   */
 #define ISDN_STAT_ADDCH   269    /* Add more Channels                     */
 #define ISDN_STAT_CAUSE   270    /* Cause-Message                         */
+#define ISDN_STAT_L1ERR   271    /* Signal Layer-1 Error                  */
+
+/*
+ * Values for errcode field
+ */
+#define ISDN_STAT_L1ERR_SEND 1
+#define ISDN_STAT_L1ERR_RECV 2
 
 /*
  * Values for feature-field of interface-struct.
 #define ISDN_FEATURE_L2_X75BUI  (0x0001 << ISDN_PROTO_L2_X75BUI)
 #define ISDN_FEATURE_L2_HDLC    (0x0001 << ISDN_PROTO_L2_HDLC)
 #define ISDN_FEATURE_L2_TRANS   (0x0001 << ISDN_PROTO_L2_TRANS)
+#define ISDN_FEATURE_L2_X25DTE  (0x0001 << ISDN_PROTO_L2_X25DTE)
+#define ISDN_FEATURE_L2_X25DCE  (0x0001 << ISDN_PROTO_L2_X25DCE)
+#define ISDN_FEATURE_L2_V11096  (0x0001 << ISDN_PROTO_L2_V11096)
+#define ISDN_FEATURE_L2_V11019  (0x0001 << ISDN_PROTO_L2_V11019)
+#define ISDN_FEATURE_L2_V11038  (0x0001 << ISDN_PROTO_L2_V11038)
+
+#define ISDN_FEATURE_L2_MASK    (0x0FFFF) /* Max. 16 protocols */
+#define ISDN_FEATURE_L2_SHIFT   (0)
 
 /* Layer 3 */
-#define ISDN_FEATURE_L3_TRANS   (0x0100 << ISDN_PROTO_L3_TRANS)
+#define ISDN_FEATURE_L3_TRANS   (0x10000 << ISDN_PROTO_L3_TRANS)
+
+#define ISDN_FEATURE_L3_MASK    (0x0FF0000) /* Max. 8 Protocols */
+#define ISDN_FEATURE_L3_SHIFT   (16)
 
 /* Signaling */
-#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)
+#define ISDN_FEATURE_P_UNKNOWN  (0x1000000 << ISDN_PTYPE_UNKNOWN)
+#define ISDN_FEATURE_P_1TR6     (0x1000000 << ISDN_PTYPE_1TR6)
+#define ISDN_FEATURE_P_EURO     (0x1000000 << ISDN_PTYPE_EURO)
+#define ISDN_FEATURE_P_NI1      (0x1000000 << ISDN_PTYPE_NI1)
+
+#define ISDN_FEATURE_P_MASK     (0x0FF000000) /* Max. 8 Protocols */
+#define ISDN_FEATURE_P_SHIFT    (24)
 
 typedef struct setup_parm {
     char phone[32];         /* Remote Phone-Number */
@@ -204,6 +253,8 @@ typedef struct {
   int   command;                 /* Command or Status (see above)         */
   ulong arg;                     /* Additional Data                       */
   union {
+       ulong errcode;               /* Type of error with STAT_L1ERR         */
+       int   length;                /* Amount of bytes sent with STAT_BSENT  */
        char  num[50];               /* Additional Data                       */
        setup_parm setup;
   } parm;
@@ -238,19 +289,6 @@ typedef struct {
    */
   unsigned short hl_hdrlen;
 
-  /* Receive-Callback
-   * Parameters:
-   *             int    Driver-ID
-   *             int    local channel-number (0 ...)
-   *             u_char pointer to received data (in Kernel-Space, volatile)
-   *             int    length of data
-   *
-   * NOTE: This callback is obsolete, and will be removed when all
-   *       current LL-drivers support rcvcall_skb. Do NOT use for new
-   *       drivers.
-   */
-  void (*rcvcallb)(int, int, u_char*, int);
-
   /*
    * Receive-Callback using sk_buff's
    * Parameters:
@@ -269,6 +307,7 @@ typedef struct {
    *                   num     = depending on status-type.
    */
   int (*statcallb)(isdn_ctrl*);
+
   /* Send command
    * Parameters:
    *             isdn_ctrl*
@@ -278,31 +317,16 @@ typedef struct {
    *                   num     = depending on command.
    */
   int (*command)(isdn_ctrl*);
-  /* Send Data
-   * Parameters:
-   *             int    driverId
-   *             int    local channel-number (0 ...)
-   *             u_char pointer to data
-   *             int    length of data
-   *             int    Flag: 0 = Call form Kernel-Space (use memcpy,
-   *                              no schedule allowed) 
-   *                          1 = Data is in User-Space (use memcpy_fromfs,
-   *                              may schedule)
-   *
-   * NOTE: This call is obsolete, and will be removed when all
-   *       current LL-drivers support writebuf_skb. Do NOT use for new
-   *       drivers.
-   */
-  int (*writebuf)(int, int, const u_char*, int, int);
 
   /*
    * Send data using sk_buff's
    * Parameters:
    *             int                    driverId
    *             int                    local channel-number (0...)
+   *             int                    Flag: Need ACK for this packet.
    *             struct sk_buff *skb    Data to send
    */
-  int (*writebuf_skb) (int, int, struct sk_buff *);
+  int (*writebuf_skb) (int, int, int, struct sk_buff *);
 
   /* Send raw D-Channel-Commands
    * Parameters:
@@ -316,6 +340,7 @@ typedef struct {
    *             int    local channel-number (0 ...)
    */
   int (*writecmd)(const u_char*, int, int, int, int);
+
   /* Read raw Status replies
    *             u_char pointer data (volatile)
    *             int    length of buffer
@@ -327,6 +352,7 @@ typedef struct {
    *             int    local channel-number (0 ...)
    */
   int (*readstat)(u_char*, int, int, int, int);
+
   char id[20];
 } isdn_if;
 
@@ -339,8 +365,7 @@ typedef struct {
  *              supporting sk_buff's should set this to 0.
  * command      Address of Command-Handler.
  * features     Bitwise coded Features of this driver. (use ISDN_FEATURE_...)
- * writebuf     Address of Send-Command-Handler. OBSOLETE do NOT use anymore.
- * writebuf_skb Address of Skbuff-Send-Handler. (NULL if not supported)
+ * writebuf_skb Address of Skbuff-Send-Handler.
  * writecmd        "    "  D-Channel  " which accepts raw D-Ch-Commands.
  * readstat        "    "  D-Channel  " which delivers raw Status-Data.
  *
@@ -348,72 +373,16 @@ typedef struct {
  *
  * channels      Driver-ID assigned to this driver. (Must be used on all
  *               subsequent callbacks.
- * rcvcallb      Address of handler for received data. OBSOLETE, do NOT use anymore.
- * rcvcallb_skb  Address of handler for received Skbuff's. (NULL if not supp.)
+ * rcvcallb_skb  Address of handler for received Skbuff's.
  * statcallb        "    "     "    for status-changes.
  *
  */
 extern int register_isdn(isdn_if*);
 
-/* Compatibility Linux-2.0.X <-> Linux-2.1.X */
-
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
-#if (LINUX_VERSION_CODE < 0x020100)
-#include <linux/mm.h>
-
-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
-#define RWARG int
-#define LSARG off_t
-#else
 #include <asm/uaccess.h>
-#define GET_USER get_user
-#define PUT_USER put_user
-#define RWTYPE ssize_t
-#define LSTYPE long long
-#define RWARG size_t
-#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 */
index baec070117c6ca6d4747e187a5e2014f5f20b42a..e72a3df89e906ff760924e991480257ccaf2c077 100644 (file)
@@ -327,6 +327,7 @@ extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_
 extern int proc_statfs(struct super_block *, struct statfs *, int);
 extern void proc_read_inode(struct inode *);
 extern void proc_write_inode(struct inode *);
+extern int proc_permission(struct inode *, int);
 
 extern int proc_match(int, const char *,struct proc_dir_entry *);
 
index b5f1be07e71b981544f13d5cf50b99e4477a8942..ca8016313012415ee533edbbf4c2b9334c2a7350 100644 (file)
@@ -20,6 +20,8 @@ extern unsigned long event;
 #include <linux/tty.h>
 #include <linux/sem.h>
 #include <linux/signal.h>
+#include <linux/capability.h>
+#include <linux/securebits.h>
 
 /*
  * cloning flags:
@@ -220,8 +222,6 @@ struct task_struct {
        pid_t session;
        /* boolean value for session group leader */
        int leader;
-       int ngroups;
-       gid_t groups[NGROUPS];
        /* 
         * pointers to (original) parent process, youngest child, younger sibling,
         * older sibling, respectively.  (p->father can be replaced with 
@@ -237,8 +237,6 @@ struct task_struct {
        struct task_struct **tarray_ptr;
 
        struct wait_queue *wait_chldexit;       /* for wait4() */
-       uid_t uid,euid,suid,fsuid;
-       gid_t gid,egid,sgid,fsgid;
        unsigned long timeout, policy, rt_priority;
        unsigned long it_real_value, it_prof_value, it_virt_value;
        unsigned long it_real_incr, it_prof_incr, it_virt_incr;
@@ -253,6 +251,12 @@ struct task_struct {
        unsigned long old_maj_flt;      /* old value of maj_flt */
        unsigned long dec_flt;          /* page fault count of the last time */
        unsigned long swap_cnt;         /* number of pages to swap on next pass */
+/* process credentials */
+       uid_t uid,euid,suid,fsuid;
+       gid_t gid,egid,sgid,fsgid;
+       int ngroups;
+       gid_t   groups[NGROUPS];
+        kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 /* limits */
        struct rlimit rlim[RLIM_NLIMITS];
        unsigned short used_math;
@@ -334,18 +338,20 @@ struct task_struct {
 /* schedlink */        &init_task,&init_task, &init_task, &init_task, \
 /* ec,brk... */        0,0,0,0,0,0, \
 /* pid etc.. */        0,0,0,0,0, \
-/* suppl grps*/ 0, {0,}, \
 /* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
 /* pidhash */  NULL, NULL, \
 /* tarray */   &task[0], \
 /* chld wait */        NULL, \
-/* uid etc */  0,0,0,0,0,0,0,0, \
 /* timeout */  0,SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */    { NULL, NULL, 0, 0, it_real_fn }, \
 /* utime */    {0,0,0,0},0, \
 /* per cpu times */ {0, }, {0, }, \
 /* flt */      0,0,0,0,0,0, \
 /* swp */      0,0,0,0,0, \
+/* process credentials */                                      \
+/* uid etc */  0,0,0,0,0,0,0,0,                                \
+/* suppl grps*/ 0, {0,},                                       \
+/* caps */      CAP_FULL_SET, CAP_FULL_SET, CAP_FULL_SET,    \
 /* rlimits */   INIT_RLIMITS, \
 /* math */     0, \
 /* comm */     "swapper", \
@@ -444,8 +450,6 @@ extern unsigned int * prof_buffer;
 extern unsigned long prof_len;
 extern unsigned long prof_shift;
 
-extern int securelevel;        /* system security level */
-
 #define CURRENT_TIME (xtime.tv_sec)
 
 extern void FASTCALL(__wake_up(struct wait_queue ** p, unsigned int mode));
@@ -530,10 +534,13 @@ extern void free_irq(unsigned int irq, void *dev_id);
  * For correctness, the above considerations need to be extended to
  * fsuser(). This is done, along with moving fsuser() checks to be
  * last.
+ *
+ * These will be removed, but in the mean time, when the SECURE_NOROOT 
+ * flag is set, uids don't grant privilege.
  */
 extern inline int suser(void)
 {
-       if (current->euid == 0) {
+       if (!issecure(SECURE_NOROOT) && current->euid == 0) { 
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
@@ -542,7 +549,27 @@ extern inline int suser(void)
 
 extern inline int fsuser(void)
 {
-       if (current->fsuid == 0) {
+       if (!issecure(SECURE_NOROOT) && current->fsuid == 0) {
+               current->flags |= PF_SUPERPRIV;
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * capable() checks for a particular capability.  
+ * New privilege checks should use this interface, rather than suser() or
+ * fsuser(). See include/linux/capability.h for defined capabilities.
+ */
+
+extern inline int capable(int cap)
+{
+#if 0 /* not yet */
+       if (cap_raised(current->cap_effective, cap))
+#else
+       if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
+#endif
+        {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
new file mode 100644 (file)
index 0000000..1e10bad
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _LINUX_SECUREBITS_H
+#define _LINUX_SECUREBITS_H 1
+
+#define SECUREBITS_DEFAULT 0x00000000
+
+extern unsigned securebits;
+
+/* When set UID 0 has no special privileges. When unset, we support
+   inheritance of root-permissions and suid-root executablew under
+   compatibility mode. We raise the effective and inheritable bitmasks
+   *of the executable file* if the effective uid of the new process is
+   0. If the real uid is 0, we raise the inheritable bitmask of the
+   executable file. */
+#define SECURE_NOROOT            0
+
+/* When set, setuid to/from uid 0 does not trigger capability-"fixes"
+   to be compatible with old programs relying on set*uid to loose
+   privileges. When unset, setuid doesn't change privileges. */
+#define SECURE_NO_SETUID_FIXUP   2
+
+/* Each securesetting is implemented using two bits. One bit specify
+   whether the setting is on or off. The other bit specify whether the
+   setting is fixed or not. A setting which is fixed cannot be changed
+   from user-level. */
+
+#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ?      \
+                     (1 << (X)) & SECUREBITS_DEFAULT :         \
+                     (1 << (X)) & securebits )
+
+#endif /* !_LINUX_SECUREBITS_H */
index 0ccd625cfd30060f98833fffec467bc48fbfcc45..79a7faf2a016cffcd60f4f013585087c860bc3bf 100644 (file)
@@ -75,8 +75,10 @@ struct sk_buff {
 
        struct  dst_entry *dst;
 
-#if (defined(__alpha__) || defined(__sparc64__)) && (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE))
+#if (defined(__alpha__) || defined(__sparc_v9__)) && (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE))
        char            cb[48];    /* sorry. 64bit pointers have a price */
+#elif (defined(__alpha__) || defined(__sparc_v9__))
+       char            cb[40];
 #else
        char            cb[36];
 #endif
@@ -370,12 +372,17 @@ extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
  *     Place a packet after a given packet in a list.
  */
 
+extern __inline__ void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
+{
+       __skb_insert(newsk, old, old->next, old->list);
+}
+
 extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&skb_queue_lock, flags);
-       __skb_insert(newsk, old, old->next, old->list);
+       __skb_append(old, newsk);
        spin_unlock_irqrestore(&skb_queue_lock, flags);
 }
 
index 3a8f31e777700437f8d5f841aeddc6e8278a8bd2..53b265f49ec60c09ece5e06374b1e409ef3ee464 100644 (file)
@@ -153,7 +153,6 @@ enum
        NET_IPV4_TCP_TIMESTAMPS,
        NET_IPV4_TCP_WINDOW_SCALING,
        NET_IPV4_TCP_SACK,
-       NET_IPV4_TCP_VEGAS_CONG_AVOID,
        NET_IPV4_DEFAULT_TTL,
        NET_IPV4_AUTOCONFIG,
        NET_IPV4_NO_PMTU_DISC,
index a990773af62f8cf722952fdfe848c151a2aae6e3..a53a4ccc10a7774e1c0321f5fac8a177b1668556 100644 (file)
@@ -69,6 +69,28 @@ typedef unsigned short               ushort;
 typedef unsigned int           uint;
 typedef unsigned long          ulong;
 
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef                __u8            u_int8_t;
+typedef                __s8            int8_t;
+typedef                __u16           u_int16_t;
+typedef                __s16           int16_t;
+typedef                __u32           u_int32_t;
+typedef                __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+typedef                __u8            uint8_t;
+typedef                __u16           uint16_t;
+typedef                __u32           uint32_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef                __u64           uint64_t;
+typedef                __u64           u_int64_t;
+typedef                __s64           int64_t;
+#endif
+
 #endif /* __KERNEL_STRICT_NAMES */
 
 /*
index 40072ab47cdc2ce208041195c818233119ff00c4..efa2e5b3e649c96efaea6b2de68bc3098ee2e15b 100644 (file)
@@ -16,7 +16,7 @@ struct vm_struct {
 struct vm_struct * get_vm_area(unsigned long size);
 void vfree(void * addr);
 void * vmalloc(unsigned long size);
-int vread(char *buf, char *addr, int count);
+long vread(char *buf, char *addr, unsigned long count);
 void vmfree_area_pages(unsigned long address, unsigned long size);
 int vmalloc_area_pages(unsigned long address, unsigned long size);
 
index d94469da9ffa4d6b9d534a152dc72598e328f021..6b6f782eacb3192065aa7cbb16692af8aebdbcfc 100644 (file)
 
 #include <asm/atomic.h>
 
-/*
- *     The AF_UNIX specific socket options
- */
-struct unix_opt
-{
+/* The AF_UNIX specific socket options */
+struct unix_opt {
        int                     family;
        char *                  name;
        int                     locks;
@@ -105,8 +101,7 @@ struct unix_opt
 #ifdef CONFIG_NETLINK
 struct netlink_callback;
 
-struct netlink_opt
-{
+struct netlink_opt {
        pid_t                   pid;
        unsigned                groups;
        pid_t                   dst_pid;
@@ -117,13 +112,9 @@ struct netlink_opt
 };
 #endif
 
-/*
- *     Once the IPX ncpd patches are in these are going into protinfo
- */
-
+/* Once the IPX ncpd patches are in these are going into protinfo. */
 #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
-struct ipx_opt
-{
+struct ipx_opt {
        ipx_address             dest_addr;
        ipx_interface           *intrfc;
        unsigned short          port;
@@ -141,8 +132,7 @@ struct ipx_opt
 #endif
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-struct ipv6_pinfo
-{
+struct ipv6_pinfo {
        struct in6_addr         saddr;
        struct in6_addr         rcv_saddr;
        struct in6_addr         daddr;
@@ -213,7 +203,7 @@ struct tcp_opt {
        __u32   lrcvtime;       /* timestamp of last received data packet*/
        __u32   srtt;           /* smothed round trip time << 3         */
 
-       __u32   ato;            /* delayed ack timeout */
+       __u32   ato;            /* delayed ack timeout                  */
        __u32   snd_wl1;        /* Sequence for window update           */
 
        __u32   snd_wl2;        /* Ack sequence for update              */
@@ -231,12 +221,11 @@ struct tcp_opt {
        __u32   packets_out;    /* Packets which are "in flight"        */
        __u32   fackets_out;    /* Non-retrans SACK'd packets           */
        __u32   retrans_out;    /* Fast-retransmitted packets out       */
-       __u32   high_seq;       /* highest sequence number sent by onset of congestion */
+       __u32   high_seq;       /* snd_nxt at onset of congestion       */
 /*
  *     Slow start and congestion control (see also Nagle, and Karn & Partridge)
  */
        __u32   snd_ssthresh;   /* Slow start size threshold            */
-       __u16   snd_cwnd_cnt;
        __u8    dup_acks;       /* Consequetive duplicate acks seen from other end */
        __u8    delayed_acks;
 
@@ -276,7 +265,6 @@ struct tcp_opt {
        struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
        struct timer_list       probe_timer;            /* Probes       */
-       __u32   basertt;        /* Vegas baseRTT                        */
        __u32   window_clamp;   /* XXX Document this... -DaveM          */
        __u32   probes_out;     /* unanswered 0 window probes           */
        __u32   syn_seq;
@@ -287,7 +275,6 @@ struct tcp_opt {
        struct open_request     *syn_wait_queue;
        struct open_request     **syn_wait_last;
        int syn_backlog;
-
 };
 
        
@@ -336,12 +323,7 @@ struct tcp_opt {
 #define SOCK_DEBUG(sk, msg...) do { } while (0)
 #endif
 
-/*
- *  TCP will start to use the new protinfo while *still using the old* fields 
- */
-
-struct sock 
-{
+struct sock {
        /* This must be first. */
        struct sock             *sklist_next;
        struct sock             *sklist_prev;
@@ -350,28 +332,29 @@ struct sock
        struct sock             *bind_next;
        struct sock             **bind_pprev;
 
-       /* Main hash linkage for various protocol lookup tables. */
-       struct sock             *next;
-       struct sock             **pprev;
-
        /* Socket demultiplex comparisons on incoming packets. */
        __u32                   daddr;          /* Foreign IPv4 addr                    */
        __u32                   rcv_saddr;      /* Bound local IPv4 addr                */
-       int                     bound_dev_if;   /* Bound device index if != 0           */
+       __u16                   dport;          /* Destination port                     */
        unsigned short          num;            /* Local port                           */
+       int                     bound_dev_if;   /* Bound device index if != 0           */
+
+       /* Main hash linkage for various protocol lookup tables. */
+       struct sock             *next;
+       struct sock             **pprev;
+
        volatile unsigned char  state,          /* Connection state                     */
                                zapped;         /* In ax25 & ipx means not linked       */
        __u16                   sport;          /* Source port                          */
-       __u16                   dport;          /* Destination port                     */
 
-       unsigned short          family;
-       unsigned char           reuse,
-                               nonagle;
+       unsigned short          family;         /* Address family                       */
+       unsigned char           reuse,          /* SO_REUSEADDR setting                 */
+                               nonagle;        /* Disable Nagle algorithm?             */
 
-       int                     sock_readers;   /* user count                           */
-       int                     rcvbuf;
+       int                     sock_readers;   /* User count                           */
+       int                     rcvbuf;         /* Size of receive buffer in bytes      */
 
-       struct wait_queue       **sleep;
+       struct wait_queue       **sleep;        /* Sock wait queue                      */
        struct dst_entry        *dst_cache;     /* Destination cache                    */
        atomic_t                rmem_alloc;     /* Receive queue bytes committed        */
        struct sk_buff_head     receive_queue;  /* Incoming packets                     */
@@ -380,13 +363,12 @@ struct sock
        atomic_t                omem_alloc;     /* "o" is "option" or "other" */
        __u32                   saddr;          /* Sending source                       */
        unsigned int            allocation;     /* Allocation mode                      */
-       int                     sndbuf;
+       int                     sndbuf;         /* Size of send buffer in bytes         */
        struct sock             *prev;
 
-  /*
-   *   Not all are volatile, but some are, so we
-   *   might as well say they all are.
-   */
+       /* Not all are volatile, but some are, so we might as well say they all are.
+        * XXX Make this a flag word -DaveM
+        */
        volatile char           dead,
                                done,
                                urginline,
@@ -409,9 +391,9 @@ struct sock
 
        struct proto            *prot;
 
-/*
- *     mss is min(mtu, max_window) 
- */
+       /* mss is min(mtu, max_window)
+        * XXX Fix this, mtu only used in one TCP place and that is it -DaveM
       */
        unsigned short          mtu;       /* mss negotiated in the syn's */
        unsigned short          mss;       /* current eff. mss - can change */
        unsigned short          user_mss;  /* mss requested by user in ioctl */
@@ -451,13 +433,10 @@ struct sock
        struct sock_filter      *filter_data;
 #endif /* CONFIG_FILTER */
 
-/*
- *     This is where all the private (optional) areas that don't
- *     overlap will eventually live. 
- */
-
-       union
-       {
+       /* This is where all the private (optional) areas that don't
+        * overlap will eventually live. 
+        */
+       union {
                void *destruct_hook;
                struct unix_opt af_unix;
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
@@ -489,9 +468,7 @@ struct sock
 #endif
        } protinfo;             
 
-/* 
- *     IP 'private area' or will be eventually 
- */
+       /* IP 'private area' or will be eventually. */
        int                     ip_ttl;                 /* TTL setting */
        int                     ip_tos;                 /* TOS */
        unsigned                ip_cmsg_flags;
@@ -505,31 +482,18 @@ struct sock
        __u32                   ip_mc_addr;
        struct ip_mc_socklist   *ip_mc_list;            /* Group array */
 
-/*
- *     This part is used for the timeout functions (timer.c). 
- */
+       /* This part is used for the timeout functions (timer.c). */
        int                     timeout;        /* What are we waiting for? */
-       struct timer_list       timer;          /* This is the TIME_WAIT/receive timer
-                                                * when we are doing IP
-                                                */
+       struct timer_list       timer;          /* This is the sock cleanup timer. */
        struct timeval          stamp;
 
- /*
-  *    Identd 
-  */
-  
+       /* Identd */
        struct socket           *socket;
 
-  /*
-   *   RPC layer private data
-   */
+       /* RPC layer private data */
        void                    *user_data;
   
-  /*
-   *   Callbacks 
-   */
-   
+       /* Callbacks */
        void                    (*state_change)(struct sock *sk);
        void                    (*data_ready)(struct sock *sk,int bytes);
        void                    (*write_space)(struct sock *sk);
@@ -540,14 +504,11 @@ struct sock
        void                    (*destruct)(struct sock *sk);
 };
 
-/*
- *     IP protocol blocks we attach to sockets.
- *     socket layer -> transport layer interface
- *     transport -> network interface is defined by struct inet_proto
+/* IP protocol blocks we attach to sockets.
+ * socket layer -> transport layer interface
+ * transport -> network interface is defined by struct inet_proto
  */
-struct proto 
-{
+struct proto {
        /* These must be first. */
        struct sock             *sklist_next;
        struct sock             *sklist_prev;
@@ -609,16 +570,10 @@ struct proto
 #define TIME_DONE      7       /* Used to absorb those last few packets */
 #define TIME_PROBE0    8
 
-/*
- *     About 10 seconds 
- */
-
+/* About 10 seconds */
 #define SOCK_DESTROY_TIME (10*HZ)
 
-/*
- *     Sockets 0-1023 can't be bound to unless you are superuser 
- */
+/* Sockets 0-1023 can't be bound to unless you are superuser */
 #define PROT_SOCK      1024
 
 #define SHUTDOWN_MASK  3
index b5af990237c2eb4ef949efc0e6f59018fc4e12a7..01a95b5789ba6d1b8fafe308b2d1e6b9436ec736 100644 (file)
@@ -154,16 +154,16 @@ struct tcp_tw_bucket {
        struct sock             *sklist_prev;
        struct sock             *bind_next;
        struct sock             **bind_pprev;
-       struct sock             *next;
-       struct sock             **pprev;
        __u32                   daddr;
        __u32                   rcv_saddr;
-       int                     bound_dev_if;
+       __u16                   dport;
        unsigned short          num;
+       int                     bound_dev_if;
+       struct sock             *next;
+       struct sock             **pprev;
        unsigned char           state,
                                zapped;
        __u16                   sport;
-       __u16                   dport;
        unsigned short          family;
        unsigned char           reuse,
                                nonagle;
@@ -181,6 +181,43 @@ struct tcp_tw_bucket {
 
 extern kmem_cache_t *tcp_timewait_cachep;
 
+/* Socket demux engine toys. */
+#ifdef __BIG_ENDIAN
+#define TCP_COMBINED_PORTS(__sport, __dport) \
+       (((__u32)(__sport)<<16) | (__u32)(__dport))
+#else /* __LITTLE_ENDIAN */
+#define TCP_COMBINED_PORTS(__sport, __dport) \
+       (((__u32)(__dport)<<16) | (__u32)(__sport))
+#endif
+
+#if defined(__alpha__) || defined(__sparc_v9__)
+#ifdef __BIG_ENDIAN
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
+       __u64 __name = (((__u64)(__saddr))<<32)|((__u64)(__daddr));
+#else /* __LITTLE_ENDIAN */
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
+       __u64 __name = (((__u64)(__daddr))<<32)|((__u64)(__saddr));
+#endif /* __BIG_ENDIAN */
+#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((*((__u64 *)&((__sk)->daddr)))== (__cookie))  &&              \
+        ((*((__u32 *)&((__sk)->dport)))== (__ports))   &&              \
+        (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#else /* 32-bit arch */
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr)
+#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((__sk)->daddr                 == (__saddr))   &&              \
+        ((__sk)->rcv_saddr             == (__daddr))   &&              \
+        ((*((__u32 *)&((__sk)->dport)))== (__ports))   &&              \
+        (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#endif /* 64-bit arch */
+
+#define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif)                    \
+       (((*((__u32 *)&((__sk)->dport)))== (__ports))                           && \
+        ((__sk)->family                == AF_INET6)                            && \
+        !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.daddr, (__saddr))           && \
+        !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.rcv_saddr, (__daddr))       && \
+        (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+
 /* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
  * because the v6 tcp code to intialize a connection needs to interoperate
  * with the v4 code using the same variables.
@@ -303,14 +340,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 #define TCPOLEN_SACK_BASE_ALIGNED      4
 #define TCPOLEN_SACK_PERBLOCK          8
 
-/*
- *     TCP Vegas constants
- */
-
-#define TCP_VEGAS_ALPHA                2       /*  v_cong_detect_top_nseg */
-#define TCP_VEGAS_BETA         4       /*  v_cong_detect_bot_nseg */
-#define TCP_VEGAS_GAMMA                1       /*  v_exp_inc_nseg         */
-
 struct open_request;
 
 struct or_calltable {
@@ -682,6 +711,12 @@ struct tcp_skb_cb {
 
 #define TCP_SKB_CB(__skb)      ((struct tcp_skb_cb *)&((__skb)->cb[0]))
 
+/* We store the congestion window as a packet count, shifted by
+ * a factor so that implementing the 1/2 MSS ssthresh rules
+ * is easy.
+ */
+#define TCP_CWND_SHIFT 1
+
 /* This determines how many packets are "in the network" to the best
  * or our knowledge.  In many cases it is conservative, but where
  * detailed information is available from the receiver (via SACK
@@ -726,7 +761,8 @@ static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
            !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))
                nagle_check = 0;
 
-       return (nagle_check && tcp_packets_in_flight(tp) < tp->snd_cwnd &&
+       return (nagle_check &&
+               (tcp_packets_in_flight(tp) < (tp->snd_cwnd>>TCP_CWND_SHIFT)) &&
                !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
                tp->retransmits == 0);
 }
index 5bb9e7ff8868b1b45a351341d5cb851bf6a42e18..c9e0fff8d13ec24bdda5a35e19dc4dd8d5a7057f 100644 (file)
@@ -1144,6 +1144,13 @@ static int init(void * unused)
        smp_begin();
 #endif 
 
+#ifdef CONFIG_KMOD
+       {
+               extern int kmod_init(void);
+               kmod_init();
+       }
+#endif
+
 #ifdef CONFIG_UMSDOS_FS
        {
                /*
@@ -1179,13 +1186,6 @@ static int init(void * unused)
        }
 #endif
 
-#ifdef CONFIG_KMOD
-       {
-               extern int kmod_init(void);
-               kmod_init();
-       }
-#endif
-
        setup(1);
        
        if (open("/dev/console", O_RDWR, 0) < 0)
index c2ff9c85640f44ef4548dd5fa0cee2199fce5881..379c276955789cb3e71fab2c4d08e065eb91f11a 100644 (file)
@@ -14,7 +14,6 @@
 */
 int kmod_unload_delay = 60;
 char modprobe_path[256] = "/sbin/modprobe";
-static int kmod_running = 0;
 static char module_name[64] = "";
 static char * argv[] = { "modprobe", "-k", module_name, NULL, };
 static char * envp[] = { "HOME=/", "TERM=linux", NULL, };
@@ -42,7 +41,6 @@ int kmod_thread(void * data)
        current->pgrp = 1;
        sprintf(current->comm, "kmod");
        sigfillset(&current->blocked);
-       kmod_running = 1;
 
        /*
                This is the main kmod_thread loop.  It first sleeps, then
@@ -135,9 +133,6 @@ int request_module(const char * name)
                the module into module_name.  Once that is done, wake up
                kmod_thread.
        */
-       if(!kmod_running)
-               return 0;
-
        strncpy(module_name, name, sizeof(module_name));
        module_name[sizeof(module_name)-1] = '\0';
        wake_up(&kmod_queue);
index ad3c4a70690760d0a1c84407c8b49204a0d6c6e3..6f1101319f082277e03eb6c449f743c356926071 100644 (file)
@@ -389,7 +389,6 @@ EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__up);
-EXPORT_SYMBOL(securelevel);
 
 /* all busmice */
 EXPORT_SYMBOL(add_mouse_randomness);
index afc178c5ee5d9901fa5a155c0a0e6b54d0487543..d8242a428c791f27c87fff4a1cde6b84237ee95c 100644 (file)
@@ -54,7 +54,7 @@ static char log_buf[LOG_BUF_LEN];
 static unsigned long log_start = 0;
 static unsigned long logged_chars = 0;
 struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
-static int selected_console = 0;
+static int preferred_console = -1;
 
 /*
  *     Setup a list of consoles. Called from init/main.c
@@ -95,11 +95,13 @@ __initfunc(void console_setup(char *str, int *ints))
         */
        for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
                if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx)
+                         console_cmdline[i].index == idx) {
+                               preferred_console = i;
                                return;
+               }
        if (i == MAX_CMDLINECONSOLES)
                return;
-       selected_console = 1;
+       preferred_console = i;
        c = &console_cmdline[i];
        memcpy(c->name, name, sizeof(c->name));
        c->options = options;
@@ -336,13 +338,13 @@ void register_console(struct console * console)
         *      didn't select a console we take the first one
         *      that registers here.
         */
-       if (selected_console == 0) {
+       if (preferred_console < 0) {
                if (console->index < 0)
                        console->index = 0;
                if (console->setup == NULL ||
                    console->setup(console, NULL) == 0) {
-                       console->flags |= CON_ENABLED | CON_FIRST;
-                       selected_console = 1;
+                       console->flags |= CON_ENABLED | CON_CONSDEV;
+                       preferred_console = 0;
                }
        }
 
@@ -362,8 +364,8 @@ void register_console(struct console * console)
                        break;
                console->flags |= CON_ENABLED;
                console->index = console_cmdline[i].index;
-               if (i == 0)
-                       console->flags |= CON_FIRST;
+               if (i == preferred_console)
+                       console->flags |= CON_CONSDEV;
                break;
        }
 
@@ -374,7 +376,7 @@ void register_console(struct console * console)
         *      Put this console in the list - keep the
         *      preferred driver at the head of the list.
         */
-       if ((console->flags & CON_FIRST) || console_drivers == NULL) {
+       if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
                console->next = console_drivers;
                console_drivers = console;
        } else {
index 8d857680807bef669e2bb46a53effd6f4de2544e..f9246e78533be29af1c4e865bdd986be386d66a3 100644 (file)
@@ -47,7 +47,7 @@
  * kernel variables
  */
 
-int securelevel = 0;                   /* system security level */
+unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
 
 long tick = (1000000 + HZ/2) / HZ;     /* timer interrupt period */
 
index 0da7a07c8828996b7c4a4d1af301f6fc5b72389f..ed2d8fd6987c01937458a3c1051f5fc4ac2348be 100644 (file)
@@ -45,6 +45,9 @@ extern int sysctl_overcommit_memory;
 extern char modprobe_path[];
 extern int kmod_unload_delay;
 #endif
+#ifdef CONFIG_CHR_DEV_SG
+extern int sg_big_buff;
+#endif
 
 #ifdef __sparc__
 extern char reboot_command [];
@@ -52,8 +55,6 @@ extern char reboot_command [];
 
 static int parse_table(int *, int, void *, size_t *, void *, size_t,
                       ctl_table *, void **);
-static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
-                                   void *, size_t, void **);
 
 
 static ctl_table root_table[];
@@ -156,8 +157,6 @@ static ctl_table kern_table[] = {
         0644, NULL, &proc_dointvec},
        {KERN_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
         0444, NULL, &proc_dointvec},
-       {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
-        0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
         0644, NULL, &proc_dointvec},
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -183,6 +182,10 @@ static ctl_table kern_table[] = {
         0644, NULL, &proc_dostring, &sysctl_string },
        {KERN_KMOD_UNLOAD_DELAY, "kmod_unload_delay", &kmod_unload_delay,
        sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_CHR_DEV_SG
+       {KERN_NRFILE, "sg-big-buff", &sg_big_buff, sizeof (int),
+        0444, NULL, &proc_dointvec},
 #endif
        {0}
 };
@@ -408,29 +411,6 @@ int do_sysctl_strategy (ctl_table *table,
        return 0;
 }
 
-/*
- * This function only checks permission for changing the security level
- * If the tests are successful, the actual change is done by
- * do_sysctl_strategy
- */
-static int do_securelevel_strategy (ctl_table *table, 
-                                   int *name, int nlen,
-                                   void *oldval, size_t *oldlenp,
-                                   void *newval, size_t newlen, void **context)
-{
-       int level;
-
-       if (newval && newlen) {
-               if (newlen != sizeof (int))
-                       return -EINVAL;
-               if(copy_from_user (&level, newval, newlen))
-                       return -EFAULT;
-               if (level < securelevel && current->pid != 1)
-                       return -EPERM;
-       }
-       return 0;
-}
-
 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
                                               int insert_at_head)
 {
index d0270d58677ae1a3fa14b907a318b1678fbc025d..6b262b403df494876f9c64706a4ce0d41d301023 100644 (file)
@@ -208,12 +208,16 @@ void * vmalloc(unsigned long size)
        return addr;
 }
 
-int vread(char *buf, char *addr, int count)
+long vread(char *buf, char *addr, unsigned long count)
 {
        struct vm_struct **p, *tmp;
        char *vaddr, *buf_start = buf;
        int n;
 
+       /* Don't allow overflow */
+       if ((unsigned long) addr + count < count)
+               count = -(unsigned long) addr;
+
        for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
                vaddr = (char *) tmp->addr;
                while (addr < vaddr) {
index 2961ff3c6d000e0183a22d2359481015da360643..014453f8cec806f354c45cc57ab8be052fc18af1 100644 (file)
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     Fixes:
- *             Yury Shevchuk   :       Bridge with non bridging ports
+ * Fixes:
+ *     Yury Shevchuk   :       Bridge with non bridging ports
+ *     Jean-Rene Peulve: jr.peulve@aix.pacwan.net              Jan/Feb 98
+ *                     support Linux 2.0
+ *                     Handle Receive config bpdu
+ *                     kick mark_bh to send Spanning Tree pdus
+ *                     bridgeId comparison using htonl()
+ *                     make STP interoperable with other vendors
+ *                     wrong test in root_selection()
+ *                     add more STP debug info 
+ *                     some performance improvments
+ *                     do not clear bridgeId.mac  while setting priority
+ *                     do not reset port priority when starting bridge
+ *                     make port priority from user value and port number
+ *                     maintains user port state out of device state
+ *                     broacast/multicast storm limitation
+ *                     forwarding statistics
+ *                     stop br_tick when bridge is turn off
+ *                     add local MACs in avl_tree to forward up stack
+ *                     fake receive on right port for IP/ARP 
+ *                     ages tree even if packet does not cross bridge
+ *                     add BRCMD_DISPLAY_FDB (ioctl for now)
+ *
+ *     Alan Cox:       Merged Jean-Rene's stuff, reformatted stuff a bit
+ *                     so blame me first if its broken ;)
  *
  *     Todo:
  *             Don't bring up devices automatically. Start ports disabled
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <linux/version.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <net/br.h>
 
+#ifndef min
+#define min(a, b) (((a) <= (b)) ? (a) : (b))
+#endif
+
 static void transmit_config(int port_no);
 static int root_bridge(void);
 static int supersedes_port_info(int port_no, Config_bpdu *config);
@@ -80,7 +109,7 @@ static void br_init_port(int port_no);
 static void enable_port(int port_no);
 static void disable_port(int port_no);
 static void set_bridge_priority(bridge_id_t *new_bridge_id);
-static void set_port_priority(int port_no, unsigned short new_port_id);
+static void set_port_priority(int port_no);
 static void set_path_cost(int port_no, unsigned short path_cost);
 static void start_hello_timer(void);
 static void stop_hello_timer(void);
@@ -104,11 +133,12 @@ static int br_device_event(struct notifier_block *dnot, unsigned long event, voi
 static void br_tick(unsigned long arg);
 static int br_forward(struct sk_buff *skb, int port);  /* 3.7 */
 static int br_port_cost(struct device *dev);   /* 4.10.2 */
-static void br_bpdu(struct sk_buff *skb); /* consumes skb */
+static void br_bpdu(struct sk_buff *skb, int port); /* consumes skb */
 static int br_cmp(unsigned int *a, unsigned int *b);
 static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu);
 static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu);
 static int find_port(struct device *dev);
+static void br_add_local_mac(unsigned char *mac);
 static int br_flood(struct sk_buff *skb, int port);
 static int br_drop(struct sk_buff *skb);
 static int br_learn(struct sk_buff *skb, int port);    /* 3.8 */
@@ -116,8 +146,21 @@ static int br_learn(struct sk_buff *skb, int port);        /* 3.8 */
 static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 static Bridge_data     bridge_info;                      /* (4.5.3)     */
 Port_data       port_info[All_ports];            /* (4.5.5)     */
-Config_bpdu     config_bpdu[All_ports];
-Tcn_bpdu        tcn_bpdu[All_ports];
+
+/* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
+struct fdb     *newfdb[All_ports];
+int allocated_fdb_cnt = 0;
+
+/* broacast/multicast storm limitation */
+int max_mcast_per_period = MAX_MCAST_PER_PERIOD;
+int mcast_hold_time     = MCAST_HOLD_TIME;
+
+/* JRP: next two bpdu are copied to skbuff so we need only 1 of each */
+static Config_bpdu     config_bpdu;
+static Tcn_bpdu                tcn_bpdu;
+static unsigned char   port_priority[All_ports];
+static unsigned char   user_port_state[All_ports];
+
 static Timer    hello_timer;                     /* (4.5.4.1)   */
 static Timer    tcn_timer;                       /* (4.5.4.2)   */
 static Timer    topology_change_timer;           /* (4.5.4.3)   */
@@ -129,6 +172,7 @@ static Timer    hold_timer[All_ports];                /* (4.5.6.3)   */
 unsigned int fdb_aging_time = FDB_TIMEOUT; 
 
 struct br_stat br_stats;
+#define br_stats_cnt br_stats.packet_cnts
 
 static struct timer_list tl; /* for 1 second timer... */
 
@@ -154,23 +198,28 @@ static struct notifier_block br_dev_notifier={
 #define BR_PROTOCOL_HASH(x) (x % BR_MAX_PROTOCOLS)
 
 /* Checks if that protocol type is to be bridged */
+
 int br_protocol_ok(unsigned short protocol)
 {
        unsigned x;
        
        /* See if protocol statistics are to be kept */
        if (br_stats.flags & BR_PROT_STATS)
-       { for(x=0;x<BR_MAX_PROT_STATS &&
-            br_stats.prot_id[x]!=protocol && br_stats.prot_id[x];x++) ;
-         if (x<BR_MAX_PROT_STATS)
-         { br_stats.prot_id[x]=protocol;br_stats.prot_counter[x]++;
-         }
+       {
+               for(x=0;x<BR_MAX_PROT_STATS && br_stats.prot_id[x]!=protocol && br_stats.prot_id[x];x++);
+               if (x<BR_MAX_PROT_STATS)
+               {
+                       br_stats.prot_id[x]=protocol;br_stats.prot_counter[x]++;
+               }
        }
 
-       for (x=BR_PROTOCOL_HASH(protocol); br_stats.protocols[x]!=0;) {
-               if (br_stats.protocols[x]==protocol) return !br_stats.policy;
+       for (x=BR_PROTOCOL_HASH(protocol); br_stats.protocols[x]!=0;) 
+       {
+               if (br_stats.protocols[x]==protocol)
+                       return !br_stats.policy;
                x++;
-               if (x==BR_MAX_PROTOCOLS) x=0;
+               if (x==BR_MAX_PROTOCOLS)
+                       x=0;
        }
        return br_stats.policy;
 }
@@ -209,7 +258,7 @@ static int br_set_policy(int policy)
 /*
  * this section of code was graciously borrowed from the IEEE 802.1d
  * specification section 4.9.1 starting on pg 69.  It has been
- * modified somewhat to fit within out framework and structure.  It
+ * modified somewhat to fit within our framework and structure.  It
  * implements the spanning tree algorithm that is the heart of the
  * 802.1d bridging protocol.
  */
@@ -219,42 +268,44 @@ static void transmit_config(int port_no)    /* (4.6.1)     */
        if (hold_timer[port_no].active) {         /* (4.6.1.3.1)         */
                port_info[port_no].config_pending = TRUE;       /* (4.6.1.3.1)   */
        } else {                                  /* (4.6.1.3.2)         */
-               config_bpdu[port_no].type = BPDU_TYPE_CONFIG;
-               config_bpdu[port_no].root_id = bridge_info.designated_root;
+               config_bpdu.type = BPDU_TYPE_CONFIG;
+               config_bpdu.root_id = bridge_info.designated_root;
                /* (4.6.1.3.2(1)) */
-               config_bpdu[port_no].root_path_cost = bridge_info.root_path_cost;
+               config_bpdu.root_path_cost = bridge_info.root_path_cost;
                /* (4.6.1.3.2(2)) */
-               config_bpdu[port_no].bridge_id = bridge_info.bridge_id;
+               config_bpdu.bridge_id = bridge_info.bridge_id;
                /* (4.6.1.3.2(3)) */
-               config_bpdu[port_no].port_id = port_info[port_no].port_id;
+               config_bpdu.port_id = port_info[port_no].port_id;
                /*
                 * (4.6.1.3.2(4))
                 */
                if (root_bridge()) {
-                       config_bpdu[port_no].message_age = Zero;        /* (4.6.1.3.2(5)) */
+                       config_bpdu.message_age = Zero; /* (4.6.1.3.2(5)) */
                } else {
-                       config_bpdu[port_no].message_age
+                       config_bpdu.message_age
                                = message_age_timer[bridge_info.root_port].value
                                + Message_age_increment;        /* (4.6.1.3.2(6)) */
                }
 
-               config_bpdu[port_no].max_age = bridge_info.max_age;     /* (4.6.1.3.2(7)) */
-               config_bpdu[port_no].hello_time = bridge_info.hello_time;
-               config_bpdu[port_no].forward_delay = bridge_info.forward_delay;
-               config_bpdu[port_no].flags = 0;
-               config_bpdu[port_no].flags |=
-                       port_info[port_no].top_change_ack ? TOPOLOGY_CHANGE_ACK : 0;
-               /* (4.6.1.3.2(8)) */
+               config_bpdu.max_age = bridge_info.max_age;/* (4.6.1.3.2(7)) */
+               config_bpdu.hello_time = bridge_info.hello_time;
+               config_bpdu.forward_delay = bridge_info.forward_delay;
+               config_bpdu.top_change_ack = 
+                       port_info[port_no].top_change_ack;
+                                                       /* (4.6.1.3.2(8)) */
                port_info[port_no].top_change_ack = 0;
-               /* (4.6.1.3.2(8)) */
-               config_bpdu[port_no].flags |=
-                       bridge_info.top_change ? TOPOLOGY_CHANGE : 0;
-               /* (4.6.1.3.2(9)) */
 
-               send_config_bpdu(port_no, &config_bpdu[port_no]);
+               config_bpdu.top_change = 
+                       bridge_info.top_change;         /* (4.6.1.3.2(9)) */
+
+               send_config_bpdu(port_no, &config_bpdu);
                port_info[port_no].config_pending = FALSE;      /* (4.6.1.3.2(10)) */
                start_hold_timer(port_no);        /* (4.6.1.3.2(11)) */
        }
+/* JRP: we want the frame to be xmitted even if no other traffic.
+ *     net_bh() will do a dev_transmit() that kicks all devices
+ */
+       mark_bh(NET_BH);
 }
 
 static int root_bridge(void)
@@ -314,8 +365,7 @@ static void record_config_timeout_values(Config_bpdu *config)                 /* (4.6.3)     */
        bridge_info.max_age = config->max_age;    /* (4.6.3.3)   */
        bridge_info.hello_time = config->hello_time;
        bridge_info.forward_delay = config->forward_delay;
-       if (config->flags & TOPOLOGY_CHANGE)
-               bridge_info.top_change = 1;
+       bridge_info.top_change = config->top_change;
 }
 
 static void config_bpdu_generation(void)
@@ -353,8 +403,8 @@ static void transmit_tcn(void)
        int             port_no;
 
        port_no = bridge_info.root_port;
-       tcn_bpdu[port_no].type = BPDU_TYPE_TOPO_CHANGE;
-       send_tcn_bpdu(port_no, &tcn_bpdu[bridge_info.root_port]);       /* (4.6.6.3)     */
+       tcn_bpdu.type = BPDU_TYPE_TOPO_CHANGE;
+       send_tcn_bpdu(port_no, &tcn_bpdu);      /* (4.6.6.3)     */
 }
 
 static void configuration_update(void) /* (4.6.7) */
@@ -420,7 +470,7 @@ static void root_selection(void)
                                        )         /* (4.6.8.3.1(4)) */
                                       ||
                                       ((port_info[port_no].designated_port
-                                     = port_info[root_port].designated_port
+/* JRP: was missing an "=" ! */              == port_info[root_port].designated_port
                                         )
                                        &&
                                        (port_info[port_no].port_id
@@ -433,6 +483,10 @@ static void root_selection(void)
        bridge_info.root_port = root_port;        /* (4.6.8.3.1)         */
 
        if (root_port == No_port) {               /* (4.6.8.3.2)         */
+#ifdef DEBUG_STP
+               if (br_stats.flags & BR_DEBUG)
+                       printk(KERN_DEBUG "root_selection: becomes root\n");
+#endif
                bridge_info.designated_root = bridge_info.bridge_id;
                /* (4.6.8.3.2(1)) */
                bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */
@@ -450,6 +504,8 @@ static void designated_port_selection(void)
        int             port_no;
 
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.9.3)     */
+               if(port_info[port_no].state == Disabled)
+                       continue;
                if (designated_port(port_no)      /* (4.6.9.3.1)         */
                                ||
                                (
@@ -498,19 +554,32 @@ static void become_designated_port(int port_no)
 static void port_state_selection(void)
 {                                                /* (4.6.11) */
        int             port_no;
+       char            *state_str;
        for (port_no = One; port_no <= No_of_ports; port_no++) {
+
+               if(port_info[port_no].state == Disabled)
+                       continue;
                if (port_no == bridge_info.root_port) { /* (4.6.11.3.1) */
-                       port_info[port_no].config_pending = FALSE;      /* (4.6.11.3~1(1)) */
+                       state_str = "root";
+                       port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.1(1)) */
                        port_info[port_no].top_change_ack = 0;
                        make_forwarding(port_no); /* (4.6.11.3.1(2)) */
                } else if (designated_port(port_no)) {  /* (4.6.11.3.2) */
+                       state_str = "designated";
                        stop_message_age_timer(port_no);        /* (4.6.11.3.2(1)) */
                        make_forwarding(port_no); /* (4.6.11.3.2(2)) */
                } else {                          /* (4.6.11.3.3) */
+                       state_str = "blocking";
                        port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.3(1)) */
                        port_info[port_no].top_change_ack = 0;
                        make_blocking(port_no);   /* (4.6.11.3.3(2)) */
                }
+#ifdef DEBUG_STP
+               if (br_stats.flags & BR_DEBUG)
+                       printk(KERN_DEBUG "port_state_selection: becomes %s port %d\n",
+                               state_str, port_no);
+#endif
+               
        }
 
 }
@@ -525,6 +594,11 @@ static void make_forwarding(int port_no)
 
 static void topology_change_detection(void)
 {                                                /* (4.6.14)       */
+#ifdef DEBUG_STP
+       if ((br_stats.flags & BR_DEBUG)
+           && (bridge_info.top_change_detected == 0))
+               printk(KERN_DEBUG "topology_change_detected\n");
+#endif
        if (root_bridge()) {                      /* (4.6.14.3.1)   */
                bridge_info.top_change = 1;
                start_topology_change_timer();    /* (4.6.14.3.1(2)) */
@@ -532,12 +606,16 @@ static void topology_change_detection(void)
                transmit_tcn();                   /* (4.6.14.3.2(1)) */
                start_tcn_timer();                /* (4.6.14.3.2(2)) */
        }
-       bridge_info.top_change = 1;
+       bridge_info.top_change_detected = 1;    /* (4.6.14.3.3) */
 }
 
 static void topology_change_acknowledged(void)
 {                                                /* (4.6.15) */
-       bridge_info.top_change_detected = 0;
+#ifdef DEBUG_STP
+       if (br_stats.flags & BR_DEBUG)
+               printk(KERN_DEBUG "topology_change_acked\n");
+#endif
+       bridge_info.top_change_detected = 0;    /* (4.6.15.3.1) */
        stop_tcn_timer();                         /* (4.6.15.3.2) */
 }
 
@@ -574,10 +652,16 @@ static void set_port_state(int port_no, int state)
 
 static void received_config_bpdu(int port_no, Config_bpdu *config)               /* (4.7.1)     */
 {
-       int         root;
+       int root;
 
        root = root_bridge();
        if (port_info[port_no].state != Disabled) {
+
+#ifdef DEBUG_STP
+               if (br_stats.flags & BR_DEBUG)
+                       printk(KERN_DEBUG "received_config_bpdu: port %d\n",
+                               port_no);
+#endif
                if (supersedes_port_info(port_no, config)) {    /* (4.7.1.1)     *//* (4.
                                                                 * 6.2.2)        */
                        record_config_information(port_no, config);     /* (4.7.1.1.1)   */
@@ -588,7 +672,7 @@ static void received_config_bpdu(int port_no, Config_bpdu *config)            /* (4.7.1)
                        /* (4.6.11.2.1)  */
                        if ((!root_bridge()) && root) { /* (4.7.1.1.4)   */
                                stop_hello_timer();
-                               if (bridge_info.top_change_detected) {  /* (4.7.1.1.5~ */
+                               if (bridge_info.top_change_detected) {  /* (4.7.1.1.5 */
                                        stop_topology_change_timer();
                                        transmit_tcn(); /* (4.6.6.1)     */
                                        start_tcn_timer();
@@ -598,7 +682,7 @@ static void received_config_bpdu(int port_no, Config_bpdu *config)            /* (4.7.1)
                                record_config_timeout_values(config);   /* (4.7.1.1.6)   */
                                /* (4.6.3.2)     */
                                config_bpdu_generation();       /* (4.6.4.2.1)   */
-                               if (config->flags & TOPOLOGY_CHANGE_ACK) {      /* (4.7.1.1.7)    */
+                               if (config->top_change_ack) {   /* (4.7.1.1.7)    */
                                        topology_change_acknowledged(); /* (4.6.15.2)    */
                                }
                        }
@@ -612,6 +696,11 @@ static void received_config_bpdu(int port_no, Config_bpdu *config)           /* (4.7.1)
 static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                        /* (4.7.2)     */
 {
        if (port_info[port_no].state != Disabled) {
+#ifdef DEBUG_STP
+               if (br_stats.flags & BR_DEBUG)
+                       printk(KERN_DEBUG "received_tcn_bpdu: port %d\n",
+                               port_no);
+#endif
                if (designated_port(port_no)) {
                        topology_change_detection();    /* (4.7.2.1)     */
                        /* (4.6.14.2.1)  */
@@ -628,9 +717,14 @@ static void hello_timer_expiry(void)
 
 static void message_age_timer_expiry(int port_no) /* (4.7.4)    */
 {
-       int         root;
+       int root;
        root = root_bridge();
 
+#ifdef DEBUG_STP
+       if (br_stats.flags & BR_DEBUG)
+               printk(KERN_DEBUG "message_age_timer_expiry: port %d\n",
+                       port_no);
+#endif
        become_designated_port(port_no);          /* (4.7.4.1)   */
        /* (4.6.10.2.1)  */
        configuration_update();                   /* (4.7.4.2)   */
@@ -653,12 +747,17 @@ static void message_age_timer_expiry(int port_no) /* (4.7.4)       */
 
 static void forward_delay_timer_expiry(int port_no)    /* (4.7.5)       */
 {
-       if (port_info[port_no].state == Listening) {    /* (4.7.5.1)     */
+       if (port_info[port_no].state == Listening) 
+       {                                               /* (4.7.5.1)     */
                set_port_state(port_no, Learning);      /* (4.7.5.1.1)   */
                start_forward_delay_timer(port_no);     /* (4.7.5.1.2)   */
-       } else if (port_info[port_no].state == Learning) {      /* (4.7.5.2) */
+       }
+       else if (port_info[port_no].state == Learning) 
+       {
+                                                       /* (4.7.5.2) */
                set_port_state(port_no, Forwarding);    /* (4.7.5.2.1) */
-               if (designated_for_some_port()) { /* (4.7.5.2.2) */
+               if (designated_for_some_port()) 
+               {                                       /* (4.7.5.2.2) */
                        topology_change_detection();    /* (4.6.14.2.2) */
 
                }
@@ -667,13 +766,15 @@ static void forward_delay_timer_expiry(int port_no)       /* (4.7.5)       */
 
 static int designated_for_some_port(void)
 {
-       int             port_no;
-
+       int port_no;
 
-       for (port_no = One; port_no <= No_of_ports; port_no++) {
+       for (port_no = One; port_no <= No_of_ports; port_no++) 
+       {
+               if(port_info[port_no].state == Disabled)
+                       continue;
                if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
-                               bridge_info.bridge_id.BRIDGE_ID) == 0)
-                       ) {
+                               bridge_info.bridge_id.BRIDGE_ID) == 0)
+               {
                        return (TRUE);
                }
        }
@@ -688,26 +789,38 @@ static void tcn_timer_expiry(void)
 
 static void topology_change_timer_expiry(void)
 {                                                /* (4.7.7)     */
-       bridge_info.top_change_detected = 0;
+       bridge_info.top_change_detected = 0;    /* (4.7.7.1) */
        bridge_info.top_change = 0;
          /* (4.7.7.2)   */
 }
 
 static void hold_timer_expiry(int port_no)       /* (4.7.8)     */
 {
-       if (port_info[port_no].config_pending) {
+       if (port_info[port_no].config_pending) 
+       {
                transmit_config(port_no);         /* (4.7.8.1)   */
        }                                         /* (4.6.1.2.3)         */
 }
 
 __initfunc(void br_init(void))
 {                                                /* (4.8.1)     */
-       int             port_no;
+       int port_no;
+
+       printk(KERN_INFO "Ethernet Bridge 005 for NET3.037 (Linux 2.1)\n");
+
+       /*
+        * Form initial topology change time.
+        * The topology change timer is only used if this is the root bridge.
+        */
+       
+       bridge_info.topology_change_time = BRIDGE_MAX_AGE + BRIDGE_FORWARD_DELAY;       /* (4.5.3.13) */
 
-       printk(KERN_INFO "Ethernet Bridge 003 for NET3.037 (Linux 2.1)\n");
        bridge_info.designated_root = bridge_info.bridge_id;    /* (4.8.1.1)     */
        bridge_info.root_path_cost = Zero;
        bridge_info.root_port = No_port;
+#ifdef DEBUG_STP
+       printk(KERN_INFO "br_init: becomes root\n");
+#endif
 
        bridge_info.bridge_max_age = BRIDGE_MAX_AGE;
        bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME;
@@ -722,17 +835,22 @@ __initfunc(void br_init(void))
        bridge_info.top_change = 0;
        stop_tcn_timer();
        stop_topology_change_timer();
+       memset(newfdb, 0, sizeof(newfdb));
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.1.4) */
+               /* initial state = Enable */
+               user_port_state[port_no] = ~Disabled;
+               port_priority[port_no] = 128;
                br_init_port(port_no);
                disable_port(port_no);
        }
+#if 0 /* JRP: We are not UP ! Wait for the start command */
        port_state_selection();                   /* (4.8.1.5)   */
        config_bpdu_generation();                 /* (4.8.1.6)   */
-       
        /* initialize system timer */
        tl.expires = jiffies+HZ;        /* 1 second */
        tl.function = br_tick;
        add_timer(&tl);
+#endif 
 
        register_netdevice_notifier(&br_dev_notifier);
        br_stats.flags = 0; /*BR_UP | BR_DEBUG*/;       /* enable bridge */
@@ -741,8 +859,14 @@ __initfunc(void br_init(void))
        /*start_hello_timer();*/
 }
 
+static inline unsigned short make_port_id(int port_no)
+{
+        return (port_priority[port_no] << 8) | port_no;
+}
+
 static void br_init_port(int port_no)
 {
+       port_info[port_no].port_id = make_port_id(port_no);
        become_designated_port(port_no);          /* (4.8.1.4.1) */
        set_port_state(port_no, Blocking);        /* (4.8.1.4.2)    */
        port_info[port_no].top_change_ack = 0;
@@ -787,10 +911,12 @@ static void set_bridge_priority(bridge_id_t *new_bridge_id)
                                                  /* (4.8.4)     */
 {
 
-       int         root;
-       int             port_no;
+       int root;
+       int port_no;
        root = root_bridge();
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.4.2) */
+               if(port_info[port_no].state == Disabled)
+                       continue;
                if (designated_port(port_no)) {
                        port_info[port_no].designated_bridge = *new_bridge_id;
                }
@@ -810,9 +936,10 @@ static void set_bridge_priority(bridge_id_t *new_bridge_id)
        }
 }
 
-static void set_port_priority(int port_no, unsigned short new_port_id)
+static void set_port_priority(int port_no)
                                                  /* (4.8.5)     */
-{
+{int new_port_id = make_port_id(port_no);
+
        if (designated_port(port_no)) {           /* (4.8.5.2)   */
                port_info[port_no].designated_port = new_port_id;
        }
@@ -825,7 +952,8 @@ static void set_port_priority(int port_no, unsigned short new_port_id)
                         < port_info[port_no].designated_port
 
                         )
-               ) {
+               ) 
+       {
                become_designated_port(port_no);  /* (4.8.5.4.1) */
                port_state_selection();           /* (4.8.5.4.2) */
        }
@@ -841,27 +969,33 @@ static void set_path_cost(int port_no, unsigned short path_cost)
 
 static void br_tick(unsigned long arg)
 {
-       int             port_no;
+       int port_no;
+
+       if(!(br_stats.flags & BR_UP))
+               return;                  /* JRP: we have been shot down */
 
-       if (hello_timer_expired()) {
+       if (hello_timer_expired())
                hello_timer_expiry();
-       }
-       if (tcn_timer_expired()) {
+
+       if (tcn_timer_expired())
                tcn_timer_expiry();
-       }
-       if (topology_change_timer_expired()) {
+
+       if (topology_change_timer_expired())
                topology_change_timer_expiry();
-       }
-       for (port_no = One; port_no <= No_of_ports; port_no++) {
-               if (forward_delay_timer_expired(port_no)) {
+
+       for (port_no = One; port_no <= No_of_ports; port_no++) 
+       {
+               if(port_info[port_no].state == Disabled)
+                       continue;
+
+               if (forward_delay_timer_expired(port_no)) 
                        forward_delay_timer_expiry(port_no);
-               }
-               if (message_age_timer_expired(port_no)) {
+
+               if (message_age_timer_expired(port_no))
                        message_age_timer_expiry(port_no);
-               }
-               if (hold_timer_expired(port_no)) {
+
+               if (hold_timer_expired(port_no))
                        hold_timer_expiry(port_no);
-               }
        }
        /* call me again sometime... */
        tl.expires = jiffies+HZ;        /* 1 second */
@@ -882,7 +1016,8 @@ static void stop_hello_timer(void)
 
 static int hello_timer_expired(void)
 {
-       if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) {
+       if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) 
+       {
                hello_timer.active = FALSE;
                return (TRUE);
        }
@@ -902,8 +1037,8 @@ static void stop_tcn_timer(void)
 
 static int tcn_timer_expired(void)
 {
-       if (tcn_timer.active && (++tcn_timer.value >=
-                                bridge_info.bridge_hello_time)) {
+       if (tcn_timer.active && (++tcn_timer.value >= bridge_info.bridge_hello_time)) 
+       {
                tcn_timer.active = FALSE;
                return (TRUE);
        }
@@ -925,9 +1060,8 @@ static void stop_topology_change_timer(void)
 static int topology_change_timer_expired(void)
 {
        if (topology_change_timer.active
-                       && (++topology_change_timer.value
-                           >= bridge_info.topology_change_time
-                           )) {
+               && (++topology_change_timer.value >= bridge_info.topology_change_time )) 
+       {
                topology_change_timer.active = FALSE;
                return (TRUE);
        }
@@ -947,8 +1081,8 @@ static void stop_message_age_timer(int port_no)
 
 static int message_age_timer_expired(int port_no)
 {
-       if (message_age_timer[port_no].active &&
-             (++message_age_timer[port_no].value >= bridge_info.max_age)) {
+       if (message_age_timer[port_no].active && (++message_age_timer[port_no].value >= bridge_info.max_age)) 
+       {
                message_age_timer[port_no].active = FALSE;
                return (TRUE);
        }
@@ -968,12 +1102,12 @@ static void stop_forward_delay_timer(int port_no)
 
 static int forward_delay_timer_expired(int port_no)
 {
-               if (forward_delay_timer[port_no].active &&
-                               (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) {
-                       forward_delay_timer[port_no].active = FALSE;
-                       return (TRUE);
-               }
-               return (FALSE);
+       if (forward_delay_timer[port_no].active && (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) 
+       {
+               forward_delay_timer[port_no].active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
 }
 
 static void start_hold_timer(int port_no)
@@ -990,7 +1124,8 @@ static void stop_hold_timer(int port_no)
 static int hold_timer_expired(int port_no)
 {
        if (hold_timer[port_no].active &&
-                  (++hold_timer[port_no].value >= bridge_info.hold_time)) {
+                  (++hold_timer[port_no].value >= bridge_info.hold_time)) 
+       {
                hold_timer[port_no].active = FALSE;
                return (TRUE);
        }
@@ -998,113 +1133,112 @@ static int hold_timer_expired(int port_no)
 
 }
 
-static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
+static struct sk_buff *alloc_bridge_skb(int port_no, int pdu_size, char *pdu_name)
 {
        struct sk_buff *skb;
        struct device *dev = port_info[port_no].dev;
-       int size;
        struct ethhdr *eth;
-       
-       if (port_info[port_no].state == Disabled) {
-               printk(KERN_DEBUG "send_config_bpdu: port %i not valid\n",port_no);
-               return(-1);
+       int size = dev->hard_header_len + BRIDGE_LLC1_HS + pdu_size;
+       unsigned char *llc_buffer;
+       int pad_size = 60 - size; 
+       size = 60;      /* minimum Ethernet frame - CRC */
+
+       if (port_info[port_no].state == Disabled) 
+       {
+               printk(KERN_DEBUG "send_%s_bpdu: port %i not valid\n", pdu_name, port_no);
+               return NULL;
        }
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (skb == NULL) 
+       {
+               printk(KERN_DEBUG "send_%s_bpdu: no skb available\n", pdu_name);
+               return NULL;
+       }
+       skb->dev = dev;
+       skb->mac.raw = skb->h.raw = skb_put(skb,size);
+       memset(skb->h.raw + 60 - pad_size, 0xa5, pad_size);
+       eth = skb->mac.ethernet;
+       memcpy(eth->h_dest, bridge_ula, ETH_ALEN);
+       memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
+       if (br_stats.flags & BR_DEBUG)
+               printk("send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       pdu_name,
+                       port_no,
+                       eth->h_source[0],
+                       eth->h_source[1],
+                       eth->h_source[2],
+                       eth->h_source[3],
+                       eth->h_source[4],
+                       eth->h_source[5]);
+#if 0
+ /* 8038 is used in older DEC spanning tree protocol which uses a
+  * different pdu layout as well
+  */
+       eth->h_proto = htons(0x8038);
+#endif
+       eth->h_proto = htons(pdu_size + BRIDGE_LLC1_HS);
+  
+       skb->h.raw += skb->dev->hard_header_len;
+       llc_buffer = skb->h.raw;
+       *llc_buffer++ = BRIDGE_LLC1_DSAP;
+       *llc_buffer++ = BRIDGE_LLC1_SSAP;
+       *llc_buffer++ = BRIDGE_LLC1_CTRL;
+       /* set h.raw to where the bpdu starts */
+       skb->h.raw += BRIDGE_LLC1_HS;
+  
+       /* mark that we've been here... */
+       skb->pkt_bridged = IS_BRIDGED;
+       return skb;
+}
+static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
+{
+       struct sk_buff *skb;
        
-       if (br_stats.flags & BR_DEBUG)
-               printk("send_config_bpdu: ");
        /*
-        * create and send the message
+        *      Create and send the message
         */
-       size = dev->hard_header_len + sizeof(Config_bpdu);
-       skb = alloc_skb(size, GFP_ATOMIC);
-       if (skb == NULL) 
-       {
-               printk(KERN_DEBUG "send_config_bpdu: no skb available\n");
+        
+       skb = alloc_bridge_skb(port_no, BRIDGE_BPDU_8021_CONFIG_SIZE,
+                               "config");
+       if (skb == NULL)
                return(-1);
-       }
-       skb->dev = dev;
-       skb->mac.raw = skb->h.raw = skb_put(skb, size);
-       eth = skb->mac.ethernet;
-       memcpy(eth->h_dest, bridge_ula, ETH_ALEN);
-       memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
-       if (br_stats.flags & BR_DEBUG)
-               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
-                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-                       port_no,
-                       eth->h_source[0],
-                       eth->h_source[1],
-                       eth->h_source[2],
-                       eth->h_source[3],
-                       eth->h_source[4],
-                       eth->h_source[5],
-                       eth->h_dest[0],
-                       eth->h_dest[1],
-                       eth->h_dest[2],
-                       eth->h_dest[3],
-                       eth->h_dest[4],
-                       eth->h_dest[5]);
-       eth->h_proto = htons(0x8038);
 
-       skb->h.raw += skb->dev->hard_header_len;
-       memcpy(skb->h.raw, config_bpdu, sizeof(Config_bpdu));
+       /* copy fields before "flags" */
+       memcpy(skb->h.raw, config_bpdu, BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
 
-       /* won't get bridged again... */
-       skb->pkt_bridged = IS_BRIDGED;
-       skb->dev=dev;
-       dev_queue_xmit(skb);
-       return(0);
-}
+       /* build the "flags" field */
+       *(skb->h.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) = 0;
+       if (config_bpdu->top_change_ack)
+               *(skb->h.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x80;
+       if (config_bpdu->top_change)
+               *(skb->h.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x01;
+
+       config_bpdu_hton(config_bpdu);
+       /* copy the rest */
+       memcpy(skb->h.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET+1,
+                (char*)&(config_bpdu->root_id),
+                BRIDGE_BPDU_8021_CONFIG_SIZE-1-BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
 
+       dev_queue_xmit(skb);
+       return(0);
+}
+  
 static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
 {
        struct sk_buff *skb;
-       struct device *dev = port_info[port_no].dev;
-       int size;
-       struct ethhdr *eth;
-       
-       if (port_info[port_no].state == Disabled) {
-               printk(KERN_DEBUG "send_tcn_bpdu: port %i not valid\n",port_no);
-               return(-1);
-               }
-       if (br_stats.flags & BR_DEBUG)
-               printk("send_tcn_bpdu: ");
-       size = sizeof(Tcn_bpdu) + dev->hard_header_len;
-       skb = alloc_skb(size, GFP_ATOMIC);
-       if (skb == NULL) {
-               printk(KERN_DEBUG "send_tcn_bpdu: no skb available\n");
-               return(-1);
-               }
-       skb->dev = dev;
-       skb->mac.raw = skb->h.raw = skb_put(skb,size);
-       eth = skb->mac.ethernet;
-       memcpy(eth->h_dest, bridge_ula, ETH_ALEN);
-       memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
-       if (br_stats.flags & BR_DEBUG)
-               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
-                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-                       port_no,
-                       eth->h_source[0],
-                       eth->h_source[1],
-                       eth->h_source[2],
-                       eth->h_source[3],
-                       eth->h_source[4],
-                       eth->h_source[5],
-                       eth->h_dest[0],
-                       eth->h_dest[1],
-                       eth->h_dest[2],
-                       eth->h_dest[3],
-                       eth->h_dest[4],
-                       eth->h_dest[5]);
-       eth->h_proto = htons(0x8038);
-
-       skb->h.raw += skb->dev->hard_header_len;
-       memcpy(skb->h.raw, bpdu, sizeof(Tcn_bpdu));
-
-       /* mark that we've been here... */
-       skb->pkt_bridged = IS_BRIDGED;
-       skb->dev=dev;
-       dev_queue_xmit(skb);
-       return(0);
+       
+       skb = alloc_bridge_skb(port_no, sizeof(Tcn_bpdu), "tcn");
+       if (skb == NULL)
+               return(-1);
+  
+       memcpy(skb->h.raw, bpdu, sizeof(Tcn_bpdu));
+  
+       dev_queue_xmit(skb);
+       return(0);
 }
 
 static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
@@ -1116,52 +1250,59 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        if (dev->flags & IFF_LOOPBACK)
                return(NOTIFY_DONE);
 
-       switch (event) {
-       case NETDEV_DOWN:
-               if (br_stats.flags & BR_DEBUG)
-                       printk("br_device_event: NETDEV_DOWN...\n");
-               /* find our device and mark it down */
-               for (i = One; i <= No_of_ports; i++) {
-                       if (port_info[i].dev == dev) {
-                               disable_port(i);
-                               return NOTIFY_DONE;
-                               break;
+       switch (event) 
+       {
+               case NETDEV_DOWN:
+                       if (br_stats.flags & BR_DEBUG)
+                               printk(KERN_DEBUG "br_device_event: NETDEV_DOWN...\n");
+                       /* find our device and mark it down */
+                       for (i = One; i <= No_of_ports; i++) 
+                       {
+                               if (port_info[i].dev == dev) 
+                               {
+                                       disable_port(i);
+                                       return NOTIFY_DONE;
+                                       break;
+                               }
                        }
-               }
-               break;
-       case NETDEV_UP:
-               if (br_stats.flags & BR_DEBUG)
-                       printk("br_device_event: NETDEV_UP...\n");
-               /* Only handle ethernet ports */
-               if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
-                       return NOTIFY_DONE;
-               /* look up an unused device and enable it */
-               for (i = One; i <= No_of_ports; i++) {
-                       if ((port_info[i].dev == (struct device *)0) ||
-                               (port_info[i].dev == dev)) {
-                               port_info[i].dev = dev;
-                               enable_port(i);
-                               set_path_cost(i, br_port_cost(dev));
-                               set_port_priority(i, 128); 
-                               port_info[i].port_id = i;
-                               /* set bridge addr from 1st device addr */
-                               if ((bridge_info.bridge_id.BRIDGE_ID[0] == 0) &&
-                                               (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) {
-                                       memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6);
-                                       bridge_info.bridge_id.BRIDGE_PRIORITY = port_info[i].port_id;
-                                       set_bridge_priority(&bridge_info.bridge_id);
-                               }       
-                               make_forwarding(i);
+                       break;
+               case NETDEV_UP:
+                       if (br_stats.flags & BR_DEBUG)
+                               printk(KERN_DEBUG "br_device_event: NETDEV_UP...\n");
+                       /* Only handle ethernet ports */
+                       if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
                                return NOTIFY_DONE;
-                               break;
+                       /* look up an unused device and enable it */
+                       for (i = One; i <= No_of_ports; i++) 
+                       {
+                               if (port_info[i].dev == NULL || port_info[i].dev == dev) 
+                               {
+                                       port_info[i].dev = dev;
+                                       port_info[i].port_id = i;
+                                       /* set bridge addr from 1st device addr */
+                                       if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) &&
+                                               (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) 
+                                       {
+                                               memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6);
+                                               if(bridge_info.bridge_id.BRIDGE_PRIORITY == 0)
+                                                       bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768);
+                                               set_bridge_priority(&bridge_info.bridge_id);
+                                       }
+                                       br_add_local_mac(dev->dev_addr);
+                                       if((br_stats.flags & BR_UP) &&
+                                               (user_port_state[i] != Disabled)) 
+                                       {
+                                               /* don't start if user said so */
+                                                       enable_port(i);
+                                               set_path_cost(i, br_port_cost(dev));
+                                               set_port_priority(i); 
+                                               make_forwarding(i);
+                                       }
+                                       return NOTIFY_DONE;
+                                       break;
+                               }
                        }
-               }
-               break;
-#if 0
-       default:
-               printk("br_device_event: unknown event [%x]\n",
-                       (unsigned int)event);
-#endif                 
+                       break;
        }
        return NOTIFY_DONE;
 }
@@ -1175,10 +1316,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 int br_receive_frame(struct sk_buff *skb)      /* 3.5 */
 {
        int port;
+       Port_data  *p;
        struct ethhdr *eth;
        
-       if (br_stats.flags & BR_DEBUG)
-               printk("br_receive_frame: ");
        /* sanity */
        if (!skb) {
                printk(KERN_CRIT "br_receive_frame: no skb!\n");
@@ -1189,88 +1329,79 @@ int br_receive_frame(struct sk_buff *skb)       /* 3.5 */
 
        /* check for loopback */
        if (skb->dev->flags & IFF_LOOPBACK)
-               return(0);
+               return 0 ;
 
        port = find_port(skb->dev);
        
+       if(!port)
+               return 0;
+       
        skb->h.raw = skb->mac.raw;
        eth = skb->mac.ethernet;
-       if (br_stats.flags & BR_DEBUG)
-               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
-                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
-                       port,
-                       eth->h_source[0],
-                       eth->h_source[1],
-                       eth->h_source[2],
-                       eth->h_source[3],
-                       eth->h_source[4],
-                       eth->h_source[5],
-                       eth->h_dest[0],
-                       eth->h_dest[1],
-                       eth->h_dest[2],
-                       eth->h_dest[3],
-                       eth->h_dest[4],
-                       eth->h_dest[5]);
+       p = &port_info[port];
+       if(p->state == Disabled) 
+       {
+               /* We are here if BR_UP even if this port is Disabled.
+                * Send everything up
+                */
+               skb->pkt_type = PACKET_HOST;
+               ++br_stats_cnt.port_disable_up_stack;
+               return(0);      /* pass frame up our stack (this will */
+                               /* happen in net_bh() in dev.c) */
+       }
+       /* Here only if not disable.
+        * Remark: only frames going up will show up in NIT (tcpdump)
+        */
 
-       if (!port) {
-               if(br_stats.flags&BR_DEBUG)
-                       printk("\nbr_receive_frame: no port!\n");
-               return(0);
+       /* JRP: even if port is Blocking we need to process the Spanning Tree
+        * frames to keep the port in that state
+        */
+       if (memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) 
+       {
+               ++br_stats_cnt.rcv_bpdu;
+               br_bpdu(skb, port); /* br_bpdu consumes skb */
+               return(1);
        }
-
-       switch (port_info[port].state) 
+       switch (p->state) 
        {
                case Learning:
-                       (void) br_learn(skb, port);     /* 3.8 */
+                       if(br_learn(skb, port)) 
+                       {       /* 3.8 */
+                               ++br_stats_cnt.drop_multicast;
+                               return br_drop(skb);
+                       }
                        /* fall through */
                case Listening:
-                       /* process BPDUs */
-                       if (memcmp(eth->h_dest, bridge_ula, 6) == 0) {
-                               br_bpdu(skb);
-                               return(1); /* br_bpdu consumes skb */
-                       }
                        /* fall through */
                case Blocking:
-                       /* fall through */
-               case Disabled:
-                       /* should drop frames, but for now, we let
-                        * them get passed up to the next higher layer
+                       ++br_stats_cnt.notForwarding;
                        return(br_drop(skb));   
-                        */
-                       return(0);      /* pass frame up stack */
+               /*
+               case Disabled: is now handled before this switch !
+               Keep the break to allow GCC to use a jmp table.
+                */
                        break;
                case Forwarding:
-                       (void) br_learn(skb, port);     /* 3.8 */
-                       /* process BPDUs */
-                       if (memcmp(eth->h_dest, bridge_ula, 
-                                       ETH_ALEN) == 0) 
-                       {
-                               /*printk("frame bpdu processor for me!!!\n");*/
-                               br_bpdu(skb);
-                               return(1); /* br_bpdu consumes skb */
-                       }
-                       /* is frame for me? */  
-                       if (memcmp(eth->h_dest, 
-                                       port_info[port].dev->dev_addr, 
-                                       ETH_ALEN) == 0) 
-                       {
-                               /* Packet is for us */
-                               skb->pkt_type = PACKET_HOST;
-                               return(0);      /* pass frame up our stack (this will */
-                                               /* happen in net_bh() in dev.c) */
+                       if(br_learn(skb, port)) {       /* 3.8 */
+                               ++br_stats_cnt.drop_multicast;
+                               return br_drop(skb);
                        }
                        /* Now this frame came from one of bridged
-                          ports, and it appears to be not for me;
-                          this means we should attempt to forward it.
-                          But actually this frame can still be for me
-                          [as well] if it is destined to one of our
-                          multicast groups.  br_forward() will not
-                          consume the frame if this is the case */
+                          ports this means we should attempt to forward it.
+                          JRP: local addresses are now in the AVL tree,
+                          br_forward will pass frames up if it matches
+                          one of our local MACs or if it is a multicast
+                          group address.
+                          br_forward() will not consume the frame if this
+                          is the case */
                        return(br_forward(skb, port));
                default:
                        printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
-                               port, port_info[port].state);
-                       return(0);      /* pass frame up stack? */
+                               port, p->state);
+                       ++br_stats_cnt.unknown_state;
+                       return(br_drop(skb));   /* discard frame */
        }
 }
 
@@ -1304,15 +1435,17 @@ int br_tx_frame(struct sk_buff *skb)    /* 3.5 */
 
        /* if bridging is not enabled on the port we are going to send
            to, we have nothing to do with this frame, hands off */
-       if (! find_port(skb->dev))
+       if (((port=find_port(skb->dev))==0)||(port_info[port].state==Disabled)) {
+               ++br_stats_cnt.port_disable;
                return(0);
-
+       }
+       ++br_stats_cnt.port_not_disable;
        skb->mac.raw = skb->h.raw = skb->data;
        eth = skb->mac.ethernet;
-       port = 0;       /* an impossible port */        
+       port = 0;       /* an impossible port (locally generated) */    
        if (br_stats.flags & BR_DEBUG)
-               printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x\
-                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+               printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x"
+                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
                        port,
                        eth->h_source[0],
                        eth->h_source[1],
@@ -1329,55 +1462,135 @@ int br_tx_frame(struct sk_buff *skb)   /* 3.5 */
        return(br_forward(skb, port));
 }
 
+static void br_add_local_mac(unsigned char *mac)
+{
+       struct fdb *f;
+       f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
+       if (!f) 
+       {
+               printk(KERN_CRIT "br_add_local_mac: unable to malloc fdb\n");
+               return;
+       }
+       f->port = 0;    /* dest port == 0 =>local */
+       memcpy(f->ula, mac, 6);
+       f->timer = 0;   /* will not aged anyway */
+       f->flags = 0;   /* not valid => br_forward special route */
+       /*
+        * add entity to AVL tree.  If entity already
+        * exists in the tree, update the fields with
+        * what we have here.
+        */
+       if (br_avl_insert(f) != NULL) 
+       {
+               /* Already in */
+               kfree(f);
+       }
+}
+
+/* Avoid broadcast loop by limiting the number of broacast frames per
+ * period. The idea is to limit this per source
+ * returns: 0 if limit is not reached
+ *          1 if frame should be dropped
+ */
+
+static inline int mcast_quench(struct fdb *f)
+{
+       if(f->mcast_count++ == 0) /* first time */
+               f->mcast_timer = jiffies;
+       else {
+               if(f->mcast_count > max_mcast_per_period) {
+                       if(jiffies > (f->mcast_timer + mcast_hold_time))
+                               f->mcast_count = 0;
+                       else    return 1;
+               }
+       }
+       return 0;
+}
+
 /*
  * this routine returns 0 when it learns (or updates) from the
- * frame, and -1 if the frame is simply discarded due to port
- * state or lack of resources...
+ * frame, and 1 if we must dropped the frame.
  */
 
 static int br_learn(struct sk_buff *skb, int port)     /* 3.8 */
 {
-       struct fdb *f;
+       struct fdb *f, *oldfdb;
+       Port_data  *p = &port_info[port];
+       struct ethhdr *eth = skb->mac.ethernet;
 
-       switch (port_info[port].state) {
-               case Listening:
-               case Blocking:
-               case Disabled:
-               default:
-                       return(-1);
-                       /* break; */
-               case Learning:
-               case Forwarding:
-                       /* don't keep group addresses in the tree */
-                       if (skb->mac.ethernet->h_source[0] & 0x01)
-                               return(-1);
-                       
-                       f = (struct fdb *)kmalloc(sizeof(struct fdb), 
-                               GFP_ATOMIC);
+       /* JRP: no reason to check port state again. We are called by
+        * br_receive_frame() only when in Learning or Forwarding
+        * Remark: code not realigned yet to keep diffs smaller
+        */
 
-                       if (!f) {
-                               printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
-                               return(-1);
-                       }
-                       f->port = port; /* source port */
-                       memcpy(f->ula, skb->mac.ethernet->h_source, 6);
-                       f->timer = CURRENT_TIME;
-                       f->flags = FDB_ENT_VALID;
-                       /*
-                        * add entity to AVL tree.  If entity already
-                        * exists in the tree, update the fields with
-                        * what we have here.
-                        */
-                       if (br_avl_insert(f) == 0) { /* update */
-                               kfree(f);
-                               return(0);
-                       }
-                       /* add to head of port chain */
-                       f->fdb_next = port_info[port].fdb;
-                       port_info[port].fdb = f;
-                       return(0);
-                       /* break */
+       /* don't keep group addresses in the tree */
+       if (eth->h_source[0] & 0x01)
+               return 0;
+
+       if((f= newfdb[port]) == NULL) 
+       {
+               newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
+               if (!f) 
+               {
+                       printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
+                       return(-1); /* this drop the frame */
+               }
+       }
+       f->port = port; /* source port */
+       memcpy(f->ula, eth->h_source, 6);
+       f->timer = CURRENT_TIME;
+       f->flags = FDB_ENT_VALID;
+       /*
+        * add entity to AVL tree.  If entity already
+        * exists in the tree, update the fields with
+        * what we have here.
+        */
+       if ((oldfdb = br_avl_insert(f))) 
+       {
+               /* update if !NULL */
+               if((eth->h_dest[0] & 0x01) &&  /* multicast */ mcast_quench(oldfdb))
+                       return 1;
+               return 0;
        }
+       newfdb[port] = NULL;    /* force kmalloc next time */
+       f->mcast_count = 0;
+       /* add to head of port chain */
+       f->fdb_next = p->fdb;
+       p->fdb = f;
+       allocated_fdb_cnt++;
+       return 0;
+}
+
+/* JRP: always called under br_receive_frame(). No need for Q protection. */
+
+void requeue_fdb(struct fdb *node, int new_port)
+{
+       Port_data *p = &port_info[node->port];
+
+       /* dequeue */
+       if(p->fdb == node)
+               p->fdb = node->fdb_next;
+       else 
+       {
+               struct fdb *prev;
+
+               for(prev = p->fdb; prev; prev = prev->fdb_next)
+                       if (prev->fdb_next == node)
+                               break;
+
+               if(prev != NULL)
+                       prev->fdb_next = node->fdb_next;
+               else 
+               {
+                       /*      Forget about this update. */
+                       printk(KERN_ERR "br:requeue_fdb\n");
+                       return;
+               }
+       }
+       /* enqueue */
+       node->port = new_port;
+       node->fdb_next = port_info[new_port].fdb;
+       port_info[new_port].fdb = node;
 }
 
 /*
@@ -1429,26 +1642,43 @@ static int br_forward(struct sk_buff *skb, int port)    /* 3.7 */
                 *      This probably should be dropped since the flood will
                 *      have sent it anyway.
                 */
-               if (port == 0)                  /* locally generated */
+               if (port == 0) 
+               {
+                       /* Locally generated */
+                       ++br_stats_cnt.local_multicast;
                        return(br_dev_drop(skb));
+               }
+               ++br_stats_cnt.forwarded_multicast;
                return(0);
-       } else {
-               /* locate port to forward to */
+       }
+       else 
+       {
+               /* unicast frame, locate port to forward to */
                f = br_avl_find_addr(skb->mac.ethernet->h_dest);
                /*
                 *      Send flood and drop.
                 */
-               if (!f || !(f->flags & FDB_ENT_VALID)) {
-                       /* not found; flood all ports */
+               if (!f || !(f->flags & FDB_ENT_VALID)) 
+               {
+                       if(f && (f->port == 0)) 
+                       {
+                               skb->pkt_type = PACKET_HOST;
+                               ++br_stats_cnt.forwarded_unicast_up_stack;
+                               return(0);
+                       }
+                       /* not found or too old; flood all ports */
+                       ++br_stats_cnt.flood_unicast;
                        br_flood(skb, port);
                        return(br_dev_drop(skb));
                }
                /*
                 *      Sending
                 */
-               if (f->port!=port && port_info[f->port].state == Forwarding) {
-                       /* has entry expired? */
-                       if (f->timer + fdb_aging_time < CURRENT_TIME) {
+               if (f->port!=port && port_info[f->port].state == Forwarding) 
+               {
+                       /* Has entry expired? */
+                       if (f->timer + fdb_aging_time < CURRENT_TIME) 
+                       {
                                /* timer expired, invalidate entry */
                                f->flags &= ~FDB_ENT_VALID;
                                if (br_stats.flags & BR_DEBUG)
@@ -1456,9 +1686,11 @@ static int br_forward(struct sk_buff *skb, int port)     /* 3.7 */
                                /*
                                 *      Send flood and drop original
                                 */
+                               ++br_stats_cnt.aged_flood_unicast;
                                br_flood(skb, port);
                                return(br_dev_drop(skb));
                        }
+                       ++br_stats_cnt.forwarded_unicast;
                        /* mark that's we've been here... */
                        skb->pkt_bridged = IS_BRIDGED;
                        
@@ -1477,7 +1709,25 @@ static int br_forward(struct sk_buff *skb, int port)     /* 3.7 */
                        skb->priority = 1;
                        dev_queue_xmit(skb);
                        return(1);      /* skb has been consumed */
-               } else {
+               }
+               else 
+               {
+                       /* JRP: Needs to aged entry as well, if topology changes
+                        * the entry would not age. Got this while swapping
+                        * two cables !
+                        *
+                        *      Has entry expired?
+                        */
+                        
+                       if (f->timer + fdb_aging_time < CURRENT_TIME) 
+                       {
+                               /* timer expired, invalidate entry */
+                               f->flags &= ~FDB_ENT_VALID;
+                               if (br_stats.flags & BR_DEBUG)
+                                       printk("fdb entry expired...\n");
+                               ++br_stats_cnt.drop_same_port_aged;
+                       }
+                       else ++br_stats_cnt.drop_same_port;
                        /*
                         *      Arrived on the right port, we discard
                         */
@@ -1499,7 +1749,7 @@ static int br_flood(struct sk_buff *skb, int port)
 
        for (i = One; i <= No_of_ports; i++) 
        {
-               if (i == port)
+               if (i == port)  /* don't send back where we got it */
                        continue;
                if (port_info[i].state == Forwarding) 
                {
@@ -1515,8 +1765,12 @@ static int br_flood(struct sk_buff *skb, int port)
                        
 /*                     printk("Flood to port %d\n",i);*/
                        nskb->h.raw = nskb->data + ETH_HLEN;
+#if LINUX_VERSION_CODE >= 0x20100
                        nskb->priority = 1;
                        dev_queue_xmit(nskb);
+#else
+                       dev_queue_xmit(nskb,nskb->dev,1);
+#endif
                }
        }
        return(0);
@@ -1527,12 +1781,16 @@ static int find_port(struct device *dev)
        int i;
 
        for (i = One; i <= No_of_ports; i++)
-               if ((port_info[i].dev == dev) && 
-                       (port_info[i].state != Disabled))
+               if (port_info[i].dev == dev)
                        return(i);
        return(0);
 }
 
+/*
+ *     FIXME: This needs to come from the device structs, eg for
+ *     10,100,1Gbit ethernet.
+ */
 static int br_port_cost(struct device *dev)    /* 4.10.2 */
 {
        if (strncmp(dev->name, "eth", 3) == 0)  /* ethernet */
@@ -1546,43 +1804,103 @@ static int br_port_cost(struct device *dev)    /* 4.10.2 */
  * this routine always consumes the skb 
  */
 
-static void br_bpdu(struct sk_buff *skb) /* consumes skb */
+static void br_bpdu(struct sk_buff *skb, int port) /* consumes skb */
 {
-       Tcn_bpdu *bpdu;
-       int port;
-
-       port = find_port(skb->dev);
-       if (port == 0) {        /* unknown port */
-               br_drop(skb);
-               return;
-       }
-               
-       bpdu = (Tcn_bpdu *) (skb->data + ETH_HLEN);
-       switch (bpdu->type) {
-               case BPDU_TYPE_CONFIG:
-                       received_config_bpdu(port, (Config_bpdu *)bpdu);
-                       break;
-               case BPDU_TYPE_TOPO_CHANGE:
-                       received_tcn_bpdu(port, bpdu);
-                       break;
-               default:
-                       printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n",
-                               bpdu->type);
+       char *bufp = skb->data + ETH_HLEN;
+       Tcn_bpdu *bpdu = (Tcn_bpdu *) (bufp + BRIDGE_LLC1_HS);
+       Config_bpdu rcv_bpdu;
+
+       if((*bufp++ == BRIDGE_LLC1_DSAP) && (*bufp++ == BRIDGE_LLC1_SSAP) &&
+               (*bufp++ == BRIDGE_LLC1_CTRL) &&
+               (bpdu->protocol_id == BRIDGE_BPDU_8021_PROTOCOL_ID) &&
+               (bpdu->protocol_version_id == BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID)) 
+       {
+  
+               switch (bpdu->type) 
+               {
+                       case BPDU_TYPE_CONFIG:
+                               /* realign for portability to RISC */
+                               memcpy((char*)&rcv_bpdu, bufp,
+                                       BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
+                               bufp+= BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET;
+                               rcv_bpdu.top_change_ack =
+                                       (*bufp & TOPOLOGY_CHANGE_ACK) != 0;
+                               rcv_bpdu.top_change =
+                                       (*bufp & TOPOLOGY_CHANGE) != 0;
+                               bufp++;
+                               memcpy((char*)&rcv_bpdu.root_id, bufp,
+                                       BRIDGE_BPDU_8021_CONFIG_SIZE-1
+                                        -BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET);
+                               config_bpdu_ntoh(&rcv_bpdu);
+                               received_config_bpdu(port, &rcv_bpdu);
+                               break;
+                       
+                       case BPDU_TYPE_TOPO_CHANGE:
+                               received_tcn_bpdu(port, bpdu);
+                               break;
+                       default:
+                               printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n", bpdu->type);
                        /* break; */
+               }
        }
        br_drop(skb);
 }
 
+struct fdb_info *get_fdb_info(int user_buf_size, int *copied,int *notcopied)
+{
+       int fdb_size, i, built = 0;
+       struct fdb_info *fdbi, *fdbis;
+
+       *copied = user_buf_size - sizeof(struct fdb_info_hdr);
+       *copied /= sizeof(struct fdb_info);
+       *copied = min(*copied, allocated_fdb_cnt);
+       *notcopied = allocated_fdb_cnt - *copied;
+       if(*copied == 0)
+               return NULL;
+       fdb_size = *copied * sizeof(struct fdb_info);
+       fdbis = kmalloc(fdb_size, GFP_KERNEL);
+       if(fdbis == NULL)
+               return NULL;
+       fdbi = fdbis;
+
+       for(i=One; i<=No_of_ports;i++)
+       {
+               struct fdb *fdb;
+
+               cli();
+               fdb = port_info[i].fdb;
+               while(fdb) 
+               {
+                       memcpy(fdbi->ula, fdb->ula, ETH_ALEN);
+                       fdbi->port = fdb->port;
+                       fdbi->flags = fdb->flags;
+                       fdbi->timer = fdb->timer;
+                       fdbi++;
+                       if(++built == *copied) 
+                       {
+                               sti();
+                               return fdbis;
+                       }
+                       fdb = fdb->fdb_next;
+               }
+               sti();
+       }
+       printk(KERN_DEBUG "get_fdb_info: built=%d\n", built);
+       return fdbis;
+}
+
 int br_ioctl(unsigned int cmd, void *arg)
 {
-       int err;
+       int err, i;
        struct br_cf bcf;
+       bridge_id_t new_id;
 
        switch(cmd)
        {
                case SIOCGIFBR: /* get bridging control blocks */
                        memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
                        memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
+
                        err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
                        if (err)
                        {
@@ -1590,17 +1908,33 @@ int br_ioctl(unsigned int cmd, void *arg)
                        }
                        return err;
                case SIOCSIFBR:
-                       if (!suser())
-                               return -EPERM;
                        err = copy_from_user(&bcf, arg, sizeof(struct br_cf));
                        if (err)
                                return -EFAULT; 
-                       switch (bcf.cmd) {
+                       if (bcf.cmd != BRCMD_DISPLAY_FDB && !suser())
+                               return -EPERM;
+                       switch (bcf.cmd) 
+                       {
                                case BRCMD_BRIDGE_ENABLE:
                                        if (br_stats.flags & BR_UP)
                                                return(-EALREADY);      
                                        printk(KERN_DEBUG "br: enabling bridging function\n");
                                        br_stats.flags |= BR_UP;        /* enable bridge */
+                                       for(i=One;i<=No_of_ports; i++)
+                                       {
+                                               /* don't start if user said so */
+                                               if((user_port_state[i] != Disabled)
+                                                       && port_info[i].dev) 
+                                               {
+                                                       enable_port(i);
+                                               }
+                                       }
+                                       port_state_selection();   /* (4.8.1.5)   */
+                                       config_bpdu_generation();  /* (4.8.1.6)  */
+                                       /* initialize system timer */
+                                       tl.expires = jiffies+HZ;        /* 1 second */
+                                       tl.function = br_tick;
+                                       add_timer(&tl);
                                        start_hello_timer();
                                        break;
                                case BRCMD_BRIDGE_DISABLE:
@@ -1609,35 +1943,41 @@ int br_ioctl(unsigned int cmd, void *arg)
                                        printk(KERN_DEBUG "br: disabling bridging function\n");
                                        br_stats.flags &= ~BR_UP;       /* disable bridge */
                                        stop_hello_timer();
-#if 0                                  
                                        for (i = One; i <= No_of_ports; i++)
                                                if (port_info[i].state != Disabled)
                                                        disable_port(i);
-#endif                                                 
                                        break;
                                case BRCMD_PORT_ENABLE:
                                        if (port_info[bcf.arg1].dev == 0)
                                                return(-EINVAL);
-                                       if (port_info[bcf.arg1].state != Disabled)
+                                       if (user_port_state[bcf.arg1] != Disabled)
                                                return(-EALREADY);
                                        printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
-                                       enable_port(bcf.arg1);
+                                       user_port_state[bcf.arg1] = ~Disabled;
+                                       if(br_stats.flags & BR_UP)
+                                               enable_port(bcf.arg1);
                                        break;
                                case BRCMD_PORT_DISABLE:
                                        if (port_info[bcf.arg1].dev == 0)
                                                return(-EINVAL);
-                                       if (port_info[bcf.arg1].state == Disabled)
+                                       if (user_port_state[bcf.arg1] == Disabled)
                                                return(-EALREADY);
                                        printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1);
-                                       disable_port(bcf.arg1);
+                                       user_port_state[bcf.arg1] = Disabled;
+                                       if(br_stats.flags & BR_UP)
+                                               disable_port(bcf.arg1);
                                        break;
                                case BRCMD_SET_BRIDGE_PRIORITY:
-                                       set_bridge_priority((bridge_id_t *)&bcf.arg1);
+                                       new_id = bridge_info.bridge_id;
+                                       new_id.BRIDGE_PRIORITY = htons(bcf.arg1);
+                                       set_bridge_priority(&new_id);
                                        break;
                                case BRCMD_SET_PORT_PRIORITY:
-                                       if (port_info[bcf.arg1].dev == 0)
+                                       if((port_info[bcf.arg1].dev == 0)
+                                           || (bcf.arg2 & ~0xff))
                                                return(-EINVAL);
-                                       set_port_priority(bcf.arg1, bcf.arg2);
+                                       port_priority[bcf.arg1] = bcf.arg2;
+                                       set_port_priority(bcf.arg1);
                                        break;
                                case BRCMD_SET_PATH_COST:
                                        if (port_info[bcf.arg1].dev == 0)
@@ -1664,6 +2004,36 @@ int br_ioctl(unsigned int cmd, void *arg)
                                        memset(&br_stats.prot_id,0,sizeof(br_stats.prot_id));
                                        memset(&br_stats.prot_counter,0,sizeof(br_stats.prot_counter));
                                        break;
+                               case BRCMD_DISPLAY_FDB:
+                               {
+                                       struct fdb_info_hdr *user_buf = (void*) bcf.arg1;
+                                       struct fdb_info *u_fdbs, *fdbis;
+                                       int copied, notcopied;
+                                       u32 j = CURRENT_TIME;
+
+                                       if(bcf.arg2<sizeof(struct fdb_info_hdr))
+                                               return -EINVAL;
+                                       put_user(j, &user_buf->cmd_time);
+                                       if(allocated_fdb_cnt == 0) 
+                                       {
+                                               put_user(0, &user_buf->copied);
+                                               put_user(0, &user_buf->not_copied);
+                                               return 0;
+                                       }
+                                       fdbis = get_fdb_info(bcf.arg2, &copied, &notcopied);
+                                       put_user(copied, &user_buf->copied);
+                                       put_user(notcopied, &user_buf->not_copied);
+                                       if(!fdbis)
+                                               return -ENOMEM;
+                                       u_fdbs = (struct fdb_info *) (user_buf+1);
+                                       err = copy_to_user(u_fdbs, fdbis, copied*sizeof(struct fdb_info));
+                                       kfree(fdbis);
+                                       if (err)
+                                       {
+                                               err = -EFAULT;
+                                       }
+                                       return err;
+                               }
                                default:
                                        return -EINVAL;
                        }
@@ -1680,12 +2050,13 @@ static int br_cmp(unsigned int *a, unsigned int *b)
        int i;  
        for (i=0; i<2; i++) 
        {
-               if (a[i] == b[i])
-                       continue;
-               if (a[i] < b[i])
-                       return(1);
-               if (a[i] > b[i])
+               /* JRP: compares prty then MAC address in memory byte order
+                * OK optimizer does htonl() only once per long !
+                */
+               if (htonl(a[i]) < htonl(b[i]))
                        return(-1);
+               if (htonl(a[i]) > htonl(b[i]))
+                       return(1);
        }
        return(0);
 }
index 8234249c5094cd4d25527dd7f2d5d297394c472f..709bafb2b511cb9dd7b1d709153a6d76de06f67b 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * this code is derived from the avl functions in mmap.c
+ *     This code is derived from the avl functions in mmap.c
  */
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
  * Written by Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>.
  * Taken from mmap.c, extensively modified by John Hayes 
  * <hayes@netplumbing.com>
+ * 98-02 Modified by Jean-Rene Peulve jr.peulve@aix.pacwan.net
+ *             update port number when topology change
+ *             return oldfdb when updating, for broadcast storm checking
+ *             call addr_cmp once per node
  */
 
 static struct fdb fdb_head;
@@ -50,8 +55,7 @@ static int addr_cmp(unsigned char *a1, unsigned char *a2);
  *    foreach node in tree->fdb_avl_right: node->fdb_avl_key >= tree->fdb_avl_key.
  */
 
-static int
-fdb_init(void)
+static int fdb_init(void)
 {
        fdb_head.fdb_avl_height = 0;
        fdb_head.fdb_avl_left = (struct fdb *)0;
@@ -109,7 +113,6 @@ struct fdb *br_avl_find_addr(unsigned char addr[6])
 }
 
 
-#if (0)
 /*
  * Rebalance a tree.
  * After inserting or deleting a node of a tree we have a sequence of subtrees
@@ -196,10 +199,14 @@ static void br_avl_rebalance (struct fdb *** nodeplaces_ptr, int count)
        printk_avl(&fdb_head);
 #endif /* DEBUG_AVL */
 }
-#endif /* (0) */
 
-/* Insert a node into a tree. */
-int br_avl_insert (struct fdb * new_node)
+/* Insert a node into a tree.
+ * Performance improvement:
+ *      call addr_cmp() only once per node and use result in a switch.
+ * Return old node address if we knew that MAC address already
+ * Return NULL if we insert the new node
+ */
+struct fdb *br_avl_insert (struct fdb * new_node)
 {
        struct fdb ** nodeplace = fhpp;
        struct fdb ** stack[avl_maxheight];
@@ -214,15 +221,38 @@ int br_avl_insert (struct fdb * new_node)
                if (node == avl_br_empty)
                        break;
                *stack_ptr++ = nodeplace; stack_count++;
-               if (addr_cmp(new_node->ula, node->ula) == 0) { /* update */
+               switch(addr_cmp(new_node->ula, node->ula)) {
+               case 0: /* update */
+                   if (node->port == new_node->port) {
                        node->flags = new_node->flags;
                        node->timer = new_node->timer;  
-                       return(0);
-               }
-               if (addr_cmp(new_node->ula, node->ula) < 0) {
-                       nodeplace = &node->fdb_avl_left;
-               } else {
-                       nodeplace = &node->fdb_avl_right;
+                  } else if (!(node->flags & FDB_ENT_VALID) &&
+                               node->port) {
+                       /* update fdb but never for local interfaces */
+#if (DEBUG_AVL)
+                       printk("node 0x%x:port changed old=%d new=%d\n",
+                               (unsigned int)node, node->port,new_node->port);
+#endif
+                       /* JRP: update port as well if the topology change !
+                        * Don't do this while entry is still valid otherwise
+                        * a broadcast that we flooded and is reentered by another
+                        * port would mess up the good port number.
+                        * The fdb list per port needs to be updated as well.
+                        */
+                       requeue_fdb(node, new_node->port);
+                       node->flags = new_node->flags;
+                       node->timer = new_node->timer;  
+#if (DEBUG_AVL)
+                       printk_avl(&fdb_head);
+#endif /* DEBUG_AVL */
+                  }
+                  return node;         /* pass old fdb to caller */
+
+               case 1: /* new_node->ula > node->ula */
+                  nodeplace = &node->fdb_avl_right;
+                  break;
+               default: /* -1 => new_node->ula < node->ula */
+                  nodeplace = &node->fdb_avl_left;
                }
        }
 #if (DEBUG_AVL)
@@ -239,17 +269,14 @@ int br_avl_insert (struct fdb * new_node)
        new_node->fdb_avl_right = avl_br_empty;
        new_node->fdb_avl_height = 1;
        *nodeplace = new_node;
-#if (0)        
        br_avl_rebalance(stack_ptr,stack_count);
-#endif /* (0) */
 #ifdef DEBUG_AVL
        printk_avl(&fdb_head);
 #endif /* DEBUG_AVL */
-       return(1);
+       return NULL;            /* this is a new node */
 }
 
 
-#if (0)
 /* Removes a node out of a tree. */
 static int br_avl_remove (struct fdb * node_to_delete)
 {
@@ -302,7 +329,6 @@ static int br_avl_remove (struct fdb * node_to_delete)
        br_avl_rebalance(stack_ptr,stack_count);
        return(0);
 }
-#endif /* (0) */
 
 #ifdef DEBUG_AVL
 
@@ -311,13 +337,14 @@ static void printk_avl (struct fdb * tree)
 {
        if (tree != avl_br_empty) {
                printk("(");
-               printk("%02x:%02x:%02x:%02x:%02x:%02x",
+               printk("%02x:%02x:%02x:%02x:%02x:%02x(%d)",
                        tree->ula[0],
                        tree->ula[1],
                        tree->ula[2],
                        tree->ula[3],
                        tree->ula[4],
-                       tree->ula[5]);
+                       tree->ula[5],
+                       tree->port);
                if (tree->fdb_avl_left != avl_br_empty) {
                        printk_avl(tree->fdb_avl_left);
                        printk("<");
@@ -330,7 +357,6 @@ static void printk_avl (struct fdb * tree)
        }
 }
 
-#if (0)
 static char *avl_check_point = "somewhere";
 
 /* check a tree's consistency and balancing */
@@ -387,7 +413,6 @@ static void avl_checkorder (struct fdb * tree)
        avl_checkright(tree->fdb_avl_right,tree->fdb_avl_key);
 }
 
-#endif /* (0) */
 #endif /* DEBUG_AVL */
 
 static int addr_cmp(unsigned char a1[], unsigned char a2[])
index ebd7a887a073126d3e83b8537448be9678bbad79..7b4f9c844e483ed7315067902265662677846c2c 100644 (file)
@@ -506,7 +506,7 @@ static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, i
         struct sk_buff *n_skb;
        int offset;
 
-       maxsize = skb->truesize - sizeof(struct sk_buff);
+       maxsize = skb->truesize;
 
         diff = n_len - o_len;
         o_offset = o_buf - (char*) skb->data;
@@ -547,7 +547,6 @@ static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, i
                 offset = n_skb->data - skb->data;
                 n_skb->nh.raw = skb->nh.raw + offset;
                 n_skb->h.raw = skb->h.raw + offset;
-                n_skb->when = skb->when;
                 n_skb->dev = skb->dev;
                 n_skb->mac.raw = skb->mac.raw + offset;
                 n_skb->pkt_type = skb->pkt_type;
index 52a250b957b2fab3d9ed9004d1c352be4cc42f20..1d7315481d41ad38eafc5736aef19dad4490aa9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.30 1998/03/23 23:56:29 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.31 1998/03/30 08:41:41 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -70,9 +70,6 @@ extern int sysctl_icmp_echoreply_time;
 
 int tcp_retr1_max = 255; 
 
-extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
-                               void *buffer, size_t *lenp);
-
 struct ipv4_config ipv4_config;
 
 extern ctl_table ipv4_route_table[];
@@ -108,9 +105,6 @@ ctl_table ipv4_table[] = {
         {NET_IPV4_TCP_SACK, "tcp_sack",
          &sysctl_tcp_sack, sizeof(int), 0644, NULL,
          &proc_dointvec},
-       {NET_IPV4_TCP_VEGAS_CONG_AVOID, "tcp_vegas_cong_avoid",
-        &sysctl_tcp_cong_avoidance, sizeof(int), 0644,
-        NULL, &tcp_sysctl_congavoid },
         {NET_IPV4_FORWARD, "ip_forward",
          &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
          &ipv4_sysctl_forward},
index 86595e1c31e495d5c9118f44b5890591bbc7baf6..e9fcec0476e9831f57e9c3138252aca383a7ecd2 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.107 1998/03/28 00:55:28 davem Exp $
+ * Version:    $Id: tcp.c,v 1.108 1998/03/29 08:43:51 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1407,7 +1407,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
         *  descriptor close, not protocol-sourced closes, because the
         *  reader process may not have drained the data yet!
         */
-       while((skb=skb_dequeue(&sk->receive_queue))!=NULL) {
+       while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) {
                data_was_unread++;
                kfree_skb(skb);
        }
index d9c5a95846f2faec5fcd5f0d273c669dba0a1672..7dab8ff8874d9a3b759f4cb2fc47ca7d6c4554d0 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.100 1998/03/28 00:55:31 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.103 1998/03/30 08:41:12 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 #include <net/tcp.h>
 #include <linux/ipsec.h>
 
-typedef void                   (*tcp_sys_cong_ctl_t)(struct sock *sk,
-                                                     u32 seq, u32 ack,
-                                                     u32 seq_rtt);
-
-static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack,
-                               u32 seq_rtt);
-static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
-                                u32 seq_rtt);
-
 #ifdef CONFIG_SYSCTL
 #define SYNC_INIT 0 /* let the user enable it */
 #else
@@ -80,8 +71,6 @@ int sysctl_tcp_syncookies = SYNC_INIT;
 int sysctl_tcp_stdurg;
 int sysctl_tcp_rfc1337;
 
-static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj;
-
 /* There is something which you must keep in mind when you analyze the
  * behavior of the tp->ato delayed ack timeout interval.  When a
  * connection starts up, we want to ack as quickly as possible.  The
@@ -164,7 +153,7 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
 static __inline__ void tcp_set_rto(struct tcp_opt *tp)
 {
        tp->rto = (tp->srtt >> 3) + tp->mdev;
-       tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
+       tp->rto += (tp->rto >> 2) + (tp->rto >> ((tp->snd_cwnd>>TCP_CWND_SHIFT)-1));
 }
  
 
@@ -450,7 +439,7 @@ static void tcp_compute_tsack(struct sock *sk, struct tcp_opt *tp)
 static __inline__ void clear_fast_retransmit(struct tcp_opt *tp)
 {
        if (tp->dup_acks > 3)
-               tp->snd_cwnd = tp->snd_ssthresh;
+               tp->snd_cwnd = (tp->snd_ssthresh << TCP_CWND_SHIFT);
 
        tp->dup_acks = 0;
 }
@@ -490,8 +479,8 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                        tp->dup_acks++;
                        if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
                                tp->dup_acks++;
-                                tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
-                                tp->snd_cwnd = tp->snd_ssthresh + 3;
+                                tp->snd_ssthresh = max(tp->snd_cwnd >> (TCP_CWND_SHIFT + 1), 2);
+                                tp->snd_cwnd = (tp->snd_ssthresh + 3) << TCP_CWND_SHIFT;
                                tp->high_seq = tp->snd_nxt;
                                if(!tp->fackets_out)
                                        tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
@@ -511,7 +500,7 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                  */
                 if (tp->dup_acks > 3) {
                        if(!tp->fackets_out) {
-                               tp->snd_cwnd++;
+                               tp->snd_cwnd += (1 << TCP_CWND_SHIFT);
                        } else {
                                /* Fill any further holes which may have appeared.
                                 * We may want to change this to run every further
@@ -572,121 +561,25 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
        }
 }
 
-/*
- *      TCP slow start and congestion avoidance in two flavors:
- *      RFC 1122 and TCP Vegas.
+/* This is Jacobson's slow start and congestion avoidance. 
+ * SIGCOMM '88, p. 328.
  *
- *      This is a /proc/sys configurable option. 
+ * FIXME: What happens when the congestion window gets larger
+ * than the maximum receiver window by some large factor
+ * Suppose the pipeline never looses packets for a long
+ * period of time, then traffic increases causing packet loss.
+ * The congestion window should be reduced, but what it should
+ * be reduced to is not clear, since 1/2 the old window may
+ * still be larger than the maximum sending rate we ever achieved.
  */
-
-#define SHIFT_FACTOR 16
-
-static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
-                                u32 seq_rtt)
+static void tcp_cong_avoid(struct tcp_opt *tp, u32 seq, u32 ack, u32 seq_rtt)
 {
-       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       unsigned int actual, expected;
-       unsigned int inv_rtt, inv_basertt, inv_basebd;
-       u32 snt_bytes;
-
-       /*      From:
-        *      TCP Vegas: New Techniques for Congestion 
-        *      Detection and Avoidance.
-        *
-        *      Warning: This code is a scratch implementation taken
-        *      from the paper only. The code they distribute seams
-        *      to have improved several things over the initial spec.
-        */
-
-       if (!seq_rtt)
-               seq_rtt = 1;
-
-       if (tp->basertt)
-               tp->basertt = min(seq_rtt, tp->basertt);
-       else
-               tp->basertt = seq_rtt;
-
-       /*      actual   = throughput for this segment.
-        *      expected = number_of_bytes in transit / BaseRTT
-        */
-
-       snt_bytes = ack - seq;
-
-       inv_rtt = (1 << SHIFT_FACTOR) / seq_rtt;
-       inv_basertt = (1 << SHIFT_FACTOR) / tp->basertt;
-
-       actual =  snt_bytes * inv_rtt;
-
-       expected = (tp->snd_nxt - tp->snd_una) * inv_basertt;
-
-       inv_basebd = sk->mss * inv_basertt;
-
-       /* Slow Start */
-       if (tp->snd_cwnd < tp->snd_ssthresh &&
-           (seq == tp->snd_nxt ||
-            (expected - actual <= TCP_VEGAS_GAMMA * inv_basebd))) {
-               /* "Vegas allows exponential growth only every other RTT" */
-               if (tp->snd_cwnd_cnt++) {
-                       tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               }
-       } else {
-               /* Congestion Avoidance */
-               if (expected - actual <= TCP_VEGAS_ALPHA * inv_basebd) {
-                       /* Increase Linearly */
-                       if (tp->snd_cwnd_cnt++ >= tp->snd_cwnd) {
-                               tp->snd_cwnd++;
-                               tp->snd_cwnd_cnt = 0;
-                       }
-               }
-
-               if (expected - actual >= TCP_VEGAS_BETA * inv_basebd) {
-                       /* Decrease Linearly */
-                       if (tp->snd_cwnd_cnt++ >= tp->snd_cwnd) {
-                               tp->snd_cwnd--;
-                               tp->snd_cwnd_cnt = 0;
-                       }
-
-                       /* Never less than 2 segments. */
-                       if (tp->snd_cwnd < 2)
-                               tp->snd_cwnd = 2;
-               }
-       }
-}
-
-static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack, u32 seq_rtt)
-{
-       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       
-        /* This is Jacobson's slow start and congestion avoidance. 
-         * SIGCOMM '88, p. 328.  Because we keep cong_window in 
-         * integral mss's, we can't do cwnd += 1 / cwnd.  
-         * Instead, maintain a counter and increment it once every 
-         * cwnd times.  
-        * FIXME: Check to be sure the mathematics works out right
-        * on this trick when we have to reduce the congestion window.
-        * The snd_cwnd_cnt has to be reset properly when reduction events
-        * happen.
-        * FIXME: What happens when the congestion window gets larger
-        * than the maximum receiver window by some large factor
-        * Suppose the pipeline never looses packets for a long
-        * period of time, then traffic increases causing packet loss.
-        * The congestion window should be reduced, but what it should
-        * be reduced to is not clear, since 1/2 the old window may
-        * still be larger than the maximum sending rate we ever achieved.
-         */
-        if (tp->snd_cwnd <= tp->snd_ssthresh) {
+        if ((tp->snd_cwnd>>TCP_CWND_SHIFT) <= tp->snd_ssthresh) {
                 /* In "safe" area, increase. */
-                tp->snd_cwnd++;
+                tp->snd_cwnd += (1 << TCP_CWND_SHIFT);
        } else {
-                /* In dangerous area, increase slowly.  In theory this is
-                 * tp->snd_cwnd += 1 / tp->snd_cwnd
-                 */
-                if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-                        tp->snd_cwnd++;
-                        tp->snd_cwnd_cnt = 0;
-                } else 
-                        tp->snd_cwnd_cnt++;
+                /* In dangerous area, increase slowly. */
+               tp->snd_cwnd += 1;
         }       
 }
 
@@ -738,7 +631,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
                tp->packets_out--;
                *seq = TCP_SKB_CB(skb)->seq;
                *seq_rtt = now - TCP_SKB_CB(skb)->when;
-               skb_unlink(skb);
+               __skb_unlink(skb, skb->list);
                kfree_skb(skb);
        }
 
@@ -791,7 +684,7 @@ static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
        } else {
                tcp_set_rto(tp);
                if (flag & FLAG_DATA_ACKED)
-                       (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
+                       tcp_cong_avoid(tp, seq, ack, seq_rtt);
        }
        /* NOTE: safe here so long as cong_ctl doesn't use rto */
        tcp_bound_rto(tp);
@@ -910,7 +803,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
                                        tcp_set_rto(tp);
                                        tcp_bound_rto(tp);
                                }
-                               (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
+                               tcp_cong_avoid(tp, seq, ack, seq_rtt);
                        }
                }
        }
@@ -1326,9 +1219,13 @@ static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
        int num_sacks = tp->num_sacks;
        int this_sack;
 
-       /* We know this removed SKB will eat from the front of a SACK. */
+       /* This is an in order data segment _or_ an out-of-order SKB being
+        * moved to the receive queue, so we know this removed SKB will eat
+        * from the front of a SACK.
+        */
        for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-               if(sp->start_seq == TCP_SKB_CB(skb)->seq)
+               if(!after(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
+                  before(sp->start_seq, TCP_SKB_CB(skb)->end_seq))
                        break;
        }
 
@@ -1380,7 +1277,7 @@ static void tcp_ofo_queue(struct sock *sk)
 
                if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
                        SOCK_DEBUG(sk, "ofo packet was already received \n");
-                       skb_unlink(skb);
+                       __skb_unlink(skb, skb->list);
                        kfree_skb(skb);
                        continue;
                }
@@ -1390,8 +1287,8 @@ static void tcp_ofo_queue(struct sock *sk)
 
                if(tp->sack_ok)
                        tcp_sack_remove_skb(tp, skb);
-               skb_unlink(skb);
-               skb_queue_tail(&sk->receive_queue, skb);
+               __skb_unlink(skb, skb->list);
+               __skb_queue_tail(&sk->receive_queue, skb);
                tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if(skb->h.th->fin)
                        tcp_fin(skb, sk, skb->h.th);
@@ -1411,7 +1308,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                /* Ok. In sequence. */
        queue_and_out:
                dst_confirm(sk->dst_cache);
-               skb_queue_tail(&sk->receive_queue, skb);
+               __skb_queue_tail(&sk->receive_queue, skb);
                tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if(skb->h.th->fin) {
                        tcp_fin(skb, sk, skb->h.th);
@@ -1468,7 +1365,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
                        tp->selective_acks[0].end_seq = TCP_SKB_CB(skb)->end_seq;
                }
-               skb_queue_head(&tp->out_of_order_queue,skb);
+               __skb_queue_head(&tp->out_of_order_queue,skb);
        } else {
                for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) {
                        /* Already there. */
@@ -1476,8 +1373,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                                if (skb->len >= skb1->len) {
                                        if(tp->sack_ok)
                                                tcp_sack_extend(tp, skb1, skb);
-                                       skb_append(skb1, skb);
-                                       skb_unlink(skb1);
+                                       __skb_append(skb1, skb);
+                                       __skb_unlink(skb1, skb1->list);
                                        kfree_skb(skb1);
                                } else {
                                        /* A duplicate, smaller than what is in the
@@ -1489,7 +1386,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        }
                        
                        if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) {
-                               skb_append(skb1,skb);
+                               __skb_append(skb1, skb);
                                if(tp->sack_ok)
                                        tcp_sack_new_ofo_skb(sk, skb);
                                break;
@@ -1497,7 +1394,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 
                         /* See if we've hit the start. If so insert. */
                        if (skb1 == skb_peek(&tp->out_of_order_queue)) {
-                               skb_queue_head(&tp->out_of_order_queue,skb);
+                               __skb_queue_head(&tp->out_of_order_queue,skb);
                                if(tp->sack_ok)
                                        tcp_sack_new_ofo_skb(sk, skb);
                                break;
@@ -1550,7 +1447,7 @@ static void tcp_data_snd_check(struct sock *sk)
 
        if ((skb = tp->send_head)) {
                if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
-                   tcp_packets_in_flight(tp) < tp->snd_cwnd) {
+                   tcp_packets_in_flight(tp) < (tp->snd_cwnd >> TCP_CWND_SHIFT)) {
                        /* Put more data onto the wire. */
                        tcp_write_xmit(sk);
                } else if (tp->packets_out == 0 && !tp->pending) {
@@ -1695,7 +1592,7 @@ static void prune_queue(struct sock *sk)
        /* Start with the end because there are probably the least
         * useful packets (crossing fingers).
         */
-       while ((skb = skb_dequeue_tail(&tp->out_of_order_queue))) { 
+       while ((skb = __skb_dequeue_tail(&tp->out_of_order_queue))) { 
                kfree_skb(skb);
                if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
                        return;
@@ -1715,7 +1612,7 @@ static void prune_queue(struct sock *sk)
                                tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->last_ack_sent);
                        break; 
                }
-               skb_unlink(skb);
+               __skb_unlink(skb, skb->list);
                tp->rcv_nxt = TCP_SKB_CB(skb)->seq;
                SOCK_DEBUG(sk, "prune_queue: removing %x-%x (c=%x)\n",
                           TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
@@ -1796,7 +1693,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        /* DO NOT notify forward progress here.
                         * It saves dozen of CPU instructions in fast path. --ANK
                         */
-                       skb_queue_tail(&sk->receive_queue, skb);
+                       __skb_queue_tail(&sk->receive_queue, skb);
                        tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 
                        /* FIN bit check is not done since if FIN is set in
@@ -2249,26 +2146,3 @@ discard:
        }
        return 0;
 }
-
-int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
-                        void *buffer, size_t *lenp)
-{
-       int val = sysctl_tcp_cong_avoidance;
-       int retv;
-       static tcp_sys_cong_ctl_t tab[] = { 
-               tcp_cong_avoid_vanj, 
-               tcp_cong_avoid_vegas
-       };
-
-       retv = proc_dointvec(ctl, write, filp, buffer, lenp);
-
-       if (write) {
-               if ((unsigned)sysctl_tcp_cong_avoidance > 1) {
-                       retv = -EINVAL;
-                       sysctl_tcp_cong_avoidance = val;
-               } else {
-                       tcp_sys_cong_ctl_f = tab[sysctl_tcp_cong_avoidance];
-               }
-       }
-       return retv;
-}
index 0d3b957cf9085dc4a10ee7aa936c2ed8ff65c5ef..408fa3e8735ef4071883ef619b812a70beb499bf 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.123 1998/03/28 00:55:30 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.127 1998/03/30 08:41:25 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -347,7 +347,9 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
                                           u32 saddr, u16 sport,
                                           u32 daddr, u16 dport, int dif)
 {
-       unsigned short hnum = ntohs(dport);
+       TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
+       __u16 hnum = ntohs(dport);
+       __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
        struct sock *sk;
        int hash;
 
@@ -359,12 +361,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
 
        /* Check TCP register quick cache first. */
        sk = TCP_RHASH(sport);
-       if(sk                                           &&
-          sk->daddr            == saddr                && /* remote address */
-          sk->dport            == sport                && /* remote port    */
-          sk->num              == hnum                 && /* local port     */
-          sk->rcv_saddr        == daddr                && /* local address  */
-          (!sk->bound_dev_if || sk->bound_dev_if == dif))
+       if(sk && TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
                goto hit;
 
        /* Optimize here for direct hit, only listening connections can
@@ -372,25 +369,16 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
         */
        hash = tcp_hashfn(daddr, hnum, saddr, sport);
        for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
-               if(sk->daddr            == saddr                && /* remote address */
-                  sk->dport            == sport                && /* remote port    */
-                  sk->num              == hnum                 && /* local port     */
-                  sk->rcv_saddr        == daddr                && /* local address  */
-                  (!sk->bound_dev_if || sk->bound_dev_if == dif)) {
+               if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
                                TCP_RHASH(sport) = sk;
                        goto hit; /* You sunk my battleship! */
                }
        }
        /* Must check for a TIME_WAIT'er before going to listener hash. */
-       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
-               if(sk->daddr            == saddr                && /* remote address */
-                  sk->dport            == sport                && /* remote port    */
-                  sk->num              == hnum                 && /* local port     */
-                  sk->rcv_saddr        == daddr                && /* local address  */
-                  (!sk->bound_dev_if || sk->bound_dev_if == dif))
+       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
+               if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
                        goto hit;
-       }
 #ifdef USE_QUICKSYNS
 listener_shortcut:
 #endif
@@ -771,8 +759,8 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
        switch (type) {
        case ICMP_SOURCE_QUENCH:
 #ifndef OLD_SOURCE_QUENCH /* This is deprecated */
-               tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
-               tp->snd_cwnd = tp->snd_ssthresh;
+               tp->snd_ssthresh = max(tp->snd_cwnd >> (1 + TCP_CWND_SHIFT), 2);
+               tp->snd_cwnd = (tp->snd_ssthresh << TCP_CWND_SHIFT);
                tp->high_seq = tp->snd_nxt;
 #endif
                return;
@@ -1203,14 +1191,13 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                newtp->last_ack_sent = req->rcv_isn + 1;
                newtp->backoff = 0;
                newtp->mdev = TCP_TIMEOUT_INIT;
-               newtp->snd_cwnd = 1;
+               newtp->snd_cwnd = (1 << TCP_CWND_SHIFT);
                newtp->rto = TCP_TIMEOUT_INIT;
                newtp->packets_out = 0;
                newtp->fackets_out = 0;
                newtp->retrans_out = 0;
                newtp->high_seq = 0;
                newtp->snd_ssthresh = 0x7fffffff;
-               newtp->snd_cwnd_cnt = 0;
                newtp->dup_acks = 0;
                newtp->delayed_acks = 0;
                init_timer(&newtp->retransmit_timer);
@@ -1659,7 +1646,7 @@ static int tcp_v4_init_sock(struct sock *sk)
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
         */
-       tp->snd_cwnd = 1;
+       tp->snd_cwnd = (1 << TCP_CWND_SHIFT);
        tp->snd_ssthresh = 0x7fffffff;  /* Infinity */
 
        sk->priority = 1;
@@ -1687,11 +1674,11 @@ static int tcp_v4_destroy_sock(struct sock *sk)
                tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
 
        /* Cleanup up the write buffer. */
-       while((skb = skb_dequeue(&sk->write_queue)) != NULL)
+       while((skb = __skb_dequeue(&sk->write_queue)) != NULL)
                kfree_skb(skb);
 
        /* Cleans up our, hopefuly empty, out_of_order_queue. */
-       while((skb = skb_dequeue(&tp->out_of_order_queue)) != NULL)
+       while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL)
                kfree_skb(skb);
 
        /* Clean up a locked TCP bind bucket, this only happens if a
index dea48c176ec912e8dca2a8ac4502677b662af46b..664231f23e9f9a31a92f81cba28aeca29c546f48 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.79 1998/03/28 00:55:33 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.81 1998/03/30 08:41:36 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -138,7 +138,7 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
 
        /* Advance write_seq and place onto the write_queue. */
        tp->write_seq += (TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq);
-       skb_queue_tail(&sk->write_queue, skb);
+       __skb_queue_tail(&sk->write_queue, skb);
 
        if (!force_queue && tp->send_head == NULL && tcp_snd_test(sk, skb)) {
                /* Send it out now. */
@@ -215,7 +215,7 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
        skb->csum = csum_partial(skb->data, skb->len, 0);
 
        /* Link BUFF into the send queue. */
-       skb_append(skb, buff);
+       __skb_append(skb, buff);
 
        return 0;
 }
@@ -396,7 +396,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
                        return;
 
                /* Ok.  We will be able to collapse the packet. */
-               skb_unlink(next_skb);
+               __skb_unlink(next_skb, next_skb->list);
 
                if(skb->len % 4) {
                        /* Must copy and rechecksum all data. */
@@ -548,7 +548,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
                        /* Stop retransmitting if we've hit the congestion
                         * window limit.
                         */
-                       if (tp->retrans_out >= tp->snd_cwnd)
+                       if (tp->retrans_out >= (tp->snd_cwnd >> TCP_CWND_SHIFT))
                                break;
                }
                update_retrans_head(sk);
@@ -577,7 +577,7 @@ void tcp_fack_retransmit(struct sock *sk)
                if(tcp_retransmit_skb(sk, skb))
                        break;
 
-               if(tcp_packets_in_flight(tp) >= tp->snd_cwnd)
+               if(tcp_packets_in_flight(tp) >= (tp->snd_cwnd >> TCP_CWND_SHIFT))
                        break;
 next_packet:
                packet_cnt++;
@@ -687,7 +687,7 @@ int tcp_send_synack(struct sock *sk)
        /* SYN eats a sequence byte. */
        TCP_SKB_CB(skb)->seq = tp->snd_una;
        TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
-       skb_queue_tail(&sk->write_queue, skb);
+       __skb_queue_tail(&sk->write_queue, skb);
        TCP_SKB_CB(skb)->when = jiffies;
        tp->packets_out++;
        tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
@@ -838,7 +838,7 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss)
        tp->retrans_out = 0;
 
        /* Send it off. */
-       skb_queue_tail(&sk->write_queue, buff);
+       __skb_queue_tail(&sk->write_queue, buff);
        TCP_SKB_CB(buff)->when = jiffies;
        tp->packets_out++;
        tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL));
index 00d021415762b8887fed07649ffef8df86c1bcff..78fcad3fefa5c3668bc9ef5b30e0d353d295df37 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.44 1998/03/27 04:07:43 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.45 1998/03/30 08:41:31 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -382,9 +382,8 @@ void tcp_retransmit_timer(unsigned long data)
                 * "one half of the current window but at least 2 segments"
                 */
                tp->retrans_out = 0;
-               tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
-               tp->snd_cwnd_cnt = 0;
-               tp->snd_cwnd = 1;
+               tp->snd_ssthresh = max(tp->snd_cwnd >> (1 + TCP_CWND_SHIFT), 2);
+               tp->snd_cwnd = (1 << TCP_CWND_SHIFT);
        }
 
        tp->retransmits++;
index 0f1c710d36255b2f19592b62c7cd7d4e2479f5d9..e92b4e878fb92da719cca44404cd5b49f09dd564 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: ip6_output.c,v 1.10 1998/03/20 09:12:17 davem Exp $
+ *     $Id: ip6_output.c,v 1.11 1998/03/28 08:29:39 davem Exp $
  *
  *     Based on linux/net/ipv4/ip_output.c
  *
@@ -265,7 +265,6 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
                return err;
 
        last_skb->dst = dst_clone(dst);
-       last_skb->when = jiffies;
 
        skb_reserve(last_skb, (dst->dev->hard_header_len + 15) & ~15);
        
@@ -461,8 +460,6 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
                dev = dst->dev;
                skb->dst = dst_clone(dst);
 
-               skb->when = jiffies;
-
                skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
 
                hdr = (struct ipv6hdr *) skb->tail;
index 5e3446b49df7ba39b3f7ce5057c074ce90fee3aa..e4162fac9a4b8de825e9e6245deea810c9d25de2 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.69 1998/03/28 00:55:36 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.72 1998/03/30 08:41:52 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -240,8 +240,9 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                                           struct in6_addr *daddr, u16 dport,
                                           int dif)
 {
-       unsigned short hnum = ntohs(dport);
        struct sock *sk;
+       __u16 hnum = ntohs(dport);
+       __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
        int hash;
 
 #ifdef USE_QUICKSYNS
@@ -252,13 +253,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
 
        /* Check TCP register quick cache first. */
        sk = TCP_RHASH(sport);
-       if(sk                                           &&
-          sk->num              == hnum                 && /* local port     */
-          sk->family           == AF_INET6             && /* address family */
-          sk->dport            == sport                && /* remote port    */
-          !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
-          !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr) &&
-          (!sk->bound_dev_if || sk->bound_dev_if == dif))
+       if(sk && TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
                goto hit;
 
        /* Optimize here for direct hit, only listening connections can
@@ -267,28 +262,23 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
        hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
        for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
                /* For IPV6 do the cheaper port and family tests first. */
-               if(sk->num              == hnum                 && /* local port     */
-                  sk->family           == AF_INET6             && /* address family */
-                  sk->dport            == sport                && /* remote port    */
-                  !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
-                  !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr) &&
-                  (!sk->bound_dev_if || sk->bound_dev_if == dif)) {
+               if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
                                TCP_RHASH(sport) = sk;
                        goto hit; /* You sunk my battleship! */
                }
        }
        /* Must check for a TIME_WAIT'er before going to listener hash. */
-       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
-               if(sk->num              == hnum                 && /* local port     */
-                  sk->family           == AF_INET6             && /* address family */
-                  sk->dport            == sport) {                /* remote port    */
+       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
+               if(*((__u32 *)&(sk->dport))     == ports        &&
+                  sk->family                   == AF_INET6) {
                        struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
                        if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) &&
                           !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) &&
                           (!sk->bound_dev_if || sk->bound_dev_if == dif))
                                goto hit;
                }
+       }
 #ifdef USE_QUICKSYNS
 listener_shortcut:
 #endif
@@ -1302,7 +1292,7 @@ static int tcp_v6_init_sock(struct sock *sk)
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
         */
-       tp->snd_cwnd = 1;
+       tp->snd_cwnd = (1 << TCP_CWND_SHIFT);
        tp->snd_ssthresh = 0x7fffffff;
 
        sk->priority = 1;
@@ -1333,14 +1323,14 @@ static int tcp_v6_destroy_sock(struct sock *sk)
         *      Cleanup up the write buffer.
         */
 
-       while((skb = skb_dequeue(&sk->write_queue)) != NULL)
+       while((skb = __skb_dequeue(&sk->write_queue)) != NULL)
                kfree_skb(skb);
 
        /*
         *  Cleans up our, hopefuly empty, out_of_order_queue
         */
 
-       while((skb = skb_dequeue(&tp->out_of_order_queue)) != NULL)
+       while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL)
                kfree_skb(skb);
 
        /*
index 8bc8ca237d156a097d850b91b91fe5c8ade362c3..4c469e2a2a5f234cf838ef31bdbe3f945d6fd519 100644 (file)
@@ -73,7 +73,6 @@ extern void destroy_8023_client(struct datalink_proto *);
 /* Skbuff symbols. */
 EXPORT_SYMBOL(skb_push_errstr);
 EXPORT_SYMBOL(skb_put_errstr);
-EXPORT_SYMBOL(skb_queue_lock);
 
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
@@ -121,6 +120,7 @@ EXPORT_SYMBOL(put_cmsg);
 EXPORT_SYMBOL(net_families);
 EXPORT_SYMBOL(sock_kmalloc);
 EXPORT_SYMBOL(sock_kfree_s);
+EXPORT_SYMBOL(skb_queue_lock);
 
 #ifdef CONFIG_FILTER
 EXPORT_SYMBOL(sk_run_filter);
index 5ca0e83662ff81eb9226e662105c82913685f0a4..3b05916e6a3fe060dd6bdeaf0440961ecffa1f84 100644 (file)
@@ -50,6 +50,9 @@
 # 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max 
 # arguments to "int", allow dep_tristate to take a list of dependencies
 # rather than just one.
+#
+# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
+# texts.
 
 #
 # Make sure we're really running bash.
@@ -89,16 +92,18 @@ function help () {
      var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
      #now pick out the right help text:
      text=$(sed -n "/^$var[    ]*\$/,\${
-                       /^$var[         ]*\$/b
-                       /^#.*/b
-                       /^[     ]*\$/q
+                       /^$var[         ]*\$/c\\
+${var}:\\
+
+                       /^#/b
+                       /^[^    ]/q
                        p
                    }" Documentation/Configure.help)
      if [ -z "$text" ]
      then
          echo; echo "  Sorry, no help available for this option yet.";echo
      else
-         (echo; echo "$text"; echo) | ${PAGER:-more}
+         (echo; echo "$text") | ${PAGER:-more}
      fi
   else
      echo;
index 0679ae8cfe411446a50038b33f85d070d7dfc1c0..6f112d1e5f1cd00db6c74d95ad880e763f56f5ee 100644 (file)
@@ -44,6 +44,9 @@
 #
 # 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command
 # (complement existing value) when used on virgin uninitialized variables.
+#
+# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
+# texts.
 #----------------------------------------------------------------------------
 
 
@@ -278,9 +281,11 @@ function extract_help () {
      var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
      #now pick out the right help text:
      text=$(sed -n "/^$var[    ]*\$/,\${
-                        /^$var[        ]*\$/d
-                        /^#.*/d
-                       /^[     ]*\$/q
+                        /^$var[        ]*\$/c\\
+${var}:\\
+
+                        /^#/b
+                        /^[^   ]/q
                         s/^  //
                         p
                     }" Documentation/Configure.help)
index 6e4a1f2cc032572ff64ff00bb0422b038f082fab..76b576097a02dcc852129848b72786288dcc7de9 100644 (file)
@@ -36,14 +36,14 @@ if { [cget .ref -disabledforeground] == "" } {
 # Define some macros we will need to parse the config.in file.
 #
 proc mainmenu_name { text } {
-       message .header.message -width 400 -relief raised -text "$text"
-       pack .header.label .header.message -side left -padx 15
-        wm title . "$text"
+       message .header.message -width 400 -text "$text"
+       pack .header.message -side left -padx 15
+       wm title . "$text"
 }
 
 proc menu_option { w menu_num text } {
        button .f0.x$menu_num -text "$text" -width 50 -command "$w .$w \"$text\""
-       pack .f0.x$menu_num -pady 1 -expand on
+       pack .f0.x$menu_num -pady 0 -expand on
 }
 
 #
@@ -370,21 +370,19 @@ proc dohelp {w var }  {
 
        if { [file readable Documentation/Configure.help] == 1} then {
                set filefound 1
+               # First escape sed regexp special characters in var:
+               set var [exec echo "$var" | sed s/\[\]\[\/.^$*\]/\\\\&/g]
+               # Now pick out right help text:
                set message [exec sed -n "
                        /^$var\[        \]*\$/,\${
                                /^$var\[        \]*\$/c\\
 ${var}:\\
 
-                               /^#.*/d
-                               /^\[    \]*\$/bL
-                               H
+                               /^#/b
+                               /^\[^   \]/q
+                               s/^  //
+                               p
                        }
-                       d
-                       :L x
-                       s/\\n  //
-                       s/\\n  / /g
-                       p
-                       q
                        " Documentation/Configure.help]
                set found [expr [string length "$message"] > 0]
        }
@@ -402,8 +400,10 @@ ${var}:\\
                label $w.f1.bm -bitmap error
                wm title $w "RTFM"
        } else {
-               message $w.f1.m -width 400 -aspect 300 -text $message \
-                        -relief flat
+               text $w.f1.m -width 73 -relief flat -wrap word
+               $w.f1.m insert 0.0 $message
+               $w.f1.m conf -state disabled  -height [$w.f1.m index end]
+
                label $w.f1.bm -bitmap info
                wm title $w "Configuration help" 
        }
@@ -416,7 +416,7 @@ ${var}:\\
        frame $w.f2
        button $w.f2.ok -text "OK" \
                -width 10 -command "destroy $w; focus $oldFocus"
-       pack $w.f2.ok -side bottom -pady 10 -anchor s
+       pack $w.f2.ok -side bottom -pady 6 -anchor n
        pack $w.f2 -side bottom -padx 10 -anchor s
 
        # Finish off the window
@@ -454,7 +454,6 @@ proc wrapup {w }  {
 # buttons which we will stick down at the bottom.
 #
 frame .header
-label .header.label 
 
 frame .f0 
 
index ee2edae7ecd989b9c2bd131be99badb78d118bb0..2a727fe895b5c8f8aa3ab01346729da73d64ad80 100644 (file)
@@ -1,7 +1,3 @@
-
-pack .header -side top -padx 10 -pady 10 -expand on
-pack .f0 -side top -padx 15 -pady 10 -fill y -expand on
-
 #
 # Misc buttons to save/restore state and so forth.
 # 
@@ -46,13 +42,19 @@ button .f0_bot.l.load -text "Load Configuration from File" -width 25 -command {
        load_configfile .load "Load Configuration from file" read_config_file
 }
 
-pack  .f0_bot.r.save .f0_bot.r.quit -padx 25 -ipadx 10 -ipady 2 -expand on
-pack  .f0_bot.l.load .f0_bot.l.store -padx 25 -ipadx 10 -ipady 2 -expand on
+#
+# Now pack everything, important things first because of small screens.
+#
+pack  .f0_bot.r.save .f0_bot.r.quit -padx 25 -ipadx 10 -expand on
+pack  .f0_bot.l.load .f0_bot.l.store -padx 25 -ipadx 10 -expand on
+
+pack .f0_bot.r -side left -padx 15 -expand on -fill y
+pack .f0_bot.l -side right -padx 15 -expand on -fill y
 
-pack .f0_bot.r -side left -padx 15 -pady 10 -expand on -fill y
-pack .f0_bot.l -side right -padx 15 -pady 10 -expand on -fill y
+pack .f0_bot -side bottom -fill both -expand on -pady 4
+pack .f0 -side bottom -padx 15 -pady 0 -fill y -expand on
+pack .header -padx 10 -pady 7 -expand on
 
-pack .f0_bot -fill both -expand on
 
 #
 # If we cannot write our config files, disable the write button.
index dcf025e2e5681efd3357a5cd4546892f40cbc71a..040c1fe80f9e8c7e05bd698f996a2ffb799878d0 100644 (file)
  *                    user switches from one configuration method to
  *                    another.
  *
+ * 1998 03 09
+ * Axel Boldt - Smaller layout of main menu - it's still too big for 800x600.
+ *            - Display help in text window to allow for cut and paste.
+ *            - Allow for empty lines in help texts.
+ *            - update_define should not set all variables unconditionally to
+ *              0: they may have been set to 1 elsewhere. CONFIG_NETLINK is
+ *              an example.
+ *
  * TO DO:
  *   - clean up - there are useless ifdef's everywhere.
  *   - better comments throughout - C code generating tcl is really cryptic.
@@ -73,9 +81,6 @@
  *   - make choice and int/hex input types line up vertically with
  *           bool/tristate.
  *   - general speedups - how?  The canvas seems to slow it down a lot.
- *   - choice buttons should default to the first menu option, rather than a
- *           blank.  Also look up the right variable when the help button
- *           is pressed.
  *   - clean up +/- 16 confusion for enabling/disabling variables; causes
  *           (theoretical, at the moment) problems with dependencies.
  *   
@@ -1124,7 +1129,7 @@ void dump_tk_script(struct kconfig *scfg)
   for(cfg = scfg; cfg != NULL; cfg = cfg->next)
     {
       if( cfg->tok != tok_define ) continue;
-      printf("\tglobal %s; set %s 0\n",  cfg->optionname,  cfg->optionname);
+      printf("\tglobal %s\n",  cfg->optionname);
       cfg->flags |= GLOBAL_WRITTEN;
     }
   for(cfg = scfg; cfg != NULL; cfg = cfg->next)